@webex/contact-center 3.10.0-next.2 → 3.10.0-next.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cc.js +13 -1
- package/dist/cc.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/logger-proxy.js.map +1 -1
- package/dist/metrics/MetricsManager.js +2 -1
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +12 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +4 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +2 -3
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/EntryPoint.js +2 -3
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +2 -3
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/WebCallingService.js +1 -1
- package/dist/services/WebCallingService.js.map +1 -1
- package/dist/services/agent/index.js +1 -2
- package/dist/services/agent/index.js.map +1 -1
- package/dist/services/agent/types.js +10 -0
- package/dist/services/agent/types.js.map +1 -1
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +1 -1
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +2 -2
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/GlobalTypes.js.map +1 -1
- package/dist/services/core/Utils.js +92 -74
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/WebexRequest.js +1 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +2 -3
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/constants.js +17 -1
- package/dist/services/core/constants.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +1 -2
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/connection-service.js +1 -1
- package/dist/services/core/websocket/connection-service.js.map +1 -1
- package/dist/services/core/websocket/keepalive.worker.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/AutoWrapup.js +1 -1
- package/dist/services/task/AutoWrapup.js.map +1 -1
- package/dist/services/task/TaskManager.js +177 -56
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +122 -5
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +3 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +0 -2
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/index.js +46 -40
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +377 -4
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +6 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/metrics/constants.d.ts +4 -0
- package/dist/types/services/config/types.d.ts +4 -4
- package/dist/types/services/core/Utils.d.ts +32 -17
- package/dist/types/services/core/constants.d.ts +14 -0
- package/dist/types/services/task/TaskUtils.d.ts +59 -3
- package/dist/types/services/task/constants.d.ts +2 -0
- package/dist/types/services/task/types.d.ts +57 -13
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +1 -1
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex-config.js.map +1 -1
- package/dist/webex.js +2 -2
- package/dist/webex.js.map +1 -1
- package/package.json +8 -8
- package/src/cc.ts +12 -0
- package/src/index.ts +1 -0
- package/src/metrics/behavioral-events.ts +12 -0
- package/src/metrics/constants.ts +4 -0
- package/src/services/config/types.ts +2 -2
- package/src/services/core/Utils.ts +101 -85
- package/src/services/core/constants.ts +16 -0
- package/src/services/task/TaskManager.ts +204 -36
- package/src/services/task/TaskUtils.ts +145 -5
- package/src/services/task/constants.ts +2 -0
- package/src/services/task/index.ts +50 -63
- package/src/services/task/types.ts +60 -13
- package/test/unit/spec/cc.ts +1 -0
- package/test/unit/spec/metrics/behavioral-events.ts +14 -0
- package/test/unit/spec/services/core/Utils.ts +262 -31
- package/test/unit/spec/services/task/TaskManager.ts +748 -5
- package/test/unit/spec/services/task/TaskUtils.ts +311 -9
- package/test/unit/spec/services/task/index.ts +323 -68
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -479,6 +479,73 @@ describe('TaskManager', () => {
|
|
|
479
479
|
);
|
|
480
480
|
});
|
|
481
481
|
|
|
482
|
+
it('should set isConferenceInProgress correctly when creating task via AGENT_CONTACT with conference in progress', () => {
|
|
483
|
+
const testAgentId = '723a8ffb-a26e-496d-b14a-ff44fb83b64f';
|
|
484
|
+
taskManager.setAgentId(testAgentId);
|
|
485
|
+
taskManager.taskCollection = [];
|
|
486
|
+
|
|
487
|
+
const payload = {
|
|
488
|
+
data: {
|
|
489
|
+
...initalPayload.data,
|
|
490
|
+
type: CC_EVENTS.AGENT_CONTACT,
|
|
491
|
+
interaction: {
|
|
492
|
+
mediaType: 'telephony',
|
|
493
|
+
state: 'conference',
|
|
494
|
+
participants: {
|
|
495
|
+
[testAgentId]: { pType: 'Agent', hasLeft: false },
|
|
496
|
+
'agent-2': { pType: 'Agent', hasLeft: false },
|
|
497
|
+
'customer-1': { pType: 'Customer', hasLeft: false },
|
|
498
|
+
},
|
|
499
|
+
media: {
|
|
500
|
+
[taskId]: {
|
|
501
|
+
mType: 'mainCall',
|
|
502
|
+
participants: [testAgentId, 'agent-2', 'customer-1'],
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
510
|
+
|
|
511
|
+
const createdTask = taskManager.getTask(taskId);
|
|
512
|
+
expect(createdTask).toBeDefined();
|
|
513
|
+
expect(createdTask.data.isConferenceInProgress).toBe(true);
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
it('should set isConferenceInProgress to false when creating task via AGENT_CONTACT with only one agent', () => {
|
|
517
|
+
const testAgentId = '723a8ffb-a26e-496d-b14a-ff44fb83b64f';
|
|
518
|
+
taskManager.setAgentId(testAgentId);
|
|
519
|
+
taskManager.taskCollection = [];
|
|
520
|
+
|
|
521
|
+
const payload = {
|
|
522
|
+
data: {
|
|
523
|
+
...initalPayload.data,
|
|
524
|
+
type: CC_EVENTS.AGENT_CONTACT,
|
|
525
|
+
interaction: {
|
|
526
|
+
mediaType: 'telephony',
|
|
527
|
+
state: 'connected',
|
|
528
|
+
participants: {
|
|
529
|
+
[testAgentId]: { pType: 'Agent', hasLeft: false },
|
|
530
|
+
'customer-1': { pType: 'Customer', hasLeft: false },
|
|
531
|
+
},
|
|
532
|
+
media: {
|
|
533
|
+
[taskId]: {
|
|
534
|
+
mType: 'mainCall',
|
|
535
|
+
participants: [testAgentId, 'customer-1'],
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
543
|
+
|
|
544
|
+
const createdTask = taskManager.getTask(taskId);
|
|
545
|
+
expect(createdTask).toBeDefined();
|
|
546
|
+
expect(createdTask.data.isConferenceInProgress).toBe(false);
|
|
547
|
+
});
|
|
548
|
+
|
|
482
549
|
it('should emit TASK_END event on AGENT_WRAPUP event', () => {
|
|
483
550
|
webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
|
|
484
551
|
|
|
@@ -606,14 +673,181 @@ describe('TaskManager', () => {
|
|
|
606
673
|
expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
|
|
607
674
|
});
|
|
608
675
|
|
|
609
|
-
|
|
676
|
+
describe('Auto-Answer Functionality', () => {
|
|
677
|
+
it('should emit both TASK_OFFER_CONTACT and TASK_AUTO_ANSWERED events when auto-answer succeeds', async () => {
|
|
678
|
+
// Step 1: Create the task first with initial payload
|
|
679
|
+
webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
|
|
680
|
+
|
|
681
|
+
const task = taskManager.getTask(taskId);
|
|
682
|
+
const taskEmitSpy = jest.spyOn(task, 'emit');
|
|
683
|
+
const taskManagerEmitSpy = jest.spyOn(taskManager, 'emit');
|
|
684
|
+
const taskAcceptSpy = jest.spyOn(task, 'accept').mockResolvedValue(undefined);
|
|
685
|
+
|
|
686
|
+
// Step 2: Trigger AGENT_OFFER_CONTACT with auto-answer
|
|
687
|
+
const autoAnswerPayload = {
|
|
688
|
+
data: {
|
|
689
|
+
...initalPayload.data,
|
|
690
|
+
type: CC_EVENTS.AGENT_OFFER_CONTACT,
|
|
691
|
+
isAutoAnswering: true,
|
|
692
|
+
interaction: {
|
|
693
|
+
...initalPayload.data.interaction,
|
|
694
|
+
mediaType: 'telephony',
|
|
695
|
+
state: 'new',
|
|
696
|
+
},
|
|
697
|
+
},
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
webSocketManagerMock.emit('message', JSON.stringify(autoAnswerPayload));
|
|
701
|
+
|
|
702
|
+
// Wait for async auto-answer to complete
|
|
703
|
+
await new Promise(process.nextTick);
|
|
704
|
+
|
|
705
|
+
// Verify accept was called
|
|
706
|
+
expect(taskAcceptSpy).toHaveBeenCalledTimes(1);
|
|
707
|
+
|
|
708
|
+
// Verify BOTH events were emitted
|
|
709
|
+
expect(taskManagerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_OFFER_CONTACT, task);
|
|
710
|
+
expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_AUTO_ANSWERED, task);
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
it('should NOT emit TASK_AUTO_ANSWERED event when auto-answer fails', async () => {
|
|
714
|
+
// Step 1: Create the task first with initial payload
|
|
715
|
+
webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
|
|
716
|
+
|
|
717
|
+
const task = taskManager.getTask(taskId);
|
|
718
|
+
const taskEmitSpy = jest.spyOn(task, 'emit');
|
|
719
|
+
const taskAcceptSpy = jest.spyOn(task, 'accept').mockRejectedValue(new Error('Accept failed'));
|
|
720
|
+
|
|
721
|
+
// Step 2: Trigger AGENT_OFFER_CONTACT with auto-answer (will fail)
|
|
722
|
+
const autoAnswerPayload = {
|
|
723
|
+
data: {
|
|
724
|
+
...initalPayload.data,
|
|
725
|
+
type: CC_EVENTS.AGENT_OFFER_CONTACT,
|
|
726
|
+
isAutoAnswering: true,
|
|
727
|
+
interaction: {
|
|
728
|
+
...initalPayload.data.interaction,
|
|
729
|
+
mediaType: 'telephony',
|
|
730
|
+
state: 'new',
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
webSocketManagerMock.emit('message', JSON.stringify(autoAnswerPayload));
|
|
736
|
+
|
|
737
|
+
// Wait for async auto-answer to complete
|
|
738
|
+
await new Promise(process.nextTick);
|
|
739
|
+
|
|
740
|
+
// Verify accept was called
|
|
741
|
+
expect(taskAcceptSpy).toHaveBeenCalledTimes(1);
|
|
742
|
+
|
|
743
|
+
// Verify TASK_AUTO_ANSWERED event was NOT emitted on failure
|
|
744
|
+
expect(taskEmitSpy).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_AUTO_ANSWERED, task);
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
it('should emit both TASK_OFFER_CONSULT and TASK_AUTO_ANSWERED events for consult with auto-answer', async () => {
|
|
748
|
+
// Step 1: Create the task first with initial payload
|
|
749
|
+
webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
|
|
750
|
+
|
|
751
|
+
const task = taskManager.getTask(taskId);
|
|
752
|
+
const taskEmitSpy = jest.spyOn(task, 'emit');
|
|
753
|
+
const taskAcceptSpy = jest.spyOn(task, 'accept').mockResolvedValue(undefined);
|
|
754
|
+
|
|
755
|
+
// Step 2: Trigger AGENT_OFFER_CONSULT with auto-answer
|
|
756
|
+
const consultAutoAnswerPayload = {
|
|
757
|
+
data: {
|
|
758
|
+
...initalPayload.data,
|
|
759
|
+
type: CC_EVENTS.AGENT_OFFER_CONSULT,
|
|
760
|
+
isAutoAnswering: true,
|
|
761
|
+
isConsulted: true,
|
|
762
|
+
interaction: {
|
|
763
|
+
...initalPayload.data.interaction,
|
|
764
|
+
mediaType: 'telephony',
|
|
765
|
+
state: 'consult',
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
webSocketManagerMock.emit('message', JSON.stringify(consultAutoAnswerPayload));
|
|
771
|
+
|
|
772
|
+
// Wait for async auto-answer to complete
|
|
773
|
+
await new Promise(process.nextTick);
|
|
774
|
+
|
|
775
|
+
// Verify accept was called
|
|
776
|
+
expect(taskAcceptSpy).toHaveBeenCalledTimes(1);
|
|
777
|
+
|
|
778
|
+
// Verify BOTH events were emitted
|
|
779
|
+
expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_OFFER_CONSULT, task);
|
|
780
|
+
expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_AUTO_ANSWERED, task);
|
|
781
|
+
|
|
782
|
+
// Verify isConsulted flag is set correctly
|
|
783
|
+
expect(task.data.isConsulted).toBe(true);
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
it('should NOT emit TASK_AUTO_ANSWERED when isAutoAnswering is false', async () => {
|
|
787
|
+
// Step 1: Create the task first with initial payload
|
|
788
|
+
webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
|
|
789
|
+
|
|
790
|
+
const task = taskManager.getTask(taskId);
|
|
791
|
+
const taskEmitSpy = jest.spyOn(task, 'emit');
|
|
792
|
+
const taskAcceptSpy = jest.spyOn(task, 'accept').mockResolvedValue(undefined);
|
|
793
|
+
|
|
794
|
+
// Step 2: Trigger AGENT_OFFER_CONTACT without auto-answer
|
|
795
|
+
const normalPayload = {
|
|
796
|
+
data: {
|
|
797
|
+
...initalPayload.data,
|
|
798
|
+
type: CC_EVENTS.AGENT_OFFER_CONTACT,
|
|
799
|
+
isAutoAnswering: false,
|
|
800
|
+
interaction: {
|
|
801
|
+
...initalPayload.data.interaction,
|
|
802
|
+
mediaType: 'telephony',
|
|
803
|
+
state: 'new',
|
|
804
|
+
},
|
|
805
|
+
},
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
webSocketManagerMock.emit('message', JSON.stringify(normalPayload));
|
|
809
|
+
|
|
810
|
+
// Wait for any async operations
|
|
811
|
+
await new Promise(process.nextTick);
|
|
812
|
+
|
|
813
|
+
// Verify accept was NOT called
|
|
814
|
+
expect(taskAcceptSpy).not.toHaveBeenCalled();
|
|
815
|
+
|
|
816
|
+
// Verify TASK_AUTO_ANSWERED event was NOT emitted
|
|
817
|
+
expect(taskEmitSpy).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_AUTO_ANSWERED, expect.anything());
|
|
818
|
+
});
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
it('should NOT remove OUTDIAL task from taskCollection on AGENT_OUTBOUND_FAILED when terminated (wrap-up flow)', () => {
|
|
822
|
+
const task = taskManager.getTask(taskId);
|
|
823
|
+
task.updateTaskData = jest.fn().mockImplementation((newData) => {
|
|
824
|
+
task.data = {
|
|
825
|
+
...task.data,
|
|
826
|
+
...newData,
|
|
827
|
+
interaction: {
|
|
828
|
+
...task.data.interaction,
|
|
829
|
+
...newData.interaction,
|
|
830
|
+
outboundType: 'OUTDIAL',
|
|
831
|
+
state: 'new',
|
|
832
|
+
isTerminated: true,
|
|
833
|
+
},
|
|
834
|
+
};
|
|
835
|
+
return task;
|
|
836
|
+
});
|
|
837
|
+
task.unregisterWebCallListeners = jest.fn();
|
|
838
|
+
const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
|
|
839
|
+
|
|
610
840
|
const payload = {
|
|
611
841
|
data: {
|
|
612
842
|
type: CC_EVENTS.AGENT_OUTBOUND_FAILED,
|
|
613
843
|
agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
614
844
|
eventTime: 1733211616959,
|
|
615
845
|
eventType: 'RoutingMessage',
|
|
616
|
-
interaction: {
|
|
846
|
+
interaction: {
|
|
847
|
+
outboundType: 'OUTDIAL',
|
|
848
|
+
state: 'new',
|
|
849
|
+
isTerminated: true,
|
|
850
|
+
},
|
|
617
851
|
interactionId: taskId,
|
|
618
852
|
orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
|
|
619
853
|
trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
|
|
@@ -621,14 +855,220 @@ describe('TaskManager', () => {
|
|
|
621
855
|
destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
|
|
622
856
|
owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
623
857
|
queueMgr: 'aqm',
|
|
858
|
+
reason: 'CUSTOMER_BUSY',
|
|
859
|
+
reasonCode: 1022,
|
|
624
860
|
},
|
|
625
861
|
};
|
|
626
862
|
|
|
627
|
-
|
|
863
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
864
|
+
|
|
865
|
+
expect(taskManager.getTask(taskId)).toBeDefined();
|
|
866
|
+
expect(removeTaskSpy).not.toHaveBeenCalled();
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
it('should emit TASK_OUTDIAL_FAILED event on AGENT_OUTBOUND_FAILED', () => {
|
|
870
|
+
const task = taskManager.getTask(taskId);
|
|
871
|
+
task.updateTaskData = jest.fn().mockReturnValue(task);
|
|
872
|
+
const taskEmitSpy = jest.spyOn(task, 'emit');
|
|
873
|
+
const payload = {
|
|
874
|
+
data: {
|
|
875
|
+
type: CC_EVENTS.AGENT_OUTBOUND_FAILED,
|
|
876
|
+
interactionId: taskId,
|
|
877
|
+
reason: 'CUSTOMER_BUSY',
|
|
878
|
+
},
|
|
879
|
+
};
|
|
880
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
881
|
+
expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_OUTDIAL_FAILED, 'CUSTOMER_BUSY');
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
it('should handle AGENT_OUTBOUND_FAILED gracefully when task is undefined', () => {
|
|
885
|
+
const payload = {
|
|
886
|
+
data: {
|
|
887
|
+
type: CC_EVENTS.AGENT_OUTBOUND_FAILED,
|
|
888
|
+
interactionId: 'non-existent-task-id',
|
|
889
|
+
reason: 'CUSTOMER_BUSY',
|
|
890
|
+
},
|
|
891
|
+
};
|
|
892
|
+
// Should not throw error when task doesn't exist
|
|
893
|
+
expect(() => {
|
|
894
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
895
|
+
}).not.toThrow();
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
it('should NOT remove OUTDIAL task on CONTACT_ENDED when agentsPendingWrapUp exists', () => {
|
|
899
|
+
const task = taskManager.getTask(taskId);
|
|
900
|
+
task.updateTaskData = jest.fn().mockImplementation((newData) => {
|
|
901
|
+
task.data = {
|
|
902
|
+
...task.data,
|
|
903
|
+
...newData,
|
|
904
|
+
interaction: {
|
|
905
|
+
...task.data.interaction,
|
|
906
|
+
outboundType: 'OUTDIAL',
|
|
907
|
+
state: 'new',
|
|
908
|
+
mediaType: 'telephony',
|
|
909
|
+
},
|
|
910
|
+
agentsPendingWrapUp: ['agent-123'],
|
|
911
|
+
};
|
|
912
|
+
return task;
|
|
913
|
+
});
|
|
914
|
+
task.unregisterWebCallListeners = jest.fn();
|
|
915
|
+
const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
|
|
916
|
+
|
|
917
|
+
const payload = {
|
|
918
|
+
data: {
|
|
919
|
+
type: CC_EVENTS.CONTACT_ENDED,
|
|
920
|
+
interactionId: taskId,
|
|
921
|
+
interaction: {
|
|
922
|
+
outboundType: 'OUTDIAL',
|
|
923
|
+
state: 'new',
|
|
924
|
+
mediaType: 'telephony',
|
|
925
|
+
},
|
|
926
|
+
agentsPendingWrapUp: ['agent-123'],
|
|
927
|
+
},
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
931
|
+
|
|
932
|
+
expect(removeTaskSpy).not.toHaveBeenCalled();
|
|
933
|
+
expect(taskManager.getTask(taskId)).toBeDefined();
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
it('should remove OUTDIAL task on CONTACT_ENDED when agentsPendingWrapUp is empty', () => {
|
|
937
|
+
const task = taskManager.getTask(taskId);
|
|
938
|
+
task.updateTaskData = jest.fn().mockImplementation((newData) => {
|
|
939
|
+
task.data = {
|
|
940
|
+
...task.data,
|
|
941
|
+
...newData,
|
|
942
|
+
interaction: {
|
|
943
|
+
...task.data.interaction,
|
|
944
|
+
outboundType: 'OUTDIAL',
|
|
945
|
+
state: 'new',
|
|
946
|
+
mediaType: 'telephony',
|
|
947
|
+
},
|
|
948
|
+
agentsPendingWrapUp: [],
|
|
949
|
+
};
|
|
950
|
+
return task;
|
|
951
|
+
});
|
|
952
|
+
task.unregisterWebCallListeners = jest.fn();
|
|
953
|
+
const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
|
|
954
|
+
|
|
955
|
+
const payload = {
|
|
956
|
+
data: {
|
|
957
|
+
type: CC_EVENTS.CONTACT_ENDED,
|
|
958
|
+
interactionId: taskId,
|
|
959
|
+
interaction: {
|
|
960
|
+
outboundType: 'OUTDIAL',
|
|
961
|
+
state: 'new',
|
|
962
|
+
mediaType: 'telephony',
|
|
963
|
+
},
|
|
964
|
+
agentsPendingWrapUp: [],
|
|
965
|
+
},
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
969
|
+
|
|
970
|
+
expect(removeTaskSpy).toHaveBeenCalled();
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
it('should remove OUTDIAL task on CONTACT_ENDED when agentsPendingWrapUp is undefined', () => {
|
|
974
|
+
const task = taskManager.getTask(taskId);
|
|
975
|
+
task.updateTaskData = jest.fn().mockImplementation((newData) => {
|
|
976
|
+
task.data = {
|
|
977
|
+
...task.data,
|
|
978
|
+
...newData,
|
|
979
|
+
interaction: {
|
|
980
|
+
...task.data.interaction,
|
|
981
|
+
outboundType: 'OUTDIAL',
|
|
982
|
+
state: 'new',
|
|
983
|
+
mediaType: 'telephony',
|
|
984
|
+
},
|
|
985
|
+
// agentsPendingWrapUp is undefined
|
|
986
|
+
};
|
|
987
|
+
return task;
|
|
988
|
+
});
|
|
989
|
+
task.unregisterWebCallListeners = jest.fn();
|
|
990
|
+
const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
|
|
991
|
+
|
|
992
|
+
const payload = {
|
|
993
|
+
data: {
|
|
994
|
+
type: CC_EVENTS.CONTACT_ENDED,
|
|
995
|
+
interactionId: taskId,
|
|
996
|
+
interaction: {
|
|
997
|
+
outboundType: 'OUTDIAL',
|
|
998
|
+
state: 'new',
|
|
999
|
+
mediaType: 'telephony',
|
|
1000
|
+
},
|
|
1001
|
+
// agentsPendingWrapUp not included
|
|
1002
|
+
},
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1006
|
+
|
|
1007
|
+
expect(removeTaskSpy).toHaveBeenCalled();
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
it('should handle CONTACT_ENDED gracefully when task is undefined', () => {
|
|
1011
|
+
const payload = {
|
|
1012
|
+
data: {
|
|
1013
|
+
type: CC_EVENTS.CONTACT_ENDED,
|
|
1014
|
+
interactionId: 'non-existent-task-id',
|
|
1015
|
+
interaction: {
|
|
1016
|
+
state: 'new',
|
|
1017
|
+
},
|
|
1018
|
+
},
|
|
1019
|
+
};
|
|
1020
|
+
// Should not throw error when task doesn't exist
|
|
1021
|
+
expect(() => {
|
|
1022
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1023
|
+
}).not.toThrow();
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
it('should remove OUTDIAL task from taskCollection on AGENT_CONTACT_ASSIGN_FAILED when NOT terminated (user-declined)', () => {
|
|
1027
|
+
const task = taskManager.getTask(taskId);
|
|
1028
|
+
task.updateTaskData = jest.fn().mockImplementation((newData) => {
|
|
1029
|
+
task.data = {
|
|
1030
|
+
...task.data,
|
|
1031
|
+
...newData,
|
|
1032
|
+
interaction: {
|
|
1033
|
+
...task.data.interaction,
|
|
1034
|
+
...newData.interaction,
|
|
1035
|
+
outboundType: 'OUTDIAL',
|
|
1036
|
+
state: 'new',
|
|
1037
|
+
isTerminated: false,
|
|
1038
|
+
},
|
|
1039
|
+
};
|
|
1040
|
+
return task;
|
|
1041
|
+
});
|
|
1042
|
+
task.unregisterWebCallListeners = jest.fn();
|
|
1043
|
+
const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
|
|
1044
|
+
|
|
1045
|
+
const payload = {
|
|
1046
|
+
data: {
|
|
1047
|
+
type: CC_EVENTS.AGENT_CONTACT_ASSIGN_FAILED,
|
|
1048
|
+
agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
1049
|
+
eventTime: 1733211616959,
|
|
1050
|
+
eventType: 'RoutingMessage',
|
|
1051
|
+
interaction: {
|
|
1052
|
+
outboundType: 'OUTDIAL',
|
|
1053
|
+
state: 'new',
|
|
1054
|
+
isTerminated: false,
|
|
1055
|
+
},
|
|
1056
|
+
interactionId: taskId,
|
|
1057
|
+
orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
|
|
1058
|
+
trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
|
|
1059
|
+
mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
|
|
1060
|
+
destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
|
|
1061
|
+
owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
1062
|
+
queueMgr: 'aqm',
|
|
1063
|
+
reason: 'USER_DECLINED',
|
|
1064
|
+
reasonCode: 156,
|
|
1065
|
+
},
|
|
1066
|
+
};
|
|
628
1067
|
|
|
629
1068
|
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
630
1069
|
|
|
631
1070
|
expect(taskManager.getTask(taskId)).toBeUndefined();
|
|
1071
|
+
expect(removeTaskSpy).toHaveBeenCalled();
|
|
632
1072
|
});
|
|
633
1073
|
|
|
634
1074
|
it('handle AGENT_OFFER_CONSULT event', () => {
|
|
@@ -1353,7 +1793,7 @@ describe('TaskManager', () => {
|
|
|
1353
1793
|
expect(spy).toHaveBeenCalledWith(taskEvent, task);
|
|
1354
1794
|
});
|
|
1355
1795
|
});
|
|
1356
|
-
});
|
|
1796
|
+
});
|
|
1357
1797
|
|
|
1358
1798
|
describe('Conference event handling', () => {
|
|
1359
1799
|
let task;
|
|
@@ -1428,6 +1868,18 @@ describe('TaskManager', () => {
|
|
|
1428
1868
|
interactionId: taskId,
|
|
1429
1869
|
participantId: 'new-participant-123',
|
|
1430
1870
|
participantType: 'agent',
|
|
1871
|
+
interaction: {
|
|
1872
|
+
participants: {
|
|
1873
|
+
[agentId]: { pType: 'Agent', hasLeft: false },
|
|
1874
|
+
'new-participant-123': { pType: 'Agent', hasLeft: false },
|
|
1875
|
+
},
|
|
1876
|
+
media: {
|
|
1877
|
+
[taskId]: {
|
|
1878
|
+
mType: 'mainCall',
|
|
1879
|
+
participants: [agentId, 'new-participant-123'],
|
|
1880
|
+
},
|
|
1881
|
+
},
|
|
1882
|
+
},
|
|
1431
1883
|
},
|
|
1432
1884
|
};
|
|
1433
1885
|
|
|
@@ -1438,7 +1890,86 @@ describe('TaskManager', () => {
|
|
|
1438
1890
|
// No specific task event emission for participant joined - just data update
|
|
1439
1891
|
});
|
|
1440
1892
|
|
|
1893
|
+
it('should call updateTaskData only once for PARTICIPANT_JOINED_CONFERENCE with pre-calculated isConferenceInProgress', () => {
|
|
1894
|
+
const payload = {
|
|
1895
|
+
data: {
|
|
1896
|
+
type: CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE,
|
|
1897
|
+
interactionId: taskId,
|
|
1898
|
+
participantId: 'new-agent-789',
|
|
1899
|
+
interaction: {
|
|
1900
|
+
participants: {
|
|
1901
|
+
[agentId]: { pType: 'Agent', hasLeft: false },
|
|
1902
|
+
'agent-2': { pType: 'Agent', hasLeft: false },
|
|
1903
|
+
'new-agent-789': { pType: 'Agent', hasLeft: false },
|
|
1904
|
+
'customer-1': { pType: 'Customer', hasLeft: false },
|
|
1905
|
+
},
|
|
1906
|
+
media: {
|
|
1907
|
+
[taskId]: {
|
|
1908
|
+
mType: 'mainCall',
|
|
1909
|
+
participants: [agentId, 'agent-2', 'new-agent-789', 'customer-1'],
|
|
1910
|
+
},
|
|
1911
|
+
},
|
|
1912
|
+
},
|
|
1913
|
+
},
|
|
1914
|
+
};
|
|
1915
|
+
|
|
1916
|
+
const updateTaskDataSpy = jest.spyOn(task, 'updateTaskData');
|
|
1917
|
+
|
|
1918
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1919
|
+
|
|
1920
|
+
// Verify updateTaskData was called exactly once
|
|
1921
|
+
expect(updateTaskDataSpy).toHaveBeenCalledTimes(1);
|
|
1922
|
+
|
|
1923
|
+
// Verify it was called with isConferenceInProgress already calculated
|
|
1924
|
+
expect(updateTaskDataSpy).toHaveBeenCalledWith(
|
|
1925
|
+
expect.objectContaining({
|
|
1926
|
+
participantId: 'new-agent-789',
|
|
1927
|
+
isConferenceInProgress: true, // 3 active agents
|
|
1928
|
+
})
|
|
1929
|
+
);
|
|
1930
|
+
|
|
1931
|
+
expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_JOINED, task);
|
|
1932
|
+
});
|
|
1933
|
+
|
|
1441
1934
|
describe('PARTICIPANT_LEFT_CONFERENCE event handling', () => {
|
|
1935
|
+
it('should call updateTaskData only once for PARTICIPANT_LEFT_CONFERENCE with pre-calculated isConferenceInProgress', () => {
|
|
1936
|
+
const payload = {
|
|
1937
|
+
data: {
|
|
1938
|
+
type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
|
|
1939
|
+
interactionId: taskId,
|
|
1940
|
+
interaction: {
|
|
1941
|
+
participants: {
|
|
1942
|
+
[agentId]: { pType: 'Agent', hasLeft: false },
|
|
1943
|
+
'agent-2': { pType: 'Agent', hasLeft: true }, // This agent left
|
|
1944
|
+
'customer-1': { pType: 'Customer', hasLeft: false },
|
|
1945
|
+
},
|
|
1946
|
+
media: {
|
|
1947
|
+
[taskId]: {
|
|
1948
|
+
mType: 'mainCall',
|
|
1949
|
+
participants: [agentId, 'customer-1'], // agent-2 removed from participants
|
|
1950
|
+
},
|
|
1951
|
+
},
|
|
1952
|
+
},
|
|
1953
|
+
},
|
|
1954
|
+
};
|
|
1955
|
+
|
|
1956
|
+
const updateTaskDataSpy = jest.spyOn(task, 'updateTaskData');
|
|
1957
|
+
|
|
1958
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1959
|
+
|
|
1960
|
+
// Verify updateTaskData was called exactly once
|
|
1961
|
+
expect(updateTaskDataSpy).toHaveBeenCalledTimes(1);
|
|
1962
|
+
|
|
1963
|
+
// Verify it was called with isConferenceInProgress already calculated
|
|
1964
|
+
expect(updateTaskDataSpy).toHaveBeenCalledWith(
|
|
1965
|
+
expect.objectContaining({
|
|
1966
|
+
isConferenceInProgress: false, // Only 1 active agent remains
|
|
1967
|
+
})
|
|
1968
|
+
);
|
|
1969
|
+
|
|
1970
|
+
expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
|
|
1971
|
+
});
|
|
1972
|
+
|
|
1442
1973
|
it('should emit TASK_PARTICIPANT_LEFT event when participant leaves conference', () => {
|
|
1443
1974
|
const payload = {
|
|
1444
1975
|
data: {
|
|
@@ -1735,6 +2266,218 @@ describe('TaskManager', () => {
|
|
|
1735
2266
|
expect(otherTask.data.isConferencing).toBeUndefined();
|
|
1736
2267
|
expect(otherTask.emit).not.toHaveBeenCalled();
|
|
1737
2268
|
});
|
|
1738
|
-
});
|
|
2269
|
+
});
|
|
2270
|
+
|
|
2271
|
+
describe('CONTACT_MERGED event handling', () => {
|
|
2272
|
+
let task;
|
|
2273
|
+
let taskEmitSpy;
|
|
2274
|
+
let managerEmitSpy;
|
|
2275
|
+
|
|
2276
|
+
beforeEach(() => {
|
|
2277
|
+
// Create initial task
|
|
2278
|
+
webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
|
|
2279
|
+
task = taskManager.getTask(taskId);
|
|
2280
|
+
taskEmitSpy = jest.spyOn(task, 'emit');
|
|
2281
|
+
managerEmitSpy = jest.spyOn(taskManager, 'emit');
|
|
2282
|
+
});
|
|
2283
|
+
|
|
2284
|
+
it('should update existing task data and emit TASK_MERGED event when CONTACT_MERGED is received', () => {
|
|
2285
|
+
const mergedPayload = {
|
|
2286
|
+
data: {
|
|
2287
|
+
type: CC_EVENTS.CONTACT_MERGED,
|
|
2288
|
+
interactionId: taskId,
|
|
2289
|
+
agentId: taskDataMock.agentId,
|
|
2290
|
+
interaction: {
|
|
2291
|
+
...taskDataMock.interaction,
|
|
2292
|
+
state: 'merged',
|
|
2293
|
+
customField: 'updated-value',
|
|
2294
|
+
},
|
|
2295
|
+
},
|
|
2296
|
+
};
|
|
2297
|
+
|
|
2298
|
+
webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
|
|
2299
|
+
|
|
2300
|
+
const updatedTask = taskManager.getTask(taskId);
|
|
2301
|
+
expect(updatedTask).toBeDefined();
|
|
2302
|
+
expect(updatedTask.data.interaction.customField).toBe('updated-value');
|
|
2303
|
+
expect(updatedTask.data.interaction.state).toBe('merged');
|
|
2304
|
+
expect(managerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_MERGED, updatedTask);
|
|
2305
|
+
});
|
|
2306
|
+
|
|
2307
|
+
it('should create new task when CONTACT_MERGED is received for non-existing task', () => {
|
|
2308
|
+
const newMergedTaskId = 'new-merged-task-id';
|
|
2309
|
+
const mergedPayload = {
|
|
2310
|
+
data: {
|
|
2311
|
+
type: CC_EVENTS.CONTACT_MERGED,
|
|
2312
|
+
interactionId: newMergedTaskId,
|
|
2313
|
+
agentId: taskDataMock.agentId,
|
|
2314
|
+
interaction: {
|
|
2315
|
+
mediaType: 'telephony',
|
|
2316
|
+
state: 'merged',
|
|
2317
|
+
participants: {
|
|
2318
|
+
[taskDataMock.agentId]: {
|
|
2319
|
+
isWrapUp: false,
|
|
2320
|
+
hasJoined: true,
|
|
2321
|
+
},
|
|
2322
|
+
},
|
|
2323
|
+
},
|
|
2324
|
+
},
|
|
2325
|
+
};
|
|
2326
|
+
|
|
2327
|
+
// Verify task doesn't exist before
|
|
2328
|
+
expect(taskManager.getTask(newMergedTaskId)).toBeUndefined();
|
|
2329
|
+
|
|
2330
|
+
webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
|
|
2331
|
+
|
|
2332
|
+
// Verify task was created
|
|
2333
|
+
const newTask = taskManager.getTask(newMergedTaskId);
|
|
2334
|
+
expect(newTask).toBeDefined();
|
|
2335
|
+
expect(newTask.data.interactionId).toBe(newMergedTaskId);
|
|
2336
|
+
expect(managerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_MERGED, newTask);
|
|
2337
|
+
});
|
|
2338
|
+
|
|
2339
|
+
it('should remove child task when childInteractionId is present in CONTACT_MERGED', () => {
|
|
2340
|
+
const childTaskId = 'child-task-id';
|
|
2341
|
+
const parentTaskId = 'parent-task-id';
|
|
2342
|
+
|
|
2343
|
+
// Create child task
|
|
2344
|
+
const childPayload = {
|
|
2345
|
+
data: {
|
|
2346
|
+
type: CC_EVENTS.AGENT_CONTACT_RESERVED,
|
|
2347
|
+
interactionId: childTaskId,
|
|
2348
|
+
agentId: taskDataMock.agentId,
|
|
2349
|
+
interaction: {mediaType: 'telephony'},
|
|
2350
|
+
},
|
|
2351
|
+
};
|
|
2352
|
+
webSocketManagerMock.emit('message', JSON.stringify(childPayload));
|
|
2353
|
+
|
|
2354
|
+
// Verify child task exists
|
|
2355
|
+
expect(taskManager.getTask(childTaskId)).toBeDefined();
|
|
2356
|
+
|
|
2357
|
+
// Create parent task
|
|
2358
|
+
const parentPayload = {
|
|
2359
|
+
data: {
|
|
2360
|
+
type: CC_EVENTS.AGENT_CONTACT_RESERVED,
|
|
2361
|
+
interactionId: parentTaskId,
|
|
2362
|
+
agentId: taskDataMock.agentId,
|
|
2363
|
+
interaction: {mediaType: 'telephony'},
|
|
2364
|
+
},
|
|
2365
|
+
};
|
|
2366
|
+
webSocketManagerMock.emit('message', JSON.stringify(parentPayload));
|
|
2367
|
+
|
|
2368
|
+
// Send CONTACT_MERGED with childInteractionId
|
|
2369
|
+
const mergedPayload = {
|
|
2370
|
+
data: {
|
|
2371
|
+
type: CC_EVENTS.CONTACT_MERGED,
|
|
2372
|
+
interactionId: parentTaskId,
|
|
2373
|
+
childInteractionId: childTaskId,
|
|
2374
|
+
agentId: taskDataMock.agentId,
|
|
2375
|
+
interaction: {
|
|
2376
|
+
mediaType: 'telephony',
|
|
2377
|
+
state: 'merged',
|
|
2378
|
+
},
|
|
2379
|
+
},
|
|
2380
|
+
};
|
|
2381
|
+
|
|
2382
|
+
webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
|
|
2383
|
+
|
|
2384
|
+
// Verify child task was removed
|
|
2385
|
+
expect(taskManager.getTask(childTaskId)).toBeUndefined();
|
|
2386
|
+
|
|
2387
|
+
// Verify parent task still exists
|
|
2388
|
+
expect(taskManager.getTask(parentTaskId)).toBeDefined();
|
|
2389
|
+
|
|
2390
|
+
// Verify TASK_MERGED event was emitted
|
|
2391
|
+
expect(managerEmitSpy).toHaveBeenCalledWith(
|
|
2392
|
+
TASK_EVENTS.TASK_MERGED,
|
|
2393
|
+
expect.objectContaining({
|
|
2394
|
+
data: expect.objectContaining({
|
|
2395
|
+
interactionId: parentTaskId,
|
|
2396
|
+
}),
|
|
2397
|
+
})
|
|
2398
|
+
);
|
|
2399
|
+
});
|
|
2400
|
+
|
|
2401
|
+
it('should handle CONTACT_MERGED with EP-DN participant correctly', () => {
|
|
2402
|
+
const epdnTaskId = 'epdn-merged-task';
|
|
2403
|
+
const mergedPayload = {
|
|
2404
|
+
data: {
|
|
2405
|
+
type: CC_EVENTS.CONTACT_MERGED,
|
|
2406
|
+
interactionId: epdnTaskId,
|
|
2407
|
+
agentId: taskDataMock.agentId,
|
|
2408
|
+
interaction: {
|
|
2409
|
+
mediaType: 'telephony',
|
|
2410
|
+
state: 'merged',
|
|
2411
|
+
participants: {
|
|
2412
|
+
[taskDataMock.agentId]: {
|
|
2413
|
+
type: 'Agent',
|
|
2414
|
+
isWrapUp: false,
|
|
2415
|
+
hasJoined: true,
|
|
2416
|
+
},
|
|
2417
|
+
'epdn-participant': {
|
|
2418
|
+
type: 'EpDn',
|
|
2419
|
+
epId: 'entry-point-123',
|
|
2420
|
+
isWrapUp: false,
|
|
2421
|
+
},
|
|
2422
|
+
},
|
|
2423
|
+
},
|
|
2424
|
+
},
|
|
2425
|
+
};
|
|
2426
|
+
|
|
2427
|
+
webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
|
|
2428
|
+
|
|
2429
|
+
const mergedTask = taskManager.getTask(epdnTaskId);
|
|
2430
|
+
expect(mergedTask).toBeDefined();
|
|
2431
|
+
expect(mergedTask.data.interaction.participants['epdn-participant']).toBeDefined();
|
|
2432
|
+
expect(mergedTask.data.interaction.participants['epdn-participant'].type).toBe('EpDn');
|
|
2433
|
+
expect(managerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_MERGED, mergedTask);
|
|
2434
|
+
});
|
|
2435
|
+
|
|
2436
|
+
it('should not affect other tasks when CONTACT_MERGED is received', () => {
|
|
2437
|
+
const otherTaskId = 'other-unrelated-task';
|
|
2438
|
+
const otherPayload = {
|
|
2439
|
+
data: {
|
|
2440
|
+
type: CC_EVENTS.AGENT_CONTACT_RESERVED,
|
|
2441
|
+
interactionId: otherTaskId,
|
|
2442
|
+
agentId: taskDataMock.agentId,
|
|
2443
|
+
interaction: {mediaType: 'chat'},
|
|
2444
|
+
},
|
|
2445
|
+
};
|
|
2446
|
+
webSocketManagerMock.emit('message', JSON.stringify(otherPayload));
|
|
2447
|
+
|
|
2448
|
+
const otherTask = taskManager.getTask(otherTaskId);
|
|
2449
|
+
const otherTaskEmitSpy = jest.spyOn(otherTask, 'emit');
|
|
2450
|
+
|
|
2451
|
+
// Send CONTACT_MERGED for the original task
|
|
2452
|
+
const mergedPayload = {
|
|
2453
|
+
data: {
|
|
2454
|
+
type: CC_EVENTS.CONTACT_MERGED,
|
|
2455
|
+
interactionId: taskId,
|
|
2456
|
+
agentId: taskDataMock.agentId,
|
|
2457
|
+
interaction: {
|
|
2458
|
+
mediaType: 'telephony',
|
|
2459
|
+
state: 'merged',
|
|
2460
|
+
},
|
|
2461
|
+
},
|
|
2462
|
+
};
|
|
2463
|
+
|
|
2464
|
+
webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
|
|
2465
|
+
|
|
2466
|
+
// Verify other task was not affected
|
|
2467
|
+
expect(otherTaskEmitSpy).not.toHaveBeenCalled();
|
|
2468
|
+
expect(otherTask.data.interaction.mediaType).toBe('chat');
|
|
2469
|
+
|
|
2470
|
+
// Verify original task was updated
|
|
2471
|
+
expect(managerEmitSpy).toHaveBeenCalledWith(
|
|
2472
|
+
TASK_EVENTS.TASK_MERGED,
|
|
2473
|
+
expect.objectContaining({
|
|
2474
|
+
data: expect.objectContaining({
|
|
2475
|
+
interactionId: taskId,
|
|
2476
|
+
}),
|
|
2477
|
+
})
|
|
2478
|
+
);
|
|
2479
|
+
});
|
|
2480
|
+
});
|
|
2481
|
+
|
|
1739
2482
|
});
|
|
1740
2483
|
|