* Remove dead code * Rename SlackBotPingWorker to Slack::Messengers::Worker * Remove useless Slack mock * Fix specs
257 lines
8.7 KiB
Ruby
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
|