@webex/contact-center 3.10.0-next.8 → 3.10.0-wxc-disconnect.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.
- package/dist/cc.js +1 -12
- package/dist/cc.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/config/types.js +2 -2
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Utils.js +71 -90
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/constants.js +1 -17
- package/dist/services/core/constants.js.map +1 -1
- package/dist/services/task/TaskManager.js +17 -89
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/constants.js +1 -20
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/index.js +98 -123
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +4 -2
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +0 -6
- package/dist/types/index.d.ts +1 -1
- package/dist/types/services/config/types.d.ts +4 -4
- package/dist/types/services/core/Utils.d.ts +17 -32
- package/dist/types/services/core/constants.d.ts +0 -14
- package/dist/types/services/task/constants.d.ts +0 -17
- package/dist/types/services/task/index.d.ts +2 -41
- package/dist/types/services/task/types.d.ts +33 -133
- package/dist/webex.js +1 -1
- package/package.json +9 -9
- package/src/cc.ts +1 -12
- package/src/index.ts +0 -1
- package/src/services/config/types.ts +2 -2
- package/src/services/core/Utils.ts +85 -101
- package/src/services/core/constants.ts +0 -16
- package/src/services/task/TaskManager.ts +15 -112
- package/src/services/task/constants.ts +0 -19
- package/src/services/task/index.ts +82 -108
- package/src/services/task/types.ts +33 -142
- package/test/unit/spec/services/core/Utils.ts +31 -262
- package/test/unit/spec/services/task/TaskManager.ts +6 -620
- package/test/unit/spec/services/task/index.ts +79 -502
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/TaskUtils.js +0 -104
- package/dist/services/task/TaskUtils.js.map +0 -1
- package/dist/types/services/task/TaskUtils.d.ts +0 -42
- package/src/services/task/TaskUtils.ts +0 -113
- package/test/unit/spec/services/task/TaskUtils.ts +0 -131
|
@@ -39,8 +39,7 @@ describe('Task', () => {
|
|
|
39
39
|
let loggerInfoSpy;
|
|
40
40
|
let loggerLogSpy;
|
|
41
41
|
let loggerErrorSpy;
|
|
42
|
-
let
|
|
43
|
-
let calculateDestTypeSpy;
|
|
42
|
+
let getDestinationAgentIdSpy;
|
|
44
43
|
|
|
45
44
|
const taskId = '0ae913a4-c857-4705-8d49-76dd3dde75e4';
|
|
46
45
|
const mockTrack = {} as MediaStreamTrack;
|
|
@@ -120,32 +119,6 @@ describe('Task', () => {
|
|
|
120
119
|
interaction: {
|
|
121
120
|
mediaType: 'telephony',
|
|
122
121
|
mainInteractionId: taskId,
|
|
123
|
-
participants: {
|
|
124
|
-
'723a8ffb-a26e-496d-b14a-ff44fb83b64f': {
|
|
125
|
-
pType: 'Agent',
|
|
126
|
-
type: 'AGENT',
|
|
127
|
-
id: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
128
|
-
hasLeft: false,
|
|
129
|
-
hasJoined: true,
|
|
130
|
-
isWrapUp: false,
|
|
131
|
-
},
|
|
132
|
-
'f520d6b5-28ad-4f2f-b83e-781bb64af617': {
|
|
133
|
-
pType: 'Agent',
|
|
134
|
-
type: 'AGENT',
|
|
135
|
-
id: 'f520d6b5-28ad-4f2f-b83e-781bb64af617',
|
|
136
|
-
hasLeft: false,
|
|
137
|
-
hasJoined: true,
|
|
138
|
-
isWrapUp: false,
|
|
139
|
-
},
|
|
140
|
-
'ebeb893b-ba67-4f36-8418-95c7492b28c2': {
|
|
141
|
-
pType: 'Agent',
|
|
142
|
-
type: 'AGENT',
|
|
143
|
-
id: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
|
|
144
|
-
hasLeft: false,
|
|
145
|
-
hasJoined: true,
|
|
146
|
-
isWrapUp: false,
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
122
|
media: {
|
|
150
123
|
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
151
124
|
holdTimestamp: null,
|
|
@@ -172,18 +145,13 @@ describe('Task', () => {
|
|
|
172
145
|
},
|
|
173
146
|
};
|
|
174
147
|
|
|
175
|
-
// Mock
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('agent');
|
|
148
|
+
// Mock destination agent id resolution from participants
|
|
149
|
+
getDestinationAgentIdSpy = jest
|
|
150
|
+
.spyOn(Utils, 'getDestinationAgentId')
|
|
151
|
+
.mockReturnValue(taskDataMock.destAgentId);
|
|
180
152
|
|
|
181
|
-
// Create an instance of Task
|
|
182
|
-
task = new Task(contactMock, webCallingService, taskDataMock
|
|
183
|
-
wrapUpProps: { wrapUpReasonList: [] },
|
|
184
|
-
autoWrapEnabled: false,
|
|
185
|
-
autoWrapAfterSeconds: 0
|
|
186
|
-
}, taskDataMock.agentId);
|
|
153
|
+
// Create an instance of Task
|
|
154
|
+
task = new Task(contactMock, webCallingService, taskDataMock);
|
|
187
155
|
|
|
188
156
|
// Mock navigator.mediaDevices
|
|
189
157
|
global.navigator.mediaDevices = {
|
|
@@ -249,7 +217,7 @@ describe('Task', () => {
|
|
|
249
217
|
});
|
|
250
218
|
|
|
251
219
|
describe('updateTaskData cases', () => {
|
|
252
|
-
it('
|
|
220
|
+
it('test updating the task data by overwrite', async () => {
|
|
253
221
|
const newData = {
|
|
254
222
|
type: CC_EVENTS.AGENT_CONTACT_ASSIGNED,
|
|
255
223
|
agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
@@ -298,12 +266,12 @@ describe('Task', () => {
|
|
|
298
266
|
expect(task.data).toEqual(newData);
|
|
299
267
|
});
|
|
300
268
|
|
|
301
|
-
it('
|
|
269
|
+
it('test updating the task data by merging', async () => {
|
|
302
270
|
const newData = {
|
|
303
|
-
// Purposefully omit
|
|
271
|
+
// ...taskDataMock, // Purposefully omit this to test scenario when other keys isn't present
|
|
304
272
|
isConsulting: true, // Add a new custom key to test persistence
|
|
305
273
|
interaction: {
|
|
306
|
-
// Purposefully omit
|
|
274
|
+
// ...taskDataMock.interaction, // Purposefully omit this to test scenario when a nested key isn't present
|
|
307
275
|
media: {
|
|
308
276
|
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
309
277
|
holdTimestamp: null,
|
|
@@ -330,12 +298,11 @@ describe('Task', () => {
|
|
|
330
298
|
},
|
|
331
299
|
};
|
|
332
300
|
|
|
333
|
-
// The reconcileData method removes keys from oldData that are not in newData
|
|
334
|
-
// This means only keys present in newData will remain in the final result
|
|
335
301
|
const expectedData: TaskData = {
|
|
336
|
-
|
|
302
|
+
...taskDataMock,
|
|
303
|
+
isConsulting: true,
|
|
337
304
|
interaction: {
|
|
338
|
-
|
|
305
|
+
...taskDataMock.interaction,
|
|
339
306
|
media: {
|
|
340
307
|
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
341
308
|
holdTimestamp: null,
|
|
@@ -368,60 +335,6 @@ describe('Task', () => {
|
|
|
368
335
|
|
|
369
336
|
expect(task.data).toEqual(expectedData);
|
|
370
337
|
});
|
|
371
|
-
|
|
372
|
-
it('updates the task data by merging and preserving existing keys', async () => {
|
|
373
|
-
const newData = {
|
|
374
|
-
...taskDataMock, // Include all existing keys to test merge without removal
|
|
375
|
-
isConsulting: true, // Add a new custom key
|
|
376
|
-
interaction: {
|
|
377
|
-
...taskDataMock.interaction, // Include existing interaction data
|
|
378
|
-
media: {
|
|
379
|
-
...taskDataMock.interaction.media, // Include existing media
|
|
380
|
-
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
381
|
-
holdTimestamp: null,
|
|
382
|
-
isHold: true,
|
|
383
|
-
mType: 'consult',
|
|
384
|
-
mediaMgr: 'callmm',
|
|
385
|
-
mediaResourceId: '58a45567-4e61-4f4b-a580-5bc86357bef0',
|
|
386
|
-
mediaType: 'telephony',
|
|
387
|
-
participants: [
|
|
388
|
-
'f520d6b5-28ad-4f2f-b83e-781bb64af617',
|
|
389
|
-
'723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
390
|
-
],
|
|
391
|
-
},
|
|
392
|
-
},
|
|
393
|
-
},
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
const expectedData: TaskData = {
|
|
397
|
-
...taskDataMock,
|
|
398
|
-
isConsulting: true,
|
|
399
|
-
interaction: {
|
|
400
|
-
...taskDataMock.interaction,
|
|
401
|
-
media: {
|
|
402
|
-
...taskDataMock.interaction.media,
|
|
403
|
-
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
404
|
-
holdTimestamp: null,
|
|
405
|
-
isHold: true,
|
|
406
|
-
mType: 'consult',
|
|
407
|
-
mediaMgr: 'callmm',
|
|
408
|
-
mediaResourceId: '58a45567-4e61-4f4b-a580-5bc86357bef0',
|
|
409
|
-
mediaType: 'telephony',
|
|
410
|
-
participants: [
|
|
411
|
-
'f520d6b5-28ad-4f2f-b83e-781bb64af617',
|
|
412
|
-
'723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
413
|
-
],
|
|
414
|
-
},
|
|
415
|
-
},
|
|
416
|
-
},
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
expect(task.data).toEqual(taskDataMock);
|
|
420
|
-
const shouldOverwrite = false;
|
|
421
|
-
task.updateTaskData(newData, shouldOverwrite);
|
|
422
|
-
|
|
423
|
-
expect(task.data).toEqual(expectedData);
|
|
424
|
-
});
|
|
425
338
|
});
|
|
426
339
|
|
|
427
340
|
it('should accept a task and answer call when using BROWSER login option', async () => {
|
|
@@ -657,40 +570,6 @@ describe('Task', () => {
|
|
|
657
570
|
);
|
|
658
571
|
});
|
|
659
572
|
|
|
660
|
-
it('should hold the task with custom mediaResourceId and return the expected response', async () => {
|
|
661
|
-
const customMediaResourceId = 'custom-media-resource-id-123';
|
|
662
|
-
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
663
|
-
contactMock.hold.mockResolvedValue(expectedResponse);
|
|
664
|
-
|
|
665
|
-
const response = await task.hold(customMediaResourceId);
|
|
666
|
-
|
|
667
|
-
expect(contactMock.hold).toHaveBeenCalledWith({
|
|
668
|
-
interactionId: taskId,
|
|
669
|
-
data: {mediaResourceId: customMediaResourceId},
|
|
670
|
-
});
|
|
671
|
-
expect(response).toEqual(expectedResponse);
|
|
672
|
-
expect(loggerInfoSpy).toHaveBeenCalledWith(`Holding task`, {
|
|
673
|
-
module: TASK_FILE,
|
|
674
|
-
method: 'hold',
|
|
675
|
-
interactionId: task.data.interactionId,
|
|
676
|
-
});
|
|
677
|
-
expect(loggerLogSpy).toHaveBeenCalledWith(`Task placed on hold successfully`, {
|
|
678
|
-
module: TASK_FILE,
|
|
679
|
-
method: 'hold',
|
|
680
|
-
interactionId: task.data.interactionId,
|
|
681
|
-
});
|
|
682
|
-
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
683
|
-
1,
|
|
684
|
-
METRIC_EVENT_NAMES.TASK_HOLD_SUCCESS,
|
|
685
|
-
{
|
|
686
|
-
...MetricsManager.getCommonTrackingFieldForAQMResponse(expectedResponse),
|
|
687
|
-
taskId: taskDataMock.interactionId,
|
|
688
|
-
mediaResourceId: customMediaResourceId,
|
|
689
|
-
},
|
|
690
|
-
['operational', 'behavioral']
|
|
691
|
-
);
|
|
692
|
-
});
|
|
693
|
-
|
|
694
573
|
it('should handle errors in hold method', async () => {
|
|
695
574
|
const error = {details: (global as any).makeFailure('Hold Failed')};
|
|
696
575
|
contactMock.hold.mockImplementation(() => {
|
|
@@ -720,36 +599,6 @@ describe('Task', () => {
|
|
|
720
599
|
);
|
|
721
600
|
});
|
|
722
601
|
|
|
723
|
-
it('should handle errors in hold method with custom mediaResourceId', async () => {
|
|
724
|
-
const customMediaResourceId = 'custom-media-resource-id-456';
|
|
725
|
-
const error = {details: (global as any).makeFailure('Hold Failed with custom mediaResourceId')};
|
|
726
|
-
contactMock.hold.mockImplementation(() => {
|
|
727
|
-
throw error;
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
await expect(task.hold(customMediaResourceId)).rejects.toThrow(error.details.data.reason);
|
|
731
|
-
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'hold', TASK_FILE);
|
|
732
|
-
const expectedTaskErrorFieldsHold = {
|
|
733
|
-
trackingId: error.details.trackingId,
|
|
734
|
-
errorMessage: error.details.data.reason,
|
|
735
|
-
errorType: '',
|
|
736
|
-
errorData: '',
|
|
737
|
-
reasonCode: 0,
|
|
738
|
-
};
|
|
739
|
-
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
740
|
-
1,
|
|
741
|
-
METRIC_EVENT_NAMES.TASK_HOLD_FAILED,
|
|
742
|
-
{
|
|
743
|
-
taskId: taskDataMock.interactionId,
|
|
744
|
-
mediaResourceId: customMediaResourceId,
|
|
745
|
-
error: error.toString(),
|
|
746
|
-
...expectedTaskErrorFieldsHold,
|
|
747
|
-
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
748
|
-
},
|
|
749
|
-
['operational', 'behavioral']
|
|
750
|
-
);
|
|
751
|
-
});
|
|
752
|
-
|
|
753
602
|
it('should resume the task and return the expected response', async () => {
|
|
754
603
|
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
755
604
|
contactMock.unHold.mockResolvedValue(expectedResponse);
|
|
@@ -774,29 +623,6 @@ describe('Task', () => {
|
|
|
774
623
|
);
|
|
775
624
|
});
|
|
776
625
|
|
|
777
|
-
it('should resume the task with custom mediaResourceId and return the expected response', async () => {
|
|
778
|
-
const customMediaResourceId = 'custom-media-resource-id-789';
|
|
779
|
-
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
780
|
-
contactMock.unHold.mockResolvedValue(expectedResponse);
|
|
781
|
-
const response = await task.resume(customMediaResourceId);
|
|
782
|
-
expect(contactMock.unHold).toHaveBeenCalledWith({
|
|
783
|
-
interactionId: taskId,
|
|
784
|
-
data: {mediaResourceId: customMediaResourceId},
|
|
785
|
-
});
|
|
786
|
-
expect(response).toEqual(expectedResponse);
|
|
787
|
-
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
788
|
-
1,
|
|
789
|
-
METRIC_EVENT_NAMES.TASK_RESUME_SUCCESS,
|
|
790
|
-
{
|
|
791
|
-
taskId: taskDataMock.interactionId,
|
|
792
|
-
mainInteractionId: taskDataMock.interaction.mainInteractionId,
|
|
793
|
-
mediaResourceId: customMediaResourceId,
|
|
794
|
-
...MetricsManager.getCommonTrackingFieldForAQMResponse(expectedResponse),
|
|
795
|
-
},
|
|
796
|
-
['operational', 'behavioral']
|
|
797
|
-
);
|
|
798
|
-
});
|
|
799
|
-
|
|
800
626
|
it('should handle errors in resume method', async () => {
|
|
801
627
|
const error = {details: (global as any).makeFailure('Resume Failed')};
|
|
802
628
|
contactMock.unHold.mockImplementation(() => {
|
|
@@ -828,36 +654,6 @@ describe('Task', () => {
|
|
|
828
654
|
);
|
|
829
655
|
});
|
|
830
656
|
|
|
831
|
-
it('should handle errors in resume method with custom mediaResourceId', async () => {
|
|
832
|
-
const customMediaResourceId = 'custom-media-resource-id-999';
|
|
833
|
-
const error = {details: (global as any).makeFailure('Resume Failed with custom mediaResourceId')};
|
|
834
|
-
contactMock.unHold.mockImplementation(() => {
|
|
835
|
-
throw error;
|
|
836
|
-
});
|
|
837
|
-
|
|
838
|
-
await expect(task.resume(customMediaResourceId)).rejects.toThrow(error.details.data.reason);
|
|
839
|
-
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'resume', TASK_FILE);
|
|
840
|
-
const expectedTaskErrorFieldsResume = {
|
|
841
|
-
trackingId: error.details.trackingId,
|
|
842
|
-
errorMessage: error.details.data.reason,
|
|
843
|
-
errorType: '',
|
|
844
|
-
errorData: '',
|
|
845
|
-
reasonCode: 0,
|
|
846
|
-
};
|
|
847
|
-
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
848
|
-
1,
|
|
849
|
-
METRIC_EVENT_NAMES.TASK_RESUME_FAILED,
|
|
850
|
-
{
|
|
851
|
-
taskId: taskDataMock.interactionId,
|
|
852
|
-
mainInteractionId: taskDataMock.interaction.mainInteractionId,
|
|
853
|
-
mediaResourceId: customMediaResourceId,
|
|
854
|
-
...expectedTaskErrorFieldsResume,
|
|
855
|
-
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
856
|
-
},
|
|
857
|
-
['operational', 'behavioral']
|
|
858
|
-
);
|
|
859
|
-
});
|
|
860
|
-
|
|
861
657
|
it('should initiate a consult call and return the expected response', async () => {
|
|
862
658
|
const consultPayload = {
|
|
863
659
|
to: '1234',
|
|
@@ -1025,16 +821,15 @@ describe('Task', () => {
|
|
|
1025
821
|
);
|
|
1026
822
|
});
|
|
1027
823
|
|
|
1028
|
-
it('should send DIALNUMBER when
|
|
824
|
+
it('should send DIALNUMBER when task destinationType is DN during consultTransfer', async () => {
|
|
1029
825
|
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
1030
826
|
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
1031
827
|
|
|
1032
|
-
//
|
|
1033
|
-
|
|
828
|
+
// Ensure task data indicates DN scenario
|
|
829
|
+
task.data.destinationType = 'DN' as unknown as string;
|
|
1034
830
|
|
|
1035
831
|
await task.consultTransfer();
|
|
1036
832
|
|
|
1037
|
-
expect(calculateDestTypeSpy).toHaveBeenCalledWith(taskDataMock.interaction, taskDataMock.agentId);
|
|
1038
833
|
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
1039
834
|
interactionId: taskId,
|
|
1040
835
|
data: {
|
|
@@ -1044,16 +839,15 @@ describe('Task', () => {
|
|
|
1044
839
|
});
|
|
1045
840
|
});
|
|
1046
841
|
|
|
1047
|
-
it('should send ENTRYPOINT when
|
|
842
|
+
it('should send ENTRYPOINT when task destinationType is EPDN during consultTransfer', async () => {
|
|
1048
843
|
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
1049
844
|
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
1050
845
|
|
|
1051
|
-
//
|
|
1052
|
-
|
|
846
|
+
// Ensure task data indicates EP/EPDN scenario
|
|
847
|
+
task.data.destinationType = 'EPDN' as unknown as string;
|
|
1053
848
|
|
|
1054
849
|
await task.consultTransfer();
|
|
1055
850
|
|
|
1056
|
-
expect(calculateDestTypeSpy).toHaveBeenCalledWith(taskDataMock.interaction, taskDataMock.agentId);
|
|
1057
851
|
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
1058
852
|
interactionId: taskId,
|
|
1059
853
|
data: {
|
|
@@ -1063,16 +857,15 @@ describe('Task', () => {
|
|
|
1063
857
|
});
|
|
1064
858
|
});
|
|
1065
859
|
|
|
1066
|
-
it('should
|
|
860
|
+
it('should keep AGENT when task destinationType is neither DN nor EPDN/ENTRYPOINT', async () => {
|
|
1067
861
|
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
1068
862
|
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
1069
863
|
|
|
1070
|
-
//
|
|
1071
|
-
|
|
864
|
+
// Ensure task data indicates non-DN and non-EP/EPDN scenario
|
|
865
|
+
task.data.destinationType = 'SOMETHING_ELSE' as unknown as string;
|
|
1072
866
|
|
|
1073
867
|
await task.consultTransfer();
|
|
1074
868
|
|
|
1075
|
-
expect(calculateDestTypeSpy).toHaveBeenCalledWith(taskDataMock.interaction, taskDataMock.agentId);
|
|
1076
869
|
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
1077
870
|
interactionId: taskId,
|
|
1078
871
|
data: {
|
|
@@ -1109,11 +902,7 @@ describe('Task', () => {
|
|
|
1109
902
|
const taskWithoutDestAgentId = new Task(contactMock, webCallingService, {
|
|
1110
903
|
...taskDataMock,
|
|
1111
904
|
destAgentId: undefined,
|
|
1112
|
-
}
|
|
1113
|
-
wrapUpProps: { wrapUpReasonList: [] },
|
|
1114
|
-
autoWrapEnabled: false,
|
|
1115
|
-
autoWrapAfterSeconds: 0
|
|
1116
|
-
}, taskDataMock.agentId);
|
|
905
|
+
});
|
|
1117
906
|
|
|
1118
907
|
const queueConsultTransferPayload: ConsultTransferPayLoad = {
|
|
1119
908
|
to: 'some-queue-id',
|
|
@@ -1121,123 +910,61 @@ describe('Task', () => {
|
|
|
1121
910
|
};
|
|
1122
911
|
|
|
1123
912
|
// For this negative case, ensure computed destination is empty
|
|
1124
|
-
|
|
913
|
+
getDestinationAgentIdSpy.mockReturnValueOnce('');
|
|
1125
914
|
|
|
1126
915
|
await expect(
|
|
1127
916
|
taskWithoutDestAgentId.consultTransfer(queueConsultTransferPayload)
|
|
1128
|
-
).rejects.toThrow('
|
|
917
|
+
).rejects.toThrow('Error while performing consultTransfer');
|
|
1129
918
|
});
|
|
1130
919
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
calculateDestTypeSpy.mockReturnValue(CONSULT_TRANSFER_DESTINATION_TYPE.AGENT);
|
|
920
|
+
it('should handle errors in consult transfer', async () => {
|
|
921
|
+
const consultPayload = {
|
|
922
|
+
destination: '1234',
|
|
923
|
+
destinationType: DESTINATION_TYPE.AGENT,
|
|
924
|
+
};
|
|
925
|
+
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
926
|
+
contactMock.consult.mockResolvedValue(expectedResponse);
|
|
1140
927
|
|
|
1141
|
-
|
|
928
|
+
const response = await task.consult(consultPayload);
|
|
1142
929
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
1146
|
-
interactionId: taskId,
|
|
1147
|
-
data: {
|
|
1148
|
-
to: taskDataMock.destAgentId,
|
|
1149
|
-
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
1150
|
-
},
|
|
1151
|
-
});
|
|
1152
|
-
expect(result).toEqual(expectedResponse);
|
|
1153
|
-
expect(loggerInfoSpy).toHaveBeenCalledWith(
|
|
1154
|
-
`Initiating consult transfer to ${taskDataMock.destAgentId}`,
|
|
1155
|
-
{
|
|
1156
|
-
module: TASK_FILE,
|
|
1157
|
-
method: 'consultTransfer',
|
|
1158
|
-
interactionId: taskId,
|
|
1159
|
-
}
|
|
1160
|
-
);
|
|
1161
|
-
expect(loggerLogSpy).toHaveBeenCalledWith(
|
|
1162
|
-
`Consult transfer completed successfully to ${taskDataMock.destAgentId}`,
|
|
1163
|
-
{
|
|
1164
|
-
module: TASK_FILE,
|
|
1165
|
-
method: 'consultTransfer',
|
|
1166
|
-
trackingId: expectedResponse.trackingId,
|
|
1167
|
-
interactionId: taskId,
|
|
1168
|
-
}
|
|
1169
|
-
);
|
|
1170
|
-
});
|
|
1171
|
-
|
|
1172
|
-
it('should track metrics on successful consult transfer', async () => {
|
|
1173
|
-
const expectedResponse: TaskResponse = {
|
|
1174
|
-
data: {interactionId: taskId},
|
|
1175
|
-
trackingId: 'test-tracking-id'
|
|
1176
|
-
} as AgentContact;
|
|
1177
|
-
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
1178
|
-
|
|
1179
|
-
await task.consultTransfer();
|
|
1180
|
-
|
|
1181
|
-
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
1182
|
-
METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS,
|
|
1183
|
-
{
|
|
1184
|
-
taskId: taskDataMock.interactionId,
|
|
1185
|
-
destination: taskDataMock.destAgentId,
|
|
1186
|
-
destinationType: 'agent',
|
|
1187
|
-
isConsultTransfer: true,
|
|
1188
|
-
...MetricsManager.getCommonTrackingFieldForAQMResponse(expectedResponse),
|
|
1189
|
-
},
|
|
1190
|
-
['operational', 'behavioral', 'business']
|
|
1191
|
-
);
|
|
1192
|
-
});
|
|
930
|
+
expect(contactMock.consult).toHaveBeenCalledWith({interactionId: taskId, data: consultPayload});
|
|
931
|
+
expect(response).toEqual(expectedResponse);
|
|
1193
932
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
await expect(task.consultTransfer()).rejects.toThrow('No agent has accepted this queue consult yet');
|
|
1198
|
-
|
|
1199
|
-
expect(contactMock.consultTransfer).not.toHaveBeenCalled();
|
|
933
|
+
const error = {details: (global as any).makeFailure('Consult Transfer Failed')};
|
|
934
|
+
contactMock.consultTransfer.mockImplementation(() => {
|
|
935
|
+
throw error;
|
|
1200
936
|
});
|
|
1201
937
|
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
await expect(task.consultTransfer()).rejects.toThrow('Consult Transfer Failed');
|
|
1208
|
-
|
|
1209
|
-
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(mockError, 'consultTransfer', TASK_FILE);
|
|
1210
|
-
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
1211
|
-
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
1212
|
-
expect.objectContaining({
|
|
1213
|
-
taskId: taskDataMock.interactionId,
|
|
1214
|
-
destination: taskDataMock.destAgentId,
|
|
1215
|
-
destinationType: 'agent',
|
|
1216
|
-
isConsultTransfer: true,
|
|
1217
|
-
error: mockError.toString(),
|
|
1218
|
-
}),
|
|
1219
|
-
['operational', 'behavioral', 'business']
|
|
1220
|
-
);
|
|
1221
|
-
});
|
|
1222
|
-
|
|
1223
|
-
it('should dynamically calculate destAgentId when not available', async () => {
|
|
1224
|
-
const consultedAgentId = 'dynamic-agent-123';
|
|
1225
|
-
calculateDestAgentIdSpy.mockReturnValue(consultedAgentId);
|
|
1226
|
-
|
|
1227
|
-
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
1228
|
-
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
1229
|
-
|
|
1230
|
-
await task.consultTransfer();
|
|
938
|
+
const consultTransferPayload: ConsultTransferPayLoad = {
|
|
939
|
+
to: '1234',
|
|
940
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
941
|
+
};
|
|
1231
942
|
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
943
|
+
await expect(task.consultTransfer(consultTransferPayload)).rejects.toThrow(
|
|
944
|
+
error.details.data.reason
|
|
945
|
+
);
|
|
946
|
+
expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'consultTransfer', TASK_FILE);
|
|
947
|
+
const expectedTaskErrorFieldsConsultTransfer = {
|
|
948
|
+
trackingId: error.details.trackingId,
|
|
949
|
+
errorMessage: error.details.data.reason,
|
|
950
|
+
errorType: '',
|
|
951
|
+
errorData: '',
|
|
952
|
+
reasonCode: 0,
|
|
953
|
+
};
|
|
954
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
955
|
+
2,
|
|
956
|
+
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
957
|
+
{
|
|
958
|
+
taskId: taskDataMock.interactionId,
|
|
959
|
+
destination: taskDataMock.destAgentId,
|
|
960
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
961
|
+
isConsultTransfer: true,
|
|
962
|
+
error: error.toString(),
|
|
963
|
+
...expectedTaskErrorFieldsConsultTransfer,
|
|
964
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|
|
965
|
+
},
|
|
966
|
+
['operational', 'behavioral', 'business']
|
|
967
|
+
);
|
|
1241
968
|
});
|
|
1242
969
|
|
|
1243
970
|
it('should do vteamTransfer if destinationType is queue and return the expected response', async () => {
|
|
@@ -1860,6 +1587,12 @@ describe('Task', () => {
|
|
|
1860
1587
|
conferenceTransfer: jest.fn(),
|
|
1861
1588
|
};
|
|
1862
1589
|
|
|
1590
|
+
// Re-setup the getDestinationAgentId spy for conference methods
|
|
1591
|
+
getDestinationAgentIdSpy = jest
|
|
1592
|
+
.spyOn(Utils, 'getDestinationAgentId')
|
|
1593
|
+
.mockReturnValue(taskDataMock.destAgentId);
|
|
1594
|
+
|
|
1595
|
+
|
|
1863
1596
|
task = new Task(contactMock, webCallingService, taskDataMock, {
|
|
1864
1597
|
wrapUpProps: { wrapUpReasonList: [] },
|
|
1865
1598
|
autoWrapEnabled: false,
|
|
@@ -1883,7 +1616,7 @@ describe('Task', () => {
|
|
|
1883
1616
|
interactionId: taskId,
|
|
1884
1617
|
data: {
|
|
1885
1618
|
agentId: taskDataMock.agentId, // From task data agent ID
|
|
1886
|
-
to: taskDataMock.destAgentId, // From
|
|
1619
|
+
to: taskDataMock.destAgentId, // From getDestinationAgentId() using task participants
|
|
1887
1620
|
destinationType: 'agent', // From consultation data
|
|
1888
1621
|
},
|
|
1889
1622
|
});
|
|
@@ -1925,166 +1658,6 @@ describe('Task', () => {
|
|
|
1925
1658
|
interactionId: taskId,
|
|
1926
1659
|
});
|
|
1927
1660
|
});
|
|
1928
|
-
|
|
1929
|
-
it('should dynamically calculate destAgentId from participants when this.data.destAgentId is null', async () => {
|
|
1930
|
-
// Simulate scenario where destAgentId is not preserved (e.g., after hold/unhold)
|
|
1931
|
-
task.data.destAgentId = null;
|
|
1932
|
-
|
|
1933
|
-
const consultedAgentId = 'consulted-agent-123';
|
|
1934
|
-
calculateDestAgentIdSpy.mockReturnValue(consultedAgentId);
|
|
1935
|
-
|
|
1936
|
-
const mockResponse = {
|
|
1937
|
-
trackingId: 'test-tracking-dynamic',
|
|
1938
|
-
interactionId: taskId,
|
|
1939
|
-
};
|
|
1940
|
-
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
1941
|
-
|
|
1942
|
-
const result = await task.consultConference();
|
|
1943
|
-
|
|
1944
|
-
// Verify calculateDestAgentId was called to dynamically calculate the destination
|
|
1945
|
-
expect(calculateDestAgentIdSpy).toHaveBeenCalledWith(
|
|
1946
|
-
taskDataMock.interaction,
|
|
1947
|
-
taskDataMock.agentId
|
|
1948
|
-
);
|
|
1949
|
-
|
|
1950
|
-
// Verify the conference was called with the dynamically calculated destAgentId
|
|
1951
|
-
expect(contactMock.consultConference).toHaveBeenCalledWith({
|
|
1952
|
-
interactionId: taskId,
|
|
1953
|
-
data: {
|
|
1954
|
-
agentId: taskDataMock.agentId,
|
|
1955
|
-
to: consultedAgentId, // Dynamically calculated value
|
|
1956
|
-
destinationType: 'agent',
|
|
1957
|
-
},
|
|
1958
|
-
});
|
|
1959
|
-
expect(result).toEqual(mockResponse);
|
|
1960
|
-
});
|
|
1961
|
-
|
|
1962
|
-
it('should throw error when no destination agent is found (queue consult not accepted)', async () => {
|
|
1963
|
-
// Simulate queue consult scenario where no agent has accepted yet
|
|
1964
|
-
calculateDestAgentIdSpy.mockReturnValue(''); // No agent found
|
|
1965
|
-
|
|
1966
|
-
await expect(task.consultConference()).rejects.toThrow('No agent has accepted this queue consult yet');
|
|
1967
|
-
|
|
1968
|
-
// Verify the conference was NOT called
|
|
1969
|
-
expect(contactMock.consultConference).not.toHaveBeenCalled();
|
|
1970
|
-
});
|
|
1971
|
-
|
|
1972
|
-
it('should calculate destination type from participant type for regular agents', async () => {
|
|
1973
|
-
const destAgentId = 'consulted-agent-456';
|
|
1974
|
-
|
|
1975
|
-
calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
|
|
1976
|
-
calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('agent');
|
|
1977
|
-
|
|
1978
|
-
const mockResponse = {trackingId: 'test-tracking-id', interactionId: taskId};
|
|
1979
|
-
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
1980
|
-
|
|
1981
|
-
await task.consultConference();
|
|
1982
|
-
|
|
1983
|
-
expect(calculateDestTypeSpy).toHaveBeenCalledWith(
|
|
1984
|
-
task.data.interaction,
|
|
1985
|
-
taskDataMock.agentId
|
|
1986
|
-
);
|
|
1987
|
-
|
|
1988
|
-
expect(contactMock.consultConference).toHaveBeenCalledWith({
|
|
1989
|
-
interactionId: taskId,
|
|
1990
|
-
data: {
|
|
1991
|
-
agentId: taskDataMock.agentId,
|
|
1992
|
-
to: destAgentId,
|
|
1993
|
-
destinationType: 'agent',
|
|
1994
|
-
},
|
|
1995
|
-
});
|
|
1996
|
-
});
|
|
1997
|
-
|
|
1998
|
-
it('should use DN destination type for dial number participants', async () => {
|
|
1999
|
-
const destAgentId = 'dn-uuid-123';
|
|
2000
|
-
|
|
2001
|
-
calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
|
|
2002
|
-
calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('dialNumber');
|
|
2003
|
-
|
|
2004
|
-
const mockResponse = {trackingId: 'test-tracking-id-dn', interactionId: taskId};
|
|
2005
|
-
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
2006
|
-
|
|
2007
|
-
await task.consultConference();
|
|
2008
|
-
|
|
2009
|
-
expect(contactMock.consultConference).toHaveBeenCalledWith({
|
|
2010
|
-
interactionId: taskId,
|
|
2011
|
-
data: {
|
|
2012
|
-
agentId: taskDataMock.agentId,
|
|
2013
|
-
to: destAgentId,
|
|
2014
|
-
destinationType: 'dialNumber',
|
|
2015
|
-
},
|
|
2016
|
-
});
|
|
2017
|
-
});
|
|
2018
|
-
|
|
2019
|
-
it('should use EpDn destination type for entry point dial number participants', async () => {
|
|
2020
|
-
const destAgentId = 'epdn-uuid-456';
|
|
2021
|
-
|
|
2022
|
-
calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
|
|
2023
|
-
calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('entryPoint');
|
|
2024
|
-
|
|
2025
|
-
const mockResponse = {trackingId: 'test-tracking-id-epdn', interactionId: taskId};
|
|
2026
|
-
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
2027
|
-
|
|
2028
|
-
await task.consultConference();
|
|
2029
|
-
|
|
2030
|
-
expect(contactMock.consultConference).toHaveBeenCalledWith({
|
|
2031
|
-
interactionId: taskId,
|
|
2032
|
-
data: {
|
|
2033
|
-
agentId: taskDataMock.agentId,
|
|
2034
|
-
to: destAgentId,
|
|
2035
|
-
destinationType: 'entryPoint',
|
|
2036
|
-
},
|
|
2037
|
-
});
|
|
2038
|
-
});
|
|
2039
|
-
|
|
2040
|
-
it('should fall back to task.data.destinationType when calculateDestType returns empty', async () => {
|
|
2041
|
-
const destAgentId = 'consulted-agent-789';
|
|
2042
|
-
|
|
2043
|
-
calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
|
|
2044
|
-
calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue(''); // No type found
|
|
2045
|
-
|
|
2046
|
-
task.data.destinationType = 'EPDN';
|
|
2047
|
-
|
|
2048
|
-
const mockResponse = {trackingId: 'test-tracking-id-fallback', interactionId: taskId};
|
|
2049
|
-
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
2050
|
-
|
|
2051
|
-
await task.consultConference();
|
|
2052
|
-
|
|
2053
|
-
expect(contactMock.consultConference).toHaveBeenCalledWith({
|
|
2054
|
-
interactionId: taskId,
|
|
2055
|
-
data: {
|
|
2056
|
-
agentId: taskDataMock.agentId,
|
|
2057
|
-
to: destAgentId,
|
|
2058
|
-
destinationType: 'EPDN', // Falls back to task.data.destinationType
|
|
2059
|
-
},
|
|
2060
|
-
});
|
|
2061
|
-
});
|
|
2062
|
-
|
|
2063
|
-
it('should handle CBT scenarios with correct destination type', async () => {
|
|
2064
|
-
const destAgentId = 'agent-cbt-uuid';
|
|
2065
|
-
|
|
2066
|
-
calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
|
|
2067
|
-
calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('dialNumber');
|
|
2068
|
-
|
|
2069
|
-
const mockResponse = {trackingId: 'test-tracking-id-cbt', interactionId: taskId};
|
|
2070
|
-
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
2071
|
-
|
|
2072
|
-
await task.consultConference();
|
|
2073
|
-
|
|
2074
|
-
expect(calculateDestTypeSpy).toHaveBeenCalledWith(
|
|
2075
|
-
task.data.interaction,
|
|
2076
|
-
taskDataMock.agentId
|
|
2077
|
-
);
|
|
2078
|
-
|
|
2079
|
-
expect(contactMock.consultConference).toHaveBeenCalledWith({
|
|
2080
|
-
interactionId: taskId,
|
|
2081
|
-
data: {
|
|
2082
|
-
agentId: taskDataMock.agentId,
|
|
2083
|
-
to: destAgentId,
|
|
2084
|
-
destinationType: 'dialNumber', // dialNumber for CBT scenarios
|
|
2085
|
-
},
|
|
2086
|
-
});
|
|
2087
|
-
});
|
|
2088
1661
|
});
|
|
2089
1662
|
|
|
2090
1663
|
describe('exitConference', () => {
|
|
@@ -2134,6 +1707,9 @@ describe('Task', () => {
|
|
|
2134
1707
|
});
|
|
2135
1708
|
});
|
|
2136
1709
|
|
|
1710
|
+
// TODO: Uncomment this test section in future PR for Multi-Party Conference support (>3 participants)
|
|
1711
|
+
// Conference transfer tests will be uncommented when implementing enhanced multi-party conference functionality
|
|
1712
|
+
/*
|
|
2137
1713
|
describe('transferConference', () => {
|
|
2138
1714
|
it('should successfully transfer conference', async () => {
|
|
2139
1715
|
const mockResponse = {
|
|
@@ -2180,5 +1756,6 @@ describe('Task', () => {
|
|
|
2180
1756
|
});
|
|
2181
1757
|
});
|
|
2182
1758
|
});
|
|
1759
|
+
*/
|
|
2183
1760
|
});
|
|
2184
1761
|
});
|