mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-01 03:27:52 +00:00 
			
		
		
		
	fix: resolve mutex conflicts in Instagram webhook specs (#12154)
This PR fixes flaky test failures in the Instagram webhook specs that were caused by Redis mutex lock conflicts when tests ran in parallel. ### The Problem: The InstagramEventsJob uses a Redis mutex with a key based on sender_id and ig_account_id to prevent race conditions. However, all test factories were using the same hardcoded sender_id: 'Sender-id-1', causing multiple test instances to compete for the same mutex lock when running in parallel. ### The Solution: - Updated all Instagram event factories to generate unique sender IDs using SecureRandom.hex(4) - Modified test stubs and expectations to work with dynamic sender IDs instead of hardcoded values - Ensured each test instance gets its own unique mutex key, eliminating lock contention
This commit is contained in:
		| @@ -17,40 +17,34 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|   let!(:shared_reel_params) { build(:instagram_shared_reel_event).with_indifferent_access } |   let!(:shared_reel_params) { build(:instagram_shared_reel_event).with_indifferent_access } | ||||||
|   let!(:instagram_story_reply_event) { build(:instagram_story_reply_event).with_indifferent_access } |   let!(:instagram_story_reply_event) { build(:instagram_story_reply_event).with_indifferent_access } | ||||||
|   let!(:instagram_message_reply_event) { build(:instagram_message_reply_event).with_indifferent_access } |   let!(:instagram_message_reply_event) { build(:instagram_message_reply_event).with_indifferent_access } | ||||||
|   let!(:contact) { create(:contact, id: 'Sender-id-1', name: 'Jane Dae') } |  | ||||||
|   let!(:contact_inbox) { create(:contact_inbox, contact_id: contact.id, inbox_id: instagram_inbox.id, source_id: 'Sender-id-1') } |  | ||||||
|   let(:conversation) do |  | ||||||
|     create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, contact_id: contact.id) |  | ||||||
|   end |  | ||||||
|   let(:message) do |  | ||||||
|     create(:message, account_id: account.id, inbox_id: instagram_inbox.id, conversation_id: conversation.id, message_type: 'outgoing', |  | ||||||
|                      source_id: 'message-id-1') |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   describe '#perform' do |   describe '#perform' do | ||||||
|     before do |     before do | ||||||
|       instagram_channel.update(access_token: 'valid_instagram_token') |       instagram_channel.update(access_token: 'valid_instagram_token') | ||||||
|  |  | ||||||
|       stub_request(:get, %r{https://graph\.instagram\.com/.*?/Sender-id-1\?.*}) |       stub_request(:get, %r{https://graph\.instagram\.com/.*?/Sender-id-.*?\?.*}) | ||||||
|         .to_return( |         .to_return( | ||||||
|           status: 200, |           status: 200, | ||||||
|           body: { |           body: proc { |request| | ||||||
|  |             sender_id = request.uri.path.split('/').last.split('?').first | ||||||
|  |             { | ||||||
|               name: 'Jane', |               name: 'Jane', | ||||||
|               username: 'some_user_name', |               username: 'some_user_name', | ||||||
|               profile_pic: 'https://chatwoot-assets.local/sample.png', |               profile_pic: 'https://chatwoot-assets.local/sample.png', | ||||||
|             id: 'Sender-id-1', |               id: sender_id, | ||||||
|               follower_count: 100, |               follower_count: 100, | ||||||
|               is_user_follow_business: true, |               is_user_follow_business: true, | ||||||
|               is_business_follow_user: true, |               is_business_follow_user: true, | ||||||
|               is_verified_user: false |               is_verified_user: false | ||||||
|           }.to_json, |             }.to_json | ||||||
|  |           }, | ||||||
|           headers: { 'Content-Type' => 'application/json' } |           headers: { 'Content-Type' => 'application/json' } | ||||||
|         ) |         ) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'creates contact and message for the instagram direct inbox' do |     it 'creates contact and message for the instagram direct inbox' do | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|       contact_inbox |       create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       instagram_inbox.reload |       instagram_inbox.reload | ||||||
| @@ -63,13 +57,15 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'discard echo message already sent by chatwoot' do |     it 'discard echo message already sent by chatwoot' do | ||||||
|       conversation |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|       message |       contact = create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|  |       conversation = create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, contact_id: contact.id) | ||||||
|  |       create(:message, account_id: account.id, inbox_id: instagram_inbox.id, conversation_id: conversation.id, message_type: 'outgoing', | ||||||
|  |                        source_id: 'message-id-1') | ||||||
|  |  | ||||||
|       expect(instagram_inbox.conversations.count).to be 1 |       expect(instagram_inbox.conversations.count).to be 1 | ||||||
|       expect(instagram_inbox.messages.count).to be 1 |       expect(instagram_inbox.messages.count).to be 1 | ||||||
|  |  | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |  | ||||||
|       messaging[:message][:mid] = 'message-id-1' # Set same source_id as the existing message |       messaging[:message][:mid] = 'message-id-1' # Set same source_id as the existing message | ||||||
|       described_class.new(messaging, instagram_inbox, outgoing_echo: true).perform |       described_class.new(messaging, instagram_inbox, outgoing_echo: true).perform | ||||||
|  |  | ||||||
| @@ -81,6 +77,7 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|  |  | ||||||
|     it 'discards duplicate messages from webhook events with the same message_id' do |     it 'discards duplicate messages from webhook events with the same message_id' do | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       initial_message_count = instagram_inbox.messages.count |       initial_message_count = instagram_inbox.messages.count | ||||||
| @@ -93,6 +90,7 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|  |  | ||||||
|     it 'creates message for shared reel' do |     it 'creates message for shared reel' do | ||||||
|       messaging = shared_reel_params[:entry][0]['messaging'][0] |       messaging = shared_reel_params[:entry][0]['messaging'][0] | ||||||
|  |       create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       message = instagram_inbox.messages.first |       message = instagram_inbox.messages.first | ||||||
| @@ -103,7 +101,9 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'creates message with story id' do |     it 'creates message with story id' do | ||||||
|       story_source_id = instagram_story_reply_event[:entry][0]['messaging'][0]['message']['mid'] |       messaging = instagram_story_reply_event[:entry][0]['messaging'][0] | ||||||
|  |       create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|  |       story_source_id = messaging['message']['mid'] | ||||||
|  |  | ||||||
|       stub_request(:get, %r{https://graph\.instagram\.com/.*?/#{story_source_id}\?.*}) |       stub_request(:get, %r{https://graph\.instagram\.com/.*?/#{story_source_id}\?.*}) | ||||||
|         .to_return( |         .to_return( | ||||||
| @@ -121,7 +121,6 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|           headers: { 'Content-Type' => 'application/json' } |           headers: { 'Content-Type' => 'application/json' } | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|       messaging = instagram_story_reply_event[:entry][0]['messaging'][0] |  | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       message = instagram_inbox.messages.first |       message = instagram_inbox.messages.first | ||||||
| @@ -134,10 +133,13 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     it 'creates message with reply to mid' do |     it 'creates message with reply to mid' do | ||||||
|       # Create first message to ensure reply to is valid |       # Create first message to ensure reply to is valid | ||||||
|       first_messaging = dm_params[:entry][0]['messaging'][0] |       first_messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       sender_id = first_messaging['sender']['id'] | ||||||
|  |       create_instagram_contact_for_sender(sender_id, instagram_inbox) | ||||||
|       described_class.new(first_messaging, instagram_inbox).perform |       described_class.new(first_messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       # Create second message with reply to mid |       # Create second message with reply to mid, using same sender_id | ||||||
|       messaging = instagram_message_reply_event[:entry][0]['messaging'][0] |       messaging = instagram_message_reply_event[:entry][0]['messaging'][0] | ||||||
|  |       messaging['sender']['id'] = sender_id | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       first_message = instagram_inbox.messages.first |       first_message = instagram_inbox.messages.first | ||||||
| @@ -148,12 +150,13 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'handles deleted story' do |     it 'handles deleted story' do | ||||||
|       story_source_id = story_mention_params[:entry][0][:messaging][0]['message']['mid'] |       messaging = story_mention_params[:entry][0][:messaging][0] | ||||||
|  |       create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|  |       story_source_id = messaging['message']['mid'] | ||||||
|  |  | ||||||
|       stub_request(:get, %r{https://graph\.instagram\.com/.*?/#{story_source_id}\?.*}) |       stub_request(:get, %r{https://graph\.instagram\.com/.*?/#{story_source_id}\?.*}) | ||||||
|         .to_return(status: 404, body: { error: { message: 'Story not found', code: 1_609_005 } }.to_json) |         .to_return(status: 404, body: { error: { message: 'Story not found', code: 1_609_005 } }.to_json) | ||||||
|  |  | ||||||
|       messaging = story_mention_params[:entry][0][:messaging][0] |  | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       message = instagram_inbox.messages.first |       message = instagram_inbox.messages.first | ||||||
| @@ -163,11 +166,12 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'does not create message for unsupported file type' do |     it 'does not create message for unsupported file type' do | ||||||
|       conversation |       messaging = story_mention_params[:entry][0][:messaging][0] | ||||||
|  |       contact = create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|  |       create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, contact_id: contact.id) | ||||||
|  |  | ||||||
|       # try to create a message with unsupported file type |       # try to create a message with unsupported file type | ||||||
|       story_mention_params[:entry][0][:messaging][0]['message']['attachments'][0]['type'] = 'unsupported_type' |       messaging['message']['attachments'][0]['type'] = 'unsupported_type' | ||||||
|       messaging = story_mention_params[:entry][0][:messaging][0] |  | ||||||
|  |  | ||||||
|       described_class.new(messaging, instagram_inbox, outgoing_echo: false).perform |       described_class.new(messaging, instagram_inbox, outgoing_echo: false).perform | ||||||
|  |  | ||||||
| @@ -177,7 +181,11 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'does not create message if the message is already exists' do |     it 'does not create message if the message is already exists' do | ||||||
|       message |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       contact = create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|  |       conversation = create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, contact_id: contact.id) | ||||||
|  |       create(:message, account_id: account.id, inbox_id: instagram_inbox.id, conversation_id: conversation.id, message_type: 'outgoing', | ||||||
|  |                        source_id: 'message-id-1') | ||||||
|  |  | ||||||
|       expect(instagram_inbox.conversations.count).to be 1 |       expect(instagram_inbox.conversations.count).to be 1 | ||||||
|       expect(instagram_inbox.messages.count).to be 1 |       expect(instagram_inbox.messages.count).to be 1 | ||||||
| @@ -194,7 +202,7 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|       instagram_channel.update(access_token: 'invalid_token') |       instagram_channel.update(access_token: 'invalid_token') | ||||||
|  |  | ||||||
|       # Stub the request to return authorization error status |       # Stub the request to return authorization error status | ||||||
|       stub_request(:get, %r{https://graph\.instagram\.com/.*?/Sender-id-1\?.*}) |       stub_request(:get, %r{https://graph\.instagram\.com/.*?/Sender-id-.*?\?.*}) | ||||||
|         .to_return( |         .to_return( | ||||||
|           status: 401, |           status: 401, | ||||||
|           body: { error: { message: 'unauthorized access token', code: 190 } }.to_json, |           body: { error: { message: 'unauthorized access token', code: 190 } }.to_json, | ||||||
| @@ -218,6 +226,7 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     it 'creates a new conversation if existing conversation is not present' do |     it 'creates a new conversation if existing conversation is not present' do | ||||||
|       initial_count = Conversation.count |       initial_count = Conversation.count | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|  |  | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
| @@ -226,21 +235,23 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'will not create a new conversation if last conversation is not resolved' do |     it 'will not create a new conversation if last conversation is not resolved' do | ||||||
|  |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       contact = create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|       existing_conversation = create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, |       existing_conversation = create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, | ||||||
|                                                     contact_id: contact.id, status: :open) |                                                     contact_id: contact.id, status: :open) | ||||||
|  |  | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |  | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       expect(instagram_inbox.conversations.last.id).to eq(existing_conversation.id) |       expect(instagram_inbox.conversations.last.id).to eq(existing_conversation.id) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'creates a new conversation if last conversation is resolved' do |     it 'creates a new conversation if last conversation is resolved' do | ||||||
|  |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       contact = create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|       existing_conversation = create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, |       existing_conversation = create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, | ||||||
|                                                     contact_id: contact.id, status: :resolved) |                                                     contact_id: contact.id, status: :resolved) | ||||||
|  |  | ||||||
|       initial_count = Conversation.count |       initial_count = Conversation.count | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |  | ||||||
|  |  | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
| @@ -257,6 +268,7 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     it 'creates a new conversation if existing conversation is not present' do |     it 'creates a new conversation if existing conversation is not present' do | ||||||
|       initial_count = Conversation.count |       initial_count = Conversation.count | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|  |  | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
| @@ -265,6 +277,8 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'reopens last conversation if last conversation is resolved' do |     it 'reopens last conversation if last conversation is resolved' do | ||||||
|  |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       contact = create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|       existing_conversation = create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, |       existing_conversation = create(:conversation, account_id: account.id, inbox_id: instagram_inbox.id, | ||||||
|                                                     contact_id: contact.id, status: :resolved) |                                                     contact_id: contact.id, status: :resolved) | ||||||
|  |  | ||||||
| @@ -307,6 +321,7 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|  |  | ||||||
|     it 'saves story information when story mention is processed' do |     it 'saves story information when story mention is processed' do | ||||||
|       messaging = story_mention_params[:entry][0][:messaging][0] |       messaging = story_mention_params[:entry][0][:messaging][0] | ||||||
|  |       create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       message = instagram_inbox.messages.first |       message = instagram_inbox.messages.first | ||||||
| @@ -328,6 +343,7 @@ describe Messages::Instagram::MessageBuilder do | |||||||
|         ) |         ) | ||||||
|  |  | ||||||
|       messaging = story_mention_params[:entry][0][:messaging][0] |       messaging = story_mention_params[:entry][0][:messaging][0] | ||||||
|  |       create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox) | ||||||
|       described_class.new(messaging, instagram_inbox).perform |       described_class.new(messaging, instagram_inbox).perform | ||||||
|  |  | ||||||
|       message = instagram_inbox.messages.first |       message = instagram_inbox.messages.first | ||||||
|   | |||||||
| @@ -17,30 +17,23 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|   let!(:instagram_story_reply_event) { build(:instagram_story_reply_event).with_indifferent_access } |   let!(:instagram_story_reply_event) { build(:instagram_story_reply_event).with_indifferent_access } | ||||||
|   let!(:instagram_message_reply_event) { build(:instagram_message_reply_event).with_indifferent_access } |   let!(:instagram_message_reply_event) { build(:instagram_message_reply_event).with_indifferent_access } | ||||||
|   let(:fb_object) { double } |   let(:fb_object) { double } | ||||||
|   let(:contact) { create(:contact, id: 'Sender-id-1', name: 'Jane Dae') } |  | ||||||
|   let(:contact_inbox) { create(:contact_inbox, contact_id: contact.id, inbox_id: instagram_messenger_inbox.id, source_id: 'Sender-id-1') } |  | ||||||
|   let(:conversation) do |  | ||||||
|     create(:conversation, account_id: account.id, inbox_id: instagram_messenger_inbox.id, contact_id: contact.id, |  | ||||||
|                           additional_attributes: { type: 'instagram_direct_message', conversation_language: 'en' }) |  | ||||||
|   end |  | ||||||
|   let(:message) do |  | ||||||
|     create(:message, account_id: account.id, inbox_id: instagram_messenger_inbox.id, conversation_id: conversation.id, message_type: 'outgoing', |  | ||||||
|                      source_id: 'message-id-1') |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   describe '#perform' do |   describe '#perform' do | ||||||
|     it 'creates contact and message for the facebook inbox' do |     it 'creates contact and message for the facebook inbox' do | ||||||
|  |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       sender_id = messaging['sender']['id'] | ||||||
|  |  | ||||||
|       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|       allow(fb_object).to receive(:get_object).and_return( |       allow(fb_object).to receive(:get_object).and_return( | ||||||
|         { |         { | ||||||
|           name: 'Jane', |           name: 'Jane', | ||||||
|           id: 'Sender-id-1', |           id: sender_id, | ||||||
|           account_id: instagram_messenger_inbox.account_id, |           account_id: instagram_messenger_inbox.account_id, | ||||||
|           profile_pic: 'https://chatwoot-assets.local/sample.png' |           profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|         }.with_indifferent_access |         }.with_indifferent_access | ||||||
|       ) |       ) | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |  | ||||||
|       contact_inbox |       create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|       described_class.new(messaging, instagram_messenger_inbox).perform |       described_class.new(messaging, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|       instagram_messenger_inbox.reload |       instagram_messenger_inbox.reload | ||||||
| @@ -56,7 +49,13 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'discard echo message already sent by chatwoot' do |     it 'discard echo message already sent by chatwoot' do | ||||||
|       message |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       sender_id = messaging['sender']['id'] | ||||||
|  |       contact = create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|  |       conversation = create(:conversation, account_id: account.id, inbox_id: instagram_messenger_inbox.id, contact_id: contact.id, | ||||||
|  |                                            additional_attributes: { type: 'instagram_direct_message', conversation_language: 'en' }) | ||||||
|  |       create(:message, account_id: account.id, inbox_id: instagram_messenger_inbox.id, conversation_id: conversation.id, message_type: 'outgoing', | ||||||
|  |                        source_id: 'message-id-1') | ||||||
|  |  | ||||||
|       expect(instagram_messenger_inbox.conversations.count).to be 1 |       expect(instagram_messenger_inbox.conversations.count).to be 1 | ||||||
|       expect(instagram_messenger_inbox.messages.count).to be 1 |       expect(instagram_messenger_inbox.messages.count).to be 1 | ||||||
| @@ -65,13 +64,11 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|       allow(fb_object).to receive(:get_object).and_return( |       allow(fb_object).to receive(:get_object).and_return( | ||||||
|         { |         { | ||||||
|           name: 'Jane', |           name: 'Jane', | ||||||
|           id: 'Sender-id-1', |           id: sender_id, | ||||||
|           account_id: instagram_messenger_inbox.account_id, |           account_id: instagram_messenger_inbox.account_id, | ||||||
|           profile_pic: 'https://chatwoot-assets.local/sample.png' |           profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|         }.with_indifferent_access |         }.with_indifferent_access | ||||||
|       ) |       ) | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |  | ||||||
|       contact_inbox |  | ||||||
|       described_class.new(messaging, instagram_messenger_inbox, outgoing_echo: true).perform |       described_class.new(messaging, instagram_messenger_inbox, outgoing_echo: true).perform | ||||||
|  |  | ||||||
|       instagram_messenger_inbox.reload |       instagram_messenger_inbox.reload | ||||||
| @@ -81,17 +78,20 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'creates message for shared reel' do |     it 'creates message for shared reel' do | ||||||
|  |       messaging = shared_reel_params[:entry][0]['messaging'][0] | ||||||
|  |       sender_id = messaging['sender']['id'] | ||||||
|  |  | ||||||
|       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|       allow(fb_object).to receive(:get_object).and_return( |       allow(fb_object).to receive(:get_object).and_return( | ||||||
|         { |         { | ||||||
|           name: 'Jane', |           name: 'Jane', | ||||||
|           id: 'Sender-id-1', |           id: sender_id, | ||||||
|           account_id: instagram_messenger_inbox.account_id, |           account_id: instagram_messenger_inbox.account_id, | ||||||
|           profile_pic: 'https://chatwoot-assets.local/sample.png' |           profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|         }.with_indifferent_access |         }.with_indifferent_access | ||||||
|       ) |       ) | ||||||
|       messaging = shared_reel_params[:entry][0]['messaging'][0] |  | ||||||
|       contact_inbox |       create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|       described_class.new(messaging, instagram_messenger_inbox).perform |       described_class.new(messaging, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|       message = instagram_messenger_channel.inbox.messages.first |       message = instagram_messenger_channel.inbox.messages.first | ||||||
| @@ -102,18 +102,20 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'creates message with for reply with story id' do |     it 'creates message with for reply with story id' do | ||||||
|  |       messaging = instagram_story_reply_event[:entry][0]['messaging'][0] | ||||||
|  |       sender_id = messaging['sender']['id'] | ||||||
|  |  | ||||||
|       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|       allow(fb_object).to receive(:get_object).and_return( |       allow(fb_object).to receive(:get_object).and_return( | ||||||
|         { |         { | ||||||
|           name: 'Jane', |           name: 'Jane', | ||||||
|           id: 'Sender-id-1', |           id: sender_id, | ||||||
|           account_id: instagram_messenger_inbox.account_id, |           account_id: instagram_messenger_inbox.account_id, | ||||||
|           profile_pic: 'https://chatwoot-assets.local/sample.png' |           profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|         }.with_indifferent_access |         }.with_indifferent_access | ||||||
|       ) |       ) | ||||||
|       messaging = instagram_story_reply_event[:entry][0]['messaging'][0] |  | ||||||
|       contact_inbox |  | ||||||
|  |  | ||||||
|  |       create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|       described_class.new(messaging, instagram_messenger_inbox).perform |       described_class.new(messaging, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|       message = instagram_messenger_channel.inbox.messages.first |       message = instagram_messenger_channel.inbox.messages.first | ||||||
| @@ -125,24 +127,26 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'creates message with for reply with mid' do |     it 'creates message with for reply with mid' do | ||||||
|  |       # create first message to ensure reply to is valid | ||||||
|  |       first_message_data = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       sender_id = first_message_data['sender']['id'] | ||||||
|  |  | ||||||
|       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|       allow(fb_object).to receive(:get_object).and_return( |       allow(fb_object).to receive(:get_object).and_return( | ||||||
|         { |         { | ||||||
|           name: 'Jane', |           name: 'Jane', | ||||||
|           id: 'Sender-id-1', |           id: sender_id, | ||||||
|           account_id: instagram_messenger_inbox.account_id, |           account_id: instagram_messenger_inbox.account_id, | ||||||
|           profile_pic: 'https://chatwoot-assets.local/sample.png' |           profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|         }.with_indifferent_access |         }.with_indifferent_access | ||||||
|       ) |       ) | ||||||
|       # create first message to ensure reply to is valid |  | ||||||
|       first_message = dm_params[:entry][0]['messaging'][0] |  | ||||||
|       contact_inbox |  | ||||||
|       described_class.new(first_message, instagram_messenger_inbox).perform |  | ||||||
|  |  | ||||||
|       # create the second message with the reply to mid set |       create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|  |       described_class.new(first_message_data, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|  |       # create the second message with the reply to mid set, ensure same sender_id | ||||||
|       messaging = instagram_message_reply_event[:entry][0]['messaging'][0] |       messaging = instagram_message_reply_event[:entry][0]['messaging'][0] | ||||||
|       contact_inbox |       messaging['sender']['id'] = sender_id  # Use the same sender_id | ||||||
|  |  | ||||||
|       described_class.new(messaging, instagram_messenger_inbox).perform |       described_class.new(messaging, instagram_messenger_inbox).perform | ||||||
|       first_message = instagram_messenger_channel.inbox.messages.first |       first_message = instagram_messenger_channel.inbox.messages.first | ||||||
|       message = instagram_messenger_channel.inbox.messages.last |       message = instagram_messenger_channel.inbox.messages.last | ||||||
| @@ -153,14 +157,16 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'raises exception on deleted story' do |     it 'raises exception on deleted story' do | ||||||
|  |       messaging = story_mention_params[:entry][0][:messaging][0] | ||||||
|  |       sender_id = messaging['sender']['id'] | ||||||
|  |  | ||||||
|       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|       allow(fb_object).to receive(:get_object).and_raise(Koala::Facebook::ClientError.new( |       allow(fb_object).to receive(:get_object).and_raise(Koala::Facebook::ClientError.new( | ||||||
|                                                            190, |                                                            190, | ||||||
|                                                            'This Message has been deleted by the user or the business.' |                                                            'This Message has been deleted by the user or the business.' | ||||||
|                                                          )) |                                                          )) | ||||||
|  |  | ||||||
|       messaging = story_mention_params[:entry][0][:messaging][0] |       create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|       contact_inbox |  | ||||||
|       described_class.new(messaging, instagram_messenger_inbox, outgoing_echo: false).perform |       described_class.new(messaging, instagram_messenger_inbox, outgoing_echo: false).perform | ||||||
|  |  | ||||||
|       instagram_messenger_inbox.reload |       instagram_messenger_inbox.reload | ||||||
| @@ -180,22 +186,24 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'does not create message for unsupported file type' do |     it 'does not create message for unsupported file type' do | ||||||
|  |       # create a message with unsupported file type | ||||||
|  |       story_mention_params[:entry][0][:messaging][0]['message']['attachments'][0]['type'] = 'unsupported_type' | ||||||
|  |       messaging = story_mention_params[:entry][0][:messaging][0] | ||||||
|  |       sender_id = messaging['sender']['id'] | ||||||
|  |  | ||||||
|       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |       allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|       allow(fb_object).to receive(:get_object).and_return( |       allow(fb_object).to receive(:get_object).and_return( | ||||||
|         { |         { | ||||||
|           name: 'Jane', |           name: 'Jane', | ||||||
|           id: 'Sender-id-1', |           id: sender_id, | ||||||
|           account_id: instagram_messenger_inbox.account_id, |           account_id: instagram_messenger_inbox.account_id, | ||||||
|           profile_pic: 'https://chatwoot-assets.local/sample.png' |           profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|         }.with_indifferent_access |         }.with_indifferent_access | ||||||
|       ) |       ) | ||||||
|  |  | ||||||
|       conversation |       contact = create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|  |       create(:conversation, account_id: account.id, inbox_id: instagram_messenger_inbox.id, contact_id: contact.id, | ||||||
|       # create a message with unsupported file type |                             additional_attributes: { type: 'instagram_direct_message', conversation_language: 'en' }) | ||||||
|       story_mention_params[:entry][0][:messaging][0]['message']['attachments'][0]['type'] = 'unsupported_type' |  | ||||||
|       messaging = story_mention_params[:entry][0][:messaging][0] |  | ||||||
|  |  | ||||||
|       described_class.new(messaging, instagram_messenger_inbox, outgoing_echo: false).perform |       described_class.new(messaging, instagram_messenger_inbox, outgoing_echo: false).perform | ||||||
|  |  | ||||||
|       instagram_messenger_inbox.reload |       instagram_messenger_inbox.reload | ||||||
| @@ -218,18 +226,22 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|     it 'creates a new conversation if existing conversation is not present' do |     it 'creates a new conversation if existing conversation is not present' do | ||||||
|       inital_count = Conversation.count |       inital_count = Conversation.count | ||||||
|       message = dm_params[:entry][0]['messaging'][0] |       message = dm_params[:entry][0]['messaging'][0] | ||||||
|       contact_inbox |       sender_id = message['sender']['id'] | ||||||
|  |  | ||||||
|  |       create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|       described_class.new(message, instagram_messenger_inbox).perform |       described_class.new(message, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|       instagram_messenger_inbox.reload |       instagram_messenger_inbox.reload | ||||||
|       contact_inbox.reload |  | ||||||
|  |  | ||||||
|       expect(instagram_messenger_inbox.conversations.count).to eq(1) |       expect(instagram_messenger_inbox.conversations.count).to eq(1) | ||||||
|       expect(Conversation.count).to eq(inital_count + 1) |       expect(Conversation.count).to eq(inital_count + 1) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'will not create a new conversation if last conversation is not resolved' do |     it 'will not create a new conversation if last conversation is not resolved' do | ||||||
|  |       message = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       sender_id = message['sender']['id'] | ||||||
|  |       contact = create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|  |  | ||||||
|       existing_conversation = create( |       existing_conversation = create( | ||||||
|         :conversation, |         :conversation, | ||||||
|         account_id: account.id, |         account_id: account.id, | ||||||
| @@ -239,18 +251,18 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|         additional_attributes: { type: 'instagram_direct_message', conversation_language: 'en' } |         additional_attributes: { type: 'instagram_direct_message', conversation_language: 'en' } | ||||||
|       ) |       ) | ||||||
|  |  | ||||||
|       message = dm_params[:entry][0]['messaging'][0] |  | ||||||
|       contact_inbox |  | ||||||
|  |  | ||||||
|       described_class.new(message, instagram_messenger_inbox).perform |       described_class.new(message, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|       instagram_messenger_inbox.reload |       instagram_messenger_inbox.reload | ||||||
|       contact_inbox.reload |  | ||||||
|  |  | ||||||
|       expect(instagram_messenger_inbox.conversations.last.id).to eq(existing_conversation.id) |       expect(instagram_messenger_inbox.conversations.last.id).to eq(existing_conversation.id) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'creates a new conversation if last conversation is resolved' do |     it 'creates a new conversation if last conversation is resolved' do | ||||||
|  |       message = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       sender_id = message['sender']['id'] | ||||||
|  |       contact = create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|  |  | ||||||
|       existing_conversation = create( |       existing_conversation = create( | ||||||
|         :conversation, |         :conversation, | ||||||
|         account_id: account.id, |         account_id: account.id, | ||||||
| @@ -261,13 +273,9 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|       ) |       ) | ||||||
|  |  | ||||||
|       inital_count = Conversation.count |       inital_count = Conversation.count | ||||||
|       message = dm_params[:entry][0]['messaging'][0] |  | ||||||
|       contact_inbox |  | ||||||
|  |  | ||||||
|       described_class.new(message, instagram_messenger_inbox).perform |       described_class.new(message, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|       instagram_messenger_inbox.reload |       instagram_messenger_inbox.reload | ||||||
|       contact_inbox.reload |  | ||||||
|  |  | ||||||
|       expect(instagram_messenger_inbox.conversations.last.id).not_to eq(existing_conversation.id) |       expect(instagram_messenger_inbox.conversations.last.id).not_to eq(existing_conversation.id) | ||||||
|       expect(Conversation.count).to eq(inital_count + 1) |       expect(Conversation.count).to eq(inital_count + 1) | ||||||
| @@ -283,18 +291,22 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|     it 'creates a new conversation if existing conversation is not present' do |     it 'creates a new conversation if existing conversation is not present' do | ||||||
|       inital_count = Conversation.count |       inital_count = Conversation.count | ||||||
|       message = dm_params[:entry][0]['messaging'][0] |       message = dm_params[:entry][0]['messaging'][0] | ||||||
|       contact_inbox |       sender_id = message['sender']['id'] | ||||||
|  |  | ||||||
|  |       create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|       described_class.new(message, instagram_messenger_inbox).perform |       described_class.new(message, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|       instagram_messenger_inbox.reload |       instagram_messenger_inbox.reload | ||||||
|       contact_inbox.reload |  | ||||||
|  |  | ||||||
|       expect(instagram_messenger_inbox.conversations.count).to eq(1) |       expect(instagram_messenger_inbox.conversations.count).to eq(1) | ||||||
|       expect(Conversation.count).to eq(inital_count + 1) |       expect(Conversation.count).to eq(inital_count + 1) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'reopens last conversation if last conversation is resolved' do |     it 'reopens last conversation if last conversation is resolved' do | ||||||
|  |       message = dm_params[:entry][0]['messaging'][0] | ||||||
|  |       sender_id = message['sender']['id'] | ||||||
|  |       contact = create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|  |  | ||||||
|       existing_conversation = create( |       existing_conversation = create( | ||||||
|         :conversation, |         :conversation, | ||||||
|         account_id: account.id, |         account_id: account.id, | ||||||
| @@ -306,13 +318,9 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|  |  | ||||||
|       inital_count = Conversation.count |       inital_count = Conversation.count | ||||||
|  |  | ||||||
|       message = dm_params[:entry][0]['messaging'][0] |  | ||||||
|       contact_inbox |  | ||||||
|  |  | ||||||
|       described_class.new(message, instagram_messenger_inbox).perform |       described_class.new(message, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|       instagram_messenger_inbox.reload |       instagram_messenger_inbox.reload | ||||||
|       contact_inbox.reload |  | ||||||
|  |  | ||||||
|       expect(instagram_messenger_inbox.conversations.last.id).to eq(existing_conversation.id) |       expect(instagram_messenger_inbox.conversations.last.id).to eq(existing_conversation.id) | ||||||
|       expect(Conversation.count).to eq(inital_count) |       expect(Conversation.count).to eq(inital_count) | ||||||
| @@ -344,7 +352,9 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|       allow(fb_object).to receive(:get_object).and_return(story_data) |       allow(fb_object).to receive(:get_object).and_return(story_data) | ||||||
|  |  | ||||||
|       messaging = story_mention_params[:entry][0][:messaging][0] |       messaging = story_mention_params[:entry][0][:messaging][0] | ||||||
|       contact_inbox |       sender_id = messaging['sender']['id'] | ||||||
|  |  | ||||||
|  |       create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|       builder = described_class.new(messaging, instagram_messenger_inbox) |       builder = described_class.new(messaging, instagram_messenger_inbox) | ||||||
|       builder.perform |       builder.perform | ||||||
|  |  | ||||||
| @@ -358,18 +368,20 @@ describe Messages::Instagram::Messenger::MessageBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'handles story mentions specifically in the Instagram builder' do |     it 'handles story mentions specifically in the Instagram builder' do | ||||||
|  |       messaging = story_mention_params[:entry][0][:messaging][0] | ||||||
|  |       sender_id = messaging['sender']['id'] | ||||||
|  |  | ||||||
|       # First allow contact info fetch |       # First allow contact info fetch | ||||||
|       allow(fb_object).to receive(:get_object).and_return({ |       allow(fb_object).to receive(:get_object).and_return({ | ||||||
|         name: 'Jane', |         name: 'Jane', | ||||||
|         id: 'Sender-id-1' |         id: sender_id | ||||||
|       }.with_indifferent_access) |       }.with_indifferent_access) | ||||||
|  |  | ||||||
|       # Then allow story data fetch |       # Then allow story data fetch | ||||||
|       allow(fb_object).to receive(:get_object).with(anything, fields: %w[story from]) |       allow(fb_object).to receive(:get_object).with(anything, fields: %w[story from]) | ||||||
|                                               .and_return(story_data) |                                               .and_return(story_data) | ||||||
|  |  | ||||||
|       messaging = story_mention_params[:entry][0][:messaging][0] |       create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox) | ||||||
|       contact_inbox |  | ||||||
|       described_class.new(messaging, instagram_messenger_inbox).perform |       described_class.new(messaging, instagram_messenger_inbox).perform | ||||||
|  |  | ||||||
|       message = instagram_messenger_inbox.messages.first |       message = instagram_messenger_inbox.messages.first | ||||||
|   | |||||||
| @@ -1,14 +1,18 @@ | |||||||
| FactoryBot.define do | FactoryBot.define do | ||||||
|   factory :instagram_message_create_event, class: Hash do |   factory :instagram_message_create_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-id-123', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -27,15 +31,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_message_standby_event, class: Hash do |   factory :instagram_message_standby_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'id': 'instagram-message-id-123', |           'id': ig_entry_id, | ||||||
|           'standby': [ |           'standby': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -54,15 +62,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_story_reply_event, class: Hash do |   factory :instagram_story_reply_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-id-123', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -87,15 +99,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_message_reply_event, class: Hash do |   factory :instagram_message_reply_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-id-123', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:35:04+0000', |           'time': '2021-09-08T06:35:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -117,11 +133,14 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_test_text_event, class: Hash do |   factory :instagram_test_text_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'time' => 1_661_141_837_537, |           'time' => 1_661_141_837_537, | ||||||
|           'id' => '0', |           'id' => ig_entry_id, | ||||||
|           'messaging' => [ |           'messaging' => [ | ||||||
|             { |             { | ||||||
|               'sender' => { |               'sender' => { | ||||||
| @@ -144,15 +163,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_message_unsend_event, class: Hash do |   factory :instagram_message_unsend_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-id-123', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -171,15 +194,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_message_attachment_event, class: Hash do |   factory :instagram_message_attachment_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-id-1234', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -205,15 +232,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_shared_reel_event, class: Hash do |   factory :instagram_shared_reel_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-id-1234', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -241,15 +272,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_story_mention_event, class: Hash do |   factory :instagram_story_mention_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-id-1234', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -275,15 +310,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_story_mention_event_with_echo, class: Hash do |   factory :instagram_story_mention_event_with_echo, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-id-1234', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -310,15 +349,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :instagram_message_unsupported_event, class: Hash do |   factory :instagram_message_unsupported_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-unsupported-id-123', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
| @@ -337,15 +380,19 @@ FactoryBot.define do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   factory :messaging_seen_event, class: Hash do |   factory :messaging_seen_event, class: Hash do | ||||||
|  |     transient do | ||||||
|  |       ig_entry_id { SecureRandom.uuid } | ||||||
|  |       sender_id { "Sender-id-#{SecureRandom.hex(4)}" } | ||||||
|  |     end | ||||||
|     entry do |     entry do | ||||||
|       [ |       [ | ||||||
|         { |         { | ||||||
|           'id': 'instagram-message-id-123', |           'id': ig_entry_id, | ||||||
|           'time': '2021-09-08T06:34:04+0000', |           'time': '2021-09-08T06:34:04+0000', | ||||||
|           'messaging': [ |           'messaging': [ | ||||||
|             { |             { | ||||||
|               'sender': { |               'sender': { | ||||||
|                 'id': 'Sender-id-1' |                 'id': sender_id | ||||||
|               }, |               }, | ||||||
|               'recipient': { |               'recipient': { | ||||||
|                 'id': 'chatwoot-app-user-id-1' |                 'id': 'chatwoot-app-user-id-1' | ||||||
|   | |||||||
| @@ -10,19 +10,10 @@ describe Webhooks::InstagramEventsJob do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   let!(:account) { create(:account) } |   let!(:account) { create(:account) } | ||||||
|   let(:return_object) do |  | ||||||
|     { name: 'Jane', |  | ||||||
|       id: 'Sender-id-1', |  | ||||||
|       account_id: instagram_messenger_inbox.account_id, |  | ||||||
|       profile_pic: 'https://chatwoot-assets.local/sample.png', |  | ||||||
|       username: 'some_user_name' } |  | ||||||
|   end |  | ||||||
|   let!(:instagram_messenger_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') } |   let!(:instagram_messenger_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') } | ||||||
|   let!(:instagram_messenger_inbox) { create(:inbox, channel: instagram_messenger_channel, account: account, greeting_enabled: false) } |   let!(:instagram_messenger_inbox) { create(:inbox, channel: instagram_messenger_channel, account: account, greeting_enabled: false) } | ||||||
|  |  | ||||||
|   let!(:instagram_channel) { create(:channel_instagram, account: account, instagram_id: 'chatwoot-app-user-id-1') } |   let!(:instagram_channel) { create(:channel_instagram, account: account, instagram_id: 'chatwoot-app-user-id-1') } | ||||||
|   let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) } |   let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) } | ||||||
|  |  | ||||||
|   # Combined message events into one helper |   # Combined message events into one helper | ||||||
|   let(:message_events) do |   let(:message_events) do | ||||||
|     { |     { | ||||||
| @@ -37,6 +28,14 @@ describe Webhooks::InstagramEventsJob do | |||||||
|     } |     } | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   def return_object_for(sender_id) | ||||||
|  |     { name: 'Jane', | ||||||
|  |       id: sender_id, | ||||||
|  |       account_id: instagram_messenger_inbox.account_id, | ||||||
|  |       profile_pic: 'https://chatwoot-assets.local/sample.png', | ||||||
|  |       username: 'some_user_name' } | ||||||
|  |   end | ||||||
|  |  | ||||||
|   describe '#perform' do |   describe '#perform' do | ||||||
|     context 'when handling messaging events for Instagram via Facebook page' do |     context 'when handling messaging events for Instagram via Facebook page' do | ||||||
|       let(:fb_object) { double } |       let(:fb_object) { double } | ||||||
| @@ -47,8 +46,9 @@ describe Webhooks::InstagramEventsJob do | |||||||
|  |  | ||||||
|       it 'creates incoming message in the instagram inbox' do |       it 'creates incoming message in the instagram inbox' do | ||||||
|         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|  |         sender_id = message_events[:dm][:entry][0][:messaging][0][:sender][:id] | ||||||
|         allow(fb_object).to receive(:get_object).and_return( |         allow(fb_object).to receive(:get_object).and_return( | ||||||
|           return_object.with_indifferent_access |           return_object_for(sender_id).with_indifferent_access | ||||||
|         ) |         ) | ||||||
|         instagram_webhook.perform_now(message_events[:dm][:entry]) |         instagram_webhook.perform_now(message_events[:dm][:entry]) | ||||||
|  |  | ||||||
| @@ -63,8 +63,9 @@ describe Webhooks::InstagramEventsJob do | |||||||
|  |  | ||||||
|       it 'creates standby message in the instagram inbox' do |       it 'creates standby message in the instagram inbox' do | ||||||
|         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|  |         sender_id = message_events[:standby][:entry][0][:standby][0][:sender][:id] | ||||||
|         allow(fb_object).to receive(:get_object).and_return( |         allow(fb_object).to receive(:get_object).and_return( | ||||||
|           return_object.with_indifferent_access |           return_object_for(sender_id).with_indifferent_access | ||||||
|         ) |         ) | ||||||
|         instagram_webhook.perform_now(message_events[:standby][:entry]) |         instagram_webhook.perform_now(message_events[:standby][:entry]) | ||||||
|  |  | ||||||
| @@ -82,10 +83,11 @@ describe Webhooks::InstagramEventsJob do | |||||||
|       it 'handle instagram unsend message event' do |       it 'handle instagram unsend message event' do | ||||||
|         message = create(:message, inbox_id: instagram_messenger_inbox.id, source_id: 'message-id-to-delete') |         message = create(:message, inbox_id: instagram_messenger_inbox.id, source_id: 'message-id-to-delete') | ||||||
|         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|  |         sender_id = message_events[:unsend][:entry][0][:messaging][0][:sender][:id] | ||||||
|         allow(fb_object).to receive(:get_object).and_return( |         allow(fb_object).to receive(:get_object).and_return( | ||||||
|           { |           { | ||||||
|             name: 'Jane', |             name: 'Jane', | ||||||
|             id: 'Sender-id-1', |             id: sender_id, | ||||||
|             account_id: instagram_messenger_inbox.account_id, |             account_id: instagram_messenger_inbox.account_id, | ||||||
|             profile_pic: 'https://chatwoot-assets.local/sample.png' |             profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|           }.with_indifferent_access |           }.with_indifferent_access | ||||||
| @@ -104,8 +106,9 @@ describe Webhooks::InstagramEventsJob do | |||||||
|  |  | ||||||
|       it 'creates incoming message with attachments in the instagram inbox' do |       it 'creates incoming message with attachments in the instagram inbox' do | ||||||
|         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|  |         sender_id = message_events[:attachment][:entry][0][:messaging][0][:sender][:id] | ||||||
|         allow(fb_object).to receive(:get_object).and_return( |         allow(fb_object).to receive(:get_object).and_return( | ||||||
|           return_object.with_indifferent_access |           return_object_for(sender_id).with_indifferent_access | ||||||
|         ) |         ) | ||||||
|         instagram_webhook.perform_now(message_events[:attachment][:entry]) |         instagram_webhook.perform_now(message_events[:attachment][:entry]) | ||||||
|  |  | ||||||
| @@ -118,8 +121,9 @@ describe Webhooks::InstagramEventsJob do | |||||||
|  |  | ||||||
|       it 'creates incoming message with attachments in the instagram inbox for story mention' do |       it 'creates incoming message with attachments in the instagram inbox for story mention' do | ||||||
|         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|  |         sender_id = message_events[:story_mention][:entry][0][:messaging][0][:sender][:id] | ||||||
|         allow(fb_object).to receive(:get_object).and_return( |         allow(fb_object).to receive(:get_object).and_return( | ||||||
|           return_object.with_indifferent_access, |           return_object_for(sender_id).with_indifferent_access, | ||||||
|           { story: |           { story: | ||||||
|             { |             { | ||||||
|               mention: { |               mention: { | ||||||
| @@ -165,8 +169,9 @@ describe Webhooks::InstagramEventsJob do | |||||||
|  |  | ||||||
|       it 'handles unsupported message' do |       it 'handles unsupported message' do | ||||||
|         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) |         allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) | ||||||
|  |         sender_id = message_events[:unsupported][:entry][0][:messaging][0][:sender][:id] | ||||||
|         allow(fb_object).to receive(:get_object).and_return( |         allow(fb_object).to receive(:get_object).and_return( | ||||||
|           return_object.with_indifferent_access |           return_object_for(sender_id).with_indifferent_access | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         instagram_webhook.perform_now(message_events[:unsupported][:entry]) |         instagram_webhook.perform_now(message_events[:unsupported][:entry]) | ||||||
| @@ -184,19 +189,22 @@ describe Webhooks::InstagramEventsJob do | |||||||
|       before do |       before do | ||||||
|         instagram_channel.update(access_token: 'valid_instagram_token') |         instagram_channel.update(access_token: 'valid_instagram_token') | ||||||
|  |  | ||||||
|         stub_request(:get, %r{https://graph\.instagram\.com/v22\.0/Sender-id-1\?.*}) |         stub_request(:get, %r{https://graph\.instagram\.com/v22\.0/Sender-id-.*\?.*}) | ||||||
|           .to_return( |           .to_return( | ||||||
|             status: 200, |             status: 200, | ||||||
|             body: { |             body: proc { |request| | ||||||
|  |               sender_id = request.uri.path.split('/').last.split('?').first | ||||||
|  |               { | ||||||
|                 name: 'Jane', |                 name: 'Jane', | ||||||
|                 username: 'some_user_name', |                 username: 'some_user_name', | ||||||
|                 profile_pic: 'https://chatwoot-assets.local/sample.png', |                 profile_pic: 'https://chatwoot-assets.local/sample.png', | ||||||
|               id: 'Sender-id-1', |                 id: sender_id, | ||||||
|                 follower_count: 100, |                 follower_count: 100, | ||||||
|                 is_user_follow_business: true, |                 is_user_follow_business: true, | ||||||
|                 is_business_follow_user: true, |                 is_business_follow_user: true, | ||||||
|                 is_verified_user: false |                 is_verified_user: false | ||||||
|             }.to_json, |               }.to_json | ||||||
|  |             }, | ||||||
|             headers: { 'Content-Type' => 'application/json' } |             headers: { 'Content-Type' => 'application/json' } | ||||||
|           ) |           ) | ||||||
|       end |       end | ||||||
| @@ -289,14 +297,15 @@ describe Webhooks::InstagramEventsJob do | |||||||
|         stub_request(:get, %r{https://graph\.instagram\.com/v22\.0/.*\?.*}) |         stub_request(:get, %r{https://graph\.instagram\.com/v22\.0/.*\?.*}) | ||||||
|           .to_return(status: 401, body: { error: { message: 'No matching Instagram user', code: 9010 } }.to_json) |           .to_return(status: 401, body: { error: { message: 'No matching Instagram user', code: 9010 } }.to_json) | ||||||
|  |  | ||||||
|  |         sender_id = message_events[:dm][:entry][0][:messaging][0][:sender][:id] | ||||||
|         instagram_webhook.perform_now(message_events[:dm][:entry]) |         instagram_webhook.perform_now(message_events[:dm][:entry]) | ||||||
|  |  | ||||||
|         instagram_inbox.reload |         instagram_inbox.reload | ||||||
|  |  | ||||||
|         expect(instagram_inbox.contacts.count).to be 1 |         expect(instagram_inbox.contacts.count).to be 1 | ||||||
|         expect(instagram_inbox.contacts.last.name).to eq 'Unknown (IG: Sender-id-1)' |         expect(instagram_inbox.contacts.last.name).to eq "Unknown (IG: #{sender_id})" | ||||||
|         expect(instagram_inbox.contacts.last.contact_inboxes.count).to be 1 |         expect(instagram_inbox.contacts.last.contact_inboxes.count).to be 1 | ||||||
|         expect(instagram_inbox.contacts.last.contact_inboxes.first.source_id).to eq 'Sender-id-1' |         expect(instagram_inbox.contacts.last.contact_inboxes.first.source_id).to eq sender_id | ||||||
|  |  | ||||||
|         expect(instagram_inbox.conversations.count).to eq 1 |         expect(instagram_inbox.conversations.count).to eq 1 | ||||||
|         expect(instagram_inbox.messages.count).to eq 1 |         expect(instagram_inbox.messages.count).to eq 1 | ||||||
|   | |||||||
| @@ -70,6 +70,7 @@ RSpec.configure do |config| | |||||||
|   config.include SlackStubs |   config.include SlackStubs | ||||||
|   config.include FileUploadHelpers |   config.include FileUploadHelpers | ||||||
|   config.include CsvSpecHelpers |   config.include CsvSpecHelpers | ||||||
|  |   config.include InstagramSpecHelpers | ||||||
|   config.include Devise::Test::IntegrationHelpers, type: :request |   config.include Devise::Test::IntegrationHelpers, type: :request | ||||||
|   config.include ActiveSupport::Testing::TimeHelpers |   config.include ActiveSupport::Testing::TimeHelpers | ||||||
|   config.include ActionCable::TestHelper |   config.include ActionCable::TestHelper | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								spec/support/instagram_spec_helpers.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								spec/support/instagram_spec_helpers.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | module InstagramSpecHelpers | ||||||
|  |   def create_instagram_contact_for_sender(sender_id, inbox) | ||||||
|  |     contact = Contact.find_by(identifier: sender_id) | ||||||
|  |     if contact.nil? | ||||||
|  |       contact = create(:contact, identifier: sender_id, name: 'Jane Dae') | ||||||
|  |       create(:contact_inbox, contact_id: contact.id, inbox_id: inbox.id, source_id: sender_id) | ||||||
|  |     end | ||||||
|  |     contact | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   def instagram_user_response_object_for(sender_id, account_id) | ||||||
|  |     { | ||||||
|  |       name: 'Jane', | ||||||
|  |       id: sender_id, | ||||||
|  |       account_id: account_id, | ||||||
|  |       profile_pic: 'https://chatwoot-assets.local/sample.png', | ||||||
|  |       username: 'some_user_name' | ||||||
|  |     } | ||||||
|  |   end | ||||||
|  | end | ||||||
		Reference in New Issue
	
	Block a user
	 Sojan Jose
					Sojan Jose