Adds Skooma-based OpenAPI validation so SDK-facing request specs can assert that documented request and response contracts match real Rails behavior. This also upgrades the spec to OpenAPI 3.1 and fixes contract drift uncovered while validating core application and platform resources. Closes None Why We want CI to catch OpenAPI drift before it reaches SDK consumers. While wiring validation in, this PR surfaced several mismatches between the documented contract and what the Rails endpoints actually accept or return. What this change does - Adds Skooma-backed OpenAPI validation to the request spec flow and a dedicated OpenAPI validation spec. - Migrates nullable schema definitions to OpenAPI 3.1-compatible unions. - Updates core SDK-facing schemas and payloads across accounts, contacts, conversations, inboxes, messages, teams, reporting events, and platform account resources. - Documents concrete runtime cases that were previously missing or inaccurate, including nested `profile` update payloads, multipart avatar uploads, required profile update bodies, nullable inbox feature flags, and message sender types that include both `Captain::Assistant` and senderless activity-style messages. - Regenerates the committed Swagger JSON and tag-group artifacts used by CI sync checks. Validation - `bundle exec rake swagger:build` - `bundle exec rspec spec/swagger/openapi_spec.rb` --------- Co-authored-by: Sojan Jose <sojan@pepalo.com>
1235 lines
48 KiB
Ruby
1235 lines
48 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe 'Inboxes API', type: :request do
|
|
include ActiveJob::TestHelper
|
|
|
|
let(:account) { create(:account) }
|
|
let(:agent) { create(:user, account: account, role: :agent) }
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes' do
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:agent) { create(:user, account: account, role: :agent) }
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
before do
|
|
create(:inbox, account: account)
|
|
create(:inbox_member, user: agent, inbox: inbox)
|
|
end
|
|
|
|
it 'returns all inboxes of current_account as administrator' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response).to conform_schema(200)
|
|
expect(JSON.parse(response.body, symbolize_names: true)[:payload].size).to eq(2)
|
|
end
|
|
|
|
it 'returns only assigned inboxes of current_account as agent' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(JSON.parse(response.body, symbolize_names: true)[:payload].size).to eq(1)
|
|
end
|
|
|
|
context 'when provider_config' do
|
|
let(:inbox) { create(:channel_whatsapp, account: account, sync_templates: false, validate_provider_config: false).inbox }
|
|
|
|
it 'returns provider config attributes for admin' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
expect(response.body).to include('provider_config')
|
|
end
|
|
|
|
it 'will not return provider config for agent' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response.body).not_to include('provider_config')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:agent) { create(:user, account: account, role: :agent) }
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
it 'returns unauthorized for an agent who is not assigned' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'returns the inbox if administrator' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response).to conform_schema(200)
|
|
expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(inbox.id)
|
|
end
|
|
|
|
it 'returns the inbox if assigned inbox is assigned as agent' do
|
|
create(:inbox_member, user: agent, inbox: inbox)
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(data[:id]).to eq(inbox.id)
|
|
expect(data[:hmac_token]).to be_nil
|
|
end
|
|
|
|
it 'returns empty imap details in inbox when agent' do
|
|
email_channel = create(:channel_email, account: account, imap_enabled: true, imap_login: 'test@test.com')
|
|
email_inbox = create(:inbox, channel: email_channel, account: account)
|
|
create(:inbox_member, user: agent, inbox: email_inbox)
|
|
|
|
imap_connection = double
|
|
allow(Mail).to receive(:connection).and_return(imap_connection)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
|
|
expect(data[:imap_enabled]).to be_nil
|
|
expect(data[:imap_login]).to be_nil
|
|
end
|
|
|
|
it 'returns imap details in inbox when admin' do
|
|
email_channel = create(:channel_email, account: account, imap_enabled: true, imap_login: 'test@test.com')
|
|
email_inbox = create(:inbox, channel: email_channel, account: account)
|
|
|
|
imap_connection = double
|
|
allow(Mail).to receive(:connection).and_return(imap_connection)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
|
|
expect(data[:imap_enabled]).to be_truthy
|
|
expect(data[:imap_login]).to eq('test@test.com')
|
|
end
|
|
|
|
context 'when it is a Twilio inbox' do
|
|
let(:twilio_channel) { create(:channel_twilio_sms, account: account, account_sid: 'AC123', auth_token: 'secrettoken') }
|
|
let(:twilio_inbox) { create(:inbox, channel: twilio_channel, account: account) }
|
|
|
|
it 'returns auth_token and account_sid for admin' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{twilio_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(data[:auth_token]).to eq('secrettoken')
|
|
expect(data[:account_sid]).to eq('AC123')
|
|
end
|
|
|
|
it "doesn't return auth_token and account_sid for agent" do
|
|
create(:inbox_member, user: agent, inbox: twilio_inbox)
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{twilio_inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(data[:auth_token]).to be_nil
|
|
expect(data[:account_sid]).to be_nil
|
|
end
|
|
end
|
|
|
|
it 'fetch API inbox without hmac token when agent' do
|
|
api_channel = create(:channel_api, account: account)
|
|
api_inbox = create(:inbox, channel: api_channel, account: account)
|
|
create(:inbox_member, user: agent, inbox: api_inbox)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{api_inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
|
|
expect(data[:hmac_token]).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}/assignable_agents' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignable_agents"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
before do
|
|
create(:inbox_member, user: agent, inbox: inbox)
|
|
end
|
|
|
|
it 'returns all assignable inbox members along with administrators' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignable_agents",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
response_data = JSON.parse(response.body, symbolize_names: true)[:payload]
|
|
expect(response_data.size).to eq(2)
|
|
expect(response_data.pluck(:role)).to include('agent', 'administrator')
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}/campaigns' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/campaigns"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:agent) { create(:user, account: account, role: :agent) }
|
|
let(:administrator) { create(:user, account: account, role: :administrator) }
|
|
|
|
let!(:campaign) { create(:campaign, account: account, inbox: inbox, trigger_rules: { url: 'https://test.com' }) }
|
|
|
|
it 'returns unauthorized for agents' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/campaigns",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'returns all campaigns belonging to the inbox to administrators' do
|
|
# create a random campaign
|
|
create(:campaign, account: account, trigger_rules: { url: 'https://test.com' })
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/campaigns",
|
|
headers: administrator.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
body = JSON.parse(response.body, symbolize_names: true)
|
|
expect(body.first[:id]).to eq(campaign.display_id)
|
|
expect(body.length).to eq(1)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'DELETE /api/v1/accounts/{account.id}/inboxes/{inbox.id}/avatar' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/avatar"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
before do
|
|
create(:inbox_member, user: agent, inbox: inbox)
|
|
inbox.avatar.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
|
|
end
|
|
|
|
it 'delete inbox avatar for administrator user' do
|
|
perform_enqueued_jobs(only: DeleteObjectJob) do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/avatar",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
end
|
|
|
|
expect { inbox.avatar.attachment.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
expect(response).to have_http_status(:success)
|
|
end
|
|
|
|
it 'returns unauthorized for agent user' do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/avatar",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'DELETE /api/v1/accounts/{account.id}/inboxes/:id' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
|
|
it 'deletes inbox' do
|
|
expect(DeleteObjectJob).to receive(:perform_later).with(inbox, admin, anything).once
|
|
|
|
perform_enqueued_jobs(only: DeleteObjectJob) do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
end
|
|
|
|
json_response = response.parsed_body
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(json_response['message']).to eq('Your inbox deletion request will be processed in some time.')
|
|
end
|
|
|
|
it 'is unable to delete inbox of another account' do
|
|
other_account = create(:account)
|
|
other_inbox = create(:inbox, account: other_account)
|
|
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{other_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
|
|
it 'is unable to delete inbox as agent' do
|
|
agent = create(:user, account: account, role: :agent)
|
|
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'POST /api/v1/accounts/{account.id}/inboxes' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:valid_params) { { name: 'test', channel: { type: 'web_widget', website_url: 'test.com' } } }
|
|
|
|
it 'will not create inbox for agent' do
|
|
agent = create(:user, account: account, role: :agent)
|
|
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: agent.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'creates a webwidget inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response).to conform_schema(200)
|
|
expect(response.body).to include('test.com')
|
|
end
|
|
|
|
it 'creates a email inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: { name: 'test', channel: { type: 'email', email: 'test@test.com' } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.body).to include('test@test.com')
|
|
end
|
|
|
|
it 'creates an api inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: { name: 'API Inbox', channel: { type: 'api', webhook_url: 'http://test.com' } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.body).to include('API Inbox')
|
|
end
|
|
|
|
it 'creates a line inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: { name: 'Line Inbox',
|
|
channel: { type: 'line', line_channel_id: SecureRandom.uuid, line_channel_secret: SecureRandom.uuid,
|
|
line_channel_token: SecureRandom.uuid } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.body).to include('Line Inbox')
|
|
expect(response.body).to include('callback_webhook_url')
|
|
end
|
|
|
|
it 'creates a sms inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: { name: 'Sms Inbox',
|
|
channel: { type: 'sms', phone_number: '+123456789', provider_config: { test: 'test' } } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.body).to include('Sms Inbox')
|
|
expect(response.body).to include('+123456789')
|
|
end
|
|
|
|
it 'creates the webwidget inbox that allow messages after conversation is resolved' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response['allow_messages_after_resolved']).to be true
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'PATCH /api/v1/accounts/{account.id}/inboxes/:id' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let!(:portal) { create(:portal, account_id: account.id) }
|
|
let(:valid_params) { { name: 'new test inbox', enable_auto_assignment: false, portal_id: portal.id } }
|
|
|
|
it 'will not update inbox for agent' do
|
|
agent = create(:user, account: account, role: :agent)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'updates inbox when administrator' do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response).to conform_schema(200)
|
|
expect(inbox.reload.enable_auto_assignment).to be_falsey
|
|
expect(inbox.reload.portal_id).to eq(portal.id)
|
|
expect(response.parsed_body['name']).to eq 'new test inbox'
|
|
end
|
|
|
|
it 'updates api inbox when administrator' do
|
|
api_channel = create(:channel_api, account: account)
|
|
api_inbox = create(:inbox, channel: api_channel, account: account)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{api_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { enable_auto_assignment: false, channel: { webhook_url: 'webhook.test', selected_feature_flags: [] } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(api_inbox.reload.enable_auto_assignment).to be_falsey
|
|
expect(api_channel.reload.webhook_url).to eq('webhook.test')
|
|
end
|
|
|
|
it 'updates whatsapp inbox when administrator' do
|
|
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook').to_return(status: 200, body: '', headers: {})
|
|
stub_request(:get, 'https://waba.360dialog.io/v1/configs/templates').to_return(status: 200, body: '', headers: {})
|
|
whatsapp_channel = create(:channel_whatsapp, account: account)
|
|
whatsapp_inbox = create(:inbox, channel: whatsapp_channel, account: account)
|
|
whatsapp_channel.prompt_reauthorization!
|
|
|
|
expect(whatsapp_channel).to be_reauthorization_required
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { enable_auto_assignment: false, channel: { provider_config: { api_key: 'new_key' } } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(whatsapp_inbox.reload.enable_auto_assignment).to be_falsey
|
|
expect(whatsapp_channel.reload.provider_config['api_key']).to eq('new_key')
|
|
expect(whatsapp_channel.reload).not_to be_reauthorization_required
|
|
end
|
|
|
|
it 'updates twitter inbox when administrator' do
|
|
twitter_channel = create(:channel_twitter_profile, account: account, tweets_enabled: true)
|
|
twitter_inbox = create(:inbox, channel: twitter_channel, account: account)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{twitter_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { channel: { tweets_enabled: false } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(twitter_channel.reload.tweets_enabled).to be(false)
|
|
end
|
|
|
|
it 'updates email inbox when administrator' do
|
|
email_channel = create(:channel_email, account: account)
|
|
email_inbox = create(:inbox, channel: email_channel, account: account)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { enable_auto_assignment: false, channel: { email: 'emailtest@email.test' } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_inbox.reload.enable_auto_assignment).to be_falsey
|
|
expect(email_channel.reload.email).to eq('emailtest@email.test')
|
|
end
|
|
|
|
it 'updates twilio sms inbox when administrator' do
|
|
twilio_sms_channel = create(:channel_twilio_sms, account: account)
|
|
twilio_sms_inbox = create(:inbox, channel: twilio_sms_channel, account: account)
|
|
expect(twilio_sms_inbox.reload.channel.account_sid).not_to eq('account_sid')
|
|
expect(twilio_sms_inbox.reload.channel.auth_token).not_to eq('new_auth_token')
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{twilio_sms_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { channel: { account_sid: 'account_sid', auth_token: 'new_auth_token' } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(twilio_sms_inbox.reload.channel.account_sid).to eq('account_sid')
|
|
expect(twilio_sms_inbox.reload.channel.auth_token).to eq('new_auth_token')
|
|
end
|
|
|
|
it 'updates email inbox with imap when administrator' do
|
|
email_channel = create(:channel_email, account: account)
|
|
email_inbox = create(:inbox, channel: email_channel, account: account)
|
|
|
|
imap_connection = double
|
|
allow(Mail).to receive(:connection).and_return(imap_connection)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: {
|
|
channel: {
|
|
imap_enabled: true,
|
|
imap_address: 'imap.gmail.com',
|
|
imap_port: 993,
|
|
imap_login: 'imaptest@gmail.com'
|
|
}
|
|
},
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_channel.reload.imap_enabled).to be true
|
|
expect(email_channel.reload.imap_address).to eq('imap.gmail.com')
|
|
expect(email_channel.reload.imap_port).to eq(993)
|
|
end
|
|
|
|
it 'updates avatar when administrator' do
|
|
# no avatar before upload
|
|
expect(inbox.avatar.attached?).to be(false)
|
|
file = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png')
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: valid_params.merge(avatar: file),
|
|
headers: admin.create_new_auth_token
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox.reload
|
|
expect(inbox.avatar.attached?).to be(true)
|
|
end
|
|
|
|
it 'updates working hours when administrator' do
|
|
params = {
|
|
working_hours: [{ 'day_of_week' => 0, 'open_hour' => 9, 'open_minutes' => 0, 'close_hour' => 17, 'close_minutes' => 0 }],
|
|
working_hours_enabled: true,
|
|
out_of_office_message: 'hello'
|
|
}
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: valid_params.merge(params),
|
|
headers: admin.create_new_auth_token
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox.reload
|
|
expect(inbox.reload.weekly_schedule.find { |schedule| schedule['day_of_week'] == 0 }['open_hour']).to eq 9
|
|
end
|
|
|
|
it 'updates the webwidget inbox to disallow the messages after conversation is resolved' do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params.merge({ allow_messages_after_resolved: false }),
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(inbox.reload.allow_messages_after_resolved).to be_falsey
|
|
end
|
|
end
|
|
|
|
context 'when an authenticated user updates email inbox' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:email_channel) { create(:channel_email, account: account) }
|
|
let(:email_inbox) { create(:inbox, channel: email_channel, account: account) }
|
|
|
|
it 'updates smtp configuration with starttls encryption' do
|
|
smtp_connection = double
|
|
allow(smtp_connection).to receive(:open_timeout=).and_return(10)
|
|
allow(smtp_connection).to receive(:start).and_return(true)
|
|
allow(smtp_connection).to receive(:finish).and_return(true)
|
|
allow(smtp_connection).to receive(:respond_to?).and_return(true)
|
|
allow(smtp_connection).to receive(:enable_starttls_auto).and_return(true)
|
|
allow(Net::SMTP).to receive(:new).and_return(smtp_connection)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: {
|
|
channel: {
|
|
smtp_enabled: true,
|
|
smtp_address: 'smtp.gmail.com',
|
|
smtp_port: 587,
|
|
smtp_login: 'smtptest@gmail.com',
|
|
smtp_enable_starttls_auto: true,
|
|
smtp_openssl_verify_mode: 'peer'
|
|
}
|
|
},
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_channel.reload.smtp_enabled).to be true
|
|
expect(email_channel.reload.smtp_address).to eq('smtp.gmail.com')
|
|
expect(email_channel.reload.smtp_port).to eq(587)
|
|
expect(email_channel.reload.smtp_enable_starttls_auto).to be true
|
|
expect(email_channel.reload.smtp_openssl_verify_mode).to eq('peer')
|
|
end
|
|
|
|
it 'updates smtp configuration with ssl/tls encryption' do
|
|
smtp_connection = double
|
|
allow(smtp_connection).to receive(:open_timeout=).and_return(10)
|
|
allow(smtp_connection).to receive(:start).and_return(true)
|
|
allow(smtp_connection).to receive(:finish).and_return(true)
|
|
allow(smtp_connection).to receive(:respond_to?).and_return(true)
|
|
allow(smtp_connection).to receive(:enable_tls).and_return(true)
|
|
allow(Net::SMTP).to receive(:new).and_return(smtp_connection)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: {
|
|
channel: {
|
|
smtp_enabled: true,
|
|
smtp_address: 'smtp.gmail.com',
|
|
smtp_login: 'smtptest@gmail.com',
|
|
smtp_port: 587,
|
|
smtp_enable_ssl_tls: true,
|
|
smtp_openssl_verify_mode: 'none'
|
|
}
|
|
},
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_channel.reload.smtp_enabled).to be true
|
|
expect(email_channel.reload.smtp_address).to eq('smtp.gmail.com')
|
|
expect(email_channel.reload.smtp_port).to eq(587)
|
|
expect(email_channel.reload.smtp_enable_ssl_tls).to be true
|
|
expect(email_channel.reload.smtp_openssl_verify_mode).to eq('none')
|
|
end
|
|
|
|
it 'updates smtp configuration with authentication mechanism' do
|
|
smtp_connection = double
|
|
allow(smtp_connection).to receive(:open_timeout=).and_return(10)
|
|
allow(smtp_connection).to receive(:start).and_return(true)
|
|
allow(smtp_connection).to receive(:finish).and_return(true)
|
|
allow(smtp_connection).to receive(:respond_to?).and_return(true)
|
|
allow(smtp_connection).to receive(:enable_starttls_auto).and_return(true)
|
|
allow(Net::SMTP).to receive(:new).and_return(smtp_connection)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: {
|
|
channel: {
|
|
smtp_enabled: true,
|
|
smtp_address: 'smtp.gmail.com',
|
|
smtp_port: 587,
|
|
smtp_email: 'smtptest@gmail.com',
|
|
smtp_authentication: 'plain'
|
|
}
|
|
},
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_channel.reload.smtp_enabled).to be true
|
|
expect(email_channel.reload.smtp_address).to eq('smtp.gmail.com')
|
|
expect(email_channel.reload.smtp_port).to eq(587)
|
|
expect(email_channel.reload.smtp_authentication).to eq('plain')
|
|
end
|
|
end
|
|
|
|
context 'when handling CSAT configuration' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
let(:csat_config) do
|
|
{
|
|
'display_type' => 'emoji',
|
|
'message' => 'How would you rate your experience?',
|
|
'survey_rules' => {
|
|
'operator' => 'contains',
|
|
'values' => %w[support help]
|
|
}
|
|
}
|
|
end
|
|
|
|
it 'successfully updates the inbox with CSAT configuration' do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
end
|
|
|
|
context 'when CSAT is configured' do
|
|
before do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
end
|
|
|
|
it 'returns configured CSAT settings in inbox details' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response['csat_survey_enabled']).to be true
|
|
|
|
saved_config = json_response['csat_config']
|
|
expect(saved_config).to be_present
|
|
expect(saved_config['display_type']).to eq('emoji')
|
|
end
|
|
|
|
it 'returns configured CSAT message' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
json_response = response.parsed_body
|
|
saved_config = json_response['csat_config']
|
|
expect(saved_config['message']).to eq('How would you rate your experience?')
|
|
end
|
|
|
|
it 'returns configured CSAT survey rules' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
json_response = response.parsed_body
|
|
saved_config = json_response['csat_config']
|
|
expect(saved_config['survey_rules']['operator']).to eq('contains')
|
|
expect(saved_config['survey_rules']['values']).to match_array(%w[support help])
|
|
end
|
|
|
|
it 'includes CSAT configuration in inbox list' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox_list = response.parsed_body
|
|
found_inbox = inbox_list['payload'].find { |i| i['id'] == inbox.id }
|
|
|
|
expect(found_inbox['csat_survey_enabled']).to be true
|
|
expect(found_inbox['csat_config']).to be_present
|
|
expect(found_inbox['csat_config']['display_type']).to eq('emoji')
|
|
end
|
|
end
|
|
|
|
it 'successfully updates inbox with template configuration' do
|
|
csat_config_with_template = csat_config.merge({
|
|
'template' => {
|
|
'name' => 'custom_survey_template',
|
|
'template_id' => '123456789',
|
|
'language' => 'en',
|
|
'created_at' => Time.current.iso8601
|
|
}
|
|
})
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config_with_template
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
|
|
inbox.reload
|
|
template_config = inbox.csat_config['template']
|
|
expect(template_config).to be_present
|
|
expect(template_config['name']).to eq('custom_survey_template')
|
|
expect(template_config['template_id']).to eq('123456789')
|
|
expect(template_config['language']).to eq('en')
|
|
end
|
|
|
|
it 'returns template configuration in inbox details' do
|
|
csat_config_with_template = csat_config.merge({
|
|
'template' => {
|
|
'name' => 'custom_survey_template',
|
|
'template_id' => '123456789',
|
|
'language' => 'en',
|
|
'created_at' => Time.current.iso8601
|
|
}
|
|
})
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config_with_template
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
template_config = json_response['csat_config']['template']
|
|
|
|
expect(template_config).to be_present
|
|
expect(template_config['name']).to eq('custom_survey_template')
|
|
expect(template_config['template_id']).to eq('123456789')
|
|
expect(template_config['language']).to eq('en')
|
|
expect(template_config['created_at']).to be_present
|
|
end
|
|
|
|
it 'removes template configuration when not provided in update' do
|
|
# First set up template configuration
|
|
csat_config_with_template = csat_config.merge({
|
|
'template' => {
|
|
'name' => 'custom_survey_template',
|
|
'template_id' => '123456789'
|
|
}
|
|
})
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config_with_template
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
# Then update without template
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config.merge({ 'message' => 'Updated message' })
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
|
|
inbox.reload
|
|
config = inbox.csat_config
|
|
expect(config['message']).to eq('Updated message')
|
|
expect(config['template']).to be_nil # Template should be removed when not provided
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}/agent_bot' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
before do
|
|
create(:inbox_member, user: agent, inbox: inbox)
|
|
end
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/agent_bot"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
it 'returns empty when no agent bot is present' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/agent_bot",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox_data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(inbox_data[:agent_bot].blank?).to be(true)
|
|
end
|
|
|
|
it 'returns the agent bot attached to the inbox' do
|
|
agent_bot = create(:agent_bot)
|
|
create(:agent_bot_inbox, agent_bot: agent_bot, inbox: inbox)
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/agent_bot",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox_data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(inbox_data[:agent_bot][:name]).to eq agent_bot.name
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'POST /api/v1/accounts/{account.id}/inboxes/:id/set_agent_bot' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
let(:agent_bot) { create(:agent_bot) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:valid_params) { { agent_bot: agent_bot.id } }
|
|
|
|
it 'sets the agent bot' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(inbox.reload.agent_bot.id).to eq agent_bot.id
|
|
end
|
|
|
|
it 'throw error when invalid agent bot id' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot",
|
|
headers: admin.create_new_auth_token,
|
|
params: { agent_bot: 0 },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
|
|
it 'disconnects the agent bot' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot",
|
|
headers: admin.create_new_auth_token,
|
|
params: { agent_bot: nil },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(inbox.reload.agent_bot).to be_falsey
|
|
end
|
|
|
|
it 'will not update agent bot when its an agent' do
|
|
agent = create(:user, account: account, role: :agent)
|
|
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot",
|
|
headers: agent.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'POST /api/v1/accounts/{account.id}/inboxes/:id/sync_templates' do
|
|
let(:whatsapp_channel) do
|
|
create(:channel_whatsapp, account: account, provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false)
|
|
end
|
|
let(:whatsapp_inbox) { create(:inbox, account: account, channel: whatsapp_channel) }
|
|
let(:non_whatsapp_inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/sync_templates"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated agent' do
|
|
it 'returns unauthorized for agent' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/sync_templates",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated administrator' do
|
|
context 'with WhatsApp inbox' do
|
|
it 'successfully initiates template sync' do
|
|
expect(Channels::Whatsapp::TemplatesSyncJob).to receive(:perform_later).with(whatsapp_channel)
|
|
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/sync_templates",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response['message']).to eq('Template sync initiated successfully')
|
|
end
|
|
|
|
it 'handles job errors gracefully' do
|
|
allow(Channels::Whatsapp::TemplatesSyncJob).to receive(:perform_later).and_raise(StandardError, 'Job failed')
|
|
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/sync_templates",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:internal_server_error)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Job failed')
|
|
end
|
|
end
|
|
|
|
context 'with non-WhatsApp inbox' do
|
|
it 'returns unprocessable entity error' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{non_whatsapp_inbox.id}/sync_templates",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Template sync is only available for WhatsApp channels')
|
|
end
|
|
end
|
|
|
|
context 'with non-existent inbox' do
|
|
it 'returns not found error' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/999999/sync_templates",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}/health' do
|
|
let(:whatsapp_channel) do
|
|
create(:channel_whatsapp, account: account, provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false)
|
|
end
|
|
let(:whatsapp_inbox) { create(:inbox, account: account, channel: whatsapp_channel) }
|
|
let(:non_whatsapp_inbox) { create(:inbox, account: account) }
|
|
let(:health_service) { instance_double(Whatsapp::HealthService) }
|
|
let(:health_data) do
|
|
{
|
|
display_phone_number: '+1234567890',
|
|
verified_name: 'Test Business',
|
|
name_status: 'APPROVED',
|
|
quality_rating: 'GREEN',
|
|
messaging_limit_tier: 'TIER_1000',
|
|
account_mode: 'LIVE',
|
|
business_id: 'business123'
|
|
}
|
|
end
|
|
|
|
before do
|
|
allow(Whatsapp::HealthService).to receive(:new).and_return(health_service)
|
|
allow(health_service).to receive(:fetch_health_status).and_return(health_data)
|
|
end
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
context 'with WhatsApp inbox' do
|
|
it 'returns health data for administrator' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response).to include(
|
|
'display_phone_number' => '+1234567890',
|
|
'verified_name' => 'Test Business',
|
|
'name_status' => 'APPROVED',
|
|
'quality_rating' => 'GREEN',
|
|
'messaging_limit_tier' => 'TIER_1000',
|
|
'account_mode' => 'LIVE',
|
|
'business_id' => 'business123'
|
|
)
|
|
end
|
|
|
|
it 'returns health data for agent with inbox access' do
|
|
create(:inbox_member, user: agent, inbox: whatsapp_inbox)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response['display_phone_number']).to eq('+1234567890')
|
|
end
|
|
|
|
it 'returns unauthorized for agent without inbox access' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'calls the health service with correct channel' do
|
|
expect(Whatsapp::HealthService).to receive(:new).with(whatsapp_channel).and_return(health_service)
|
|
expect(health_service).to receive(:fetch_health_status)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
end
|
|
|
|
it 'handles service errors gracefully' do
|
|
allow(health_service).to receive(:fetch_health_status).and_raise(StandardError, 'API Error')
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to include('API Error')
|
|
end
|
|
end
|
|
|
|
context 'with non-WhatsApp inbox' do
|
|
it 'returns bad request error for administrator' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{non_whatsapp_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:bad_request)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Health data only available for WhatsApp Cloud API channels')
|
|
end
|
|
|
|
it 'returns bad request error for agent' do
|
|
create(:inbox_member, user: agent, inbox: non_whatsapp_inbox)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{non_whatsapp_inbox.id}/health",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:bad_request)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Health data only available for WhatsApp Cloud API channels')
|
|
end
|
|
end
|
|
|
|
context 'with WhatsApp non-cloud inbox' do
|
|
let(:whatsapp_default_channel) do
|
|
create(:channel_whatsapp, account: account, provider: 'default', sync_templates: false, validate_provider_config: false)
|
|
end
|
|
let(:whatsapp_default_inbox) { create(:inbox, account: account, channel: whatsapp_default_channel) }
|
|
|
|
it 'returns bad request error for non-cloud provider' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_default_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:bad_request)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Health data only available for WhatsApp Cloud API channels')
|
|
end
|
|
end
|
|
|
|
context 'with non-existent inbox' do
|
|
it 'returns not found error' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/999999/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|