@webex/contact-center 3.9.0-next.10 → 3.9.0-next.11
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 -0
- package/dist/cc.js.map +1 -1
- package/dist/metrics/behavioral-events.js +37 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +14 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/config/types.js +22 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Utils.js +42 -1
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/task/TaskManager.js +73 -2
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/constants.js +7 -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 +239 -1
- 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/metrics/constants.d.ts +13 -0
- package/dist/types/services/config/types.d.ts +44 -0
- package/dist/types/services/core/Utils.d.ts +14 -1
- package/dist/types/services/task/constants.d.ts +6 -0
- package/dist/types/services/task/contact.d.ts +10 -0
- package/dist/types/services/task/index.d.ts +43 -1
- package/dist/types/services/task/types.d.ts +123 -1
- package/dist/webex.js +1 -1
- package/package.json +1 -1
- package/src/cc.ts +1 -0
- package/src/metrics/behavioral-events.ts +38 -0
- package/src/metrics/constants.ts +15 -0
- package/src/services/config/types.ts +22 -0
- package/src/services/core/Utils.ts +44 -0
- package/src/services/task/TaskManager.ts +78 -3
- package/src/services/task/constants.ts +6 -0
- package/src/services/task/contact.ts +80 -0
- package/src/services/task/index.ts +285 -1
- package/src/services/task/types.ts +133 -0
- package/test/unit/spec/cc.ts +1 -0
- package/test/unit/spec/metrics/behavioral-events.ts +42 -0
- package/test/unit/spec/services/task/TaskManager.ts +137 -0
- package/test/unit/spec/services/task/contact.ts +31 -1
- package/test/unit/spec/services/task/index.ts +184 -1
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -370,6 +370,126 @@ export enum TASK_EVENTS {
|
|
|
370
370
|
* ```
|
|
371
371
|
*/
|
|
372
372
|
TASK_OFFER_CONTACT = 'task:offerContact',
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Triggered when a conference is being established
|
|
376
|
+
* @example
|
|
377
|
+
* ```typescript
|
|
378
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_ESTABLISHING, (task: ITask) => {
|
|
379
|
+
* console.log('Conference establishing:', task.data.interactionId);
|
|
380
|
+
* // Handle conference setup in progress
|
|
381
|
+
* });
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
TASK_CONFERENCE_ESTABLISHING = 'task:conferenceEstablishing',
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Triggered when a conference is started successfully
|
|
388
|
+
* @example
|
|
389
|
+
* ```typescript
|
|
390
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_STARTED, (task: ITask) => {
|
|
391
|
+
* console.log('Conference started:', task.data.interactionId);
|
|
392
|
+
* // Handle conference start
|
|
393
|
+
* });
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
TASK_CONFERENCE_STARTED = 'task:conferenceStarted',
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Triggered when a conference fails to start
|
|
400
|
+
* @example
|
|
401
|
+
* ```typescript
|
|
402
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_FAILED, (task: ITask) => {
|
|
403
|
+
* console.log('Conference failed:', task.data.interactionId);
|
|
404
|
+
* // Handle conference failure
|
|
405
|
+
* });
|
|
406
|
+
* ```
|
|
407
|
+
*/
|
|
408
|
+
TASK_CONFERENCE_FAILED = 'task:conferenceFailed',
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Triggered when a conference is ended successfully
|
|
412
|
+
* @example
|
|
413
|
+
* ```typescript
|
|
414
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_ENDED, (task: ITask) => {
|
|
415
|
+
* console.log('Conference ended:', task.data.interactionId);
|
|
416
|
+
* // Handle conference end
|
|
417
|
+
* });
|
|
418
|
+
* ```
|
|
419
|
+
*/
|
|
420
|
+
TASK_CONFERENCE_ENDED = 'task:conferenceEnded',
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Triggered when a participant joins the conference
|
|
424
|
+
* @example
|
|
425
|
+
* ```typescript
|
|
426
|
+
* task.on(TASK_EVENTS.TASK_PARTICIPANT_JOINED, (task: ITask) => {
|
|
427
|
+
* console.log('Participant joined conference:', task.data.interactionId);
|
|
428
|
+
* // Handle participant joining
|
|
429
|
+
* });
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
TASK_PARTICIPANT_JOINED = 'task:participantJoined',
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Triggered when a participant leaves the conference
|
|
436
|
+
* @example
|
|
437
|
+
* ```typescript
|
|
438
|
+
* task.on(TASK_EVENTS.TASK_PARTICIPANT_LEFT, (task: ITask) => {
|
|
439
|
+
* console.log('Participant left conference:', task.data.interactionId);
|
|
440
|
+
* // Handle participant leaving
|
|
441
|
+
* });
|
|
442
|
+
* ```
|
|
443
|
+
*/
|
|
444
|
+
TASK_PARTICIPANT_LEFT = 'task:participantLeft',
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Triggered when conference transfer is successful
|
|
448
|
+
* @example
|
|
449
|
+
* ```typescript
|
|
450
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_TRANSFERRED, (task: ITask) => {
|
|
451
|
+
* console.log('Conference transferred:', task.data.interactionId);
|
|
452
|
+
* // Handle successful conference transfer
|
|
453
|
+
* });
|
|
454
|
+
* ```
|
|
455
|
+
*/
|
|
456
|
+
TASK_CONFERENCE_TRANSFERRED = 'task:conferenceTransferred',
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Triggered when conference transfer fails
|
|
460
|
+
* @example
|
|
461
|
+
* ```typescript
|
|
462
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_TRANSFER_FAILED, (task: ITask) => {
|
|
463
|
+
* console.log('Conference transfer failed:', task.data.interactionId);
|
|
464
|
+
* // Handle failed conference transfer
|
|
465
|
+
* });
|
|
466
|
+
* ```
|
|
467
|
+
*/
|
|
468
|
+
TASK_CONFERENCE_TRANSFER_FAILED = 'task:conferenceTransferFailed',
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Triggered when ending a conference fails
|
|
472
|
+
* @example
|
|
473
|
+
* ```typescript
|
|
474
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_END_FAILED, (task: ITask) => {
|
|
475
|
+
* console.log('Conference end failed:', task.data.interactionId);
|
|
476
|
+
* // Handle failed conference end
|
|
477
|
+
* });
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
TASK_CONFERENCE_END_FAILED = 'task:conferenceEndFailed',
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Triggered when participant exit from conference fails
|
|
484
|
+
* @example
|
|
485
|
+
* ```typescript
|
|
486
|
+
* task.on(TASK_EVENTS.TASK_PARTICIPANT_LEFT_FAILED, (task: ITask) => {
|
|
487
|
+
* console.log('Participant failed to leave conference:', task.data.interactionId);
|
|
488
|
+
* // Handle failed participant exit
|
|
489
|
+
* });
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
TASK_PARTICIPANT_LEFT_FAILED = 'task:participantLeftFailed',
|
|
373
493
|
}
|
|
374
494
|
|
|
375
495
|
/**
|
|
@@ -883,6 +1003,19 @@ export type ConsultConferenceData = {
|
|
|
883
1003
|
destinationType: string;
|
|
884
1004
|
};
|
|
885
1005
|
|
|
1006
|
+
/**
|
|
1007
|
+
* Legacy consultation conference data type matching Agent Desktop
|
|
1008
|
+
* @public
|
|
1009
|
+
*/
|
|
1010
|
+
export type consultConferencePayloadData = {
|
|
1011
|
+
/** Identifier of the agent initiating consult/conference */
|
|
1012
|
+
agentId: string;
|
|
1013
|
+
/** Type of destination (e.g., 'agent', 'queue') */
|
|
1014
|
+
destinationType: string;
|
|
1015
|
+
/** Identifier of the destination agent */
|
|
1016
|
+
destAgentId: string;
|
|
1017
|
+
};
|
|
1018
|
+
|
|
886
1019
|
/**
|
|
887
1020
|
* Parameters required for cancelling a consult to queue operation
|
|
888
1021
|
* @public
|
package/test/unit/spec/cc.ts
CHANGED
|
@@ -139,6 +139,7 @@ describe('webex.cc', () => {
|
|
|
139
139
|
webSocketManager: mockWebSocketManager,
|
|
140
140
|
task: undefined,
|
|
141
141
|
setWrapupData: jest.fn(),
|
|
142
|
+
setAgentId: jest.fn(),
|
|
142
143
|
registerIncomingCallEvent: jest.fn(),
|
|
143
144
|
registerTaskListeners: jest.fn(),
|
|
144
145
|
getTask: jest.fn(),
|
|
@@ -110,6 +110,48 @@ describe('metrics/behavioral-events', () => {
|
|
|
110
110
|
verb: 'fail',
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
+
expect(getEventTaxonomy(METRIC_EVENT_NAMES.TASK_CONFERENCE_START_SUCCESS)).toEqual({
|
|
114
|
+
product,
|
|
115
|
+
agent: 'user',
|
|
116
|
+
target: 'task_conference_start',
|
|
117
|
+
verb: 'complete',
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(getEventTaxonomy(METRIC_EVENT_NAMES.TASK_CONFERENCE_START_FAILED)).toEqual({
|
|
121
|
+
product,
|
|
122
|
+
agent: 'user',
|
|
123
|
+
target: 'task_conference_start',
|
|
124
|
+
verb: 'fail',
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(getEventTaxonomy(METRIC_EVENT_NAMES.TASK_CONFERENCE_END_SUCCESS)).toEqual({
|
|
128
|
+
product,
|
|
129
|
+
agent: 'user',
|
|
130
|
+
target: 'task_conference_end',
|
|
131
|
+
verb: 'complete',
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
expect(getEventTaxonomy(METRIC_EVENT_NAMES.TASK_CONFERENCE_END_FAILED)).toEqual({
|
|
135
|
+
product,
|
|
136
|
+
agent: 'user',
|
|
137
|
+
target: 'task_conference_end',
|
|
138
|
+
verb: 'fail',
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
expect(getEventTaxonomy(METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_SUCCESS)).toEqual({
|
|
142
|
+
product,
|
|
143
|
+
agent: 'user',
|
|
144
|
+
target: 'task_conference_transfer',
|
|
145
|
+
verb: 'complete',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
expect(getEventTaxonomy(METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_FAILED)).toEqual({
|
|
149
|
+
product,
|
|
150
|
+
agent: 'user',
|
|
151
|
+
target: 'task_conference_transfer',
|
|
152
|
+
verb: 'fail',
|
|
153
|
+
});
|
|
154
|
+
|
|
113
155
|
expect(getEventTaxonomy('' as METRIC_EVENT_NAMES)).toEqual(undefined);
|
|
114
156
|
});
|
|
115
157
|
});
|
|
@@ -1353,6 +1353,143 @@ describe('TaskManager', () => {
|
|
|
1353
1353
|
expect(spy).toHaveBeenCalledWith(taskEvent, task);
|
|
1354
1354
|
});
|
|
1355
1355
|
});
|
|
1356
|
+
});
|
|
1357
|
+
|
|
1358
|
+
describe('Conference event handling', () => {
|
|
1359
|
+
let task;
|
|
1360
|
+
|
|
1361
|
+
beforeEach(() => {
|
|
1362
|
+
task = {
|
|
1363
|
+
data: { interactionId: taskId },
|
|
1364
|
+
emit: jest.fn(),
|
|
1365
|
+
updateTaskData: jest.fn().mockImplementation((updatedData) => {
|
|
1366
|
+
// Mock the updateTaskData method to actually update task.data
|
|
1367
|
+
task.data = { ...task.data, ...updatedData };
|
|
1368
|
+
return task;
|
|
1369
|
+
}),
|
|
1370
|
+
};
|
|
1371
|
+
taskManager.taskCollection[taskId] = task;
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
it('should handle AGENT_CONSULT_CONFERENCED event', () => {
|
|
1375
|
+
const payload = {
|
|
1376
|
+
data: {
|
|
1377
|
+
type: CC_EVENTS.AGENT_CONSULT_CONFERENCED,
|
|
1378
|
+
interactionId: taskId,
|
|
1379
|
+
isConferencing: true,
|
|
1380
|
+
},
|
|
1381
|
+
};
|
|
1382
|
+
|
|
1383
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1384
|
+
|
|
1385
|
+
expect(task.data.isConferencing).toBe(true);
|
|
1386
|
+
expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
|
|
1387
|
+
});
|
|
1388
|
+
|
|
1389
|
+
it('should handle AGENT_CONSULT_CONFERENCING event', () => {
|
|
1390
|
+
const payload = {
|
|
1391
|
+
data: {
|
|
1392
|
+
type: CC_EVENTS.AGENT_CONSULT_CONFERENCING,
|
|
1393
|
+
interactionId: taskId,
|
|
1394
|
+
isConferencing: true,
|
|
1395
|
+
},
|
|
1396
|
+
};
|
|
1397
|
+
|
|
1398
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1399
|
+
|
|
1400
|
+
expect(task.data.isConferencing).toBe(true);
|
|
1401
|
+
// No task event emission for conferencing - only for conferenced (completed)
|
|
1402
|
+
expect(task.emit).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
|
|
1403
|
+
});
|
|
1404
|
+
|
|
1405
|
+
it('should handle AGENT_CONSULT_CONFERENCE_FAILED event', () => {
|
|
1406
|
+
const payload = {
|
|
1407
|
+
data: {
|
|
1408
|
+
type: CC_EVENTS.AGENT_CONSULT_CONFERENCE_FAILED,
|
|
1409
|
+
interactionId: taskId,
|
|
1410
|
+
reason: 'Network error',
|
|
1411
|
+
},
|
|
1412
|
+
};
|
|
1413
|
+
|
|
1414
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1415
|
+
|
|
1416
|
+
expect(task.data.reason).toBe('Network error');
|
|
1417
|
+
// No event emission expected for failure - handled by contact method promise rejection
|
|
1418
|
+
});
|
|
1419
|
+
|
|
1420
|
+
it('should handle PARTICIPANT_JOINED_CONFERENCE event', () => {
|
|
1421
|
+
const payload = {
|
|
1422
|
+
data: {
|
|
1423
|
+
type: CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE,
|
|
1424
|
+
interactionId: taskId,
|
|
1425
|
+
participantId: 'new-participant-123',
|
|
1426
|
+
participantType: 'agent',
|
|
1427
|
+
},
|
|
1428
|
+
};
|
|
1429
|
+
|
|
1430
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1431
|
+
|
|
1432
|
+
expect(task.data.participantId).toBe('new-participant-123');
|
|
1433
|
+
expect(task.data.participantType).toBe('agent');
|
|
1434
|
+
// No specific task event emission for participant joined - just data update
|
|
1435
|
+
});
|
|
1436
|
+
|
|
1437
|
+
it('should handle PARTICIPANT_LEFT_CONFERENCE event', () => {
|
|
1438
|
+
const payload = {
|
|
1439
|
+
data: {
|
|
1440
|
+
type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
|
|
1441
|
+
interactionId: taskId,
|
|
1442
|
+
isConferencing: false,
|
|
1443
|
+
},
|
|
1444
|
+
};
|
|
1445
|
+
|
|
1446
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1447
|
+
|
|
1448
|
+
expect(task.data.isConferencing).toBe(false);
|
|
1449
|
+
expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
|
|
1450
|
+
});
|
|
1451
|
+
|
|
1452
|
+
it('should handle PARTICIPANT_LEFT_CONFERENCE_FAILED event', () => {
|
|
1453
|
+
const payload = {
|
|
1454
|
+
data: {
|
|
1455
|
+
type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE_FAILED,
|
|
1456
|
+
interactionId: taskId,
|
|
1457
|
+
reason: 'Exit failed',
|
|
1458
|
+
},
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1462
|
+
|
|
1463
|
+
expect(task.data.reason).toBe('Exit failed');
|
|
1464
|
+
// No event emission expected for failure - handled by contact method promise rejection
|
|
1465
|
+
});
|
|
1466
|
+
|
|
1467
|
+
it('should only update task for matching interactionId', () => {
|
|
1468
|
+
const otherTaskId = 'other-task-id';
|
|
1469
|
+
const otherTask = {
|
|
1470
|
+
data: { interactionId: otherTaskId },
|
|
1471
|
+
emit: jest.fn(),
|
|
1472
|
+
};
|
|
1473
|
+
taskManager.taskCollection[otherTaskId] = otherTask;
|
|
1474
|
+
|
|
1475
|
+
const payload = {
|
|
1476
|
+
data: {
|
|
1477
|
+
type: CC_EVENTS.AGENT_CONSULT_CONFERENCED,
|
|
1478
|
+
interactionId: taskId,
|
|
1479
|
+
isConferencing: true,
|
|
1480
|
+
},
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1483
|
+
webSocketManagerMock.emit('message', JSON.stringify(payload));
|
|
1484
|
+
|
|
1485
|
+
// Only the matching task should be updated
|
|
1486
|
+
expect(task.data.isConferencing).toBe(true);
|
|
1487
|
+
expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
|
|
1488
|
+
|
|
1489
|
+
// Other task should not be affected
|
|
1490
|
+
expect(otherTask.data.isConferencing).toBeUndefined();
|
|
1491
|
+
expect(otherTask.emit).not.toHaveBeenCalled();
|
|
1492
|
+
});
|
|
1356
1493
|
});
|
|
1357
1494
|
});
|
|
1358
1495
|
|
|
@@ -197,7 +197,37 @@ describe("Routing contacts", () => {
|
|
|
197
197
|
const req = contact.wrapup({
|
|
198
198
|
interactionId: "interactionId",
|
|
199
199
|
data: { wrapUpReason: "testWrapUpReason", auxCodeId: "auxCodeID1234", isAutoWrapup: "on" }
|
|
200
|
-
|
|
200
|
+
} as any);
|
|
201
|
+
expect(req).toBeDefined();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("consultConference", () => {
|
|
205
|
+
fakeAqm.pendingRequests = {};
|
|
206
|
+
const consultData = {
|
|
207
|
+
agentId: "current-agent-id",
|
|
208
|
+
to: "destination-agent-id",
|
|
209
|
+
destinationType: "agent"
|
|
210
|
+
};
|
|
211
|
+
const req = contact.consultConference({
|
|
212
|
+
interactionId: "test-interaction-123",
|
|
213
|
+
data: consultData
|
|
214
|
+
});
|
|
215
|
+
expect(req).toBeDefined();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("exitConference", () => {
|
|
219
|
+
fakeAqm.pendingRequests = {};
|
|
220
|
+
const req = contact.exitConference({
|
|
221
|
+
interactionId: "test-interaction-456"
|
|
222
|
+
});
|
|
223
|
+
expect(req).toBeDefined();
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("conferenceTransfer", () => {
|
|
227
|
+
fakeAqm.pendingRequests = {};
|
|
228
|
+
const req = contact.conferenceTransfer({
|
|
229
|
+
interactionId: "test-interaction-transfer-123"
|
|
230
|
+
});
|
|
201
231
|
expect(req).toBeDefined();
|
|
202
232
|
});
|
|
203
233
|
});
|
|
@@ -75,6 +75,9 @@ describe('Task', () => {
|
|
|
75
75
|
wrapup: jest.fn().mockResolvedValue({}),
|
|
76
76
|
pauseRecording: jest.fn().mockResolvedValue({}),
|
|
77
77
|
resumeRecording: jest.fn().mockResolvedValue({}),
|
|
78
|
+
consultConference: jest.fn().mockResolvedValue({}),
|
|
79
|
+
exitConference: jest.fn().mockResolvedValue({}),
|
|
80
|
+
conferenceTransfer: jest.fn().mockResolvedValue({}),
|
|
78
81
|
};
|
|
79
82
|
|
|
80
83
|
mockMetricsManager = {
|
|
@@ -671,8 +674,8 @@ describe('Task', () => {
|
|
|
671
674
|
expect(loggerLogSpy).toHaveBeenCalledWith(`Consult started successfully to ${consultPayload.to}`, {
|
|
672
675
|
module: TASK_FILE,
|
|
673
676
|
method: 'consult',
|
|
674
|
-
trackingId: expectedResponse.trackingId,
|
|
675
677
|
interactionId: task.data.interactionId,
|
|
678
|
+
trackingId: '1234',
|
|
676
679
|
});
|
|
677
680
|
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
678
681
|
METRIC_EVENT_NAMES.TASK_CONSULT_START_SUCCESS,
|
|
@@ -1575,4 +1578,184 @@ describe('Task', () => {
|
|
|
1575
1578
|
});
|
|
1576
1579
|
});
|
|
1577
1580
|
});
|
|
1581
|
+
|
|
1582
|
+
describe('Conference methods', () => {
|
|
1583
|
+
beforeEach(() => {
|
|
1584
|
+
contactMock = {
|
|
1585
|
+
consultConference: jest.fn(),
|
|
1586
|
+
exitConference: jest.fn(),
|
|
1587
|
+
conferenceTransfer: jest.fn(),
|
|
1588
|
+
};
|
|
1589
|
+
|
|
1590
|
+
// Re-setup the getDestinationAgentId spy for conference methods
|
|
1591
|
+
getDestinationAgentIdSpy = jest
|
|
1592
|
+
.spyOn(Utils, 'getDestinationAgentId')
|
|
1593
|
+
.mockReturnValue(taskDataMock.destAgentId);
|
|
1594
|
+
|
|
1595
|
+
|
|
1596
|
+
task = new Task(contactMock, webCallingService, taskDataMock, {
|
|
1597
|
+
wrapUpProps: { wrapUpReasonList: [] },
|
|
1598
|
+
autoWrapEnabled: false,
|
|
1599
|
+
autoWrapAfterSeconds: 0
|
|
1600
|
+
}, taskDataMock.agentId);
|
|
1601
|
+
});
|
|
1602
|
+
|
|
1603
|
+
describe('consultConference', () => {
|
|
1604
|
+
|
|
1605
|
+
it('should successfully start conference and emit event', async () => {
|
|
1606
|
+
const mockResponse = {
|
|
1607
|
+
trackingId: 'test-tracking-id',
|
|
1608
|
+
interactionId: taskId,
|
|
1609
|
+
};
|
|
1610
|
+
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
1611
|
+
|
|
1612
|
+
|
|
1613
|
+
const result = await task.consultConference();
|
|
1614
|
+
|
|
1615
|
+
expect(contactMock.consultConference).toHaveBeenCalledWith({
|
|
1616
|
+
interactionId: taskId,
|
|
1617
|
+
data: {
|
|
1618
|
+
agentId: taskDataMock.agentId, // From task data agent ID
|
|
1619
|
+
to: taskDataMock.destAgentId, // From getDestinationAgentId() using task participants
|
|
1620
|
+
destinationType: 'agent', // From consultation data
|
|
1621
|
+
},
|
|
1622
|
+
});
|
|
1623
|
+
expect(result).toEqual(mockResponse);
|
|
1624
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith(`Initiating consult conference to ${taskDataMock.destAgentId}`, {
|
|
1625
|
+
module: TASK_FILE,
|
|
1626
|
+
method: 'consultConference',
|
|
1627
|
+
interactionId: taskId,
|
|
1628
|
+
});
|
|
1629
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Consult conference started successfully', {
|
|
1630
|
+
module: TASK_FILE,
|
|
1631
|
+
method: 'consultConference',
|
|
1632
|
+
interactionId: taskId,
|
|
1633
|
+
});
|
|
1634
|
+
});
|
|
1635
|
+
|
|
1636
|
+
it('should handle basic validation scenarios', async () => {
|
|
1637
|
+
// Agent Desktop logic validates data structure but not participant availability
|
|
1638
|
+
// This test confirms the method works with the Agent Desktop data flow
|
|
1639
|
+
const mockResponse = {
|
|
1640
|
+
trackingId: 'test-tracking-validation',
|
|
1641
|
+
interactionId: taskId,
|
|
1642
|
+
};
|
|
1643
|
+
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
1644
|
+
|
|
1645
|
+
const result = await task.consultConference();
|
|
1646
|
+
expect(result).toEqual(mockResponse);
|
|
1647
|
+
});
|
|
1648
|
+
|
|
1649
|
+
it('should handle and rethrow contact method errors', async () => {
|
|
1650
|
+
const mockError = new Error('Conference start failed');
|
|
1651
|
+
contactMock.consultConference.mockRejectedValue(mockError);
|
|
1652
|
+
generateTaskErrorObjectSpy.mockReturnValue(mockError);
|
|
1653
|
+
|
|
1654
|
+
await expect(task.consultConference()).rejects.toThrow('Conference start failed');
|
|
1655
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to start consult conference', {
|
|
1656
|
+
module: TASK_FILE,
|
|
1657
|
+
method: 'consultConference',
|
|
1658
|
+
interactionId: taskId,
|
|
1659
|
+
});
|
|
1660
|
+
});
|
|
1661
|
+
});
|
|
1662
|
+
|
|
1663
|
+
describe('exitConference', () => {
|
|
1664
|
+
it('should successfully end conference and emit event', async () => {
|
|
1665
|
+
const mockResponse = {
|
|
1666
|
+
trackingId: 'test-tracking-id-end',
|
|
1667
|
+
interactionId: taskId,
|
|
1668
|
+
};
|
|
1669
|
+
contactMock.exitConference.mockResolvedValue(mockResponse);
|
|
1670
|
+
|
|
1671
|
+
const result = await task.exitConference();
|
|
1672
|
+
|
|
1673
|
+
expect(contactMock.exitConference).toHaveBeenCalledWith({
|
|
1674
|
+
interactionId: taskId,
|
|
1675
|
+
});
|
|
1676
|
+
expect(result).toEqual(mockResponse);
|
|
1677
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Exiting consult conference', {
|
|
1678
|
+
module: TASK_FILE,
|
|
1679
|
+
method: 'exitConference',
|
|
1680
|
+
interactionId: taskId,
|
|
1681
|
+
});
|
|
1682
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Consult conference exited successfully', {
|
|
1683
|
+
module: TASK_FILE,
|
|
1684
|
+
method: 'exitConference',
|
|
1685
|
+
interactionId: taskId,
|
|
1686
|
+
});
|
|
1687
|
+
});
|
|
1688
|
+
|
|
1689
|
+
it('should throw error for invalid interaction ID', async () => {
|
|
1690
|
+
task.data.interactionId = '';
|
|
1691
|
+
|
|
1692
|
+
await expect(task.exitConference()).rejects.toThrow('Error while performing exitConference');
|
|
1693
|
+
expect(contactMock.exitConference).not.toHaveBeenCalled();
|
|
1694
|
+
});
|
|
1695
|
+
|
|
1696
|
+
it('should handle and rethrow contact method errors', async () => {
|
|
1697
|
+
const mockError = new Error('Conference end failed');
|
|
1698
|
+
contactMock.exitConference.mockRejectedValue(mockError);
|
|
1699
|
+
generateTaskErrorObjectSpy.mockReturnValue(mockError);
|
|
1700
|
+
|
|
1701
|
+
await expect(task.exitConference()).rejects.toThrow('Conference end failed');
|
|
1702
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to exit consult conference', {
|
|
1703
|
+
module: TASK_FILE,
|
|
1704
|
+
method: 'exitConference',
|
|
1705
|
+
interactionId: taskId,
|
|
1706
|
+
});
|
|
1707
|
+
});
|
|
1708
|
+
});
|
|
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
|
+
/*
|
|
1713
|
+
describe('transferConference', () => {
|
|
1714
|
+
it('should successfully transfer conference', async () => {
|
|
1715
|
+
const mockResponse = {
|
|
1716
|
+
trackingId: 'test-tracking-id-transfer',
|
|
1717
|
+
interactionId: taskId,
|
|
1718
|
+
};
|
|
1719
|
+
contactMock.conferenceTransfer.mockResolvedValue(mockResponse);
|
|
1720
|
+
|
|
1721
|
+
const result = await task.transferConference();
|
|
1722
|
+
|
|
1723
|
+
expect(contactMock.conferenceTransfer).toHaveBeenCalledWith({
|
|
1724
|
+
interactionId: taskId,
|
|
1725
|
+
});
|
|
1726
|
+
expect(result).toEqual(mockResponse);
|
|
1727
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Transferring conference', {
|
|
1728
|
+
module: TASK_FILE,
|
|
1729
|
+
method: 'transferConference',
|
|
1730
|
+
interactionId: taskId,
|
|
1731
|
+
});
|
|
1732
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Conference transferred successfully', {
|
|
1733
|
+
module: TASK_FILE,
|
|
1734
|
+
method: 'transferConference',
|
|
1735
|
+
interactionId: taskId,
|
|
1736
|
+
});
|
|
1737
|
+
});
|
|
1738
|
+
|
|
1739
|
+
it('should throw error for invalid interaction ID', async () => {
|
|
1740
|
+
task.data.interactionId = '';
|
|
1741
|
+
|
|
1742
|
+
await expect(task.transferConference()).rejects.toThrow('Error while performing transferConference');
|
|
1743
|
+
expect(contactMock.conferenceTransfer).not.toHaveBeenCalled();
|
|
1744
|
+
});
|
|
1745
|
+
|
|
1746
|
+
it('should handle and rethrow contact method errors', async () => {
|
|
1747
|
+
const mockError = new Error('Conference transfer failed');
|
|
1748
|
+
contactMock.conferenceTransfer.mockRejectedValue(mockError);
|
|
1749
|
+
generateTaskErrorObjectSpy.mockReturnValue(mockError);
|
|
1750
|
+
|
|
1751
|
+
await expect(task.transferConference()).rejects.toThrow('Conference transfer failed');
|
|
1752
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to transfer conference', {
|
|
1753
|
+
module: TASK_FILE,
|
|
1754
|
+
method: 'transferConference',
|
|
1755
|
+
interactionId: taskId,
|
|
1756
|
+
});
|
|
1757
|
+
});
|
|
1758
|
+
});
|
|
1759
|
+
*/
|
|
1760
|
+
});
|
|
1578
1761
|
});
|