@webex/contact-center 3.12.0-next.13 → 3.12.0-next.130
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/.sdd/manifest.json +884 -0
- package/AGENTS.md +94 -0
- package/ai-docs/ARCHITECTURE.md +168 -0
- package/ai-docs/CONTRACTS.md +53 -0
- package/ai-docs/GETTING_STARTED.md +168 -0
- package/ai-docs/GLOSSARY.md +43 -0
- package/ai-docs/README.md +138 -0
- package/ai-docs/REVIEW_CHECKLIST.md +41 -0
- package/ai-docs/RULES.md +444 -0
- package/ai-docs/SECURITY.md +52 -0
- package/ai-docs/SERVICE_STATE.md +52 -0
- package/ai-docs/SPEC_INDEX.md +65 -0
- package/ai-docs/adr/0001-spec-source-policy.md +55 -0
- package/ai-docs/adr/README.md +8 -0
- package/ai-docs/adr/_adr-template.md +31 -0
- package/ai-docs/contact-center-spec.md +382 -0
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/ai-docs/features/contact-owner-change-refactor.md +78 -0
- package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
- package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
- package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
- package/ai-docs/patterns/event-driven-patterns.md +485 -0
- package/ai-docs/patterns/testing-patterns.md +480 -0
- package/ai-docs/patterns/typescript-patterns.md +365 -0
- package/ai-docs/templates/README.md +102 -0
- package/ai-docs/templates/documentation/create-agents-md.md +240 -0
- package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
- package/ai-docs/templates/existing-service/bug-fix.md +254 -0
- package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
- package/ai-docs/templates/new-method/00-master.md +80 -0
- package/ai-docs/templates/new-method/01-requirements.md +232 -0
- package/ai-docs/templates/new-method/02-implementation.md +295 -0
- package/ai-docs/templates/new-method/03-tests.md +201 -0
- package/ai-docs/templates/new-method/04-validation.md +141 -0
- package/ai-docs/templates/new-service/00-master.md +109 -0
- package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
- package/ai-docs/templates/new-service/02-code-generation.md +346 -0
- package/ai-docs/templates/new-service/03-integration.md +178 -0
- package/ai-docs/templates/new-service/04-test-generation.md +205 -0
- package/ai-docs/templates/new-service/05-validation.md +145 -0
- package/dist/cc.js +971 -42
- package/dist/cc.js.map +1 -1
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +31 -3
- package/dist/constants.js.map +1 -1
- package/dist/index.js +45 -15
- package/dist/index.js.map +1 -1
- package/dist/metrics/MetricsManager.js +16 -0
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +205 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +48 -4
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +18 -15
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/AnswerCallOnWebexService.js +202 -0
- package/dist/services/AnswerCallOnWebexService.js.map +1 -0
- package/dist/services/ApiAiAssistant.js +269 -9
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/EntryPoint.js +46 -68
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +27 -22
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/UserPreference.js +427 -0
- package/dist/services/UserPreference.js.map +1 -0
- package/dist/services/WebexCrossClientService.js +222 -0
- package/dist/services/WebexCrossClientService.js.map +1 -0
- package/dist/services/WxAppTelephonyMercurySync.js +108 -0
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
- package/dist/services/config/Util.js +11 -4
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +41 -7
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +51 -0
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +57 -12
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +111 -32
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/WebexRequest.js +6 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +28 -14
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +2 -1
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +754 -0
- package/dist/services/task/Task.js.map +1 -0
- package/dist/services/task/TaskFactory.js +49 -0
- package/dist/services/task/TaskFactory.js.map +1 -0
- package/dist/services/task/TaskManager.js +1172 -521
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +211 -27
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/WebexCallingUtils.js +70 -0
- package/dist/services/task/WebexCallingUtils.js.map +1 -0
- package/dist/services/task/constants.js +12 -2
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +29 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/dialer.js +78 -0
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/digital/Digital.js +78 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +982 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
- package/dist/services/task/state-machine/actions.js +572 -0
- package/dist/services/task/state-machine/actions.js.map +1 -0
- package/dist/services/task/state-machine/constants.js +161 -0
- package/dist/services/task/state-machine/constants.js.map +1 -0
- package/dist/services/task/state-machine/guards.js +379 -0
- package/dist/services/task/state-machine/guards.js.map +1 -0
- package/dist/services/task/state-machine/index.js +53 -0
- package/dist/services/task/state-machine/index.js.map +1 -0
- package/dist/services/task/state-machine/types.js +54 -0
- package/dist/services/task/state-machine/types.js.map +1 -0
- package/dist/services/task/state-machine/uiControlsComputer.js +703 -0
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
- package/dist/services/task/taskDataNormalizer.js +99 -0
- package/dist/services/task/taskDataNormalizer.js.map +1 -0
- package/dist/services/task/types.js +228 -5
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1485 -0
- package/dist/services/task/voice/Voice.js.map +1 -0
- package/dist/services/task/voice/WebRTC.js +152 -0
- package/dist/services/task/voice/WebRTC.js.map +1 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js +354 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
- package/dist/services/wxAppDiagnosticLogging.js +122 -0
- package/dist/services/wxAppDiagnosticLogging.js.map +1 -0
- package/dist/services/wxAppTelephonyUtils.js +19 -0
- package/dist/services/wxAppTelephonyUtils.js.map +1 -0
- package/dist/types/cc.d.ts +193 -6
- package/dist/types/config.d.ts +13 -0
- package/dist/types/constants.d.ts +29 -1
- package/dist/types/index.d.ts +35 -8
- package/dist/types/metrics/MetricsManager.d.ts +6 -0
- package/dist/types/metrics/constants.d.ts +43 -1
- package/dist/types/services/AddressBook.d.ts +2 -1
- package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
- package/dist/types/services/ApiAiAssistant.d.ts +56 -5
- package/dist/types/services/EntryPoint.d.ts +7 -5
- package/dist/types/services/Queue.d.ts +5 -3
- package/dist/types/services/UserPreference.d.ts +118 -0
- package/dist/types/services/WebexCrossClientService.d.ts +32 -0
- package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
- package/dist/types/services/config/constants.d.ts +34 -5
- package/dist/types/services/config/types.d.ts +197 -12
- package/dist/types/services/core/Err.d.ts +6 -0
- package/dist/types/services/core/Utils.d.ts +35 -13
- package/dist/types/services/core/WebexRequest.d.ts +1 -0
- package/dist/types/services/core/types.d.ts +2 -0
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
- package/dist/types/services/core/websocket/types.d.ts +1 -1
- package/dist/types/services/index.d.ts +1 -1
- package/dist/types/services/task/Task.d.ts +175 -0
- package/dist/types/services/task/TaskFactory.d.ts +13 -0
- package/dist/types/services/task/TaskUtils.d.ts +48 -2
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +10 -0
- package/dist/types/services/task/contact.d.ts +4 -0
- package/dist/types/services/task/dialer.d.ts +30 -0
- package/dist/types/services/task/digital/Digital.d.ts +22 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1442 -0
- package/dist/types/services/task/state-machine/actions.d.ts +10 -0
- package/dist/types/services/task/state-machine/constants.d.ts +107 -0
- package/dist/types/services/task/state-machine/guards.d.ts +103 -0
- package/dist/types/services/task/state-machine/index.d.ts +13 -0
- package/dist/types/services/task/state-machine/types.d.ts +277 -0
- package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
- package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
- package/dist/types/services/task/types.d.ts +680 -66
- package/dist/types/services/task/voice/Voice.d.ts +227 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +55 -0
- package/dist/types/services/wxAppDiagnosticLogging.d.ts +51 -0
- package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
- package/dist/types/types.d.ts +205 -9
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +162 -4
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +19 -5
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex.js +22 -2
- package/dist/webex.js.map +1 -1
- package/package.json +16 -12
- package/src/cc.ts +1289 -112
- package/src/config.ts +13 -0
- package/src/constants.ts +29 -1
- package/src/index.ts +36 -5
- package/src/metrics/MetricsManager.ts +16 -0
- package/src/metrics/ai-docs/AGENTS.md +350 -0
- package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
- package/src/metrics/ai-docs/metrics-spec.md +921 -0
- package/src/metrics/behavioral-events.ts +212 -0
- package/src/metrics/constants.ts +52 -4
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +239 -0
- package/src/services/ApiAiAssistant.ts +356 -9
- package/src/services/EntryPoint.ts +59 -60
- package/src/services/Queue.ts +29 -12
- package/src/services/UserPreference.ts +509 -0
- package/src/services/WebexCrossClientService.ts +293 -0
- package/src/services/WxAppTelephonyMercurySync.ts +142 -0
- package/src/services/agent/ai-docs/AGENTS.md +240 -0
- package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
- package/src/services/agent/ai-docs/agent-spec.md +505 -0
- package/src/services/ai-docs/AGENTS.md +386 -0
- package/src/services/ai-docs/services-spec.md +505 -0
- package/src/services/config/Util.ts +12 -3
- package/src/services/config/ai-docs/AGENTS.md +255 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
- package/src/services/config/ai-docs/config-spec.md +686 -0
- package/src/services/config/constants.ts +46 -6
- package/src/services/config/index.ts +65 -0
- package/src/services/config/types.ts +197 -13
- package/src/services/core/Err.ts +3 -0
- package/src/services/core/Utils.ts +127 -37
- package/src/services/core/WebexRequest.ts +3 -1
- package/src/services/core/ai-docs/AGENTS.md +381 -0
- package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
- package/src/services/core/ai-docs/core-spec.md +787 -0
- package/src/services/core/aqm-reqs.ts +30 -15
- package/src/services/core/types.ts +2 -0
- package/src/services/core/websocket/WebSocketManager.ts +2 -0
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +1 -1
- package/src/services/task/Task.ts +908 -0
- package/src/services/task/TaskFactory.ts +60 -0
- package/src/services/task/TaskManager.ts +1419 -608
- package/src/services/task/TaskUtils.ts +303 -25
- package/src/services/task/WebexCallingUtils.ts +136 -0
- package/src/services/task/ai-docs/AGENTS.md +457 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
- package/src/services/task/ai-docs/task-spec.md +1474 -0
- package/src/services/task/constants.ts +10 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/dialer.ts +80 -0
- package/src/services/task/digital/Digital.ts +97 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +1320 -0
- package/src/services/task/state-machine/actions.ts +741 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +460 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1156 -0
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2247 -0
- package/src/services/task/state-machine/constants.ts +172 -0
- package/src/services/task/state-machine/guards.ts +442 -0
- package/src/services/task/state-machine/index.ts +28 -0
- package/src/services/task/state-machine/types.ts +258 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
- package/src/services/task/taskDataNormalizer.ts +137 -0
- package/src/services/task/types.ts +819 -70
- package/src/services/task/voice/Voice.ts +1851 -0
- package/src/services/task/voice/WebRTC.ts +191 -0
- package/src/services/task/voice/wxAppVoiceMethods.ts +516 -0
- package/src/services/wxAppDiagnosticLogging.ts +174 -0
- package/src/services/wxAppTelephonyUtils.ts +14 -0
- package/src/types.ts +262 -11
- package/src/utils/AGENTS.md +289 -0
- package/src/utils/PageCache.ts +38 -5
- package/src/utils/ai-docs/utils-spec.md +391 -0
- package/src/webex.js +10 -0
- package/test/unit/spec/cc.ts +2210 -119
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/metrics/MetricsManager.ts +25 -0
- package/test/unit/spec/metrics/behavioral-events.ts +60 -0
- package/test/unit/spec/services/AddressBook.ts +37 -6
- package/test/unit/spec/services/AnswerCallOnWebexService.ts +264 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +311 -21
- package/test/unit/spec/services/EntryPoint.ts +87 -40
- package/test/unit/spec/services/Queue.ts +123 -12
- package/test/unit/spec/services/UserPreference.ts +401 -0
- package/test/unit/spec/services/WebCallingService.ts +7 -1
- package/test/unit/spec/services/WebexCrossClientService.ts +467 -0
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
- package/test/unit/spec/services/config/Util.ts +129 -0
- package/test/unit/spec/services/config/index.ts +97 -29
- package/test/unit/spec/services/core/Utils.ts +425 -8
- package/test/unit/spec/services/core/WebexRequest.ts +3 -1
- package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +745 -0
- package/test/unit/spec/services/task/TaskFactory.ts +99 -0
- package/test/unit/spec/services/task/TaskManager.ts +2518 -1494
- package/test/unit/spec/services/task/TaskUtils.ts +235 -0
- package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
- package/test/unit/spec/services/task/contact.ts +33 -0
- package/test/unit/spec/services/task/dialer.ts +190 -0
- package/test/unit/spec/services/task/digital/Digital.ts +105 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +4060 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
- package/test/unit/spec/services/task/state-machine/types.ts +18 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
- package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
- package/test/unit/spec/services/task/voice/Voice.ts +2061 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +603 -0
- package/test/unit/spec/services/wxAppDiagnosticLogging.ts +143 -0
- package/test/unit/spec/wellnessSampleUtils.ts +288 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/index.js +0 -1525
- package/dist/services/task/index.js.map +0 -1
- package/dist/types/services/task/index.d.ts +0 -650
- package/src/services/task/index.ts +0 -1801
- package/test/unit/spec/services/task/index.ts +0 -2184
|
@@ -8,6 +8,12 @@ import {
|
|
|
8
8
|
isDigitalOutbound,
|
|
9
9
|
hasAgentInitiatedOutdial,
|
|
10
10
|
shouldAutoAnswerTask,
|
|
11
|
+
getIsCustomerInCall,
|
|
12
|
+
getConferenceParticipantsCount,
|
|
13
|
+
isSecondaryAgent,
|
|
14
|
+
isSecondaryEpDnAgent,
|
|
15
|
+
getConsultMediaResourceId,
|
|
16
|
+
getIsConsultInProgressForConferenceControls,
|
|
11
17
|
} from '../../../../../src/services/task/TaskUtils';
|
|
12
18
|
import {ITask, Interaction, TaskData} from '../../../../../src/services/task/types';
|
|
13
19
|
import {LoginOption} from '../../../../../src/types';
|
|
@@ -430,4 +436,233 @@ describe('TaskUtils', () => {
|
|
|
430
436
|
});
|
|
431
437
|
});
|
|
432
438
|
});
|
|
439
|
+
|
|
440
|
+
// Additional coverage for conference/consult utility functions
|
|
441
|
+
describe('Conference Utility Functions', () => {
|
|
442
|
+
const interactionId = 'interaction-123';
|
|
443
|
+
const createInteraction = (media: any = {}, participants: any = {}) =>
|
|
444
|
+
({interactionId, mainInteractionId: interactionId, media, participants}) as any;
|
|
445
|
+
|
|
446
|
+
it('getIsCustomerInCall returns true when customer active', () => {
|
|
447
|
+
const interaction = createInteraction(
|
|
448
|
+
{[interactionId]: {mType: 'mainCall', participants: ['c1']}},
|
|
449
|
+
{'c1': {pType: 'Customer', hasLeft: false}}
|
|
450
|
+
);
|
|
451
|
+
expect(getIsCustomerInCall(interaction, interactionId)).toBe(true);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it('getIsCustomerInCall returns false when participants map is missing', () => {
|
|
455
|
+
const interaction = createInteraction(
|
|
456
|
+
{[interactionId]: {mType: 'mainCall', participants: ['c1']}},
|
|
457
|
+
undefined
|
|
458
|
+
);
|
|
459
|
+
expect(getIsCustomerInCall(interaction, interactionId)).toBe(false);
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
it('getConferenceParticipantsCount counts active agents only', () => {
|
|
463
|
+
const interaction = createInteraction(
|
|
464
|
+
{[interactionId]: {mType: 'mainCall', participants: ['a1', 'a2', 'c1']}},
|
|
465
|
+
{'a1': {pType: 'Agent', hasLeft: false}, 'a2': {pType: 'Agent', hasLeft: false}, 'c1': {pType: 'Customer', hasLeft: false}}
|
|
466
|
+
);
|
|
467
|
+
expect(getConferenceParticipantsCount(interaction, interactionId)).toBe(2);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it('getConferenceParticipantsCount returns 0 when participants map is missing', () => {
|
|
471
|
+
const interaction = createInteraction(
|
|
472
|
+
{[interactionId]: {mType: 'mainCall', participants: ['a1', 'a2', 'c1']}},
|
|
473
|
+
undefined
|
|
474
|
+
);
|
|
475
|
+
expect(getConferenceParticipantsCount(interaction, interactionId)).toBe(0);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it('isSecondaryAgent returns true for consult with parentInteractionId', () => {
|
|
479
|
+
const interaction = createInteraction();
|
|
480
|
+
interaction.callProcessingDetails = {relationshipType: 'consult', parentInteractionId: 'parent-456'};
|
|
481
|
+
expect(isSecondaryAgent(interaction)).toBe(true);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
it('isSecondaryEpDnAgent returns true for telephony secondary agent', () => {
|
|
485
|
+
const interaction = createInteraction();
|
|
486
|
+
interaction.mediaType = 'telephony';
|
|
487
|
+
interaction.callProcessingDetails = {relationshipType: 'consult', parentInteractionId: 'parent-456'};
|
|
488
|
+
expect(isSecondaryEpDnAgent(interaction)).toBe(true);
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
describe('getConsultMediaResourceId', () => {
|
|
493
|
+
it('returns consultMediaResourceId directly when provided', () => {
|
|
494
|
+
const result = getConsultMediaResourceId(undefined, 'consult-media-1', 'agent1');
|
|
495
|
+
expect(result).toBe('consult-media-1');
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it('returns undefined when no interaction and no consultMediaResourceId', () => {
|
|
499
|
+
const result = getConsultMediaResourceId(undefined, undefined, 'agent1');
|
|
500
|
+
expect(result).toBeUndefined();
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it('returns undefined when no agentId and no consultMediaResourceId', () => {
|
|
504
|
+
const interaction = {media: {}} as any;
|
|
505
|
+
const result = getConsultMediaResourceId(interaction, undefined, undefined);
|
|
506
|
+
expect(result).toBeUndefined();
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
it('finds consult media leg by mType and agent participation', () => {
|
|
510
|
+
const interaction = {
|
|
511
|
+
media: {
|
|
512
|
+
'main-media': {
|
|
513
|
+
mediaResourceId: 'main-media',
|
|
514
|
+
mType: 'mainCall',
|
|
515
|
+
participants: ['agent1', 'customer1'],
|
|
516
|
+
},
|
|
517
|
+
'consult-media': {
|
|
518
|
+
mediaResourceId: 'consult-media',
|
|
519
|
+
mType: 'consult',
|
|
520
|
+
participants: ['agent1', 'agent2'],
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
} as any;
|
|
524
|
+
const result = getConsultMediaResourceId(interaction, undefined, 'agent1');
|
|
525
|
+
expect(result).toBe('consult-media');
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it('returns undefined when no consult media leg matches the agent', () => {
|
|
529
|
+
const interaction = {
|
|
530
|
+
media: {
|
|
531
|
+
'main-media': {
|
|
532
|
+
mediaResourceId: 'main-media',
|
|
533
|
+
mType: 'mainCall',
|
|
534
|
+
participants: ['agent1', 'customer1'],
|
|
535
|
+
},
|
|
536
|
+
'consult-media': {
|
|
537
|
+
mediaResourceId: 'consult-media',
|
|
538
|
+
mType: 'consult',
|
|
539
|
+
participants: ['agent2', 'agent3'],
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
} as any;
|
|
543
|
+
const result = getConsultMediaResourceId(interaction, undefined, 'agent1');
|
|
544
|
+
expect(result).toBeUndefined();
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
it('returns undefined when media has no consult type entries', () => {
|
|
548
|
+
const interaction = {
|
|
549
|
+
media: {
|
|
550
|
+
'main-media': {
|
|
551
|
+
mediaResourceId: 'main-media',
|
|
552
|
+
mType: 'mainCall',
|
|
553
|
+
participants: ['agent1', 'customer1'],
|
|
554
|
+
},
|
|
555
|
+
},
|
|
556
|
+
} as any;
|
|
557
|
+
const result = getConsultMediaResourceId(interaction, undefined, 'agent1');
|
|
558
|
+
expect(result).toBeUndefined();
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
it('prioritizes direct consultMediaResourceId over interaction search', () => {
|
|
562
|
+
const interaction = {
|
|
563
|
+
media: {
|
|
564
|
+
'consult-media': {
|
|
565
|
+
mediaResourceId: 'consult-media',
|
|
566
|
+
mType: 'consult',
|
|
567
|
+
participants: ['agent1', 'agent2'],
|
|
568
|
+
},
|
|
569
|
+
},
|
|
570
|
+
} as any;
|
|
571
|
+
const result = getConsultMediaResourceId(interaction, 'direct-id', 'agent1');
|
|
572
|
+
expect(result).toBe('direct-id');
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
describe('getIsConsultInProgressForConferenceControls', () => {
|
|
577
|
+
it('returns false when consultee is reserved but has not joined (RONA)', () => {
|
|
578
|
+
const interaction = {
|
|
579
|
+
participants: {
|
|
580
|
+
'agent-1': {id: 'agent-1', pType: 'Agent', hasLeft: false, isConsulted: false},
|
|
581
|
+
'agent-2': {
|
|
582
|
+
id: 'agent-2',
|
|
583
|
+
pType: 'Agent',
|
|
584
|
+
hasLeft: false,
|
|
585
|
+
hasJoined: false,
|
|
586
|
+
isConsulted: true,
|
|
587
|
+
consultState: 'consultReserved',
|
|
588
|
+
},
|
|
589
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false},
|
|
590
|
+
},
|
|
591
|
+
media: {
|
|
592
|
+
'interaction-1': {
|
|
593
|
+
mType: 'mainCall',
|
|
594
|
+
participants: ['customer-1', 'agent-1'],
|
|
595
|
+
},
|
|
596
|
+
'consult-media': {
|
|
597
|
+
mType: 'consult',
|
|
598
|
+
participants: ['agent-2', 'agent-1'],
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
} as any;
|
|
602
|
+
|
|
603
|
+
expect(
|
|
604
|
+
getIsConsultInProgressForConferenceControls(interaction, 'interaction-1', 'agent-1')
|
|
605
|
+
).toBe(false);
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
it('returns true when consultee is actively consulting', () => {
|
|
609
|
+
const interaction = {
|
|
610
|
+
participants: {
|
|
611
|
+
'agent-1': {id: 'agent-1', pType: 'Agent', hasLeft: false, isConsulted: false},
|
|
612
|
+
'agent-2': {
|
|
613
|
+
id: 'agent-2',
|
|
614
|
+
pType: 'Agent',
|
|
615
|
+
hasLeft: false,
|
|
616
|
+
hasJoined: true,
|
|
617
|
+
isConsulted: true,
|
|
618
|
+
consultState: 'consulting',
|
|
619
|
+
},
|
|
620
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false},
|
|
621
|
+
},
|
|
622
|
+
media: {
|
|
623
|
+
'interaction-1': {
|
|
624
|
+
mType: 'mainCall',
|
|
625
|
+
participants: ['customer-1', 'agent-1'],
|
|
626
|
+
},
|
|
627
|
+
'consult-media': {
|
|
628
|
+
mType: 'consult',
|
|
629
|
+
participants: ['agent-2', 'agent-1'],
|
|
630
|
+
},
|
|
631
|
+
},
|
|
632
|
+
} as any;
|
|
633
|
+
|
|
634
|
+
expect(
|
|
635
|
+
getIsConsultInProgressForConferenceControls(interaction, 'interaction-1', 'agent-1')
|
|
636
|
+
).toBe(true);
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
it('returns true when EP-DN participant is on consult leg but not main call (CAI-8329)', () => {
|
|
640
|
+
const interaction = {
|
|
641
|
+
participants: {
|
|
642
|
+
'agent-1': {id: 'agent-1', pType: 'Agent', hasLeft: false, consultState: 'conferencing'},
|
|
643
|
+
'+13159998087': {
|
|
644
|
+
id: '+13159998087',
|
|
645
|
+
pType: 'EP-DN',
|
|
646
|
+
type: 'EpDn',
|
|
647
|
+
hasLeft: false,
|
|
648
|
+
},
|
|
649
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false, hasJoined: true},
|
|
650
|
+
},
|
|
651
|
+
media: {
|
|
652
|
+
'interaction-1': {
|
|
653
|
+
mType: 'mainCall',
|
|
654
|
+
participants: ['customer-1', 'agent-1'],
|
|
655
|
+
},
|
|
656
|
+
'consult-media-1': {
|
|
657
|
+
mType: 'consult',
|
|
658
|
+
participants: ['+13159998087', 'agent-1'],
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
} as any;
|
|
662
|
+
|
|
663
|
+
expect(
|
|
664
|
+
getIsConsultInProgressForConferenceControls(interaction, 'interaction-1', 'agent-1')
|
|
665
|
+
).toBe(true);
|
|
666
|
+
});
|
|
667
|
+
});
|
|
433
668
|
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {expect} from '@jest/globals';
|
|
2
|
+
import {
|
|
3
|
+
getWebexCallingDeviceDetailsForAgent,
|
|
4
|
+
isWebexCallingCallForAgent,
|
|
5
|
+
isWxAppEngagedForControls,
|
|
6
|
+
decodedLineOwnerId,
|
|
7
|
+
} from '../../../../../src/services/task/WebexCallingUtils';
|
|
8
|
+
import {TaskState} from '../../../../../src/services/task/state-machine/constants';
|
|
9
|
+
|
|
10
|
+
const WX_APP_PARTICIPANT = {
|
|
11
|
+
id: 'agent-1',
|
|
12
|
+
deviceType: 'wxApp',
|
|
13
|
+
deviceId: 'device-id-1',
|
|
14
|
+
deviceCallId: 'call-id-1',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const participantsById = {
|
|
18
|
+
'agent-1': WX_APP_PARTICIPANT,
|
|
19
|
+
'customer-1': {id: 'customer-1', pType: 'Customer'},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
describe('getWebexCallingDeviceDetailsForAgent', () => {
|
|
23
|
+
it('returns device details when agent participant has wxApp deviceType', () => {
|
|
24
|
+
const result = getWebexCallingDeviceDetailsForAgent('agent-1', participantsById);
|
|
25
|
+
|
|
26
|
+
expect(result).toEqual({
|
|
27
|
+
deviceType: 'wxApp',
|
|
28
|
+
deviceId: 'device-id-1',
|
|
29
|
+
deviceCallId: 'call-id-1',
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('returns undefined when agentId is undefined', () => {
|
|
34
|
+
expect(getWebexCallingDeviceDetailsForAgent(undefined, participantsById)).toBeUndefined();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('returns undefined when agentId is empty string', () => {
|
|
38
|
+
expect(getWebexCallingDeviceDetailsForAgent('', participantsById)).toBeUndefined();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('returns undefined when participants is null', () => {
|
|
42
|
+
expect(getWebexCallingDeviceDetailsForAgent('agent-1', null)).toBeUndefined();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('returns undefined when participants is an array (not object-by-id)', () => {
|
|
46
|
+
expect(getWebexCallingDeviceDetailsForAgent('agent-1', [WX_APP_PARTICIPANT])).toBeUndefined();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('returns undefined when agent participant lacks deviceCallId', () => {
|
|
50
|
+
const participants = {
|
|
51
|
+
'agent-1': {id: 'agent-1', deviceType: 'wxApp', deviceId: 'device-id-1'},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
expect(getWebexCallingDeviceDetailsForAgent('agent-1', participants)).toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('returns undefined when agent participant lacks deviceId', () => {
|
|
58
|
+
const participants = {
|
|
59
|
+
'agent-1': {id: 'agent-1', deviceType: 'wxApp', deviceCallId: 'call-id-1'},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
expect(getWebexCallingDeviceDetailsForAgent('agent-1', participants)).toBeUndefined();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('finds participant by id field when keyed differently', () => {
|
|
66
|
+
const participants = {
|
|
67
|
+
'some-other-key': WX_APP_PARTICIPANT,
|
|
68
|
+
};
|
|
69
|
+
const result = getWebexCallingDeviceDetailsForAgent('agent-1', participants);
|
|
70
|
+
|
|
71
|
+
expect(result?.deviceCallId).toBe('call-id-1');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('defaults deviceType to empty string when missing', () => {
|
|
75
|
+
const participants = {
|
|
76
|
+
'agent-1': {id: 'agent-1', deviceId: 'device-id-1', deviceCallId: 'call-id-1'},
|
|
77
|
+
};
|
|
78
|
+
const result = getWebexCallingDeviceDetailsForAgent('agent-1', participants);
|
|
79
|
+
|
|
80
|
+
expect(result?.deviceType).toBe('');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('isWebexCallingCallForAgent', () => {
|
|
85
|
+
it('returns true when device details are found', () => {
|
|
86
|
+
expect(isWebexCallingCallForAgent('agent-1', participantsById)).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('returns false when no device details are found', () => {
|
|
90
|
+
expect(isWebexCallingCallForAgent('unknown-agent', participantsById)).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('returns false when agentId is undefined', () => {
|
|
94
|
+
expect(isWebexCallingCallForAgent(undefined, participantsById)).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('isWxAppEngagedForControls', () => {
|
|
99
|
+
it('returns true when flag is on, wxApp participant exists, and state is CONNECTED', () => {
|
|
100
|
+
expect(
|
|
101
|
+
isWxAppEngagedForControls(true, 'agent-1', participantsById, TaskState.CONNECTED)
|
|
102
|
+
).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('returns false in OFFERED state', () => {
|
|
106
|
+
expect(isWxAppEngagedForControls(true, 'agent-1', participantsById, TaskState.OFFERED)).toBe(
|
|
107
|
+
false
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('returns false when enableWxBetterTogether is false', () => {
|
|
112
|
+
expect(
|
|
113
|
+
isWxAppEngagedForControls(false, 'agent-1', participantsById, TaskState.CONNECTED)
|
|
114
|
+
).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('returns false in TERMINATED state', () => {
|
|
118
|
+
expect(
|
|
119
|
+
isWxAppEngagedForControls(true, 'agent-1', participantsById, TaskState.TERMINATED)
|
|
120
|
+
).toBe(false);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('returns false in COMPLETED state', () => {
|
|
124
|
+
expect(
|
|
125
|
+
isWxAppEngagedForControls(true, 'agent-1', participantsById, TaskState.COMPLETED)
|
|
126
|
+
).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('returns false in WRAPPING_UP state', () => {
|
|
130
|
+
expect(
|
|
131
|
+
isWxAppEngagedForControls(true, 'agent-1', participantsById, TaskState.WRAPPING_UP)
|
|
132
|
+
).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('decodedLineOwnerId', () => {
|
|
137
|
+
it('returns undefined when lineOwnerId is not provided', () => {
|
|
138
|
+
expect(decodedLineOwnerId(undefined)).toBeUndefined();
|
|
139
|
+
expect(decodedLineOwnerId('')).toBeUndefined();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('decodes base64 encoded ID and returns last path segment', () => {
|
|
143
|
+
const orgId = 'ciscospark://us/ORGANIZATION/org-abc';
|
|
144
|
+
const encoded = btoa(orgId);
|
|
145
|
+
const result = decodedLineOwnerId(encoded);
|
|
146
|
+
|
|
147
|
+
expect(result).toBe('org-abc');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('returns undefined when base64 decoding fails', () => {
|
|
151
|
+
expect(decodedLineOwnerId('not-valid-base64!!')).toBeUndefined();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -215,6 +215,39 @@ describe("Routing contacts", () => {
|
|
|
215
215
|
expect(req).toBeDefined();
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
+
it('dropConferenceParticipant', () => {
|
|
219
|
+
fakeAqm.pendingRequests = {};
|
|
220
|
+
const req = contact.dropConferenceParticipant({
|
|
221
|
+
interactionId: 'test-interaction-drop-123',
|
|
222
|
+
participantId: '+1/participant 42',
|
|
223
|
+
}) as any;
|
|
224
|
+
|
|
225
|
+
expect(req).toEqual({
|
|
226
|
+
url: '/v1/tasks/test-interaction-drop-123/conference/participants/%2B1%2Fparticipant%2042/drop',
|
|
227
|
+
data: {},
|
|
228
|
+
host: 'wcc-api-gateway',
|
|
229
|
+
err: expect.any(Function),
|
|
230
|
+
redactSensitiveLogs: true,
|
|
231
|
+
notifSuccess: {
|
|
232
|
+
bind: {
|
|
233
|
+
type: 'RoutingMessage',
|
|
234
|
+
data: {
|
|
235
|
+
type: 'ParticipantLeftConference',
|
|
236
|
+
interactionId: 'test-interaction-drop-123',
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
msg: {},
|
|
240
|
+
},
|
|
241
|
+
notifFail: {
|
|
242
|
+
bind: {
|
|
243
|
+
type: 'RoutingMessage',
|
|
244
|
+
data: {type: 'ParticipantDropConferenceFailed'},
|
|
245
|
+
},
|
|
246
|
+
errId: 'Service.aqm.task.dropConferenceParticipant',
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
218
251
|
it("exitConference", () => {
|
|
219
252
|
fakeAqm.pendingRequests = {};
|
|
220
253
|
const req = contact.exitConference({
|
|
@@ -239,5 +239,195 @@ describe('AQM routing dialer', () => {
|
|
|
239
239
|
).rejects.toThrow('Request Timeout');
|
|
240
240
|
});
|
|
241
241
|
});
|
|
242
|
+
|
|
243
|
+
describe('skipPreviewContact', () => {
|
|
244
|
+
it('should construct the correct URL with campaignId and interactionId', () => {
|
|
245
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
246
|
+
const config = dialer.skipPreviewContact({data: previewPayload}) as any;
|
|
247
|
+
|
|
248
|
+
expect(config.url).toBe(
|
|
249
|
+
`/v1/dialer/campaign/${previewPayload.campaignId}/preview-task/${previewPayload.interactionId}/skip`
|
|
250
|
+
);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should URL-encode campaignId when it contains reserved characters', () => {
|
|
254
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
255
|
+
const payloadWithSpecialChars = {
|
|
256
|
+
interactionId: 'interaction-456',
|
|
257
|
+
campaignId: 'My Campaign/Test #1',
|
|
258
|
+
};
|
|
259
|
+
const config = dialer.skipPreviewContact({data: payloadWithSpecialChars}) as any;
|
|
260
|
+
|
|
261
|
+
expect(config.url).toBe(
|
|
262
|
+
`/v1/dialer/campaign/${encodeURIComponent(
|
|
263
|
+
payloadWithSpecialChars.campaignId
|
|
264
|
+
)}/preview-task/${payloadWithSpecialChars.interactionId}/skip`
|
|
265
|
+
);
|
|
266
|
+
expect(config.url).toContain('My%20Campaign%2FTest%20%231');
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should call the skipPreviewContact api', () => {
|
|
270
|
+
const fakeAqm = {
|
|
271
|
+
req: () =>
|
|
272
|
+
jest.fn().mockResolvedValue(() => {
|
|
273
|
+
Promise.resolve({data: 'skip preview success'});
|
|
274
|
+
}),
|
|
275
|
+
evt: jest.fn(),
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
279
|
+
|
|
280
|
+
dialer
|
|
281
|
+
.skipPreviewContact({data: previewPayload})
|
|
282
|
+
.then((response) => {
|
|
283
|
+
expect(response.data).toBe('skip preview success');
|
|
284
|
+
})
|
|
285
|
+
.catch(() => {
|
|
286
|
+
expect(true).toBe(true);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
expect(dialer.skipPreviewContact).toHaveBeenCalled();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('should handle network errors', () => {
|
|
293
|
+
const fakeAqm = {
|
|
294
|
+
req: () => jest.fn().mockRejectedValue(new Error('Network Error')),
|
|
295
|
+
evt: jest.fn(),
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
299
|
+
|
|
300
|
+
return expect(
|
|
301
|
+
dialer.skipPreviewContact({
|
|
302
|
+
data: previewPayload,
|
|
303
|
+
})
|
|
304
|
+
).rejects.toThrow('Network Error');
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('should handle server errors', () => {
|
|
308
|
+
const fakeAqm = {
|
|
309
|
+
req: () => jest.fn().mockRejectedValue(new Error('Server Error')),
|
|
310
|
+
evt: jest.fn(),
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
314
|
+
|
|
315
|
+
return expect(
|
|
316
|
+
dialer.skipPreviewContact({
|
|
317
|
+
data: previewPayload,
|
|
318
|
+
})
|
|
319
|
+
).rejects.toThrow('Server Error');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should handle timeout scenarios', () => {
|
|
323
|
+
const fakeAqm = {
|
|
324
|
+
req: () => jest.fn().mockRejectedValue(new Error('Request Timeout')),
|
|
325
|
+
evt: jest.fn(),
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
329
|
+
|
|
330
|
+
return expect(
|
|
331
|
+
dialer.skipPreviewContact({
|
|
332
|
+
data: previewPayload,
|
|
333
|
+
})
|
|
334
|
+
).rejects.toThrow('Request Timeout');
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
describe('removePreviewContact', () => {
|
|
339
|
+
it('should construct the correct URL with campaignId and interactionId', () => {
|
|
340
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
341
|
+
const config = dialer.removePreviewContact({data: previewPayload}) as any;
|
|
342
|
+
|
|
343
|
+
expect(config.url).toBe(
|
|
344
|
+
`/v1/dialer/campaign/${previewPayload.campaignId}/preview-task/${previewPayload.interactionId}/remove`
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('should URL-encode campaignId when it contains reserved characters', () => {
|
|
349
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
350
|
+
const payloadWithSpecialChars = {
|
|
351
|
+
interactionId: 'interaction-456',
|
|
352
|
+
campaignId: 'My Campaign/Test #1',
|
|
353
|
+
};
|
|
354
|
+
const config = dialer.removePreviewContact({data: payloadWithSpecialChars}) as any;
|
|
355
|
+
|
|
356
|
+
expect(config.url).toBe(
|
|
357
|
+
`/v1/dialer/campaign/${encodeURIComponent(
|
|
358
|
+
payloadWithSpecialChars.campaignId
|
|
359
|
+
)}/preview-task/${payloadWithSpecialChars.interactionId}/remove`
|
|
360
|
+
);
|
|
361
|
+
expect(config.url).toContain('My%20Campaign%2FTest%20%231');
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it('should call the removePreviewContact api', () => {
|
|
365
|
+
const fakeAqm = {
|
|
366
|
+
req: () =>
|
|
367
|
+
jest.fn().mockResolvedValue(() => {
|
|
368
|
+
Promise.resolve({data: 'remove preview success'});
|
|
369
|
+
}),
|
|
370
|
+
evt: jest.fn(),
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
374
|
+
|
|
375
|
+
dialer
|
|
376
|
+
.removePreviewContact({data: previewPayload})
|
|
377
|
+
.then((response) => {
|
|
378
|
+
expect(response.data).toBe('remove preview success');
|
|
379
|
+
})
|
|
380
|
+
.catch(() => {
|
|
381
|
+
expect(true).toBe(true);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
expect(dialer.removePreviewContact).toHaveBeenCalled();
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it('should handle network errors', () => {
|
|
388
|
+
const fakeAqm = {
|
|
389
|
+
req: () => jest.fn().mockRejectedValue(new Error('Network Error')),
|
|
390
|
+
evt: jest.fn(),
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
394
|
+
|
|
395
|
+
return expect(
|
|
396
|
+
dialer.removePreviewContact({
|
|
397
|
+
data: previewPayload,
|
|
398
|
+
})
|
|
399
|
+
).rejects.toThrow('Network Error');
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('should handle server errors', () => {
|
|
403
|
+
const fakeAqm = {
|
|
404
|
+
req: () => jest.fn().mockRejectedValue(new Error('Server Error')),
|
|
405
|
+
evt: jest.fn(),
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
409
|
+
|
|
410
|
+
return expect(
|
|
411
|
+
dialer.removePreviewContact({
|
|
412
|
+
data: previewPayload,
|
|
413
|
+
})
|
|
414
|
+
).rejects.toThrow('Server Error');
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('should handle timeout scenarios', () => {
|
|
418
|
+
const fakeAqm = {
|
|
419
|
+
req: () => jest.fn().mockRejectedValue(new Error('Request Timeout')),
|
|
420
|
+
evt: jest.fn(),
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
const dialer = aqmDialer(fakeAqm as any);
|
|
424
|
+
|
|
425
|
+
return expect(
|
|
426
|
+
dialer.removePreviewContact({
|
|
427
|
+
data: previewPayload,
|
|
428
|
+
})
|
|
429
|
+
).rejects.toThrow('Request Timeout');
|
|
430
|
+
});
|
|
431
|
+
});
|
|
242
432
|
});
|
|
243
433
|
});
|