trabajo-afectivo/spec/models/cti/caller_id_spec.rb

327 lines
12 KiB
Ruby
Raw Permalink Normal View History

# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
require 'rails_helper'
RSpec.describe Cti::CallerId do
describe '.extract_numbers' do
context 'for strings containing arbitrary numbers (<6 digits long)' do
it 'returns an empty array' do
expect(described_class.extract_numbers(<<~INPUT.chomp)).to be_empty
some text
test 123
INPUT
end
end
context 'for strings containing a phone number with "(0)" after country code' do
it 'returns the number in an array, without the leading "(0)"' do
expect(described_class.extract_numbers(<<~INPUT.chomp)).to eq(['4930600000000'])
Lorem ipsum dolor sit amet, consectetuer +49 (0) 30 60 00 00 00-0
adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur
ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu,
pretium quis, sem. Nulla consequat massa quis enim. Donec pede
justo, fringilla vel.
INPUT
end
end
context 'for strings containing a phone number with leading 0 (no country code)' do
it 'returns the number in an array, using default country code (49)' do
expect(described_class.extract_numbers(<<~INPUT.chomp)).to eq(['4994221000'])
GS Oberalteich
Telefon 09422 1000
E-Mail:
INPUT
end
end
context 'for strings containing multiple phone numbers' do
it 'returns all numbers in an array' do
expect(described_class.extract_numbers(<<~INPUT.chomp)).to eq(%w[41812886393 41763467214])
Tel +41 81 288 63 93 / +41 76 346 72 14 ...
INPUT
end
end
context 'for strings containing US-formatted numbers' do
it 'returns the numbers in an array correctly' do
expect(described_class.extract_numbers(<<~INPUT.chomp)).to eq(%w[19494310000 19494310001])
P: +1 (949) 431 0000
F: +1 (949) 431 0001
W: http://znuny
INPUT
end
end
end
describe '.normalize_number' do
it 'does not modify digit-only strings (starting with 1-9)' do
expect(described_class.normalize_number('5754321')).to eq('5754321')
end
it 'strips whitespace' do
expect(described_class.normalize_number('622 32281')).to eq('62232281')
end
it 'strips hyphens' do
expect(described_class.normalize_number('1-888-407-4747')).to eq('18884074747')
end
it 'strips leading pluses' do
expect(described_class.normalize_number('+49 30 53 00 00 000')).to eq('4930530000000')
expect(described_class.normalize_number('+49 160 0000000')).to eq('491600000000')
end
it 'replaces a single leading zero with the default country code (49)' do
expect(described_class.normalize_number('092213212')).to eq('4992213212')
expect(described_class.normalize_number('0271233211')).to eq('49271233211')
expect(described_class.normalize_number('022 1234567')).to eq('49221234567')
expect(described_class.normalize_number('09 123 32112')).to eq('49912332112')
expect(described_class.normalize_number('021 2331231')).to eq('49212331231')
expect(described_class.normalize_number('021 321123123')).to eq('4921321123123')
expect(described_class.normalize_number('0150 12345678')).to eq('4915012345678')
expect(described_class.normalize_number('021-233-9123')).to eq('49212339123')
end
it 'strips two leading zeroes' do
expect(described_class.normalize_number('0049 1234 123456789')).to eq('491234123456789')
expect(described_class.normalize_number('0043 30 60 00 00 00-0')).to eq('4330600000000')
end
it 'strips leading zero from "(0x)" at start of number or after country code' do
expect(described_class.normalize_number('(09)1234321')).to eq('4991234321')
expect(described_class.normalize_number('+49 (0) 30 60 00 00 00-0')).to eq('4930600000000')
expect(described_class.normalize_number('0043 (0) 30 60 00 00 00-0')).to eq('4330600000000')
end
end
describe '.lookup' do
context 'when given an unrecognized number' do
it 'returns an empty array' do
expect(described_class.lookup('1')).to eq([])
end
end
context 'when given a recognized number' do
subject!(:caller_id) { create(:caller_id, caller_id: number) }
let(:number) { '1234567890' }
it 'returns an array with the corresponding CallerId' do
expect(described_class.lookup(number)).to match_array([caller_id])
end
context 'shared by multiple CallerIds' do
context '(for different users)' do
subject!(:caller_ids) do
[create(:caller_id, caller_id: number, user: create(:user)),
create(:caller_id, caller_id: number, user: create(:user))]
end
it 'returns all corresponding CallerId records' do
expect(described_class.lookup(number)).to match_array(caller_ids)
end
end
context '(for the same user)' do
subject!(:caller_ids) { create_list(:caller_id, 2, caller_id: number) }
it 'returns one corresponding CallerId record by MAX(id)' do
expect(described_class.lookup(number)).to match_array(caller_ids.last(1))
end
end
context '(some for the same user, some for another)' do
subject!(:caller_ids) do
[*create_list(:caller_id, 2, caller_id: number, user: create(:user)),
create(:caller_id, caller_id: number, user: create(:user))]
end
it 'returns one CallerId record per unique #user_id, by MAX(id)' do
expect(described_class.lookup(number)).to match_array(caller_ids.last(2))
end
end
end
end
end
describe '.rebuild' do
context 'when a User record contains a valid phone number' do
let!(:user) { create(:agent, phone: '+49 123 456') }
context 'and no corresponding CallerId exists' do
it 'generates a CallerId record (with #level "known")' do
described_class.destroy_all # CallerId already generated in User callback
expect { described_class.rebuild }
.to change { described_class.exists?(user_id: user.id, caller_id: '49123456', level: 'known') }
.to(true)
end
end
it 'does not create duplicate CallerId records' do
expect { described_class.rebuild }.not_to change(described_class, :count)
end
end
context 'when no User exists for a given CallerId record' do
subject!(:caller_id) { create(:caller_id) }
it 'deletes the CallerId record' do
expect { described_class.rebuild }
.to change { described_class.exists?(caller_id.id) }.to(false)
end
end
context 'when two User records contains the same valid phone number' do
let!(:users) { create_list(:agent, 2, phone: '+49 123 456') }
it 'generates two corresponding CallerId records (with #level "known")' do
described_class.destroy_all # CallerId already generated in User callback
expect { described_class.rebuild }
.to change { described_class.exists?(user_id: users.first.id, caller_id: '49123456', level: 'known') }
.to(true)
.and change { described_class.exists?(user_id: users.last.id, caller_id: '49123456', level: 'known') }
.to(true)
end
end
context 'when an Article record contains a valid phone number in its body' do
let!(:article) { create(:ticket_article, body: <<~BODY, sender_name: sender_name) }
some message
Fon (GEL): +49 123-456 Mi-Fr
BODY
context 'and comes from a customer' do
let(:sender_name) { 'Customer' }
it 'generates a CallerId record (with #level "maybe")' do
described_class.destroy_all # CallerId already generated in Article observer job
expect { described_class.rebuild }
.to change { described_class.exists?(user_id: article.created_by_id, caller_id: '49123456', level: 'maybe') }
.to(true)
end
end
context 'and comes from an Agent' do
let(:sender_name) { 'Agent' }
it 'does not generate a CallerId record' do
expect { described_class.rebuild }
.not_to change { described_class.exists?(caller_id: '49123456') }
end
end
end
end
describe '.maybe_add' do
let(:attributes) { attributes_for(:caller_id) }
it 'wraps .find_or_initialize_by (passing only five defining attributes)' do
expect(described_class)
.to receive(:find_or_initialize_by)
.with(attributes.slice(:caller_id, :level, :object, :o_id, :user_id))
.and_call_original
described_class.maybe_add(attributes)
end
context 'if no matching record found' do
it 'adds given #comment attribute' do
expect { described_class.maybe_add(attributes.merge(comment: 'foo')) }
.to change(described_class, :count).by(1)
expect(described_class.last.comment).to eq('foo')
end
end
context 'if matching record found' do
let(:attributes) { caller_id.attributes.symbolize_keys }
let(:caller_id) { create(:caller_id) }
it 'ignores given #comment attribute' do
expect(described_class.maybe_add(attributes.merge(comment: 'foo')))
.to eq(caller_id)
expect(caller_id.comment).to be_blank
end
end
end
describe '.known_agents_by_number' do
context 'with known agent caller_id' do
let!(:agent1) { create(:agent, phone: '0123456') }
let!(:agent2) { create(:agent, phone: '0123457') }
it 'gives matching agents' do
expect(described_class.known_agents_by_number('49123456'))
.to match_array([agent1])
end
end
context 'with known customer caller_id' do
let!(:customer1) { create(:customer, phone: '0123456') }
it 'returns an empty array' do
expect(described_class.known_agents_by_number('49123456')).to eq([])
end
end
context 'with maybe caller_id' do
let(:ticket1) do
create(:ticket_article, created_by_id: customer2.id, body: 'some text 0123457') # create ticket
TransactionDispatcher.commit
Scheduler.worker(true)
end
let!(:customer2) { create(:customer) }
it 'returns an empty array' do
expect(described_class.known_agents_by_number('49123457').count).to eq(0)
end
end
end
describe 'callbacks' do
subject!(:caller_id) { build(:cti_caller_id, caller_id: phone) }
let(:phone) { '1234567890' }
describe 'on creation' do
it 'adopts CTI Logs from same number (via UpdateCtiLogsByCallerJob)' do
expect(UpdateCtiLogsByCallerJob).to receive(:perform_later)
caller_id.save
end
it 'splits job into fg and bg (for more responsive UI see #2057)' do
expect(UpdateCtiLogsByCallerJob).to receive(:perform_now).with(phone, limit: 20)
expect(UpdateCtiLogsByCallerJob).to receive(:perform_later).with(phone, limit: 40, offset: 20)
caller_id.save
end
it 'skips jobs on import_mode true' do
Setting.set('import_mode', true)
expect(UpdateCtiLogsByCallerJob).not_to receive(:perform_now)
expect(UpdateCtiLogsByCallerJob).not_to receive(:perform_later)
caller_id.save
end
end
describe 'on destruction' do
before { caller_id.save }
it 'orphans CTI Logs from same number (via UpdateCtiLogsByCallerJob)' do
expect(UpdateCtiLogsByCallerJob).to receive(:perform_later).with(phone)
caller_id.destroy
end
end
end
end