@webex/contact-center 3.9.0-next.9 → 3.10.0
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 +182 -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/behavioral-events.js +89 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +30 -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/Utils.js +42 -1
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/task/TaskManager.js +113 -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 +241 -5
- 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 +24 -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/Utils.d.ts +14 -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 +64 -1
- package/dist/types/services/task/types.d.ts +221 -19
- 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 +206 -52
- package/src/constants.ts +1 -0
- package/src/index.ts +16 -2
- package/src/logger-proxy.ts +24 -1
- package/src/metrics/behavioral-events.ts +94 -0
- package/src/metrics/constants.ts +34 -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/Utils.ts +44 -0
- package/src/services/task/TaskManager.ts +122 -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 +300 -4
- package/src/services/task/types.ts +239 -18
- 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/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/task/TaskManager.ts +382 -0
- 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 +242 -8
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -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 = {
|
|
@@ -214,7 +217,7 @@ describe('Task', () => {
|
|
|
214
217
|
});
|
|
215
218
|
|
|
216
219
|
describe('updateTaskData cases', () => {
|
|
217
|
-
it('
|
|
220
|
+
it('updates the task data by overwrite', async () => {
|
|
218
221
|
const newData = {
|
|
219
222
|
type: CC_EVENTS.AGENT_CONTACT_ASSIGNED,
|
|
220
223
|
agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
|
|
@@ -263,12 +266,12 @@ describe('Task', () => {
|
|
|
263
266
|
expect(task.data).toEqual(newData);
|
|
264
267
|
});
|
|
265
268
|
|
|
266
|
-
it('
|
|
269
|
+
it('updates the task data by merging with key removal', async () => {
|
|
267
270
|
const newData = {
|
|
268
|
-
//
|
|
271
|
+
// Purposefully omit other keys to test remove and merge behavior
|
|
269
272
|
isConsulting: true, // Add a new custom key to test persistence
|
|
270
273
|
interaction: {
|
|
271
|
-
//
|
|
274
|
+
// Purposefully omit other interaction keys to test removal
|
|
272
275
|
media: {
|
|
273
276
|
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
274
277
|
holdTimestamp: null,
|
|
@@ -295,11 +298,12 @@ describe('Task', () => {
|
|
|
295
298
|
},
|
|
296
299
|
};
|
|
297
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
|
|
298
303
|
const expectedData: TaskData = {
|
|
299
|
-
|
|
300
|
-
isConsulting: true,
|
|
304
|
+
isConsulting: true, // New key is added
|
|
301
305
|
interaction: {
|
|
302
|
-
|
|
306
|
+
// Only the media key from newData.interaction remains
|
|
303
307
|
media: {
|
|
304
308
|
'58a45567-4e61-4f4b-a580-5bc86357bef0': {
|
|
305
309
|
holdTimestamp: null,
|
|
@@ -332,6 +336,60 @@ describe('Task', () => {
|
|
|
332
336
|
|
|
333
337
|
expect(task.data).toEqual(expectedData);
|
|
334
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
|
+
});
|
|
335
393
|
});
|
|
336
394
|
|
|
337
395
|
it('should accept a task and answer call when using BROWSER login option', async () => {
|
|
@@ -671,8 +729,8 @@ describe('Task', () => {
|
|
|
671
729
|
expect(loggerLogSpy).toHaveBeenCalledWith(`Consult started successfully to ${consultPayload.to}`, {
|
|
672
730
|
module: TASK_FILE,
|
|
673
731
|
method: 'consult',
|
|
674
|
-
trackingId: expectedResponse.trackingId,
|
|
675
732
|
interactionId: task.data.interactionId,
|
|
733
|
+
trackingId: '1234',
|
|
676
734
|
});
|
|
677
735
|
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
678
736
|
METRIC_EVENT_NAMES.TASK_CONSULT_START_SUCCESS,
|
|
@@ -1575,4 +1633,180 @@ describe('Task', () => {
|
|
|
1575
1633
|
});
|
|
1576
1634
|
});
|
|
1577
1635
|
});
|
|
1636
|
+
|
|
1637
|
+
describe('Conference methods', () => {
|
|
1638
|
+
beforeEach(() => {
|
|
1639
|
+
contactMock = {
|
|
1640
|
+
consultConference: jest.fn(),
|
|
1641
|
+
exitConference: jest.fn(),
|
|
1642
|
+
conferenceTransfer: jest.fn(),
|
|
1643
|
+
};
|
|
1644
|
+
|
|
1645
|
+
// Re-setup the getDestinationAgentId spy for conference methods
|
|
1646
|
+
getDestinationAgentIdSpy = jest
|
|
1647
|
+
.spyOn(Utils, 'getDestinationAgentId')
|
|
1648
|
+
.mockReturnValue(taskDataMock.destAgentId);
|
|
1649
|
+
|
|
1650
|
+
|
|
1651
|
+
task = new Task(contactMock, webCallingService, taskDataMock, {
|
|
1652
|
+
wrapUpProps: { wrapUpReasonList: [] },
|
|
1653
|
+
autoWrapEnabled: false,
|
|
1654
|
+
autoWrapAfterSeconds: 0
|
|
1655
|
+
}, taskDataMock.agentId);
|
|
1656
|
+
});
|
|
1657
|
+
|
|
1658
|
+
describe('consultConference', () => {
|
|
1659
|
+
|
|
1660
|
+
it('should successfully start conference and emit event', async () => {
|
|
1661
|
+
const mockResponse = {
|
|
1662
|
+
trackingId: 'test-tracking-id',
|
|
1663
|
+
interactionId: taskId,
|
|
1664
|
+
};
|
|
1665
|
+
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
1666
|
+
|
|
1667
|
+
|
|
1668
|
+
const result = await task.consultConference();
|
|
1669
|
+
|
|
1670
|
+
expect(contactMock.consultConference).toHaveBeenCalledWith({
|
|
1671
|
+
interactionId: taskId,
|
|
1672
|
+
data: {
|
|
1673
|
+
agentId: taskDataMock.agentId, // From task data agent ID
|
|
1674
|
+
to: taskDataMock.destAgentId, // From getDestinationAgentId() using task participants
|
|
1675
|
+
destinationType: 'agent', // From consultation data
|
|
1676
|
+
},
|
|
1677
|
+
});
|
|
1678
|
+
expect(result).toEqual(mockResponse);
|
|
1679
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith(`Initiating consult conference to ${taskDataMock.destAgentId}`, {
|
|
1680
|
+
module: TASK_FILE,
|
|
1681
|
+
method: 'consultConference',
|
|
1682
|
+
interactionId: taskId,
|
|
1683
|
+
});
|
|
1684
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Consult conference started successfully', {
|
|
1685
|
+
module: TASK_FILE,
|
|
1686
|
+
method: 'consultConference',
|
|
1687
|
+
interactionId: taskId,
|
|
1688
|
+
});
|
|
1689
|
+
});
|
|
1690
|
+
|
|
1691
|
+
it('should handle basic validation scenarios', async () => {
|
|
1692
|
+
// Agent Desktop logic validates data structure but not participant availability
|
|
1693
|
+
// This test confirms the method works with the Agent Desktop data flow
|
|
1694
|
+
const mockResponse = {
|
|
1695
|
+
trackingId: 'test-tracking-validation',
|
|
1696
|
+
interactionId: taskId,
|
|
1697
|
+
};
|
|
1698
|
+
contactMock.consultConference.mockResolvedValue(mockResponse);
|
|
1699
|
+
|
|
1700
|
+
const result = await task.consultConference();
|
|
1701
|
+
expect(result).toEqual(mockResponse);
|
|
1702
|
+
});
|
|
1703
|
+
|
|
1704
|
+
it('should handle and rethrow contact method errors', async () => {
|
|
1705
|
+
const mockError = new Error('Conference start failed');
|
|
1706
|
+
contactMock.consultConference.mockRejectedValue(mockError);
|
|
1707
|
+
generateTaskErrorObjectSpy.mockReturnValue(mockError);
|
|
1708
|
+
|
|
1709
|
+
await expect(task.consultConference()).rejects.toThrow('Conference start failed');
|
|
1710
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to start consult conference', {
|
|
1711
|
+
module: TASK_FILE,
|
|
1712
|
+
method: 'consultConference',
|
|
1713
|
+
interactionId: taskId,
|
|
1714
|
+
});
|
|
1715
|
+
});
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
describe('exitConference', () => {
|
|
1719
|
+
it('should successfully end conference and emit event', async () => {
|
|
1720
|
+
const mockResponse = {
|
|
1721
|
+
trackingId: 'test-tracking-id-end',
|
|
1722
|
+
interactionId: taskId,
|
|
1723
|
+
};
|
|
1724
|
+
contactMock.exitConference.mockResolvedValue(mockResponse);
|
|
1725
|
+
|
|
1726
|
+
const result = await task.exitConference();
|
|
1727
|
+
|
|
1728
|
+
expect(contactMock.exitConference).toHaveBeenCalledWith({
|
|
1729
|
+
interactionId: taskId,
|
|
1730
|
+
});
|
|
1731
|
+
expect(result).toEqual(mockResponse);
|
|
1732
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Exiting consult conference', {
|
|
1733
|
+
module: TASK_FILE,
|
|
1734
|
+
method: 'exitConference',
|
|
1735
|
+
interactionId: taskId,
|
|
1736
|
+
});
|
|
1737
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Consult conference exited successfully', {
|
|
1738
|
+
module: TASK_FILE,
|
|
1739
|
+
method: 'exitConference',
|
|
1740
|
+
interactionId: taskId,
|
|
1741
|
+
});
|
|
1742
|
+
});
|
|
1743
|
+
|
|
1744
|
+
it('should throw error for invalid interaction ID', async () => {
|
|
1745
|
+
task.data.interactionId = '';
|
|
1746
|
+
|
|
1747
|
+
await expect(task.exitConference()).rejects.toThrow('Error while performing exitConference');
|
|
1748
|
+
expect(contactMock.exitConference).not.toHaveBeenCalled();
|
|
1749
|
+
});
|
|
1750
|
+
|
|
1751
|
+
it('should handle and rethrow contact method errors', async () => {
|
|
1752
|
+
const mockError = new Error('Conference end failed');
|
|
1753
|
+
contactMock.exitConference.mockRejectedValue(mockError);
|
|
1754
|
+
generateTaskErrorObjectSpy.mockReturnValue(mockError);
|
|
1755
|
+
|
|
1756
|
+
await expect(task.exitConference()).rejects.toThrow('Conference end failed');
|
|
1757
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to exit consult conference', {
|
|
1758
|
+
module: TASK_FILE,
|
|
1759
|
+
method: 'exitConference',
|
|
1760
|
+
interactionId: taskId,
|
|
1761
|
+
});
|
|
1762
|
+
});
|
|
1763
|
+
});
|
|
1764
|
+
|
|
1765
|
+
describe('transferConference', () => {
|
|
1766
|
+
it('should successfully transfer conference', async () => {
|
|
1767
|
+
const mockResponse = {
|
|
1768
|
+
trackingId: 'test-tracking-id-transfer',
|
|
1769
|
+
interactionId: taskId,
|
|
1770
|
+
};
|
|
1771
|
+
contactMock.conferenceTransfer.mockResolvedValue(mockResponse);
|
|
1772
|
+
|
|
1773
|
+
const result = await task.transferConference();
|
|
1774
|
+
|
|
1775
|
+
expect(contactMock.conferenceTransfer).toHaveBeenCalledWith({
|
|
1776
|
+
interactionId: taskId,
|
|
1777
|
+
});
|
|
1778
|
+
expect(result).toEqual(mockResponse);
|
|
1779
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Transferring conference', {
|
|
1780
|
+
module: TASK_FILE,
|
|
1781
|
+
method: 'transferConference',
|
|
1782
|
+
interactionId: taskId,
|
|
1783
|
+
});
|
|
1784
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Conference transferred successfully', {
|
|
1785
|
+
module: TASK_FILE,
|
|
1786
|
+
method: 'transferConference',
|
|
1787
|
+
interactionId: taskId,
|
|
1788
|
+
});
|
|
1789
|
+
});
|
|
1790
|
+
|
|
1791
|
+
it('should throw error for invalid interaction ID', async () => {
|
|
1792
|
+
task.data.interactionId = '';
|
|
1793
|
+
|
|
1794
|
+
await expect(task.transferConference()).rejects.toThrow('Error while performing transferConference');
|
|
1795
|
+
expect(contactMock.conferenceTransfer).not.toHaveBeenCalled();
|
|
1796
|
+
});
|
|
1797
|
+
|
|
1798
|
+
it('should handle and rethrow contact method errors', async () => {
|
|
1799
|
+
const mockError = new Error('Conference transfer failed');
|
|
1800
|
+
contactMock.conferenceTransfer.mockRejectedValue(mockError);
|
|
1801
|
+
generateTaskErrorObjectSpy.mockReturnValue(mockError);
|
|
1802
|
+
|
|
1803
|
+
await expect(task.transferConference()).rejects.toThrow('Conference transfer failed');
|
|
1804
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to transfer conference', {
|
|
1805
|
+
module: TASK_FILE,
|
|
1806
|
+
method: 'transferConference',
|
|
1807
|
+
interactionId: taskId,
|
|
1808
|
+
});
|
|
1809
|
+
});
|
|
1810
|
+
});
|
|
1811
|
+
});
|
|
1578
1812
|
});
|