2020-01-09 07:36:40 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'rails_helper'
|
|
|
|
|
|
|
|
RSpec.describe Message, type: :model do
|
|
|
|
context 'with validations' do
|
|
|
|
it { is_expected.to validate_presence_of(:inbox_id) }
|
|
|
|
it { is_expected.to validate_presence_of(:conversation_id) }
|
|
|
|
it { is_expected.to validate_presence_of(:account_id) }
|
|
|
|
end
|
|
|
|
|
2021-07-23 09:54:07 +00:00
|
|
|
describe '#reopen_conversation' do
|
|
|
|
let(:conversation) { create(:conversation) }
|
|
|
|
let(:message) { build(:message, message_type: :incoming, conversation: conversation) }
|
|
|
|
|
|
|
|
it 'reopens resolved conversation when the message is from a contact' do
|
|
|
|
conversation.resolved!
|
|
|
|
message.save!
|
2022-07-15 02:51:59 +00:00
|
|
|
expect(message.conversation.open?).to be true
|
2021-07-23 09:54:07 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'reopens snoozed conversation when the message is from a contact' do
|
|
|
|
conversation.snoozed!
|
|
|
|
message.save!
|
2022-07-15 02:51:59 +00:00
|
|
|
expect(message.conversation.open?).to be true
|
2021-07-23 09:54:07 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'will not reopen if the conversation is muted' do
|
|
|
|
conversation.resolved!
|
|
|
|
conversation.mute!
|
|
|
|
message.save!
|
2022-07-15 02:51:59 +00:00
|
|
|
expect(message.conversation.open?).to be false
|
2021-07-23 09:54:07 +00:00
|
|
|
end
|
2022-11-02 20:54:56 +00:00
|
|
|
|
|
|
|
it 'will mark the conversation as pending if the agent bot is active' do
|
|
|
|
agent_bot = create(:agent_bot)
|
|
|
|
inbox = conversation.inbox
|
|
|
|
inbox.agent_bot = agent_bot
|
|
|
|
inbox.save!
|
|
|
|
conversation.resolved!
|
|
|
|
message.save!
|
|
|
|
expect(conversation.open?).to be false
|
|
|
|
expect(conversation.pending?).to be true
|
|
|
|
end
|
2021-07-23 09:54:07 +00:00
|
|
|
end
|
|
|
|
|
2022-10-18 00:36:56 +00:00
|
|
|
context 'with webhook_data' do
|
|
|
|
it 'contains the message attachment when attachment is present' do
|
|
|
|
message = create(:message)
|
|
|
|
attachment = message.attachments.new(account_id: message.account_id, file_type: :image)
|
|
|
|
attachment.file.attach(io: File.open(Rails.root.join('spec/assets/avatar.png')), filename: 'avatar.png', content_type: 'image/png')
|
|
|
|
attachment.save!
|
|
|
|
expect(message.webhook_data.key?(:attachments)).to be true
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not contain the message attachment when attachment is not present' do
|
|
|
|
message = create(:message)
|
|
|
|
expect(message.webhook_data.key?(:attachments)).to be false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-01-09 07:36:40 +00:00
|
|
|
context 'when message is created' do
|
2020-09-10 13:49:15 +00:00
|
|
|
let(:message) { build(:message, account: create(:account)) }
|
2020-01-09 07:36:40 +00:00
|
|
|
|
2020-10-05 17:22:43 +00:00
|
|
|
it 'updates conversation last_activity_at when created' do
|
2021-01-05 14:37:04 +00:00
|
|
|
message.save!
|
2020-10-05 17:22:43 +00:00
|
|
|
expect(message.created_at).to eq message.conversation.last_activity_at
|
|
|
|
end
|
|
|
|
|
2021-05-13 08:02:19 +00:00
|
|
|
it 'updates contact last_activity_at when created' do
|
|
|
|
expect { message.save! }.to(change { message.sender.last_activity_at })
|
|
|
|
end
|
|
|
|
|
2020-01-09 07:36:40 +00:00
|
|
|
it 'triggers ::MessageTemplates::HookExecutionService' do
|
|
|
|
hook_execution_service = double
|
|
|
|
allow(::MessageTemplates::HookExecutionService).to receive(:new).and_return(hook_execution_service)
|
|
|
|
allow(hook_execution_service).to receive(:perform).and_return(true)
|
|
|
|
|
|
|
|
message.save!
|
|
|
|
|
|
|
|
expect(::MessageTemplates::HookExecutionService).to have_received(:new).with(message: message)
|
|
|
|
expect(hook_execution_service).to have_received(:perform)
|
|
|
|
end
|
2020-01-23 17:29:07 +00:00
|
|
|
|
2022-01-26 23:59:48 +00:00
|
|
|
context 'with conversation continuity' do
|
|
|
|
it 'calls notify email method on after save for outgoing messages in website channel' do
|
|
|
|
allow(ConversationReplyEmailWorker).to receive(:perform_in).and_return(true)
|
|
|
|
message.message_type = 'outgoing'
|
|
|
|
message.save!
|
|
|
|
expect(ConversationReplyEmailWorker).to have_received(:perform_in)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not call notify email for website channel if continuity is disabled' do
|
|
|
|
message.inbox = create(:inbox, account: message.account,
|
|
|
|
channel: build(:channel_widget, account: message.account, continuity_via_email: false))
|
|
|
|
allow(ConversationReplyEmailWorker).to receive(:perform_in).and_return(true)
|
|
|
|
message.message_type = 'outgoing'
|
|
|
|
message.save!
|
|
|
|
expect(ConversationReplyEmailWorker).not_to have_received(:perform_in)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'wont call notify email method for private notes' do
|
|
|
|
message.private = true
|
|
|
|
allow(ConversationReplyEmailWorker).to receive(:perform_in).and_return(true)
|
|
|
|
message.save!
|
|
|
|
expect(ConversationReplyEmailWorker).not_to have_received(:perform_in)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'calls EmailReply worker if the channel is email' do
|
|
|
|
message.inbox = create(:inbox, account: message.account, channel: build(:channel_email, account: message.account))
|
|
|
|
allow(EmailReplyWorker).to receive(:perform_in).and_return(true)
|
|
|
|
message.message_type = 'outgoing'
|
|
|
|
message.save!
|
|
|
|
expect(EmailReplyWorker).to have_received(:perform_in).with(1.second, message.id)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'wont call notify email method unless its website or email channel' do
|
|
|
|
message.inbox = create(:inbox, account: message.account, channel: build(:channel_api, account: message.account))
|
|
|
|
allow(ConversationReplyEmailWorker).to receive(:perform_in).and_return(true)
|
|
|
|
message.save!
|
|
|
|
expect(ConversationReplyEmailWorker).not_to have_received(:perform_in)
|
|
|
|
end
|
2020-01-23 17:29:07 +00:00
|
|
|
end
|
2020-01-09 07:36:40 +00:00
|
|
|
end
|
2021-10-05 18:40:29 +00:00
|
|
|
|
|
|
|
context 'when content_type is blank' do
|
|
|
|
let(:message) { build(:message, content_type: nil, account: create(:account)) }
|
|
|
|
|
|
|
|
it 'sets content_type as text' do
|
|
|
|
message.save!
|
|
|
|
expect(message.content_type).to eq 'text'
|
|
|
|
end
|
|
|
|
end
|
2022-02-15 11:41:28 +00:00
|
|
|
|
2022-09-30 18:33:00 +00:00
|
|
|
context 'when attachments size maximum' do
|
|
|
|
let(:message) { build(:message, content_type: nil, account: create(:account)) }
|
|
|
|
|
|
|
|
it 'add errors to message for attachment size is more than allowed limit' do
|
|
|
|
16.times.each do
|
|
|
|
attachment = message.attachments.new(account_id: message.account_id, file_type: :image)
|
|
|
|
attachment.file.attach(io: File.open(Rails.root.join('spec/assets/avatar.png')), filename: 'avatar.png', content_type: 'image/png')
|
|
|
|
end
|
|
|
|
|
|
|
|
expect(message.errors.messages).to eq({ attachments: ['exceeded maximum allowed'] })
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-02-15 11:41:28 +00:00
|
|
|
context 'when email notifiable message' do
|
|
|
|
let(:message) { build(:message, content_type: nil, account: create(:account)) }
|
|
|
|
|
|
|
|
it 'return false if private message' do
|
|
|
|
message.private = true
|
2022-02-15 12:45:45 +00:00
|
|
|
message.message_type = 'outgoing'
|
2022-02-15 11:41:28 +00:00
|
|
|
expect(message.email_notifiable_message?).to be false
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'return false if incoming message' do
|
|
|
|
message.private = false
|
|
|
|
message.message_type = 'incoming'
|
|
|
|
expect(message.email_notifiable_message?).to be false
|
|
|
|
end
|
|
|
|
|
2022-02-15 12:45:45 +00:00
|
|
|
it 'return false if activity message' do
|
|
|
|
message.private = false
|
|
|
|
message.message_type = 'activity'
|
|
|
|
expect(message.email_notifiable_message?).to be false
|
|
|
|
end
|
|
|
|
|
2022-02-15 11:41:28 +00:00
|
|
|
it 'return false if message type is template and content type is not input_csat or text' do
|
|
|
|
message.private = false
|
|
|
|
message.message_type = 'template'
|
|
|
|
message.content_type = 'incoming_email'
|
|
|
|
expect(message.email_notifiable_message?).to be false
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'return true if not private and not incoming and message content type is input_csat or text' do
|
|
|
|
message.private = false
|
|
|
|
message.message_type = 'template'
|
|
|
|
message.content_type = 'text'
|
|
|
|
expect(message.email_notifiable_message?).to be true
|
|
|
|
end
|
|
|
|
end
|
2022-12-08 12:55:24 +00:00
|
|
|
|
|
|
|
context 'when facebook channel with unavailable story link' do
|
|
|
|
let(:instagram_message) { create(:message, :instagram_story_mention) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
# stubbing the request to facebook api during the message creation
|
|
|
|
stub_request(:get, %r{https://graph.facebook.com/.*}).to_return(status: 200, body: {
|
|
|
|
story: { mention: { link: 'http://graph.facebook.com/test-story-mention', id: '17920786367196703' } },
|
|
|
|
from: { username: 'Sender-id-1', id: 'Sender-id-1' },
|
|
|
|
id: 'instagram-message-id-1234'
|
|
|
|
}.to_json, headers: {})
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'deletes the attachment for deleted stories' do
|
|
|
|
expect(instagram_message.attachments.count).to eq 1
|
|
|
|
stub_request(:get, %r{https://graph.facebook.com/.*}).to_return(status: 404)
|
|
|
|
instagram_message.push_event_data
|
|
|
|
expect(instagram_message.reload.attachments.count).to eq 0
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'deletes the attachment for expired stories' do
|
|
|
|
expect(instagram_message.attachments.count).to eq 1
|
|
|
|
# for expired stories, the link will be empty
|
|
|
|
stub_request(:get, %r{https://graph.facebook.com/.*}).to_return(status: 200, body: {
|
|
|
|
story: { mention: { link: '', id: '17920786367196703' } }
|
|
|
|
}.to_json, headers: {})
|
|
|
|
instagram_message.push_event_data
|
|
|
|
expect(instagram_message.reload.attachments.count).to eq 0
|
|
|
|
end
|
|
|
|
end
|
2020-01-09 07:36:40 +00:00
|
|
|
end
|