@webex/contact-center 3.9.0 → 3.10.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cc.js +196 -47
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/logger-proxy.js +24 -1
- package/dist/logger-proxy.js.map +1 -1
- package/dist/metrics/MetricsManager.js +1 -1
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +89 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +32 -2
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +271 -0
- package/dist/services/AddressBook.js.map +1 -0
- package/dist/services/EntryPoint.js +227 -0
- package/dist/services/EntryPoint.js.map +1 -0
- package/dist/services/Queue.js +261 -0
- package/dist/services/Queue.js.map +1 -0
- package/dist/services/config/constants.js +36 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +29 -21
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +33 -1
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/GlobalTypes.js.map +1 -1
- package/dist/services/core/Utils.js +162 -2
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +0 -4
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +0 -4
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/task/TaskManager.js +114 -3
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +76 -0
- package/dist/services/task/TaskUtils.js.map +1 -0
- package/dist/services/task/constants.js +26 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +86 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/index.js +418 -87
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +14 -0
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +115 -35
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/metrics/constants.d.ts +25 -1
- package/dist/types/services/AddressBook.d.ts +74 -0
- package/dist/types/services/EntryPoint.d.ts +67 -0
- package/dist/types/services/Queue.d.ts +76 -0
- package/dist/types/services/config/constants.d.ts +35 -1
- package/dist/types/services/config/index.d.ts +6 -9
- package/dist/types/services/config/types.d.ts +79 -58
- package/dist/types/services/core/GlobalTypes.d.ts +25 -0
- package/dist/types/services/core/Utils.d.ts +40 -1
- package/dist/types/services/task/TaskUtils.d.ts +28 -0
- package/dist/types/services/task/constants.d.ts +23 -0
- package/dist/types/services/task/contact.d.ts +10 -0
- package/dist/types/services/task/index.d.ts +85 -4
- package/dist/types/services/task/types.d.ts +233 -21
- package/dist/types/types.d.ts +162 -0
- package/dist/types/utils/PageCache.d.ts +173 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +192 -0
- package/dist/utils/PageCache.js.map +1 -0
- package/dist/webex.js +1 -1
- package/package.json +10 -9
- package/src/cc.ts +221 -52
- package/src/constants.ts +1 -0
- package/src/index.ts +16 -2
- package/src/logger-proxy.ts +24 -1
- package/src/metrics/MetricsManager.ts +1 -1
- package/src/metrics/behavioral-events.ts +94 -0
- package/src/metrics/constants.ts +37 -1
- package/src/services/AddressBook.ts +291 -0
- package/src/services/EntryPoint.ts +241 -0
- package/src/services/Queue.ts +277 -0
- package/src/services/config/constants.ts +42 -2
- package/src/services/config/index.ts +30 -30
- package/src/services/config/types.ts +59 -58
- package/src/services/core/GlobalTypes.ts +27 -0
- package/src/services/core/Utils.ts +199 -1
- package/src/services/core/aqm-reqs.ts +0 -5
- package/src/services/core/websocket/WebSocketManager.ts +0 -4
- package/src/services/task/TaskManager.ts +123 -5
- package/src/services/task/TaskUtils.ts +81 -0
- package/src/services/task/constants.ts +25 -0
- package/src/services/task/contact.ts +80 -0
- package/src/services/task/index.ts +510 -71
- package/src/services/task/types.ts +251 -20
- package/src/types.ts +180 -0
- package/src/utils/PageCache.ts +252 -0
- package/test/unit/spec/cc.ts +282 -85
- package/test/unit/spec/metrics/MetricsManager.ts +0 -1
- package/test/unit/spec/metrics/behavioral-events.ts +42 -0
- package/test/unit/spec/services/AddressBook.ts +332 -0
- package/test/unit/spec/services/EntryPoint.ts +259 -0
- package/test/unit/spec/services/Queue.ts +323 -0
- package/test/unit/spec/services/config/index.ts +279 -65
- package/test/unit/spec/services/core/Utils.ts +50 -0
- package/test/unit/spec/services/core/aqm-reqs.ts +1 -3
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +0 -4
- package/test/unit/spec/services/task/TaskManager.ts +390 -1
- package/test/unit/spec/services/task/TaskUtils.ts +131 -0
- package/test/unit/spec/services/task/contact.ts +31 -1
- package/test/unit/spec/services/task/index.ts +585 -130
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -33,12 +33,13 @@ describe('Task', () => {
|
|
|
33
33
|
let mockMetricsManager;
|
|
34
34
|
let taskDataMock;
|
|
35
35
|
let webCallingService;
|
|
36
|
-
let
|
|
36
|
+
let generateTaskErrorObjectSpy;
|
|
37
37
|
let mockWebexRequest;
|
|
38
38
|
let webex: WebexSDK;
|
|
39
39
|
let loggerInfoSpy;
|
|
40
40
|
let loggerLogSpy;
|
|
41
41
|
let loggerErrorSpy;
|
|
42
|
+
let getDestinationAgentIdSpy;
|
|
42
43
|
|
|
43
44
|
const taskId = '0ae913a4-c857-4705-8d49-76dd3dde75e4';
|
|
44
45
|
const mockTrack = {} as MediaStreamTrack;
|
|
@@ -74,6 +75,9 @@ describe('Task', () => {
|
|
|
74
75
|
wrapup: jest.fn().mockResolvedValue({}),
|
|
75
76
|
pauseRecording: jest.fn().mockResolvedValue({}),
|
|
76
77
|
resumeRecording: jest.fn().mockResolvedValue({}),
|
|
78
|
+
consultConference: jest.fn().mockResolvedValue({}),
|
|
79
|
+
exitConference: jest.fn().mockResolvedValue({}),
|
|
80
|
+
conferenceTransfer: jest.fn().mockResolvedValue({}),
|
|
77
81
|
};
|
|
78
82
|
|
|
79
83
|
mockMetricsManager = {
|
|
@@ -141,6 +145,11 @@ describe('Task', () => {
|
|
|
141
145
|
},
|
|
142
146
|
};
|
|
143
147
|
|
|
148
|
+
// Mock destination agent id resolution from participants
|
|
149
|
+
getDestinationAgentIdSpy = jest
|
|
150
|
+
.spyOn(Utils, 'getDestinationAgentId')
|
|
151
|
+
.mockReturnValue(taskDataMock.destAgentId);
|
|
152
|
+
|
|
144
153
|
// Create an instance of Task
|
|
145
154
|
task = new Task(contactMock, webCallingService, taskDataMock);
|
|
146
155
|
|
|
@@ -158,11 +167,42 @@ describe('Task', () => {
|
|
|
158
167
|
return mockStream;
|
|
159
168
|
});
|
|
160
169
|
|
|
161
|
-
|
|
170
|
+
generateTaskErrorObjectSpy = jest.spyOn(Utils, 'generateTaskErrorObject');
|
|
171
|
+
generateTaskErrorObjectSpy.mockImplementation((error: any, methodName: string) => {
|
|
172
|
+
const trackingId = error?.details?.trackingId;
|
|
173
|
+
const msg = error?.details?.msg;
|
|
174
|
+
const legacyReason = error?.details?.data?.reason;
|
|
175
|
+
const errorMessage = msg?.errorMessage || legacyReason || `Error while performing ${methodName}`;
|
|
176
|
+
const errorType = msg?.errorType || '';
|
|
177
|
+
const errorData = msg?.errorData || '';
|
|
178
|
+
const reasonCode = msg?.reasonCode || 0;
|
|
179
|
+
const reason = legacyReason || (errorType ? `${errorType}: ${errorMessage}` : errorMessage);
|
|
180
|
+
const err: any = new Error(reason);
|
|
181
|
+
err.data = {
|
|
182
|
+
trackingId,
|
|
183
|
+
message: errorMessage,
|
|
184
|
+
errorType,
|
|
185
|
+
errorData,
|
|
186
|
+
reasonCode,
|
|
187
|
+
};
|
|
188
|
+
return err;
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
(global as any).makeFailure = (reason: string, trackingId = '1234', orgId = 'org1') => ({
|
|
192
|
+
type: 'failure_event',
|
|
193
|
+
orgId,
|
|
194
|
+
trackingId,
|
|
195
|
+
data: {
|
|
196
|
+
agentId: 'agent1',
|
|
197
|
+
reason,
|
|
198
|
+
reasonCode: 0,
|
|
199
|
+
},
|
|
200
|
+
});
|
|
162
201
|
});
|
|
163
202
|
|
|
164
203
|
afterEach(() => {
|
|
165
204
|
jest.clearAllMocks();
|
|
205
|
+
jest.restoreAllMocks();
|
|
166
206
|
});
|
|
167
207
|
|
|
168
208
|
it('test the on spy', async () => {
|
|
@@ -177,7 +217,7 @@ describe('Task', () => {
|
|
|
177
217
|
});
|
|
178
218
|
|
|
179
219
|
describe('updateTaskData cases', () => {
|
|
180
|
-
it('
|
|
220
|
+
it('updates the task data by overwrite', async () => {
|
|
181
221
|
const newData = {
|
|
182
222
|
type: CC_EVENTS.AGENT_CONTACT_ASSIGNED,
|
|
183
223
|
agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
@@ -226,12 +266,12 @@ describe('Task', () => {
|
|
|
226
266
|
expect(task.data).toEqual(newData);
|
|
227
267
|
});
|
|
228
268
|
|
|
229
|
-
it('
|
|
269
|
+
it('updates the task data by merging with key removal', async () => {
|
|
230
270
|
const newData = {
|
|
231
|
-
//
|
|
271
|
+
// Purposefully omit other keys to test remove and merge behavior
|
|
232
272
|
isConsulting: true, // Add a new custom key to test persistence
|
|
233
273
|
interaction: {
|
|
234
|
-
//
|
|
274
|
+
// Purposefully omit other interaction keys to test removal
|
|
235
275
|
media: {
|
|
236
276
|
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
237
277
|
holdTimestamp: null,
|
|
@@ -258,11 +298,12 @@ describe('Task', () => {
|
|
|
258
298
|
},
|
|
259
299
|
};
|
|
260
300
|
|
|
301
|
+
// The reconcileData method removes keys from oldData that are not in newData
|
|
302
|
+
// This means only keys present in newData will remain in the final result
|
|
261
303
|
const expectedData: TaskData = {
|
|
262
|
-
|
|
263
|
-
isConsulting: true,
|
|
304
|
+
isConsulting: true, // New key is added
|
|
264
305
|
interaction: {
|
|
265
|
-
|
|
306
|
+
// Only the media key from newData.interaction remains
|
|
266
307
|
media: {
|
|
267
308
|
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
268
309
|
holdTimestamp: null,
|
|
@@ -295,6 +336,60 @@ describe('Task', () => {
|
|
|
295
336
|
|
|
296
337
|
expect(task.data).toEqual(expectedData);
|
|
297
338
|
});
|
|
339
|
+
|
|
340
|
+
it('updates the task data by merging and preserving existing keys', async () => {
|
|
341
|
+
const newData = {
|
|
342
|
+
...taskDataMock, // Include all existing keys to test merge without removal
|
|
343
|
+
isConsulting: true, // Add a new custom key
|
|
344
|
+
interaction: {
|
|
345
|
+
...taskDataMock.interaction, // Include existing interaction data
|
|
346
|
+
media: {
|
|
347
|
+
...taskDataMock.interaction.media, // Include existing media
|
|
348
|
+
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
349
|
+
holdTimestamp: null,
|
|
350
|
+
isHold: true,
|
|
351
|
+
mType: 'consult',
|
|
352
|
+
mediaMgr: 'callmm',
|
|
353
|
+
mediaResourceId: '58a45567-4e61-4f4b-a580-5bc86357bef0',
|
|
354
|
+
mediaType: 'telephony',
|
|
355
|
+
participants: [
|
|
356
|
+
'f520d6b5-28ad-4f2f-b83e-781bb64af617',
|
|
357
|
+
'723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
358
|
+
],
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
const expectedData: TaskData = {
|
|
365
|
+
...taskDataMock,
|
|
366
|
+
isConsulting: true,
|
|
367
|
+
interaction: {
|
|
368
|
+
...taskDataMock.interaction,
|
|
369
|
+
media: {
|
|
370
|
+
...taskDataMock.interaction.media,
|
|
371
|
+
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
372
|
+
holdTimestamp: null,
|
|
373
|
+
isHold: true,
|
|
374
|
+
mType: 'consult',
|
|
375
|
+
mediaMgr: 'callmm',
|
|
376
|
+
mediaResourceId: '58a45567-4e61-4f4b-a580-5bc86357bef0',
|
|
377
|
+
mediaType: 'telephony',
|
|
378
|
+
participants: [
|
|
379
|
+
'f520d6b5-28ad-4f2f-b83e-781bb64af617',
|
|
380
|
+
'723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
381
|
+
],
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
expect(task.data).toEqual(taskDataMock);
|
|
388
|
+
const shouldOverwrite = false;
|
|
389
|
+
task.updateTaskData(newData, shouldOverwrite);
|
|
390
|
+
|
|
391
|
+
expect(task.data).toEqual(expectedData);
|
|
392
|
+
});
|
|
298
393
|
});
|
|
299
394
|
|
|
300
395
|
it('should accept a task and answer call when using BROWSER login option', async () => {
|
|
@@ -413,27 +508,28 @@ describe('Task', () => {
|
|
|
413
508
|
});
|
|
414
509
|
|
|
415
510
|
it('should handle errors in accept method', async () => {
|
|
416
|
-
const error = {
|
|
417
|
-
details: {
|
|
418
|
-
trackingId: '1234',
|
|
419
|
-
data: {
|
|
420
|
-
reason: 'Accept Failed',
|
|
421
|
-
},
|
|
422
|
-
},
|
|
423
|
-
};
|
|
511
|
+
const error = {details: (global as any).makeFailure('Accept Failed')};
|
|
424
512
|
|
|
425
513
|
jest.spyOn(webCallingService, 'answerCall').mockImplementation(() => {
|
|
426
514
|
throw error;
|
|
427
515
|
});
|
|
428
516
|
|
|
429
517
|
await expect(task.accept()).rejects.toThrow(new Error(error.details.data.reason));
|
|
430
|
-
expect(
|
|
518
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'accept', TASK_FILE);
|
|
519
|
+
const expectedTaskErrorFields = {
|
|
520
|
+
trackingId: error.details.trackingId,
|
|
521
|
+
errorMessage: error.details.data.reason,
|
|
522
|
+
errorType: '',
|
|
523
|
+
errorData: '',
|
|
524
|
+
reasonCode: 0,
|
|
525
|
+
};
|
|
431
526
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
432
527
|
1,
|
|
433
528
|
METRIC_EVENT_NAMES.TASK_ACCEPT_FAILED,
|
|
434
529
|
{
|
|
435
530
|
taskId: taskDataMock.interactionId,
|
|
436
531
|
error: error.toString(),
|
|
532
|
+
...expectedTaskErrorFields,
|
|
437
533
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
438
534
|
},
|
|
439
535
|
['operational', 'behavioral', 'business']
|
|
@@ -469,26 +565,27 @@ describe('Task', () => {
|
|
|
469
565
|
});
|
|
470
566
|
|
|
471
567
|
it('should handle errors in decline method', async () => {
|
|
472
|
-
const error = {
|
|
473
|
-
details: {
|
|
474
|
-
trackingId: '1234',
|
|
475
|
-
data: {
|
|
476
|
-
reason: 'Decline Failed',
|
|
477
|
-
},
|
|
478
|
-
},
|
|
479
|
-
};
|
|
568
|
+
const error = {details: (global as any).makeFailure('Decline Failed')};
|
|
480
569
|
|
|
481
570
|
jest.spyOn(webCallingService, 'declineCall').mockImplementation(() => {
|
|
482
571
|
throw error;
|
|
483
572
|
});
|
|
484
573
|
await expect(task.decline()).rejects.toThrow(new Error(error.details.data.reason));
|
|
485
|
-
expect(
|
|
574
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'decline', TASK_FILE);
|
|
575
|
+
const expectedTaskErrorFieldsDecline = {
|
|
576
|
+
trackingId: error.details.trackingId,
|
|
577
|
+
errorMessage: error.details.data.reason,
|
|
578
|
+
errorType: '',
|
|
579
|
+
errorData: '',
|
|
580
|
+
reasonCode: 0,
|
|
581
|
+
};
|
|
486
582
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
487
583
|
1,
|
|
488
584
|
METRIC_EVENT_NAMES.TASK_DECLINE_FAILED,
|
|
489
585
|
{
|
|
490
586
|
taskId: taskDataMock.interactionId,
|
|
491
587
|
error: error.toString(),
|
|
588
|
+
...expectedTaskErrorFieldsDecline,
|
|
492
589
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
493
590
|
},
|
|
494
591
|
['operational', 'behavioral']
|
|
@@ -528,21 +625,55 @@ describe('Task', () => {
|
|
|
528
625
|
);
|
|
529
626
|
});
|
|
530
627
|
|
|
531
|
-
it('should
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
628
|
+
it('should hold the task with custom mediaResourceId and return the expected response', async () => {
|
|
629
|
+
const customMediaResourceId = 'custom-media-resource-id-123';
|
|
630
|
+
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
631
|
+
contactMock.hold.mockResolvedValue(expectedResponse);
|
|
632
|
+
|
|
633
|
+
const response = await task.hold(customMediaResourceId);
|
|
634
|
+
|
|
635
|
+
expect(contactMock.hold).toHaveBeenCalledWith({
|
|
636
|
+
interactionId: taskId,
|
|
637
|
+
data: {mediaResourceId: customMediaResourceId},
|
|
638
|
+
});
|
|
639
|
+
expect(response).toEqual(expectedResponse);
|
|
640
|
+
expect(loggerInfoSpy).toHaveBeenCalledWith(`Holding task`, {
|
|
641
|
+
module: TASK_FILE,
|
|
642
|
+
method: 'hold',
|
|
643
|
+
interactionId: task.data.interactionId,
|
|
644
|
+
});
|
|
645
|
+
expect(loggerLogSpy).toHaveBeenCalledWith(`Task placed on hold successfully`, {
|
|
646
|
+
module: TASK_FILE,
|
|
647
|
+
method: 'hold',
|
|
648
|
+
interactionId: task.data.interactionId,
|
|
649
|
+
});
|
|
650
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
651
|
+
1,
|
|
652
|
+
METRIC_EVENT_NAMES.TASK_HOLD_SUCCESS,
|
|
653
|
+
{
|
|
654
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(expectedResponse),
|
|
655
|
+
taskId: taskDataMock.interactionId,
|
|
656
|
+
mediaResourceId: customMediaResourceId,
|
|
538
657
|
},
|
|
539
|
-
|
|
658
|
+
['operational', 'behavioral']
|
|
659
|
+
);
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
it('should handle errors in hold method', async () => {
|
|
663
|
+
const error = {details: (global as any).makeFailure('Hold Failed')};
|
|
540
664
|
contactMock.hold.mockImplementation(() => {
|
|
541
665
|
throw error;
|
|
542
666
|
});
|
|
543
667
|
|
|
544
668
|
await expect(task.hold()).rejects.toThrow(error.details.data.reason);
|
|
545
|
-
expect(
|
|
669
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'hold', TASK_FILE);
|
|
670
|
+
const expectedTaskErrorFieldsHold = {
|
|
671
|
+
trackingId: error.details.trackingId,
|
|
672
|
+
errorMessage: error.details.data.reason,
|
|
673
|
+
errorType: '',
|
|
674
|
+
errorData: '',
|
|
675
|
+
reasonCode: 0,
|
|
676
|
+
};
|
|
546
677
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
547
678
|
1,
|
|
548
679
|
METRIC_EVENT_NAMES.TASK_HOLD_FAILED,
|
|
@@ -550,6 +681,37 @@ describe('Task', () => {
|
|
|
550
681
|
taskId: taskDataMock.interactionId,
|
|
551
682
|
mediaResourceId: taskDataMock.mediaResourceId,
|
|
552
683
|
error: error.toString(),
|
|
684
|
+
...expectedTaskErrorFieldsHold,
|
|
685
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
686
|
+
},
|
|
687
|
+
['operational', 'behavioral']
|
|
688
|
+
);
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
it('should handle errors in hold method with custom mediaResourceId', async () => {
|
|
692
|
+
const customMediaResourceId = 'custom-media-resource-id-456';
|
|
693
|
+
const error = {details: (global as any).makeFailure('Hold Failed with custom mediaResourceId')};
|
|
694
|
+
contactMock.hold.mockImplementation(() => {
|
|
695
|
+
throw error;
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
await expect(task.hold(customMediaResourceId)).rejects.toThrow(error.details.data.reason);
|
|
699
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'hold', TASK_FILE);
|
|
700
|
+
const expectedTaskErrorFieldsHold = {
|
|
701
|
+
trackingId: error.details.trackingId,
|
|
702
|
+
errorMessage: error.details.data.reason,
|
|
703
|
+
errorType: '',
|
|
704
|
+
errorData: '',
|
|
705
|
+
reasonCode: 0,
|
|
706
|
+
};
|
|
707
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
708
|
+
1,
|
|
709
|
+
METRIC_EVENT_NAMES.TASK_HOLD_FAILED,
|
|
710
|
+
{
|
|
711
|
+
taskId: taskDataMock.interactionId,
|
|
712
|
+
mediaResourceId: customMediaResourceId,
|
|
713
|
+
error: error.toString(),
|
|
714
|
+
...expectedTaskErrorFieldsHold,
|
|
553
715
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
554
716
|
},
|
|
555
717
|
['operational', 'behavioral']
|
|
@@ -580,21 +742,44 @@ describe('Task', () => {
|
|
|
580
742
|
);
|
|
581
743
|
});
|
|
582
744
|
|
|
583
|
-
it('should
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
745
|
+
it('should resume the task with custom mediaResourceId and return the expected response', async () => {
|
|
746
|
+
const customMediaResourceId = 'custom-media-resource-id-789';
|
|
747
|
+
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
748
|
+
contactMock.unHold.mockResolvedValue(expectedResponse);
|
|
749
|
+
const response = await task.resume(customMediaResourceId);
|
|
750
|
+
expect(contactMock.unHold).toHaveBeenCalledWith({
|
|
751
|
+
interactionId: taskId,
|
|
752
|
+
data: {mediaResourceId: customMediaResourceId},
|
|
753
|
+
});
|
|
754
|
+
expect(response).toEqual(expectedResponse);
|
|
755
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
756
|
+
1,
|
|
757
|
+
METRIC_EVENT_NAMES.TASK_RESUME_SUCCESS,
|
|
758
|
+
{
|
|
759
|
+
taskId: taskDataMock.interactionId,
|
|
760
|
+
mainInteractionId: taskDataMock.interaction.mainInteractionId,
|
|
761
|
+
mediaResourceId: customMediaResourceId,
|
|
762
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(expectedResponse),
|
|
590
763
|
},
|
|
591
|
-
|
|
764
|
+
['operational', 'behavioral']
|
|
765
|
+
);
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
it('should handle errors in resume method', async () => {
|
|
769
|
+
const error = {details: (global as any).makeFailure('Resume Failed')};
|
|
592
770
|
contactMock.unHold.mockImplementation(() => {
|
|
593
771
|
throw error;
|
|
594
772
|
});
|
|
595
773
|
|
|
596
774
|
await expect(task.resume()).rejects.toThrow(error.details.data.reason);
|
|
597
|
-
expect(
|
|
775
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'resume', TASK_FILE);
|
|
776
|
+
const expectedTaskErrorFieldsResume = {
|
|
777
|
+
trackingId: error.details.trackingId,
|
|
778
|
+
errorMessage: error.details.data.reason,
|
|
779
|
+
errorType: '',
|
|
780
|
+
errorData: '',
|
|
781
|
+
reasonCode: 0,
|
|
782
|
+
};
|
|
598
783
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
599
784
|
1,
|
|
600
785
|
METRIC_EVENT_NAMES.TASK_RESUME_FAILED,
|
|
@@ -604,6 +789,37 @@ describe('Task', () => {
|
|
|
604
789
|
mediaResourceId:
|
|
605
790
|
taskDataMock.interaction.media[taskDataMock.interaction.mainInteractionId]
|
|
606
791
|
.mediaResourceId,
|
|
792
|
+
...expectedTaskErrorFieldsResume,
|
|
793
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
794
|
+
},
|
|
795
|
+
['operational', 'behavioral']
|
|
796
|
+
);
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
it('should handle errors in resume method with custom mediaResourceId', async () => {
|
|
800
|
+
const customMediaResourceId = 'custom-media-resource-id-999';
|
|
801
|
+
const error = {details: (global as any).makeFailure('Resume Failed with custom mediaResourceId')};
|
|
802
|
+
contactMock.unHold.mockImplementation(() => {
|
|
803
|
+
throw error;
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
await expect(task.resume(customMediaResourceId)).rejects.toThrow(error.details.data.reason);
|
|
807
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'resume', TASK_FILE);
|
|
808
|
+
const expectedTaskErrorFieldsResume = {
|
|
809
|
+
trackingId: error.details.trackingId,
|
|
810
|
+
errorMessage: error.details.data.reason,
|
|
811
|
+
errorType: '',
|
|
812
|
+
errorData: '',
|
|
813
|
+
reasonCode: 0,
|
|
814
|
+
};
|
|
815
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
816
|
+
1,
|
|
817
|
+
METRIC_EVENT_NAMES.TASK_RESUME_FAILED,
|
|
818
|
+
{
|
|
819
|
+
taskId: taskDataMock.interactionId,
|
|
820
|
+
mainInteractionId: taskDataMock.interaction.mainInteractionId,
|
|
821
|
+
mediaResourceId: customMediaResourceId,
|
|
822
|
+
...expectedTaskErrorFieldsResume,
|
|
607
823
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
608
824
|
},
|
|
609
825
|
['operational', 'behavioral']
|
|
@@ -630,8 +846,8 @@ describe('Task', () => {
|
|
|
630
846
|
expect(loggerLogSpy).toHaveBeenCalledWith(`Consult started successfully to ${consultPayload.to}`, {
|
|
631
847
|
module: TASK_FILE,
|
|
632
848
|
method: 'consult',
|
|
633
|
-
trackingId: expectedResponse.trackingId,
|
|
634
849
|
interactionId: task.data.interactionId,
|
|
850
|
+
trackingId: '1234',
|
|
635
851
|
});
|
|
636
852
|
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
637
853
|
METRIC_EVENT_NAMES.TASK_CONSULT_START_SUCCESS,
|
|
@@ -646,14 +862,7 @@ describe('Task', () => {
|
|
|
646
862
|
});
|
|
647
863
|
|
|
648
864
|
it('should handle errors in consult method', async () => {
|
|
649
|
-
const error = {
|
|
650
|
-
details: {
|
|
651
|
-
trackingId: '1234',
|
|
652
|
-
data: {
|
|
653
|
-
reason: 'Consult Failed',
|
|
654
|
-
},
|
|
655
|
-
},
|
|
656
|
-
};
|
|
865
|
+
const error = {details: (global as any).makeFailure('Consult Failed')};
|
|
657
866
|
contactMock.consult.mockImplementation(() => {
|
|
658
867
|
throw error;
|
|
659
868
|
});
|
|
@@ -664,12 +873,19 @@ describe('Task', () => {
|
|
|
664
873
|
};
|
|
665
874
|
|
|
666
875
|
await expect(task.consult(consultPayload)).rejects.toThrow(error.details.data.reason);
|
|
667
|
-
expect(
|
|
876
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'consult', TASK_FILE);
|
|
668
877
|
expect(loggerInfoSpy).toHaveBeenCalledWith(`Starting consult`, {
|
|
669
878
|
module: TASK_FILE,
|
|
670
879
|
method: 'consult',
|
|
671
880
|
interactionId: task.data.interactionId,
|
|
672
881
|
});
|
|
882
|
+
const expectedTaskErrorFieldsConsult = {
|
|
883
|
+
trackingId: error.details.trackingId,
|
|
884
|
+
errorMessage: error.details.data.reason,
|
|
885
|
+
errorType: '',
|
|
886
|
+
errorData: '',
|
|
887
|
+
reasonCode: 0,
|
|
888
|
+
};
|
|
673
889
|
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
674
890
|
METRIC_EVENT_NAMES.TASK_CONSULT_START_FAILED,
|
|
675
891
|
{
|
|
@@ -677,6 +893,7 @@ describe('Task', () => {
|
|
|
677
893
|
destination: consultPayload.to,
|
|
678
894
|
destinationType: consultPayload.destinationType,
|
|
679
895
|
error: error.toString(),
|
|
896
|
+
...expectedTaskErrorFieldsConsult,
|
|
680
897
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
681
898
|
},
|
|
682
899
|
['operational', 'behavioral', 'business']
|
|
@@ -710,14 +927,7 @@ describe('Task', () => {
|
|
|
710
927
|
});
|
|
711
928
|
|
|
712
929
|
it('should handle errors in endConsult method', async () => {
|
|
713
|
-
const error = {
|
|
714
|
-
details: {
|
|
715
|
-
trackingId: '1234',
|
|
716
|
-
data: {
|
|
717
|
-
reason: 'End Consult Failed',
|
|
718
|
-
},
|
|
719
|
-
},
|
|
720
|
-
};
|
|
930
|
+
const error = {details: (global as any).makeFailure('End Consult Failed')};
|
|
721
931
|
contactMock.consultEnd.mockImplementation(() => {
|
|
722
932
|
throw error;
|
|
723
933
|
});
|
|
@@ -728,13 +938,21 @@ describe('Task', () => {
|
|
|
728
938
|
};
|
|
729
939
|
|
|
730
940
|
await expect(task.endConsult(consultEndPayload)).rejects.toThrow(error.details.data.reason);
|
|
731
|
-
expect(
|
|
941
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'endConsult', TASK_FILE);
|
|
942
|
+
const expectedTaskErrorFieldsEndConsult = {
|
|
943
|
+
trackingId: error.details.trackingId,
|
|
944
|
+
errorMessage: error.details.data.reason,
|
|
945
|
+
errorType: '',
|
|
946
|
+
errorData: '',
|
|
947
|
+
reasonCode: 0,
|
|
948
|
+
};
|
|
732
949
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
733
950
|
1,
|
|
734
951
|
METRIC_EVENT_NAMES.TASK_CONSULT_END_FAILED,
|
|
735
952
|
{
|
|
736
953
|
taskId: taskDataMock.interactionId,
|
|
737
954
|
error: error.toString(),
|
|
955
|
+
...expectedTaskErrorFieldsEndConsult,
|
|
738
956
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
739
957
|
},
|
|
740
958
|
['operational', 'behavioral', 'business']
|
|
@@ -754,29 +972,81 @@ describe('Task', () => {
|
|
|
754
972
|
expect(contactMock.consult).toHaveBeenCalledWith({interactionId: taskId, data: consultPayload});
|
|
755
973
|
expect(response).toEqual(expectedResponse);
|
|
756
974
|
|
|
757
|
-
const
|
|
758
|
-
to: '1234',
|
|
759
|
-
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
760
|
-
};
|
|
761
|
-
|
|
762
|
-
const consultTransferResponse = await task.consultTransfer(consultTransferPayload);
|
|
975
|
+
const consultTransferResponse = await task.consultTransfer();
|
|
763
976
|
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
764
977
|
interactionId: taskId,
|
|
765
|
-
data:
|
|
978
|
+
data: {
|
|
979
|
+
to: taskDataMock.destAgentId,
|
|
980
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
981
|
+
},
|
|
766
982
|
});
|
|
767
983
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
768
984
|
2,
|
|
769
985
|
METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS,
|
|
770
986
|
{
|
|
771
987
|
taskId: taskDataMock.interactionId,
|
|
772
|
-
destination:
|
|
773
|
-
destinationType:
|
|
988
|
+
destination: taskDataMock.destAgentId,
|
|
989
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
774
990
|
isConsultTransfer: true,
|
|
775
991
|
},
|
|
776
992
|
['operational', 'behavioral', 'business']
|
|
777
993
|
);
|
|
778
994
|
});
|
|
779
995
|
|
|
996
|
+
it('should send DIALNUMBER when task destinationType is DN during consultTransfer', async () => {
|
|
997
|
+
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
998
|
+
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
999
|
+
|
|
1000
|
+
// Ensure task data indicates DN scenario
|
|
1001
|
+
task.data.destinationType = 'DN' as unknown as string;
|
|
1002
|
+
|
|
1003
|
+
await task.consultTransfer();
|
|
1004
|
+
|
|
1005
|
+
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
1006
|
+
interactionId: taskId,
|
|
1007
|
+
data: {
|
|
1008
|
+
to: taskDataMock.destAgentId,
|
|
1009
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER,
|
|
1010
|
+
},
|
|
1011
|
+
});
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
it('should send ENTRYPOINT when task destinationType is EPDN during consultTransfer', async () => {
|
|
1015
|
+
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
1016
|
+
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
1017
|
+
|
|
1018
|
+
// Ensure task data indicates EP/EPDN scenario
|
|
1019
|
+
task.data.destinationType = 'EPDN' as unknown as string;
|
|
1020
|
+
|
|
1021
|
+
await task.consultTransfer();
|
|
1022
|
+
|
|
1023
|
+
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
1024
|
+
interactionId: taskId,
|
|
1025
|
+
data: {
|
|
1026
|
+
to: taskDataMock.destAgentId,
|
|
1027
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT,
|
|
1028
|
+
},
|
|
1029
|
+
});
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
it('should keep AGENT when task destinationType is neither DN nor EPDN/ENTRYPOINT', async () => {
|
|
1033
|
+
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
1034
|
+
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
1035
|
+
|
|
1036
|
+
// Ensure task data indicates non-DN and non-EP/EPDN scenario
|
|
1037
|
+
task.data.destinationType = 'SOMETHING_ELSE' as unknown as string;
|
|
1038
|
+
|
|
1039
|
+
await task.consultTransfer();
|
|
1040
|
+
|
|
1041
|
+
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
1042
|
+
interactionId: taskId,
|
|
1043
|
+
data: {
|
|
1044
|
+
to: taskDataMock.destAgentId,
|
|
1045
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
1046
|
+
},
|
|
1047
|
+
});
|
|
1048
|
+
});
|
|
1049
|
+
|
|
780
1050
|
it('should do consult transfer to a queue by using the destAgentId from task data', async () => {
|
|
781
1051
|
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
782
1052
|
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
@@ -811,6 +1081,9 @@ describe('Task', () => {
|
|
|
811
1081
|
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.QUEUE,
|
|
812
1082
|
};
|
|
813
1083
|
|
|
1084
|
+
// For this negative case, ensure computed destination is empty
|
|
1085
|
+
getDestinationAgentIdSpy.mockReturnValueOnce('');
|
|
1086
|
+
|
|
814
1087
|
await expect(
|
|
815
1088
|
taskWithoutDestAgentId.consultTransfer(queueConsultTransferPayload)
|
|
816
1089
|
).rejects.toThrow('Error while performing consultTransfer');
|
|
@@ -829,14 +1102,7 @@ describe('Task', () => {
|
|
|
829
1102
|
expect(contactMock.consult).toHaveBeenCalledWith({interactionId: taskId, data: consultPayload});
|
|
830
1103
|
expect(response).toEqual(expectedResponse);
|
|
831
1104
|
|
|
832
|
-
const error = {
|
|
833
|
-
details: {
|
|
834
|
-
trackingId: '1234',
|
|
835
|
-
data: {
|
|
836
|
-
reason: 'Consult Transfer Failed',
|
|
837
|
-
},
|
|
838
|
-
},
|
|
839
|
-
};
|
|
1105
|
+
const error = {details: (global as any).makeFailure('Consult Transfer Failed')};
|
|
840
1106
|
contactMock.consultTransfer.mockImplementation(() => {
|
|
841
1107
|
throw error;
|
|
842
1108
|
});
|
|
@@ -849,16 +1115,24 @@ describe('Task', () => {
|
|
|
849
1115
|
await expect(task.consultTransfer(consultTransferPayload)).rejects.toThrow(
|
|
850
1116
|
error.details.data.reason
|
|
851
1117
|
);
|
|
852
|
-
expect(
|
|
1118
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'consultTransfer', TASK_FILE);
|
|
1119
|
+
const expectedTaskErrorFieldsConsultTransfer = {
|
|
1120
|
+
trackingId: error.details.trackingId,
|
|
1121
|
+
errorMessage: error.details.data.reason,
|
|
1122
|
+
errorType: '',
|
|
1123
|
+
errorData: '',
|
|
1124
|
+
reasonCode: 0,
|
|
1125
|
+
};
|
|
853
1126
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
854
1127
|
2,
|
|
855
1128
|
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
856
1129
|
{
|
|
857
1130
|
taskId: taskDataMock.interactionId,
|
|
858
|
-
destination:
|
|
859
|
-
destinationType:
|
|
1131
|
+
destination: taskDataMock.destAgentId,
|
|
1132
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
860
1133
|
isConsultTransfer: true,
|
|
861
1134
|
error: error.toString(),
|
|
1135
|
+
...expectedTaskErrorFieldsConsultTransfer,
|
|
862
1136
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
863
1137
|
},
|
|
864
1138
|
['operational', 'behavioral', 'business']
|
|
@@ -926,14 +1200,7 @@ describe('Task', () => {
|
|
|
926
1200
|
});
|
|
927
1201
|
|
|
928
1202
|
it('should handle errors in transfer method', async () => {
|
|
929
|
-
const error = {
|
|
930
|
-
details: {
|
|
931
|
-
trackingId: '1234',
|
|
932
|
-
data: {
|
|
933
|
-
reason: 'Consult Transfer Failed',
|
|
934
|
-
},
|
|
935
|
-
},
|
|
936
|
-
};
|
|
1203
|
+
const error = {details: (global as any).makeFailure('Consult Transfer Failed')};
|
|
937
1204
|
contactMock.blindTransfer.mockImplementation(() => {
|
|
938
1205
|
throw error;
|
|
939
1206
|
});
|
|
@@ -944,7 +1211,14 @@ describe('Task', () => {
|
|
|
944
1211
|
};
|
|
945
1212
|
|
|
946
1213
|
await expect(task.transfer(blindTransferPayload)).rejects.toThrow(error.details.data.reason);
|
|
947
|
-
expect(
|
|
1214
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'transfer', TASK_FILE);
|
|
1215
|
+
const expectedTaskErrorFieldsTransfer = {
|
|
1216
|
+
trackingId: error.details.trackingId,
|
|
1217
|
+
errorMessage: error.details.data.reason,
|
|
1218
|
+
errorType: '',
|
|
1219
|
+
errorData: '',
|
|
1220
|
+
reasonCode: 0,
|
|
1221
|
+
};
|
|
948
1222
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
949
1223
|
1,
|
|
950
1224
|
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
@@ -954,6 +1228,7 @@ describe('Task', () => {
|
|
|
954
1228
|
destinationType: blindTransferPayload.destinationType,
|
|
955
1229
|
isConsultTransfer: false,
|
|
956
1230
|
error: error.toString(),
|
|
1231
|
+
...expectedTaskErrorFieldsTransfer,
|
|
957
1232
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
958
1233
|
},
|
|
959
1234
|
['operational', 'behavioral', 'business']
|
|
@@ -990,25 +1265,26 @@ describe('Task', () => {
|
|
|
990
1265
|
});
|
|
991
1266
|
|
|
992
1267
|
it('should handle errors in end method', async () => {
|
|
993
|
-
const error = {
|
|
994
|
-
details: {
|
|
995
|
-
trackingId: '1234',
|
|
996
|
-
data: {
|
|
997
|
-
reason: 'End Failed',
|
|
998
|
-
},
|
|
999
|
-
},
|
|
1000
|
-
};
|
|
1268
|
+
const error = {details: (global as any).makeFailure('End Failed')};
|
|
1001
1269
|
contactMock.end.mockImplementation(() => {
|
|
1002
1270
|
throw error;
|
|
1003
1271
|
});
|
|
1004
1272
|
|
|
1005
1273
|
await expect(task.end()).rejects.toThrow(error.details.data.reason);
|
|
1006
|
-
expect(
|
|
1274
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'end', TASK_FILE);
|
|
1275
|
+
const expectedTaskErrorFieldsEnd = {
|
|
1276
|
+
trackingId: error.details.trackingId,
|
|
1277
|
+
errorMessage: error.details.data.reason,
|
|
1278
|
+
errorType: '',
|
|
1279
|
+
errorData: '',
|
|
1280
|
+
reasonCode: 0,
|
|
1281
|
+
};
|
|
1007
1282
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
1008
1283
|
1,
|
|
1009
1284
|
METRIC_EVENT_NAMES.TASK_END_FAILED,
|
|
1010
1285
|
{
|
|
1011
1286
|
taskId: taskDataMock.interactionId,
|
|
1287
|
+
...expectedTaskErrorFieldsEnd,
|
|
1012
1288
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
1013
1289
|
},
|
|
1014
1290
|
['operational', 'behavioral', 'business']
|
|
@@ -1041,14 +1317,7 @@ describe('Task', () => {
|
|
|
1041
1317
|
});
|
|
1042
1318
|
|
|
1043
1319
|
it('should handle errors in wrapup method', async () => {
|
|
1044
|
-
const error = {
|
|
1045
|
-
details: {
|
|
1046
|
-
trackingId: '1234',
|
|
1047
|
-
data: {
|
|
1048
|
-
reason: 'Wrapup Failed',
|
|
1049
|
-
},
|
|
1050
|
-
},
|
|
1051
|
-
};
|
|
1320
|
+
const error = {details: (global as any).makeFailure('Wrapup Failed')};
|
|
1052
1321
|
contactMock.wrapup.mockImplementation(() => {
|
|
1053
1322
|
throw error;
|
|
1054
1323
|
});
|
|
@@ -1059,7 +1328,14 @@ describe('Task', () => {
|
|
|
1059
1328
|
};
|
|
1060
1329
|
|
|
1061
1330
|
await expect(task.wrapup(wrapupPayload)).rejects.toThrow(error.details.data.reason);
|
|
1062
|
-
expect(
|
|
1331
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'wrapup', TASK_FILE);
|
|
1332
|
+
const expectedTaskErrorFieldsWrapup = {
|
|
1333
|
+
trackingId: error.details.trackingId,
|
|
1334
|
+
errorMessage: error.details.data.reason,
|
|
1335
|
+
errorType: '',
|
|
1336
|
+
errorData: '',
|
|
1337
|
+
reasonCode: 0,
|
|
1338
|
+
};
|
|
1063
1339
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
1064
1340
|
1,
|
|
1065
1341
|
METRIC_EVENT_NAMES.TASK_WRAPUP_FAILED,
|
|
@@ -1067,6 +1343,7 @@ describe('Task', () => {
|
|
|
1067
1343
|
taskId: taskDataMock.interactionId,
|
|
1068
1344
|
wrapUpCode: wrapupPayload.auxCodeId,
|
|
1069
1345
|
wrapUpReason: wrapupPayload.wrapUpReason,
|
|
1346
|
+
...expectedTaskErrorFieldsWrapup,
|
|
1070
1347
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
1071
1348
|
},
|
|
1072
1349
|
['operational', 'behavioral', 'business']
|
|
@@ -1124,26 +1401,27 @@ describe('Task', () => {
|
|
|
1124
1401
|
});
|
|
1125
1402
|
|
|
1126
1403
|
it('should handle errors in pauseRecording method', async () => {
|
|
1127
|
-
const error = {
|
|
1128
|
-
details: {
|
|
1129
|
-
trackingId: '1234',
|
|
1130
|
-
data: {
|
|
1131
|
-
reason: 'Pause Recording Failed',
|
|
1132
|
-
},
|
|
1133
|
-
},
|
|
1134
|
-
};
|
|
1404
|
+
const error = {details: (global as any).makeFailure('Pause Recording Failed')};
|
|
1135
1405
|
contactMock.pauseRecording.mockImplementation(() => {
|
|
1136
1406
|
throw error;
|
|
1137
1407
|
});
|
|
1138
1408
|
|
|
1139
1409
|
await expect(task.pauseRecording()).rejects.toThrow(error.details.data.reason);
|
|
1140
|
-
expect(
|
|
1410
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'pauseRecording', TASK_FILE);
|
|
1411
|
+
const expectedTaskErrorFieldsPause = {
|
|
1412
|
+
trackingId: error.details.trackingId,
|
|
1413
|
+
errorMessage: error.details.data.reason,
|
|
1414
|
+
errorType: '',
|
|
1415
|
+
errorData: '',
|
|
1416
|
+
reasonCode: 0,
|
|
1417
|
+
};
|
|
1141
1418
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
1142
1419
|
1,
|
|
1143
1420
|
METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_FAILED,
|
|
1144
1421
|
{
|
|
1145
1422
|
taskId: taskDataMock.interactionId,
|
|
1146
1423
|
error: error.toString(),
|
|
1424
|
+
...expectedTaskErrorFieldsPause,
|
|
1147
1425
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
1148
1426
|
},
|
|
1149
1427
|
['operational', 'behavioral', 'business']
|
|
@@ -1204,14 +1482,7 @@ describe('Task', () => {
|
|
|
1204
1482
|
});
|
|
1205
1483
|
|
|
1206
1484
|
it('should handle errors in resumeRecording method', async () => {
|
|
1207
|
-
const error = {
|
|
1208
|
-
details: {
|
|
1209
|
-
trackingId: '1234',
|
|
1210
|
-
data: {
|
|
1211
|
-
reason: 'Resume Recording Failed',
|
|
1212
|
-
},
|
|
1213
|
-
},
|
|
1214
|
-
};
|
|
1485
|
+
const error = {details: (global as any).makeFailure('Resume Recording Failed')};
|
|
1215
1486
|
contactMock.resumeRecording.mockImplementation(() => {
|
|
1216
1487
|
throw error;
|
|
1217
1488
|
});
|
|
@@ -1221,13 +1492,21 @@ describe('Task', () => {
|
|
|
1221
1492
|
};
|
|
1222
1493
|
|
|
1223
1494
|
await expect(task.resumeRecording(resumePayload)).rejects.toThrow(error.details.data.reason);
|
|
1224
|
-
expect(
|
|
1495
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'resumeRecording', TASK_FILE);
|
|
1496
|
+
const expectedTaskErrorFieldsResumeRec = {
|
|
1497
|
+
trackingId: error.details.trackingId,
|
|
1498
|
+
errorMessage: error.details.data.reason,
|
|
1499
|
+
errorType: '',
|
|
1500
|
+
errorData: '',
|
|
1501
|
+
reasonCode: 0,
|
|
1502
|
+
};
|
|
1225
1503
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
1226
1504
|
1,
|
|
1227
1505
|
METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_FAILED,
|
|
1228
1506
|
{
|
|
1229
1507
|
taskId: taskDataMock.interactionId,
|
|
1230
1508
|
error: error.toString(),
|
|
1509
|
+
...expectedTaskErrorFieldsResumeRec,
|
|
1231
1510
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
1232
1511
|
},
|
|
1233
1512
|
['operational', 'behavioral', 'business']
|
|
@@ -1267,7 +1546,7 @@ describe('Task', () => {
|
|
|
1267
1546
|
throw error;
|
|
1268
1547
|
});
|
|
1269
1548
|
await expect(task.toggleMute()).rejects.toThrow(new Error(error.details.data.reason));
|
|
1270
|
-
expect(
|
|
1549
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'toggleMute', TASK_FILE);
|
|
1271
1550
|
expect(loggerInfoSpy).toHaveBeenCalledWith(`Toggling mute state`, {
|
|
1272
1551
|
module: TASK_FILE,
|
|
1273
1552
|
method: 'toggleMute',
|
|
@@ -1471,4 +1750,180 @@ describe('Task', () => {
|
|
|
1471
1750
|
});
|
|
1472
1751
|
});
|
|
1473
1752
|
});
|
|
1753
|
+
|
|
1754
|
+
describe('Conference methods', () => {
|
|
1755
|
+
beforeEach(() => {
|
|
1756
|
+
contactMock = {
|
|
1757
|
+
consultConference: jest.fn(),
|
|
1758
|
+
exitConference: jest.fn(),
|
|
1759
|
+
conferenceTransfer: jest.fn(),
|
|
1760
|
+
};
|
|
1761
|
+
|
|
1762
|
+
// Re-setup the getDestinationAgentId spy for conference methods
|
|
1763
|
+
getDestinationAgentIdSpy = jest
|
|
1764
|
+
.spyOn(Utils, 'getDestinationAgentId')
|
|
1765
|
+
.mockReturnValue(taskDataMock.destAgentId);
|
|
1766
|
+
|
|
1767
|
+
|
|
1768
|
+
task = new Task(contactMock, webCallingService, taskDataMock, {
|
|
1769
|
+
wrapUpProps: { wrapUpReasonList: [] },
|
|
1770
|
+
autoWrapEnabled: false,
|
|
1771
|
+
autoWrapAfterSeconds: 0
|
|
1772
|
+
}, taskDataMock.agentId);
|
|
1773
|
+
});
|
|
1774
|
+
|
|
1775
|
+
describe('consultConference', () => {
|
|
1776
|
+
|
|
1777
|
+
it('should successfully start conference and emit event', async () => {
|
|
1778
|
+
const mockResponse = {
|
|
1779
|
+
trackingId: 'test-tracking-id',
|
|
1780
|
+
interactionId: taskId,
|
|
1781
|
+
};
|
|
1782
|
+
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
1783
|
+
|
|
1784
|
+
|
|
1785
|
+
const result = await task.consultConference();
|
|
1786
|
+
|
|
1787
|
+
expect(contactMock.consultConference).toHaveBeenCalledWith({
|
|
1788
|
+
interactionId: taskId,
|
|
1789
|
+
data: {
|
|
1790
|
+
agentId: taskDataMock.agentId, // From task data agent ID
|
|
1791
|
+
to: taskDataMock.destAgentId, // From getDestinationAgentId() using task participants
|
|
1792
|
+
destinationType: 'agent', // From consultation data
|
|
1793
|
+
},
|
|
1794
|
+
});
|
|
1795
|
+
expect(result).toEqual(mockResponse);
|
|
1796
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith(`Initiating consult conference to ${taskDataMock.destAgentId}`, {
|
|
1797
|
+
module: TASK_FILE,
|
|
1798
|
+
method: 'consultConference',
|
|
1799
|
+
interactionId: taskId,
|
|
1800
|
+
});
|
|
1801
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Consult conference started successfully', {
|
|
1802
|
+
module: TASK_FILE,
|
|
1803
|
+
method: 'consultConference',
|
|
1804
|
+
interactionId: taskId,
|
|
1805
|
+
});
|
|
1806
|
+
});
|
|
1807
|
+
|
|
1808
|
+
it('should handle basic validation scenarios', async () => {
|
|
1809
|
+
// Agent Desktop logic validates data structure but not participant availability
|
|
1810
|
+
// This test confirms the method works with the Agent Desktop data flow
|
|
1811
|
+
const mockResponse = {
|
|
1812
|
+
trackingId: 'test-tracking-validation',
|
|
1813
|
+
interactionId: taskId,
|
|
1814
|
+
};
|
|
1815
|
+
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
1816
|
+
|
|
1817
|
+
const result = await task.consultConference();
|
|
1818
|
+
expect(result).toEqual(mockResponse);
|
|
1819
|
+
});
|
|
1820
|
+
|
|
1821
|
+
it('should handle and rethrow contact method errors', async () => {
|
|
1822
|
+
const mockError = new Error('Conference start failed');
|
|
1823
|
+
contactMock.consultConference.mockRejectedValue(mockError);
|
|
1824
|
+
generateTaskErrorObjectSpy.mockReturnValue(mockError);
|
|
1825
|
+
|
|
1826
|
+
await expect(task.consultConference()).rejects.toThrow('Conference start failed');
|
|
1827
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to start consult conference', {
|
|
1828
|
+
module: TASK_FILE,
|
|
1829
|
+
method: 'consultConference',
|
|
1830
|
+
interactionId: taskId,
|
|
1831
|
+
});
|
|
1832
|
+
});
|
|
1833
|
+
});
|
|
1834
|
+
|
|
1835
|
+
describe('exitConference', () => {
|
|
1836
|
+
it('should successfully end conference and emit event', async () => {
|
|
1837
|
+
const mockResponse = {
|
|
1838
|
+
trackingId: 'test-tracking-id-end',
|
|
1839
|
+
interactionId: taskId,
|
|
1840
|
+
};
|
|
1841
|
+
contactMock.exitConference.mockResolvedValue(mockResponse);
|
|
1842
|
+
|
|
1843
|
+
const result = await task.exitConference();
|
|
1844
|
+
|
|
1845
|
+
expect(contactMock.exitConference).toHaveBeenCalledWith({
|
|
1846
|
+
interactionId: taskId,
|
|
1847
|
+
});
|
|
1848
|
+
expect(result).toEqual(mockResponse);
|
|
1849
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Exiting consult conference', {
|
|
1850
|
+
module: TASK_FILE,
|
|
1851
|
+
method: 'exitConference',
|
|
1852
|
+
interactionId: taskId,
|
|
1853
|
+
});
|
|
1854
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Consult conference exited successfully', {
|
|
1855
|
+
module: TASK_FILE,
|
|
1856
|
+
method: 'exitConference',
|
|
1857
|
+
interactionId: taskId,
|
|
1858
|
+
});
|
|
1859
|
+
});
|
|
1860
|
+
|
|
1861
|
+
it('should throw error for invalid interaction ID', async () => {
|
|
1862
|
+
task.data.interactionId = '';
|
|
1863
|
+
|
|
1864
|
+
await expect(task.exitConference()).rejects.toThrow('Error while performing exitConference');
|
|
1865
|
+
expect(contactMock.exitConference).not.toHaveBeenCalled();
|
|
1866
|
+
});
|
|
1867
|
+
|
|
1868
|
+
it('should handle and rethrow contact method errors', async () => {
|
|
1869
|
+
const mockError = new Error('Conference end failed');
|
|
1870
|
+
contactMock.exitConference.mockRejectedValue(mockError);
|
|
1871
|
+
generateTaskErrorObjectSpy.mockReturnValue(mockError);
|
|
1872
|
+
|
|
1873
|
+
await expect(task.exitConference()).rejects.toThrow('Conference end failed');
|
|
1874
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to exit consult conference', {
|
|
1875
|
+
module: TASK_FILE,
|
|
1876
|
+
method: 'exitConference',
|
|
1877
|
+
interactionId: taskId,
|
|
1878
|
+
});
|
|
1879
|
+
});
|
|
1880
|
+
});
|
|
1881
|
+
|
|
1882
|
+
describe('transferConference', () => {
|
|
1883
|
+
it('should successfully transfer conference', async () => {
|
|
1884
|
+
const mockResponse = {
|
|
1885
|
+
trackingId: 'test-tracking-id-transfer',
|
|
1886
|
+
interactionId: taskId,
|
|
1887
|
+
};
|
|
1888
|
+
contactMock.conferenceTransfer.mockResolvedValue(mockResponse);
|
|
1889
|
+
|
|
1890
|
+
const result = await task.transferConference();
|
|
1891
|
+
|
|
1892
|
+
expect(contactMock.conferenceTransfer).toHaveBeenCalledWith({
|
|
1893
|
+
interactionId: taskId,
|
|
1894
|
+
});
|
|
1895
|
+
expect(result).toEqual(mockResponse);
|
|
1896
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Transferring conference', {
|
|
1897
|
+
module: TASK_FILE,
|
|
1898
|
+
method: 'transferConference',
|
|
1899
|
+
interactionId: taskId,
|
|
1900
|
+
});
|
|
1901
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Conference transferred successfully', {
|
|
1902
|
+
module: TASK_FILE,
|
|
1903
|
+
method: 'transferConference',
|
|
1904
|
+
interactionId: taskId,
|
|
1905
|
+
});
|
|
1906
|
+
});
|
|
1907
|
+
|
|
1908
|
+
it('should throw error for invalid interaction ID', async () => {
|
|
1909
|
+
task.data.interactionId = '';
|
|
1910
|
+
|
|
1911
|
+
await expect(task.transferConference()).rejects.toThrow('Error while performing transferConference');
|
|
1912
|
+
expect(contactMock.conferenceTransfer).not.toHaveBeenCalled();
|
|
1913
|
+
});
|
|
1914
|
+
|
|
1915
|
+
it('should handle and rethrow contact method errors', async () => {
|
|
1916
|
+
const mockError = new Error('Conference transfer failed');
|
|
1917
|
+
contactMock.conferenceTransfer.mockRejectedValue(mockError);
|
|
1918
|
+
generateTaskErrorObjectSpy.mockReturnValue(mockError);
|
|
1919
|
+
|
|
1920
|
+
await expect(task.transferConference()).rejects.toThrow('Conference transfer failed');
|
|
1921
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to transfer conference', {
|
|
1922
|
+
module: TASK_FILE,
|
|
1923
|
+
method: 'transferConference',
|
|
1924
|
+
interactionId: taskId,
|
|
1925
|
+
});
|
|
1926
|
+
});
|
|
1927
|
+
});
|
|
1928
|
+
});
|
|
1474
1929
|
});
|