Files
moreminimore-chat/spec/services/conversations/assignment_service_spec.rb
Sojan Jose 35a5f3390c feat: update status on agent bot assignment (#14870)
Assigning a conversation to an Agent Bot now moves it to pending.
Assigning a bot-owned pending conversation to a human opens it again,
while other assignment changes preserve the existing status. This makes
existing Agent Bot ownership behave like an AI handoff without depending
on the assignment dropdown UI work.

Closes:
https://linear.app/chatwoot/issue/CW-7448/apply-agent-bot-assignment-behavior

## Why
Agent Bot ownership should remove conversations from the main open queue
while the bot is handling them. Explicit human takeover should bring a
bot-owned pending conversation back to the open queue and clear the bot
owner.

## What changed
- Agent Bot assignment clears the human assignee and marks the
conversation pending.
- Human assignment clears the Agent Bot owner and opens the conversation
only when it was bot-owned and pending.
- Ordinary human assignment, non-pending bot takeover, and unassignment
preserve the existing conversation status.
- Manual human takeover uses the existing assignment and status events.
Bot-initiated handoffs continue to use the existing bot-handoff event
path.

## Validation
- Assign an open conversation to an Agent Bot through the assignment API
and verify it becomes pending.
- Assign that bot-owned pending conversation to a human and verify it
becomes open.
- Verify ordinary human assignment, non-pending bot takeover, and
unassignment do not force a status change.
2026-08-07 12:08:58 -07:00

115 lines
3.7 KiB
Ruby

require 'rails_helper'
describe Conversations::AssignmentService do
let(:account) { create(:account) }
let(:agent) { create(:user, account: account) }
let(:agent_bot) { create(:agent_bot, account: account) }
let(:conversation) { create(:conversation, account: account) }
describe '#perform' do
context 'when assignee_id is blank' do
before do
conversation.update!(assignee: agent, assignee_agent_bot: agent_bot)
end
it 'clears both human and bot assignees' do
described_class.new(conversation: conversation, assignee_id: nil).perform
conversation.reload
expect(conversation.assignee_id).to be_nil
expect(conversation.assignee_agent_bot_id).to be_nil
end
it 'preserves conversation status' do
conversation.update!(status: :snoozed, snoozed_until: 1.day.from_now)
described_class.new(conversation: conversation, assignee_id: nil).perform
expect(conversation.reload.status).to eq('snoozed')
end
end
context 'when assigning a user' do
before do
conversation.update!(assignee_agent_bot: agent_bot, assignee: nil, status: :pending)
end
it 'sets the agent, clears agent bot and opens the conversation' do
result = described_class.new(conversation: conversation, assignee_id: agent.id).perform
conversation.reload
expect(result).to eq(agent)
expect(conversation.assignee_id).to eq(agent.id)
expect(conversation.assignee_agent_bot_id).to be_nil
expect(conversation.status).to eq('open')
end
it 'starts the waiting clock when opening a bot-owned pending conversation' do
conversation.update!(waiting_since: nil)
freeze_time do
described_class.new(conversation: conversation, assignee_id: agent.id).perform
expect(conversation.reload.waiting_since).to eq(Time.current)
end
end
it 'preserves status for ordinary human assignment changes' do
conversation.update!(assignee_agent_bot: nil, status: :resolved)
described_class.new(conversation: conversation, assignee_id: agent.id).perform
expect(conversation.reload.status).to eq('resolved')
end
it 'preserves status when taking over a bot-owned non-pending conversation' do
conversation.update!(assignee_agent_bot: agent_bot, status: :resolved)
described_class.new(conversation: conversation, assignee_id: agent.id).perform
expect(conversation.reload.status).to eq('resolved')
end
end
context 'when assigning an agent bot' do
let(:service) do
described_class.new(
conversation: conversation,
assignee_id: agent_bot.id,
assignee_type: 'AgentBot'
)
end
it 'sets the agent bot, clears human assignee and marks the conversation pending' do
conversation.update!(assignee: agent, assignee_agent_bot: nil, status: :open)
result = service.perform
conversation.reload
expect(result).to eq(agent_bot)
expect(conversation.assignee_agent_bot_id).to eq(agent_bot.id)
expect(conversation.assignee_id).to be_nil
expect(conversation.status).to eq('pending')
end
it 'marks a resolved conversation pending' do
conversation.update!(status: :resolved)
service.perform
expect(conversation.reload.status).to eq('pending')
end
it 'marks a snoozed conversation pending and clears the snooze timestamp' do
conversation.update!(status: :snoozed, snoozed_until: 1.day.from_now)
service.perform
conversation.reload
expect(conversation.status).to eq('pending')
expect(conversation.snoozed_until).to be_nil
end
end
end
end