@webex/contact-center 3.12.0-task-refactor.12 → 3.12.0-task-refactor.13

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.
@@ -164,19 +164,7 @@ describe('TaskManager', () => {
164
164
  beforeEach(() => {
165
165
  contactMock = contact;
166
166
  webSocketManagerMock = new EventEmitter();
167
- <<<<<<< HEAD
168
167
  rtdWebSocketManagerMock = new EventEmitter();
169
- =======
170
- mockApiAIAssistant = {
171
- sendEvent: jest.fn().mockResolvedValue({}),
172
- setAIFeatureFlags: jest.fn(),
173
- aiFeature: {
174
- realtimeTranscripts: {
175
- enable: true,
176
- },
177
- },
178
- };
179
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
180
168
 
181
169
  webex = {
182
170
  logger: {
@@ -206,7 +194,6 @@ describe('TaskManager', () => {
206
194
  onSpy = jest.spyOn(webCallingService, 'on');
207
195
  offSpy = jest.spyOn(webCallingService, 'off');
208
196
 
209
- <<<<<<< HEAD
210
197
  mockApiAIAssistant = {
211
198
  sendEvent: jest.fn().mockResolvedValue({}),
212
199
  };
@@ -220,26 +207,6 @@ describe('TaskManager', () => {
220
207
  );
221
208
  taskManager.taskCollection[taskId] = createMockTask(taskDataMock);
222
209
  (taskManager as any).setupTaskListeners?.(taskManager.taskCollection[taskId]);
223
- =======
224
- taskManager = new TaskManager(
225
- mockApiAIAssistant,
226
- contactMock,
227
- webCallingService,
228
- webSocketManagerMock
229
- );
230
- const taskMock = {
231
- emit: jest.fn(),
232
- accept: jest.fn(),
233
- decline: jest.fn(),
234
- updateTaskData: jest.fn().mockImplementation((updatedData) => {
235
- taskMock.data = {...taskMock.data, ...updatedData};
236
- return taskMock;
237
- }),
238
- data: taskDataMock,
239
- };
240
- taskManager.taskCollection[taskId] = taskMock;
241
- taskManager.agentId = 'test-agent-id';
242
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
243
210
  taskManager.call = mockCall;
244
211
  taskManager.setAgentId('test-agent-id');
245
212
 
@@ -266,15 +233,8 @@ describe('TaskManager', () => {
266
233
 
267
234
  incomingCallCb(mockCall);
268
235
 
269
- <<<<<<< HEAD
270
236
  expect(incomingHandler).toHaveBeenCalledWith(taskManager.getTask(taskId));
271
237
  taskManager.off(TASK_EVENTS.TASK_INCOMING, incomingHandler);
272
- =======
273
- expect(taskEmitSpy).toHaveBeenCalledWith(
274
- TASK_EVENTS.TASK_INCOMING,
275
- taskManager.getTask(taskId)
276
- );
277
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
278
238
  });
279
239
 
280
240
  it('should re-emit task related events', () => {
@@ -472,106 +432,6 @@ describe('TaskManager', () => {
472
432
  expect(existingTaskEmitSpy).not.toHaveBeenCalled();
473
433
  });
474
434
 
475
- it('should invoke sendEvent for configured start/stop backend events', () => {
476
- const message = (type: CC_EVENTS) =>
477
- JSON.stringify({
478
- data: {
479
- ...taskDataMock,
480
- taskId,
481
- type,
482
- },
483
- });
484
-
485
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_CONTACT_ASSIGNED));
486
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_CONSULTING));
487
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_CONSULT_CONFERENCED));
488
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_CONSULT_ENDED));
489
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_WRAPUP));
490
- webSocketManagerMock.emit('message', message(CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE));
491
-
492
- expect(mockApiAIAssistant.sendEvent).toHaveBeenCalledTimes(6);
493
- expect(mockApiAIAssistant.sendEvent).toHaveBeenCalledWith(
494
- 'test-agent-id',
495
- taskId,
496
- 'CUSTOM_EVENT',
497
- 'GET_TRANSCRIPTS',
498
- 'START'
499
- );
500
- expect(mockApiAIAssistant.sendEvent).toHaveBeenCalledWith(
501
- 'test-agent-id',
502
- taskId,
503
- 'CUSTOM_EVENT',
504
- 'GET_TRANSCRIPTS',
505
- 'STOP'
506
- );
507
- });
508
-
509
- it('should not invoke sendEvent for transcript events when realtime transcript feature is disabled', () => {
510
- mockApiAIAssistant.aiFeature = {
511
- realtimeTranscripts: {
512
- enable: false,
513
- },
514
- };
515
- mockApiAIAssistant.setAIFeatureFlags(mockApiAIAssistant.aiFeature);
516
-
517
- const message = (type: CC_EVENTS) =>
518
- JSON.stringify({
519
- data: {
520
- ...taskDataMock,
521
- taskId,
522
- type,
523
- },
524
- });
525
-
526
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_CONTACT_ASSIGNED));
527
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_CONSULTING));
528
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_CONSULT_CONFERENCED));
529
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_CONSULT_ENDED));
530
- webSocketManagerMock.emit('message', message(CC_EVENTS.AGENT_WRAPUP));
531
- webSocketManagerMock.emit('message', message(CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE));
532
-
533
- expect(mockApiAIAssistant.sendEvent).not.toHaveBeenCalled();
534
- });
535
-
536
- it('should emit REAL_TIME_TRANSCRIPTION from task object', () => {
537
- const task = taskManager.getTask(taskId);
538
- const taskEmitSpy = jest.spyOn(task, 'emit');
539
- const realtimePayload = {
540
- data: {
541
- ...taskDataMock,
542
- type: CC_EVENTS.REAL_TIME_TRANSCRIPTION,
543
- data: {
544
- content: 'hello from transcript',
545
- },
546
- },
547
- };
548
-
549
- webSocketManagerMock.emit('message', JSON.stringify(realtimePayload));
550
-
551
- expect(taskEmitSpy).toHaveBeenCalledWith(
552
- CC_EVENTS.REAL_TIME_TRANSCRIPTION,
553
- realtimePayload.data
554
- );
555
- });
556
-
557
- it('should emit REAL_TIME_TRANSCRIPTION from RTD websocket payload on task object', () => {
558
- const task = taskManager.getTask(taskId);
559
- const taskEmitSpy = jest.spyOn(task, 'emit');
560
- const realtimePayload = {
561
- data: {
562
- notifType: CC_EVENTS.REAL_TIME_TRANSCRIPTION,
563
- data: {
564
- conversationId: taskId,
565
- content: 'hello from rtd websocket',
566
- },
567
- },
568
- };
569
-
570
- taskManager.handleRealtimeWebsocketEvent(JSON.stringify(realtimePayload));
571
-
572
- expect(taskEmitSpy).toHaveBeenCalledWith(CC_EVENTS.REAL_TIME_TRANSCRIPTION, realtimePayload.data);
573
- });
574
-
575
435
  it('should not re-emit agent related events', () => {
576
436
  const dummyPayload = {
577
437
  data: {
@@ -813,7 +673,6 @@ describe('TaskManager', () => {
813
673
  it('test call listeners being switched off on call end', () => {
814
674
  webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
815
675
 
816
- <<<<<<< HEAD
817
676
  const webrtcTask = new WebRTC(contactMock, webCallingService, taskDataMock, {
818
677
  isEndTaskEnabled: true,
819
678
  isEndConsultEnabled: true,
@@ -836,13 +695,6 @@ describe('TaskManager', () => {
836
695
  });
837
696
 
838
697
  const webCallListenerSpy = jest.spyOn(task, 'unregisterWebCallListeners');
839
- =======
840
- const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
841
- const webCallListenerSpy = jest.spyOn(
842
- taskManager.getTask(taskId),
843
- 'unregisterWebCallListeners'
844
- );
845
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
846
698
  const callOffSpy = jest.spyOn(mockCall, 'off');
847
699
  const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
848
700
  const payload = {
@@ -875,18 +727,12 @@ describe('TaskManager', () => {
875
727
  webSocketManagerMock.emit('message', JSON.stringify(hydratePayload));
876
728
 
877
729
  taskManager.getTask(taskId).data = payload.data;
878
- <<<<<<< HEAD
879
730
  webSocketManagerMock.emit('message', JSON.stringify(payload));
880
731
  const stateMachineEvent = expectLastStateMachineEvent(
881
732
  sendStateMachineEventSpy,
882
733
  TaskEvent.CONTACT_ENDED
883
734
  );
884
735
  expect(stateMachineEvent?.taskData.wrapUpRequired).toBe(false);
885
- =======
886
- const task = taskManager.getTask(taskId);
887
- webSocketManagerMock.emit('message', JSON.stringify(payload));
888
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, task);
889
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
890
736
  expect(webCallListenerSpy).toHaveBeenCalledWith();
891
737
  expect(callOffSpy).toHaveBeenCalledWith(
892
738
  CALL_EVENT_KEYS.REMOTE_MEDIA,
@@ -918,34 +764,25 @@ describe('TaskManager', () => {
918
764
  destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
919
765
  owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
920
766
  queueMgr: 'aqm',
767
+ agentsPendingWrapUp: ['test-agent-id'],
921
768
  },
922
769
  };
923
770
 
924
771
  task.updateTaskData(payload.data);
925
772
  webSocketManagerMock.emit('message', JSON.stringify(payload));
926
- <<<<<<< HEAD
927
773
  const stateMachineEvent = expectLastStateMachineEvent(
928
774
  sendStateMachineEventSpy,
929
775
  TaskEvent.CONTACT_ENDED
930
776
  );
931
777
  expect(stateMachineEvent?.taskData.wrapUpRequired).toBe(true);
932
778
  sendStateMachineEventSpy.mockRestore();
933
- =======
934
- expect(taskEmitSpy).toHaveBeenCalledWith(CC_EVENTS.CONTACT_ENDED, {...payload.data});
935
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, taskManager.getTask(taskId));
936
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
937
779
  });
938
780
 
939
781
  it('should emit TASK_REJECT event on AGENT_INVITE_FAILED event', () => {
940
782
  webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
941
783
 
942
- <<<<<<< HEAD
943
784
  const task = taskManager.getTask(taskId);
944
785
  const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
945
- =======
946
- const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
947
- const metricsTrackSpy = jest.spyOn(taskManager.metricsManager, 'trackEvent');
948
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
949
786
  const payload = {
950
787
  data: {
951
788
  type: CC_EVENTS.AGENT_INVITE_FAILED,
@@ -964,7 +801,6 @@ describe('TaskManager', () => {
964
801
  },
965
802
  };
966
803
 
967
- <<<<<<< HEAD
968
804
  task.updateTaskData(payload.data);
969
805
  webSocketManagerMock.emit('message', JSON.stringify(payload));
970
806
  const stateMachineEvent = expectLastStateMachineEvent(
@@ -976,18 +812,6 @@ describe('TaskManager', () => {
976
812
  });
977
813
 
978
814
  it('should emit TASK_HYDRATE even if task is already present in taskManager', () => {
979
- =======
980
- taskManager.getTask(taskId).updateTaskData(payload.data);
981
- webSocketManagerMock.emit('message', JSON.stringify(payload));
982
- expect(taskEmitSpy).toHaveBeenCalledWith(CC_EVENTS.AGENT_INVITE_FAILED, {...payload.data});
983
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_REJECT, payload.data.reason);
984
- // Verify the correct metric event name is used for AGENT_INVITE_FAILED
985
- expect(metricsTrackSpy).toHaveBeenCalled();
986
- expect(metricsTrackSpy.mock.calls[0][0]).toBe('Agent Invite Failed');
987
- });
988
-
989
- it('should not emit TASK_HYDRATE if task is already present in taskManager', () => {
990
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
991
815
  const payload = {
992
816
  data: {
993
817
  ...initalPayload.data,
@@ -1124,11 +948,7 @@ describe('TaskManager', () => {
1124
948
  expect(createdTask.data.isConferenceInProgress).toBe(false);
1125
949
  });
1126
950
 
1127
- <<<<<<< HEAD
1128
951
  it('should emit TASK_WRAPUP event on AGENT_WRAPUP event', () => {
1129
- =======
1130
- it('should emit TASK_END event on AGENT_WRAPUP event', () => {
1131
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
1132
952
  webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1133
953
 
1134
954
  const wrapupPayload = {
@@ -1283,13 +1103,8 @@ describe('TaskManager', () => {
1283
1103
 
1284
1104
  const task = taskManager.getTask(taskId);
1285
1105
  const taskEmitSpy = jest.spyOn(task, 'emit');
1286
- <<<<<<< HEAD
1287
1106
  const taskAcceptSpy = jest.spyOn(task, 'accept').mockResolvedValue(undefined);
1288
1107
  const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
1289
- =======
1290
- const taskManagerEmitSpy = jest.spyOn(taskManager, 'emit');
1291
- const taskAcceptSpy = jest.spyOn(task, 'accept').mockResolvedValue(undefined);
1292
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
1293
1108
 
1294
1109
  // Step 2: Trigger AGENT_OFFER_CONTACT with auto-answer
1295
1110
  const autoAnswerPayload = {
@@ -1313,7 +1128,6 @@ describe('TaskManager', () => {
1313
1128
  // Verify accept was called
1314
1129
  expect(taskAcceptSpy).toHaveBeenCalledTimes(1);
1315
1130
 
1316
- <<<<<<< HEAD
1317
1131
  const stateMachineEvent = expectLastStateMachineEvent(
1318
1132
  sendStateMachineEventSpy,
1319
1133
  TaskEvent.TASK_OFFERED
@@ -1322,11 +1136,6 @@ describe('TaskManager', () => {
1322
1136
  // Verify task auto-answer event was emitted
1323
1137
  expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_AUTO_ANSWERED, task);
1324
1138
  sendStateMachineEventSpy.mockRestore();
1325
- =======
1326
- // Verify BOTH events were emitted
1327
- expect(taskManagerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_OFFER_CONTACT, task);
1328
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_AUTO_ANSWERED, task);
1329
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
1330
1139
  });
1331
1140
 
1332
1141
  it('should NOT emit TASK_AUTO_ANSWERED event when auto-answer fails', async () => {
@@ -1372,10 +1181,7 @@ describe('TaskManager', () => {
1372
1181
  const task = taskManager.getTask(taskId);
1373
1182
  const taskEmitSpy = jest.spyOn(task, 'emit');
1374
1183
  const taskAcceptSpy = jest.spyOn(task, 'accept').mockResolvedValue(undefined);
1375
- <<<<<<< HEAD
1376
1184
  const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
1377
- =======
1378
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
1379
1185
 
1380
1186
  // Step 2: Trigger AGENT_OFFER_CONSULT with auto-answer
1381
1187
  const consultAutoAnswerPayload = {
@@ -1400,7 +1206,6 @@ describe('TaskManager', () => {
1400
1206
  // Verify accept was called
1401
1207
  expect(taskAcceptSpy).toHaveBeenCalledTimes(1);
1402
1208
 
1403
- <<<<<<< HEAD
1404
1209
  const stateMachineEvent = expectLastStateMachineEvent(
1405
1210
  sendStateMachineEventSpy,
1406
1211
  TaskEvent.OFFER_CONSULT
@@ -1410,18 +1215,11 @@ describe('TaskManager', () => {
1410
1215
  isConsulted: true,
1411
1216
  });
1412
1217
  // Verify task auto-answer event was emitted
1413
- =======
1414
- // Verify BOTH events were emitted
1415
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_OFFER_CONSULT, task);
1416
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
1417
1218
  expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_AUTO_ANSWERED, task);
1418
1219
 
1419
1220
  // Verify isConsulted flag is set correctly
1420
1221
  expect(task.data.isConsulted).toBe(true);
1421
- <<<<<<< HEAD
1422
1222
  sendStateMachineEventSpy.mockRestore();
1423
- =======
1424
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
1425
1223
  });
1426
1224
 
1427
1225
  it('should NOT emit TASK_AUTO_ANSWERED when isAutoAnswering is false', async () => {
@@ -1462,7 +1260,6 @@ describe('TaskManager', () => {
1462
1260
  });
1463
1261
  });
1464
1262
 
1465
- <<<<<<< HEAD
1466
1263
  it('should remove OUTDIAL task from taskCollection on AGENT_OUTBOUND_FAILED when terminated', () => {
1467
1264
  const task = taskManager.getTask(taskId);
1468
1265
  Object.assign(task.data, {
@@ -1477,26 +1274,6 @@ describe('TaskManager', () => {
1477
1274
  task.unregisterWebCallListeners = jest.fn();
1478
1275
  const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
1479
1276
  const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
1480
- =======
1481
- it('should NOT remove OUTDIAL task from taskCollection on AGENT_OUTBOUND_FAILED when terminated (wrap-up flow)', () => {
1482
- const task = taskManager.getTask(taskId);
1483
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1484
- task.data = {
1485
- ...task.data,
1486
- ...newData,
1487
- interaction: {
1488
- ...task.data.interaction,
1489
- ...newData.interaction,
1490
- outboundType: 'OUTDIAL',
1491
- state: 'new',
1492
- isTerminated: true,
1493
- },
1494
- };
1495
- return task;
1496
- });
1497
- task.unregisterWebCallListeners = jest.fn();
1498
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
1499
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
1500
1277
 
1501
1278
  const payload = {
1502
1279
  data: {
@@ -1509,10 +1286,7 @@ describe('TaskManager', () => {
1509
1286
  state: 'new',
1510
1287
  isTerminated: true,
1511
1288
  },
1512
- <<<<<<< HEAD
1513
1289
  agentsPendingWrapUp: ['agent-123'],
1514
- =======
1515
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
1516
1290
  interactionId: taskId,
1517
1291
  orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
1518
1292
  trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
@@ -1526,26 +1300,62 @@ describe('TaskManager', () => {
1526
1300
  };
1527
1301
 
1528
1302
  webSocketManagerMock.emit('message', JSON.stringify(payload));
1529
- <<<<<<< HEAD
1530
- =======
1531
1303
 
1532
- expect(taskManager.getTask(taskId)).toBeDefined();
1533
- expect(removeTaskSpy).not.toHaveBeenCalled();
1304
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1305
+
1306
+ expect(taskManager.getTask(taskId)).toBeUndefined();
1307
+ expect(removeTaskSpy).toHaveBeenCalled();
1308
+ const stateMachineEvent = expectLastStateMachineEvent(
1309
+ sendStateMachineEventSpy,
1310
+ TaskEvent.OUTBOUND_FAILED
1311
+ );
1312
+ expect(stateMachineEvent?.reason).toBe('CUSTOMER_BUSY');
1313
+ sendStateMachineEventSpy.mockRestore();
1534
1314
  });
1535
1315
 
1536
1316
  it('should emit TASK_OUTDIAL_FAILED event on AGENT_OUTBOUND_FAILED', () => {
1537
1317
  const task = taskManager.getTask(taskId);
1538
- task.updateTaskData = jest.fn().mockReturnValue(task);
1539
- const taskEmitSpy = jest.spyOn(task, 'emit');
1318
+ const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
1319
+ const payload = {
1320
+ data: {
1321
+ type: CC_EVENTS.AGENT_OUTBOUND_FAILED,
1322
+ interactionId: taskId,
1323
+ reason: 'CUSTOMER_BUSY',
1324
+ },
1325
+ };
1326
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1327
+ const stateMachineEvent = expectLastStateMachineEvent(
1328
+ sendStateMachineEventSpy,
1329
+ TaskEvent.OUTBOUND_FAILED
1330
+ );
1331
+ expect(stateMachineEvent?.reason).toBe('CUSTOMER_BUSY');
1332
+ sendStateMachineEventSpy.mockRestore();
1333
+ });
1334
+
1335
+ it('should pass taskData in OUTBOUND_FAILED event for shouldWrapUp guard evaluation', () => {
1336
+ const task = taskManager.getTask(taskId);
1337
+ const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
1540
1338
  const payload = {
1541
1339
  data: {
1542
1340
  type: CC_EVENTS.AGENT_OUTBOUND_FAILED,
1543
1341
  interactionId: taskId,
1544
1342
  reason: 'CUSTOMER_BUSY',
1343
+ agentsPendingWrapUp: ['agent-123'],
1344
+ interaction: {
1345
+ outboundType: 'OUTDIAL',
1346
+ isTerminated: true,
1347
+ },
1545
1348
  },
1546
1349
  };
1547
1350
  webSocketManagerMock.emit('message', JSON.stringify(payload));
1548
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_OUTDIAL_FAILED, 'CUSTOMER_BUSY');
1351
+ const stateMachineEvent = expectLastStateMachineEvent(
1352
+ sendStateMachineEventSpy,
1353
+ TaskEvent.OUTBOUND_FAILED
1354
+ );
1355
+ expect(stateMachineEvent?.taskData).toBeDefined();
1356
+ expect(stateMachineEvent?.taskData?.agentsPendingWrapUp).toEqual(['agent-123']);
1357
+ expect(stateMachineEvent?.taskData?.interaction?.outboundType).toBe('OUTDIAL');
1358
+ sendStateMachineEventSpy.mockRestore();
1549
1359
  });
1550
1360
 
1551
1361
  it('should handle AGENT_OUTBOUND_FAILED gracefully when task is undefined', () => {
@@ -1563,23 +1373,15 @@ describe('TaskManager', () => {
1563
1373
  });
1564
1374
 
1565
1375
  it('should NOT remove OUTDIAL task on CONTACT_ENDED when agentsPendingWrapUp exists', () => {
1566
- const agentId = '723a8ffb-a26e-496d-b14a-ff44fb83b64f';
1567
- taskManager.setAgentId(agentId);
1568
-
1569
1376
  const task = taskManager.getTask(taskId);
1570
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1571
- task.data = {
1572
- ...task.data,
1573
- ...newData,
1574
- interaction: {
1575
- ...task.data.interaction,
1576
- outboundType: 'OUTDIAL',
1577
- state: 'new',
1578
- mediaType: 'telephony',
1579
- },
1580
- agentsPendingWrapUp: [agentId],
1581
- };
1582
- return task;
1377
+ Object.assign(task.data, {
1378
+ interaction: {
1379
+ ...task.data.interaction,
1380
+ outboundType: 'OUTDIAL',
1381
+ state: 'new',
1382
+ mediaType: 'telephony',
1383
+ },
1384
+ agentsPendingWrapUp: ['test-agent-id'],
1583
1385
  });
1584
1386
  task.unregisterWebCallListeners = jest.fn();
1585
1387
  const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
@@ -1593,7 +1395,7 @@ describe('TaskManager', () => {
1593
1395
  state: 'new',
1594
1396
  mediaType: 'telephony',
1595
1397
  },
1596
- agentsPendingWrapUp: [agentId],
1398
+ agentsPendingWrapUp: ['test-agent-id'],
1597
1399
  },
1598
1400
  };
1599
1401
 
@@ -1605,19 +1407,14 @@ describe('TaskManager', () => {
1605
1407
 
1606
1408
  it('should remove OUTDIAL task on CONTACT_ENDED when agentsPendingWrapUp is empty', () => {
1607
1409
  const task = taskManager.getTask(taskId);
1608
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1609
- task.data = {
1610
- ...task.data,
1611
- ...newData,
1612
- interaction: {
1613
- ...task.data.interaction,
1614
- outboundType: 'OUTDIAL',
1615
- state: 'new',
1616
- mediaType: 'telephony',
1617
- },
1618
- agentsPendingWrapUp: [],
1619
- };
1620
- return task;
1410
+ Object.assign(task.data, {
1411
+ interaction: {
1412
+ ...task.data.interaction,
1413
+ outboundType: 'OUTDIAL',
1414
+ state: 'new',
1415
+ mediaType: 'telephony',
1416
+ },
1417
+ agentsPendingWrapUp: [],
1621
1418
  });
1622
1419
  task.unregisterWebCallListeners = jest.fn();
1623
1420
  const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
@@ -1642,19 +1439,13 @@ describe('TaskManager', () => {
1642
1439
 
1643
1440
  it('should remove OUTDIAL task on CONTACT_ENDED when agentsPendingWrapUp is undefined', () => {
1644
1441
  const task = taskManager.getTask(taskId);
1645
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1646
- task.data = {
1647
- ...task.data,
1648
- ...newData,
1649
- interaction: {
1650
- ...task.data.interaction,
1651
- outboundType: 'OUTDIAL',
1652
- state: 'new',
1653
- mediaType: 'telephony',
1654
- },
1655
- // agentsPendingWrapUp is undefined
1656
- };
1657
- return task;
1442
+ Object.assign(task.data, {
1443
+ interaction: {
1444
+ ...task.data.interaction,
1445
+ outboundType: 'OUTDIAL',
1446
+ state: 'new',
1447
+ mediaType: 'telephony',
1448
+ },
1658
1449
  });
1659
1450
  task.unregisterWebCallListeners = jest.fn();
1660
1451
  const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
@@ -1693,333 +1484,29 @@ describe('TaskManager', () => {
1693
1484
  }).not.toThrow();
1694
1485
  });
1695
1486
 
1696
- describe('wrapUpRequired logic in CONTACT_ENDED event', () => {
1697
- const agentId = '723a8ffb-a26e-496d-b14a-ff44fb83b64f';
1698
-
1699
- beforeEach(() => {
1700
- // Set the agent ID on taskManager
1701
- taskManager.setAgentId(agentId);
1487
+ it('should remove OUTDIAL task from taskCollection on AGENT_CONTACT_ASSIGN_FAILED when NOT terminated (user-declined)', () => {
1488
+ const task = taskManager.getTask(taskId);
1489
+ Object.assign(task.data, {
1490
+ interaction: {
1491
+ ...task.data.interaction,
1492
+ outboundType: 'OUTDIAL',
1493
+ state: 'new',
1494
+ isTerminated: false,
1495
+ },
1702
1496
  });
1497
+ task.unregisterWebCallListeners = jest.fn();
1498
+ const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
1703
1499
 
1704
- it('should set wrapUpRequired to true when agent is in agentsPendingWrapUp array for non-campaign tasks', () => {
1705
- const task = taskManager.getTask(taskId);
1706
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1707
- task.data = {
1708
- ...task.data,
1709
- ...newData,
1710
- };
1711
- return task;
1712
- });
1713
- task.unregisterWebCallListeners = jest.fn();
1714
-
1715
- const payload = {
1716
- data: {
1717
- type: CC_EVENTS.CONTACT_ENDED,
1718
- interactionId: taskId,
1719
- interaction: {
1720
- state: 'connected',
1721
- mediaType: 'telephony',
1722
- },
1723
- agentsPendingWrapUp: [agentId, 'other-agent-id'],
1724
- },
1725
- };
1726
-
1727
- webSocketManagerMock.emit('message', JSON.stringify(payload));
1728
-
1729
- expect(task.updateTaskData).toHaveBeenCalledWith(
1730
- expect.objectContaining({
1731
- wrapUpRequired: true,
1732
- })
1733
- );
1734
- });
1735
-
1736
- it('should set wrapUpRequired to false when agent is not in agentsPendingWrapUp array', () => {
1737
- const task = taskManager.getTask(taskId);
1738
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1739
- task.data = {
1740
- ...task.data,
1741
- ...newData,
1742
- };
1743
- return task;
1744
- });
1745
- task.unregisterWebCallListeners = jest.fn();
1746
-
1747
- const payload = {
1748
- data: {
1749
- type: CC_EVENTS.CONTACT_ENDED,
1750
- interactionId: taskId,
1751
- interaction: {
1752
- state: 'connected',
1753
- mediaType: 'telephony',
1754
- },
1755
- agentsPendingWrapUp: ['other-agent-id', 'another-agent-id'],
1756
- },
1757
- };
1758
-
1759
- webSocketManagerMock.emit('message', JSON.stringify(payload));
1760
-
1761
- expect(task.updateTaskData).toHaveBeenCalledWith(
1762
- expect.objectContaining({
1763
- wrapUpRequired: false,
1764
- })
1765
- );
1766
- });
1767
-
1768
- it('should set wrapUpRequired to false when agentsPendingWrapUp is an empty array', () => {
1769
- const task = taskManager.getTask(taskId);
1770
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1771
- task.data = {
1772
- ...task.data,
1773
- ...newData,
1774
- };
1775
- return task;
1776
- });
1777
- task.unregisterWebCallListeners = jest.fn();
1778
-
1779
- const payload = {
1780
- data: {
1781
- type: CC_EVENTS.CONTACT_ENDED,
1782
- interactionId: taskId,
1783
- interaction: {
1784
- state: 'connected',
1785
- mediaType: 'telephony',
1786
- },
1787
- agentsPendingWrapUp: [],
1788
- },
1789
- };
1790
-
1791
- webSocketManagerMock.emit('message', JSON.stringify(payload));
1792
-
1793
- expect(task.updateTaskData).toHaveBeenCalledWith(
1794
- expect.objectContaining({
1795
- wrapUpRequired: false,
1796
- })
1797
- );
1798
- });
1799
-
1800
- it('should set wrapUpRequired to false when agentsPendingWrapUp is undefined', () => {
1801
- const task = taskManager.getTask(taskId);
1802
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1803
- task.data = {
1804
- ...task.data,
1805
- ...newData,
1806
- };
1807
- return task;
1808
- });
1809
- task.unregisterWebCallListeners = jest.fn();
1810
-
1811
- const payload = {
1812
- data: {
1813
- type: CC_EVENTS.CONTACT_ENDED,
1814
- interactionId: taskId,
1815
- interaction: {
1816
- state: 'connected',
1817
- mediaType: 'telephony',
1818
- },
1819
- // agentsPendingWrapUp is not defined
1820
- },
1821
- };
1822
-
1823
- webSocketManagerMock.emit('message', JSON.stringify(payload));
1824
-
1825
- expect(task.updateTaskData).toHaveBeenCalledWith(
1826
- expect.objectContaining({
1827
- wrapUpRequired: false,
1828
- })
1829
- );
1830
- });
1831
-
1832
- it('should set wrapUpRequired to false when agentsPendingWrapUp is null', () => {
1833
- const task = taskManager.getTask(taskId);
1834
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1835
- task.data = {
1836
- ...task.data,
1837
- ...newData,
1838
- };
1839
- return task;
1840
- });
1841
- task.unregisterWebCallListeners = jest.fn();
1842
-
1843
- const payload = {
1844
- data: {
1845
- type: CC_EVENTS.CONTACT_ENDED,
1846
- interactionId: taskId,
1847
- interaction: {
1848
- state: 'connected',
1849
- mediaType: 'telephony',
1850
- },
1851
- agentsPendingWrapUp: null,
1852
- },
1853
- };
1854
-
1855
- webSocketManagerMock.emit('message', JSON.stringify(payload));
1856
-
1857
- expect(task.updateTaskData).toHaveBeenCalledWith(
1858
- expect.objectContaining({
1859
- wrapUpRequired: false,
1860
- })
1861
- );
1862
- });
1863
-
1864
- it('should set wrapUpRequired to true when agent is the only one in agentsPendingWrapUp for non-campaign tasks', () => {
1865
- const task = taskManager.getTask(taskId);
1866
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1867
- task.data = {
1868
- ...task.data,
1869
- ...newData,
1870
- };
1871
- return task;
1872
- });
1873
- task.unregisterWebCallListeners = jest.fn();
1874
-
1875
- const payload = {
1876
- data: {
1877
- type: CC_EVENTS.CONTACT_ENDED,
1878
- interactionId: taskId,
1879
- interaction: {
1880
- state: 'connected',
1881
- mediaType: 'telephony',
1882
- },
1883
- agentsPendingWrapUp: [agentId],
1884
- },
1885
- };
1886
-
1887
- webSocketManagerMock.emit('message', JSON.stringify(payload));
1888
-
1889
- expect(task.updateTaskData).toHaveBeenCalledWith(
1890
- expect.objectContaining({
1891
- wrapUpRequired: true,
1892
- })
1893
- );
1894
- });
1895
-
1896
- it('should set wrapUpRequired to true for different interaction states when agent is in agentsPendingWrapUp for non-campaign tasks', () => {
1897
- const task = taskManager.getTask(taskId);
1898
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1899
- task.data = {
1900
- ...task.data,
1901
- ...newData,
1902
- interaction: {
1903
- ...task.data.interaction,
1904
- ...newData.interaction,
1905
- },
1906
- };
1907
- return task;
1908
- });
1909
- task.unregisterWebCallListeners = jest.fn();
1910
-
1911
- // Test with 'connected' state
1912
- const payloadConnected = {
1913
- data: {
1914
- type: CC_EVENTS.CONTACT_ENDED,
1915
- interactionId: taskId,
1916
- interaction: {
1917
- state: 'connected',
1918
- mediaType: 'telephony',
1919
- },
1920
- agentsPendingWrapUp: [agentId],
1921
- },
1922
- };
1923
-
1924
- webSocketManagerMock.emit('message', JSON.stringify(payloadConnected));
1925
-
1926
- expect(task.updateTaskData).toHaveBeenNthCalledWith(
1927
- 1,
1928
- expect.objectContaining({
1929
- wrapUpRequired: true,
1930
- })
1931
- );
1932
-
1933
- // Test with 'held' state to verify it still works regardless of state
1934
- const payloadHeld = {
1935
- data: {
1936
- type: CC_EVENTS.CONTACT_ENDED,
1937
- interactionId: taskId,
1938
- interaction: {
1939
- state: 'held',
1940
- mediaType: 'telephony',
1941
- },
1942
- agentsPendingWrapUp: [agentId],
1943
- },
1944
- };
1945
-
1946
- webSocketManagerMock.emit('message', JSON.stringify(payloadHeld));
1947
-
1948
- expect(task.updateTaskData).toHaveBeenNthCalledWith(
1949
- 2,
1950
- expect.objectContaining({
1951
- wrapUpRequired: true,
1952
- })
1953
- );
1954
- });
1955
-
1956
- it('should set wrapUpRequired to false for campaign preview tasks even when agent is in agentsPendingWrapUp', () => {
1957
- const task = taskManager.getTask(taskId);
1958
- // Set up task as a campaign preview task via outboundType
1959
- task.data.interaction = {
1960
- ...task.data.interaction,
1961
- outboundType: 'STANDARD_PREVIEW_CAMPAIGN',
1962
- };
1963
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1964
- task.data = {
1965
- ...task.data,
1966
- ...newData,
1967
- };
1968
- return task;
1969
- });
1970
- task.unregisterWebCallListeners = jest.fn();
1971
-
1972
- const payload = {
1973
- data: {
1974
- type: CC_EVENTS.CONTACT_ENDED,
1975
- interactionId: taskId,
1976
- interaction: {
1977
- state: 'connected',
1978
- mediaType: 'telephony',
1979
- },
1980
- agentsPendingWrapUp: [agentId],
1981
- },
1982
- };
1983
-
1984
- webSocketManagerMock.emit('message', JSON.stringify(payload));
1985
-
1986
- expect(task.updateTaskData).toHaveBeenCalledWith(
1987
- expect.objectContaining({
1988
- wrapUpRequired: false,
1989
- })
1990
- );
1991
- });
1992
- });
1993
-
1994
- it('should remove OUTDIAL task from taskCollection on AGENT_CONTACT_ASSIGN_FAILED when NOT terminated (user-declined)', () => {
1995
- const task = taskManager.getTask(taskId);
1996
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
1997
- task.data = {
1998
- ...task.data,
1999
- ...newData,
2000
- interaction: {
2001
- ...task.data.interaction,
2002
- ...newData.interaction,
2003
- outboundType: 'OUTDIAL',
2004
- state: 'new',
2005
- isTerminated: false,
2006
- },
2007
- };
2008
- return task;
2009
- });
2010
- task.unregisterWebCallListeners = jest.fn();
2011
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
2012
-
2013
- const payload = {
2014
- data: {
2015
- type: CC_EVENTS.AGENT_CONTACT_ASSIGN_FAILED,
2016
- agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
2017
- eventTime: 1733211616959,
2018
- eventType: 'RoutingMessage',
2019
- interaction: {
2020
- outboundType: 'OUTDIAL',
2021
- state: 'new',
2022
- isTerminated: false,
1500
+ const payload = {
1501
+ data: {
1502
+ type: CC_EVENTS.AGENT_CONTACT_ASSIGN_FAILED,
1503
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
1504
+ eventTime: 1733211616959,
1505
+ eventType: 'RoutingMessage',
1506
+ interaction: {
1507
+ outboundType: 'OUTDIAL',
1508
+ state: 'new',
1509
+ isTerminated: false,
2023
1510
  },
2024
1511
  interactionId: taskId,
2025
1512
  orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
@@ -2032,326 +1519,95 @@ describe('TaskManager', () => {
2032
1519
  reasonCode: 156,
2033
1520
  },
2034
1521
  };
2035
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2036
1522
 
2037
1523
  webSocketManagerMock.emit('message', JSON.stringify(payload));
2038
1524
 
2039
1525
  expect(taskManager.getTask(taskId)).toBeUndefined();
2040
1526
  expect(removeTaskSpy).toHaveBeenCalled();
2041
- <<<<<<< HEAD
2042
- const stateMachineEvent = expectLastStateMachineEvent(
2043
- sendStateMachineEventSpy,
2044
- TaskEvent.OUTBOUND_FAILED
2045
- );
2046
- expect(stateMachineEvent?.reason).toBe('CUSTOMER_BUSY');
2047
- sendStateMachineEventSpy.mockRestore();
2048
1527
  });
2049
1528
 
2050
- it('should emit TASK_OUTDIAL_FAILED event on AGENT_OUTBOUND_FAILED', () => {
2051
- const task = taskManager.getTask(taskId);
2052
- const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
1529
+ it('handle AGENT_OFFER_CONSULT event', () => {
2053
1530
  const payload = {
2054
1531
  data: {
2055
- type: CC_EVENTS.AGENT_OUTBOUND_FAILED,
2056
- interactionId: taskId,
2057
- reason: 'CUSTOMER_BUSY',
1532
+ ...initalPayload.data,
1533
+ type: CC_EVENTS.AGENT_OFFER_CONSULT,
2058
1534
  },
2059
1535
  };
1536
+
1537
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1538
+ const task = taskManager.getTask(taskId);
1539
+ const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
1540
+
2060
1541
  webSocketManagerMock.emit('message', JSON.stringify(payload));
1542
+
2061
1543
  const stateMachineEvent = expectLastStateMachineEvent(
2062
1544
  sendStateMachineEventSpy,
2063
- TaskEvent.OUTBOUND_FAILED
1545
+ TaskEvent.OFFER_CONSULT
2064
1546
  );
2065
- expect(stateMachineEvent?.reason).toBe('CUSTOMER_BUSY');
1547
+ expect(stateMachineEvent?.taskData).toEqual({...payload.data, isConsulted: true});
2066
1548
  sendStateMachineEventSpy.mockRestore();
2067
1549
  });
2068
1550
 
2069
- it('should pass taskData in OUTBOUND_FAILED event for shouldWrapUp guard evaluation', () => {
1551
+ it('should emit TASK_CONSULT_ACCEPTED event on AGENT_CONSULTING event', () => {
1552
+ const initialConsultingPayload = {
1553
+ data: {
1554
+ ...initalPayload.data,
1555
+ type: CC_EVENTS.AGENT_OFFER_CONSULT,
1556
+ },
1557
+ };
1558
+
1559
+ const consultingPayload = {
1560
+ data: {
1561
+ ...initalPayload.data,
1562
+ type: CC_EVENTS.AGENT_CONSULTING,
1563
+ },
1564
+ };
1565
+
1566
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1567
+
2070
1568
  const task = taskManager.getTask(taskId);
2071
1569
  const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
1570
+
1571
+ webSocketManagerMock.emit('message', JSON.stringify(initialConsultingPayload));
1572
+ webSocketManagerMock.emit('message', JSON.stringify(consultingPayload));
1573
+ const stateMachineEvent = expectLastStateMachineEvent(
1574
+ sendStateMachineEventSpy,
1575
+ TaskEvent.CONSULTING_ACTIVE
1576
+ );
1577
+ expect(stateMachineEvent?.taskData).toEqual(consultingPayload.data);
1578
+ sendStateMachineEventSpy.mockRestore();
1579
+ });
1580
+
1581
+ it('should emit TASK_CONSULT_ENDED event on AGENT_CONSULT_ENDED event', () => {
2072
1582
  const payload = {
2073
1583
  data: {
2074
- type: CC_EVENTS.AGENT_OUTBOUND_FAILED,
2075
- interactionId: taskId,
2076
- reason: 'CUSTOMER_BUSY',
2077
- agentsPendingWrapUp: ['agent-123'],
2078
- interaction: {
2079
- outboundType: 'OUTDIAL',
2080
- isTerminated: true,
2081
- },
1584
+ ...initalPayload.data,
1585
+ type: CC_EVENTS.AGENT_CONSULT_ENDED,
2082
1586
  },
2083
1587
  };
1588
+
1589
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1590
+ taskManager.getTask(taskId).data.isConsulted = true;
1591
+ const task = taskManager.getTask(taskId);
1592
+ const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
2084
1593
  webSocketManagerMock.emit('message', JSON.stringify(payload));
2085
1594
  const stateMachineEvent = expectLastStateMachineEvent(
2086
1595
  sendStateMachineEventSpy,
2087
- TaskEvent.OUTBOUND_FAILED
1596
+ TaskEvent.CONSULT_END
2088
1597
  );
2089
- expect(stateMachineEvent?.taskData).toBeDefined();
2090
- expect(stateMachineEvent?.taskData?.agentsPendingWrapUp).toEqual(['agent-123']);
2091
- expect(stateMachineEvent?.taskData?.interaction?.outboundType).toBe('OUTDIAL');
1598
+ expect(stateMachineEvent?.taskData).toEqual(payload.data);
2092
1599
  sendStateMachineEventSpy.mockRestore();
2093
1600
  });
2094
1601
 
2095
- it('should handle AGENT_OUTBOUND_FAILED gracefully when task is undefined', () => {
1602
+ it('should emit TASK_CONSULT_ENDED event and remove currentTask when on AGENT_CONSULT_ENDED event when requested for a consult', () => {
2096
1603
  const payload = {
2097
1604
  data: {
2098
- type: CC_EVENTS.AGENT_OUTBOUND_FAILED,
2099
- interactionId: 'non-existent-task-id',
2100
- reason: 'CUSTOMER_BUSY',
1605
+ ...initalPayload.data,
1606
+ type: CC_EVENTS.AGENT_CONSULT_ENDED,
2101
1607
  },
2102
1608
  };
2103
- // Should not throw error when task doesn't exist
2104
- expect(() => {
2105
- webSocketManagerMock.emit('message', JSON.stringify(payload));
2106
- }).not.toThrow();
2107
- });
2108
1609
 
2109
- it('should NOT remove OUTDIAL task on CONTACT_ENDED when agentsPendingWrapUp exists', () => {
2110
- const task = taskManager.getTask(taskId);
2111
- Object.assign(task.data, {
2112
- interaction: {
2113
- ...task.data.interaction,
2114
- outboundType: 'OUTDIAL',
2115
- state: 'new',
2116
- mediaType: 'telephony',
2117
- },
2118
- agentsPendingWrapUp: ['agent-123'],
2119
- });
2120
- task.unregisterWebCallListeners = jest.fn();
2121
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
2122
-
2123
- const payload = {
2124
- data: {
2125
- type: CC_EVENTS.CONTACT_ENDED,
2126
- interactionId: taskId,
2127
- interaction: {
2128
- outboundType: 'OUTDIAL',
2129
- state: 'new',
2130
- mediaType: 'telephony',
2131
- },
2132
- agentsPendingWrapUp: ['agent-123'],
2133
- },
2134
- };
2135
-
2136
- webSocketManagerMock.emit('message', JSON.stringify(payload));
2137
-
2138
- expect(removeTaskSpy).not.toHaveBeenCalled();
2139
- expect(taskManager.getTask(taskId)).toBeDefined();
2140
- });
2141
-
2142
- it('should remove OUTDIAL task on CONTACT_ENDED when agentsPendingWrapUp is empty', () => {
2143
- const task = taskManager.getTask(taskId);
2144
- Object.assign(task.data, {
2145
- interaction: {
2146
- ...task.data.interaction,
2147
- outboundType: 'OUTDIAL',
2148
- state: 'new',
2149
- mediaType: 'telephony',
2150
- },
2151
- agentsPendingWrapUp: [],
2152
- });
2153
- task.unregisterWebCallListeners = jest.fn();
2154
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
2155
-
2156
- const payload = {
2157
- data: {
2158
- type: CC_EVENTS.CONTACT_ENDED,
2159
- interactionId: taskId,
2160
- interaction: {
2161
- outboundType: 'OUTDIAL',
2162
- state: 'new',
2163
- mediaType: 'telephony',
2164
- },
2165
- agentsPendingWrapUp: [],
2166
- },
2167
- };
2168
-
2169
- webSocketManagerMock.emit('message', JSON.stringify(payload));
2170
-
2171
- expect(removeTaskSpy).toHaveBeenCalled();
2172
- });
2173
-
2174
- it('should remove OUTDIAL task on CONTACT_ENDED when agentsPendingWrapUp is undefined', () => {
2175
- const task = taskManager.getTask(taskId);
2176
- Object.assign(task.data, {
2177
- interaction: {
2178
- ...task.data.interaction,
2179
- outboundType: 'OUTDIAL',
2180
- state: 'new',
2181
- mediaType: 'telephony',
2182
- },
2183
- });
2184
- task.unregisterWebCallListeners = jest.fn();
2185
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
2186
-
2187
- const payload = {
2188
- data: {
2189
- type: CC_EVENTS.CONTACT_ENDED,
2190
- interactionId: taskId,
2191
- interaction: {
2192
- outboundType: 'OUTDIAL',
2193
- state: 'new',
2194
- mediaType: 'telephony',
2195
- },
2196
- // agentsPendingWrapUp not included
2197
- },
2198
- };
2199
-
2200
- webSocketManagerMock.emit('message', JSON.stringify(payload));
2201
-
2202
- expect(removeTaskSpy).toHaveBeenCalled();
2203
- });
2204
-
2205
- it('should handle CONTACT_ENDED gracefully when task is undefined', () => {
2206
- const payload = {
2207
- data: {
2208
- type: CC_EVENTS.CONTACT_ENDED,
2209
- interactionId: 'non-existent-task-id',
2210
- interaction: {
2211
- state: 'new',
2212
- },
2213
- },
2214
- };
2215
- // Should not throw error when task doesn't exist
2216
- expect(() => {
2217
- webSocketManagerMock.emit('message', JSON.stringify(payload));
2218
- }).not.toThrow();
2219
- });
2220
-
2221
- it('should remove OUTDIAL task from taskCollection on AGENT_CONTACT_ASSIGN_FAILED when NOT terminated (user-declined)', () => {
2222
- const task = taskManager.getTask(taskId);
2223
- Object.assign(task.data, {
2224
- interaction: {
2225
- ...task.data.interaction,
2226
- outboundType: 'OUTDIAL',
2227
- state: 'new',
2228
- isTerminated: false,
2229
- },
2230
- });
2231
- task.unregisterWebCallListeners = jest.fn();
2232
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
2233
-
2234
- const payload = {
2235
- data: {
2236
- type: CC_EVENTS.AGENT_CONTACT_ASSIGN_FAILED,
2237
- agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
2238
- eventTime: 1733211616959,
2239
- eventType: 'RoutingMessage',
2240
- interaction: {
2241
- outboundType: 'OUTDIAL',
2242
- state: 'new',
2243
- isTerminated: false,
2244
- },
2245
- interactionId: taskId,
2246
- orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
2247
- trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
2248
- mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
2249
- destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
2250
- owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
2251
- queueMgr: 'aqm',
2252
- reason: 'USER_DECLINED',
2253
- reasonCode: 156,
2254
- },
2255
- };
2256
-
2257
- webSocketManagerMock.emit('message', JSON.stringify(payload));
2258
-
2259
- expect(taskManager.getTask(taskId)).toBeUndefined();
2260
- expect(removeTaskSpy).toHaveBeenCalled();
2261
- =======
2262
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2263
- });
2264
-
2265
- it('handle AGENT_OFFER_CONSULT event', () => {
2266
- const payload = {
2267
- data: {
2268
- ...initalPayload.data,
2269
- type: CC_EVENTS.AGENT_OFFER_CONSULT,
2270
- },
2271
- };
2272
-
2273
- webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
2274
- const task = taskManager.getTask(taskId);
2275
- const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
2276
-
2277
- webSocketManagerMock.emit('message', JSON.stringify(payload));
2278
-
2279
- const stateMachineEvent = expectLastStateMachineEvent(
2280
- sendStateMachineEventSpy,
2281
- TaskEvent.OFFER_CONSULT
2282
- );
2283
- expect(stateMachineEvent?.taskData).toEqual({...payload.data, isConsulted: true});
2284
- sendStateMachineEventSpy.mockRestore();
2285
- });
2286
-
2287
- it('should emit TASK_CONSULT_ACCEPTED event on AGENT_CONSULTING event', () => {
2288
- const initialConsultingPayload = {
2289
- data: {
2290
- ...initalPayload.data,
2291
- type: CC_EVENTS.AGENT_OFFER_CONSULT,
2292
- },
2293
- };
2294
-
2295
- const consultingPayload = {
2296
- data: {
2297
- ...initalPayload.data,
2298
- type: CC_EVENTS.AGENT_CONSULTING,
2299
- },
2300
- };
2301
-
2302
- webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
2303
-
2304
- const task = taskManager.getTask(taskId);
2305
- const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
2306
-
2307
- webSocketManagerMock.emit('message', JSON.stringify(initialConsultingPayload));
2308
- webSocketManagerMock.emit('message', JSON.stringify(consultingPayload));
2309
- const stateMachineEvent = expectLastStateMachineEvent(
2310
- sendStateMachineEventSpy,
2311
- TaskEvent.CONSULTING_ACTIVE
2312
- );
2313
- expect(stateMachineEvent?.taskData).toEqual(consultingPayload.data);
2314
- sendStateMachineEventSpy.mockRestore();
2315
- });
2316
-
2317
- it('should emit TASK_CONSULT_ENDED event on AGENT_CONSULT_ENDED event', () => {
2318
- const payload = {
2319
- data: {
2320
- ...initalPayload.data,
2321
- type: CC_EVENTS.AGENT_CONSULT_ENDED,
2322
- },
2323
- };
2324
-
2325
- webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
2326
- taskManager.getTask(taskId).data.isConsulted = true;
2327
- const task = taskManager.getTask(taskId);
2328
- const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
2329
- webSocketManagerMock.emit('message', JSON.stringify(payload));
2330
- <<<<<<< HEAD
2331
- const stateMachineEvent = expectLastStateMachineEvent(
2332
- sendStateMachineEventSpy,
2333
- TaskEvent.CONSULT_END
2334
- );
2335
- expect(stateMachineEvent?.taskData).toEqual(payload.data);
2336
- sendStateMachineEventSpy.mockRestore();
2337
- =======
2338
- expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
2339
- expect(taskEmitSpy).toHaveBeenCalledWith(
2340
- TASK_EVENTS.TASK_CONSULT_END,
2341
- taskManager.getTask(taskId)
2342
- );
2343
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2344
- });
2345
-
2346
- it('should emit TASK_CONSULT_ENDED event and remove currentTask when on AGENT_CONSULT_ENDED event when requested for a consult', () => {
2347
- const payload = {
2348
- data: {
2349
- ...initalPayload.data,
2350
- type: CC_EVENTS.AGENT_CONSULT_ENDED,
2351
- },
2352
- };
2353
-
2354
- webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1610
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
2355
1611
 
2356
1612
  taskManager.getTask(taskId).data.isConsulted = true;
2357
1613
  const task = taskManager.getTask(taskId);
@@ -2520,23 +1776,12 @@ describe('TaskManager', () => {
2520
1776
 
2521
1777
  webSocketManagerMock.emit('message', JSON.stringify(assignFailedPayload));
2522
1778
 
2523
- <<<<<<< HEAD
2524
1779
  const stateMachineEvent = expectLastStateMachineEvent(
2525
1780
  sendStateMachineEventSpy,
2526
1781
  TaskEvent.ASSIGN_FAILED
2527
1782
  );
2528
1783
  expect(stateMachineEvent?.reason).toBe(assignFailedPayload.data.reason);
2529
1784
  sendStateMachineEventSpy.mockRestore();
2530
- =======
2531
- expect(taskUpdateDataSpy).toHaveBeenCalledWith(assignFailedPayload.data);
2532
- expect(taskEmitSpy).toHaveBeenCalledWith(
2533
- TASK_EVENTS.TASK_REJECT,
2534
- assignFailedPayload.data.reason
2535
- );
2536
- // Verify the correct metric event name is used for AGENT_CONTACT_ASSIGN_FAILED
2537
- expect(metricsTrackSpy).toHaveBeenCalled();
2538
- expect(metricsTrackSpy.mock.calls[0][0]).toBe('Agent Contact Assign Failed');
2539
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2540
1785
  });
2541
1786
 
2542
1787
  it('should remove currentTask from taskCollection on AGENT_WRAPPEDUP event', () => {
@@ -2611,20 +1856,12 @@ describe('TaskManager', () => {
2611
1856
  },
2612
1857
  };
2613
1858
  webSocketManagerMock.emit('message', JSON.stringify(consultingPayload));
2614
- <<<<<<< HEAD
2615
1859
  expectLastStateMachineEvent(sendStateMachineEventSpy, TaskEvent.CONSULTING_ACTIVE);
2616
1860
  expect(taskManagerEmitSpy).toHaveBeenCalledWith(
2617
1861
  TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
2618
1862
  taskManager.getTask(taskId)
2619
1863
  );
2620
1864
  sendStateMachineEventSpy.mockRestore();
2621
- =======
2622
- expect(taskEmitSpy).toHaveBeenCalledWith(CC_EVENTS.AGENT_CONSULTING, consultingPayload.data);
2623
- expect(taskEmitSpy).toHaveBeenCalledWith(
2624
- TASK_EVENTS.TASK_CONSULTING,
2625
- taskManager.getTask(taskId)
2626
- );
2627
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2628
1865
  });
2629
1866
 
2630
1867
  it('should update task data on AGENT_CONTACT_UNASSIGNED', () => {
@@ -2651,7 +1888,6 @@ describe('TaskManager', () => {
2651
1888
  },
2652
1889
  };
2653
1890
  webSocketManagerMock.emit('message', JSON.stringify(unassignedPayload));
2654
- <<<<<<< HEAD
2655
1891
  expect(sendStateMachineEventSpy).not.toHaveBeenCalled();
2656
1892
  expect(updateTaskDataSpy).toHaveBeenCalledWith(unassignedPayload.data);
2657
1893
  });
@@ -2722,13 +1958,6 @@ describe('TaskManager', () => {
2722
1958
  destinationType: null,
2723
1959
  })
2724
1960
  );
2725
- =======
2726
- expect(taskEmitSpy).toHaveBeenCalledWith(
2727
- CC_EVENTS.AGENT_CONTACT_UNASSIGNED,
2728
- unassignedPayload.data
2729
- );
2730
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, taskManager.getTask(taskId));
2731
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2732
1961
  });
2733
1962
 
2734
1963
  it('should handle chat interaction and emit TASK_INCOMING immediately', () => {
@@ -2740,11 +1969,6 @@ describe('TaskManager', () => {
2740
1969
  },
2741
1970
  };
2742
1971
 
2743
- <<<<<<< HEAD
2744
- =======
2745
- const taskIncomingSpy = jest.spyOn(taskManager, 'emit');
2746
-
2747
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2748
1972
  // Simulate receiving a chat task
2749
1973
  webSocketManagerMock.emit('message', JSON.stringify(chatPayload));
2750
1974
 
@@ -2767,11 +1991,6 @@ describe('TaskManager', () => {
2767
1991
  },
2768
1992
  };
2769
1993
 
2770
- <<<<<<< HEAD
2771
- =======
2772
- const taskIncomingSpy = jest.spyOn(taskManager, 'emit');
2773
-
2774
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2775
1994
  // Simulate receiving an email task
2776
1995
  webSocketManagerMock.emit('message', JSON.stringify(emailPayload));
2777
1996
 
@@ -2795,21 +2014,11 @@ describe('TaskManager', () => {
2795
2014
  },
2796
2015
  };
2797
2016
 
2798
- <<<<<<< HEAD
2799
2017
  webSocketManagerMock.emit('message', JSON.stringify(chatReservedPayload));
2800
2018
  const task = taskManager.getTask(chatReservedPayload.data.interactionId);
2801
2019
  const sendStateMachineEventSpy = task.sendStateMachineEvent as jest.Mock;
2802
2020
 
2803
2021
  expectLastStateMachineEvent(sendStateMachineEventSpy, TaskEvent.TASK_INCOMING);
2804
- =======
2805
- const taskIncomingSpy = jest.spyOn(taskManager, 'emit');
2806
- webSocketManagerMock.emit('message', JSON.stringify(chatReservedPayload));
2807
-
2808
- expect(taskIncomingSpy).toHaveBeenCalledWith(
2809
- TASK_EVENTS.TASK_INCOMING,
2810
- taskManager.getTask(chatReservedPayload.data.interactionId)
2811
- );
2812
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2813
2022
 
2814
2023
  // 2. Chat task is assigned
2815
2024
  const chatAssignedPayload = {
@@ -2819,18 +2028,9 @@ describe('TaskManager', () => {
2819
2028
  },
2820
2029
  };
2821
2030
 
2822
- <<<<<<< HEAD
2823
2031
  webSocketManagerMock.emit('message', JSON.stringify(chatAssignedPayload));
2824
2032
 
2825
2033
  expectLastStateMachineEvent(sendStateMachineEventSpy, TaskEvent.ASSIGN);
2826
- =======
2827
- const task = taskManager.getTask(chatReservedPayload.data.interactionId);
2828
- const taskEmitSpy = jest.spyOn(task, 'emit');
2829
-
2830
- webSocketManagerMock.emit('message', JSON.stringify(chatAssignedPayload));
2831
-
2832
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_ASSIGNED, task);
2833
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2834
2034
 
2835
2035
  // 3. Chat task is ended with state 'new' to trigger cleanup
2836
2036
  const chatEndedPayload = {
@@ -2838,10 +2038,7 @@ describe('TaskManager', () => {
2838
2038
  ...chatReservedPayload.data,
2839
2039
  type: CC_EVENTS.CONTACT_ENDED,
2840
2040
  interaction: {mediaType: 'chat', state: 'new'}, // Change to 'new' state
2841
- <<<<<<< HEAD
2842
2041
  wrapUpRequired: false,
2843
- =======
2844
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2845
2042
  },
2846
2043
  };
2847
2044
 
@@ -2938,18 +2135,8 @@ describe('TaskManager', () => {
2938
2135
  expect(taskManager.getAllTasks()).toHaveProperty(task2Payload.data.interactionId);
2939
2136
  expect(taskManager.getAllTasks()).toHaveProperty(task3Payload.data.interactionId);
2940
2137
 
2941
- <<<<<<< HEAD
2942
2138
  const task2 = taskManager.getTask(task2Payload.data.interactionId);
2943
2139
  const task2SendStateMachineEventSpy = task2.sendStateMachineEvent as jest.Mock;
2944
- =======
2945
- // Create spies for all tasks
2946
- const task1EmitSpy = jest.spyOn(taskManager.getTask(task1Payload.data.interactionId), 'emit');
2947
- const task2EmitSpy = jest.spyOn(taskManager.getTask(task2Payload.data.interactionId), 'emit');
2948
- const task3EmitSpy = jest.spyOn(taskManager.getTask(task3Payload.data.interactionId), 'emit');
2949
-
2950
- // Store reference to task2 before it gets removed
2951
- const task2 = taskManager.getTask(task2Payload.data.interactionId);
2952
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2953
2140
 
2954
2141
  // End only the second task (chat task)
2955
2142
  const chatEndedPayload = {
@@ -2957,7 +2144,6 @@ describe('TaskManager', () => {
2957
2144
  ...task2Payload.data,
2958
2145
  type: CC_EVENTS.CONTACT_ENDED,
2959
2146
  interaction: {mediaType: 'chat', state: 'new'}, // Using 'new' to trigger cleanup
2960
- <<<<<<< HEAD
2961
2147
  wrapUpRequired: false,
2962
2148
  },
2963
2149
  };
@@ -2970,17 +2156,6 @@ describe('TaskManager', () => {
2970
2156
  TaskEvent.CONTACT_ENDED
2971
2157
  );
2972
2158
  expect(firstEndEvent?.taskData).toEqual(chatEndedPayload.data);
2973
- =======
2974
- },
2975
- };
2976
-
2977
- webSocketManagerMock.emit('message', JSON.stringify(chatEndedPayload));
2978
-
2979
- // Verify only task2 emitted TASK_END
2980
- expect(task1EmitSpy).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_END);
2981
- expect(task2EmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, task2);
2982
- expect(task3EmitSpy).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_END);
2983
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2984
2159
 
2985
2160
  // Verify task2 was removed from collection (since state was 'new')
2986
2161
  expect(taskManager.getTask(task2Payload.data.interactionId)).toBeUndefined();
@@ -2991,10 +2166,7 @@ describe('TaskManager', () => {
2991
2166
 
2992
2167
  // Store reference to task3 before we end it
2993
2168
  const task3 = taskManager.getTask(task3Payload.data.interactionId);
2994
- <<<<<<< HEAD
2995
2169
  const task3SendStateMachineEventSpy = task3.sendStateMachineEvent as jest.Mock;
2996
- =======
2997
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
2998
2170
 
2999
2171
  // Now end task3 with a state that doesn't trigger cleanup
3000
2172
  const emailEndedPayload = {
@@ -3002,8 +2174,8 @@ describe('TaskManager', () => {
3002
2174
  ...task3Payload.data,
3003
2175
  type: CC_EVENTS.CONTACT_ENDED,
3004
2176
  interaction: {mediaType: 'email', state: 'connected'}, // Using 'connected' to NOT trigger cleanup
3005
- <<<<<<< HEAD
3006
2177
  wrapUpRequired: true,
2178
+ agentsPendingWrapUp: ['test-agent-id'],
3007
2179
  },
3008
2180
  };
3009
2181
 
@@ -3015,15 +2187,6 @@ describe('TaskManager', () => {
3015
2187
  TaskEvent.CONTACT_ENDED
3016
2188
  );
3017
2189
  expect(secondEndEvent?.taskData).toEqual(emailEndedPayload.data);
3018
- =======
3019
- },
3020
- };
3021
-
3022
- webSocketManagerMock.emit('message', JSON.stringify(emailEndedPayload));
3023
-
3024
- // Verify task3 emitted TASK_END
3025
- expect(task3EmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, task3);
3026
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
3027
2190
 
3028
2191
  // Verify task3 is still in collection (since state was 'connected')
3029
2192
  expect(taskManager.getTask(task3Payload.data.interactionId)).toBeDefined();
@@ -3035,17 +2198,8 @@ describe('TaskManager', () => {
3035
2198
  it('should emit TRANSFER_SUCCESS event on AGENT_VTEAM_TRANSFERRED event', () => {
3036
2199
  // First create a task by emitting the initial payload
3037
2200
  webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
3038
- <<<<<<< HEAD
3039
2201
  const task = taskManager.getTask(taskId);
3040
2202
  const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
3041
- =======
3042
-
3043
- // Get a reference to the task from taskCollection
3044
- const task = taskManager.getTask(taskId);
3045
-
3046
- // Now spy on the task's emit method
3047
- const taskEmitSpy = jest.spyOn(task, 'emit');
3048
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
3049
2203
 
3050
2204
  const vteamTransferredPayload = {
3051
2205
  data: {
@@ -3069,14 +2223,9 @@ describe('TaskManager', () => {
3069
2223
 
3070
2224
  webSocketManagerMock.emit('message', JSON.stringify(vteamTransferredPayload));
3071
2225
 
3072
- <<<<<<< HEAD
3073
2226
  // Check that the state machine received the END event
3074
2227
  expectLastStateMachineEvent(sendStateMachineEventSpy, TaskEvent.TRANSFER_SUCCESS);
3075
2228
  sendStateMachineEventSpy.mockRestore();
3076
- =======
3077
- // Check that task.emit was called with TASK_END event
3078
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, task);
3079
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
3080
2229
 
3081
2230
  // The task should still exist in the collection based on current implementation
3082
2231
  expect(taskManager.getTask(taskId)).toBeDefined();
@@ -3091,14 +2240,7 @@ describe('TaskManager', () => {
3091
2240
  },
3092
2241
  };
3093
2242
  const task = taskManager.getTask(taskId);
3094
- <<<<<<< HEAD
3095
2243
  const sendStateMachineEventSpy = jest.spyOn(task, 'sendStateMachineEvent');
3096
- =======
3097
- const updateSpy = jest.spyOn(task, 'updateTaskData').mockImplementation((data) => {
3098
- task.data = {...(task.data || {}), ...(data || {})};
3099
- return task;
3100
- });
3101
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
3102
2244
  webSocketManagerMock.emit('message', JSON.stringify(payload));
3103
2245
  expect(sendStateMachineEventSpy).toHaveBeenCalled();
3104
2246
  const stateMachineEvent = sendStateMachineEventSpy.mock.calls.at(-1)?.[0];
@@ -3219,7 +2361,6 @@ describe('TaskManager', () => {
3219
2361
 
3220
2362
  describe('Conference event handling', () => {
3221
2363
  let task;
3222
- <<<<<<< HEAD
3223
2364
 
3224
2365
  beforeEach(() => {
3225
2366
  task = {
@@ -3227,22 +2368,6 @@ describe('TaskManager', () => {
3227
2368
  emit: jest.fn(),
3228
2369
  updateTaskData: jest.fn(),
3229
2370
  sendStateMachineEvent: jest.fn(),
3230
- =======
3231
- const agentId = '723a8ffb-a26e-496d-b14a-ff44fb83b64f';
3232
-
3233
- beforeEach(() => {
3234
- // Set the agentId on taskManager before tests run
3235
- taskManager.setAgentId(agentId);
3236
-
3237
- task = {
3238
- data: {interactionId: taskId},
3239
- emit: jest.fn(),
3240
- updateTaskData: jest.fn().mockImplementation((updatedData) => {
3241
- // Mock the updateTaskData method to actually update task.data
3242
- task.data = {...task.data, ...updatedData};
3243
- return task;
3244
- }),
3245
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
3246
2371
  };
3247
2372
  taskManager.taskCollection[taskId] = task as any;
3248
2373
  });
@@ -3279,28 +2404,7 @@ describe('TaskManager', () => {
3279
2404
 
3280
2405
  it('sends PARTICIPANT_LEFT_CONFERENCE to state machine as PARTICIPANT_LEAVE', () => {
3281
2406
  const payload = {
3282
- <<<<<<< HEAD
3283
2407
  data: {type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE, interactionId: taskId},
3284
- =======
3285
- data: {
3286
- type: CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE,
3287
- interactionId: taskId,
3288
- participantId: 'new-participant-123',
3289
- participantType: 'agent',
3290
- interaction: {
3291
- participants: {
3292
- [agentId]: {pType: 'Agent', hasLeft: false},
3293
- 'new-participant-123': {pType: 'Agent', hasLeft: false},
3294
- },
3295
- media: {
3296
- [taskId]: {
3297
- mType: 'mainCall',
3298
- participants: [agentId, 'new-participant-123'],
3299
- },
3300
- },
3301
- },
3302
- },
3303
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
3304
2408
  };
3305
2409
  webSocketManagerMock.emit('message', JSON.stringify(payload));
3306
2410
  expect(task.sendStateMachineEvent).toHaveBeenCalled();
@@ -3308,346 +2412,7 @@ describe('TaskManager', () => {
3308
2412
  expect(call.type).toBe(TaskEvent.PARTICIPANT_LEAVE);
3309
2413
  });
3310
2414
 
3311
- <<<<<<< HEAD
3312
2415
  it('handles AGENT_CONSULT_CONFERENCING event without errors', () => {
3313
- =======
3314
- it('should call updateTaskData only once for PARTICIPANT_JOINED_CONFERENCE with pre-calculated isConferenceInProgress', () => {
3315
- const payload = {
3316
- data: {
3317
- type: CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE,
3318
- interactionId: taskId,
3319
- participantId: 'new-agent-789',
3320
- interaction: {
3321
- participants: {
3322
- [agentId]: {pType: 'Agent', hasLeft: false},
3323
- 'agent-2': {pType: 'Agent', hasLeft: false},
3324
- 'new-agent-789': {pType: 'Agent', hasLeft: false},
3325
- 'customer-1': {pType: 'Customer', hasLeft: false},
3326
- },
3327
- media: {
3328
- [taskId]: {
3329
- mType: 'mainCall',
3330
- participants: [agentId, 'agent-2', 'new-agent-789', 'customer-1'],
3331
- },
3332
- },
3333
- },
3334
- },
3335
- };
3336
-
3337
- const updateTaskDataSpy = jest.spyOn(task, 'updateTaskData');
3338
-
3339
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3340
-
3341
- // Verify updateTaskData was called exactly once
3342
- expect(updateTaskDataSpy).toHaveBeenCalledTimes(1);
3343
-
3344
- // Verify it was called with isConferenceInProgress already calculated
3345
- expect(updateTaskDataSpy).toHaveBeenCalledWith(
3346
- expect.objectContaining({
3347
- participantId: 'new-agent-789',
3348
- isConferenceInProgress: true, // 3 active agents
3349
- })
3350
- );
3351
-
3352
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_JOINED, task);
3353
- });
3354
-
3355
- describe('PARTICIPANT_LEFT_CONFERENCE event handling', () => {
3356
- it('should call updateTaskData only once for PARTICIPANT_LEFT_CONFERENCE with pre-calculated isConferenceInProgress', () => {
3357
- const payload = {
3358
- data: {
3359
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3360
- interactionId: taskId,
3361
- interaction: {
3362
- participants: {
3363
- [agentId]: {pType: 'Agent', hasLeft: false},
3364
- 'agent-2': {pType: 'Agent', hasLeft: true}, // This agent left
3365
- 'customer-1': {pType: 'Customer', hasLeft: false},
3366
- },
3367
- media: {
3368
- [taskId]: {
3369
- mType: 'mainCall',
3370
- participants: [agentId, 'customer-1'], // agent-2 removed from participants
3371
- },
3372
- },
3373
- },
3374
- },
3375
- };
3376
-
3377
- const updateTaskDataSpy = jest.spyOn(task, 'updateTaskData');
3378
-
3379
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3380
-
3381
- // Verify updateTaskData was called exactly once
3382
- expect(updateTaskDataSpy).toHaveBeenCalledTimes(1);
3383
-
3384
- // Verify it was called with isConferenceInProgress already calculated
3385
- expect(updateTaskDataSpy).toHaveBeenCalledWith(
3386
- expect.objectContaining({
3387
- isConferenceInProgress: false, // Only 1 active agent remains
3388
- })
3389
- );
3390
-
3391
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3392
- });
3393
-
3394
- it('should emit TASK_PARTICIPANT_LEFT event when participant leaves conference', () => {
3395
- const payload = {
3396
- data: {
3397
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3398
- interactionId: taskId,
3399
- interaction: {
3400
- participants: {
3401
- [agentId]: {
3402
- hasLeft: false,
3403
- },
3404
- },
3405
- },
3406
- },
3407
- };
3408
-
3409
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3410
-
3411
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3412
- });
3413
-
3414
- it('should NOT remove task when agent is still in interaction', () => {
3415
- const payload = {
3416
- data: {
3417
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3418
- interactionId: taskId,
3419
- interaction: {
3420
- participants: {
3421
- [agentId]: {
3422
- hasLeft: false,
3423
- },
3424
- },
3425
- },
3426
- },
3427
- };
3428
-
3429
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3430
-
3431
- // Task should still exist in collection
3432
- expect(taskManager.getTask(taskId)).toBeDefined();
3433
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3434
- });
3435
-
3436
- it('should NOT remove task when agent left but is in main interaction', () => {
3437
- const payload = {
3438
- data: {
3439
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3440
- interactionId: taskId,
3441
- interaction: {
3442
- participants: {
3443
- [agentId]: {
3444
- hasLeft: true,
3445
- },
3446
- },
3447
- media: {
3448
- [taskId]: {
3449
- mType: 'mainCall',
3450
- participants: [agentId],
3451
- },
3452
- },
3453
- },
3454
- },
3455
- };
3456
-
3457
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3458
-
3459
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3460
-
3461
- // Task should still exist - not removed
3462
- expect(removeTaskSpy).not.toHaveBeenCalled();
3463
- expect(taskManager.getTask(taskId)).toBeDefined();
3464
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3465
- });
3466
-
3467
- it('should NOT remove task when agent left but is primary (owner)', () => {
3468
- const payload = {
3469
- data: {
3470
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3471
- interactionId: taskId,
3472
- interaction: {
3473
- participants: {
3474
- [agentId]: {
3475
- hasLeft: true,
3476
- },
3477
- },
3478
- owner: agentId,
3479
- media: {
3480
- [taskId]: {
3481
- mType: 'consultCall',
3482
- participants: ['other-agent'],
3483
- },
3484
- },
3485
- },
3486
- },
3487
- };
3488
-
3489
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3490
-
3491
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3492
-
3493
- // Task should still exist - not removed because agent is primary
3494
- expect(removeTaskSpy).not.toHaveBeenCalled();
3495
- expect(taskManager.getTask(taskId)).toBeDefined();
3496
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3497
- });
3498
-
3499
- it('should remove task when agent left and is NOT in main interaction and is NOT primary', () => {
3500
- const payload = {
3501
- data: {
3502
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3503
- interactionId: taskId,
3504
- interaction: {
3505
- participants: {
3506
- [agentId]: {
3507
- hasLeft: true,
3508
- },
3509
- },
3510
- owner: 'another-agent-id',
3511
- media: {
3512
- [taskId]: {
3513
- mType: 'mainCall',
3514
- participants: ['another-agent-id'],
3515
- },
3516
- },
3517
- },
3518
- },
3519
- };
3520
-
3521
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3522
-
3523
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3524
-
3525
- // Task should be removed
3526
- expect(removeTaskSpy).toHaveBeenCalled();
3527
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3528
- });
3529
-
3530
- it('should remove task when agent is not in participants list', () => {
3531
- const payload = {
3532
- data: {
3533
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3534
- interactionId: taskId,
3535
- interaction: {
3536
- participants: {
3537
- 'other-agent-id': {
3538
- hasLeft: false,
3539
- },
3540
- },
3541
- owner: 'another-agent-id',
3542
- },
3543
- },
3544
- };
3545
-
3546
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3547
-
3548
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3549
-
3550
- // Task should be removed because agent is not in participants
3551
- expect(removeTaskSpy).toHaveBeenCalled();
3552
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3553
- });
3554
-
3555
- it('should update isConferenceInProgress based on remaining active agents', () => {
3556
- const payload = {
3557
- data: {
3558
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3559
- interactionId: taskId,
3560
- interaction: {
3561
- participants: {
3562
- [agentId]: {
3563
- hasLeft: false,
3564
- pType: 'Agent',
3565
- },
3566
- 'agent-2': {
3567
- hasLeft: false,
3568
- pType: 'Agent',
3569
- },
3570
- 'customer-1': {
3571
- hasLeft: false,
3572
- pType: 'Customer',
3573
- },
3574
- },
3575
- media: {
3576
- [taskId]: {
3577
- mType: 'mainCall',
3578
- participants: [agentId, 'agent-2', 'customer-1'],
3579
- },
3580
- },
3581
- },
3582
- },
3583
- };
3584
-
3585
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3586
-
3587
- // isConferenceInProgress should be true (2 active agents)
3588
- expect(task.data.isConferenceInProgress).toBe(true);
3589
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3590
- });
3591
-
3592
- it('should set isConferenceInProgress to false when only one agent remains', () => {
3593
- const payload = {
3594
- data: {
3595
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3596
- interactionId: taskId,
3597
- interaction: {
3598
- participants: {
3599
- [agentId]: {
3600
- hasLeft: false,
3601
- pType: 'Agent',
3602
- },
3603
- 'agent-2': {
3604
- hasLeft: true,
3605
- pType: 'Agent',
3606
- },
3607
- 'customer-1': {
3608
- hasLeft: false,
3609
- pType: 'Customer',
3610
- },
3611
- },
3612
- media: {
3613
- [taskId]: {
3614
- mType: 'mainCall',
3615
- participants: [agentId, 'customer-1'],
3616
- },
3617
- },
3618
- },
3619
- },
3620
- };
3621
-
3622
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3623
-
3624
- // isConferenceInProgress should be false (only 1 active agent)
3625
- expect(task.data.isConferenceInProgress).toBe(false);
3626
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3627
- });
3628
-
3629
- it('should handle participant left when no participants data exists', () => {
3630
- const payload = {
3631
- data: {
3632
- type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
3633
- interactionId: taskId,
3634
- interaction: {},
3635
- },
3636
- };
3637
-
3638
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3639
-
3640
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3641
-
3642
- // When no participants data exists, checkParticipantNotInInteraction returns true
3643
- // Since agent won't be in main interaction either, task should be removed
3644
- expect(removeTaskSpy).toHaveBeenCalled();
3645
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
3646
- });
3647
- });
3648
-
3649
- it('should handle PARTICIPANT_LEFT_CONFERENCE_FAILED event', () => {
3650
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
3651
2416
  const payload = {
3652
2417
  data: {type: CC_EVENTS.AGENT_CONSULT_CONFERENCING, interactionId: taskId},
3653
2418
  };
@@ -3667,11 +2432,7 @@ describe('TaskManager', () => {
3667
2432
 
3668
2433
  it('only routes conference events to matching tasks', () => {
3669
2434
  const otherTaskId = 'other-task-id';
3670
- <<<<<<< HEAD
3671
2435
  const otherTask: any = {
3672
- =======
3673
- const otherTask = {
3674
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
3675
2436
  data: {interactionId: otherTaskId},
3676
2437
  emit: jest.fn(),
3677
2438
  updateTaskData: jest.fn(),
@@ -3684,7 +2445,6 @@ describe('TaskManager', () => {
3684
2445
  };
3685
2446
  webSocketManagerMock.emit('message', JSON.stringify(payload));
3686
2447
 
3687
- <<<<<<< HEAD
3688
2448
  expect(task.sendStateMachineEvent).toHaveBeenCalled();
3689
2449
  expect(otherTask.sendStateMachineEvent).not.toHaveBeenCalled();
3690
2450
  });
@@ -3716,939 +2476,6 @@ describe('TaskManager', () => {
3716
2476
  });
3717
2477
 
3718
2478
  sendStateMachineEventSpy.mockRestore();
3719
- =======
3720
- // Only the matching task should be updated
3721
- expect(task.data.isConferencing).toBe(true);
3722
- expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
3723
-
3724
- // Other task should not be affected
3725
- expect(otherTask.data.isConferencing).toBeUndefined();
3726
- expect(otherTask.emit).not.toHaveBeenCalled();
3727
- });
3728
- });
3729
-
3730
- describe('handleTaskCleanup - stage changes', () => {
3731
- const agentId = '723a8ffb-a26e-496d-b14a-ff44fb83b64f';
3732
-
3733
- beforeEach(() => {
3734
- taskManager.setAgentId(agentId);
3735
- });
3736
-
3737
- it('should remove OUTDIAL task on CONTACT_ENDED when current agent is NOT in agentsPendingWrapUp', () => {
3738
- const task = taskManager.getTask(taskId);
3739
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
3740
- task.data = {
3741
- ...task.data,
3742
- ...newData,
3743
- interaction: {
3744
- ...task.data.interaction,
3745
- outboundType: 'OUTDIAL',
3746
- state: 'new',
3747
- mediaType: 'telephony',
3748
- },
3749
- agentsPendingWrapUp: ['different-agent-123'], // Current agent not in the list
3750
- };
3751
- return task;
3752
- });
3753
- task.unregisterWebCallListeners = jest.fn();
3754
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3755
-
3756
- const payload = {
3757
- data: {
3758
- type: CC_EVENTS.CONTACT_ENDED,
3759
- interactionId: taskId,
3760
- interaction: {
3761
- outboundType: 'OUTDIAL',
3762
- state: 'new',
3763
- mediaType: 'telephony',
3764
- },
3765
- agentsPendingWrapUp: ['different-agent-123'], // Current agent not in the list
3766
- },
3767
- };
3768
-
3769
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3770
-
3771
- expect(removeTaskSpy).toHaveBeenCalled();
3772
- expect(taskManager.getTask(taskId)).toBeUndefined();
3773
- });
3774
-
3775
- it('should NOT remove OUTDIAL task on CONTACT_ENDED when current agent IS in agentsPendingWrapUp', () => {
3776
- const task = taskManager.getTask(taskId);
3777
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
3778
- task.data = {
3779
- ...task.data,
3780
- ...newData,
3781
- interaction: {
3782
- ...task.data.interaction,
3783
- outboundType: 'OUTDIAL',
3784
- state: 'new',
3785
- mediaType: 'telephony',
3786
- },
3787
- agentsPendingWrapUp: [agentId, 'other-agent-456'], // Current agent IS in the list
3788
- };
3789
- return task;
3790
- });
3791
- task.unregisterWebCallListeners = jest.fn();
3792
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3793
-
3794
- const payload = {
3795
- data: {
3796
- type: CC_EVENTS.CONTACT_ENDED,
3797
- interactionId: taskId,
3798
- interaction: {
3799
- outboundType: 'OUTDIAL',
3800
- state: 'new',
3801
- mediaType: 'telephony',
3802
- },
3803
- agentsPendingWrapUp: [agentId, 'other-agent-456'], // Current agent IS in the list
3804
- },
3805
- };
3806
-
3807
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3808
-
3809
- expect(removeTaskSpy).not.toHaveBeenCalled();
3810
- expect(taskManager.getTask(taskId)).toBeDefined();
3811
- });
3812
-
3813
- it('should remove OUTDIAL task when needsWrapUp is false and task is outdial', () => {
3814
- const task = taskManager.getTask(taskId);
3815
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
3816
- task.data = {
3817
- ...task.data,
3818
- ...newData,
3819
- interaction: {
3820
- ...task.data.interaction,
3821
- outboundType: 'OUTDIAL',
3822
- state: 'WRAPUP', // Not 'new' state
3823
- mediaType: 'telephony',
3824
- },
3825
- agentsPendingWrapUp: [], // No agents pending wrap-up
3826
- };
3827
- return task;
3828
- });
3829
- task.unregisterWebCallListeners = jest.fn();
3830
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3831
-
3832
- const payload = {
3833
- data: {
3834
- type: CC_EVENTS.CONTACT_ENDED,
3835
- interactionId: taskId,
3836
- interaction: {
3837
- outboundType: 'OUTDIAL',
3838
- state: 'WRAPUP', // Not 'new' state
3839
- mediaType: 'telephony',
3840
- },
3841
- agentsPendingWrapUp: [], // No agents pending wrap-up
3842
- },
3843
- };
3844
-
3845
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3846
-
3847
- expect(removeTaskSpy).toHaveBeenCalled();
3848
- expect(taskManager.getTask(taskId)).toBeUndefined();
3849
- });
3850
-
3851
- it('should remove OUTDIAL task when needsWrapUp is false (agentsPendingWrapUp is undefined)', () => {
3852
- const task = taskManager.getTask(taskId);
3853
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
3854
- task.data = {
3855
- ...task.data,
3856
- ...newData,
3857
- interaction: {
3858
- ...task.data.interaction,
3859
- outboundType: 'OUTDIAL',
3860
- state: 'WRAPUP',
3861
- mediaType: 'telephony',
3862
- },
3863
- agentsPendingWrapUp: undefined, // No agentsPendingWrapUp field
3864
- };
3865
- return task;
3866
- });
3867
- task.unregisterWebCallListeners = jest.fn();
3868
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3869
-
3870
- const payload = {
3871
- data: {
3872
- type: CC_EVENTS.CONTACT_ENDED,
3873
- interactionId: taskId,
3874
- interaction: {
3875
- outboundType: 'OUTDIAL',
3876
- state: 'WRAPUP',
3877
- mediaType: 'telephony',
3878
- },
3879
- // agentsPendingWrapUp not included
3880
- },
3881
- };
3882
-
3883
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3884
-
3885
- expect(removeTaskSpy).toHaveBeenCalled();
3886
- expect(taskManager.getTask(taskId)).toBeUndefined();
3887
- });
3888
-
3889
- it('should NOT remove OUTDIAL task when needsWrapUp is true (current agent in agentsPendingWrapUp) even if state is WRAPUP', () => {
3890
- const task = taskManager.getTask(taskId);
3891
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
3892
- task.data = {
3893
- ...task.data,
3894
- ...newData,
3895
- interaction: {
3896
- ...task.data.interaction,
3897
- outboundType: 'OUTDIAL',
3898
- state: 'WRAPUP',
3899
- mediaType: 'telephony',
3900
- },
3901
- agentsPendingWrapUp: [agentId], // Current agent needs wrap-up
3902
- };
3903
- return task;
3904
- });
3905
- task.unregisterWebCallListeners = jest.fn();
3906
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3907
-
3908
- const payload = {
3909
- data: {
3910
- type: CC_EVENTS.CONTACT_ENDED,
3911
- interactionId: taskId,
3912
- interaction: {
3913
- outboundType: 'OUTDIAL',
3914
- state: 'WRAPUP',
3915
- mediaType: 'telephony',
3916
- },
3917
- agentsPendingWrapUp: [agentId], // Current agent needs wrap-up
3918
- },
3919
- };
3920
-
3921
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3922
-
3923
- expect(removeTaskSpy).not.toHaveBeenCalled();
3924
- expect(taskManager.getTask(taskId)).toBeDefined();
3925
- });
3926
-
3927
- it('should remove non-OUTDIAL task when state is new regardless of agentsPendingWrapUp', () => {
3928
- const task = taskManager.getTask(taskId);
3929
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
3930
- task.data = {
3931
- ...task.data,
3932
- ...newData,
3933
- interaction: {
3934
- ...task.data.interaction,
3935
- outboundType: 'PREVIEW', // Not OUTDIAL
3936
- state: 'new',
3937
- mediaType: 'telephony',
3938
- },
3939
- agentsPendingWrapUp: [agentId],
3940
- };
3941
- return task;
3942
- });
3943
- task.unregisterWebCallListeners = jest.fn();
3944
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3945
-
3946
- const payload = {
3947
- data: {
3948
- type: CC_EVENTS.CONTACT_ENDED,
3949
- interactionId: taskId,
3950
- interaction: {
3951
- outboundType: 'PREVIEW',
3952
- state: 'new',
3953
- mediaType: 'telephony',
3954
- },
3955
- agentsPendingWrapUp: [agentId],
3956
- },
3957
- };
3958
-
3959
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3960
-
3961
- expect(removeTaskSpy).toHaveBeenCalled();
3962
- expect(taskManager.getTask(taskId)).toBeUndefined();
3963
- });
3964
-
3965
- it('should handle agentsPendingWrapUp with multiple agents correctly - remove if current agent not in list', () => {
3966
- const task = taskManager.getTask(taskId);
3967
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
3968
- task.data = {
3969
- ...task.data,
3970
- ...newData,
3971
- interaction: {
3972
- ...task.data.interaction,
3973
- outboundType: 'OUTDIAL',
3974
- state: 'new',
3975
- mediaType: 'telephony',
3976
- },
3977
- agentsPendingWrapUp: ['agent-1', 'agent-2', 'agent-3'], // Current agent not in the list
3978
- };
3979
- return task;
3980
- });
3981
- task.unregisterWebCallListeners = jest.fn();
3982
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
3983
-
3984
- const payload = {
3985
- data: {
3986
- type: CC_EVENTS.CONTACT_ENDED,
3987
- interactionId: taskId,
3988
- interaction: {
3989
- outboundType: 'OUTDIAL',
3990
- state: 'new',
3991
- mediaType: 'telephony',
3992
- },
3993
- agentsPendingWrapUp: ['agent-1', 'agent-2', 'agent-3'],
3994
- },
3995
- };
3996
-
3997
- webSocketManagerMock.emit('message', JSON.stringify(payload));
3998
-
3999
- expect(removeTaskSpy).toHaveBeenCalled();
4000
- expect(taskManager.getTask(taskId)).toBeUndefined();
4001
- });
4002
-
4003
- it('should handle agentsPendingWrapUp with multiple agents correctly - keep if current agent is in list', () => {
4004
- const task = taskManager.getTask(taskId);
4005
- task.updateTaskData = jest.fn().mockImplementation((newData) => {
4006
- task.data = {
4007
- ...task.data,
4008
- ...newData,
4009
- interaction: {
4010
- ...task.data.interaction,
4011
- outboundType: 'OUTDIAL',
4012
- state: 'new',
4013
- mediaType: 'telephony',
4014
- },
4015
- agentsPendingWrapUp: ['agent-1', agentId, 'agent-3'], // Current agent IS in the list
4016
- };
4017
- return task;
4018
- });
4019
- task.unregisterWebCallListeners = jest.fn();
4020
- const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
4021
-
4022
- const payload = {
4023
- data: {
4024
- type: CC_EVENTS.CONTACT_ENDED,
4025
- interactionId: taskId,
4026
- interaction: {
4027
- outboundType: 'OUTDIAL',
4028
- state: 'new',
4029
- mediaType: 'telephony',
4030
- },
4031
- agentsPendingWrapUp: ['agent-1', agentId, 'agent-3'],
4032
- },
4033
- };
4034
-
4035
- webSocketManagerMock.emit('message', JSON.stringify(payload));
4036
-
4037
- expect(removeTaskSpy).not.toHaveBeenCalled();
4038
- expect(taskManager.getTask(taskId)).toBeDefined();
4039
- });
4040
- });
4041
-
4042
- describe('CONTACT_MERGED event handling', () => {
4043
- let task;
4044
- let taskEmitSpy;
4045
- let managerEmitSpy;
4046
-
4047
- beforeEach(() => {
4048
- // Create initial task
4049
- webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
4050
- task = taskManager.getTask(taskId);
4051
- taskEmitSpy = jest.spyOn(task, 'emit');
4052
- managerEmitSpy = jest.spyOn(taskManager, 'emit');
4053
- });
4054
-
4055
- it('should update existing task data and emit TASK_MERGED event when CONTACT_MERGED is received', () => {
4056
- const mergedPayload = {
4057
- data: {
4058
- type: CC_EVENTS.CONTACT_MERGED,
4059
- interactionId: taskId,
4060
- agentId: taskDataMock.agentId,
4061
- interaction: {
4062
- ...taskDataMock.interaction,
4063
- state: 'merged',
4064
- customField: 'updated-value',
4065
- },
4066
- },
4067
- };
4068
-
4069
- webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
4070
-
4071
- const updatedTask = taskManager.getTask(taskId);
4072
- expect(updatedTask).toBeDefined();
4073
- expect(updatedTask.data.interaction.customField).toBe('updated-value');
4074
- expect(updatedTask.data.interaction.state).toBe('merged');
4075
- expect(managerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_MERGED, updatedTask);
4076
- });
4077
-
4078
- it('should create new task when CONTACT_MERGED is received for non-existing task', () => {
4079
- const newMergedTaskId = 'new-merged-task-id';
4080
- const mergedPayload = {
4081
- data: {
4082
- type: CC_EVENTS.CONTACT_MERGED,
4083
- interactionId: newMergedTaskId,
4084
- agentId: taskDataMock.agentId,
4085
- interaction: {
4086
- mediaType: 'telephony',
4087
- state: 'merged',
4088
- participants: {
4089
- [taskDataMock.agentId]: {
4090
- isWrapUp: false,
4091
- hasJoined: true,
4092
- },
4093
- },
4094
- },
4095
- },
4096
- };
4097
-
4098
- // Verify task doesn't exist before
4099
- expect(taskManager.getTask(newMergedTaskId)).toBeUndefined();
4100
-
4101
- webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
4102
-
4103
- // Verify task was created
4104
- const newTask = taskManager.getTask(newMergedTaskId);
4105
- expect(newTask).toBeDefined();
4106
- expect(newTask.data.interactionId).toBe(newMergedTaskId);
4107
- expect(managerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_MERGED, newTask);
4108
- });
4109
-
4110
- it('should remove child task when childInteractionId is present in CONTACT_MERGED', () => {
4111
- const childTaskId = 'child-task-id';
4112
- const parentTaskId = 'parent-task-id';
4113
-
4114
- // Create child task
4115
- const childPayload = {
4116
- data: {
4117
- type: CC_EVENTS.AGENT_CONTACT_RESERVED,
4118
- interactionId: childTaskId,
4119
- agentId: taskDataMock.agentId,
4120
- interaction: {mediaType: 'telephony'},
4121
- },
4122
- };
4123
- webSocketManagerMock.emit('message', JSON.stringify(childPayload));
4124
-
4125
- // Verify child task exists
4126
- expect(taskManager.getTask(childTaskId)).toBeDefined();
4127
-
4128
- // Create parent task
4129
- const parentPayload = {
4130
- data: {
4131
- type: CC_EVENTS.AGENT_CONTACT_RESERVED,
4132
- interactionId: parentTaskId,
4133
- agentId: taskDataMock.agentId,
4134
- interaction: {mediaType: 'telephony'},
4135
- },
4136
- };
4137
- webSocketManagerMock.emit('message', JSON.stringify(parentPayload));
4138
-
4139
- // Send CONTACT_MERGED with childInteractionId
4140
- const mergedPayload = {
4141
- data: {
4142
- type: CC_EVENTS.CONTACT_MERGED,
4143
- interactionId: parentTaskId,
4144
- childInteractionId: childTaskId,
4145
- agentId: taskDataMock.agentId,
4146
- interaction: {
4147
- mediaType: 'telephony',
4148
- state: 'merged',
4149
- },
4150
- },
4151
- };
4152
-
4153
- webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
4154
-
4155
- // Verify child task was removed
4156
- expect(taskManager.getTask(childTaskId)).toBeUndefined();
4157
-
4158
- // Verify parent task still exists
4159
- expect(taskManager.getTask(parentTaskId)).toBeDefined();
4160
-
4161
- // Verify TASK_MERGED event was emitted
4162
- expect(managerEmitSpy).toHaveBeenCalledWith(
4163
- TASK_EVENTS.TASK_MERGED,
4164
- expect.objectContaining({
4165
- data: expect.objectContaining({
4166
- interactionId: parentTaskId,
4167
- }),
4168
- })
4169
- );
4170
- });
4171
-
4172
- it('should handle CONTACT_MERGED with EP-DN participant correctly', () => {
4173
- const epdnTaskId = 'epdn-merged-task';
4174
- const mergedPayload = {
4175
- data: {
4176
- type: CC_EVENTS.CONTACT_MERGED,
4177
- interactionId: epdnTaskId,
4178
- agentId: taskDataMock.agentId,
4179
- interaction: {
4180
- mediaType: 'telephony',
4181
- state: 'merged',
4182
- participants: {
4183
- [taskDataMock.agentId]: {
4184
- type: 'Agent',
4185
- isWrapUp: false,
4186
- hasJoined: true,
4187
- },
4188
- 'epdn-participant': {
4189
- type: 'EpDn',
4190
- epId: 'entry-point-123',
4191
- isWrapUp: false,
4192
- },
4193
- },
4194
- },
4195
- },
4196
- };
4197
-
4198
- webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
4199
-
4200
- const mergedTask = taskManager.getTask(epdnTaskId);
4201
- expect(mergedTask).toBeDefined();
4202
- expect(mergedTask.data.interaction.participants['epdn-participant']).toBeDefined();
4203
- expect(mergedTask.data.interaction.participants['epdn-participant'].type).toBe('EpDn');
4204
- expect(managerEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_MERGED, mergedTask);
4205
- });
4206
-
4207
- it('should not affect other tasks when CONTACT_MERGED is received', () => {
4208
- const otherTaskId = 'other-unrelated-task';
4209
- const otherPayload = {
4210
- data: {
4211
- type: CC_EVENTS.AGENT_CONTACT_RESERVED,
4212
- interactionId: otherTaskId,
4213
- agentId: taskDataMock.agentId,
4214
- interaction: {mediaType: 'chat'},
4215
- },
4216
- };
4217
- webSocketManagerMock.emit('message', JSON.stringify(otherPayload));
4218
-
4219
- const otherTask = taskManager.getTask(otherTaskId);
4220
- const otherTaskEmitSpy = jest.spyOn(otherTask, 'emit');
4221
-
4222
- // Send CONTACT_MERGED for the original task
4223
- const mergedPayload = {
4224
- data: {
4225
- type: CC_EVENTS.CONTACT_MERGED,
4226
- interactionId: taskId,
4227
- agentId: taskDataMock.agentId,
4228
- interaction: {
4229
- mediaType: 'telephony',
4230
- state: 'merged',
4231
- },
4232
- },
4233
- };
4234
-
4235
- webSocketManagerMock.emit('message', JSON.stringify(mergedPayload));
4236
-
4237
- // Verify other task was not affected
4238
- expect(otherTaskEmitSpy).not.toHaveBeenCalled();
4239
- expect(otherTask.data.interaction.mediaType).toBe('chat');
4240
-
4241
- // Verify original task was updated
4242
- expect(managerEmitSpy).toHaveBeenCalledWith(
4243
- TASK_EVENTS.TASK_MERGED,
4244
- expect.objectContaining({
4245
- data: expect.objectContaining({
4246
- interactionId: taskId,
4247
- }),
4248
- })
4249
- );
4250
- });
4251
- });
4252
-
4253
- describe('Campaign Preview Reservation', () => {
4254
- it('should create a task and emit TASK_CAMPAIGN_PREVIEW_RESERVATION when AgentOfferCampaignReservation is received', () => {
4255
- const campaignPayload = {
4256
- data: {
4257
- type: CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION,
4258
- interactionId: 'campaign-interaction-123',
4259
- agentId: taskDataMock.agentId,
4260
- orgId: taskDataMock.orgId,
4261
- trackingId: 'campaign-tracking-456',
4262
- interaction: {
4263
- mediaType: 'telephony',
4264
- callProcessingDetails: {
4265
- campaignId: 'campaign-789',
4266
- },
4267
- },
4268
- },
4269
- };
4270
-
4271
- const managerEmitSpy = jest.spyOn(taskManager, 'emit');
4272
-
4273
- webSocketManagerMock.emit('message', JSON.stringify(campaignPayload));
4274
-
4275
- // Should emit with a task object (not raw data)
4276
- expect(managerEmitSpy).toHaveBeenCalledWith(
4277
- TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION,
4278
- expect.objectContaining({
4279
- data: expect.objectContaining({
4280
- interactionId: 'campaign-interaction-123',
4281
- type: CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION,
4282
- wrapUpRequired: false,
4283
- isAutoAnswering: false,
4284
- }),
4285
- })
4286
- );
4287
-
4288
- // Task should be in the collection so subsequent events (e.g. AGENT_CONTACT_ASSIGNED) can find it
4289
- expect(taskManager['taskCollection']['campaign-interaction-123']).toBeDefined();
4290
- });
4291
-
4292
- it('should re-key task and emit TASK_ASSIGNED when AgentContactAssigned uses a new interactionId', () => {
4293
- const reservationInteractionId = 'campaign-reservation-id';
4294
- const assignedInteractionId = 'campaign-assigned-id';
4295
-
4296
- webSocketManagerMock.emit(
4297
- 'message',
4298
- JSON.stringify({
4299
- data: {
4300
- type: CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION,
4301
- interactionId: reservationInteractionId,
4302
- agentId: taskDataMock.agentId,
4303
- orgId: taskDataMock.orgId,
4304
- trackingId: 'campaign-tracking-456',
4305
- interaction: {
4306
- mediaType: 'telephony',
4307
- callProcessingDetails: {campaignId: 'campaign-789'},
4308
- },
4309
- },
4310
- })
4311
- );
4312
-
4313
- const taskBeforeAssign = taskManager['taskCollection'][reservationInteractionId];
4314
- expect(taskBeforeAssign).toBeDefined();
4315
-
4316
- const taskEmitSpy = jest.spyOn(taskBeforeAssign, 'emit');
4317
-
4318
- webSocketManagerMock.emit(
4319
- 'message',
4320
- JSON.stringify({
4321
- data: {
4322
- type: CC_EVENTS.AGENT_CONTACT_ASSIGNED,
4323
- interactionId: assignedInteractionId,
4324
- reservationInteractionId,
4325
- agentId: taskDataMock.agentId,
4326
- orgId: taskDataMock.orgId,
4327
- trackingId: 'campaign-tracking-assigned',
4328
- interaction: {mediaType: 'telephony', state: 'connected'},
4329
- },
4330
- })
4331
- );
4332
-
4333
- expect(taskManager['taskCollection'][reservationInteractionId]).toBeUndefined();
4334
- expect(taskManager['taskCollection'][assignedInteractionId]).toBe(taskBeforeAssign);
4335
- expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_ASSIGNED, taskBeforeAssign);
4336
-
4337
- taskEmitSpy.mockRestore();
4338
- });
4339
-
4340
- it('should not emit TASK_INCOMING for campaign preview reservation when incoming WebRTC call arrives', () => {
4341
- const campaignPayload = {
4342
- data: {
4343
- type: CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION,
4344
- interactionId: 'campaign-interaction-123',
4345
- agentId: taskDataMock.agentId,
4346
- orgId: taskDataMock.orgId,
4347
- trackingId: 'campaign-tracking-456',
4348
- interaction: {
4349
- mediaType: 'telephony',
4350
- callProcessingDetails: {
4351
- campaignId: 'campaign-789',
4352
- },
4353
- },
4354
- },
4355
- };
4356
-
4357
- // Remove the default task so only the campaign preview task is in the collection
4358
- delete taskManager['taskCollection'][taskId];
4359
-
4360
- // Create campaign preview task via the reservation event
4361
- webSocketManagerMock.emit('message', JSON.stringify(campaignPayload));
4362
-
4363
- const managerEmitSpy = jest.spyOn(taskManager, 'emit');
4364
-
4365
- // Simulate an incoming WebRTC call
4366
- const incomingCallCb = onSpy.mock.calls[0][1];
4367
- incomingCallCb(mockCall);
4368
-
4369
- // TASK_INCOMING should NOT be emitted because the only telephony task is a campaign preview
4370
- expect(managerEmitSpy).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_INCOMING, expect.anything());
4371
- });
4372
-
4373
- it('should update existing task when AgentOfferCampaignReservation is received for known interactionId', () => {
4374
- const campaignPayload = {
4375
- data: {
4376
- type: CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION,
4377
- interactionId: 'campaign-interaction-123',
4378
- agentId: taskDataMock.agentId,
4379
- orgId: taskDataMock.orgId,
4380
- trackingId: 'campaign-tracking-456',
4381
- interaction: {
4382
- mediaType: 'telephony',
4383
- callProcessingDetails: {
4384
- campaignId: 'campaign-789',
4385
- },
4386
- },
4387
- },
4388
- };
4389
-
4390
- // Send the first reservation to create the task
4391
- webSocketManagerMock.emit('message', JSON.stringify(campaignPayload));
4392
-
4393
- const managerEmitSpy = jest.spyOn(taskManager, 'emit');
4394
-
4395
- // Send a second reservation for the same interactionId
4396
- webSocketManagerMock.emit('message', JSON.stringify(campaignPayload));
4397
-
4398
- expect(managerEmitSpy).toHaveBeenCalledWith(
4399
- TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION,
4400
- expect.objectContaining({
4401
- data: expect.objectContaining({
4402
- interactionId: 'campaign-interaction-123',
4403
- }),
4404
- })
4405
- );
4406
- });
4407
-
4408
- it('should emit TASK_CAMPAIGN_CONTACT_UPDATED and NOT remove task when CampaignContactUpdated is received', () => {
4409
- const campaignInteractionId = 'campaign-interaction-123';
4410
-
4411
- // First create a campaign preview task
4412
- const reservationPayload = {
4413
- data: {
4414
- type: CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION,
4415
- interactionId: campaignInteractionId,
4416
- agentId: taskDataMock.agentId,
4417
- orgId: taskDataMock.orgId,
4418
- trackingId: 'campaign-tracking-456',
4419
- interaction: {
4420
- mediaType: 'telephony',
4421
- callProcessingDetails: {
4422
- campaignId: 'campaign-789',
4423
- },
4424
- },
4425
- },
4426
- };
4427
-
4428
- webSocketManagerMock.emit('message', JSON.stringify(reservationPayload));
4429
-
4430
- // Verify task exists in collection
4431
- const task = taskManager['taskCollection'][campaignInteractionId];
4432
- expect(task).toBeDefined();
4433
-
4434
- const taskEmitSpy = jest.spyOn(task, 'emit');
4435
-
4436
- // Now send CampaignContactUpdated
4437
- const campaignContactUpdatedPayload = {
4438
- data: {
4439
- type: CC_EVENTS.CAMPAIGN_CONTACT_UPDATED,
4440
- interactionId: campaignInteractionId,
4441
- agentId: taskDataMock.agentId,
4442
- orgId: taskDataMock.orgId,
4443
- interaction: {
4444
- mediaType: 'telephony',
4445
- state: 'new',
4446
- callProcessingDetails: {
4447
- campaignId: 'campaign-789',
4448
- },
4449
- },
4450
- },
4451
- };
4452
-
4453
- webSocketManagerMock.emit('message', JSON.stringify(campaignContactUpdatedPayload));
4454
-
4455
- // Task should still exist in collection (not removed — non-terminal event)
4456
- expect(taskManager['taskCollection'][campaignInteractionId]).toBeDefined();
4457
-
4458
- // TASK_CAMPAIGN_CONTACT_UPDATED should have been emitted
4459
- expect(taskEmitSpy).toHaveBeenCalledWith(
4460
- TASK_EVENTS.TASK_CAMPAIGN_CONTACT_UPDATED,
4461
- expect.objectContaining({
4462
- data: expect.objectContaining({
4463
- interactionId: campaignInteractionId,
4464
- }),
4465
- })
4466
- );
4467
-
4468
- // TASK_END should NOT have been emitted
4469
- expect(taskEmitSpy).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_END, expect.anything());
4470
- });
4471
-
4472
- it('should emit TASK_CAMPAIGN_PREVIEW_ACCEPT_FAILED when CampaignPreviewAcceptFailed is received', () => {
4473
- const campaignInteractionId = 'campaign-interaction-123';
4474
-
4475
- // First create a campaign preview task
4476
- const reservationPayload = {
4477
- data: {
4478
- type: CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION,
4479
- interactionId: campaignInteractionId,
4480
- agentId: taskDataMock.agentId,
4481
- orgId: taskDataMock.orgId,
4482
- trackingId: 'campaign-tracking-456',
4483
- interaction: {
4484
- mediaType: 'telephony',
4485
- callProcessingDetails: {
4486
- campaignId: 'campaign-789',
4487
- },
4488
- },
4489
- },
4490
- };
4491
-
4492
- webSocketManagerMock.emit('message', JSON.stringify(reservationPayload));
4493
-
4494
- const task = taskManager['taskCollection'][campaignInteractionId];
4495
- expect(task).toBeDefined();
4496
-
4497
- const taskEmitSpy = jest.spyOn(task, 'emit');
4498
-
4499
- const failPayload = {
4500
- data: {
4501
- type: CC_EVENTS.CAMPAIGN_PREVIEW_ACCEPT_FAILED,
4502
- interactionId: campaignInteractionId,
4503
- campaignId: 'campaign-789',
4504
- reason: 'INTERNAL_ERROR',
4505
- },
4506
- };
4507
-
4508
- webSocketManagerMock.emit('message', JSON.stringify(failPayload));
4509
-
4510
- expect(taskEmitSpy).toHaveBeenCalledWith(
4511
- TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_ACCEPT_FAILED,
4512
- expect.objectContaining({
4513
- data: expect.objectContaining({interactionId: campaignInteractionId}),
4514
- })
4515
- );
4516
- // Task should still exist (failure is non-terminal)
4517
- expect(taskManager['taskCollection'][campaignInteractionId]).toBeDefined();
4518
-
4519
- // Failure payload (reason, campaignId) should be merged into task.data
4520
- expect(task.data.reason).toBe('INTERNAL_ERROR');
4521
-
4522
- // Original reservation data must be preserved
4523
- expect(task.data.interaction).toBeDefined();
4524
- expect(task.data.interaction.callProcessingDetails.campaignId).toBe('campaign-789');
4525
- });
4526
-
4527
- it('should emit TASK_CAMPAIGN_PREVIEW_SKIP_FAILED when CampaignPreviewSkipFailed is received', () => {
4528
- const campaignInteractionId = 'campaign-interaction-123';
4529
-
4530
- const reservationPayload = {
4531
- data: {
4532
- type: CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION,
4533
- interactionId: campaignInteractionId,
4534
- agentId: taskDataMock.agentId,
4535
- orgId: taskDataMock.orgId,
4536
- trackingId: 'campaign-tracking-456',
4537
- interaction: {
4538
- mediaType: 'telephony',
4539
- callProcessingDetails: {
4540
- campaignId: 'campaign-789',
4541
- },
4542
- },
4543
- },
4544
- };
4545
-
4546
- webSocketManagerMock.emit('message', JSON.stringify(reservationPayload));
4547
-
4548
- const task = taskManager['taskCollection'][campaignInteractionId];
4549
- expect(task).toBeDefined();
4550
-
4551
- const taskEmitSpy = jest.spyOn(task, 'emit');
4552
-
4553
- const failPayload = {
4554
- data: {
4555
- type: CC_EVENTS.CAMPAIGN_PREVIEW_SKIP_FAILED,
4556
- interactionId: campaignInteractionId,
4557
- campaignId: 'campaign-789',
4558
- reason: 'INTERNAL_ERROR',
4559
- },
4560
- };
4561
-
4562
- webSocketManagerMock.emit('message', JSON.stringify(failPayload));
4563
-
4564
- expect(taskEmitSpy).toHaveBeenCalledWith(
4565
- TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_SKIP_FAILED,
4566
- expect.objectContaining({
4567
- data: expect.objectContaining({interactionId: campaignInteractionId}),
4568
- })
4569
- );
4570
- expect(taskManager['taskCollection'][campaignInteractionId]).toBeDefined();
4571
-
4572
- // Failure payload (reason) should be merged into task.data
4573
- expect(task.data.reason).toBe('INTERNAL_ERROR');
4574
-
4575
- // Original reservation data must be preserved
4576
- expect(task.data.interaction).toBeDefined();
4577
- expect(task.data.interaction.callProcessingDetails.campaignId).toBe('campaign-789');
4578
- });
4579
-
4580
- it('should emit TASK_CAMPAIGN_PREVIEW_REMOVE_FAILED when CampaignPreviewRemoveFailed is received', () => {
4581
- const campaignInteractionId = 'campaign-interaction-123';
4582
-
4583
- const reservationPayload = {
4584
- data: {
4585
- type: CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION,
4586
- interactionId: campaignInteractionId,
4587
- agentId: taskDataMock.agentId,
4588
- orgId: taskDataMock.orgId,
4589
- trackingId: 'campaign-tracking-456',
4590
- interaction: {
4591
- mediaType: 'telephony',
4592
- callProcessingDetails: {
4593
- campaignId: 'campaign-789',
4594
- },
4595
- },
4596
- },
4597
- };
4598
-
4599
- webSocketManagerMock.emit('message', JSON.stringify(reservationPayload));
4600
-
4601
- const task = taskManager['taskCollection'][campaignInteractionId];
4602
- expect(task).toBeDefined();
4603
-
4604
- const taskEmitSpy = jest.spyOn(task, 'emit');
4605
-
4606
- const failPayload = {
4607
- data: {
4608
- type: CC_EVENTS.CAMPAIGN_PREVIEW_REMOVE_FAILED,
4609
- interactionId: campaignInteractionId,
4610
- campaignId: 'campaign-789',
4611
- reason: 'INTERNAL_ERROR',
4612
- },
4613
- };
4614
-
4615
- webSocketManagerMock.emit('message', JSON.stringify(failPayload));
4616
-
4617
- expect(taskEmitSpy).toHaveBeenCalledWith(
4618
- TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_REMOVE_FAILED,
4619
- expect.objectContaining({
4620
- data: expect.objectContaining({interactionId: campaignInteractionId}),
4621
- })
4622
- );
4623
- expect(taskManager['taskCollection'][campaignInteractionId]).toBeDefined();
4624
-
4625
- // Failure payload (reason) should be merged into task.data
4626
- expect(task.data.reason).toBe('INTERNAL_ERROR');
4627
-
4628
- // Original reservation data must be preserved
4629
- expect(task.data.interaction).toBeDefined();
4630
- expect(task.data.interaction.callProcessingDetails.campaignId).toBe('campaign-789');
4631
- });
4632
-
4633
- it('should not emit campaign preview failure events when task does not exist', () => {
4634
- const nonExistentId = 'non-existent-interaction';
4635
-
4636
- const failPayload = {
4637
- data: {
4638
- type: CC_EVENTS.CAMPAIGN_PREVIEW_SKIP_FAILED,
4639
- interactionId: nonExistentId,
4640
- campaignId: 'campaign-789',
4641
- reason: 'INTERNAL_ERROR',
4642
- },
4643
- };
4644
-
4645
- // Should not throw when task is not found
4646
- expect(() => {
4647
- webSocketManagerMock.emit('message', JSON.stringify(failPayload));
4648
- }).not.toThrow();
4649
-
4650
- expect(taskManager['taskCollection'][nonExistentId]).toBeUndefined();
4651
- >>>>>>> 81672300901738f14289fd2a7414c6c4b1389aa6
4652
2479
  });
4653
2480
  });
4654
2481
  });