@webex/contact-center 3.12.0-task-refactor.11 → 3.12.0-task-refactor.13
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 +297 -83
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +3 -0
- package/dist/constants.js.map +1 -1
- package/dist/metrics/behavioral-events.js +39 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +8 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +3 -0
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/config/Util.js +1 -1
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/types.js +10 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js +1 -0
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +57 -6
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +92 -17
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +24 -3
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/index.js +1 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +6 -0
- package/dist/services/task/Task.js.map +1 -1
- package/dist/services/task/TaskManager.js +155 -6
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +39 -11
- package/dist/services/task/TaskUtils.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/dialer.js +129 -0
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +30 -3
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +4 -0
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/constants.js +3 -0
- package/dist/services/task/state-machine/constants.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +23 -0
- package/dist/services/task/state-machine/guards.js.map +1 -1
- package/dist/services/task/state-machine/types.js.map +1 -1
- package/dist/services/task/types.js +59 -0
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +76 -2
- package/dist/types/constants.d.ts +3 -0
- package/dist/types/metrics/constants.d.ts +6 -0
- package/dist/types/services/config/types.d.ts +22 -1
- package/dist/types/services/core/Err.d.ts +6 -0
- package/dist/types/services/core/Utils.d.ts +20 -2
- package/dist/types/services/core/aqm-reqs.d.ts +49 -0
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
- package/dist/types/services/core/websocket/connection-service.d.ts +1 -0
- package/dist/types/services/task/Task.d.ts +1 -0
- package/dist/types/services/task/TaskUtils.d.ts +13 -0
- package/dist/types/services/task/constants.d.ts +6 -0
- package/dist/types/services/task/dialer.d.ts +45 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +36 -8
- package/dist/types/services/task/state-machine/constants.d.ts +3 -0
- package/dist/types/services/task/state-machine/guards.d.ts +2 -0
- package/dist/types/services/task/state-machine/types.d.ts +11 -0
- package/dist/types/services/task/types.d.ts +75 -1
- package/dist/types.js.map +1 -1
- package/dist/webex.js +1 -1
- package/package.json +2 -2
- package/src/cc.ts +389 -111
- package/src/constants.ts +3 -0
- package/src/metrics/behavioral-events.ts +42 -0
- package/src/metrics/constants.ts +9 -1
- package/src/services/ApiAiAssistant.ts +3 -0
- package/src/services/config/Util.ts +1 -1
- package/src/services/config/types.ts +12 -1
- package/src/services/constants.ts +1 -0
- package/src/services/core/Err.ts +3 -0
- package/src/services/core/Utils.ts +68 -5
- package/src/services/core/aqm-reqs.ts +100 -22
- package/src/services/core/websocket/WebSocketManager.ts +23 -2
- package/src/services/index.ts +1 -0
- package/src/services/task/Task.ts +13 -0
- package/src/services/task/TaskManager.ts +171 -7
- package/src/services/task/TaskUtils.ts +33 -1
- package/src/services/task/constants.ts +6 -0
- package/src/services/task/dialer.ts +136 -1
- package/src/services/task/state-machine/TaskStateMachine.ts +37 -5
- package/src/services/task/state-machine/actions.ts +4 -0
- package/src/services/task/state-machine/constants.ts +3 -0
- package/src/services/task/state-machine/guards.ts +30 -0
- package/src/services/task/state-machine/types.ts +14 -1
- package/src/services/task/types.ts +80 -0
- package/src/types.ts +4 -1
- package/test/unit/spec/cc.ts +294 -32
- package/test/unit/spec/services/config/index.ts +30 -2
- package/test/unit/spec/services/core/Utils.ts +367 -1
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +91 -1
- package/test/unit/spec/services/core/websocket/connection-service.ts +4 -5
- package/test/unit/spec/services/task/TaskManager.ts +4 -2
- package/test/unit/spec/services/task/dialer.ts +372 -96
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -639,6 +639,66 @@ export enum TASK_EVENTS {
|
|
|
639
639
|
* ```
|
|
640
640
|
*/
|
|
641
641
|
TASK_MULTI_LOGIN_HYDRATE = 'task:multiLoginHydrate',
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Triggered when a campaign preview contact is offered to the agent
|
|
645
|
+
* @example
|
|
646
|
+
* ```typescript
|
|
647
|
+
* task.on(TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, (data: AgentContact) => {
|
|
648
|
+
* console.log('Campaign preview contact received:', data.interactionId);
|
|
649
|
+
* // Handle campaign preview reservation
|
|
650
|
+
* });
|
|
651
|
+
* ```
|
|
652
|
+
*/
|
|
653
|
+
TASK_CAMPAIGN_PREVIEW_RESERVATION = 'task:campaignPreviewReservation',
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Triggered when accepting a campaign preview contact fails
|
|
657
|
+
* @example
|
|
658
|
+
* ```typescript
|
|
659
|
+
* task.on(TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_ACCEPT_FAILED, (task: ITask) => {
|
|
660
|
+
* console.log('Campaign preview accept failed:', task.data.interactionId);
|
|
661
|
+
* // Handle accept failure
|
|
662
|
+
* });
|
|
663
|
+
* ```
|
|
664
|
+
*/
|
|
665
|
+
TASK_CAMPAIGN_PREVIEW_ACCEPT_FAILED = 'task:campaignPreviewAcceptFailed',
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Triggered when skipping a campaign preview contact fails
|
|
669
|
+
* @example
|
|
670
|
+
* ```typescript
|
|
671
|
+
* task.on(TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_SKIP_FAILED, (task: ITask) => {
|
|
672
|
+
* console.log('Campaign preview skip failed:', task.data.interactionId);
|
|
673
|
+
* // Handle skip failure
|
|
674
|
+
* });
|
|
675
|
+
* ```
|
|
676
|
+
*/
|
|
677
|
+
TASK_CAMPAIGN_PREVIEW_SKIP_FAILED = 'task:campaignPreviewSkipFailed',
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Triggered when removing a campaign preview contact fails
|
|
681
|
+
* @example
|
|
682
|
+
* ```typescript
|
|
683
|
+
* task.on(TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_REMOVE_FAILED, (task: ITask) => {
|
|
684
|
+
* console.log('Campaign preview remove failed:', task.data.interactionId);
|
|
685
|
+
* // Handle remove failure
|
|
686
|
+
* });
|
|
687
|
+
* ```
|
|
688
|
+
*/
|
|
689
|
+
TASK_CAMPAIGN_PREVIEW_REMOVE_FAILED = 'task:campaignPreviewRemoveFailed',
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Triggered when a campaign contact is updated (e.g., after skip or remove, when the next contact is offered)
|
|
693
|
+
* @example
|
|
694
|
+
* ```typescript
|
|
695
|
+
* task.on(TASK_EVENTS.TASK_CAMPAIGN_CONTACT_UPDATED, (task: ITask) => {
|
|
696
|
+
* console.log('Campaign contact updated:', task.data.interactionId);
|
|
697
|
+
* // Handle updated campaign contact (e.g., display next contact)
|
|
698
|
+
* });
|
|
699
|
+
* ```
|
|
700
|
+
*/
|
|
701
|
+
TASK_CAMPAIGN_CONTACT_UPDATED = 'task:campaignContactUpdated',
|
|
642
702
|
}
|
|
643
703
|
|
|
644
704
|
/**
|
|
@@ -948,6 +1008,14 @@ export type Interaction = {
|
|
|
948
1008
|
outdialAgentId?: string;
|
|
949
1009
|
/** Indicates if the customer has left the call during an active consult */
|
|
950
1010
|
hasCustomerLeft?: string;
|
|
1011
|
+
/** Indicates if the skip action is disabled for campaign preview contacts */
|
|
1012
|
+
campaignPreviewSkipDisabled?: string;
|
|
1013
|
+
/** Indicates if the remove action is disabled for campaign preview contacts */
|
|
1014
|
+
campaignPreviewRemoveDisabled?: string;
|
|
1015
|
+
/** Auto-action to perform when campaign preview offer times out (ACCEPT, SKIP, REMOVE) */
|
|
1016
|
+
campaignPreviewAutoAction?: string;
|
|
1017
|
+
/** Timestamp (ms) when the campaign preview offer expires */
|
|
1018
|
+
campaignPreviewOfferTimeout?: string;
|
|
951
1019
|
};
|
|
952
1020
|
/** Main interaction identifier for related interactions */
|
|
953
1021
|
mainInteractionId?: string;
|
|
@@ -1472,6 +1540,18 @@ export type DialerPayload = {
|
|
|
1472
1540
|
origin: string;
|
|
1473
1541
|
};
|
|
1474
1542
|
|
|
1543
|
+
/**
|
|
1544
|
+
* Payload for campaign preview contact operations (accept, skip, remove)
|
|
1545
|
+
* @public
|
|
1546
|
+
*/
|
|
1547
|
+
export type PreviewContactPayload = {
|
|
1548
|
+
/** The interaction ID from the campaign reservation */
|
|
1549
|
+
interactionId: string;
|
|
1550
|
+
/** The campaign name (not a UUID). Available from the reservation event at
|
|
1551
|
+
* `task.data.interaction.callProcessingDetails.campaignId` or `task.data.campaignId`. */
|
|
1552
|
+
campaignId: string;
|
|
1553
|
+
};
|
|
1554
|
+
|
|
1475
1555
|
/**
|
|
1476
1556
|
* Data structure for cleaning up contact resources
|
|
1477
1557
|
* @public
|
package/src/types.ts
CHANGED
|
@@ -297,6 +297,8 @@ interface IWebexInternal {
|
|
|
297
297
|
get: (service: string) => string;
|
|
298
298
|
/** Wait for service catalog to be loaded */
|
|
299
299
|
waitForCatalog: (service: string) => Promise<void>;
|
|
300
|
+
/** Check if current environment is INT (integration) */
|
|
301
|
+
isIntegrationEnvironment: () => boolean;
|
|
300
302
|
/** Host catalog for service discovery */
|
|
301
303
|
_hostCatalog: Record<string, ServiceHost[]>;
|
|
302
304
|
/** Service URLs cache */
|
|
@@ -541,7 +543,8 @@ export type RequestBody =
|
|
|
541
543
|
| Contact.ConsultTransferPayLoad
|
|
542
544
|
| Contact.cancelCtq
|
|
543
545
|
| Contact.WrapupPayLoad
|
|
544
|
-
| Contact.DialerPayload
|
|
546
|
+
| Contact.DialerPayload
|
|
547
|
+
| Contact.PreviewContactPayload;
|
|
545
548
|
|
|
546
549
|
/**
|
|
547
550
|
* Represents the options to fetch buddy agents for the logged in agent.
|
package/test/unit/spec/cc.ts
CHANGED
|
@@ -15,7 +15,7 @@ import type {ContactServiceQueuesResponse} from '../../../src/types';
|
|
|
15
15
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
16
16
|
import {StationLoginSuccess, AGENT_EVENTS} from '../../../src/services/agent/types';
|
|
17
17
|
import {SetStateResponse} from '../../../src/types';
|
|
18
|
-
import {AGENT, WEB_RTC_PREFIX} from '../../../src/services/constants';
|
|
18
|
+
import {AGENT, SUBSCRIBE_API, WEB_RTC_PREFIX} from '../../../src/services/constants';
|
|
19
19
|
import Services from '../../../src/services';
|
|
20
20
|
import config from '../../../src/config';
|
|
21
21
|
import {CC_EVENTS} from '../../../src/services/config/types';
|
|
@@ -89,6 +89,8 @@ describe('webex.cc', () => {
|
|
|
89
89
|
initWebSocket: jest.fn(),
|
|
90
90
|
on: jest.fn(),
|
|
91
91
|
off: jest.fn(),
|
|
92
|
+
close: jest.fn(),
|
|
93
|
+
isSocketClosed: false,
|
|
92
94
|
};
|
|
93
95
|
|
|
94
96
|
mockContact = {
|
|
@@ -130,6 +132,13 @@ describe('webex.cc', () => {
|
|
|
130
132
|
getOutdialAniEntries: jest.fn(),
|
|
131
133
|
},
|
|
132
134
|
webSocketManager: mockWebSocketManager,
|
|
135
|
+
rtdWebSocketManager: {
|
|
136
|
+
initWebSocket: jest.fn().mockResolvedValue({}),
|
|
137
|
+
on: jest.fn(),
|
|
138
|
+
off: jest.fn(),
|
|
139
|
+
close: jest.fn(),
|
|
140
|
+
isSocketClosed: false,
|
|
141
|
+
},
|
|
133
142
|
connectionService: {
|
|
134
143
|
on: jest.fn(),
|
|
135
144
|
off: jest.fn(),
|
|
@@ -138,6 +147,13 @@ describe('webex.cc', () => {
|
|
|
138
147
|
|
|
139
148
|
dialer: {
|
|
140
149
|
startOutdial: jest.fn(),
|
|
150
|
+
acceptPreviewContact: jest.fn(),
|
|
151
|
+
skipPreviewContact: jest.fn(),
|
|
152
|
+
removePreviewContact: jest.fn(),
|
|
153
|
+
},
|
|
154
|
+
apiAIAssistant: {
|
|
155
|
+
sendEvent: jest.fn(),
|
|
156
|
+
fetchHistoricTranscripts: jest.fn(),
|
|
141
157
|
},
|
|
142
158
|
};
|
|
143
159
|
|
|
@@ -302,6 +318,7 @@ describe('webex.cc', () => {
|
|
|
302
318
|
};
|
|
303
319
|
|
|
304
320
|
it('should register successfully and return agent profile', async () => {
|
|
321
|
+
mockAgentProfile.aiFeature = {realtimeTranscripts: {enable: true}} as any;
|
|
305
322
|
const mercuryConnect = jest.spyOn(webex.internal.mercury, 'connect').mockResolvedValue(true);
|
|
306
323
|
const connectWebsocketSpy = jest.spyOn(webex.cc, 'connectWebsocket');
|
|
307
324
|
const setupEventListenersSpy = jest.spyOn(webex.cc, 'setupEventListeners');
|
|
@@ -323,7 +340,7 @@ describe('webex.cc', () => {
|
|
|
323
340
|
const result = await webex.cc.register();
|
|
324
341
|
|
|
325
342
|
// Verify logging calls
|
|
326
|
-
expect(LoggerProxy.
|
|
343
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting CC SDK registration', {
|
|
327
344
|
module: CC_FILE,
|
|
328
345
|
method: 'register',
|
|
329
346
|
});
|
|
@@ -345,7 +362,7 @@ describe('webex.cc', () => {
|
|
|
345
362
|
clientType: 'WebexCCSDK',
|
|
346
363
|
allowMultiLogin: false,
|
|
347
364
|
},
|
|
348
|
-
resource:
|
|
365
|
+
resource: SUBSCRIBE_API,
|
|
349
366
|
});
|
|
350
367
|
|
|
351
368
|
// TODO: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-626777 Implement the de-register method and close the listener there
|
|
@@ -362,6 +379,19 @@ describe('webex.cc', () => {
|
|
|
362
379
|
expect.any(Function)
|
|
363
380
|
);
|
|
364
381
|
expect(mockWebSocketManager.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
382
|
+
expect(webex.cc.services.rtdWebSocketManager.initWebSocket).toHaveBeenCalledWith({
|
|
383
|
+
body: {
|
|
384
|
+
force: true,
|
|
385
|
+
isKeepAliveEnabled: false,
|
|
386
|
+
clientType: 'WebexCCSDK',
|
|
387
|
+
allowMultiLogin: false,
|
|
388
|
+
},
|
|
389
|
+
resource: 'v1/realtime/subscribe',
|
|
390
|
+
});
|
|
391
|
+
expect(webex.cc.services.rtdWebSocketManager.on).toHaveBeenCalledWith(
|
|
392
|
+
'message',
|
|
393
|
+
expect.any(Function)
|
|
394
|
+
);
|
|
365
395
|
|
|
366
396
|
expect(configSpy).toHaveBeenCalled();
|
|
367
397
|
expect(LoggerProxy.log).toHaveBeenCalledWith('Agent config is fetched successfully', {
|
|
@@ -373,12 +403,7 @@ describe('webex.cc', () => {
|
|
|
373
403
|
isEndConsultEnabled: mockAgentProfile.isEndConsultEnabled,
|
|
374
404
|
webRtcEnabled: mockAgentProfile.webRtcEnabled,
|
|
375
405
|
autoWrapup: mockAgentProfile.wrapUpData.wrapUpProps.autoWrapup ?? false,
|
|
376
|
-
|
|
377
|
-
expect(mockTaskManager.setConfigFlags).toHaveBeenCalledWith({
|
|
378
|
-
isEndTaskEnabled: mockAgentProfile.isEndTaskEnabled,
|
|
379
|
-
isEndConsultEnabled: mockAgentProfile.isEndConsultEnabled,
|
|
380
|
-
webRtcEnabled: mockAgentProfile.webRtcEnabled,
|
|
381
|
-
autoWrapup: mockAgentProfile.wrapUpData.wrapUpProps.autoWrapup ?? false,
|
|
406
|
+
aiFeature: mockAgentProfile.aiFeature,
|
|
382
407
|
});
|
|
383
408
|
expect(reloadSpy).toHaveBeenCalled();
|
|
384
409
|
expect(result).toEqual(mockAgentProfile);
|
|
@@ -417,7 +442,7 @@ describe('webex.cc', () => {
|
|
|
417
442
|
clientType: 'WebexCCSDK',
|
|
418
443
|
allowMultiLogin: true,
|
|
419
444
|
},
|
|
420
|
-
resource:
|
|
445
|
+
resource: SUBSCRIBE_API,
|
|
421
446
|
});
|
|
422
447
|
expect(configSpy).toHaveBeenCalled();
|
|
423
448
|
expect(LoggerProxy.log).toHaveBeenCalledWith('Agent config is fetched successfully', {
|
|
@@ -439,7 +464,7 @@ describe('webex.cc', () => {
|
|
|
439
464
|
|
|
440
465
|
await expect(webex.cc.register()).rejects.toThrow('Error while performing register');
|
|
441
466
|
|
|
442
|
-
expect(LoggerProxy.
|
|
467
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting CC SDK registration', {
|
|
443
468
|
module: CC_FILE,
|
|
444
469
|
method: 'register',
|
|
445
470
|
});
|
|
@@ -497,7 +522,7 @@ describe('webex.cc', () => {
|
|
|
497
522
|
clientType: 'WebexCCSDK',
|
|
498
523
|
allowMultiLogin: false,
|
|
499
524
|
},
|
|
500
|
-
resource:
|
|
525
|
+
resource: SUBSCRIBE_API,
|
|
501
526
|
});
|
|
502
527
|
|
|
503
528
|
expect(mockTaskManager.on).toHaveBeenCalledWith(
|
|
@@ -555,6 +580,7 @@ describe('webex.cc', () => {
|
|
|
555
580
|
|
|
556
581
|
it('should not attempt for mercury connection when webrtc is disabled', async () => {
|
|
557
582
|
mockAgentProfile.webRtcEnabled = false;
|
|
583
|
+
mockAgentProfile.aiFeature = {realtimeTranscripts: {enable: false}} as any;
|
|
558
584
|
const mercurySpy = jest.spyOn(webex.internal.mercury, 'connect');
|
|
559
585
|
const connectWebsocketSpy = jest.spyOn(webex.cc, 'connectWebsocket');
|
|
560
586
|
const setupEventListenersSpy = jest.spyOn(webex.cc, 'setupEventListeners');
|
|
@@ -584,13 +610,39 @@ describe('webex.cc', () => {
|
|
|
584
610
|
clientType: 'WebexCCSDK',
|
|
585
611
|
allowMultiLogin: false,
|
|
586
612
|
},
|
|
587
|
-
resource:
|
|
613
|
+
resource: SUBSCRIBE_API,
|
|
588
614
|
});
|
|
589
615
|
|
|
590
616
|
expect(configSpy).toHaveBeenCalled();
|
|
591
617
|
expect(mercurySpy).not.toHaveBeenCalled();
|
|
618
|
+
expect(webex.cc.services.rtdWebSocketManager.initWebSocket).not.toHaveBeenCalled();
|
|
592
619
|
expect(result).toEqual(mockAgentProfile);
|
|
593
620
|
});
|
|
621
|
+
|
|
622
|
+
it('should not connect RTD websocket when realtime transcripts feature is disabled', async () => {
|
|
623
|
+
mockAgentProfile.aiFeature = {realtimeTranscripts: {enable: false}} as any;
|
|
624
|
+
jest.spyOn(webex.internal.mercury, 'connect').mockResolvedValue(true);
|
|
625
|
+
jest.spyOn(webex.cc.services.agent, 'reload').mockResolvedValue({
|
|
626
|
+
data: {
|
|
627
|
+
auxCodeId: 'auxCodeId',
|
|
628
|
+
agentId: 'agentId',
|
|
629
|
+
deviceType: LoginOption.EXTENSION,
|
|
630
|
+
dn: '12345',
|
|
631
|
+
},
|
|
632
|
+
});
|
|
633
|
+
jest.spyOn(webex.cc.services.config, 'getAgentConfig').mockResolvedValue(mockAgentProfile);
|
|
634
|
+
mockWebSocketManager.initWebSocket.mockResolvedValue({
|
|
635
|
+
agentId: 'agent123',
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
await webex.cc.register();
|
|
639
|
+
|
|
640
|
+
expect(webex.cc.services.rtdWebSocketManager.initWebSocket).not.toHaveBeenCalled();
|
|
641
|
+
expect(webex.cc.services.rtdWebSocketManager.on).not.toHaveBeenCalledWith(
|
|
642
|
+
'message',
|
|
643
|
+
expect.any(Function)
|
|
644
|
+
);
|
|
645
|
+
});
|
|
594
646
|
});
|
|
595
647
|
|
|
596
648
|
describe('stationLogin', () => {
|
|
@@ -694,10 +746,8 @@ describe('webex.cc', () => {
|
|
|
694
746
|
|
|
695
747
|
expect(emitSpy).toHaveBeenCalledTimes(1);
|
|
696
748
|
expect(emitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_INCOMING, mockTask);
|
|
697
|
-
// Verify message
|
|
698
|
-
const messageCallback =
|
|
699
|
-
(call) => call[0] === 'message'
|
|
700
|
-
)[1];
|
|
749
|
+
// Verify websocket message handling
|
|
750
|
+
const messageCallback = webex.cc['handleWebsocketMessage'];
|
|
701
751
|
const agentStateChangeEventData = {
|
|
702
752
|
type: CC_EVENTS.AGENT_STATE_CHANGE,
|
|
703
753
|
data: {some: 'data'},
|
|
@@ -900,10 +950,13 @@ describe('webex.cc', () => {
|
|
|
900
950
|
const result = await webex.cc.stationLogin(options);
|
|
901
951
|
|
|
902
952
|
// Verify logging calls
|
|
903
|
-
expect(LoggerProxy.
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
953
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
954
|
+
`Starting agent station login | loginOption: ${options.loginOption} teamId: ${options.teamId}`,
|
|
955
|
+
{
|
|
956
|
+
module: CC_FILE,
|
|
957
|
+
method: 'stationLogin',
|
|
958
|
+
}
|
|
959
|
+
);
|
|
907
960
|
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
908
961
|
`Agent station login completed successfully agentId: ${mockData.data.agentId} loginOption: ${mockData.data.loginOption} teamId: ${mockData.data.teamId}`,
|
|
909
962
|
{
|
|
@@ -954,10 +1007,13 @@ describe('webex.cc', () => {
|
|
|
954
1007
|
|
|
955
1008
|
await expect(webex.cc.stationLogin(options)).rejects.toThrow(error.details.data.reason);
|
|
956
1009
|
|
|
957
|
-
expect(LoggerProxy.
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1010
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
1011
|
+
`Starting agent station login | loginOption: ${options.loginOption} teamId: ${options.teamId}`,
|
|
1012
|
+
{
|
|
1013
|
+
module: CC_FILE,
|
|
1014
|
+
method: 'stationLogin',
|
|
1015
|
+
}
|
|
1016
|
+
);
|
|
961
1017
|
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
962
1018
|
`stationLogin failed with reason: ${error.details.data.reason}`,
|
|
963
1019
|
{module: CC_FILE, method: 'stationLogin', trackingId: error.details.trackingId}
|
|
@@ -1296,11 +1352,11 @@ describe('webex.cc', () => {
|
|
|
1296
1352
|
const webSocketManagerOnSpy = jest.spyOn(webex.cc.services.webSocketManager, 'on');
|
|
1297
1353
|
await webex.cc['silentRelogin']();
|
|
1298
1354
|
|
|
1299
|
-
expect(LoggerProxy.
|
|
1355
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1300
1356
|
module: CC_FILE,
|
|
1301
1357
|
method: 'silentRelogin',
|
|
1302
1358
|
});
|
|
1303
|
-
expect(LoggerProxy.
|
|
1359
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
1304
1360
|
'event=requestAutoStateChange | Requesting state change to available on socket reconnect',
|
|
1305
1361
|
{module: CC_FILE, method: 'silentRelogin'}
|
|
1306
1362
|
);
|
|
@@ -1345,7 +1401,7 @@ describe('webex.cc', () => {
|
|
|
1345
1401
|
|
|
1346
1402
|
jest.spyOn(webex.cc.services.agent, 'reload').mockRejectedValue(error);
|
|
1347
1403
|
await webex.cc['silentRelogin']();
|
|
1348
|
-
expect(LoggerProxy.
|
|
1404
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1349
1405
|
module: CC_FILE,
|
|
1350
1406
|
method: 'silentRelogin',
|
|
1351
1407
|
});
|
|
@@ -1360,7 +1416,7 @@ describe('webex.cc', () => {
|
|
|
1360
1416
|
jest.spyOn(webex.cc.services.agent, 'reload').mockRejectedValue(error);
|
|
1361
1417
|
|
|
1362
1418
|
await expect(webex.cc['silentRelogin']()).rejects.toThrow(error);
|
|
1363
|
-
expect(LoggerProxy.
|
|
1419
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1364
1420
|
module: CC_FILE,
|
|
1365
1421
|
method: 'silentRelogin',
|
|
1366
1422
|
});
|
|
@@ -1402,7 +1458,7 @@ describe('webex.cc', () => {
|
|
|
1402
1458
|
|
|
1403
1459
|
await webex.cc['silentRelogin']();
|
|
1404
1460
|
|
|
1405
|
-
expect(LoggerProxy.
|
|
1461
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1406
1462
|
module: CC_FILE,
|
|
1407
1463
|
method: 'silentRelogin',
|
|
1408
1464
|
});
|
|
@@ -1678,6 +1734,13 @@ describe('webex.cc', () => {
|
|
|
1678
1734
|
});
|
|
1679
1735
|
|
|
1680
1736
|
it('should unregister successfully and clean up all resources when webrtc is enabled', async () => {
|
|
1737
|
+
webex.cc.services.rtdWebSocketManager = {
|
|
1738
|
+
isSocketClosed: false,
|
|
1739
|
+
close: jest.fn(),
|
|
1740
|
+
off: jest.fn(),
|
|
1741
|
+
on: jest.fn(),
|
|
1742
|
+
} as any;
|
|
1743
|
+
|
|
1681
1744
|
await webex.cc.deregister();
|
|
1682
1745
|
|
|
1683
1746
|
expect(mockTaskManager.off).toHaveBeenCalledWith(
|
|
@@ -1693,13 +1756,20 @@ describe('webex.cc', () => {
|
|
|
1693
1756
|
expect.any(Function)
|
|
1694
1757
|
);
|
|
1695
1758
|
expect(mockWebSocketManager.off).toHaveBeenCalledWith('message', expect.any(Function));
|
|
1759
|
+
expect(webex.cc.services.rtdWebSocketManager.off).toHaveBeenCalledWith(
|
|
1760
|
+
'message',
|
|
1761
|
+
expect.any(Function)
|
|
1762
|
+
);
|
|
1696
1763
|
expect(webex.cc.services.connectionService.off).toHaveBeenCalledWith(
|
|
1697
1764
|
'connectionLost',
|
|
1698
1765
|
expect.any(Function)
|
|
1699
1766
|
);
|
|
1700
1767
|
|
|
1701
1768
|
expect(mockWebSocketManager.close).toHaveBeenCalledWith(false, 'Unregistering the SDK');
|
|
1702
|
-
expect(
|
|
1769
|
+
expect(webex.cc.services.rtdWebSocketManager.close).toHaveBeenCalledWith(
|
|
1770
|
+
false,
|
|
1771
|
+
'Unregistering the RTD websocket'
|
|
1772
|
+
);
|
|
1703
1773
|
expect(webex.cc.agentConfig).toBeNull();
|
|
1704
1774
|
|
|
1705
1775
|
expect(webex.internal.mercury.off).toHaveBeenCalledWith('online');
|
|
@@ -1848,7 +1918,7 @@ describe('webex.cc', () => {
|
|
|
1848
1918
|
|
|
1849
1919
|
beforeEach(() => {
|
|
1850
1920
|
emitSpy = jest.spyOn(webex.cc, 'emit');
|
|
1851
|
-
messageCallback =
|
|
1921
|
+
messageCallback = webex.cc['handleWebsocketMessage'];
|
|
1852
1922
|
});
|
|
1853
1923
|
|
|
1854
1924
|
it('should emit AGENT_STATION_LOGIN_SUCCESS on CC_EVENTS.AGENT_STATION_LOGIN_SUCCESS with mapped payload', () => {
|
|
@@ -2378,4 +2448,196 @@ describe('webex.cc', () => {
|
|
|
2378
2448
|
);
|
|
2379
2449
|
});
|
|
2380
2450
|
});
|
|
2451
|
+
|
|
2452
|
+
describe('acceptPreviewContact', () => {
|
|
2453
|
+
const previewPayload = {
|
|
2454
|
+
interactionId: 'interaction-123',
|
|
2455
|
+
campaignId: 'campaign-456',
|
|
2456
|
+
};
|
|
2457
|
+
|
|
2458
|
+
it('should accept preview contact successfully', async () => {
|
|
2459
|
+
const mockResponse = {trackingId: 'track-123'} as AgentContact;
|
|
2460
|
+
|
|
2461
|
+
const acceptPreviewContactMock = jest
|
|
2462
|
+
.spyOn(webex.cc.services.dialer, 'acceptPreviewContact')
|
|
2463
|
+
.mockResolvedValue(mockResponse);
|
|
2464
|
+
|
|
2465
|
+
const result = await webex.cc.acceptPreviewContact(previewPayload);
|
|
2466
|
+
|
|
2467
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Accepting campaign preview contact', {
|
|
2468
|
+
module: CC_FILE,
|
|
2469
|
+
method: 'acceptPreviewContact',
|
|
2470
|
+
});
|
|
2471
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
2472
|
+
'Campaign preview contact accepted successfully',
|
|
2473
|
+
{
|
|
2474
|
+
module: CC_FILE,
|
|
2475
|
+
method: 'acceptPreviewContact',
|
|
2476
|
+
trackingId: 'track-123',
|
|
2477
|
+
interactionId: previewPayload.interactionId,
|
|
2478
|
+
}
|
|
2479
|
+
);
|
|
2480
|
+
|
|
2481
|
+
expect(acceptPreviewContactMock).toHaveBeenCalledWith({data: previewPayload});
|
|
2482
|
+
expect(result).toEqual(mockResponse);
|
|
2483
|
+
});
|
|
2484
|
+
|
|
2485
|
+
it('should handle error during acceptPreviewContact', async () => {
|
|
2486
|
+
getErrorDetailsSpy.mockRestore();
|
|
2487
|
+
getErrorDetailsSpy = jest.spyOn(Utils, 'getErrorDetails');
|
|
2488
|
+
|
|
2489
|
+
const error = {
|
|
2490
|
+
details: {
|
|
2491
|
+
trackingId: '1234',
|
|
2492
|
+
data: {
|
|
2493
|
+
reason: 'Error while performing acceptPreviewContact',
|
|
2494
|
+
},
|
|
2495
|
+
},
|
|
2496
|
+
};
|
|
2497
|
+
|
|
2498
|
+
jest.spyOn(webex.cc.services.dialer, 'acceptPreviewContact').mockRejectedValue(error);
|
|
2499
|
+
|
|
2500
|
+
await expect(webex.cc.acceptPreviewContact(previewPayload)).rejects.toThrow(
|
|
2501
|
+
error.details.data.reason
|
|
2502
|
+
);
|
|
2503
|
+
|
|
2504
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Accepting campaign preview contact', {
|
|
2505
|
+
module: CC_FILE,
|
|
2506
|
+
method: 'acceptPreviewContact',
|
|
2507
|
+
});
|
|
2508
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
2509
|
+
`acceptPreviewContact failed with reason: ${error.details.data.reason}`,
|
|
2510
|
+
{module: CC_FILE, method: 'acceptPreviewContact', trackingId: error.details.trackingId}
|
|
2511
|
+
);
|
|
2512
|
+
expect(getErrorDetailsSpy).toHaveBeenCalledWith(error, 'acceptPreviewContact', CC_FILE);
|
|
2513
|
+
});
|
|
2514
|
+
});
|
|
2515
|
+
|
|
2516
|
+
describe('skipPreviewContact', () => {
|
|
2517
|
+
const previewPayload = {
|
|
2518
|
+
interactionId: 'interaction-123',
|
|
2519
|
+
campaignId: 'campaign-456',
|
|
2520
|
+
};
|
|
2521
|
+
|
|
2522
|
+
it('should skip preview contact successfully', async () => {
|
|
2523
|
+
const mockResponse = {trackingId: 'track-123'} as AgentContact;
|
|
2524
|
+
|
|
2525
|
+
const skipPreviewContactMock = jest
|
|
2526
|
+
.spyOn(webex.cc.services.dialer, 'skipPreviewContact')
|
|
2527
|
+
.mockResolvedValue(mockResponse);
|
|
2528
|
+
|
|
2529
|
+
const result = await webex.cc.skipPreviewContact(previewPayload);
|
|
2530
|
+
|
|
2531
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Skipping campaign preview contact', {
|
|
2532
|
+
module: CC_FILE,
|
|
2533
|
+
method: 'skipPreviewContact',
|
|
2534
|
+
});
|
|
2535
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
2536
|
+
'Campaign preview contact skipped successfully',
|
|
2537
|
+
{
|
|
2538
|
+
module: CC_FILE,
|
|
2539
|
+
method: 'skipPreviewContact',
|
|
2540
|
+
trackingId: 'track-123',
|
|
2541
|
+
interactionId: previewPayload.interactionId,
|
|
2542
|
+
}
|
|
2543
|
+
);
|
|
2544
|
+
|
|
2545
|
+
expect(skipPreviewContactMock).toHaveBeenCalledWith({data: previewPayload});
|
|
2546
|
+
expect(result).toEqual(mockResponse);
|
|
2547
|
+
});
|
|
2548
|
+
|
|
2549
|
+
it('should handle error during skipPreviewContact', async () => {
|
|
2550
|
+
getErrorDetailsSpy.mockRestore();
|
|
2551
|
+
getErrorDetailsSpy = jest.spyOn(Utils, 'getErrorDetails');
|
|
2552
|
+
|
|
2553
|
+
const error = {
|
|
2554
|
+
details: {
|
|
2555
|
+
trackingId: '1234',
|
|
2556
|
+
data: {
|
|
2557
|
+
reason: 'Error while performing skipPreviewContact',
|
|
2558
|
+
},
|
|
2559
|
+
},
|
|
2560
|
+
};
|
|
2561
|
+
|
|
2562
|
+
jest.spyOn(webex.cc.services.dialer, 'skipPreviewContact').mockRejectedValue(error);
|
|
2563
|
+
|
|
2564
|
+
await expect(webex.cc.skipPreviewContact(previewPayload)).rejects.toThrow(
|
|
2565
|
+
error.details.data.reason
|
|
2566
|
+
);
|
|
2567
|
+
|
|
2568
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Skipping campaign preview contact', {
|
|
2569
|
+
module: CC_FILE,
|
|
2570
|
+
method: 'skipPreviewContact',
|
|
2571
|
+
});
|
|
2572
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
2573
|
+
`skipPreviewContact failed with reason: ${error.details.data.reason}`,
|
|
2574
|
+
{module: CC_FILE, method: 'skipPreviewContact', trackingId: error.details.trackingId}
|
|
2575
|
+
);
|
|
2576
|
+
expect(getErrorDetailsSpy).toHaveBeenCalledWith(error, 'skipPreviewContact', CC_FILE);
|
|
2577
|
+
});
|
|
2578
|
+
});
|
|
2579
|
+
|
|
2580
|
+
describe('removePreviewContact', () => {
|
|
2581
|
+
const previewPayload = {
|
|
2582
|
+
interactionId: 'interaction-123',
|
|
2583
|
+
campaignId: 'campaign-456',
|
|
2584
|
+
};
|
|
2585
|
+
|
|
2586
|
+
it('should remove preview contact successfully', async () => {
|
|
2587
|
+
const mockResponse = {trackingId: 'track-123'} as AgentContact;
|
|
2588
|
+
|
|
2589
|
+
const removePreviewContactMock = jest
|
|
2590
|
+
.spyOn(webex.cc.services.dialer, 'removePreviewContact')
|
|
2591
|
+
.mockResolvedValue(mockResponse);
|
|
2592
|
+
|
|
2593
|
+
const result = await webex.cc.removePreviewContact(previewPayload);
|
|
2594
|
+
|
|
2595
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Removing campaign preview contact', {
|
|
2596
|
+
module: CC_FILE,
|
|
2597
|
+
method: 'removePreviewContact',
|
|
2598
|
+
});
|
|
2599
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
2600
|
+
'Campaign preview contact removed successfully',
|
|
2601
|
+
{
|
|
2602
|
+
module: CC_FILE,
|
|
2603
|
+
method: 'removePreviewContact',
|
|
2604
|
+
trackingId: 'track-123',
|
|
2605
|
+
interactionId: previewPayload.interactionId,
|
|
2606
|
+
}
|
|
2607
|
+
);
|
|
2608
|
+
|
|
2609
|
+
expect(removePreviewContactMock).toHaveBeenCalledWith({data: previewPayload});
|
|
2610
|
+
expect(result).toEqual(mockResponse);
|
|
2611
|
+
});
|
|
2612
|
+
|
|
2613
|
+
it('should handle error during removePreviewContact', async () => {
|
|
2614
|
+
getErrorDetailsSpy.mockRestore();
|
|
2615
|
+
getErrorDetailsSpy = jest.spyOn(Utils, 'getErrorDetails');
|
|
2616
|
+
|
|
2617
|
+
const error = {
|
|
2618
|
+
details: {
|
|
2619
|
+
trackingId: '1234',
|
|
2620
|
+
data: {
|
|
2621
|
+
reason: 'Error while performing removePreviewContact',
|
|
2622
|
+
},
|
|
2623
|
+
},
|
|
2624
|
+
};
|
|
2625
|
+
|
|
2626
|
+
jest.spyOn(webex.cc.services.dialer, 'removePreviewContact').mockRejectedValue(error);
|
|
2627
|
+
|
|
2628
|
+
await expect(webex.cc.removePreviewContact(previewPayload)).rejects.toThrow(
|
|
2629
|
+
error.details.data.reason
|
|
2630
|
+
);
|
|
2631
|
+
|
|
2632
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Removing campaign preview contact', {
|
|
2633
|
+
module: CC_FILE,
|
|
2634
|
+
method: 'removePreviewContact',
|
|
2635
|
+
});
|
|
2636
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
2637
|
+
`removePreviewContact failed with reason: ${error.details.data.reason}`,
|
|
2638
|
+
{module: CC_FILE, method: 'removePreviewContact', trackingId: error.details.trackingId}
|
|
2639
|
+
);
|
|
2640
|
+
expect(getErrorDetailsSpy).toHaveBeenCalledWith(error, 'removePreviewContact', CC_FILE);
|
|
2641
|
+
});
|
|
2642
|
+
});
|
|
2381
2643
|
});
|