chore: Handle attachments in Whatsapp Channel (#3299)
send and receive attachments in 360Dialog WhatsApp channels
This commit is contained in:
parent
b3e313a200
commit
a4c87f2052
33 changed files with 422 additions and 45 deletions
3
Gemfile
3
Gemfile
|
@ -144,6 +144,8 @@ group :test do
|
||||||
gem 'cypress-on-rails', '~> 1.0'
|
gem 'cypress-on-rails', '~> 1.0'
|
||||||
# fast cleaning of database
|
# fast cleaning of database
|
||||||
gem 'database_cleaner'
|
gem 'database_cleaner'
|
||||||
|
# mock http calls
|
||||||
|
gem 'webmock'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
|
@ -171,5 +173,4 @@ group :development, :test do
|
||||||
gem 'simplecov', '0.17.1', require: false
|
gem 'simplecov', '0.17.1', require: false
|
||||||
gem 'spring'
|
gem 'spring'
|
||||||
gem 'spring-watcher-listen'
|
gem 'spring-watcher-listen'
|
||||||
gem 'webmock'
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -228,7 +228,7 @@ export default {
|
||||||
return (
|
return (
|
||||||
this.isAWebWidgetInbox ||
|
this.isAWebWidgetInbox ||
|
||||||
this.isAFacebookInbox ||
|
this.isAFacebookInbox ||
|
||||||
this.isATwilioWhatsappChannel ||
|
this.isAWhatsappChannel ||
|
||||||
this.isAPIInbox ||
|
this.isAPIInbox ||
|
||||||
this.isAnEmailChannel ||
|
this.isAnEmailChannel ||
|
||||||
this.isATwilioSMSChannel ||
|
this.isATwilioSMSChannel ||
|
||||||
|
|
|
@ -2,7 +2,12 @@
|
||||||
<div class="wizard-body small-12 medium-9 columns height-auto">
|
<div class="wizard-body small-12 medium-9 columns height-auto">
|
||||||
<page-header
|
<page-header
|
||||||
:header-title="$t('INBOX_MGMT.ADD.AUTH.TITLE')"
|
:header-title="$t('INBOX_MGMT.ADD.AUTH.TITLE')"
|
||||||
:header-content="$t('INBOX_MGMT.ADD.AUTH.DESC')"
|
:header-content="
|
||||||
|
useInstallationName(
|
||||||
|
$t('INBOX_MGMT.ADD.AUTH.DESC'),
|
||||||
|
globalConfig.installationName
|
||||||
|
)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<div class="row channels">
|
<div class="row channels">
|
||||||
<channel-item
|
<channel-item
|
||||||
|
@ -21,12 +26,14 @@ import ChannelItem from 'dashboard/components/widgets/ChannelItem';
|
||||||
import router from '../../../index';
|
import router from '../../../index';
|
||||||
import PageHeader from '../SettingsSubPageHeader';
|
import PageHeader from '../SettingsSubPageHeader';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ChannelItem,
|
ChannelItem,
|
||||||
PageHeader,
|
PageHeader,
|
||||||
},
|
},
|
||||||
|
mixins: [globalConfigMixin],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
enabledFeatures: {},
|
enabledFeatures: {},
|
||||||
|
|
|
@ -43,7 +43,7 @@ class Channel::Telegram < ApplicationRecord
|
||||||
response = HTTParty.get("#{telegram_api_url}/getUserProfilePhotos", query: { user_id: user_id })
|
response = HTTParty.get("#{telegram_api_url}/getUserProfilePhotos", query: { user_id: user_id })
|
||||||
return nil unless response.success?
|
return nil unless response.success?
|
||||||
|
|
||||||
photos = response.parsed_response['result']['photos']
|
photos = response.parsed_response.dig('result', 'photos')
|
||||||
return if photos.blank?
|
return if photos.blank?
|
||||||
|
|
||||||
get_telegram_file_path(photos.first.last['file_id'])
|
get_telegram_file_path(photos.first.last['file_id'])
|
||||||
|
|
|
@ -36,15 +36,19 @@ class Channel::Whatsapp < ApplicationRecord
|
||||||
|
|
||||||
# Extract later into provider Service
|
# Extract later into provider Service
|
||||||
def send_message(phone_number, message)
|
def send_message(phone_number, message)
|
||||||
HTTParty.post(
|
if message.attachments.present?
|
||||||
"#{api_base_path}/messages",
|
send_attachment_message(phone_number, message)
|
||||||
headers: { 'D360-API-KEY': provider_config['api_key'], 'Content-Type': 'application/json' },
|
else
|
||||||
body: {
|
send_text_message(phone_number, message)
|
||||||
to: phone_number,
|
end
|
||||||
text: { body: message },
|
end
|
||||||
type: 'text'
|
|
||||||
}.to_json
|
def media_url(media_id)
|
||||||
)
|
"#{api_base_path}/media/#{media_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def api_headers
|
||||||
|
{ 'D360-API-KEY' => provider_config['api_key'], 'Content-Type' => 'application/json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_24_hour_messaging_window?
|
def has_24_hour_messaging_window?
|
||||||
|
@ -53,6 +57,36 @@ class Channel::Whatsapp < ApplicationRecord
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def send_text_message(phone_number, message)
|
||||||
|
HTTParty.post(
|
||||||
|
"#{api_base_path}/messages",
|
||||||
|
headers: { 'D360-API-KEY': provider_config['api_key'], 'Content-Type': 'application/json' },
|
||||||
|
body: {
|
||||||
|
to: phone_number,
|
||||||
|
text: { body: message.content },
|
||||||
|
type: 'text'
|
||||||
|
}.to_json
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_attachment_message(phone_number, message)
|
||||||
|
attachment = message.attachments.first
|
||||||
|
type = %w[image audio video].include?(attachment.file_type) ? attachment.file_type : 'document'
|
||||||
|
attachment_url = attachment.file_url
|
||||||
|
HTTParty.post(
|
||||||
|
"#{api_base_path}/messages",
|
||||||
|
headers: { 'D360-API-KEY': provider_config['api_key'], 'Content-Type': 'application/json' },
|
||||||
|
body: {
|
||||||
|
'to' => phone_number,
|
||||||
|
'type' => type,
|
||||||
|
type.to_s => {
|
||||||
|
'link': attachment_url,
|
||||||
|
'caption': message.content
|
||||||
|
}
|
||||||
|
}.to_json
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# Extract later into provider Service
|
# Extract later into provider Service
|
||||||
def validate_provider_config
|
def validate_provider_config
|
||||||
response = HTTParty.post(
|
response = HTTParty.post(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Find the various telegram payload samples here: https://core.telegram.org/bots/webhooks#testing-your-bot-with-updates
|
# https://docs.360dialog.com/whatsapp-api/whatsapp-api/media
|
||||||
# https://core.telegram.org/bots/api#available-types
|
# https://developers.facebook.com/docs/whatsapp/api/media/
|
||||||
|
|
||||||
class Whatsapp::IncomingMessageService
|
class Whatsapp::IncomingMessageService
|
||||||
pattr_initialize [:inbox!, :params!]
|
pattr_initialize [:inbox!, :params!]
|
||||||
|
@ -12,7 +12,7 @@ class Whatsapp::IncomingMessageService
|
||||||
|
|
||||||
return if params[:messages].blank?
|
return if params[:messages].blank?
|
||||||
|
|
||||||
@message = @conversation.messages.create(
|
@message = @conversation.messages.build(
|
||||||
content: params[:messages].first.dig(:text, :body),
|
content: params[:messages].first.dig(:text, :body),
|
||||||
account_id: @inbox.account_id,
|
account_id: @inbox.account_id,
|
||||||
inbox_id: @inbox.id,
|
inbox_id: @inbox.id,
|
||||||
|
@ -20,6 +20,7 @@ class Whatsapp::IncomingMessageService
|
||||||
sender: @contact,
|
sender: @contact,
|
||||||
source_id: params[:messages].first[:id].to_s
|
source_id: params[:messages].first[:id].to_s
|
||||||
)
|
)
|
||||||
|
attach_files
|
||||||
@message.save!
|
@message.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,4 +59,31 @@ class Whatsapp::IncomingMessageService
|
||||||
|
|
||||||
@conversation = ::Conversation.create!(conversation_params)
|
@conversation = ::Conversation.create!(conversation_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def file_content_type(file_type)
|
||||||
|
return :image if %w[image sticker].include?(file_type)
|
||||||
|
return :audio if %w[audio voice].include?(file_type)
|
||||||
|
return :video if ['video'].include?(file_type)
|
||||||
|
|
||||||
|
'document'
|
||||||
|
end
|
||||||
|
|
||||||
|
def attach_files
|
||||||
|
message_type = params[:messages].first[:type]
|
||||||
|
return if message_type == 'text'
|
||||||
|
|
||||||
|
attachment_payload = params[:messages].first[message_type.to_sym]
|
||||||
|
attachment_file = Down.download(inbox.channel.media_url(attachment_payload[:id]), headers: inbox.channel.api_headers)
|
||||||
|
|
||||||
|
@message.content ||= attachment_payload[:caption]
|
||||||
|
@message.attachments.new(
|
||||||
|
account_id: @message.account_id,
|
||||||
|
file_type: file_content_type(message_type),
|
||||||
|
file: {
|
||||||
|
io: attachment_file,
|
||||||
|
filename: attachment_file,
|
||||||
|
content_type: attachment_file.content_type
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,6 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_reply
|
def perform_reply
|
||||||
channel.send_message(message.conversation.contact_inbox.source_id, message.content)
|
channel.send_message(message.conversation.contact_inbox.source_id, message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,7 +19,7 @@ describe ::ContactIdentifyAction do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'enques avatar job when avatar url parameter is passed' do
|
it 'enques avatar job when avatar url parameter is passed' do
|
||||||
params = { name: 'test', avatar_url: 'https://via.placeholder.com/250x250.png' }
|
params = { name: 'test', avatar_url: 'https://chatwoot-assets.local/sample.png' }
|
||||||
expect(ContactAvatarJob).to receive(:perform_later).with(contact, params[:avatar_url]).once
|
expect(ContactAvatarJob).to receive(:perform_later).with(contact, params[:avatar_url]).once
|
||||||
described_class.new(contact: contact, params: params).perform
|
described_class.new(contact: contact, params: params).perform
|
||||||
end
|
end
|
||||||
|
|
BIN
spec/assets/sample.mov
Normal file
BIN
spec/assets/sample.mov
Normal file
Binary file not shown.
BIN
spec/assets/sample.mp3
Normal file
BIN
spec/assets/sample.mp3
Normal file
Binary file not shown.
BIN
spec/assets/sample.ogg
Normal file
BIN
spec/assets/sample.ogg
Normal file
Binary file not shown.
198
spec/assets/sample.pdf
Normal file
198
spec/assets/sample.pdf
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
%PDF-1.3
|
||||||
|
%âãÏÓ
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Catalog
|
||||||
|
/Outlines 2 0 R
|
||||||
|
/Pages 3 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Outlines
|
||||||
|
/Count 0
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Pages
|
||||||
|
/Count 2
|
||||||
|
/Kids [ 4 0 R 6 0 R ]
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Page
|
||||||
|
/Parent 3 0 R
|
||||||
|
/Resources <<
|
||||||
|
/Font <<
|
||||||
|
/F1 9 0 R
|
||||||
|
>>
|
||||||
|
/ProcSet 8 0 R
|
||||||
|
>>
|
||||||
|
/MediaBox [0 0 612.0000 792.0000]
|
||||||
|
/Contents 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Length 1074 >>
|
||||||
|
stream
|
||||||
|
2 J
|
||||||
|
BT
|
||||||
|
0 0 0 rg
|
||||||
|
/F1 0027 Tf
|
||||||
|
57.3750 722.2800 Td
|
||||||
|
( A Simple PDF File ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 688.6080 Td
|
||||||
|
( This is a small demonstration .pdf file - ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 664.7040 Td
|
||||||
|
( just for use in the Virtual Mechanics tutorials. More text. And more ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 652.7520 Td
|
||||||
|
( text. And more text. And more text. And more text. ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 628.8480 Td
|
||||||
|
( And more text. And more text. And more text. And more text. And more ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 616.8960 Td
|
||||||
|
( text. And more text. Boring, zzzzz. And more text. And more text. And ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 604.9440 Td
|
||||||
|
( more text. And more text. And more text. And more text. And more text. ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 592.9920 Td
|
||||||
|
( And more text. And more text. ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 569.0880 Td
|
||||||
|
( And more text. And more text. And more text. And more text. And more ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 557.1360 Td
|
||||||
|
( text. And more text. And more text. Even more. Continued on page 2 ...) Tj
|
||||||
|
ET
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Page
|
||||||
|
/Parent 3 0 R
|
||||||
|
/Resources <<
|
||||||
|
/Font <<
|
||||||
|
/F1 9 0 R
|
||||||
|
>>
|
||||||
|
/ProcSet 8 0 R
|
||||||
|
>>
|
||||||
|
/MediaBox [0 0 612.0000 792.0000]
|
||||||
|
/Contents 7 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
7 0 obj
|
||||||
|
<< /Length 676 >>
|
||||||
|
stream
|
||||||
|
2 J
|
||||||
|
BT
|
||||||
|
0 0 0 rg
|
||||||
|
/F1 0027 Tf
|
||||||
|
57.3750 722.2800 Td
|
||||||
|
( Simple PDF File 2 ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 688.6080 Td
|
||||||
|
( ...continued from page 1. Yet more text. And more text. And more text. ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 676.6560 Td
|
||||||
|
( And more text. And more text. And more text. And more text. And more ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 664.7040 Td
|
||||||
|
( text. Oh, how boring typing this stuff. But not as boring as watching ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 652.7520 Td
|
||||||
|
( paint dry. And more text. And more text. And more text. And more text. ) Tj
|
||||||
|
ET
|
||||||
|
BT
|
||||||
|
/F1 0010 Tf
|
||||||
|
69.2500 640.8000 Td
|
||||||
|
( Boring. More, a little more text. The end, and just as well. ) Tj
|
||||||
|
ET
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
8 0 obj
|
||||||
|
[/PDF /Text]
|
||||||
|
endobj
|
||||||
|
|
||||||
|
9 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Font
|
||||||
|
/Subtype /Type1
|
||||||
|
/Name /F1
|
||||||
|
/BaseFont /Helvetica
|
||||||
|
/Encoding /WinAnsiEncoding
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
10 0 obj
|
||||||
|
<<
|
||||||
|
/Creator (Rave \(http://www.nevrona.com/rave\))
|
||||||
|
/Producer (Nevrona Designs)
|
||||||
|
/CreationDate (D:20060301072826)
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 11
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000019 00000 n
|
||||||
|
0000000093 00000 n
|
||||||
|
0000000147 00000 n
|
||||||
|
0000000222 00000 n
|
||||||
|
0000000390 00000 n
|
||||||
|
0000001522 00000 n
|
||||||
|
0000001690 00000 n
|
||||||
|
0000002423 00000 n
|
||||||
|
0000002456 00000 n
|
||||||
|
0000002574 00000 n
|
||||||
|
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/Size 11
|
||||||
|
/Root 1 0 R
|
||||||
|
/Info 10 0 R
|
||||||
|
>>
|
||||||
|
|
||||||
|
startxref
|
||||||
|
2714
|
||||||
|
%%EOF
|
BIN
spec/assets/sample.png
Normal file
BIN
spec/assets/sample.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 522 KiB |
|
@ -199,6 +199,10 @@ describe ::ContactInboxBuilder do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'facebook inbox' do
|
describe 'facebook inbox' do
|
||||||
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
|
end
|
||||||
|
|
||||||
let!(:facebook_channel) { create(:channel_facebook_page, account: account) }
|
let!(:facebook_channel) { create(:channel_facebook_page, account: account) }
|
||||||
let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) }
|
let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) }
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ require 'rails_helper'
|
||||||
describe ::Messages::Facebook::MessageBuilder do
|
describe ::Messages::Facebook::MessageBuilder do
|
||||||
subject(:message_builder) { described_class.new(incoming_fb_text_message, facebook_channel.inbox).perform }
|
subject(:message_builder) { described_class.new(incoming_fb_text_message, facebook_channel.inbox).perform }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
|
end
|
||||||
|
|
||||||
let!(:facebook_channel) { create(:channel_facebook_page) }
|
let!(:facebook_channel) { create(:channel_facebook_page) }
|
||||||
let!(:message_object) { build(:incoming_fb_text_message).to_json }
|
let!(:message_object) { build(:incoming_fb_text_message).to_json }
|
||||||
let!(:incoming_fb_text_message) { Integrations::Facebook::MessageParser.new(message_object) }
|
let!(:incoming_fb_text_message) { Integrations::Facebook::MessageParser.new(message_object) }
|
||||||
|
@ -16,7 +20,7 @@ describe ::Messages::Facebook::MessageBuilder do
|
||||||
first_name: 'Jane',
|
first_name: 'Jane',
|
||||||
last_name: 'Dae',
|
last_name: 'Dae',
|
||||||
account_id: facebook_channel.inbox.account_id,
|
account_id: facebook_channel.inbox.account_id,
|
||||||
profile_pic: 'https://via.placeholder.com/250x250.png'
|
profile_pic: 'https://chatwoot-assets.local/sample.png'
|
||||||
}.with_indifferent_access
|
}.with_indifferent_access
|
||||||
)
|
)
|
||||||
message_builder
|
message_builder
|
||||||
|
|
|
@ -3,6 +3,10 @@ require 'rails_helper'
|
||||||
describe ::Messages::Instagram::MessageBuilder do
|
describe ::Messages::Instagram::MessageBuilder do
|
||||||
subject(:instagram_message_builder) { described_class }
|
subject(:instagram_message_builder) { described_class }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
|
end
|
||||||
|
|
||||||
let!(:account) { create(:account) }
|
let!(:account) { create(:account) }
|
||||||
let!(:instagram_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') }
|
let!(:instagram_channel) { create(:channel_instagram_fb_page, 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) }
|
||||||
|
@ -19,7 +23,7 @@ describe ::Messages::Instagram::MessageBuilder do
|
||||||
name: 'Jane',
|
name: 'Jane',
|
||||||
id: 'Sender-id-1',
|
id: 'Sender-id-1',
|
||||||
account_id: instagram_inbox.account_id,
|
account_id: instagram_inbox.account_id,
|
||||||
profile_pic: 'https://via.placeholder.com/250x250.png'
|
profile_pic: 'https://chatwoot-assets.local/sample.png'
|
||||||
}.with_indifferent_access
|
}.with_indifferent_access
|
||||||
)
|
)
|
||||||
messaging = dm_params[:entry][0]['messaging'][0]
|
messaging = dm_params[:entry][0]['messaging'][0]
|
||||||
|
|
|
@ -1,16 +1,8 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe 'Callbacks API', type: :request do
|
RSpec.describe 'Callbacks API', type: :request do
|
||||||
let(:account) { create(:account) }
|
|
||||||
let(:valid_params) { attributes_for(:channel_facebook_page).merge(inbox_name: 'Test Inbox') }
|
|
||||||
let(:inbox) { create(:inbox, account: account) }
|
|
||||||
let!(:facebook_page) { create(:channel_facebook_page, inbox: inbox, account: account) }
|
|
||||||
|
|
||||||
# Doubles
|
|
||||||
let(:koala_api) { instance_double(Koala::Facebook::API) }
|
|
||||||
let(:koala_oauth) { instance_double(Koala::Facebook::OAuth) }
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
stub_request(:any, /graph.facebook.com/)
|
||||||
# Mock new and return instance doubles defined above
|
# Mock new and return instance doubles defined above
|
||||||
allow(Koala::Facebook::OAuth).to receive(:new).and_return(koala_oauth)
|
allow(Koala::Facebook::OAuth).to receive(:new).and_return(koala_oauth)
|
||||||
allow(Koala::Facebook::API).to receive(:new).and_return(koala_api)
|
allow(Koala::Facebook::API).to receive(:new).and_return(koala_api)
|
||||||
|
@ -22,6 +14,15 @@ RSpec.describe 'Callbacks API', type: :request do
|
||||||
allow(koala_oauth).to receive(:exchange_access_token_info).and_return('access_token' => SecureRandom.hex(10))
|
allow(koala_oauth).to receive(:exchange_access_token_info).and_return('access_token' => SecureRandom.hex(10))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:account) { create(:account) }
|
||||||
|
let!(:facebook_page) { create(:channel_facebook_page, inbox: inbox, account: account) }
|
||||||
|
let(:valid_params) { attributes_for(:channel_facebook_page).merge(inbox_name: 'Test Inbox') }
|
||||||
|
let(:inbox) { create(:inbox, account: account) }
|
||||||
|
|
||||||
|
# Doubles
|
||||||
|
let(:koala_api) { instance_double(Koala::Facebook::API) }
|
||||||
|
let(:koala_oauth) { instance_double(Koala::Facebook::OAuth) }
|
||||||
|
|
||||||
describe 'POST /api/v1/accounts/{account.id}/callbacks/register_facebook_page' do
|
describe 'POST /api/v1/accounts/{account.id}/callbacks/register_facebook_page' do
|
||||||
context 'when it is an unauthenticated user' do
|
context 'when it is an unauthenticated user' do
|
||||||
it 'returns unauthorized' do
|
it 'returns unauthorized' do
|
||||||
|
|
|
@ -4,7 +4,7 @@ FactoryBot.define do
|
||||||
factory :bot_message_card, class: Hash do
|
factory :bot_message_card, class: Hash do
|
||||||
title { Faker::Book.name }
|
title { Faker::Book.name }
|
||||||
description { Faker::Movie.quote }
|
description { Faker::Movie.quote }
|
||||||
media_url { 'https://via.placeholder.com/250x250.png' }
|
media_url { 'https://chatwoot-assets.local/sample.png' }
|
||||||
actions do
|
actions do
|
||||||
[{
|
[{
|
||||||
text: 'Select',
|
text: 'Select',
|
||||||
|
|
|
@ -22,12 +22,12 @@ FactoryBot.define do
|
||||||
'1' => {
|
'1' => {
|
||||||
id: '1',
|
id: '1',
|
||||||
name: 'person 1',
|
name: 'person 1',
|
||||||
profile_image_url: 'https://via.placeholder.com/250x250.png'
|
profile_image_url: 'https://chatwoot-assets.local/sample.png'
|
||||||
},
|
},
|
||||||
'2' => {
|
'2' => {
|
||||||
id: '1',
|
id: '1',
|
||||||
name: 'person 1',
|
name: 'person 1',
|
||||||
profile_image_url: 'https://via.placeholder.com/250x250.png'
|
profile_image_url: 'https://chatwoot-assets.local/sample.png'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,7 @@ RSpec.describe SendReplyJob, type: :job do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'calls Facebook::SendOnFacebookService when its facebook message' do
|
it 'calls Facebook::SendOnFacebookService when its facebook message' do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
facebook_channel = create(:channel_facebook_page)
|
facebook_channel = create(:channel_facebook_page)
|
||||||
facebook_inbox = create(:inbox, channel: facebook_channel)
|
facebook_inbox = create(:inbox, channel: facebook_channel)
|
||||||
message = create(:message, conversation: create(:conversation, inbox: facebook_inbox))
|
message = create(:message, conversation: create(:conversation, inbox: facebook_inbox))
|
||||||
|
@ -66,6 +67,7 @@ RSpec.describe SendReplyJob, type: :job do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'calls ::Whatsapp:SendOnWhatsappService when its line message' do
|
it 'calls ::Whatsapp:SendOnWhatsappService when its line message' do
|
||||||
|
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
|
||||||
whatsapp_channel = create(:channel_whatsapp)
|
whatsapp_channel = create(:channel_whatsapp)
|
||||||
message = create(:message, conversation: create(:conversation, inbox: whatsapp_channel.inbox))
|
message = create(:message, conversation: create(:conversation, inbox: whatsapp_channel.inbox))
|
||||||
allow(::Whatsapp::SendOnWhatsappService).to receive(:new).with(message: message).and_return(process_service)
|
allow(::Whatsapp::SendOnWhatsappService).to receive(:new).with(message: message).and_return(process_service)
|
||||||
|
|
|
@ -4,6 +4,10 @@ require 'webhooks/twitter'
|
||||||
describe Webhooks::InstagramEventsJob do
|
describe Webhooks::InstagramEventsJob do
|
||||||
subject(:instagram_webhook) { described_class }
|
subject(:instagram_webhook) { described_class }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
|
end
|
||||||
|
|
||||||
let!(:account) { create(:account) }
|
let!(:account) { create(:account) }
|
||||||
let!(:instagram_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') }
|
let!(:instagram_channel) { create(:channel_instagram_fb_page, 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) }
|
||||||
|
@ -20,7 +24,7 @@ describe Webhooks::InstagramEventsJob do
|
||||||
name: 'Jane',
|
name: 'Jane',
|
||||||
id: 'Sender-id-1',
|
id: 'Sender-id-1',
|
||||||
account_id: instagram_inbox.account_id,
|
account_id: instagram_inbox.account_id,
|
||||||
profile_pic: 'https://via.placeholder.com/250x250.png'
|
profile_pic: 'https://chatwoot-assets.local/sample.png'
|
||||||
}.with_indifferent_access
|
}.with_indifferent_access
|
||||||
)
|
)
|
||||||
instagram_webhook.perform_now(dm_params[:entry])
|
instagram_webhook.perform_now(dm_params[:entry])
|
||||||
|
@ -39,7 +43,7 @@ describe Webhooks::InstagramEventsJob do
|
||||||
name: 'Jane',
|
name: 'Jane',
|
||||||
id: 'Sender-id-1',
|
id: 'Sender-id-1',
|
||||||
account_id: instagram_inbox.account_id,
|
account_id: instagram_inbox.account_id,
|
||||||
profile_pic: 'https://via.placeholder.com/250x250.png'
|
profile_pic: 'https://chatwoot-assets.local/sample.png'
|
||||||
}.with_indifferent_access
|
}.with_indifferent_access
|
||||||
)
|
)
|
||||||
instagram_webhook.perform_now(test_params[:entry])
|
instagram_webhook.perform_now(test_params[:entry])
|
||||||
|
|
|
@ -10,6 +10,14 @@ describe Integrations::Slack::IncomingMessageBuilder do
|
||||||
let!(:hook) { create(:integrations_hook, account: account, reference_id: message_params[:event][:channel]) }
|
let!(:hook) { create(:integrations_hook, account: account, reference_id: message_params[:event][:channel]) }
|
||||||
let!(:conversation) { create(:conversation, identifier: message_params[:event][:thread_ts]) }
|
let!(:conversation) { create(:conversation, identifier: message_params[:event][:thread_ts]) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_request(:get, 'https://chatwoot-assets.local/sample.png').to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.read('spec/assets/sample.png'),
|
||||||
|
headers: {}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
context 'when url verification' do
|
context 'when url verification' do
|
||||||
it 'return challenge code as response' do
|
it 'return challenge code as response' do
|
||||||
|
|
|
@ -25,6 +25,10 @@ RSpec.describe AdministratorNotifications::ChannelNotificationsMailer, type: :ma
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'facebook_disconnect' do
|
describe 'facebook_disconnect' do
|
||||||
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
|
end
|
||||||
|
|
||||||
let!(:facebook_channel) { create(:channel_facebook_page, account: account) }
|
let!(:facebook_channel) { create(:channel_facebook_page, account: account) }
|
||||||
let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) }
|
let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) }
|
||||||
let(:mail) { described_class.with(account: account).facebook_disconnect(facebook_inbox).deliver_now }
|
let(:mail) { described_class.with(account: account).facebook_disconnect(facebook_inbox).deliver_now }
|
||||||
|
|
|
@ -22,6 +22,10 @@ RSpec.describe Campaign, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when Inbox other then Website or Twilio SMS' do
|
context 'when Inbox other then Website or Twilio SMS' do
|
||||||
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
|
end
|
||||||
|
|
||||||
let!(:facebook_channel) { create(:channel_facebook_page) }
|
let!(:facebook_channel) { create(:channel_facebook_page) }
|
||||||
let!(:facebook_inbox) { create(:inbox, channel: facebook_channel) }
|
let!(:facebook_inbox) { create(:inbox, channel: facebook_channel) }
|
||||||
let(:campaign) { build(:campaign, inbox: facebook_inbox) }
|
let(:campaign) { build(:campaign, inbox: facebook_inbox) }
|
||||||
|
|
|
@ -4,6 +4,10 @@ require 'rails_helper'
|
||||||
require Rails.root.join 'spec/models/concerns/reauthorizable_shared.rb'
|
require Rails.root.join 'spec/models/concerns/reauthorizable_shared.rb'
|
||||||
|
|
||||||
RSpec.describe Channel::FacebookPage do
|
RSpec.describe Channel::FacebookPage do
|
||||||
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
|
end
|
||||||
|
|
||||||
let(:channel) { create(:channel_facebook_page) }
|
let(:channel) { create(:channel_facebook_page) }
|
||||||
|
|
||||||
it { is_expected.to validate_presence_of(:account_id) }
|
it { is_expected.to validate_presence_of(:account_id) }
|
||||||
|
|
|
@ -394,6 +394,10 @@ RSpec.describe Conversation, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'on channels with 24 hour restriction' do
|
describe 'on channels with 24 hour restriction' do
|
||||||
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
|
end
|
||||||
|
|
||||||
let!(:facebook_channel) { create(:channel_facebook_page) }
|
let!(:facebook_channel) { create(:channel_facebook_page) }
|
||||||
let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: facebook_channel.account) }
|
let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: facebook_channel.account) }
|
||||||
let!(:conversation) { create(:conversation, inbox: facebook_inbox, account: facebook_channel.account) }
|
let!(:conversation) { create(:conversation, inbox: facebook_inbox, account: facebook_channel.account) }
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Contacts::ContactableInboxesService do
|
describe Contacts::ContactableInboxesService do
|
||||||
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
|
end
|
||||||
|
|
||||||
let(:account) { create(:account) }
|
let(:account) { create(:account) }
|
||||||
let(:contact) { create(:contact, account: account, email: 'contact@example.com', phone_number: '+2320000') }
|
let(:contact) { create(:contact, account: account, email: 'contact@example.com', phone_number: '+2320000') }
|
||||||
let!(:twilio_sms) { create(:channel_twilio_sms, account: account) }
|
let!(:twilio_sms) { create(:channel_twilio_sms, account: account) }
|
||||||
|
|
|
@ -4,6 +4,7 @@ describe Instagram::SendOnInstagramService do
|
||||||
subject(:send_reply_service) { described_class.new(message: message) }
|
subject(:send_reply_service) { described_class.new(message: message) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
stub_request(:post, /graph.facebook.com/)
|
||||||
create(:message, message_type: :incoming, inbox: instagram_inbox, account: account, conversation: conversation)
|
create(:message, message_type: :incoming, inbox: instagram_inbox, account: account, conversation: conversation)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,35 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Telegram::IncomingMessageService do
|
describe Telegram::IncomingMessageService do
|
||||||
|
before do
|
||||||
|
stub_request(:any, /api.telegram.org/).to_return(headers: { content_type: 'application/json' }, body: {}.to_json, status: 200)
|
||||||
|
stub_request(:get, 'https://chatwoot-assets.local/sample.png').to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.read('spec/assets/sample.png'),
|
||||||
|
headers: {}
|
||||||
|
)
|
||||||
|
stub_request(:get, 'https://chatwoot-assets.local/sample.mov').to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.read('spec/assets/sample.mov'),
|
||||||
|
headers: {}
|
||||||
|
)
|
||||||
|
stub_request(:get, 'https://chatwoot-assets.local/sample.mp3').to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.read('spec/assets/sample.mp3'),
|
||||||
|
headers: {}
|
||||||
|
)
|
||||||
|
stub_request(:get, 'https://chatwoot-assets.local/sample.ogg').to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.read('spec/assets/sample.ogg'),
|
||||||
|
headers: {}
|
||||||
|
)
|
||||||
|
stub_request(:get, 'https://chatwoot-assets.local/sample.pdf').to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.read('spec/assets/sample.pdf'),
|
||||||
|
headers: {}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
let!(:telegram_channel) { create(:channel_telegram) }
|
let!(:telegram_channel) { create(:channel_telegram) }
|
||||||
|
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
|
@ -64,7 +93,7 @@ describe Telegram::IncomingMessageService do
|
||||||
|
|
||||||
context 'when valid audio messages params' do
|
context 'when valid audio messages params' do
|
||||||
it 'creates appropriate conversations, message and contacts' do
|
it 'creates appropriate conversations, message and contacts' do
|
||||||
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.mp3')
|
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.mp3')
|
||||||
params = {
|
params = {
|
||||||
'update_id' => 2_342_342_343_242,
|
'update_id' => 2_342_342_343_242,
|
||||||
'message' => {
|
'message' => {
|
||||||
|
@ -92,7 +121,7 @@ describe Telegram::IncomingMessageService do
|
||||||
|
|
||||||
context 'when valid image attachment params' do
|
context 'when valid image attachment params' do
|
||||||
it 'creates appropriate conversations, message and contacts' do
|
it 'creates appropriate conversations, message and contacts' do
|
||||||
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.png')
|
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.png')
|
||||||
params = {
|
params = {
|
||||||
'update_id' => 2_342_342_343_242,
|
'update_id' => 2_342_342_343_242,
|
||||||
'message' => {
|
'message' => {
|
||||||
|
@ -117,7 +146,7 @@ describe Telegram::IncomingMessageService do
|
||||||
|
|
||||||
context 'when valid sticker attachment params' do
|
context 'when valid sticker attachment params' do
|
||||||
it 'creates appropriate conversations, message and contacts' do
|
it 'creates appropriate conversations, message and contacts' do
|
||||||
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.png')
|
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.png')
|
||||||
params = {
|
params = {
|
||||||
'update_id' => 2_342_342_343_242,
|
'update_id' => 2_342_342_343_242,
|
||||||
'message' => {
|
'message' => {
|
||||||
|
@ -147,7 +176,7 @@ describe Telegram::IncomingMessageService do
|
||||||
|
|
||||||
context 'when valid video messages params' do
|
context 'when valid video messages params' do
|
||||||
it 'creates appropriate conversations, message and contacts' do
|
it 'creates appropriate conversations, message and contacts' do
|
||||||
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.mov')
|
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.mov')
|
||||||
params = {
|
params = {
|
||||||
'update_id' => 2_342_342_343_242,
|
'update_id' => 2_342_342_343_242,
|
||||||
'message' => {
|
'message' => {
|
||||||
|
@ -175,7 +204,7 @@ describe Telegram::IncomingMessageService do
|
||||||
|
|
||||||
context 'when valid voice attachment params' do
|
context 'when valid voice attachment params' do
|
||||||
it 'creates appropriate conversations, message and contacts' do
|
it 'creates appropriate conversations, message and contacts' do
|
||||||
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.oga')
|
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.ogg')
|
||||||
params = {
|
params = {
|
||||||
'update_id' => 2_342_342_343_242,
|
'update_id' => 2_342_342_343_242,
|
||||||
'message' => {
|
'message' => {
|
||||||
|
@ -200,7 +229,7 @@ describe Telegram::IncomingMessageService do
|
||||||
|
|
||||||
context 'when valid document message params' do
|
context 'when valid document message params' do
|
||||||
it 'creates appropriate conversations, message and contacts' do
|
it 'creates appropriate conversations, message and contacts' do
|
||||||
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.pdf')
|
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.pdf')
|
||||||
params = {
|
params = {
|
||||||
'update_id' => 2_342_342_343_242,
|
'update_id' => 2_342_342_343_242,
|
||||||
'message' => {
|
'message' => {
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Whatsapp::IncomingMessageService do
|
describe Whatsapp::IncomingMessageService do
|
||||||
|
describe '#perform' do
|
||||||
|
before do
|
||||||
|
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
|
||||||
|
end
|
||||||
|
|
||||||
let!(:whatsapp_channel) { create(:channel_whatsapp) }
|
let!(:whatsapp_channel) { create(:channel_whatsapp) }
|
||||||
|
|
||||||
describe '#perform' do
|
|
||||||
context 'when valid text message params' do
|
context 'when valid text message params' do
|
||||||
it 'creates appropriate conversations, message and contacts' do
|
it 'creates appropriate conversations, message and contacts' do
|
||||||
params = {
|
params = {
|
||||||
|
@ -17,5 +21,29 @@ describe Whatsapp::IncomingMessageService do
|
||||||
expect(whatsapp_channel.inbox.messages.first.content).to eq('Test')
|
expect(whatsapp_channel.inbox.messages.first.content).to eq('Test')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when valid attachment message params' do
|
||||||
|
it 'creates appropriate conversations, message and contacts' do
|
||||||
|
stub_request(:get, whatsapp_channel.media_url('b1c68f38-8734-4ad3-b4a1-ef0c10d683')).to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.read('spec/assets/sample.png'),
|
||||||
|
headers: {}
|
||||||
|
)
|
||||||
|
params = {
|
||||||
|
'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }],
|
||||||
|
'messages' => [{ 'from' => '2423423243', 'id' => 'SDFADSf23sfasdafasdfa',
|
||||||
|
'image' => { 'id' => 'b1c68f38-8734-4ad3-b4a1-ef0c10d683',
|
||||||
|
'mime_type' => 'image/jpeg',
|
||||||
|
'sha256' => '29ed500fa64eb55fc19dc4124acb300e5dcca0f822a301ae99944db',
|
||||||
|
'caption' => 'Check out my product!' },
|
||||||
|
'timestamp' => '1633034394', 'type' => 'image' }]
|
||||||
|
}.with_indifferent_access
|
||||||
|
described_class.new(inbox: whatsapp_channel.inbox, params: params).perform
|
||||||
|
expect(whatsapp_channel.inbox.conversations.count).not_to eq(0)
|
||||||
|
expect(Contact.all.first.name).to eq('Sojan Jose')
|
||||||
|
expect(whatsapp_channel.inbox.messages.first.content).to eq('Check out my product!')
|
||||||
|
expect(whatsapp_channel.inbox.messages.first.attachments.present?).to eq true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,10 @@ require 'rails_helper'
|
||||||
|
|
||||||
describe Whatsapp::SendOnWhatsappService do
|
describe Whatsapp::SendOnWhatsappService do
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
|
before do
|
||||||
|
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
|
||||||
|
end
|
||||||
|
|
||||||
context 'when a valid message' do
|
context 'when a valid message' do
|
||||||
it 'calls channel.send_message' do
|
it 'calls channel.send_message' do
|
||||||
whatsapp_request = double
|
whatsapp_request = double
|
||||||
|
|
|
@ -2,7 +2,7 @@ require 'simplecov'
|
||||||
require 'webmock/rspec'
|
require 'webmock/rspec'
|
||||||
|
|
||||||
SimpleCov.start 'rails'
|
SimpleCov.start 'rails'
|
||||||
WebMock.allow_net_connect!
|
WebMock.disable_net_connect!(allow_localhost: true)
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.expect_with :rspec do |expectations|
|
config.expect_with :rspec do |expectations|
|
||||||
|
|
|
@ -78,11 +78,11 @@ module SlackStubs
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
mimetype: 'image/png',
|
mimetype: 'image/png',
|
||||||
url_private: 'https://via.placeholder.com/250x250.png',
|
url_private: 'https://chatwoot-assets.local/sample.png',
|
||||||
name: 'name_of_the_file',
|
name: 'name_of_the_file',
|
||||||
title: 'title_of_the_file',
|
title: 'title_of_the_file',
|
||||||
filetype: 'png',
|
filetype: 'png',
|
||||||
url_private_download: 'https://via.placeholder.com/250x250.png'
|
url_private_download: 'https://chatwoot-assets.local/sample.png'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue