Files
chatwoot/script/assignment_v2/test_real_time_trigger.rb
T

246 lines
8.0 KiB
Ruby

# frozen_string_literal: true
# Test: Real-Time Assignment Trigger
# Run with: bundle exec rails runner script/assignment_v2/test_real_time_trigger.rb
#
# Tests:
# - Assignment triggered when conversation status changes to 'open'
# - Assignment triggered when new conversation created
# - Assignment only runs when assignee is blank
# - Assignment respects enable_auto_assignment flag
#
# Key Implementation Details:
# - AutoAssignmentHandler is a concern included in Conversation model
# - Triggers after_save when conversation_status_changed_to_open?
# - Checks inbox.auto_assignment_v2_enabled? to use v2 vs legacy system
# - NOTE: auto_assignment_v2_enabled? not yet implemented, so this test simulates expected behavior
# - When implemented, it will call: AutoAssignment::AssignmentJob.perform_later(inbox_id: inbox.id)
#
# This test manually triggers assignment to simulate real-time behavior
require_relative 'test_helpers'
class TestRealTimeTrigger
include AssignmentV2TestHelpers
def run
section('TEST: Real-Time Assignment Trigger')
account = get_test_account
inbox = nil
begin
# Setup test inbox and policy
inbox = create_test_inbox(account, name: 'Real-Time Trigger Test Inbox')
policy = create_test_policy(account, name: 'Real-Time Policy')
link_policy_to_inbox(inbox, policy)
# Create agent
agent = create_test_agent(account, inbox, name: 'Agent Real-Time', online: true)
# Test 1: Assignment triggered when conversation status changes to open
section('Test 1: Status Change to Open Triggers Assignment')
# Create conversation with status 'pending' (not open)
conv = create_test_conversation(inbox, contact_name: 'Pending Customer', status: 'pending')
info('Created conversation with status: pending')
# Conversation should not be assigned (status is not open)
conv.reload
pending_unassigned = assert(
conv.assignee_id.nil?,
'Pending conversation not assigned',
'Pending conversation was assigned (should not be)'
)
# Change status to 'open' and manually trigger assignment (simulating handler)
conv.update!(status: 'open')
info('Changed status to: open')
# Simulate real-time trigger: run assignment job
# In production, AutoAssignmentHandler would call: AutoAssignment::AssignmentJob.perform_later
assigned_count = run_assignment(inbox)
# Verify assignment happened
log('Verifying assignment after status change...', color: :blue)
assigned_ok = assert_equal(
assigned_count,
1,
'Conversation assigned after status changed to open'
)
conv.reload
has_assignee = assert(
conv.assignee_id.present?,
'Conversation has assignee',
'Conversation not assigned'
)
test1_ok = pending_unassigned && assigned_ok && has_assignee
# Test 2: New conversation created as 'open' triggers assignment
section('Test 2: New Open Conversation Triggers Assignment')
# Create conversation directly as 'open'
conv2 = create_test_conversation(inbox, contact_name: 'Open Customer', status: 'open')
info('Created conversation with status: open')
# Simulate real-time trigger
assigned_count_2 = run_assignment(inbox)
# Verify assignment
log('Verifying assignment for new open conversation...', color: :blue)
assigned_ok_2 = assert_equal(
assigned_count_2,
1,
'New open conversation assigned'
)
conv2.reload
has_assignee_2 = assert(
conv2.assignee_id.present?,
'New conversation has assignee',
'New conversation not assigned'
)
test2_ok = assigned_ok_2 && has_assignee_2
# Test 3: Already assigned conversation not re-assigned
section('Test 3: Already Assigned Conversation Not Re-Assigned')
# Create and assign a conversation
conv3 = create_test_conversation(inbox, contact_name: 'Customer 3', status: 'open')
run_assignment(inbox)
conv3.reload
original_assignee = conv3.assignee
info("Conversation initially assigned to: #{original_assignee.name}")
# Update something else (not status, not assignee)
conv3.update!(additional_attributes: { test: 'value' })
# Simulate real-time trigger
assigned_count_3 = run_assignment(inbox)
# Verify no re-assignment
log('Verifying already-assigned conversation not re-assigned...', color: :blue)
# Should assign 0 (conversation already has assignee)
no_reassign = assert_equal(
assigned_count_3,
0,
'No conversations re-assigned'
)
conv3.reload
same_assignee = assert(
conv3.assignee_id == original_assignee.id,
'Conversation keeps original assignee',
'Conversation was re-assigned (should not be)'
)
test3_ok = no_reassign && same_assignee
# Test 4: Resolved conversation changing to open triggers assignment
section('Test 4: Resolved → Open Triggers Assignment')
# Create and resolve a conversation
conv4 = create_test_conversation(inbox, contact_name: 'Returning Customer', status: 'open')
run_assignment(inbox)
conv4.reload
conv4.update!(status: 'resolved', assignee: nil)
info('Conversation resolved and unassigned')
# Reopen conversation
conv4.update!(status: 'open')
info('Conversation reopened (status: open)')
# Simulate real-time trigger
assigned_count_4 = run_assignment(inbox)
# Verify re-assignment
log('Verifying reopened conversation assigned...', color: :blue)
assigned_ok_4 = assert_equal(
assigned_count_4,
1,
'Reopened conversation assigned'
)
conv4.reload
has_assignee_4 = assert(
conv4.assignee_id.present?,
'Reopened conversation has assignee',
'Reopened conversation not assigned'
)
test4_ok = assigned_ok_4 && has_assignee_4
# Test 5: Assignment respects online status in real-time
section('Test 5: Real-Time Assignment Respects Agent Availability')
# Take agent offline
OnlineStatusTracker.set_status(account.id, agent.id, 'offline')
info("Took #{agent.name} offline")
# Create new conversation
conv5 = create_test_conversation(inbox, contact_name: 'Customer During Offline', status: 'open')
# Simulate real-time trigger
assigned_count_5 = run_assignment(inbox)
# Verify no assignment (agent offline)
log('Verifying no assignment when agent offline...', color: :blue)
no_assign_offline = assert_equal(
assigned_count_5,
0,
'No assignment when agent offline'
)
conv5.reload
unassigned_offline = assert(
conv5.assignee_id.nil?,
'Conversation remains unassigned when agent offline',
'Conversation was assigned despite agent being offline'
)
# Bring agent back online
OnlineStatusTracker.update_presence(account.id, 'User', agent.id)
OnlineStatusTracker.set_status(account.id, agent.id, 'online')
info("Brought #{agent.name} back online")
# Simulate real-time trigger (next conversation triggers assignment for backlog)
assigned_count_6 = run_assignment(inbox)
# Now should assign
assigned_after_online = assert_equal(
assigned_count_6,
1,
'Assignment happens when agent comes online'
)
test5_ok = no_assign_offline && unassigned_offline && assigned_after_online
# Final result
if test1_ok && test2_ok && test3_ok && test4_ok && test5_ok
section('✓ ALL TESTS PASSED')
true
else
section('✗ SOME TESTS FAILED')
false
end
rescue StandardError => e
error("Test failed with error: #{e.message}")
puts e.backtrace.first(5).join("\n")
false
ensure
cleanup_test_data(account, inbox: inbox) if inbox
end
end
end
# Run test and exit with appropriate code
exit(TestRealTimeTrigger.new.run ? 0 : 1)