docbrown/spec/services/pro_memberships/biller_spec.rb
rhymes f5a6ff32cc
Finalize Slack messengers refactoring (#7484)
* Remove dead code

* Rename SlackBotPingWorker to Slack::Messengers::Worker

* Remove useless Slack mock

* Fix specs
2020-04-24 21:15:10 +02:00

257 lines
8.7 KiB
Ruby

require "rails_helper"
RSpec.describe ProMemberships::Biller, type: :service do
def format_date(datetime)
# PostgreSQL DATE(..) function uses UTC.
datetime.utc.to_date.iso8601
end
context "when there are expiring memberships with enough credits" do
let(:pro_membership) { create(:pro_membership) }
let(:user) { pro_membership.user }
before do
create_list(:credit, ProMembership::MONTHLY_COST, user: user)
end
it "renews the membership" do
Timecop.travel(format_date(pro_membership.expires_at)) do
described_class.call
pro_membership.reload
expect(pro_membership.expires_at.to_i).to eq(1.month.from_now.to_i)
expect(pro_membership.status).to eq("active")
end
end
it "subtracts the correct amount of credits" do
Timecop.travel(format_date(pro_membership.expires_at)) do
expect do
described_class.call
end.to change(user.credits.spent, :size).by(ProMembership::MONTHLY_COST)
end
end
it "adds the user back to the pro members chat channel" do
create(:chat_channel, slug: "pro-members", channel_type: "invite_only")
Timecop.travel(format_date(pro_membership.expires_at)) do
described_class.call
expect(user.reload.chat_channels.exists?(slug: "pro-members")).to be(true)
end
end
it "does not fail if the user is already in the pro members chat channel" do
cc = create(:chat_channel, slug: "pro-members", channel_type: "invite_only")
cc.add_users(user)
allow(Rails.logger).to receive(:error)
Timecop.travel(format_date(pro_membership.expires_at)) do
described_class.call
expect(Rails.logger).not_to have_received(:error)
expect(user.reload.chat_channels.exists?(slug: "pro-members")).to be(true)
end
end
it "enqueues a job to bust the users caches" do
ActiveJob::Base.queue_adapter.enqueued_jobs.clear # make sure it hasn't been previously queued
Timecop.travel(format_date(pro_membership.expires_at)) do
sidekiq_assert_enqueued_with(job: Users::BustCacheWorker, args: [user.id]) do
described_class.call
end
end
end
it "enqueues a job to bust the users articles caches" do
Timecop.travel(format_date(pro_membership.expires_at)) do
sidekiq_assert_enqueued_with(
job: Users::ResaveArticlesWorker,
args: [user.id],
queue: "medium_priority",
) do
described_class.call
end
end
end
context "when an error occurs" do
it "does not renew the membership" do
Timecop.travel(format_date(pro_membership.expires_at)) do
pro_membership.expire!
allow(Credits::Buyer).to receive(:call).and_raise(StandardError)
described_class.call
expect(pro_membership.expires_at.to_i).to be(Time.current.to_i)
expect(pro_membership.status).to eq("expired")
end
end
it "does not subtract credits" do
Timecop.travel(format_date(pro_membership.expires_at)) do
allow(Credits::Buyer).to receive(:call).and_raise(StandardError)
expect do
described_class.call
end.to change(user.credits.spent, :size).by(0)
end
end
it "notifies the admins about the error" do
Timecop.travel(format_date(pro_membership.expires_at)) do
allow(Credits::Buyer).to receive(:call).and_raise(StandardError)
sidekiq_assert_enqueued_with(job: Slack::Messengers::Worker) do
described_class.call
end
end
end
end
end
context "when there are expiring memberships with insufficient credits" do
let(:pro_membership) { create(:pro_membership) }
let(:user) { pro_membership.user }
it "expires the membership" do
Timecop.travel(format_date(pro_membership.expires_at)) do
described_class.call
pro_membership.reload
expect(pro_membership.expired?).to be(true)
expect(pro_membership.status).to eq("expired")
end
end
it "removes the user from the pro members chat channel" do
cc = create(:chat_channel, slug: "pro-members", channel_type: "invite_only")
cc.add_users(user)
Timecop.travel(format_date(pro_membership.expires_at)) do
described_class.call
expect(user.reload.chat_channels.exists?(slug: "pro-members")).to be(false)
end
end
it "notifies the admins about the expiration" do
Timecop.travel(format_date(pro_membership.expires_at)) do
sidekiq_assert_enqueued_with(job: Slack::Messengers::Worker) do
described_class.call
end
end
end
it "enqueues a job to bust the users caches" do
ActiveJob::Base.queue_adapter.enqueued_jobs.clear # make sure it hasn't been previously queued
Timecop.travel(format_date(pro_membership.expires_at)) do
sidekiq_assert_enqueued_with(job: Users::BustCacheWorker, args: [user.id]) do
described_class.call
end
end
end
it "enqueues a job to bust the users articles caches" do
Timecop.travel(format_date(pro_membership.expires_at)) do
sidekiq_assert_enqueued_with(
job: Users::ResaveArticlesWorker,
args: [user.id],
queue: "medium_priority",
) do
described_class.call
end
end
end
end
context "when there are expiring memberships with insufficient credits and auto recharge" do
let(:pro_membership) { create(:pro_membership, auto_recharge: true) }
let(:user) { pro_membership.user }
context "when the user has an associated customer" do
before do
StripeMock.start
customer = Payments::Customer.create
user.update_columns(stripe_id_code: customer.id)
end
after do
StripeMock.stop
end
it "charges the customer" do
customer = Payments::Customer.get(user.stripe_id_code)
allow(Payments::Customer).to receive(:charge)
Timecop.travel(format_date(pro_membership.expires_at)) do
described_class.call
end
expect(Payments::Customer).to have_received(:charge).with(
customer: customer,
amount: ProMembership::MONTHLY_COST_USD,
description: "Purchase of 5 credits.",
)
end
it "adds the correct amount of credits" do
Timecop.travel(format_date(pro_membership.expires_at)) do
# we cannot use "expect.to change" because of how activerecord-import works
old_num_credits = user.credits.size
described_class.call
expect(user.reload.credits.size).to be(old_num_credits + ProMembership::MONTHLY_COST)
end
end
it "renews the membership" do
Timecop.travel(format_date(pro_membership.expires_at)) do
described_class.call
pro_membership.reload
expect(pro_membership.expires_at.to_i).to eq(1.month.from_now.to_i)
expect(pro_membership.status).to eq("active")
end
end
it "spends the correct amount of credits" do
Timecop.travel(format_date(pro_membership.expires_at)) do
# we cannot use "expect.to change" because of how activerecord-import works
old_num_credits = user.reload.credits.spent.size
described_class.call
expect(user.reload.credits.spent.size).to eq(old_num_credits + ProMembership::MONTHLY_COST)
end
end
it "enqueues a job to bust the users caches" do
ActiveJob::Base.queue_adapter.enqueued_jobs.clear # make sure it hasn't been previously queued
Timecop.travel(format_date(pro_membership.expires_at)) do
sidekiq_assert_enqueued_with(job: Users::BustCacheWorker, args: [user.id]) do
described_class.call
end
end
end
it "enqueues a job to bust the users articles caches" do
Timecop.travel(format_date(pro_membership.expires_at)) do
sidekiq_assert_enqueued_with(
job: Users::ResaveArticlesWorker,
args: [user.id],
queue: "medium_priority",
) do
described_class.call
end
end
end
end
context "when the user has no associated customer" do
it "notifies the admins about the problem" do
allow(user).to receive(:stripe_id_code).and_return(nil)
Timecop.travel(format_date(pro_membership.expires_at)) do
sidekiq_assert_enqueued_with(job: Slack::Messengers::Worker) do
described_class.call
end
end
end
it "does not change the number of credits" do
Timecop.travel(format_date(pro_membership.expires_at)) do
expect do
described_class.call
end.to change(user.credits, :size).by(0)
end
end
end
end
end