Files
leadchat/spec/controllers/api/v1/widget/conversations_controller_spec.rb
Muhsin Keloth 24fbab94c3 chore: Refactor MarkMessagesAsReadJob based on conversation id and time stamp (#8217)
- Mark all messages as read by providing the conversation ID and timestamp.
- For Instagram, ensure all previous messages that weren't marked as failed are now marked as read. This is because the read events are only triggered for the most recent message and not for any previous ones.
2023-10-27 15:21:39 -07:00

318 lines
12 KiB
Ruby

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
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' do
post '/api/v1/widget/conversations',
headers: { 'X-Auth-Token' => token },
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' }
},
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'
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 '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::MarkMessagesAsReadJob).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
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, email: 'test@test.com' },
as: :json
expect(response).to have_http_status(:success)
expect(mailer).to have_received(:conversation_transcript).with(conversation, 'test@test.com')
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