Restructure omni services and add Chatwoot research snapshot
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/campaigns', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let!(:campaign_1) { create(:campaign, inbox: web_widget.inbox, enabled: true, account: account, trigger_rules: { url: 'https://test.com' }) }
|
||||
let!(:campaign_2) { create(:campaign, inbox: web_widget.inbox, enabled: false, account: account, trigger_rules: { url: 'https://test.com' }) }
|
||||
|
||||
describe 'GET /api/v1/widget/campaigns' do
|
||||
let(:params) { { website_token: web_widget.website_token } }
|
||||
|
||||
context 'when campaigns feature is enabled' do
|
||||
before do
|
||||
account.enable_features!('campaigns')
|
||||
end
|
||||
|
||||
it 'returns the list of enabled campaigns' do
|
||||
get '/api/v1/widget/campaigns', params: params
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response.length).to eq 1
|
||||
expect(json_response.pluck('id')).to include(campaign_1.display_id)
|
||||
expect(json_response.pluck('id')).not_to include(campaign_2.display_id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when campaigns feature is disabled' do
|
||||
before do
|
||||
account.disable_features!('campaigns')
|
||||
end
|
||||
|
||||
it 'returns empty array' do
|
||||
get '/api/v1/widget/campaigns', params: params
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response).to eq []
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns not found status' do
|
||||
get '/api/v1/widget/campaigns', params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,78 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/config', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let!(:contact) { create(:contact, account: account) }
|
||||
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
|
||||
let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } }
|
||||
let(:token) { Widget::TokenService.new(payload: payload).generate_token }
|
||||
|
||||
describe 'POST /api/v1/widget/config' do
|
||||
let(:params) { { website_token: web_widget.website_token } }
|
||||
let(:response_keys) { %w[website_channel_config contact global_config] }
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns not found' do
|
||||
post '/api/v1/widget/config', params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with correct website token and missing X-Auth-Token' do
|
||||
it 'returns widget config along with a new contact' do
|
||||
expect do
|
||||
post '/api/v1/widget/config',
|
||||
params: params,
|
||||
as: :json
|
||||
end.to change(Contact, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = response.parsed_body
|
||||
expect(response_data.keys).to include(*response_keys)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with correct website token and valid X-Auth-Token' do
|
||||
it 'returns widget config along with the same contact' do
|
||||
expect do
|
||||
post '/api/v1/widget/config',
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
end.not_to change(Contact, :count)
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = response.parsed_body
|
||||
expect(response_data.keys).to include(*response_keys)
|
||||
expect(response_data['contact']['pubsub_token']).to eq(contact_inbox.pubsub_token)
|
||||
end
|
||||
|
||||
it 'returns 401 if account is suspended' do
|
||||
account.update!(status: :suspended)
|
||||
|
||||
post '/api/v1/widget/config',
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with correct website token and invalid X-Auth-Token' do
|
||||
it 'returns widget config and new contact with error message' do
|
||||
expect do
|
||||
post '/api/v1/widget/config',
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => 'invalid token' },
|
||||
as: :json
|
||||
end.to change(Contact, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = response.parsed_body
|
||||
expect(response_data.keys).to include(*response_keys)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,209 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/contacts', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let(:contact) { create(:contact, account: account, email: 'test@test.com', phone_number: '+745623239') }
|
||||
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
|
||||
let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } }
|
||||
let(:token) { Widget::TokenService.new(payload: payload).generate_token }
|
||||
|
||||
describe 'PATCH /api/v1/widget/contact' do
|
||||
let(:params) { { website_token: web_widget.website_token, identifier: 'test' } }
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns unauthorized' do
|
||||
patch '/api/v1/widget/contact', params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with correct website token' do
|
||||
let(:identify_action) { double }
|
||||
|
||||
before do
|
||||
allow(ContactIdentifyAction).to receive(:new).and_return(identify_action)
|
||||
allow(identify_action).to receive(:perform).and_return(contact)
|
||||
end
|
||||
|
||||
it 'calls contact identify' do
|
||||
patch '/api/v1/widget/contact',
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expected_params = { contact: contact, params: params, discard_invalid_attrs: true }
|
||||
expect(ContactIdentifyAction).to have_received(:new).with(expected_params)
|
||||
expect(identify_action).to have_received(:perform)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with update contact' do
|
||||
let(:params) { { website_token: web_widget.website_token } }
|
||||
|
||||
it 'dont update phone number if invalid phone number passed' do
|
||||
patch '/api/v1/widget/contact',
|
||||
params: params.merge({ phone_number: '45623239' }),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
body = response.parsed_body
|
||||
expect(body['has_phone_number']).to be true
|
||||
contact.reload
|
||||
expect(contact.phone_number).to eq('+745623239')
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'update phone number if valid phone number passed' do
|
||||
patch '/api/v1/widget/contact',
|
||||
params: params.merge({ phone_number: '+245623239' }),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
body = response.parsed_body
|
||||
expect(body['has_phone_number']).to be true
|
||||
contact.reload
|
||||
expect(contact.phone_number).to eq('+245623239')
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'dont update email if invalid email passed' do
|
||||
patch '/api/v1/widget/contact',
|
||||
params: params.merge({ email: 'test@' }),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
body = response.parsed_body
|
||||
expect(body['has_email']).to be true
|
||||
contact.reload
|
||||
expect(contact.email).to eq('test@test.com')
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'dont update email if empty value email passed' do
|
||||
patch '/api/v1/widget/contact',
|
||||
params: params.merge({ email: '' }),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
body = response.parsed_body
|
||||
expect(body['has_email']).to be true
|
||||
contact.reload
|
||||
expect(contact.email).to eq('test@test.com')
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'dont update email if nil value email passed' do
|
||||
patch '/api/v1/widget/contact',
|
||||
params: params.merge({ email: nil }),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
body = response.parsed_body
|
||||
expect(body['has_email']).to be true
|
||||
contact.reload
|
||||
expect(contact.email).to eq('test@test.com')
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'update email if valid email passed' do
|
||||
patch '/api/v1/widget/contact',
|
||||
params: params.merge({ email: 'test-1@test.com' }),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
body = response.parsed_body
|
||||
expect(body['has_email']).to be true
|
||||
contact.reload
|
||||
expect(contact.email).to eq('test-1@test.com')
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH /api/v1/widget/contact/set_user' do
|
||||
let(:params) { { website_token: web_widget.website_token, identifier: 'test' } }
|
||||
let(:web_widget) { create(:channel_widget, account: account, hmac_mandatory: true) }
|
||||
let(:correct_identifier_hash) { OpenSSL::HMAC.hexdigest('sha256', web_widget.hmac_token, params[:identifier].to_s) }
|
||||
let(:incorrect_identifier_hash) { 'test' }
|
||||
|
||||
context 'when the current contact identifier is different from param identifier' do
|
||||
before do
|
||||
contact.update(identifier: 'random')
|
||||
end
|
||||
|
||||
it 'return a new contact for the provided identifier' do
|
||||
patch '/api/v1/widget/contact/set_user',
|
||||
params: params.merge(identifier_hash: correct_identifier_hash),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
body = response.parsed_body
|
||||
expect(body['id']).not_to eq(contact.id)
|
||||
expect(body['widget_auth_token']).not_to be_nil
|
||||
expect(Contact.find(body['id']).contact_inboxes.first.hmac_verified?).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with mandatory hmac' do
|
||||
let(:identify_action) { double }
|
||||
|
||||
before do
|
||||
allow(ContactIdentifyAction).to receive(:new).and_return(identify_action)
|
||||
allow(identify_action).to receive(:perform).and_return(contact)
|
||||
end
|
||||
|
||||
it 'returns success when correct identifier hash is provided' do
|
||||
patch '/api/v1/widget/contact/set_user',
|
||||
params: params.merge(identifier_hash: correct_identifier_hash),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'returns error when incorrect identifier hash is provided' do
|
||||
patch '/api/v1/widget/contact/set_user',
|
||||
params: params.merge(identifier_hash: incorrect_identifier_hash),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns error when identifier hash is blank' do
|
||||
patch '/api/v1/widget/contact/set_user',
|
||||
params: params.merge(identifier_hash: ''),
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns error when identifier hash is not provided' do
|
||||
patch '/api/v1/widget/contact/set_user',
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/widget/destroy_custom_attributes' do
|
||||
let(:params) { { website_token: web_widget.website_token, identifier: 'test', custom_attributes: ['test'] } }
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns unauthorized' do
|
||||
post '/api/v1/widget/destroy_custom_attributes', params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with correct website token' do
|
||||
it 'calls destroy custom attributes' do
|
||||
post '/api/v1/widget/destroy_custom_attributes',
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
expect(contact.reload.custom_attributes).to eq({})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,334 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/conversations/toggle_typing', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let(:contact) { create(:contact, account: account, email: nil) }
|
||||
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
|
||||
let(:second_session) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
|
||||
let!(:conversation) { create(:conversation, contact: contact, account: account, inbox: web_widget.inbox, contact_inbox: contact_inbox) }
|
||||
let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } }
|
||||
let(:token) { Widget::TokenService.new(payload: payload).generate_token }
|
||||
let(:token_without_conversation) do
|
||||
Widget::TokenService.new(payload: { source_id: second_session.source_id, inbox_id: web_widget.inbox.id }).generate_token
|
||||
end
|
||||
|
||||
def conversation_params
|
||||
{
|
||||
website_token: web_widget.website_token,
|
||||
contact: {
|
||||
name: 'contact-name',
|
||||
email: 'contact-email@chatwoot.com',
|
||||
phone_number: '+919745313456'
|
||||
},
|
||||
message: {
|
||||
content: 'This is a test message'
|
||||
},
|
||||
custom_attributes: { order_id: '12345' }
|
||||
}
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/widget/conversations' do
|
||||
context 'with a conversation' do
|
||||
it 'returns the correct conversation params' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
get '/api/v1/widget/conversations',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: { website_token: web_widget.website_token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
|
||||
expect(json_response['id']).to eq(conversation.display_id)
|
||||
expect(json_response['status']).to eq(conversation.status)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a conversation but invalid source id' do
|
||||
it 'returns the correct conversation params' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
|
||||
payload = { source_id: 'invalid source id', inbox_id: web_widget.inbox.id }
|
||||
token = Widget::TokenService.new(payload: payload).generate_token
|
||||
get '/api/v1/widget/conversations',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: { website_token: web_widget.website_token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/widget/conversations' do
|
||||
it 'creates a conversation with correct details' do
|
||||
post '/api/v1/widget/conversations',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: conversation_params,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['id']).not_to be_nil
|
||||
expect(json_response['contact']['email']).to eq 'contact-email@chatwoot.com'
|
||||
expect(json_response['contact']['phone_number']).to eq '+919745313456'
|
||||
expect(json_response['contact']['name']).to eq 'contact-name'
|
||||
end
|
||||
|
||||
it 'creates a conversation with correct message and custom attributes' do
|
||||
post '/api/v1/widget/conversations',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: conversation_params,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['custom_attributes']['order_id']).to eq '12345'
|
||||
expect(json_response['messages'][0]['content']).to eq 'This is a test message'
|
||||
expect(json_response['messages'][0]['message_type']).to eq 0
|
||||
end
|
||||
|
||||
it 'create a conversation with a name and without an email' do
|
||||
post '/api/v1/widget/conversations',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: {
|
||||
website_token: web_widget.website_token,
|
||||
contact: {
|
||||
name: 'alphy'
|
||||
},
|
||||
message: {
|
||||
content: 'This is a test message'
|
||||
}
|
||||
},
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['id']).not_to be_nil
|
||||
expect(json_response['contact']['email']).to be_nil
|
||||
expect(json_response['contact']['name']).to eq 'alphy'
|
||||
expect(json_response['messages'][0]['content']).to eq 'This is a test message'
|
||||
end
|
||||
|
||||
it 'does not update the name if the contact already exist' do
|
||||
existing_contact = create(:contact, account: account, email: 'contact-email@chatwoot.com')
|
||||
|
||||
post '/api/v1/widget/conversations',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: {
|
||||
website_token: web_widget.website_token,
|
||||
contact: {
|
||||
name: 'contact-name',
|
||||
email: existing_contact.email,
|
||||
phone_number: '+919745313456'
|
||||
},
|
||||
message: {
|
||||
content: 'This is a test message'
|
||||
},
|
||||
custom_attributes: { order_id: '12345' }
|
||||
},
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['id']).not_to be_nil
|
||||
expect(json_response['contact']['email']).to eq existing_contact.email
|
||||
expect(json_response['contact']['name']).not_to eq 'contact-name'
|
||||
expect(json_response['contact']['phone_number']).to eq '+919745313456'
|
||||
expect(json_response['custom_attributes']['order_id']).to eq '12345'
|
||||
expect(json_response['messages'][0]['content']).to eq 'This is a test message'
|
||||
end
|
||||
|
||||
it 'doesnt not add phone number if the invalid phone number is provided' do
|
||||
existing_contact = create(:contact, account: account)
|
||||
|
||||
post '/api/v1/widget/conversations',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: {
|
||||
website_token: web_widget.website_token,
|
||||
contact: {
|
||||
name: 'contact-name-1',
|
||||
email: existing_contact.email,
|
||||
phone_number: '13456'
|
||||
},
|
||||
message: {
|
||||
content: 'This is a test message'
|
||||
}
|
||||
},
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['contact']['phone_number']).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/widget/conversations/toggle_typing' do
|
||||
context 'with a conversation' do
|
||||
it 'dispatches the correct typing status' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
post '/api/v1/widget/conversations/toggle_typing',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: { typing_status: 'on', website_token: web_widget.website_token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||
.with(Conversation::CONVERSATION_TYPING_ON, kind_of(Time), { conversation: conversation, user: contact })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/widget/conversations/update_last_seen' do
|
||||
context 'with a conversation' do
|
||||
it 'returns the correct conversation params' do
|
||||
current_time = DateTime.now.utc
|
||||
allow(DateTime).to receive(:now).and_return(current_time)
|
||||
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
expect(conversation.contact_last_seen_at).to be_nil
|
||||
expect(Conversations::UpdateMessageStatusJob).to receive(:perform_later).with(conversation.id, current_time)
|
||||
|
||||
post '/api/v1/widget/conversations/update_last_seen',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: { website_token: web_widget.website_token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
|
||||
expect(conversation.reload.contact_last_seen_at).not_to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/widget/conversations/transcript' do
|
||||
context 'with a conversation' do
|
||||
it 'sends transcript email' do
|
||||
contact.update(email: 'test@test.com')
|
||||
mailer = double
|
||||
allow(ConversationReplyMailer).to receive(:with).and_return(mailer)
|
||||
allow(mailer).to receive(:conversation_transcript)
|
||||
|
||||
post '/api/v1/widget/conversations/transcript',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: { website_token: web_widget.website_token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(mailer).to have_received(:conversation_transcript).with(conversation, 'test@test.com')
|
||||
contact.update(email: nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/widget/conversations/toggle_status' do
|
||||
context 'when user end conversation from widget' do
|
||||
it 'resolves the conversation' do
|
||||
expect(conversation.open?).to be true
|
||||
|
||||
get '/api/v1/widget/conversations/toggle_status',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: { website_token: web_widget.website_token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(conversation.reload.resolved?).to be true
|
||||
expect(Conversations::ActivityMessageJob).to have_been_enqueued.at_least(:once).with(
|
||||
conversation,
|
||||
{
|
||||
account_id: conversation.account_id,
|
||||
inbox_id: conversation.inbox_id,
|
||||
message_type: :activity,
|
||||
content: "Conversation was resolved by #{contact.name}"
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when end conversation is not permitted' do
|
||||
before do
|
||||
web_widget.end_conversation = false
|
||||
web_widget.save!
|
||||
end
|
||||
|
||||
it 'returns action not permitted status' do
|
||||
expect(conversation.open?).to be true
|
||||
|
||||
get '/api/v1/widget/conversations/toggle_status',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: { website_token: web_widget.website_token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
expect(conversation.reload.resolved?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a token without any conversation is used' do
|
||||
it 'returns not found status' do
|
||||
get '/api/v1/widget/conversations/toggle_status',
|
||||
headers: { 'X-Auth-Token' => token_without_conversation },
|
||||
params: { website_token: web_widget.website_token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/widget/conversations/set_custom_attributes' do
|
||||
let(:params) { { website_token: web_widget.website_token, custom_attributes: { 'product_name': 'Chatwoot' } } }
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns unauthorized' do
|
||||
post '/api/v1/widget/conversations/set_custom_attributes', params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with correct website token' do
|
||||
it 'sets the values when provided' do
|
||||
post '/api/v1/widget/conversations/set_custom_attributes',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: params,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
conversation.reload
|
||||
# conversation custom attributes should have "product_name" key with value "Chatwoot"
|
||||
expect(conversation.custom_attributes).to include('product_name' => 'Chatwoot')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/widget/conversations/destroy_custom_attributes' do
|
||||
let(:params) { { website_token: web_widget.website_token, custom_attribute: ['product_name'] } }
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns unauthorized' do
|
||||
post '/api/v1/widget/conversations/destroy_custom_attributes', params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with correct website token' do
|
||||
it 'sets the values when provided' do
|
||||
# ensure conversation has the attribute
|
||||
conversation.custom_attributes = { 'product_name': 'Chatwoot' }
|
||||
conversation.save!
|
||||
expect(conversation.custom_attributes).to include('product_name' => 'Chatwoot')
|
||||
|
||||
post '/api/v1/widget/conversations/destroy_custom_attributes',
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: params,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
conversation.reload
|
||||
# conversation custom attributes should not have "product_name" key with value "Chatwoot"
|
||||
expect(conversation.custom_attributes).not_to include('product_name' => 'Chatwoot')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/direct_uploads', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let(:contact) { create(:contact, account: account, email: nil) }
|
||||
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
|
||||
let(:conversation) { create(:conversation, contact: contact, account: account, inbox: web_widget.inbox, contact_inbox: contact_inbox) }
|
||||
let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } }
|
||||
let(:token) { Widget::TokenService.new(payload: payload).generate_token }
|
||||
|
||||
describe 'POST /api/v1/widget/direct_uploads' do
|
||||
context 'when post request is made' do
|
||||
before do
|
||||
token
|
||||
contact
|
||||
payload
|
||||
end
|
||||
|
||||
it 'creates attachment message in conversation' do
|
||||
post api_v1_widget_direct_uploads_url,
|
||||
params: {
|
||||
website_token: web_widget.website_token,
|
||||
blob: {
|
||||
filename: 'avatar.png',
|
||||
byte_size: '1234',
|
||||
checksum: 'dsjbsdhbfif3874823mnsdbf',
|
||||
content_type: 'image/png'
|
||||
}
|
||||
},
|
||||
headers: { 'X-Auth-Token' => token }
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['content_type']).to eq('image/png')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/events', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
|
||||
let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } }
|
||||
let(:token) { Widget::TokenService.new(payload: payload).generate_token }
|
||||
|
||||
describe 'POST /api/v1/widget/events' do
|
||||
let(:params) { { website_token: web_widget.website_token, name: 'webwidget.triggered', event_info: { test_id: 'test' } } }
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns unauthorized' do
|
||||
post '/api/v1/widget/events', params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with correct website token' do
|
||||
before do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
end
|
||||
|
||||
it 'dispatches the webwidget event' do
|
||||
post '/api/v1/widget/events',
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||
.with(params[:name], anything, contact_inbox: contact_inbox,
|
||||
event_info: { test_id: 'test', browser_language: nil, widget_language: nil, browser: anything })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/inbox_members', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let(:agent_1) { create(:user, account: account) }
|
||||
let(:agent_2) { create(:user, account: account) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, user: agent_1, inbox: web_widget.inbox)
|
||||
create(:inbox_member, user: agent_2, inbox: web_widget.inbox)
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/widget/inbox_members' do
|
||||
let(:params) { { website_token: web_widget.website_token } }
|
||||
|
||||
context 'with correct website token' do
|
||||
it 'returns the list of agents' do
|
||||
get '/api/v1/widget/inbox_members', params: params
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['payload'].length).to eq 2
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns the list of agents' do
|
||||
get '/api/v1/widget/inbox_members', params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,74 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/integrations/dyte', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let(:contact) { create(:contact, account: account, email: nil) }
|
||||
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
|
||||
let(:conversation) { create(:conversation, contact: contact, account: account, inbox: web_widget.inbox, contact_inbox: contact_inbox) }
|
||||
let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } }
|
||||
let(:token) { Widget::TokenService.new(payload: payload).generate_token }
|
||||
let(:message) { create(:message, conversation: conversation, account: account, inbox: conversation.inbox) }
|
||||
let!(:integration_message) do
|
||||
create(:message, content_type: 'integrations',
|
||||
content_attributes: { type: 'dyte', data: { meeting_id: 'm_id' } },
|
||||
conversation: conversation, account: account, inbox: conversation.inbox)
|
||||
end
|
||||
|
||||
before do
|
||||
create(:integrations_hook, :dyte, account: account)
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/widget/integrations/dyte/add_participant_to_meeting' do
|
||||
context 'when token is invalid' do
|
||||
it 'returns error' do
|
||||
post add_participant_to_meeting_api_v1_widget_integrations_dyte_url,
|
||||
params: { website_token: web_widget.website_token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when token is valid' do
|
||||
context 'when message is not an integration message' do
|
||||
it 'returns error' do
|
||||
post add_participant_to_meeting_api_v1_widget_integrations_dyte_url,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: { website_token: web_widget.website_token, message_id: message.id },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
response_body = response.parsed_body
|
||||
expect(response_body['error']).to eq('Invalid message type. Action not permitted')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when message is an integration message' do
|
||||
before do
|
||||
stub_request(:post, 'https://api.dyte.io/v2/meetings/m_id/participants')
|
||||
.to_return(
|
||||
status: 200,
|
||||
body: { success: true, data: { id: 'random_uuid', auth_token: 'json-web-token' } }.to_json,
|
||||
headers: { 'Content-Type' => 'application/json' }
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns auth_token' do
|
||||
post add_participant_to_meeting_api_v1_widget_integrations_dyte_url,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
params: { website_token: web_widget.website_token, message_id: integration_message.id },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_body = response.parsed_body
|
||||
expect(response_body).to eq(
|
||||
{
|
||||
'id' => 'random_uuid', 'auth_token' => 'json-web-token'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,79 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/labels', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
|
||||
let!(:conversation) { create(:conversation, contact: contact, account: account, inbox: web_widget.inbox, contact_inbox: contact_inbox) }
|
||||
let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } }
|
||||
let(:token) { Widget::TokenService.new(payload: payload).generate_token }
|
||||
|
||||
describe 'POST /api/v1/widget/labels' do
|
||||
let(:params) { { website_token: web_widget.website_token, label: 'customer-support' } }
|
||||
|
||||
context 'with correct website token and undefined label' do
|
||||
it 'does not add the label' do
|
||||
post '/api/v1/widget/labels',
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(conversation.reload.label_list.count).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'with correct website token and a defined label' do
|
||||
before do
|
||||
account.labels.create!(title: 'customer-support')
|
||||
end
|
||||
|
||||
it 'add the label to the conversation' do
|
||||
post '/api/v1/widget/labels',
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(conversation.reload.label_list.count).to eq 1
|
||||
expect(conversation.reload.label_list.first).to eq 'customer-support'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns the list of labels' do
|
||||
post '/api/v1/widget/labels', params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v1/widget/labels' do
|
||||
before do
|
||||
conversation.label_list.add('customer-support')
|
||||
conversation.save!
|
||||
end
|
||||
|
||||
let(:params) { { website_token: web_widget.website_token, label: 'customer-support' } }
|
||||
|
||||
context 'with correct website token' do
|
||||
it 'returns the list of labels' do
|
||||
delete "/api/v1/widget/labels/#{params[:label]}",
|
||||
params: params,
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(conversation.reload.label_list.count).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid website token' do
|
||||
it 'returns the list of labels' do
|
||||
delete "/api/v1/widget/labels/#{params[:label]}", params: { website_token: '' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,220 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/widget/messages', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:web_widget) { create(:channel_widget, account: account) }
|
||||
let(:contact) { create(:contact, account: account, email: nil) }
|
||||
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
|
||||
let(:conversation) { create(:conversation, contact: contact, account: account, inbox: web_widget.inbox, contact_inbox: contact_inbox) }
|
||||
let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } }
|
||||
let(:token) { Widget::TokenService.new(payload: payload).generate_token }
|
||||
|
||||
before do |example|
|
||||
2.times.each { create(:message, account: account, inbox: web_widget.inbox, conversation: conversation) } unless example.metadata[:skip_before]
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/widget/messages' do
|
||||
context 'when get request is made' do
|
||||
it 'returns messages in conversation' do
|
||||
get api_v1_widget_messages_url,
|
||||
params: { website_token: web_widget.website_token },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
# 2 messages created + 2 messages by the email hook
|
||||
expect(json_response['payload'].length).to eq(4)
|
||||
expect(json_response['meta']).not_to be_empty
|
||||
end
|
||||
|
||||
it 'returns empty messages', :skip_before do
|
||||
get api_v1_widget_messages_url,
|
||||
params: { website_token: web_widget.website_token },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['payload'].length).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/widget/messages' do
|
||||
context 'when post request is made' do
|
||||
it 'creates message in conversation' do
|
||||
conversation.destroy! # Test all params
|
||||
message_params = { content: 'hello world', timestamp: Time.current }
|
||||
post api_v1_widget_messages_url,
|
||||
params: { website_token: web_widget.website_token, message: message_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['content']).to eq(message_params[:content])
|
||||
end
|
||||
|
||||
it 'does not create the message' do
|
||||
conversation.destroy! # Test all params
|
||||
message_params = { content: "#{'h' * 150 * 1000}a", timestamp: Time.current }
|
||||
post api_v1_widget_messages_url,
|
||||
params: { website_token: web_widget.website_token, message: message_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
|
||||
json_response = response.parsed_body
|
||||
|
||||
expect(json_response['message']).to eq('Content is too long (maximum is 150000 characters)')
|
||||
end
|
||||
|
||||
it 'creates message in conversation with a valid reply to' do
|
||||
message_params = { content: 'hello world reply', timestamp: Time.current, reply_to: conversation.messages.first.id }
|
||||
post api_v1_widget_messages_url,
|
||||
params: { website_token: web_widget.website_token, message: message_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['content']).to eq(message_params[:content])
|
||||
expect(json_response['content_attributes']['in_reply_to']).to eq(conversation.messages.first.id)
|
||||
# check nil for external id since this is a web widget conversation
|
||||
expect(json_response['content_attributes']['in_reply_to_external_id']).to be_nil
|
||||
end
|
||||
|
||||
it 'creates message in conversation with an in-valid reply to' do
|
||||
message_params = { content: 'hello world reply', timestamp: Time.current, reply_to: conversation.messages.first.id + 300 }
|
||||
post api_v1_widget_messages_url,
|
||||
params: { website_token: web_widget.website_token, message: message_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['content']).to eq(message_params[:content])
|
||||
expect(json_response['content_attributes']['in_reply_to']).to be_nil
|
||||
expect(json_response['content_attributes']['in_reply_to_external_id']).to be_nil
|
||||
end
|
||||
|
||||
it 'creates attachment message in conversation' do
|
||||
file = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png')
|
||||
message_params = { content: 'hello world', timestamp: Time.current, attachments: [file] }
|
||||
post api_v1_widget_messages_url,
|
||||
params: { website_token: web_widget.website_token, message: message_params },
|
||||
headers: { 'X-Auth-Token' => token }
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['content']).to eq(message_params[:content])
|
||||
|
||||
expect(conversation.messages.last.attachments.first.file.present?).to be(true)
|
||||
expect(conversation.messages.last.attachments.first.file_type).to eq('image')
|
||||
end
|
||||
|
||||
it 'does not reopen conversation when conversation is muted' do
|
||||
conversation.mute!
|
||||
|
||||
message_params = { content: 'hello world', timestamp: Time.current }
|
||||
post api_v1_widget_messages_url,
|
||||
params: { website_token: web_widget.website_token, message: message_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(conversation.reload.resolved?).to be(true)
|
||||
end
|
||||
|
||||
it 'does not create resolved activity messages when snoozed conversation is opened' do
|
||||
conversation.snoozed!
|
||||
|
||||
message_params = { content: 'hello world', timestamp: Time.current }
|
||||
post api_v1_widget_messages_url,
|
||||
params: { website_token: web_widget.website_token, message: message_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(Conversations::ActivityMessageJob).not_to have_been_enqueued.at_least(:once).with(
|
||||
conversation,
|
||||
{
|
||||
account_id: conversation.account_id,
|
||||
inbox_id: conversation.inbox_id,
|
||||
message_type: :activity,
|
||||
content: "Conversation was resolved by #{contact.name}"
|
||||
}
|
||||
)
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(conversation.reload.open?).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /api/v1/widget/messages' do
|
||||
context 'when put request is made with non existing email' do
|
||||
it 'updates message in conversation and creates a new contact' do
|
||||
message = create(:message, content_type: 'input_email', account: account, inbox: web_widget.inbox, conversation: conversation)
|
||||
email = Faker::Internet.email
|
||||
contact_params = { email: email }
|
||||
put api_v1_widget_message_url(message.id),
|
||||
params: { website_token: web_widget.website_token, contact: contact_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
message.reload
|
||||
expect(message.submitted_email).to eq(email)
|
||||
expect(message.conversation.contact.email).to eq(email)
|
||||
expect(message.conversation.contact.name).to eq(email.split('@')[0])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when put request is made with invalid email' do
|
||||
it 'rescues the error' do
|
||||
message = create(:message, account: account, content_type: 'input_email', inbox: web_widget.inbox, conversation: conversation)
|
||||
contact_params = { email: nil }
|
||||
put api_v1_widget_message_url(message.id),
|
||||
params: { website_token: web_widget.website_token, contact: contact_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when put request is made with existing email' do
|
||||
it 'updates message in conversation and deletes the current contact' do
|
||||
message = create(:message, account: account, content_type: 'input_email', inbox: web_widget.inbox, conversation: conversation)
|
||||
email = Faker::Internet.email
|
||||
existing_contact = create(:contact, account: account, email: email, name: 'John Doe')
|
||||
contact_params = { email: email }
|
||||
put api_v1_widget_message_url(message.id),
|
||||
params: { website_token: web_widget.website_token, contact: contact_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
message.reload
|
||||
expect(existing_contact.reload.name).to eq('John Doe')
|
||||
expect { contact.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'ignores the casing of email, updates message in conversation and deletes the current contact' do
|
||||
message = create(:message, content_type: 'input_email', account: account, inbox: web_widget.inbox, conversation: conversation)
|
||||
email = Faker::Internet.email
|
||||
create(:contact, account: account, email: email)
|
||||
contact_params = { email: email.upcase }
|
||||
put api_v1_widget_message_url(message.id),
|
||||
params: { website_token: web_widget.website_token, contact: contact_params },
|
||||
headers: { 'X-Auth-Token' => token },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
message.reload
|
||||
expect { contact.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user