@webex/contact-center 0.0.0-next.1

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 (177) hide show
  1. package/README.md +81 -0
  2. package/__mocks__/workerMock.js +15 -0
  3. package/babel.config.js +15 -0
  4. package/dist/cc.js +1416 -0
  5. package/dist/cc.js.map +1 -0
  6. package/dist/config.js +72 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/constants.js +58 -0
  9. package/dist/constants.js.map +1 -0
  10. package/dist/index.js +142 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/logger-proxy.js +115 -0
  13. package/dist/logger-proxy.js.map +1 -0
  14. package/dist/metrics/MetricsManager.js +474 -0
  15. package/dist/metrics/MetricsManager.js.map +1 -0
  16. package/dist/metrics/behavioral-events.js +322 -0
  17. package/dist/metrics/behavioral-events.js.map +1 -0
  18. package/dist/metrics/constants.js +134 -0
  19. package/dist/metrics/constants.js.map +1 -0
  20. package/dist/services/WebCallingService.js +323 -0
  21. package/dist/services/WebCallingService.js.map +1 -0
  22. package/dist/services/agent/index.js +177 -0
  23. package/dist/services/agent/index.js.map +1 -0
  24. package/dist/services/agent/types.js +137 -0
  25. package/dist/services/agent/types.js.map +1 -0
  26. package/dist/services/config/Util.js +203 -0
  27. package/dist/services/config/Util.js.map +1 -0
  28. package/dist/services/config/constants.js +221 -0
  29. package/dist/services/config/constants.js.map +1 -0
  30. package/dist/services/config/index.js +607 -0
  31. package/dist/services/config/index.js.map +1 -0
  32. package/dist/services/config/types.js +334 -0
  33. package/dist/services/config/types.js.map +1 -0
  34. package/dist/services/constants.js +117 -0
  35. package/dist/services/constants.js.map +1 -0
  36. package/dist/services/core/Err.js +43 -0
  37. package/dist/services/core/Err.js.map +1 -0
  38. package/dist/services/core/GlobalTypes.js +6 -0
  39. package/dist/services/core/GlobalTypes.js.map +1 -0
  40. package/dist/services/core/Utils.js +126 -0
  41. package/dist/services/core/Utils.js.map +1 -0
  42. package/dist/services/core/WebexRequest.js +96 -0
  43. package/dist/services/core/WebexRequest.js.map +1 -0
  44. package/dist/services/core/aqm-reqs.js +246 -0
  45. package/dist/services/core/aqm-reqs.js.map +1 -0
  46. package/dist/services/core/constants.js +109 -0
  47. package/dist/services/core/constants.js.map +1 -0
  48. package/dist/services/core/types.js +6 -0
  49. package/dist/services/core/types.js.map +1 -0
  50. package/dist/services/core/websocket/WebSocketManager.js +187 -0
  51. package/dist/services/core/websocket/WebSocketManager.js.map +1 -0
  52. package/dist/services/core/websocket/connection-service.js +111 -0
  53. package/dist/services/core/websocket/connection-service.js.map +1 -0
  54. package/dist/services/core/websocket/keepalive.worker.js +94 -0
  55. package/dist/services/core/websocket/keepalive.worker.js.map +1 -0
  56. package/dist/services/core/websocket/types.js +6 -0
  57. package/dist/services/core/websocket/types.js.map +1 -0
  58. package/dist/services/index.js +78 -0
  59. package/dist/services/index.js.map +1 -0
  60. package/dist/services/task/AutoWrapup.js +88 -0
  61. package/dist/services/task/AutoWrapup.js.map +1 -0
  62. package/dist/services/task/TaskManager.js +369 -0
  63. package/dist/services/task/TaskManager.js.map +1 -0
  64. package/dist/services/task/constants.js +58 -0
  65. package/dist/services/task/constants.js.map +1 -0
  66. package/dist/services/task/contact.js +464 -0
  67. package/dist/services/task/contact.js.map +1 -0
  68. package/dist/services/task/dialer.js +60 -0
  69. package/dist/services/task/dialer.js.map +1 -0
  70. package/dist/services/task/index.js +1188 -0
  71. package/dist/services/task/index.js.map +1 -0
  72. package/dist/services/task/types.js +214 -0
  73. package/dist/services/task/types.js.map +1 -0
  74. package/dist/types/cc.d.ts +676 -0
  75. package/dist/types/config.d.ts +66 -0
  76. package/dist/types/constants.d.ts +45 -0
  77. package/dist/types/index.d.ts +178 -0
  78. package/dist/types/logger-proxy.d.ts +71 -0
  79. package/dist/types/metrics/MetricsManager.d.ts +223 -0
  80. package/dist/types/metrics/behavioral-events.d.ts +29 -0
  81. package/dist/types/metrics/constants.d.ts +127 -0
  82. package/dist/types/services/WebCallingService.d.ts +1 -0
  83. package/dist/types/services/agent/index.d.ts +46 -0
  84. package/dist/types/services/agent/types.d.ts +413 -0
  85. package/dist/types/services/config/Util.d.ts +19 -0
  86. package/dist/types/services/config/constants.d.ts +203 -0
  87. package/dist/types/services/config/index.d.ts +171 -0
  88. package/dist/types/services/config/types.d.ts +1113 -0
  89. package/dist/types/services/constants.d.ts +97 -0
  90. package/dist/types/services/core/Err.d.ts +119 -0
  91. package/dist/types/services/core/GlobalTypes.d.ts +33 -0
  92. package/dist/types/services/core/Utils.d.ts +36 -0
  93. package/dist/types/services/core/WebexRequest.d.ts +22 -0
  94. package/dist/types/services/core/aqm-reqs.d.ts +16 -0
  95. package/dist/types/services/core/constants.d.ts +85 -0
  96. package/dist/types/services/core/types.d.ts +47 -0
  97. package/dist/types/services/core/websocket/WebSocketManager.d.ts +34 -0
  98. package/dist/types/services/core/websocket/connection-service.d.ts +27 -0
  99. package/dist/types/services/core/websocket/keepalive.worker.d.ts +2 -0
  100. package/dist/types/services/core/websocket/types.d.ts +37 -0
  101. package/dist/types/services/index.d.ts +52 -0
  102. package/dist/types/services/task/AutoWrapup.d.ts +40 -0
  103. package/dist/types/services/task/TaskManager.d.ts +1 -0
  104. package/dist/types/services/task/constants.d.ts +46 -0
  105. package/dist/types/services/task/contact.d.ts +59 -0
  106. package/dist/types/services/task/dialer.d.ts +28 -0
  107. package/dist/types/services/task/index.d.ts +569 -0
  108. package/dist/types/services/task/types.d.ts +1041 -0
  109. package/dist/types/types.d.ts +452 -0
  110. package/dist/types/webex-config.d.ts +53 -0
  111. package/dist/types/webex.d.ts +7 -0
  112. package/dist/types.js +292 -0
  113. package/dist/types.js.map +1 -0
  114. package/dist/webex-config.js +60 -0
  115. package/dist/webex-config.js.map +1 -0
  116. package/dist/webex.js +99 -0
  117. package/dist/webex.js.map +1 -0
  118. package/jest.config.js +45 -0
  119. package/package.json +83 -0
  120. package/src/cc.ts +1618 -0
  121. package/src/config.ts +65 -0
  122. package/src/constants.ts +51 -0
  123. package/src/index.ts +220 -0
  124. package/src/logger-proxy.ts +110 -0
  125. package/src/metrics/MetricsManager.ts +512 -0
  126. package/src/metrics/behavioral-events.ts +332 -0
  127. package/src/metrics/constants.ts +135 -0
  128. package/src/services/WebCallingService.ts +351 -0
  129. package/src/services/agent/index.ts +149 -0
  130. package/src/services/agent/types.ts +440 -0
  131. package/src/services/config/Util.ts +261 -0
  132. package/src/services/config/constants.ts +249 -0
  133. package/src/services/config/index.ts +743 -0
  134. package/src/services/config/types.ts +1117 -0
  135. package/src/services/constants.ts +111 -0
  136. package/src/services/core/Err.ts +126 -0
  137. package/src/services/core/GlobalTypes.ts +34 -0
  138. package/src/services/core/Utils.ts +132 -0
  139. package/src/services/core/WebexRequest.ts +103 -0
  140. package/src/services/core/aqm-reqs.ts +272 -0
  141. package/src/services/core/constants.ts +106 -0
  142. package/src/services/core/types.ts +48 -0
  143. package/src/services/core/websocket/WebSocketManager.ts +196 -0
  144. package/src/services/core/websocket/connection-service.ts +142 -0
  145. package/src/services/core/websocket/keepalive.worker.js +88 -0
  146. package/src/services/core/websocket/types.ts +40 -0
  147. package/src/services/index.ts +71 -0
  148. package/src/services/task/AutoWrapup.ts +86 -0
  149. package/src/services/task/TaskManager.ts +420 -0
  150. package/src/services/task/constants.ts +52 -0
  151. package/src/services/task/contact.ts +429 -0
  152. package/src/services/task/dialer.ts +52 -0
  153. package/src/services/task/index.ts +1375 -0
  154. package/src/services/task/types.ts +1113 -0
  155. package/src/types.ts +639 -0
  156. package/src/webex-config.ts +54 -0
  157. package/src/webex.js +96 -0
  158. package/test/unit/spec/cc.ts +1985 -0
  159. package/test/unit/spec/metrics/MetricsManager.ts +491 -0
  160. package/test/unit/spec/metrics/behavioral-events.ts +102 -0
  161. package/test/unit/spec/services/WebCallingService.ts +416 -0
  162. package/test/unit/spec/services/agent/index.ts +65 -0
  163. package/test/unit/spec/services/config/index.ts +1035 -0
  164. package/test/unit/spec/services/core/Utils.ts +279 -0
  165. package/test/unit/spec/services/core/WebexRequest.ts +144 -0
  166. package/test/unit/spec/services/core/aqm-reqs.ts +570 -0
  167. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +378 -0
  168. package/test/unit/spec/services/core/websocket/connection-service.ts +178 -0
  169. package/test/unit/spec/services/task/TaskManager.ts +1351 -0
  170. package/test/unit/spec/services/task/contact.ts +204 -0
  171. package/test/unit/spec/services/task/dialer.ts +157 -0
  172. package/test/unit/spec/services/task/index.ts +1474 -0
  173. package/tsconfig.json +6 -0
  174. package/typedoc.json +37 -0
  175. package/typedoc.md +240 -0
  176. package/umd/contact-center.min.js +3 -0
  177. package/umd/contact-center.min.js.map +1 -0
@@ -0,0 +1,1351 @@
1
+ import 'jsdom-global/register';
2
+ import EventEmitter from 'events';
3
+ import {LoginOption, WebexSDK} from '../../../../../src/types';
4
+ import {CALL_EVENT_KEYS, CallingClientConfig, LINE_EVENTS} from '@webex/calling';
5
+ import {CC_AGENT_EVENTS, CC_EVENTS} from '../../../../../src/services/config/types';
6
+ import TaskManager from '../../../../../src/services/task/TaskManager';
7
+ import * as contact from '../../../../../src/services/task/contact';
8
+ import Task from '../../../../../src/services/task';
9
+ import {TASK_EVENTS} from '../../../../../src/services/task/types';
10
+ import WebCallingService from '../../../../../src/services/WebCallingService';
11
+ import config from '../../../../../src/config';
12
+ import {CC_TASK_EVENTS} from '../../../../../src/services/config/types';
13
+
14
+ describe('TaskManager', () => {
15
+ let mockCall;
16
+ let webSocketManagerMock;
17
+ let onSpy;
18
+ let offSpy;
19
+ let taskManager;
20
+ let contactMock;
21
+ let taskDataMock;
22
+ let webCallingService;
23
+ let webex: WebexSDK;
24
+ const taskId = '0ae913a4-c857-4705-8d49-76dd3dde75e4';
25
+
26
+ taskDataMock = {
27
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
28
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
29
+ eventTime: 1733211616959,
30
+ eventType: 'RoutingMessage',
31
+ interaction: {mediaType: 'telephony'},
32
+ interactionId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
33
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
34
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
35
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
36
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
37
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
38
+ queueMgr: 'aqm',
39
+ };
40
+
41
+ const initalPayload = {
42
+ data: taskDataMock,
43
+ };
44
+
45
+ beforeEach(() => {
46
+ contactMock = contact;
47
+ webSocketManagerMock = new EventEmitter();
48
+
49
+ webex = {
50
+ logger: {
51
+ log: jest.fn(),
52
+ error: jest.fn(),
53
+ info: jest.fn(),
54
+ },
55
+ } as unknown as WebexSDK;
56
+
57
+ webCallingService = new WebCallingService(
58
+ webex,
59
+ config.cc.callingClientConfig as CallingClientConfig
60
+ );
61
+
62
+ mockCall = {
63
+ on: jest.fn(),
64
+ off: jest.fn(),
65
+ answer: jest.fn(),
66
+ mute: jest.fn(),
67
+ isMuted: jest.fn().mockReturnValue(true),
68
+ end: jest.fn(),
69
+ getCallId: jest.fn().mockReturnValue('call-id-123'),
70
+ };
71
+
72
+ webCallingService.loginOption = LoginOption.BROWSER;
73
+ webCallingService.call = mockCall;
74
+ onSpy = jest.spyOn(webCallingService, 'on');
75
+ offSpy = jest.spyOn(webCallingService, 'off');
76
+
77
+ taskManager = new TaskManager(contactMock, webCallingService, webSocketManagerMock);
78
+ taskManager.taskCollection[taskId] = {
79
+ emit: jest.fn(),
80
+ accept: jest.fn(),
81
+ decline: jest.fn(),
82
+ updateTaskData: jest.fn(),
83
+ data: taskDataMock,
84
+ };
85
+ taskManager.call = mockCall;
86
+ });
87
+
88
+ afterEach(() => {
89
+ jest.clearAllMocks();
90
+ jest.resetAllMocks();
91
+ });
92
+
93
+ it('should initialize TaskManager and register listeners', () => {
94
+ webSocketManagerMock.emit('message', JSON.stringify({data: taskDataMock}));
95
+ const incomingCallCb = onSpy.mock.calls[0][1];
96
+ const taskEmitSpy = jest.spyOn(taskManager, 'emit');
97
+
98
+ expect(taskManager).toBeInstanceOf(TaskManager);
99
+ expect(webCallingService.listenerCount(LINE_EVENTS.INCOMING_CALL)).toBe(1);
100
+ expect(webSocketManagerMock.listenerCount('message')).toBe(1);
101
+ expect(onSpy).toHaveBeenCalledWith(LINE_EVENTS.INCOMING_CALL, incomingCallCb);
102
+
103
+ incomingCallCb(mockCall);
104
+
105
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_INCOMING, taskManager.getTask(taskId));
106
+ });
107
+
108
+ it('should re-emit task related events', () => {
109
+ const dummyPayload = {
110
+ data: {...taskDataMock,
111
+ type: CC_TASK_EVENTS.AGENT_CONSULTING,
112
+ },
113
+ };
114
+ webSocketManagerMock.emit('message', JSON.stringify({data: taskDataMock}));
115
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
116
+
117
+ expect(taskManager).toBeInstanceOf(TaskManager);
118
+ expect(webCallingService.listenerCount(LINE_EVENTS.INCOMING_CALL)).toBe(1);
119
+ expect(webSocketManagerMock.listenerCount('message')).toBe(1);
120
+
121
+ webSocketManagerMock.emit('message', JSON.stringify(dummyPayload));
122
+
123
+ expect(taskEmitSpy).toHaveBeenCalledWith(dummyPayload.data.type, dummyPayload.data);
124
+ });
125
+
126
+ it('should not re-emit agent related events', () => {
127
+ const dummyPayload = {
128
+ data: {
129
+ ...taskDataMock,
130
+ type: CC_AGENT_EVENTS.AGENT_BUDDY_AGENTS,
131
+ },
132
+ };
133
+ webSocketManagerMock.emit('message', JSON.stringify({data: taskDataMock}));
134
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
135
+ expect(taskManager).toBeInstanceOf(TaskManager);
136
+ expect(webCallingService.listenerCount(LINE_EVENTS.INCOMING_CALL)).toBe(1);
137
+ expect(webSocketManagerMock.listenerCount('message')).toBe(1);
138
+
139
+ webSocketManagerMock.emit('message', JSON.stringify(dummyPayload));
140
+
141
+ expect(taskEmitSpy).not.toHaveBeenCalledWith(dummyPayload.data.type, dummyPayload.data);
142
+ });
143
+
144
+ it('should handle WebSocket message for AGENT_CONTACT_RESERVED and emit task:incoming for browser case', () => {
145
+ const payload = {
146
+ data: {
147
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
148
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
149
+ eventTime: 1733211616959,
150
+ eventType: 'RoutingMessage',
151
+ interaction: {mediaType: 'telephony'},
152
+ interactionId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
153
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
154
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
155
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
156
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
157
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
158
+ queueMgr: 'aqm',
159
+ },
160
+ };
161
+
162
+ const taskIncomingSpy = jest.spyOn(taskManager, 'emit');
163
+
164
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
165
+
166
+ expect(taskIncomingSpy).toHaveBeenCalledWith(
167
+ TASK_EVENTS.TASK_INCOMING,
168
+ taskManager.getTask(payload.data.interactionId)
169
+ );
170
+ expect(taskManager.getTask(payload.data.interactionId)).toBe(taskManager.getTask(taskId));
171
+ expect(taskManager.getAllTasks()).toHaveProperty(payload.data.interactionId);
172
+
173
+ const assignedPayload = {
174
+ data: {
175
+ type: CC_EVENTS.AGENT_CONTACT_ASSIGNED,
176
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
177
+ eventTime: 1733211616959,
178
+ eventType: 'RoutingMessage',
179
+ interaction: {mediaType: 'telephony'},
180
+ interactionId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
181
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
182
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
183
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
184
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
185
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
186
+ queueMgr: 'aqm',
187
+ },
188
+ };
189
+
190
+ const currentTaskAssignedSpy = jest.spyOn(taskManager.getTask(payload.data.interactionId), 'emit');
191
+
192
+ webSocketManagerMock.emit('message', JSON.stringify(assignedPayload));
193
+
194
+ expect(currentTaskAssignedSpy).toHaveBeenCalledWith(
195
+ TASK_EVENTS.TASK_ASSIGNED,
196
+ taskManager.getTask(taskId)
197
+ );
198
+ });
199
+
200
+ it('should handle WebSocket message for AGENT_CONTACT_RESERVED and emit task:incoming for extension case', () => {
201
+ webCallingService.loginOption = LoginOption.EXTENSION;
202
+ const payload = {
203
+ data: {
204
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
205
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
206
+ eventTime: 1733211616959,
207
+ eventType: 'RoutingMessage',
208
+ interaction: {},
209
+ interactionId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
210
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
211
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
212
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
213
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
214
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
215
+ queueMgr: 'aqm',
216
+ },
217
+ };
218
+
219
+ const taskIncomingSpy = jest.spyOn(taskManager, 'emit');
220
+
221
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
222
+
223
+ expect(taskIncomingSpy).toHaveBeenCalledWith(
224
+ TASK_EVENTS.TASK_INCOMING,
225
+ taskManager.getTask(taskId)
226
+ );
227
+ expect(taskManager.getTask(payload.data.interactionId)).toBe(taskManager.getTask(taskId));
228
+ expect(taskManager.getAllTasks()).toHaveProperty(payload.data.interactionId);
229
+ });
230
+
231
+ it('should return task by ID', () => {
232
+ const taskId = 'task123';
233
+ const mockTask = {
234
+ accept: jest.fn(),
235
+ decline: jest.fn(),
236
+ updateTaskData: jest.fn(),
237
+ data: {
238
+ type: CC_EVENTS.AGENT_CONTACT_ASSIGNED,
239
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
240
+ eventTime: 1733211616959,
241
+ eventType: 'RoutingMessage',
242
+ interaction: {},
243
+ interactionId: taskId,
244
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
245
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
246
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
247
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
248
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
249
+ queueMgr: 'aqm',
250
+ },
251
+ };
252
+
253
+ taskManager.taskCollection[taskId] = mockTask;
254
+
255
+ expect(taskManager.getTask(taskId)).toBe(mockTask);
256
+ });
257
+
258
+ it('should return all tasks', () => {
259
+ const taskId1 = 'task123';
260
+ const taskId2 = 'task456';
261
+ const mockTask1 = {
262
+ accept: jest.fn(),
263
+ decline: jest.fn(),
264
+ updateTaskData: jest.fn(),
265
+ data: {
266
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
267
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
268
+ eventTime: 1733211616959,
269
+ eventType: 'RoutingMessage',
270
+ interaction: {},
271
+ interactionId: taskId1,
272
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
273
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
274
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
275
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
276
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
277
+ queueMgr: 'aqm',
278
+ },
279
+ };
280
+
281
+ const mockTask2 = {
282
+ accept: jest.fn(),
283
+ decline: jest.fn(),
284
+ updateTaskData: jest.fn(),
285
+ data: {
286
+ type: CC_EVENTS.AGENT_CONTACT_ASSIGNED,
287
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
288
+ eventTime: 1733211616959,
289
+ eventType: 'RoutingMessage',
290
+ interaction: {},
291
+ interactionId: taskId2,
292
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
293
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
294
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
295
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
296
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
297
+ queueMgr: 'aqm',
298
+ },
299
+ };
300
+
301
+ taskManager.taskCollection[taskId1] = mockTask1;
302
+ taskManager.taskCollection[taskId2] = mockTask2;
303
+
304
+ const allTasks = taskManager.getAllTasks();
305
+
306
+ expect(allTasks).toHaveProperty(taskId1, mockTask1);
307
+ expect(allTasks).toHaveProperty(taskId2, mockTask2);
308
+ });
309
+
310
+ it('test call listeners being switched off on call end', () => {
311
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
312
+
313
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
314
+ const webCallListenerSpy = jest.spyOn(taskManager.getTask(taskId), 'unregisterWebCallListeners');
315
+ const callOffSpy = jest.spyOn(mockCall, 'off');
316
+ const payload = {
317
+ data: {
318
+ type: CC_EVENTS.CONTACT_ENDED,
319
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
320
+ eventTime: 1733211616959,
321
+ eventType: 'RoutingMessage',
322
+ interaction: {state: 'new', mediaType: 'telephony'},
323
+ interactionId: taskId,
324
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
325
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
326
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
327
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
328
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
329
+ queueMgr: 'aqm',
330
+ },
331
+ };
332
+
333
+ taskManager.getTask(taskId).data = payload.data;
334
+ const task = taskManager.getTask(taskId)
335
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
336
+ expect(taskEmitSpy).toHaveBeenCalledWith(
337
+ TASK_EVENTS.TASK_END, task
338
+ );
339
+ expect(webCallListenerSpy).toHaveBeenCalledWith();
340
+ expect(callOffSpy).toHaveBeenCalledWith(
341
+ CALL_EVENT_KEYS.REMOTE_MEDIA,
342
+ callOffSpy.mock.calls[0][1]
343
+ );
344
+
345
+ taskManager.unregisterIncomingCallEvent();
346
+ expect(offSpy.mock.calls.length).toBe(2); // 1 for incoming call and 1 for remote media
347
+ expect(offSpy).toHaveBeenCalledWith(CALL_EVENT_KEYS.REMOTE_MEDIA, offSpy.mock.calls[0][1]);
348
+ expect(offSpy).toHaveBeenCalledWith(LINE_EVENTS.INCOMING_CALL, offSpy.mock.calls[1][1]);
349
+ });
350
+
351
+ it('should emit TASK_END event with wrapupRequired on regular call end', () => {
352
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
353
+
354
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
355
+ const payload = {
356
+ data: {
357
+ type: CC_EVENTS.CONTACT_ENDED,
358
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
359
+ eventTime: 1733211616959,
360
+ eventType: 'RoutingMessage',
361
+ interaction: {state: 'connected'},
362
+ interactionId: taskId,
363
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
364
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
365
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
366
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
367
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
368
+ queueMgr: 'aqm',
369
+ },
370
+ };
371
+
372
+ taskManager.getTask(taskId).updateTaskData(payload.data);
373
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
374
+ expect(taskEmitSpy).toHaveBeenCalledWith(
375
+ CC_EVENTS.CONTACT_ENDED,
376
+ { ...payload.data}
377
+ );
378
+ expect(taskEmitSpy).toHaveBeenCalledWith(
379
+ TASK_EVENTS.TASK_END,
380
+ taskManager.getTask(taskId)
381
+ );
382
+ });
383
+
384
+ it('should emit TASK_REJECT event on AGENT_INVITE_FAILED event', () => {
385
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
386
+
387
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
388
+ const metricsTrackSpy = jest.spyOn(taskManager.metricsManager, 'trackEvent');
389
+ const payload = {
390
+ data: {
391
+ type: CC_EVENTS.AGENT_INVITE_FAILED,
392
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
393
+ eventTime: 1733211616959,
394
+ eventType: 'RoutingMessage',
395
+ interaction: {state: 'connected'},
396
+ interactionId: taskId,
397
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
398
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
399
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
400
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
401
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
402
+ queueMgr: 'aqm',
403
+ reason: 'INVITE_FAILED',
404
+ },
405
+ };
406
+
407
+ taskManager.getTask(taskId).updateTaskData(payload.data);
408
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
409
+ expect(taskEmitSpy).toHaveBeenCalledWith(
410
+ CC_EVENTS.AGENT_INVITE_FAILED,
411
+ { ...payload.data}
412
+ );
413
+ expect(taskEmitSpy).toHaveBeenCalledWith(
414
+ TASK_EVENTS.TASK_REJECT,
415
+ payload.data.reason
416
+ );
417
+ // Verify the correct metric event name is used for AGENT_INVITE_FAILED
418
+ expect(metricsTrackSpy).toHaveBeenCalled();
419
+ expect(metricsTrackSpy.mock.calls[0][0]).toBe('Agent Invite Failed');
420
+ });
421
+
422
+
423
+ it('should not emit TASK_HYDRATE if task is already present in taskManager', () => {
424
+ const payload = {
425
+ data: {
426
+ ...initalPayload.data,
427
+ type: CC_EVENTS.AGENT_CONTACT,
428
+ },
429
+ };
430
+ const taskEmitSpy = jest.spyOn(taskManager, 'emit');
431
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
432
+
433
+ expect(taskEmitSpy).not.toHaveBeenCalledWith(
434
+ TASK_EVENTS.TASK_HYDRATE,
435
+ taskManager.getTask(taskId)
436
+ );
437
+ expect(taskManager.taskCollection[payload.data.interactionId]).toBe(
438
+ taskManager.getTask(taskId)
439
+ );
440
+ });
441
+
442
+ it('should emit TASK_INCOMING event on AGENT_CONTACT event if task is new and not in the taskManager ', () => {
443
+ taskManager.taskCollection = [];
444
+ const payload = {
445
+ data: {
446
+ ...initalPayload.data,
447
+ interaction: {mediaType: 'telephony', state: 'new'},
448
+ type: CC_EVENTS.AGENT_CONTACT,
449
+ },
450
+ };
451
+
452
+ const taskEmitSpy = jest.spyOn(taskManager, 'emit');
453
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
454
+
455
+ expect(taskEmitSpy).toHaveBeenCalledWith(
456
+ TASK_EVENTS.TASK_INCOMING,
457
+ taskManager.getTask(taskId)
458
+ );
459
+ expect(taskManager.taskCollection[payload.data.interactionId]).toBe(
460
+ taskManager.getTask(taskId)
461
+ );
462
+ });
463
+
464
+ it('should emit TASK_HYDRATE event on AGENT_CONTACT event if task is connected and not in the taskManager ', () => {
465
+ taskManager.taskCollection = [];
466
+ const payload = {
467
+ data: {
468
+ ...initalPayload.data,
469
+ type: CC_EVENTS.AGENT_CONTACT,
470
+ },
471
+ };
472
+
473
+ const taskEmitSpy = jest.spyOn(taskManager, 'emit');
474
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
475
+
476
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_HYDRATE, taskManager.getTask(taskId));
477
+ expect(taskManager.taskCollection[payload.data.interactionId]).toBe(
478
+ taskManager.getTask(taskId)
479
+ );
480
+ });
481
+
482
+ it('should emit TASK_END event on AGENT_WRAPUP event', () => {
483
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
484
+
485
+ const wrapupPayload = {
486
+ data: {
487
+ type: CC_EVENTS.AGENT_WRAPUP,
488
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
489
+ eventTime: 1733211616959,
490
+ eventType: 'RoutingMessage',
491
+ interaction: {},
492
+ interactionId: taskId,
493
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
494
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
495
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
496
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
497
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
498
+ queueMgr: 'aqm',
499
+ wrapUpRequired: true
500
+ },
501
+ };
502
+
503
+ const task = taskManager.getTask(taskId);
504
+ const updateTaskDataSpy = jest.spyOn(task, 'updateTaskData');
505
+ const taskEmitSpy = jest.spyOn(task, 'emit');
506
+
507
+ webSocketManagerMock.emit('message', JSON.stringify(wrapupPayload));
508
+
509
+ expect(updateTaskDataSpy).toHaveBeenCalledWith(wrapupPayload.data);
510
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, task);
511
+ });
512
+
513
+ it('should emit TASK_HOLD event on AGENT_CONTACT_HELD event', () => {
514
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
515
+
516
+ const payload = {
517
+ data: {
518
+ type: CC_EVENTS.AGENT_CONTACT_HELD,
519
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
520
+ eventTime: 1733211616959,
521
+ eventType: 'RoutingMessage',
522
+ interaction: {},
523
+ interactionId: taskId,
524
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
525
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
526
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
527
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
528
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
529
+ queueMgr: 'aqm',
530
+ },
531
+ };
532
+
533
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
534
+ const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
535
+
536
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
537
+
538
+ expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
539
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_HOLD, taskManager.getTask(taskId));
540
+ });
541
+
542
+ it('should emit TASK_RESUME event on AGENT_CONTACT_UNHELD event', () => {
543
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
544
+
545
+ const payload = {
546
+ data: {
547
+ type: CC_EVENTS.AGENT_CONTACT_UNHELD,
548
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
549
+ eventTime: 1733211616959,
550
+ eventType: 'RoutingMessage',
551
+ interaction: {},
552
+ interactionId: taskId,
553
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
554
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
555
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
556
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
557
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
558
+ queueMgr: 'aqm',
559
+ },
560
+ };
561
+
562
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
563
+ const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
564
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
565
+ expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
566
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_RESUME, taskManager.getTask(taskId));
567
+ });
568
+
569
+ it('handle AGENT_CONSULT_CREATED event', () => {
570
+ const payload = {
571
+ data: {
572
+ ...initalPayload.data,
573
+ type: CC_EVENTS.AGENT_CONSULT_CREATED,
574
+ },
575
+ };
576
+
577
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
578
+ const task = taskManager.getTask(taskId);
579
+ const taskUpdateTaskDataSpy = jest.spyOn(task, 'updateTaskData');
580
+ const taskEmitSpy = jest.spyOn(task, 'emit');
581
+
582
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
583
+
584
+ expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith({
585
+ ...payload.data,
586
+ isConsulted: false,
587
+ });
588
+ expect(task.data.isConsulted).toBe(false);
589
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONSULT_CREATED, task);
590
+ });
591
+
592
+ it('handle AGENT_OFFER_CONTACT event', () => {
593
+ const payload = {
594
+ data: {
595
+ ...initalPayload.data,
596
+ type: CC_EVENTS.AGENT_OFFER_CONTACT,
597
+ },
598
+ };
599
+
600
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
601
+
602
+ const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
603
+
604
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
605
+
606
+ expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
607
+ });
608
+
609
+ it('should remove currentTask from taskCollection on AGENT_OUTBOUND_FAILED event', () => {
610
+ const payload = {
611
+ data: {
612
+ type: CC_EVENTS.AGENT_OUTBOUND_FAILED,
613
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
614
+ eventTime: 1733211616959,
615
+ eventType: 'RoutingMessage',
616
+ interaction: {},
617
+ interactionId: taskId,
618
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
619
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
620
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
621
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
622
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
623
+ queueMgr: 'aqm',
624
+ },
625
+ };
626
+
627
+ taskManager.taskCollection[taskId] = taskManager.getTask(taskId);
628
+
629
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
630
+
631
+ expect(taskManager.getTask(taskId)).toBeUndefined();
632
+ });
633
+
634
+ it('handle AGENT_OFFER_CONSULT event', () => {
635
+ const payload = {
636
+ data: {
637
+ ...initalPayload.data,
638
+ type: CC_EVENTS.AGENT_OFFER_CONSULT,
639
+ },
640
+ };
641
+
642
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
643
+ const task = taskManager.getTask(taskId);
644
+ task.updateTaskData = jest.fn().mockImplementation((newData) => {
645
+ task.data = {...newData, isConsulted: true};
646
+ return task;
647
+ });
648
+ const taskEmitSpy = jest.spyOn(task, 'emit');
649
+
650
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
651
+
652
+ expect(task.updateTaskData).toHaveBeenCalledWith({
653
+ ...payload.data,
654
+ isConsulted: true,
655
+ });
656
+ expect(task.data.isConsulted).toBe(true);
657
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_OFFER_CONSULT, task);
658
+ });
659
+
660
+ it('should emit TASK_CONSULT_ACCEPTED event on AGENT_CONSULTING event', () => {
661
+ const consultingPayload = {
662
+ data: {
663
+ ...initalPayload.data,
664
+ type: CC_EVENTS.AGENT_CONSULTING,
665
+ },
666
+ };
667
+
668
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
669
+ taskManager.getTask(taskId).updateTaskData = jest.fn().mockImplementation((newData) => {
670
+ taskManager.getTask(taskId).data = {...newData, isConsulted: true};
671
+ return taskManager.getTask(taskId);
672
+ });
673
+
674
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
675
+ webSocketManagerMock.emit('message', JSON.stringify(consultingPayload));
676
+ expect(taskManager.getTask(taskId).updateTaskData).toHaveBeenCalledWith(consultingPayload.data);
677
+ expect(taskManager.getTask(taskId).data.isConsulted).toBe(true);
678
+ expect(taskEmitSpy).toHaveBeenCalledWith(
679
+ TASK_EVENTS.TASK_CONSULT_ACCEPTED,
680
+ taskManager.getTask(taskId)
681
+ );
682
+ });
683
+
684
+ it('should emit TASK_CONSULT_ENDED event on AGENT_CONSULT_ENDED event', () => {
685
+ const payload = {
686
+ data: {
687
+ ...initalPayload.data,
688
+ type: CC_EVENTS.AGENT_CONSULT_ENDED,
689
+ },
690
+ };
691
+
692
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
693
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
694
+ const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
695
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
696
+ expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
697
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONSULT_END, taskManager.getTask(taskId));
698
+ });
699
+
700
+ it('should emit TASK_CONSULT_ENDED event and remove currentTask when on AGENT_CONSULT_ENDED event when requested for a consult', () => {
701
+ const payload = {
702
+ data: {
703
+ ...initalPayload.data,
704
+ type: CC_EVENTS.AGENT_CONSULT_ENDED,
705
+ },
706
+ };
707
+
708
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
709
+
710
+ taskManager.getTask(taskId).updateTaskData = jest.fn().mockImplementation((newData) => {
711
+ taskManager.getTask(taskId).data = {...newData, isConsulted: true};
712
+ return taskManager.getTask(taskId);
713
+ });
714
+ const task = taskManager.getTask(taskId);
715
+
716
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
717
+ const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
718
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
719
+ expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
720
+ expect(taskEmitSpy).toHaveBeenCalledWith(CC_EVENTS.AGENT_CONSULT_ENDED, payload.data);
721
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONSULT_END, task);
722
+ expect(taskManager.getTask(taskId)).toBeUndefined(); // Ensure task is removed from the task collection after the consult ends
723
+ });
724
+
725
+ it('should emit TASK_CANCELLED event on AGENT_CTQ_CANCELLED event', () => {
726
+ const payload = {
727
+ data: {
728
+ ...initalPayload.data,
729
+ type: CC_EVENTS.AGENT_CTQ_CANCELLED,
730
+ },
731
+ };
732
+
733
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
734
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
735
+ const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
736
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
737
+ expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
738
+ expect(taskEmitSpy).toHaveBeenCalledWith(
739
+ TASK_EVENTS.TASK_CONSULT_QUEUE_CANCELLED,
740
+ taskManager.getTask(taskId)
741
+ );
742
+ });
743
+
744
+ it('should handle AGENT_CONSULT_FAILED event', () => {
745
+ const payload = {
746
+ data: {
747
+ ...initalPayload.data,
748
+ type: CC_EVENTS.AGENT_CONSULT_FAILED,
749
+ },
750
+ };
751
+
752
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
753
+
754
+ // Always spy on the updated task object after CONTACT_RESERVED is emitted
755
+ const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
756
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
757
+ expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
758
+ });
759
+
760
+ it('should emit TASK_CONSULT_QUEUE_FAILED on AGENT_CTQ_CANCEL_FAILED event', () => {
761
+ const payload = {
762
+ data: {
763
+ ...initalPayload.data,
764
+ type: CC_EVENTS.AGENT_CTQ_CANCEL_FAILED,
765
+ },
766
+ };
767
+
768
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
769
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
770
+ const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
771
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
772
+ expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith(payload.data);
773
+ expect(taskEmitSpy).toHaveBeenCalledWith(
774
+ TASK_EVENTS.TASK_CONSULT_QUEUE_FAILED,
775
+ taskManager.getTask(taskId)
776
+ );
777
+ });
778
+
779
+ it('should emit TASK_REJECT event on AGENT_CONTACT_OFFER_RONA event', () => {
780
+ // First, emit AGENT_CONTACT_RESERVED to set up currentTask
781
+ const reservedPayload = {
782
+ data: {
783
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
784
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
785
+ eventTime: 1733211616959,
786
+ eventType: 'RoutingMessage',
787
+ interaction: {},
788
+ interactionId: taskId,
789
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
790
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
791
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
792
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
793
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
794
+ queueMgr: 'aqm',
795
+ },
796
+ };
797
+
798
+ webSocketManagerMock.emit('message', JSON.stringify(reservedPayload));
799
+
800
+ const ronaPayload = {
801
+ data: {
802
+ type: CC_EVENTS.AGENT_CONTACT_OFFER_RONA,
803
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
804
+ eventTime: 1733211616959,
805
+ eventType: 'RoutingMessage',
806
+ interaction: {},
807
+ interactionId: taskId,
808
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
809
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
810
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
811
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
812
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
813
+ queueMgr: 'aqm',
814
+ reason: 'USER_REJECTED',
815
+ },
816
+ };
817
+
818
+ taskManager.taskCollection[taskId] = taskManager.getTask(taskId);
819
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
820
+ const metricsTrackSpy = jest.spyOn(taskManager.metricsManager, 'trackEvent');
821
+
822
+ webSocketManagerMock.emit('message', JSON.stringify(ronaPayload));
823
+
824
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_REJECT, ronaPayload.data.reason);
825
+ // Verify the correct metric event name is used for AGENT_CONTACT_OFFER_RONA
826
+ expect(metricsTrackSpy).toHaveBeenCalled();
827
+ expect(metricsTrackSpy.mock.calls[0][0]).toBe('Agent RONA');
828
+ });
829
+
830
+ it('should emit TASK_REJECT event on AGENT_CONTACT_ASSIGN_FAILED event', () => {
831
+ // First, emit AGENT_CONTACT_RESERVED to set up currentTask
832
+ const reservedPayload = {
833
+ data: {
834
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
835
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
836
+ eventTime: 1733211616959,
837
+ eventType: 'RoutingMessage',
838
+ interaction: {},
839
+ interactionId: taskId,
840
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
841
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
842
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
843
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
844
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
845
+ queueMgr: 'aqm',
846
+ },
847
+ };
848
+
849
+ webSocketManagerMock.emit('message', JSON.stringify(reservedPayload));
850
+
851
+ const assignFailedPayload = {
852
+ data: {
853
+ type: CC_EVENTS.AGENT_CONTACT_ASSIGN_FAILED,
854
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
855
+ eventTime: 1733211616959,
856
+ eventType: 'RoutingMessage',
857
+ interaction: {},
858
+ interactionId: taskId,
859
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
860
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
861
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
862
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
863
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
864
+ queueMgr: 'aqm',
865
+ reason: 'ASSIGN_FAILED',
866
+ },
867
+ };
868
+
869
+ taskManager.taskCollection[taskId] = taskManager.getTask(taskId);
870
+ const task = taskManager.getTask(taskId);
871
+ const taskEmitSpy = jest.spyOn(task, 'emit');
872
+ const taskUpdateDataSpy = jest.spyOn(task, 'updateTaskData');
873
+ const metricsTrackSpy = jest.spyOn(taskManager.metricsManager, 'trackEvent');
874
+
875
+ webSocketManagerMock.emit('message', JSON.stringify(assignFailedPayload));
876
+
877
+ expect(taskUpdateDataSpy).toHaveBeenCalledWith(assignFailedPayload.data);
878
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_REJECT, assignFailedPayload.data.reason);
879
+ // Verify the correct metric event name is used for AGENT_CONTACT_ASSIGN_FAILED
880
+ expect(metricsTrackSpy).toHaveBeenCalled();
881
+ expect(metricsTrackSpy.mock.calls[0][0]).toBe('Agent Contact Assign Failed');
882
+ });
883
+
884
+ it('should remove currentTask from taskCollection on AGENT_WRAPPEDUP event', () => {
885
+ const payload = {
886
+ data: {
887
+ type: CC_EVENTS.AGENT_WRAPPEDUP,
888
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
889
+ eventTime: 1733211616959,
890
+ eventType: 'RoutingMessage',
891
+ interaction: {},
892
+ interactionId: taskId,
893
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
894
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
895
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
896
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
897
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
898
+ queueMgr: 'aqm',
899
+ },
900
+ };
901
+
902
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
903
+ const task = taskManager.getTask(taskId);
904
+ const taskEmitSpy = jest.spyOn(task, 'emit');
905
+
906
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
907
+
908
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_WRAPPEDUP, task);
909
+ expect(taskManager.getTask(taskId)).toBeUndefined();
910
+ });
911
+
912
+ // case default
913
+ it('should handle default case', () => {
914
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
915
+
916
+ const payload = {
917
+ data: {
918
+ type: 'UNKNOWN_EVENT',
919
+ agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
920
+ eventTime: 1733211616959,
921
+ eventType: 'RoutingMessage',
922
+ interaction: {},
923
+ interactionId: taskId,
924
+ orgId: '6ecef209-9a34-4ed1-a07a-7ddd1dbe925a',
925
+ trackingId: '575c0ec2-618c-42af-a61c-53aeb0a221ee',
926
+ mediaResourceId: '0ae913a4-c857-4705-8d49-76dd3dde75e4',
927
+ destAgentId: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
928
+ owner: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
929
+ queueMgr: 'aqm',
930
+ },
931
+ };
932
+
933
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
934
+ const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
935
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
936
+ expect(taskEmitSpy).not.toHaveBeenCalled();
937
+ expect(taskUpdateTaskDataSpy).not.toHaveBeenCalled();
938
+ });
939
+
940
+ it('should emit TASK_CONSULTING event when agent is consulting', () => {
941
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
942
+ taskManager.getTask(taskId).data.isConsulted = false;
943
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
944
+ const consultingPayload = {
945
+ data: {
946
+ ...initalPayload.data,
947
+ type: CC_EVENTS.AGENT_CONSULTING,
948
+ isConsulted: false,
949
+ },
950
+ };
951
+ webSocketManagerMock.emit('message', JSON.stringify(consultingPayload));
952
+ expect(taskEmitSpy).toHaveBeenCalledWith(CC_EVENTS.AGENT_CONSULTING, consultingPayload.data);
953
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONSULTING, taskManager.getTask(taskId));
954
+ });
955
+
956
+ it('should emit TASK_END event on AGENT_CONTACT_UNASSIGNED', () => {
957
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
958
+ const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
959
+ const unassignedPayload = {
960
+ data: {
961
+ type: CC_EVENTS.AGENT_CONTACT_UNASSIGNED,
962
+ agentId: initalPayload.data.agentId,
963
+ eventTime: initalPayload.data.eventTime,
964
+ eventType: initalPayload.data.eventType,
965
+ interaction: {mediaType: 'telephony'},
966
+ interactionId: initalPayload.data.interactionId,
967
+ orgId: initalPayload.data.orgId,
968
+ trackingId: initalPayload.data.trackingId,
969
+ mediaResourceId: initalPayload.data.mediaResourceId,
970
+ destAgentId: initalPayload.data.destAgentId,
971
+ owner: initalPayload.data.owner,
972
+ queueMgr: initalPayload.data.queueMgr,
973
+ },
974
+ };
975
+ webSocketManagerMock.emit('message', JSON.stringify(unassignedPayload));
976
+ expect(taskEmitSpy).toHaveBeenCalledWith(CC_EVENTS.AGENT_CONTACT_UNASSIGNED, unassignedPayload.data);
977
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, taskManager.getTask(taskId));
978
+ });
979
+
980
+ it('should handle chat interaction and emit TASK_INCOMING immediately', () => {
981
+ // Setup chat payload with specific media type
982
+ const chatPayload = {
983
+ data: {
984
+ ...initalPayload.data,
985
+ interaction: { mediaType: 'chat' },
986
+ },
987
+ };
988
+
989
+ const taskIncomingSpy = jest.spyOn(taskManager, 'emit');
990
+
991
+ // Simulate receiving a chat task
992
+ webSocketManagerMock.emit('message', JSON.stringify(chatPayload));
993
+
994
+ // For non-telephony tasks, TASK_INCOMING should be emitted immediately
995
+ expect(taskIncomingSpy).toHaveBeenCalledWith(
996
+ TASK_EVENTS.TASK_INCOMING,
997
+ taskManager.getTask(chatPayload.data.interactionId)
998
+ );
999
+ expect(taskManager.getAllTasks()).toHaveProperty(chatPayload.data.interactionId);
1000
+ });
1001
+
1002
+ it('should handle email interaction and emit TASK_INCOMING immediately', () => {
1003
+ // Setup email payload
1004
+ const emailPayload = {
1005
+ data: {
1006
+ ...initalPayload.data,
1007
+ interaction: { mediaType: 'email' },
1008
+ },
1009
+ };
1010
+
1011
+ const taskIncomingSpy = jest.spyOn(taskManager, 'emit');
1012
+
1013
+ // Simulate receiving an email task
1014
+ webSocketManagerMock.emit('message', JSON.stringify(emailPayload));
1015
+
1016
+ // For non-telephony tasks, TASK_INCOMING should be emitted immediately
1017
+ expect(taskIncomingSpy).toHaveBeenCalledWith(
1018
+ TASK_EVENTS.TASK_INCOMING,
1019
+ taskManager.getTask(emailPayload.data.interactionId)
1020
+ );
1021
+ expect(taskManager.getAllTasks()).toHaveProperty(emailPayload.data.interactionId);
1022
+ });
1023
+
1024
+ it('should handle chat task lifecycle from reservation to assignment to end', () => {
1025
+ // 1. Chat task is reserved
1026
+ const chatReservedPayload = {
1027
+ data: {
1028
+ ...initalPayload.data,
1029
+ type: CC_EVENTS.AGENT_CONTACT_RESERVED,
1030
+ interaction: { mediaType: 'chat' },
1031
+ },
1032
+ };
1033
+
1034
+ const taskIncomingSpy = jest.spyOn(taskManager, 'emit');
1035
+ webSocketManagerMock.emit('message', JSON.stringify(chatReservedPayload));
1036
+
1037
+ expect(taskIncomingSpy).toHaveBeenCalledWith(
1038
+ TASK_EVENTS.TASK_INCOMING,
1039
+ taskManager.getTask(chatReservedPayload.data.interactionId)
1040
+ );
1041
+
1042
+ // 2. Chat task is assigned
1043
+ const chatAssignedPayload = {
1044
+ data: {
1045
+ ...chatReservedPayload.data,
1046
+ type: CC_EVENTS.AGENT_CONTACT_ASSIGNED,
1047
+ },
1048
+ };
1049
+
1050
+ const task = taskManager.getTask(chatReservedPayload.data.interactionId);
1051
+ const taskEmitSpy = jest.spyOn(task, 'emit');
1052
+
1053
+ webSocketManagerMock.emit('message', JSON.stringify(chatAssignedPayload));
1054
+
1055
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_ASSIGNED, task);
1056
+
1057
+ // 3. Chat task is ended with state 'new' to trigger cleanup
1058
+ const chatEndedPayload = {
1059
+ data: {
1060
+ ...chatReservedPayload.data,
1061
+ type: CC_EVENTS.CONTACT_ENDED,
1062
+ interaction: { mediaType: 'chat', state: 'new' }, // Change to 'new' state
1063
+ },
1064
+ };
1065
+
1066
+ webSocketManagerMock.emit('message', JSON.stringify(chatEndedPayload));
1067
+
1068
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, task);
1069
+ // Verify task is removed since it was in a 'new' state
1070
+ expect(taskManager.getTask(chatReservedPayload.data.interactionId)).toBeUndefined();
1071
+ });
1072
+
1073
+ it('should handle multiple tasks of different media types simultaneously', () => {
1074
+ // Setup telephony, chat and email payloads with different IDs
1075
+ const telephonyPayload = {
1076
+ data: {
1077
+ ...initalPayload.data,
1078
+ interactionId: 'telephony-task-id',
1079
+ interaction: { mediaType: 'telephony' },
1080
+ },
1081
+ };
1082
+
1083
+ const chatPayload = {
1084
+ data: {
1085
+ ...initalPayload.data,
1086
+ interactionId: 'chat-task-id',
1087
+ interaction: { mediaType: 'chat' },
1088
+ },
1089
+ };
1090
+
1091
+ const emailPayload = {
1092
+ data: {
1093
+ ...initalPayload.data,
1094
+ interactionId: 'email-task-id',
1095
+ interaction: { mediaType: 'email' },
1096
+ },
1097
+ };
1098
+
1099
+ // Simulate receiving tasks of different types
1100
+ webSocketManagerMock.emit('message', JSON.stringify(telephonyPayload));
1101
+ webSocketManagerMock.emit('message', JSON.stringify(chatPayload));
1102
+ webSocketManagerMock.emit('message', JSON.stringify(emailPayload));
1103
+
1104
+ // Verify all tasks are in the collection
1105
+ expect(taskManager.getAllTasks()).toHaveProperty(telephonyPayload.data.interactionId);
1106
+ expect(taskManager.getAllTasks()).toHaveProperty(chatPayload.data.interactionId);
1107
+ expect(taskManager.getAllTasks()).toHaveProperty(emailPayload.data.interactionId);
1108
+
1109
+ // Verify the task media types are correctly set
1110
+ expect(taskManager.getTask(telephonyPayload.data.interactionId).data.interaction.mediaType).toBe('telephony');
1111
+ expect(taskManager.getTask(chatPayload.data.interactionId).data.interaction.mediaType).toBe('chat');
1112
+ expect(taskManager.getTask(emailPayload.data.interactionId).data.interaction.mediaType).toBe('email');
1113
+ });
1114
+
1115
+ it('should properly handle one task ending when multiple tasks are active', () => {
1116
+ // Create three tasks with different IDs and media types
1117
+ const task1Payload = {
1118
+ data: {
1119
+ ...initalPayload.data,
1120
+ interactionId: 'task-id-1',
1121
+ interaction: { mediaType: 'telephony' },
1122
+ },
1123
+ };
1124
+
1125
+ const task2Payload = {
1126
+ data: {
1127
+ ...initalPayload.data,
1128
+ interactionId: 'task-id-2',
1129
+ interaction: { mediaType: 'chat' },
1130
+ },
1131
+ };
1132
+
1133
+ const task3Payload = {
1134
+ data: {
1135
+ ...initalPayload.data,
1136
+ interactionId: 'task-id-3',
1137
+ interaction: { mediaType: 'email' },
1138
+ },
1139
+ };
1140
+
1141
+ // Initialize all tasks
1142
+ webSocketManagerMock.emit('message', JSON.stringify(task1Payload));
1143
+ webSocketManagerMock.emit('message', JSON.stringify(task2Payload));
1144
+ webSocketManagerMock.emit('message', JSON.stringify(task3Payload));
1145
+
1146
+ // Verify all tasks are in the collection
1147
+ expect(taskManager.getAllTasks()).toHaveProperty(task1Payload.data.interactionId);
1148
+ expect(taskManager.getAllTasks()).toHaveProperty(task2Payload.data.interactionId);
1149
+ expect(taskManager.getAllTasks()).toHaveProperty(task3Payload.data.interactionId);
1150
+
1151
+ // Create spies for all tasks
1152
+ const task1EmitSpy = jest.spyOn(taskManager.getTask(task1Payload.data.interactionId), 'emit');
1153
+ const task2EmitSpy = jest.spyOn(taskManager.getTask(task2Payload.data.interactionId), 'emit');
1154
+ const task3EmitSpy = jest.spyOn(taskManager.getTask(task3Payload.data.interactionId), 'emit');
1155
+
1156
+ // Store reference to task2 before it gets removed
1157
+ const task2 = taskManager.getTask(task2Payload.data.interactionId);
1158
+
1159
+ // End only the second task (chat task)
1160
+ const chatEndedPayload = {
1161
+ data: {
1162
+ ...task2Payload.data,
1163
+ type: CC_EVENTS.CONTACT_ENDED,
1164
+ interaction: { mediaType: 'chat', state: 'new' }, // Using 'new' to trigger cleanup
1165
+ },
1166
+ };
1167
+
1168
+ webSocketManagerMock.emit('message', JSON.stringify(chatEndedPayload));
1169
+
1170
+ // Verify only task2 emitted TASK_END
1171
+ expect(task1EmitSpy).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_END);
1172
+ expect(task2EmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, task2);
1173
+ expect(task3EmitSpy).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_END);
1174
+
1175
+ // Verify task2 was removed from collection (since state was 'new')
1176
+ expect(taskManager.getTask(task2Payload.data.interactionId)).toBeUndefined();
1177
+
1178
+ // Verify other tasks remain in the collection
1179
+ expect(taskManager.getTask(task1Payload.data.interactionId)).toBeDefined();
1180
+ expect(taskManager.getTask(task3Payload.data.interactionId)).toBeDefined();
1181
+
1182
+ // Store reference to task3 before we end it
1183
+ const task3 = taskManager.getTask(task3Payload.data.interactionId);
1184
+
1185
+ // Now end task3 with a state that doesn't trigger cleanup
1186
+ const emailEndedPayload = {
1187
+ data: {
1188
+ ...task3Payload.data,
1189
+ type: CC_EVENTS.CONTACT_ENDED,
1190
+ interaction: { mediaType: 'email', state: 'connected' }, // Using 'connected' to NOT trigger cleanup
1191
+ },
1192
+ };
1193
+
1194
+ webSocketManagerMock.emit('message', JSON.stringify(emailEndedPayload));
1195
+
1196
+ // Verify task3 emitted TASK_END
1197
+ expect(task3EmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, task3);
1198
+
1199
+ // Verify task3 is still in collection (since state was 'connected')
1200
+ expect(taskManager.getTask(task3Payload.data.interactionId)).toBeDefined();
1201
+
1202
+ // Verify task1 remains unaffected
1203
+ expect(task1EmitSpy).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_END);
1204
+ expect(taskManager.getTask(task1Payload.data.interactionId)).toBeDefined();
1205
+ });
1206
+
1207
+ it('should emit TASK_END event on AGENT_VTEAM_TRANSFERRED event', () => {
1208
+ // First create a task by emitting the initial payload
1209
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1210
+
1211
+ // Get a reference to the task from taskCollection
1212
+ const task = taskManager.getTask(taskId);
1213
+
1214
+ // Now spy on the task's emit method
1215
+ const taskEmitSpy = jest.spyOn(task, 'emit');
1216
+
1217
+ const vteamTransferredPayload = {
1218
+ data: {
1219
+ type: CC_EVENTS.AGENT_VTEAM_TRANSFERRED,
1220
+ agentId: initalPayload.data.agentId,
1221
+ eventTime: initalPayload.data.eventTime,
1222
+ eventType: initalPayload.data.eventType,
1223
+ interaction: {},
1224
+ interactionId: initalPayload.data.interactionId,
1225
+ orgId: initalPayload.data.orgId,
1226
+ trackingId: initalPayload.data.trackingId,
1227
+ mediaResourceId: initalPayload.data.mediaResourceId,
1228
+ destAgentId: initalPayload.data.destAgentId,
1229
+ owner: initalPayload.data.owner,
1230
+ queueMgr: initalPayload.data.queueMgr,
1231
+ },
1232
+ };
1233
+
1234
+ // No need to explicitly set the task in the collection as it's already there
1235
+ // from the initial message processing
1236
+
1237
+ webSocketManagerMock.emit('message', JSON.stringify(vteamTransferredPayload));
1238
+
1239
+ // Check that task.emit was called with TASK_END event
1240
+ expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, task);
1241
+
1242
+ // The task should still exist in the collection based on current implementation
1243
+ expect(taskManager.getTask(taskId)).toBeDefined();
1244
+ });
1245
+
1246
+ it('should update task data on AGENT_WRAPUP event', () => {
1247
+ const payload = {
1248
+ data: {
1249
+ type: CC_EVENTS.AGENT_WRAPUP,
1250
+ interactionId: taskId,
1251
+ wrapUpRequired: true,
1252
+ },
1253
+ };
1254
+ const task = taskManager.getTask(taskId);
1255
+ const updateSpy = jest.spyOn(task, 'updateTaskData').mockImplementation((data) => {
1256
+ task.data = { ...(task.data || {}), ...(data || {}) };
1257
+ return task;
1258
+ });
1259
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1260
+ expect(updateSpy).toHaveBeenCalledWith(payload.data);
1261
+ });
1262
+
1263
+ it('should not attempt cleanup twice when AGENT_CONTACT_UNASSIGNED is followed by AGENT_WRAPUP', () => {
1264
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1265
+ const task = taskManager.getTask(taskId);
1266
+ const unregisterSpy = jest.spyOn(task, 'unregisterWebCallListeners');
1267
+ const cleanUpCallSpy = jest.spyOn(webCallingService, 'cleanUpCall');
1268
+ const unassignedPayload = {
1269
+ data: {
1270
+ type: CC_EVENTS.AGENT_CONTACT_UNASSIGNED,
1271
+ agentId: initalPayload.data.agentId,
1272
+ interaction: { mediaType: 'telephony' },
1273
+ interactionId: initalPayload.data.interactionId,
1274
+ orgId: initalPayload.data.orgId,
1275
+ trackingId: initalPayload.data.trackingId,
1276
+ mediaResourceId: initalPayload.data.mediaResourceId,
1277
+ destAgentId: initalPayload.data.destAgentId,
1278
+ owner: initalPayload.data.owner,
1279
+ queueMgr: initalPayload.data.queueMgr,
1280
+ },
1281
+ };
1282
+ webSocketManagerMock.emit('message', JSON.stringify(unassignedPayload));
1283
+ expect(unregisterSpy).not.toHaveBeenCalled();
1284
+ expect(cleanUpCallSpy).not.toHaveBeenCalled();
1285
+ unregisterSpy.mockClear();
1286
+ cleanUpCallSpy.mockClear();
1287
+ const wrapupPayload = {
1288
+ data: {
1289
+ type: CC_EVENTS.AGENT_WRAPUP,
1290
+ interactionId: taskId,
1291
+ interaction: { mediaType: 'telephony' },
1292
+ },
1293
+ };
1294
+ webSocketManagerMock.emit('message', JSON.stringify(wrapupPayload));
1295
+ expect(unregisterSpy).not.toHaveBeenCalled();
1296
+ expect(cleanUpCallSpy).not.toHaveBeenCalled();
1297
+ });
1298
+
1299
+ it('should not attempt cleanup when AGENT_VTEAM_TRANSFERRED is followed by AGENT_WRAPUP', () => {
1300
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1301
+ const task = taskManager.getTask(taskId);
1302
+ const unregisterSpy = jest.spyOn(task, 'unregisterWebCallListeners');
1303
+ const cleanUpCallSpy = jest.spyOn(webCallingService, 'cleanUpCall');
1304
+ const transferredPayload = {
1305
+ data: {
1306
+ type: CC_EVENTS.AGENT_VTEAM_TRANSFERRED,
1307
+ agentId: initalPayload.data.agentId,
1308
+ interaction: { mediaType: 'telephony' },
1309
+ interactionId: initalPayload.data.interactionId,
1310
+ orgId: initalPayload.data.orgId,
1311
+ trackingId: initalPayload.data.trackingId,
1312
+ mediaResourceId: initalPayload.data.mediaResourceId,
1313
+ destAgentId: initalPayload.data.destAgentId,
1314
+ owner: initalPayload.data.owner,
1315
+ queueMgr: initalPayload.data.queueMgr,
1316
+ },
1317
+ };
1318
+ webSocketManagerMock.emit('message', JSON.stringify(transferredPayload));
1319
+ expect(unregisterSpy).not.toHaveBeenCalled();
1320
+ expect(cleanUpCallSpy).not.toHaveBeenCalled();
1321
+ unregisterSpy.mockClear();
1322
+ cleanUpCallSpy.mockClear();
1323
+ const wrapupPayload = {
1324
+ data: {
1325
+ type: CC_EVENTS.AGENT_WRAPUP,
1326
+ interactionId: taskId,
1327
+ interaction: { mediaType: 'telephony' },
1328
+ },
1329
+ };
1330
+ webSocketManagerMock.emit('message', JSON.stringify(wrapupPayload));
1331
+ expect(unregisterSpy).not.toHaveBeenCalled();
1332
+ expect(cleanUpCallSpy).not.toHaveBeenCalled();
1333
+ });
1334
+
1335
+ describe('should emit appropriate task events for recording events', () => {
1336
+ ['PAUSED', 'PAUSE_FAILED', 'RESUMED', 'RESUME_FAILED'].forEach((suffix) => {
1337
+ const ccEvent = CC_EVENTS[`CONTACT_RECORDING_${suffix}`];
1338
+ const taskEvent = TASK_EVENTS[`TASK_RECORDING_${suffix}`];
1339
+ it(`should emit ${taskEvent} on ${ccEvent} event`, () => {
1340
+ const payload = {data: {...initalPayload.data, type: ccEvent}};
1341
+ webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
1342
+ const task = taskManager.getTask(taskId);
1343
+ const spy = jest.spyOn(task, 'emit');
1344
+
1345
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1346
+ expect(spy).toHaveBeenCalledWith(taskEvent, task);
1347
+ });
1348
+ });
1349
+ });
1350
+ });
1351
+