@webex/contact-center 3.12.0-next.9 → 3.12.0-next.91

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 (229) hide show
  1. package/.sdd/manifest.json +876 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +46 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +48 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +341 -0
  17. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  18. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  19. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  20. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  21. package/ai-docs/patterns/testing-patterns.md +480 -0
  22. package/ai-docs/patterns/typescript-patterns.md +365 -0
  23. package/ai-docs/templates/README.md +102 -0
  24. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  25. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  26. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  27. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  28. package/ai-docs/templates/new-method/00-master.md +80 -0
  29. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  30. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  31. package/ai-docs/templates/new-method/03-tests.md +201 -0
  32. package/ai-docs/templates/new-method/04-validation.md +141 -0
  33. package/ai-docs/templates/new-service/00-master.md +109 -0
  34. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  35. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  36. package/ai-docs/templates/new-service/03-integration.md +178 -0
  37. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  38. package/ai-docs/templates/new-service/05-validation.md +145 -0
  39. package/dist/cc.js +265 -29
  40. package/dist/cc.js.map +1 -1
  41. package/dist/config.js +6 -0
  42. package/dist/config.js.map +1 -1
  43. package/dist/constants.js +17 -1
  44. package/dist/constants.js.map +1 -1
  45. package/dist/index.js +20 -5
  46. package/dist/index.js.map +1 -1
  47. package/dist/metrics/behavioral-events.js +101 -0
  48. package/dist/metrics/behavioral-events.js.map +1 -1
  49. package/dist/metrics/constants.js +25 -4
  50. package/dist/metrics/constants.js.map +1 -1
  51. package/dist/services/ApiAiAssistant.js +153 -8
  52. package/dist/services/ApiAiAssistant.js.map +1 -1
  53. package/dist/services/UserPreference.js +427 -0
  54. package/dist/services/UserPreference.js.map +1 -0
  55. package/dist/services/config/Util.js +3 -3
  56. package/dist/services/config/Util.js.map +1 -1
  57. package/dist/services/config/constants.js +23 -2
  58. package/dist/services/config/constants.js.map +1 -1
  59. package/dist/services/config/types.js +49 -9
  60. package/dist/services/config/types.js.map +1 -1
  61. package/dist/services/core/Err.js.map +1 -1
  62. package/dist/services/core/Utils.js +107 -32
  63. package/dist/services/core/Utils.js.map +1 -1
  64. package/dist/services/core/websocket/WebSocketManager.js +2 -1
  65. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  66. package/dist/services/core/websocket/types.js.map +1 -1
  67. package/dist/services/index.js +1 -1
  68. package/dist/services/index.js.map +1 -1
  69. package/dist/services/task/Task.js +688 -0
  70. package/dist/services/task/Task.js.map +1 -0
  71. package/dist/services/task/TaskFactory.js +45 -0
  72. package/dist/services/task/TaskFactory.js.map +1 -0
  73. package/dist/services/task/TaskManager.js +728 -527
  74. package/dist/services/task/TaskManager.js.map +1 -1
  75. package/dist/services/task/TaskUtils.js +162 -26
  76. package/dist/services/task/TaskUtils.js.map +1 -1
  77. package/dist/services/task/constants.js +9 -2
  78. package/dist/services/task/constants.js.map +1 -1
  79. package/dist/services/task/dialer.js +78 -0
  80. package/dist/services/task/dialer.js.map +1 -1
  81. package/dist/services/task/digital/Digital.js +77 -0
  82. package/dist/services/task/digital/Digital.js.map +1 -0
  83. package/dist/services/task/state-machine/TaskStateMachine.js +837 -0
  84. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  85. package/dist/services/task/state-machine/actions.js +543 -0
  86. package/dist/services/task/state-machine/actions.js.map +1 -0
  87. package/dist/services/task/state-machine/constants.js +161 -0
  88. package/dist/services/task/state-machine/constants.js.map +1 -0
  89. package/dist/services/task/state-machine/guards.js +340 -0
  90. package/dist/services/task/state-machine/guards.js.map +1 -0
  91. package/dist/services/task/state-machine/index.js +53 -0
  92. package/dist/services/task/state-machine/index.js.map +1 -0
  93. package/dist/services/task/state-machine/types.js +54 -0
  94. package/dist/services/task/state-machine/types.js.map +1 -0
  95. package/dist/services/task/state-machine/uiControlsComputer.js +553 -0
  96. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  97. package/dist/services/task/taskDataNormalizer.js +99 -0
  98. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  99. package/dist/services/task/types.js +212 -4
  100. package/dist/services/task/types.js.map +1 -1
  101. package/dist/services/task/voice/Voice.js +1042 -0
  102. package/dist/services/task/voice/Voice.js.map +1 -0
  103. package/dist/services/task/voice/WebRTC.js +149 -0
  104. package/dist/services/task/voice/WebRTC.js.map +1 -0
  105. package/dist/types/cc.d.ts +94 -1
  106. package/dist/types/config.d.ts +6 -0
  107. package/dist/types/constants.d.ts +17 -1
  108. package/dist/types/index.d.ts +21 -6
  109. package/dist/types/metrics/constants.d.ts +21 -1
  110. package/dist/types/services/ApiAiAssistant.d.ts +22 -4
  111. package/dist/types/services/UserPreference.d.ts +118 -0
  112. package/dist/types/services/config/constants.d.ts +21 -0
  113. package/dist/types/services/config/types.d.ts +171 -10
  114. package/dist/types/services/core/Err.d.ts +4 -0
  115. package/dist/types/services/core/Utils.d.ts +33 -13
  116. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  117. package/dist/types/services/core/websocket/types.d.ts +1 -1
  118. package/dist/types/services/index.d.ts +1 -1
  119. package/dist/types/services/task/Task.d.ts +157 -0
  120. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  121. package/dist/types/services/task/TaskUtils.d.ts +46 -2
  122. package/dist/types/services/task/constants.d.ts +7 -0
  123. package/dist/types/services/task/dialer.d.ts +30 -0
  124. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  125. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1144 -0
  126. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  127. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  128. package/dist/types/services/task/state-machine/guards.d.ts +90 -0
  129. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  130. package/dist/types/services/task/state-machine/types.d.ts +267 -0
  131. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  132. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  133. package/dist/types/services/task/types.d.ts +603 -66
  134. package/dist/types/services/task/voice/Voice.d.ts +184 -0
  135. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  136. package/dist/types/types.d.ts +135 -0
  137. package/dist/types/webex.d.ts +1 -0
  138. package/dist/types.js +118 -2
  139. package/dist/types.js.map +1 -1
  140. package/dist/webex.js +14 -2
  141. package/dist/webex.js.map +1 -1
  142. package/package.json +15 -12
  143. package/src/cc.ts +329 -30
  144. package/src/config.ts +6 -0
  145. package/src/constants.ts +17 -1
  146. package/src/index.ts +23 -5
  147. package/src/metrics/ai-docs/AGENTS.md +350 -0
  148. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  149. package/src/metrics/ai-docs/metrics-spec.md +854 -0
  150. package/src/metrics/behavioral-events.ts +106 -0
  151. package/src/metrics/constants.ts +27 -4
  152. package/src/services/ApiAiAssistant.ts +203 -8
  153. package/src/services/UserPreference.ts +509 -0
  154. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  155. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  156. package/src/services/agent/ai-docs/agent-spec.md +504 -0
  157. package/src/services/ai-docs/AGENTS.md +386 -0
  158. package/src/services/ai-docs/services-spec.md +492 -0
  159. package/src/services/config/Util.ts +3 -3
  160. package/src/services/config/ai-docs/AGENTS.md +255 -0
  161. package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
  162. package/src/services/config/ai-docs/config-spec.md +669 -0
  163. package/src/services/config/constants.ts +25 -1
  164. package/src/services/config/types.ts +174 -11
  165. package/src/services/core/Err.ts +2 -0
  166. package/src/services/core/Utils.ts +123 -37
  167. package/src/services/core/ai-docs/AGENTS.md +381 -0
  168. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  169. package/src/services/core/ai-docs/core-spec.md +783 -0
  170. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  171. package/src/services/core/websocket/types.ts +1 -1
  172. package/src/services/index.ts +1 -1
  173. package/src/services/task/Task.ts +837 -0
  174. package/src/services/task/TaskFactory.ts +55 -0
  175. package/src/services/task/TaskManager.ts +739 -614
  176. package/src/services/task/TaskUtils.ts +205 -25
  177. package/src/services/task/ai-docs/AGENTS.md +457 -0
  178. package/src/services/task/ai-docs/ARCHITECTURE.md +594 -0
  179. package/src/services/task/ai-docs/task-spec.md +1319 -0
  180. package/src/services/task/constants.ts +7 -0
  181. package/src/services/task/dialer.ts +80 -0
  182. package/src/services/task/digital/Digital.ts +95 -0
  183. package/src/services/task/state-machine/TaskStateMachine.ts +1077 -0
  184. package/src/services/task/state-machine/actions.ts +685 -0
  185. package/src/services/task/state-machine/ai-docs/AGENTS.md +458 -0
  186. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1137 -0
  187. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2115 -0
  188. package/src/services/task/state-machine/constants.ts +172 -0
  189. package/src/services/task/state-machine/guards.ts +406 -0
  190. package/src/services/task/state-machine/index.ts +28 -0
  191. package/src/services/task/state-machine/types.ts +241 -0
  192. package/src/services/task/state-machine/uiControlsComputer.ts +867 -0
  193. package/src/services/task/taskDataNormalizer.ts +137 -0
  194. package/src/services/task/types.ts +710 -71
  195. package/src/services/task/voice/Voice.ts +1267 -0
  196. package/src/services/task/voice/WebRTC.ts +187 -0
  197. package/src/types.ts +166 -2
  198. package/src/utils/AGENTS.md +278 -0
  199. package/src/utils/ai-docs/utils-spec.md +381 -0
  200. package/src/webex.js +2 -0
  201. package/test/unit/spec/cc.ts +343 -23
  202. package/test/unit/spec/logger-proxy.ts +70 -0
  203. package/test/unit/spec/services/ApiAiAssistant.ts +178 -20
  204. package/test/unit/spec/services/UserPreference.ts +401 -0
  205. package/test/unit/spec/services/WebCallingService.ts +7 -1
  206. package/test/unit/spec/services/config/index.ts +30 -30
  207. package/test/unit/spec/services/core/Utils.ts +425 -8
  208. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  209. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  210. package/test/unit/spec/services/task/Task.ts +477 -0
  211. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  212. package/test/unit/spec/services/task/TaskManager.ts +834 -1704
  213. package/test/unit/spec/services/task/TaskUtils.ts +206 -0
  214. package/test/unit/spec/services/task/dialer.ts +190 -0
  215. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  216. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +1825 -0
  217. package/test/unit/spec/services/task/state-machine/guards.ts +479 -0
  218. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  219. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2020 -0
  220. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  221. package/test/unit/spec/services/task/voice/Voice.ts +631 -0
  222. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  223. package/umd/contact-center.min.js +2 -2
  224. package/umd/contact-center.min.js.map +1 -1
  225. package/dist/services/task/index.js +0 -1525
  226. package/dist/services/task/index.js.map +0 -1
  227. package/dist/types/services/task/index.d.ts +0 -650
  228. package/src/services/task/index.ts +0 -1801
  229. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -1,7 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import {WebSocketManager} from '../../../../../../src/services/core/websocket/WebSocketManager';
3
3
  import {WebexSDK, SubscribeRequest} from '../../../../../../src/types';
4
- import {SUBSCRIBE_API, WCC_API_GATEWAY} from '../../../../../../src/services/constants';
4
+ import {
5
+ RTD_SUBSCRIBE_API,
6
+ SUBSCRIBE_API,
7
+ WCC_API_GATEWAY,
8
+ } from '../../../../../../src/services/constants';
5
9
  import {WEB_SOCKET_MANAGER_FILE} from '../../../../../../src/constants';
6
10
  import LoggerProxy from '../../../../../../src/logger-proxy';
7
11
 
@@ -18,10 +22,10 @@ jest.mock('../../../../../../src/logger-proxy', () => ({
18
22
 
19
23
  class MockWebSocket {
20
24
  static inst: MockWebSocket;
21
- onopen: () => void = () => { };
22
- onerror: (event: any) => void = () => { };
23
- onclose: (event: any) => void = () => { };
24
- onmessage: (msg: any) => void = () => { };
25
+ onopen: () => void = () => {};
26
+ onerror: (event: any) => void = () => {};
27
+ onclose: (event: any) => void = () => {};
28
+ onmessage: (msg: any) => void = () => {};
25
29
  close = jest.fn();
26
30
  send = jest.fn();
27
31
 
@@ -37,7 +41,7 @@ class MockWebSocket {
37
41
  class MockCustomEvent<T> extends Event {
38
42
  detail: T;
39
43
 
40
- constructor(event: string, params: { detail: T }) {
44
+ constructor(event: string, params: {detail: T}) {
41
45
  super(event);
42
46
  this.detail = params.detail;
43
47
  }
@@ -49,7 +53,7 @@ global.CustomEvent = MockCustomEvent as any;
49
53
  class MockMessageEvent extends Event {
50
54
  data: any;
51
55
 
52
- constructor(type: string, eventInitDict: { data: any }) {
56
+ constructor(type: string, eventInitDict: {data: any}) {
53
57
  super(type);
54
58
  this.data = eventInitDict.data;
55
59
  }
@@ -93,18 +97,18 @@ describe('WebSocketManager', () => {
93
97
  global.WebSocket = MockWebSocket as any;
94
98
 
95
99
  global.Blob = function (content: any[], options: any) {
96
- return { content, options };
100
+ return {content, options};
97
101
  } as any;
98
102
 
99
103
  global.URL.createObjectURL = function (blob: Blob) {
100
104
  return 'blob:http://localhost:3000/12345';
101
105
  };
102
106
 
103
- webSocketManager = new WebSocketManager({ webex: mockWebex });
107
+ webSocketManager = new WebSocketManager({webex: mockWebex});
104
108
 
105
109
  setTimeout(() => {
106
110
  MockWebSocket.inst.onopen();
107
- MockWebSocket.inst.onmessage({ data: JSON.stringify({ type: "Welcome" }) });
111
+ MockWebSocket.inst.onmessage({data: JSON.stringify({type: 'Welcome'})});
108
112
  }, 1);
109
113
 
110
114
  console.log = jest.fn();
@@ -126,7 +130,7 @@ describe('WebSocketManager', () => {
126
130
  (mockWebex.internal.services.isIntegrationEnvironment as jest.Mock).mockReturnValue(true);
127
131
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
128
132
 
129
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
133
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
130
134
 
131
135
  expect(mockWebex.request).toHaveBeenCalledWith({
132
136
  service: WCC_API_GATEWAY,
@@ -137,13 +141,35 @@ describe('WebSocketManager', () => {
137
141
  });
138
142
  });
139
143
 
140
- it('should register and connect to WebSocket without X-ORGANIZATION-ID header for production environment', async () => {
144
+ it('should connect rtd websocket', async () => {
141
145
  const subscribeResponse = {
142
146
  body: {
143
147
  webSocketUrl: 'wss://fake-url',
144
148
  },
145
149
  };
146
150
 
151
+ (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
152
+
153
+ await webSocketManager.initWebSocket({
154
+ body: fakeSubscribeRequest,
155
+ resource: RTD_SUBSCRIBE_API,
156
+ });
157
+
158
+ expect(mockWebex.request).toHaveBeenCalledWith({
159
+ service: WCC_API_GATEWAY,
160
+ resource: RTD_SUBSCRIBE_API,
161
+ method: 'POST',
162
+ body: fakeSubscribeRequest,
163
+ headers: {'X-ORGANIZATION-ID': 'test-org-id'},
164
+ });
165
+ });
166
+
167
+ it('should register and connect to WebSocket without X-ORGANIZATION-ID header for production environment', async () => {
168
+ const subscribeResponse = {
169
+ body: {
170
+ webSocketUrl: 'wss://fake-url',
171
+ },
172
+ };
147
173
  // Mock production environment (services.isIntegrationEnvironment returns false)
148
174
  (mockWebex.internal.services.isIntegrationEnvironment as jest.Mock).mockReturnValue(false);
149
175
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
@@ -225,12 +251,12 @@ describe('WebSocketManager', () => {
225
251
 
226
252
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
227
253
 
228
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
254
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
229
255
 
230
256
  webSocketManager.close(true, 'Test reason');
231
257
 
232
258
  expect(MockWebSocket.inst.close).toHaveBeenCalled();
233
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
259
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
234
260
  });
235
261
 
236
262
  it('should handle WebSocket keepalive messages', async () => {
@@ -242,19 +268,19 @@ describe('WebSocketManager', () => {
242
268
 
243
269
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
244
270
 
245
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
271
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
246
272
 
247
273
  setTimeout(() => {
248
274
  MockWebSocket.inst.onopen();
249
- MockWebSocket.inst.onmessage({ data: JSON.stringify({ type: 'keepalive' }) });
275
+ MockWebSocket.inst.onmessage({data: JSON.stringify({type: 'keepalive'})});
250
276
  mockWorker.onmessage({
251
277
  data: {
252
- type: 'keepalive'
253
- }
278
+ type: 'keepalive',
279
+ },
254
280
  });
255
281
  }, 1);
256
282
 
257
- expect(MockWebSocket.inst.send).toHaveBeenCalledWith(JSON.stringify({ keepalive: 'true' }));
283
+ expect(MockWebSocket.inst.send).toHaveBeenCalledWith(JSON.stringify({keepalive: 'true'}));
258
284
  });
259
285
 
260
286
  it('should handle WebSocket close due to network issue', async () => {
@@ -266,7 +292,7 @@ describe('WebSocketManager', () => {
266
292
 
267
293
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
268
294
 
269
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
295
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
270
296
 
271
297
  // Mock navigator.onLine to simulate network issue
272
298
  Object.defineProperty(global, 'navigator', {
@@ -289,10 +315,10 @@ describe('WebSocketManager', () => {
289
315
  // Wait for the close event to be handled
290
316
  await new Promise((resolve) => setTimeout(resolve, 10));
291
317
 
292
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
318
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
293
319
  expect(LoggerProxy.error).toHaveBeenCalledWith(
294
320
  '[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: network issue',
295
- { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
321
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
296
322
  );
297
323
 
298
324
  // Restore navigator.onLine to true
@@ -313,14 +339,14 @@ describe('WebSocketManager', () => {
313
339
 
314
340
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
315
341
 
316
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
342
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
317
343
 
318
344
  const errorEvent = new Event('error');
319
345
  MockWebSocket.inst.onerror(errorEvent);
320
346
 
321
347
  expect(LoggerProxy.error).toHaveBeenCalledWith(
322
348
  '[WebSocketStatus] | event=socketConnectionFailed | WebSocket connection failed [object Event]',
323
- { module: WEB_SOCKET_MANAGER_FILE, method: 'connect' }
349
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'connect'}
324
350
  );
325
351
  });
326
352
 
@@ -333,17 +359,17 @@ describe('WebSocketManager', () => {
333
359
 
334
360
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
335
361
 
336
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
362
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
337
363
 
338
364
  const messageEvent = new MessageEvent('message', {
339
- data: JSON.stringify({ type: 'AGENT_MULTI_LOGIN' }),
365
+ data: JSON.stringify({type: 'AGENT_MULTI_LOGIN'}),
340
366
  });
341
367
  MockWebSocket.inst.onmessage(messageEvent);
342
368
 
343
369
  expect(MockWebSocket.inst.close).toHaveBeenCalled();
344
370
  expect(LoggerProxy.error).toHaveBeenCalledWith(
345
371
  '[WebSocketStatus] | event=agentMultiLogin | WebSocket connection closed by agent multiLogin',
346
- { module: WEB_SOCKET_MANAGER_FILE, method: 'connect' }
372
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'connect'}
347
373
  );
348
374
  });
349
375
 
@@ -356,10 +382,10 @@ describe('WebSocketManager', () => {
356
382
 
357
383
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
358
384
 
359
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
385
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
360
386
 
361
387
  const messageEvent = new MessageEvent('message', {
362
- data: JSON.stringify({ type: 'Welcome', data: { someData: 'data' } }),
388
+ data: JSON.stringify({type: 'Welcome', data: {someData: 'data'}}),
363
389
  });
364
390
  MockWebSocket.inst.onmessage(messageEvent);
365
391
 
@@ -375,7 +401,7 @@ describe('WebSocketManager', () => {
375
401
 
376
402
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
377
403
 
378
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
404
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
379
405
 
380
406
  webSocketManager['forceCloseWebSocketOnTimeout'] = true;
381
407
 
@@ -394,10 +420,10 @@ describe('WebSocketManager', () => {
394
420
  // Wait for the close event to be handled
395
421
  await new Promise((resolve) => setTimeout(resolve, 10));
396
422
 
397
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
423
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
398
424
  expect(LoggerProxy.error).toHaveBeenCalledWith(
399
425
  '[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: WebSocket auto close timed out. Forcefully closed websocket.',
400
- { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
426
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
401
427
  );
402
428
  });
403
429
 
@@ -410,7 +436,7 @@ describe('WebSocketManager', () => {
410
436
 
411
437
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
412
438
 
413
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
439
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
414
440
  webSocketManager.shouldReconnect = false;
415
441
  // Simulate the WebSocket close event
416
442
  setTimeout(() => {
@@ -421,13 +447,13 @@ describe('WebSocketManager', () => {
421
447
  target: MockWebSocket.inst,
422
448
  });
423
449
  }, 1);
424
-
450
+
425
451
  await new Promise((resolve) => setTimeout(resolve, 10));
426
452
 
427
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
453
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
428
454
  expect(LoggerProxy.error).not.toHaveBeenCalledWith(
429
455
  '[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: no reconnect',
430
- { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
456
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
431
457
  );
432
458
  });
433
459
 
@@ -440,7 +466,7 @@ describe('WebSocketManager', () => {
440
466
 
441
467
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
442
468
 
443
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
469
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
444
470
 
445
471
  // Simulate the WebSocket close event
446
472
  setTimeout(() => {
@@ -455,10 +481,10 @@ describe('WebSocketManager', () => {
455
481
  // Wait for the close event to be handled
456
482
  await new Promise((resolve) => setTimeout(resolve, 10));
457
483
 
458
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
484
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
459
485
  expect(LoggerProxy.error).not.toHaveBeenCalledWith(
460
486
  '[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: clean close',
461
- { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
487
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
462
488
  );
463
489
  });
464
- });
490
+ });
@@ -0,0 +1,63 @@
1
+ import AutoWrapup from '../../../../../src/services/task/AutoWrapup';
2
+
3
+ describe('AutoWrapup', () => {
4
+ beforeEach(() => {
5
+ jest.useFakeTimers();
6
+ });
7
+
8
+ afterEach(() => {
9
+ jest.useRealTimers();
10
+ });
11
+
12
+ it('starts, reports running, and completes', () => {
13
+ const onComplete = jest.fn();
14
+ const timer = new AutoWrapup(1000, true);
15
+
16
+ expect(timer.allowCancelAutoWrapup).toBe(true);
17
+ expect(timer.isRunning()).toBe(false);
18
+
19
+ timer.start(onComplete);
20
+ expect(timer.isRunning()).toBe(true);
21
+ expect(timer.getTimeLeft()).toBeGreaterThan(0);
22
+ expect(timer.getTimeLeftSeconds()).toBeGreaterThan(0);
23
+
24
+ jest.advanceTimersByTime(1000);
25
+ expect(onComplete).toHaveBeenCalledTimes(1);
26
+ expect(timer.isRunning()).toBe(false);
27
+ });
28
+
29
+ it('clear() is safe when not running and cancels an active timer', () => {
30
+ const onComplete = jest.fn();
31
+ const timer = new AutoWrapup(1000);
32
+
33
+ timer.clear(); // no-op
34
+ expect(timer.isRunning()).toBe(false);
35
+
36
+ timer.start(onComplete);
37
+ expect(timer.isRunning()).toBe(true);
38
+
39
+ timer.clear();
40
+ expect(timer.isRunning()).toBe(false);
41
+
42
+ jest.advanceTimersByTime(1000);
43
+ expect(onComplete).not.toHaveBeenCalled();
44
+ });
45
+
46
+ it('start() replaces an existing timer', () => {
47
+ const onComplete1 = jest.fn();
48
+ const onComplete2 = jest.fn();
49
+ const timer = new AutoWrapup(1000);
50
+
51
+ timer.start(onComplete1);
52
+ jest.advanceTimersByTime(500);
53
+
54
+ timer.start(onComplete2);
55
+ jest.advanceTimersByTime(500);
56
+ expect(onComplete1).not.toHaveBeenCalled();
57
+ expect(onComplete2).not.toHaveBeenCalled();
58
+
59
+ jest.advanceTimersByTime(500);
60
+ expect(onComplete2).toHaveBeenCalledTimes(1);
61
+ });
62
+ });
63
+