docbrown/spec/requests/classified_listings_spec.rb
rhymes 77e34a726d Fix flaky listings specs (#3899)
* Fix flaky listings specs

* Fix another flaky test
2019-09-02 13:23:41 -04:00

479 lines
17 KiB
Ruby

require "rails_helper"
RSpec.describe "ClassifiedListings", type: :request do
let(:user) { create(:user) }
let(:listing_params) do
{
classified_listing: {
title: "something",
body_markdown: "something else",
category: "cfp",
tag_list: "",
contact_via_connect: true
}
}
end
let(:draft_params) do
{
classified_listing: {
title: "this a draft",
body_markdown: "something draft",
category: "cfp",
tag_list: "",
contact_via_connect: true,
action: "draft"
}
}
end
describe "GET /listings" do
let(:listing) { create(:classified_listing, user: user) }
let(:expired_listing) { create(:classified_listing, user: user) }
before do
sign_in user
create_list(:credit, 25, user: user)
end
it "returns text/html and has status 200" do
get "/listings"
expect(response.content_type).to eq("text/html")
expect(response).to have_http_status(:ok)
end
context "when the user has no params" do
it "shows all active listings" do
get "/listings"
expect(response.body).to include("classifieds-container")
end
end
context "when the user has category and slug params for active listing" do
it "shows that direct listing" do
get "/listings", params: { category: `#{listing.category}`, slug: `#{listing.slug}` }
expect(response.body).to include(CGI.escapeHTML(listing.title))
end
end
context "when the user has category and slug params for expired listing" do
it "shows only active listings from that category" do
expired_listing.published = false
expired_listing.save
get "/listings", params: { category: `#{expired_listing.category}`, slug: `#{expired_listing.slug}` }
expect(response.body).not_to include(CGI.escapeHTML(expired_listing.title))
end
end
end
describe "GET /listings/new" do
before { sign_in user }
it "shows the option to create draft" do
get "/listings/new"
expect(response.body).to include "You will not be charged credits to save a draft."
end
context "when the user has no credits" do
it "shows the proper messages" do
get "/listings/new"
expect(response.body).to include "Listings Require Credits"
expect(response.body).to include "You need at least one credit to create a listing."
end
end
context "when the user has credits" do
it "shows the number of credits" do
random_number = rand(2..100)
create_list(:credit, random_number, user: user)
get "/listings/new"
expect(response.body).to include "You have #{random_number} credits available"
end
end
context "when the user has no credits and belongs to an organization" do
let(:organization) { create(:organization) }
before { create(:organization_membership, user_id: user.id, organization_id: organization.id) }
it "shows the proper message when both user and org have no credits" do
get "/listings/new"
expect(response.body).to include "Listings Require Credits"
end
it "shows the number of credits of the user if the user has credits but the org has no credits" do
random_number = rand(2..100)
create_list(:credit, random_number, user: user)
get "/listings/new"
expect(response.body).to include "You have #{random_number} credits available"
end
it "shows the number of credits of the organization if the org has credits" do
random_number = rand(2..100)
create_list(:credit, random_number, organization: organization)
get "/listings/new"
expect(response.body).to include "has <span id=\"org-credits-number\">#{random_number}</span> credits"
end
it "shows the number of credits of both the user and the organization if they both have credits" do
random_number = rand(2..100)
create_list(:credit, random_number, organization: organization)
create_list(:credit, random_number, user: user)
get "/listings/new"
expect(response.body).to include "has <span id=\"org-credits-number\">#{random_number}</span> credits"
expect(response.body).to include "You have #{random_number} credits available"
end
end
end
describe "POST /listings" do
before do
sign_in user
create_list(:credit, 25, user: user)
end
context "when the listing is invalid" do
let(:invalid_params) do
{
classified_listing: {
title: "nothing",
body_markdown: "",
category: "cfp",
tag_list: ""
}
}
end
it "renders errors with the listing" do
post "/listings", params: invalid_params
expect(response.body).to include("prohibited this listing from being saved")
end
it "does not subtract credits or create a listing if the listing is not valid" do
expect do
post "/listings", params: invalid_params
end.to change(ClassifiedListing, :count).by(0).
and change(user.credits.spent, :size).by(0)
end
end
context "when the listing is valid" do
it "redirects if the user does not have enough credits" do
Credit.delete_all
post "/listings", params: listing_params
expect(response.body).to redirect_to("/credits")
end
it "redirects if the org does not have enough credits" do
org_admin = create(:user, :org_admin)
listing_params[:classified_listing][:post_as_organization] = "1"
sign_in org_admin
post "/listings", params: listing_params
expect(response.body).to redirect_to("/credits")
end
it "redirects to /listings/dashboard for listing draft" do
post "/listings", params: draft_params
expect(response).to redirect_to "/listings/dashboard"
end
it "redirects to /listings" do
post "/listings", params: listing_params
expect(response).to redirect_to "/listings"
end
it "properly deducts the amount of credits" do
post "/listings", params: listing_params
listing_cost = ClassifiedListing.categories_available[:cfp][:cost]
expect(user.credits.spent.size).to eq(listing_cost)
end
it "creates a listing draft under the org" do
org_admin = create(:user, :org_admin)
org_id = org_admin.organizations.first.id
Credit.create(organization_id: org_id)
draft_params[:classified_listing][:organization_id] = org_id
sign_in org_admin
post "/listings", params: draft_params
expect(ClassifiedListing.first.organization_id).to eq org_id
end
it "creates a listing under the org" do
org_admin = create(:user, :org_admin)
org_id = org_admin.organizations.first.id
Credit.create(organization_id: org_id)
listing_params[:classified_listing][:organization_id] = org_id
sign_in org_admin
post "/listings", params: listing_params
expect(ClassifiedListing.first.organization_id).to eq org_id
end
it "does not create a listing draft for an org not belonging to the user" do
org = create(:organization)
draft_params[:classified_listing][:organization_id] = org.id
expect { post "/listings", params: draft_params }.to raise_error(Pundit::NotAuthorizedError)
end
it "does not create a listing for an org not belonging to the user" do
org = create(:organization)
listing_params[:classified_listing][:organization_id] = org.id
expect { post "/listings", params: listing_params }.to raise_error(Pundit::NotAuthorizedError)
end
it "assigns the spent credits to the listing" do
post "/listings", params: listing_params
spent_credit = user.credits.spent.last
expect(spent_credit.purchase_type).to eq("ClassifiedListing")
expect(spent_credit.spent_at).not_to be_nil
end
it "creates listing draft and does not subtract credits" do
allow(Credits::Buyer).to receive(:call).and_raise(ActiveRecord::Rollback)
expect do
post "/listings", params: draft_params
end.to change(ClassifiedListing, :count).by(1).
and change(user.credits.spent, :size).by(0)
end
it "does not create a listing or subtract credits if the purchase does not go through" do
allow(Credits::Buyer).to receive(:call).and_raise(ActiveRecord::Rollback)
expect do
post "/listings", params: listing_params
end.to change(ClassifiedListing, :count).by(0).
and change(user.credits.spent, :size).by(0)
end
end
context "when user is banned" do
it "raises error" do
user.add_role(:banned)
expect do
post "/listings", params: listing_params
end.to raise_error("BANNED")
end
end
end
describe "PUT /listings/:id" do
let(:listing) { create(:classified_listing, user: user) }
let(:listing_draft) { create(:classified_listing, user: user) }
let(:organization) { create(:organization) }
let(:org_listing) { create(:classified_listing, user: user, organization: organization) }
let(:org_listing_draft) { create(:classified_listing, user: user, organization: organization) }
before do
sign_in user
listing_draft.update_columns(bumped_at: nil, published: false)
org_listing_draft.update_columns(bumped_at: nil, published: false)
end
context "when the bump action is called" do
let(:params) { { classified_listing: { action: "bump" } } }
it "does not bump the user listing and redirects to credits if the user has not enough credits" do
previous_bumped_at = listing.bumped_at
put "/listings/#{listing.id}", params: params
expect(listing.reload.bumped_at.to_i).to eq(previous_bumped_at.to_i)
expect(response.body).to redirect_to("/credits")
end
it "does not subtract spent credits if the user has not enough credits" do
expect do
put "/listings/#{listing.id}", params: params
end.to change(user.credits.spent, :size).by(0)
end
it "does not bump the listing or subtract credits if the purchase does not go through" do
previous_bumped_at = listing.bumped_at
allow(Credits::Buyer).to receive(:call).and_raise(ActiveRecord::Rollback)
expect do
put "/listings/#{listing.id}", params: params
end.to change(user.credits.spent, :size).by(0)
expect(listing.reload.bumped_at.to_i).to eq(previous_bumped_at.to_i)
end
it "bumps the listing and subtract credits" do
cost = ClassifiedListing.cost_by_category(listing.category)
create_list(:credit, cost, user: user)
previous_bumped_at = listing.bumped_at
expect do
put "/listings/#{listing.id}", params: params
end.to change(user.credits.spent, :size).by(cost)
expect(listing.reload.bumped_at >= previous_bumped_at).to eq(true)
end
it "bumps the org listing using org credits before user credits" do
cost = ClassifiedListing.cost_by_category(org_listing.category)
create_list(:credit, cost, organization: organization)
create_list(:credit, cost, user: user)
previous_bumped_at = org_listing.bumped_at
expect do
put "/listings/#{org_listing.id}", params: params
end.to change(organization.credits.spent, :size).by(cost)
expect(org_listing.reload.bumped_at >= previous_bumped_at).to eq(true)
end
it "bumps the org listing using user credits if org credits insufficient and user credits are" do
cost = ClassifiedListing.cost_by_category(org_listing.category)
create_list(:credit, cost, user: user)
previous_bumped_at = org_listing.bumped_at
expect do
put "/listings/#{org_listing.id}", params: params
end.to change(user.credits.spent, :size).by(cost)
expect(org_listing.reload.bumped_at >= previous_bumped_at).to eq(true)
end
end
context "when the publish action is called" do
let(:params) { { classified_listing: { action: "publish" } } }
it "publishes a draft and charges user credits if first publish" do
cost = ClassifiedListing.cost_by_category(listing_draft.category)
create_list(:credit, cost, user: user)
expect do
put "/listings/#{listing_draft.id}", params: params
end.to change(user.credits.spent, :size).by(cost)
end
it "publishes a draft and ensures published column is true" do
cost = ClassifiedListing.cost_by_category(listing_draft.category)
create_list(:credit, cost, user: user)
put "/listings/#{listing_draft.id}", params: params
expect(listing_draft.reload.published).to eq(true)
end
it "publishes an org draft and charges org credits if first publish" do
cost = ClassifiedListing.cost_by_category(org_listing_draft.category)
create_list(:credit, cost, organization: organization)
expect do
put "/listings/#{org_listing_draft.id}", params: params
end.to change(organization.credits.spent, :size).by(cost)
end
it "publishes an org draft and ensures published column is true" do
cost = ClassifiedListing.cost_by_category(org_listing_draft.category)
create_list(:credit, cost, organization: organization)
put "/listings/#{org_listing_draft.id}", params: params
expect(org_listing_draft.reload.published).to eq(true)
end
it "publishes a draft that was charged and is within 30 days of bump doesn't charge credits" do
listing.update_column(:published, false)
expect do
put "/listings/#{listing.id}", params: params
end.to change(user.credits.spent, :size).by(0)
end
it "publishes a draft that was charged and is within 30 days of bump and successfully sets published as true" do
listing.update_column(:published, false)
put "/listings/#{listing.id}", params: params
expect(listing.reload.published).to eq(true)
end
it "fails to publish draft and doesn't charge credits" do
expect do
put "/listings/#{listing_draft.id}", params: params
end.to change(user.credits.spent, :size).by(0)
end
it "fails to publish draft and published remains false" do
put "/listings/#{listing_draft.id}", params: params
expect(listing_draft.reload.published).to eq(false)
end
end
context "when the unpublish action is called" do
let(:params) { { classified_listing: { action: "unpublish" } } }
it "unpublishes a published listing" do
put "/listings/#{listing.id}", params: params
expect(listing.reload.published).to eq(false)
end
end
end
describe "DEL /listings/:id" do
let!(:listing) { create(:classified_listing, user: user) }
let!(:listing_draft) { create(:classified_listing, user: user, bumped_at: nil, published: false) }
let(:organization) { create(:organization) }
let!(:org_listing) { create(:classified_listing, user: user, organization: organization) }
let!(:org_listing_draft) do
create(:classified_listing, user: user, organization: organization, bumped_at: nil, published: false)
end
before do
sign_in user
end
context "when deleting draft" do
it "redirect to dashboard" do
delete "/listings/#{listing_draft.id}"
expect(response).to redirect_to("/listings/dashboard")
end
it "have status 302 found" do
delete "/listings/#{listing_draft.id}"
expect(response).to have_http_status(:found)
end
it "decrease total listings count by 1" do
expect do
delete "/listings/#{listing_draft.id}"
end.to change(ClassifiedListing, :count).by(-1)
end
end
context "when deleting listing" do
it "redirect to dashboard" do
delete "/listings/#{listing.id}"
expect(response).to redirect_to("/listings/dashboard")
end
it "have status 302 found" do
delete "/listings/#{listing.id}"
expect(response).to have_http_status(:found)
end
it "decrease total listings count by 1" do
expect do
delete "/listings/#{listing.id}"
end.to change(ClassifiedListing, :count).by(-1)
end
end
context "when deleting org listing" do
it "redirect to dashboard" do
delete "/listings/#{org_listing_draft.id}"
expect(response).to redirect_to("/listings/dashboard")
end
it "have status 302 found" do
delete "/listings/#{org_listing_draft.id}"
expect(response).to have_http_status(:found)
end
it "decrease total listings count by 1" do
expect do
delete "/listings/#{org_listing_draft.id}"
end.to change(ClassifiedListing, :count).by(-1)
end
end
context "when deleting org listing" do
it "redirect to dashboard" do
delete "/listings/#{org_listing.id}"
expect(response).to redirect_to("/listings/dashboard")
end
it "have status 302 found" do
delete "/listings/#{org_listing.id}"
expect(response).to have_http_status(:found)
end
it "decrease total listings count by 1" do
expect do
delete "/listings/#{org_listing.id}"
end.to change(ClassifiedListing, :count).by(-1)
end
end
end
end