Files
chatwoot/spec/controllers/super_admin/accounts_controller_spec.rb
Aakash BakhleandGitHub 83dda621c5 feat: default new accounts to captain v2 (#14917)
# Pull Request Template

## Description

defaults new accounts to captain v2

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.

locally and specs

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
2026-07-07 16:21:51 +05:30

207 lines
7.6 KiB
Ruby

require 'rails_helper'
RSpec.describe 'Super Admin accounts API', type: :request do
include ActiveJob::TestHelper
let!(:super_admin) { create(:super_admin) }
let!(:account) { create(:account) }
describe 'GET /super_admin/accounts' do
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do
get '/super_admin/accounts'
expect(response).to have_http_status(:redirect)
end
end
context 'when it is an authenticated user' do
it 'shows the list of accounts' do
sign_in(super_admin, scope: :super_admin)
get '/super_admin/accounts'
expect(response).to have_http_status(:success)
expect(response.body).to include('New account')
expect(response.body).to include(account.name)
end
end
end
describe 'GET /super_admin/accounts/{account_id}' do
context 'when it is an authenticated user' do
it 'shows effective Captain model routing', if: ChatwootApp.enterprise? do
account.update!(captain_models: { 'editor' => 'gpt-4.1' })
sign_in(super_admin, scope: :super_admin)
get "/super_admin/accounts/#{account.id}"
document = Nokogiri::HTML(response.body)
summaries = document.css('details summary').map { |summary| summary.text.squish }
expect(response).to have_http_status(:success)
expect(document.at_css('#captain_models').text.squish).to eq('Captain models')
expect(summaries).to include('View model routing')
expect(summaries).not_to include('All features')
expect(summaries).not_to include('Captain models')
expect(response.body).to include('Editor', 'OpenAI', 'openai', 'gpt-4.1', 'Account override', 'Label suggestion', 'Default')
end
end
end
describe 'GET /super_admin/accounts/{account_id}/edit' do
context 'when it is an authenticated user' do
it 'renders a Captain model selector for every AI feature', if: ChatwootApp.enterprise? do
account.update!(captain_models: { 'editor' => 'gpt-4.1' })
sign_in(super_admin, scope: :super_admin)
get "/super_admin/accounts/#{account.id}/edit"
expect(response).to have_http_status(:success)
Llm::Models.feature_keys.each do |feature_key|
expect(response.body).to include("account[captain_models][#{feature_key}]")
end
document = Nokogiri::HTML(response.body)
editor_select = document.at_css('select[name="account[captain_models][editor]"]')
default_model_id = Llm::Models.default_model_for('editor')
default_model = Llm::Models.model_config(default_model_id)['display_name']
expect(editor_select.at_css('option[value=""]').text.squish).to eq("Use default: #{default_model} (#{default_model_id})")
end
it 'shows the Captain V2 assistant default in the model selector', if: ChatwootApp.enterprise? do
account.enable_features!('captain_integration_v2')
sign_in(super_admin, scope: :super_admin)
get "/super_admin/accounts/#{account.id}/edit"
document = Nokogiri::HTML(response.body)
assistant_select = document.at_css('select[name="account[captain_models][assistant]"]')
default_model_id = Llm::FeatureRouter::CAPTAIN_V2_ASSISTANT_MODEL
default_model = Llm::Models.model_config(default_model_id)['display_name']
expect(response).to have_http_status(:success)
expect(assistant_select.at_css('option[value=""]').text.squish).to eq("Use default: #{default_model} (#{default_model_id})")
end
end
end
describe 'PATCH /super_admin/accounts/{account_id}' do
context 'when it is an authenticated user' do
it 'updates Captain model overrides without changing unrelated settings' do
account.update!(
captain_models: { 'editor' => 'gpt-4.1' },
keep_pending_on_bot_failure: true
)
sign_in(super_admin, scope: :super_admin)
patch "/super_admin/accounts/#{account.id}",
params: {
account: {
name: account.name,
locale: account.locale,
status: account.status,
captain_models: {
editor: '',
assistant: 'gpt-5.2'
}
}
}
expect(response).to have_http_status(:redirect)
expect(account.reload.captain_models).to eq('assistant' => 'gpt-5.2')
expect(account.keep_pending_on_bot_failure).to be true
end
it 'rejects invalid Captain model overrides' do
sign_in(super_admin, scope: :super_admin)
existing_captain_models = account.captain_models
patch "/super_admin/accounts/#{account.id}",
params: {
account: {
name: account.name,
locale: account.locale,
status: account.status,
captain_models: {
label_suggestion: 'gpt-5.1'
}
}
}
expect(response).to have_http_status(:unprocessable_entity)
expect(response.body).to include('not a valid model for label_suggestion')
expect(account.reload.captain_models).to eq(existing_captain_models)
end
end
end
describe 'POST /super_admin/accounts/{account_id}/reset_cache' do
before do
create(:label, account: account)
create(:inbox, account: account)
create(:team, account: account)
end
after do
Conversations::UnreadCounts::Store.clear_account!(account.id)
end
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do
post "/super_admin/accounts/#{account.id}/reset_cache"
expect(response).to have_http_status(:redirect)
end
end
context 'when it is an authenticated user' do
it 'shows the list of accounts' do
expect(account.cache_keys.keys).to contain_exactly(:inbox, :label, :team)
sign_in(super_admin, scope: :super_admin)
now_timestamp = Time.now.utc.to_i
post "/super_admin/accounts/#{account.id}/reset_cache"
expect(response).to have_http_status(:redirect)
expect(flash[:notice]).to eq('Cache keys cleared')
range = now_timestamp..(now_timestamp + 10)
expect(account.reload.cache_keys.values.all? { |v| range.cover?(v.to_i) }).to be(true)
end
it 'clears conversation unread count cache' do
inbox = account.inboxes.first
store = Conversations::UnreadCounts::Store
inbox_key = store.inbox_key(account.id, inbox.id)
store.mark_base_ready!(account.id)
store.add_base_membership(account_id: account.id, inbox_id: inbox.id, label_ids: [], conversation_id: 1)
sign_in(super_admin, scope: :super_admin)
post "/super_admin/accounts/#{account.id}/reset_cache"
expect(response).to have_http_status(:redirect)
expect(store.base_ready?(account.id)).to be(false)
expect(store.counts_for_keys([inbox_key])).to eq(inbox_key => 0)
end
end
end
describe 'DELETE /super_admin/accounts/{account_id}' do
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do
delete "/super_admin/accounts/#{account.id}"
expect(response).to have_http_status(:redirect)
end
end
context 'when it is an authenticated user' do
it 'Deletes the account' do
total_accounts = Account.count
sign_in(super_admin, scope: :super_admin)
perform_enqueued_jobs(only: DeleteObjectJob) do
delete "/super_admin/accounts/#{account.id}"
end
expect(Account.count).to eq(total_accounts - 1)
end
end
end
end