`SendReplyJob` was caching reloadable service class objects in `CHANNEL_SERVICES`. In test, a request spec can trigger Rails constant reloading after `SendReplyJob` has already been loaded, leaving the job with stale class objects while later specs stub the reloaded constants. This resolves the channel service at perform time so the job follows the current Rails constant table. How to reproduce Run the CircleCI shard that contains send_reply_job_spec, or the minimized order-dependent reproduction: ```sh bundle exec rspec --format progress spec/builders/v2/reports/label_summary_builder_spec.rb spec/controllers/api/v1/accounts/bulk_actions_controller_spec.rb spec/jobs/send_reply_job_spec.rb:32 ``` What changed - Store service class names in `SendReplyJob::CHANNEL_SERVICES` instead of class objects. - Resolve the service with constantize inside perform so reloads do not leave stale cached classes. Co-authored-by: Sony Mathew <2040199+sony-mathew@users.noreply.github.com>
127 lines
5.9 KiB
Ruby
127 lines
5.9 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe SendReplyJob do
|
|
subject(:job) { described_class.perform_later(message) }
|
|
|
|
let(:message) { create(:message) }
|
|
|
|
it 'enqueues the job' do
|
|
expect { job }.to have_enqueued_job(described_class)
|
|
.with(message)
|
|
.on_queue('high')
|
|
end
|
|
|
|
context 'when the job is triggered on a new message' do
|
|
let(:process_service) { double }
|
|
|
|
before do
|
|
allow(process_service).to receive(:perform)
|
|
end
|
|
|
|
def expect_mapped_service_to_perform(message, service_class_name)
|
|
channel_name = message.conversation.inbox.channel.class.name
|
|
service_class = described_class::CHANNEL_SERVICES.fetch(channel_name)
|
|
|
|
expect(service_class.name).to eq(service_class_name)
|
|
expect(service_class).to receive(:new).with(message: message).and_return(process_service)
|
|
expect(process_service).to receive(:perform)
|
|
|
|
described_class.perform_now(message.id)
|
|
end
|
|
|
|
it 'calls Facebook::SendOnFacebookService when its facebook message' do
|
|
stub_request(:post, /graph.facebook.com/)
|
|
facebook_channel = create(:channel_facebook_page)
|
|
facebook_inbox = create(:inbox, channel: facebook_channel)
|
|
message = create(:message, conversation: create(:conversation, inbox: facebook_inbox))
|
|
allow(Facebook::SendOnFacebookService).to receive(:new).with(message: message).and_return(process_service)
|
|
expect(Facebook::SendOnFacebookService).to receive(:new).with(message: message)
|
|
expect(process_service).to receive(:perform)
|
|
described_class.perform_now(message.id)
|
|
end
|
|
|
|
it 'calls ::Twitter::SendOnTwitterService when its twitter message' do
|
|
twitter_channel = create(:channel_twitter_profile)
|
|
twitter_inbox = create(:inbox, channel: twitter_channel)
|
|
message = create(:message, conversation: create(:conversation, inbox: twitter_inbox))
|
|
expect_mapped_service_to_perform(message, 'Twitter::SendOnTwitterService')
|
|
end
|
|
|
|
it 'calls ::Twilio::SendOnTwilioService when its twilio message' do
|
|
twilio_channel = create(:channel_twilio_sms)
|
|
message = create(:message, conversation: create(:conversation, inbox: twilio_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Twilio::SendOnTwilioService')
|
|
end
|
|
|
|
it 'calls ::Telegram::SendOnTelegramService when its telegram message' do
|
|
telegram_channel = create(:channel_telegram)
|
|
message = create(:message, conversation: create(:conversation, inbox: telegram_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Telegram::SendOnTelegramService')
|
|
end
|
|
|
|
it 'calls ::Line:SendOnLineService when its line message' do
|
|
line_channel = create(:channel_line)
|
|
message = create(:message, conversation: create(:conversation, inbox: line_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Line::SendOnLineService')
|
|
end
|
|
|
|
it 'calls ::Whatsapp:SendOnWhatsappService when its whatsapp message' do
|
|
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
|
|
whatsapp_channel = create(:channel_whatsapp, sync_templates: false)
|
|
message = create(:message, conversation: create(:conversation, inbox: whatsapp_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Whatsapp::SendOnWhatsappService')
|
|
end
|
|
|
|
it 'calls ::Sms::SendOnSmsService when its sms message' do
|
|
sms_channel = create(:channel_sms)
|
|
message = create(:message, conversation: create(:conversation, inbox: sms_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Sms::SendOnSmsService')
|
|
end
|
|
|
|
it 'calls ::Instagram::Direct::SendOnInstagramService when its instagram message' do
|
|
instagram_channel = create(:channel_instagram)
|
|
message = create(:message, conversation: create(:conversation, inbox: instagram_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Instagram::SendOnInstagramService')
|
|
end
|
|
|
|
it 'calls ::Instagram::Messenger::SendOnInstagramService when its an instagram_direct_message from facebook channel' do
|
|
stub_request(:post, /graph.facebook.com/)
|
|
facebook_channel = create(:channel_facebook_page)
|
|
facebook_inbox = create(:inbox, channel: facebook_channel)
|
|
conversation = create(:conversation,
|
|
inbox: facebook_inbox,
|
|
additional_attributes: { 'type' => 'instagram_direct_message' })
|
|
message = create(:message, conversation: conversation)
|
|
|
|
allow(Instagram::Messenger::SendOnInstagramService).to receive(:new).with(message: message).and_return(process_service)
|
|
expect(Instagram::Messenger::SendOnInstagramService).to receive(:new).with(message: message)
|
|
expect(process_service).to receive(:perform)
|
|
described_class.perform_now(message.id)
|
|
end
|
|
|
|
it 'calls ::Email::SendOnEmailService when its email message' do
|
|
email_channel = create(:channel_email)
|
|
message = create(:message, conversation: create(:conversation, inbox: email_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Email::SendOnEmailService')
|
|
end
|
|
|
|
it 'calls ::Messages::SendEmailNotificationService when its webwidget message' do
|
|
webwidget_channel = create(:channel_widget)
|
|
message = create(:message, conversation: create(:conversation, inbox: webwidget_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Messages::SendEmailNotificationService')
|
|
end
|
|
|
|
it 'calls ::Messages::SendEmailNotificationService when its api channel message' do
|
|
api_channel = create(:channel_api)
|
|
message = create(:message, conversation: create(:conversation, inbox: api_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Messages::SendEmailNotificationService')
|
|
end
|
|
|
|
it 'calls ::Tiktok::SendOnTiktokService when its tiktok message' do
|
|
tiktok_channel = create(:channel_tiktok)
|
|
message = create(:message, conversation: create(:conversation, inbox: tiktok_channel.inbox))
|
|
expect_mapped_service_to_perform(message, 'Tiktok::SendOnTiktokService')
|
|
end
|
|
end
|
|
end
|