Files
moreminimore-chat/spec/enterprise/models/applied_sla_spec.rb
Aakash Bakhle 6f6ddc5636 fix: flaky AppliedSla scope spec after Rails reloads (#15327)
CI no longer fails when the AppliedSla scope spec runs after Rails
reloads model classes. The spec now compares record IDs, so it checks
which SLA records the scope returns without depending on Ruby class
identity.

## How to reproduce

Run the report builder and assignment policy controller specs before
`spec/enterprise/models/applied_sla_spec.rb` in the same RSpec process.
Before the fix, the scope returns records with the expected IDs, but the
assertion rejects them because FactoryBot and Rails use different
`AppliedSla` class objects after the reload.

## What changed

The spec reads the IDs returned by `with_sla_applicable_conversation`
and checks the normal conversation, missing contact, and blocked contact
cases with those IDs.

The affected CircleCI shard passes locally after the change.
2026-08-05 14:07:04 +05:30

172 lines
6.6 KiB
Ruby

require 'rails_helper'
RSpec.describe AppliedSla, type: :model do
describe 'associations' do
it { is_expected.to belong_to(:sla_policy) }
it { is_expected.to belong_to(:account) }
it { is_expected.to belong_to(:conversation) }
end
describe 'push_event_data' do
it 'returns the correct hash' do
applied_sla = create(:applied_sla)
expect(applied_sla.push_event_data).to eq(
{
id: applied_sla.id,
sla_id: applied_sla.sla_policy_id,
sla_status: applied_sla.sla_status,
created_at: applied_sla.created_at.to_i,
updated_at: applied_sla.updated_at.to_i,
sla_completed_at: nil,
sla_description: applied_sla.sla_policy.description,
sla_name: applied_sla.sla_policy.name,
sla_first_response_time_threshold: applied_sla.sla_policy.first_response_time_threshold,
sla_next_response_time_threshold: applied_sla.sla_policy.next_response_time_threshold,
sla_only_during_business_hours: applied_sla.sla_policy.only_during_business_hours,
sla_resolution_time_threshold: applied_sla.sla_policy.resolution_time_threshold,
sla_frt_due_at: applied_sla.frt_due_at,
sla_nrt_due_at: applied_sla.nrt_due_at,
sla_rt_due_at: applied_sla.rt_due_at
}
)
end
it 'shares the working hours cache while serializing due times' do
account = create(:account)
inbox = create(:inbox, account: account, working_hours_enabled: true, timezone: 'UTC')
sla_policy = create(
:sla_policy,
account: account,
first_response_time_threshold: 1.hour,
next_response_time_threshold: 30.minutes,
resolution_time_threshold: 2.hours,
only_during_business_hours: true
)
start_time = Time.zone.parse('2024-01-17 10:00:00')
conversation = create(
:conversation,
account: account,
inbox: inbox,
created_at: start_time,
waiting_since: start_time + 1.hour
)
conversation.update!(waiting_since: start_time + 1.hour)
applied_sla = create(:applied_sla, account: account, conversation: conversation, sla_policy: sla_policy)
working_hours = inbox.working_hours
expect(working_hours).to receive(:index_by).once.and_call_original
expect(applied_sla.push_event_data).to include(
sla_frt_due_at: Time.zone.parse('2024-01-17 11:00:00').to_i,
sla_nrt_due_at: Time.zone.parse('2024-01-17 11:30:00').to_i,
sla_rt_due_at: Time.zone.parse('2024-01-17 12:00:00').to_i
)
end
end
describe 'validates_factory' do
it 'creates valid applied sla policy object' do
applied_sla = create(:applied_sla)
expect(applied_sla.sla_status).to eq 'active'
end
end
describe '.with_sla_applicable_conversation' do
it 'excludes blocked contacts and keeps conversations with missing contacts' do
applied_sla = create(:applied_sla)
blocked_applied_sla = create(:applied_sla)
missing_contact_applied_sla = create(:applied_sla)
blocked_applied_sla.conversation.contact.update!(blocked: true)
missing_contact_applied_sla.conversation.update_columns(contact_id: nil, contact_inbox_id: nil) # rubocop:disable Rails/SkipsModelValidations
applicable_sla_ids = described_class.with_sla_applicable_conversation.ids
expect(applicable_sla_ids).to include(applied_sla.id, missing_contact_applied_sla.id)
expect(applicable_sla_ids).not_to include(blocked_applied_sla.id)
end
end
describe '#frt_due_at' do
it 'returns nil when first_response_time_threshold is blank' do
applied_sla = create(:applied_sla)
applied_sla.sla_policy.update!(first_response_time_threshold: nil)
expect(applied_sla.frt_due_at).to be_nil
end
it 'returns deadline based on conversation created_at' do
applied_sla = create(:applied_sla)
applied_sla.sla_policy.update!(first_response_time_threshold: 3600, only_during_business_hours: false)
expected_deadline = applied_sla.conversation.created_at.to_i + 3600
expect(applied_sla.frt_due_at).to eq(expected_deadline)
end
end
describe '#nrt_due_at' do
it 'returns nil when next_response_time_threshold is blank' do
applied_sla = create(:applied_sla)
applied_sla.sla_policy.update!(next_response_time_threshold: nil)
expect(applied_sla.nrt_due_at).to be_nil
end
it 'returns nil when waiting_since is blank' do
applied_sla = create(:applied_sla)
applied_sla.sla_policy.update!(next_response_time_threshold: 1800)
applied_sla.conversation.update!(waiting_since: nil)
expect(applied_sla.nrt_due_at).to be_nil
end
it 'returns deadline based on waiting_since' do
applied_sla = create(:applied_sla)
waiting_since = 2.hours.ago
applied_sla.sla_policy.update!(next_response_time_threshold: 1800, only_during_business_hours: false)
applied_sla.conversation.update!(waiting_since: waiting_since)
expected_deadline = waiting_since.to_i + 1800
expect(applied_sla.nrt_due_at).to eq(expected_deadline)
end
end
describe '#rt_due_at' do
it 'returns nil when resolution_time_threshold is blank' do
applied_sla = create(:applied_sla)
applied_sla.sla_policy.update!(resolution_time_threshold: nil)
expect(applied_sla.rt_due_at).to be_nil
end
it 'returns deadline based on conversation created_at' do
applied_sla = create(:applied_sla)
applied_sla.sla_policy.update!(resolution_time_threshold: 7200, only_during_business_hours: false)
expected_deadline = applied_sla.conversation.created_at.to_i + 7200
expect(applied_sla.rt_due_at).to eq(expected_deadline)
end
end
describe '#calculate_due_at' do
it 'uses BusinessHoursService when only_during_business_hours is true' do
account = create(:account)
inbox = create(:inbox, account: account, working_hours_enabled: true)
sla_policy = create(:sla_policy, account: account, first_response_time_threshold: 3600, only_during_business_hours: true)
conversation = create(:conversation, account: account, inbox: inbox)
applied_sla = create(:applied_sla, sla_policy: sla_policy, conversation: conversation, account: account)
expect(Sla::BusinessHoursService).to receive(:new).and_call_original
applied_sla.frt_due_at
end
it 'does not use BusinessHoursService when only_during_business_hours is false' do
applied_sla = create(:applied_sla)
applied_sla.sla_policy.update!(first_response_time_threshold: 3600, only_during_business_hours: false)
expect(Sla::BusinessHoursService).not_to receive(:new)
applied_sla.frt_due_at
end
end
end