@webex/contact-center 3.9.0-next.9 → 3.10.0

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.
Files changed (95) hide show
  1. package/dist/cc.js +182 -47
  2. package/dist/cc.js.map +1 -1
  3. package/dist/constants.js +1 -0
  4. package/dist/constants.js.map +1 -1
  5. package/dist/index.js +9 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/logger-proxy.js +24 -1
  8. package/dist/logger-proxy.js.map +1 -1
  9. package/dist/metrics/behavioral-events.js +89 -0
  10. package/dist/metrics/behavioral-events.js.map +1 -1
  11. package/dist/metrics/constants.js +30 -2
  12. package/dist/metrics/constants.js.map +1 -1
  13. package/dist/services/AddressBook.js +271 -0
  14. package/dist/services/AddressBook.js.map +1 -0
  15. package/dist/services/EntryPoint.js +227 -0
  16. package/dist/services/EntryPoint.js.map +1 -0
  17. package/dist/services/Queue.js +261 -0
  18. package/dist/services/Queue.js.map +1 -0
  19. package/dist/services/config/constants.js +36 -2
  20. package/dist/services/config/constants.js.map +1 -1
  21. package/dist/services/config/index.js +29 -21
  22. package/dist/services/config/index.js.map +1 -1
  23. package/dist/services/config/types.js +33 -1
  24. package/dist/services/config/types.js.map +1 -1
  25. package/dist/services/core/Utils.js +42 -1
  26. package/dist/services/core/Utils.js.map +1 -1
  27. package/dist/services/task/TaskManager.js +113 -3
  28. package/dist/services/task/TaskManager.js.map +1 -1
  29. package/dist/services/task/TaskUtils.js +76 -0
  30. package/dist/services/task/TaskUtils.js.map +1 -0
  31. package/dist/services/task/constants.js +26 -1
  32. package/dist/services/task/constants.js.map +1 -1
  33. package/dist/services/task/contact.js +86 -0
  34. package/dist/services/task/contact.js.map +1 -1
  35. package/dist/services/task/index.js +241 -5
  36. package/dist/services/task/index.js.map +1 -1
  37. package/dist/services/task/types.js +14 -0
  38. package/dist/services/task/types.js.map +1 -1
  39. package/dist/types/cc.d.ts +115 -35
  40. package/dist/types/constants.d.ts +1 -0
  41. package/dist/types/index.d.ts +3 -2
  42. package/dist/types/metrics/constants.d.ts +24 -1
  43. package/dist/types/services/AddressBook.d.ts +74 -0
  44. package/dist/types/services/EntryPoint.d.ts +67 -0
  45. package/dist/types/services/Queue.d.ts +76 -0
  46. package/dist/types/services/config/constants.d.ts +35 -1
  47. package/dist/types/services/config/index.d.ts +6 -9
  48. package/dist/types/services/config/types.d.ts +79 -58
  49. package/dist/types/services/core/Utils.d.ts +14 -1
  50. package/dist/types/services/task/TaskUtils.d.ts +28 -0
  51. package/dist/types/services/task/constants.d.ts +23 -0
  52. package/dist/types/services/task/contact.d.ts +10 -0
  53. package/dist/types/services/task/index.d.ts +64 -1
  54. package/dist/types/services/task/types.d.ts +221 -19
  55. package/dist/types/types.d.ts +162 -0
  56. package/dist/types/utils/PageCache.d.ts +173 -0
  57. package/dist/types.js +17 -0
  58. package/dist/types.js.map +1 -1
  59. package/dist/utils/PageCache.js +192 -0
  60. package/dist/utils/PageCache.js.map +1 -0
  61. package/dist/webex.js +1 -1
  62. package/package.json +10 -9
  63. package/src/cc.ts +206 -52
  64. package/src/constants.ts +1 -0
  65. package/src/index.ts +16 -2
  66. package/src/logger-proxy.ts +24 -1
  67. package/src/metrics/behavioral-events.ts +94 -0
  68. package/src/metrics/constants.ts +34 -1
  69. package/src/services/AddressBook.ts +291 -0
  70. package/src/services/EntryPoint.ts +241 -0
  71. package/src/services/Queue.ts +277 -0
  72. package/src/services/config/constants.ts +42 -2
  73. package/src/services/config/index.ts +30 -30
  74. package/src/services/config/types.ts +59 -58
  75. package/src/services/core/Utils.ts +44 -0
  76. package/src/services/task/TaskManager.ts +122 -5
  77. package/src/services/task/TaskUtils.ts +81 -0
  78. package/src/services/task/constants.ts +25 -0
  79. package/src/services/task/contact.ts +80 -0
  80. package/src/services/task/index.ts +300 -4
  81. package/src/services/task/types.ts +239 -18
  82. package/src/types.ts +180 -0
  83. package/src/utils/PageCache.ts +252 -0
  84. package/test/unit/spec/cc.ts +282 -85
  85. package/test/unit/spec/metrics/behavioral-events.ts +42 -0
  86. package/test/unit/spec/services/AddressBook.ts +332 -0
  87. package/test/unit/spec/services/EntryPoint.ts +259 -0
  88. package/test/unit/spec/services/Queue.ts +323 -0
  89. package/test/unit/spec/services/config/index.ts +279 -65
  90. package/test/unit/spec/services/task/TaskManager.ts +382 -0
  91. package/test/unit/spec/services/task/TaskUtils.ts +131 -0
  92. package/test/unit/spec/services/task/contact.ts +31 -1
  93. package/test/unit/spec/services/task/index.ts +242 -8
  94. package/umd/contact-center.min.js +2 -2
  95. package/umd/contact-center.min.js.map +1 -1
@@ -1353,6 +1353,388 @@ describe('TaskManager', () => {
1353
1353
  expect(spy).toHaveBeenCalledWith(taskEvent, task);
1354
1354
  });
1355
1355
  });
1356
+ });
1357
+
1358
+ describe('Conference event handling', () => {
1359
+ let task;
1360
+ const agentId = '723a8ffb-a26e-496d-b14a-ff44fb83b64f';
1361
+
1362
+ beforeEach(() => {
1363
+ // Set the agentId on taskManager before tests run
1364
+ taskManager.setAgentId(agentId);
1365
+
1366
+ task = {
1367
+ data: { interactionId: taskId },
1368
+ emit: jest.fn(),
1369
+ updateTaskData: jest.fn().mockImplementation((updatedData) => {
1370
+ // Mock the updateTaskData method to actually update task.data
1371
+ task.data = { ...task.data, ...updatedData };
1372
+ return task;
1373
+ }),
1374
+ };
1375
+ taskManager.taskCollection[taskId] = task;
1376
+ });
1377
+
1378
+ it('should handle AGENT_CONSULT_CONFERENCED event', () => {
1379
+ const payload = {
1380
+ data: {
1381
+ type: CC_EVENTS.AGENT_CONSULT_CONFERENCED,
1382
+ interactionId: taskId,
1383
+ isConferencing: true,
1384
+ },
1385
+ };
1386
+
1387
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1388
+
1389
+ expect(task.data.isConferencing).toBe(true);
1390
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
1391
+ });
1392
+
1393
+ it('should handle AGENT_CONSULT_CONFERENCING event', () => {
1394
+ const payload = {
1395
+ data: {
1396
+ type: CC_EVENTS.AGENT_CONSULT_CONFERENCING,
1397
+ interactionId: taskId,
1398
+ isConferencing: true,
1399
+ },
1400
+ };
1401
+
1402
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1403
+
1404
+ expect(task.data.isConferencing).toBe(true);
1405
+ // No task event emission for conferencing - only for conferenced (completed)
1406
+ expect(task.emit).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
1407
+ });
1408
+
1409
+ it('should handle AGENT_CONSULT_CONFERENCE_FAILED event', () => {
1410
+ const payload = {
1411
+ data: {
1412
+ type: CC_EVENTS.AGENT_CONSULT_CONFERENCE_FAILED,
1413
+ interactionId: taskId,
1414
+ reason: 'Network error',
1415
+ },
1416
+ };
1417
+
1418
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1419
+
1420
+ expect(task.data.reason).toBe('Network error');
1421
+ // No event emission expected for failure - handled by contact method promise rejection
1422
+ });
1423
+
1424
+ it('should handle PARTICIPANT_JOINED_CONFERENCE event', () => {
1425
+ const payload = {
1426
+ data: {
1427
+ type: CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE,
1428
+ interactionId: taskId,
1429
+ participantId: 'new-participant-123',
1430
+ participantType: 'agent',
1431
+ },
1432
+ };
1433
+
1434
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1435
+
1436
+ expect(task.data.participantId).toBe('new-participant-123');
1437
+ expect(task.data.participantType).toBe('agent');
1438
+ // No specific task event emission for participant joined - just data update
1439
+ });
1440
+
1441
+ describe('PARTICIPANT_LEFT_CONFERENCE event handling', () => {
1442
+ it('should emit TASK_PARTICIPANT_LEFT event when participant leaves conference', () => {
1443
+ const payload = {
1444
+ data: {
1445
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1446
+ interactionId: taskId,
1447
+ interaction: {
1448
+ participants: {
1449
+ [agentId]: {
1450
+ hasLeft: false,
1451
+ },
1452
+ },
1453
+ },
1454
+ },
1455
+ };
1456
+
1457
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1458
+
1459
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1460
+ });
1461
+
1462
+ it('should NOT remove task when agent is still in interaction', () => {
1463
+ const payload = {
1464
+ data: {
1465
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1466
+ interactionId: taskId,
1467
+ interaction: {
1468
+ participants: {
1469
+ [agentId]: {
1470
+ hasLeft: false,
1471
+ },
1472
+ },
1473
+ },
1474
+ },
1475
+ };
1476
+
1477
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1478
+
1479
+ // Task should still exist in collection
1480
+ expect(taskManager.getTask(taskId)).toBeDefined();
1481
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1482
+ });
1483
+
1484
+ it('should NOT remove task when agent left but is in main interaction', () => {
1485
+ const payload = {
1486
+ data: {
1487
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1488
+ interactionId: taskId,
1489
+ interaction: {
1490
+ participants: {
1491
+ [agentId]: {
1492
+ hasLeft: true,
1493
+ },
1494
+ },
1495
+ media: {
1496
+ [taskId]: {
1497
+ mType: 'mainCall',
1498
+ participants: [agentId],
1499
+ },
1500
+ },
1501
+ },
1502
+ },
1503
+ };
1504
+
1505
+ const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
1506
+
1507
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1508
+
1509
+ // Task should still exist - not removed
1510
+ expect(removeTaskSpy).not.toHaveBeenCalled();
1511
+ expect(taskManager.getTask(taskId)).toBeDefined();
1512
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1513
+ });
1514
+
1515
+ it('should NOT remove task when agent left but is primary (owner)', () => {
1516
+ const payload = {
1517
+ data: {
1518
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1519
+ interactionId: taskId,
1520
+ interaction: {
1521
+ participants: {
1522
+ [agentId]: {
1523
+ hasLeft: true,
1524
+ },
1525
+ },
1526
+ owner: agentId,
1527
+ media: {
1528
+ [taskId]: {
1529
+ mType: 'consultCall',
1530
+ participants: ['other-agent'],
1531
+ },
1532
+ },
1533
+ },
1534
+ },
1535
+ };
1536
+
1537
+ const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
1538
+
1539
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1540
+
1541
+ // Task should still exist - not removed because agent is primary
1542
+ expect(removeTaskSpy).not.toHaveBeenCalled();
1543
+ expect(taskManager.getTask(taskId)).toBeDefined();
1544
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1545
+ });
1546
+
1547
+ it('should remove task when agent left and is NOT in main interaction and is NOT primary', () => {
1548
+ const payload = {
1549
+ data: {
1550
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1551
+ interactionId: taskId,
1552
+ interaction: {
1553
+ participants: {
1554
+ [agentId]: {
1555
+ hasLeft: true,
1556
+ },
1557
+ },
1558
+ owner: 'another-agent-id',
1559
+ media: {
1560
+ [taskId]: {
1561
+ mType: 'mainCall',
1562
+ participants: ['another-agent-id'],
1563
+ },
1564
+ },
1565
+ },
1566
+ },
1567
+ };
1568
+
1569
+ const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
1570
+
1571
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1572
+
1573
+ // Task should be removed
1574
+ expect(removeTaskSpy).toHaveBeenCalled();
1575
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1576
+ });
1577
+
1578
+ it('should remove task when agent is not in participants list', () => {
1579
+ const payload = {
1580
+ data: {
1581
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1582
+ interactionId: taskId,
1583
+ interaction: {
1584
+ participants: {
1585
+ 'other-agent-id': {
1586
+ hasLeft: false,
1587
+ },
1588
+ },
1589
+ owner: 'another-agent-id',
1590
+ },
1591
+ },
1592
+ };
1593
+
1594
+ const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
1595
+
1596
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1597
+
1598
+ // Task should be removed because agent is not in participants
1599
+ expect(removeTaskSpy).toHaveBeenCalled();
1600
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1601
+ });
1602
+
1603
+ it('should update isConferenceInProgress based on remaining active agents', () => {
1604
+ const payload = {
1605
+ data: {
1606
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1607
+ interactionId: taskId,
1608
+ interaction: {
1609
+ participants: {
1610
+ [agentId]: {
1611
+ hasLeft: false,
1612
+ pType: 'Agent',
1613
+ },
1614
+ 'agent-2': {
1615
+ hasLeft: false,
1616
+ pType: 'Agent',
1617
+ },
1618
+ 'customer-1': {
1619
+ hasLeft: false,
1620
+ pType: 'Customer',
1621
+ },
1622
+ },
1623
+ media: {
1624
+ [taskId]: {
1625
+ mType: 'mainCall',
1626
+ participants: [agentId, 'agent-2', 'customer-1'],
1627
+ },
1628
+ },
1629
+ },
1630
+ },
1631
+ };
1632
+
1633
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1634
+
1635
+ // isConferenceInProgress should be true (2 active agents)
1636
+ expect(task.data.isConferenceInProgress).toBe(true);
1637
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1638
+ });
1639
+
1640
+ it('should set isConferenceInProgress to false when only one agent remains', () => {
1641
+ const payload = {
1642
+ data: {
1643
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1644
+ interactionId: taskId,
1645
+ interaction: {
1646
+ participants: {
1647
+ [agentId]: {
1648
+ hasLeft: false,
1649
+ pType: 'Agent',
1650
+ },
1651
+ 'agent-2': {
1652
+ hasLeft: true,
1653
+ pType: 'Agent',
1654
+ },
1655
+ 'customer-1': {
1656
+ hasLeft: false,
1657
+ pType: 'Customer',
1658
+ },
1659
+ },
1660
+ media: {
1661
+ [taskId]: {
1662
+ mType: 'mainCall',
1663
+ participants: [agentId, 'customer-1'],
1664
+ },
1665
+ },
1666
+ },
1667
+ },
1668
+ };
1669
+
1670
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1671
+
1672
+ // isConferenceInProgress should be false (only 1 active agent)
1673
+ expect(task.data.isConferenceInProgress).toBe(false);
1674
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1675
+ });
1676
+
1677
+ it('should handle participant left when no participants data exists', () => {
1678
+ const payload = {
1679
+ data: {
1680
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1681
+ interactionId: taskId,
1682
+ interaction: {},
1683
+ },
1684
+ };
1685
+
1686
+ const removeTaskSpy = jest.spyOn(taskManager, 'removeTaskFromCollection');
1687
+
1688
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1689
+
1690
+ // When no participants data exists, checkParticipantNotInInteraction returns true
1691
+ // Since agent won't be in main interaction either, task should be removed
1692
+ expect(removeTaskSpy).toHaveBeenCalled();
1693
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1694
+ });
1695
+ });
1696
+
1697
+ it('should handle PARTICIPANT_LEFT_CONFERENCE_FAILED event', () => {
1698
+ const payload = {
1699
+ data: {
1700
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE_FAILED,
1701
+ interactionId: taskId,
1702
+ reason: 'Exit failed',
1703
+ },
1704
+ };
1705
+
1706
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1707
+
1708
+ expect(task.data.reason).toBe('Exit failed');
1709
+ // No event emission expected for failure - handled by contact method promise rejection
1710
+ });
1711
+
1712
+ it('should only update task for matching interactionId', () => {
1713
+ const otherTaskId = 'other-task-id';
1714
+ const otherTask = {
1715
+ data: { interactionId: otherTaskId },
1716
+ emit: jest.fn(),
1717
+ };
1718
+ taskManager.taskCollection[otherTaskId] = otherTask;
1719
+
1720
+ const payload = {
1721
+ data: {
1722
+ type: CC_EVENTS.AGENT_CONSULT_CONFERENCED,
1723
+ interactionId: taskId,
1724
+ isConferencing: true,
1725
+ },
1726
+ };
1727
+
1728
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1729
+
1730
+ // Only the matching task should be updated
1731
+ expect(task.data.isConferencing).toBe(true);
1732
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
1733
+
1734
+ // Other task should not be affected
1735
+ expect(otherTask.data.isConferencing).toBeUndefined();
1736
+ expect(otherTask.emit).not.toHaveBeenCalled();
1737
+ });
1356
1738
  });
1357
1739
  });
1358
1740
 
@@ -0,0 +1,131 @@
1
+ import { checkParticipantNotInInteraction,
2
+ getIsConferenceInProgress,
3
+ isParticipantInMainInteraction,
4
+ isPrimary,} from '../../../../../src/services/task/TaskUtils';
5
+ import {ITask} from '../../../../../src/services/task/types';
6
+
7
+ describe('TaskUtils', () => {
8
+ let mockTask: ITask;
9
+ const mockAgentId = 'agent-123';
10
+ const mockOtherAgentId = 'agent-456';
11
+
12
+ beforeEach(() => {
13
+ mockTask = {
14
+ data: {
15
+ interactionId: 'interaction-123',
16
+ agentId: mockAgentId,
17
+ interaction: {
18
+ owner: mockAgentId,
19
+ participants: {
20
+ [mockAgentId]: { hasLeft: false },
21
+ [mockOtherAgentId]: { hasLeft: false },
22
+ },
23
+ media: {
24
+ 'media-1': {
25
+ mType: 'mainCall',
26
+ participants: [mockAgentId, mockOtherAgentId],
27
+ },
28
+ },
29
+ },
30
+ },
31
+ emit: jest.fn(),
32
+ updateTaskData: jest.fn(),
33
+ } as any;
34
+ });
35
+
36
+ describe('isPrimary', () => {
37
+ it('should return true when agent is the owner', () => {
38
+ expect(isPrimary(mockTask, mockAgentId)).toBe(true);
39
+ });
40
+
41
+ it('should return false when agent is not the owner', () => {
42
+ expect(isPrimary(mockTask, mockOtherAgentId)).toBe(false);
43
+ });
44
+
45
+ it('should fallback to data.agentId when owner is not set', () => {
46
+ mockTask.data.interaction.owner = undefined;
47
+ expect(isPrimary(mockTask, mockAgentId)).toBe(true);
48
+ expect(isPrimary(mockTask, mockOtherAgentId)).toBe(false);
49
+ });
50
+ });
51
+
52
+ describe('isParticipantInMainInteraction', () => {
53
+ it('should return true when agent is in mainCall media', () => {
54
+ expect(isParticipantInMainInteraction(mockTask, mockAgentId)).toBe(true);
55
+ });
56
+
57
+ it('should return false when agent is not in mainCall media', () => {
58
+ mockTask.data.interaction.media['media-1'].participants = [mockOtherAgentId];
59
+ expect(isParticipantInMainInteraction(mockTask, mockAgentId)).toBe(false);
60
+ });
61
+
62
+ it('should return false when no mainCall media exists', () => {
63
+ mockTask.data.interaction.media['media-1'].mType = 'consult';
64
+ expect(isParticipantInMainInteraction(mockTask, mockAgentId)).toBe(false);
65
+ });
66
+ });
67
+
68
+ describe('checkParticipantNotInInteraction', () => {
69
+ it('should return false when agent is active participant', () => {
70
+ expect(checkParticipantNotInInteraction(mockTask, mockAgentId)).toBe(false);
71
+ });
72
+
73
+ it('should return true when agent is not in participants', () => {
74
+ delete mockTask.data.interaction.participants[mockAgentId];
75
+ expect(checkParticipantNotInInteraction(mockTask, mockAgentId)).toBe(true);
76
+ });
77
+
78
+ it('should return true when agent has left', () => {
79
+ mockTask.data.interaction.participants[mockAgentId].hasLeft = true;
80
+ expect(checkParticipantNotInInteraction(mockTask, mockAgentId)).toBe(true);
81
+ });
82
+ });
83
+
84
+ describe('getIsConferenceInProgress', () => {
85
+ beforeEach(() => {
86
+ // Set up mock task with proper media structure for conference detection
87
+ mockTask.data.interaction.media = {
88
+ [mockTask.data.interactionId]: {
89
+ mType: 'mainCall',
90
+ participants: [mockAgentId, mockOtherAgentId, 'customer-123'],
91
+ },
92
+ };
93
+ mockTask.data.interaction.participants = {
94
+ [mockAgentId]: { pType: 'Agent', hasLeft: false },
95
+ [mockOtherAgentId]: { pType: 'Agent', hasLeft: false },
96
+ 'customer-123': { pType: 'Customer', hasLeft: false },
97
+ };
98
+ });
99
+
100
+ it('should return true when there are 2 or more active agents', () => {
101
+ expect(getIsConferenceInProgress(mockTask)).toBe(true);
102
+ });
103
+
104
+ it('should return false when there is only 1 active agent', () => {
105
+ mockTask.data.interaction.participants[mockOtherAgentId].hasLeft = true;
106
+ expect(getIsConferenceInProgress(mockTask)).toBe(false);
107
+ });
108
+
109
+ it('should exclude customers from agent count', () => {
110
+ // Remove one agent, should still be false with only 1 agent + customer
111
+ delete mockTask.data.interaction.participants[mockOtherAgentId];
112
+ mockTask.data.interaction.media[mockTask.data.interactionId].participants = [mockAgentId, 'customer-123'];
113
+ expect(getIsConferenceInProgress(mockTask)).toBe(false);
114
+ });
115
+
116
+ it('should exclude supervisors from agent count', () => {
117
+ mockTask.data.interaction.participants[mockOtherAgentId].pType = 'Supervisor';
118
+ expect(getIsConferenceInProgress(mockTask)).toBe(false);
119
+ });
120
+
121
+ it('should exclude VVA from agent count', () => {
122
+ mockTask.data.interaction.participants[mockOtherAgentId].pType = 'VVA';
123
+ expect(getIsConferenceInProgress(mockTask)).toBe(false);
124
+ });
125
+
126
+ it('should return false when no main call media exists', () => {
127
+ mockTask.data.interaction.media = {};
128
+ expect(getIsConferenceInProgress(mockTask)).toBe(false);
129
+ });
130
+ });
131
+ });
@@ -197,7 +197,37 @@ describe("Routing contacts", () => {
197
197
  const req = contact.wrapup({
198
198
  interactionId: "interactionId",
199
199
  data: { wrapUpReason: "testWrapUpReason", auxCodeId: "auxCodeID1234", isAutoWrapup: "on" }
200
- } as any);
200
+ } as any);
201
+ expect(req).toBeDefined();
202
+ });
203
+
204
+ it("consultConference", () => {
205
+ fakeAqm.pendingRequests = {};
206
+ const consultData = {
207
+ agentId: "current-agent-id",
208
+ to: "destination-agent-id",
209
+ destinationType: "agent"
210
+ };
211
+ const req = contact.consultConference({
212
+ interactionId: "test-interaction-123",
213
+ data: consultData
214
+ });
215
+ expect(req).toBeDefined();
216
+ });
217
+
218
+ it("exitConference", () => {
219
+ fakeAqm.pendingRequests = {};
220
+ const req = contact.exitConference({
221
+ interactionId: "test-interaction-456"
222
+ });
223
+ expect(req).toBeDefined();
224
+ });
225
+
226
+ it("conferenceTransfer", () => {
227
+ fakeAqm.pendingRequests = {};
228
+ const req = contact.conferenceTransfer({
229
+ interactionId: "test-interaction-transfer-123"
230
+ });
201
231
  expect(req).toBeDefined();
202
232
  });
203
233
  });