@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
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import ApiAIAssistant from '../../../../src/services/ApiAiAssistant';
|
|
2
2
|
import MetricsManager from '../../../../src/metrics/MetricsManager';
|
|
3
3
|
import LoggerProxy from '../../../../src/logger-proxy';
|
|
4
|
-
import
|
|
4
|
+
import WebexRequest from '../../../../src/services/core/WebexRequest';
|
|
5
|
+
import {
|
|
6
|
+
HTTP_METHODS,
|
|
7
|
+
RealTimeAssistanceUserActionId,
|
|
8
|
+
WELLNESS_BREAK_USER_ACTIONS,
|
|
9
|
+
WebexSDK,
|
|
10
|
+
} from '../../../../src/types';
|
|
5
11
|
|
|
6
12
|
jest.mock('../../../../src/metrics/MetricsManager');
|
|
7
13
|
jest.mock('../../../../src/logger-proxy');
|
|
@@ -10,9 +16,17 @@ describe('ApiAIAssistant', () => {
|
|
|
10
16
|
let apiAIAssistant: ApiAIAssistant;
|
|
11
17
|
let mockWebex: WebexSDK;
|
|
12
18
|
let mockMetricsManager: jest.Mocked<MetricsManager>;
|
|
19
|
+
let wellnessContext: {
|
|
20
|
+
isWellnessBreakEnabled: boolean;
|
|
21
|
+
agentId?: string;
|
|
22
|
+
agentSessionId?: string;
|
|
23
|
+
};
|
|
13
24
|
|
|
14
25
|
beforeEach(() => {
|
|
15
26
|
jest.clearAllMocks();
|
|
27
|
+
jest.spyOn(WebexRequest, 'getInstance').mockReturnValue({
|
|
28
|
+
uploadLogs: jest.fn(),
|
|
29
|
+
} as any);
|
|
16
30
|
|
|
17
31
|
mockWebex = {
|
|
18
32
|
credentials: {
|
|
@@ -39,7 +53,8 @@ describe('ApiAIAssistant', () => {
|
|
|
39
53
|
} as unknown as jest.Mocked<MetricsManager>;
|
|
40
54
|
(MetricsManager.getInstance as jest.Mock).mockReturnValue(mockMetricsManager);
|
|
41
55
|
|
|
42
|
-
|
|
56
|
+
wellnessContext = {isWellnessBreakEnabled: false};
|
|
57
|
+
apiAIAssistant = new ApiAIAssistant(mockWebex, () => wellnessContext);
|
|
43
58
|
});
|
|
44
59
|
|
|
45
60
|
it('should send transcript start event successfully', async () => {
|
|
@@ -50,26 +65,21 @@ describe('ApiAIAssistant', () => {
|
|
|
50
65
|
'interaction-1',
|
|
51
66
|
'CUSTOM_EVENT',
|
|
52
67
|
'GET_TRANSCRIPTS',
|
|
53
|
-
'START'
|
|
68
|
+
{action: 'START'}
|
|
54
69
|
);
|
|
55
70
|
|
|
56
|
-
expect(mockWebex.request).
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
action: 'START',
|
|
69
|
-
}),
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
});
|
|
71
|
+
expect(mockWebex.request).toHaveBeenCalledTimes(1);
|
|
72
|
+
const requestArgs = (mockWebex.request as jest.Mock).mock.calls[0][0];
|
|
73
|
+
|
|
74
|
+
expect(requestArgs.uri).toBe('https://api-ai-assistant.produs1.ciscoccservice.com/event');
|
|
75
|
+
expect(requestArgs.method).toBe(HTTP_METHODS.POST);
|
|
76
|
+
expect(requestArgs.addAuthHeader).toBe(true);
|
|
77
|
+
expect(requestArgs.body.agentId).toBe('test-agent-id');
|
|
78
|
+
expect(requestArgs.body.orgId).toBe('test-org-id');
|
|
79
|
+
expect(requestArgs.body.eventType).toBe('CUSTOM_EVENT');
|
|
80
|
+
expect(requestArgs.body.eventName).toBe('GET_TRANSCRIPTS');
|
|
81
|
+
expect(requestArgs.body.eventDetails.data.interactionId).toBe('interaction-1');
|
|
82
|
+
expect(requestArgs.body.eventDetails.data.action).toBe('START');
|
|
73
83
|
expect(result).toEqual({ok: true});
|
|
74
84
|
});
|
|
75
85
|
|
|
@@ -93,6 +103,118 @@ describe('ApiAIAssistant', () => {
|
|
|
93
103
|
expect(result).toEqual(responseBody as any);
|
|
94
104
|
});
|
|
95
105
|
|
|
106
|
+
it('should request real-time assistance without extra context using sendEvent', async () => {
|
|
107
|
+
const sendEventSpy = jest.spyOn(apiAIAssistant, 'sendEvent').mockResolvedValue({ok: true});
|
|
108
|
+
apiAIAssistant.setAIFeatureFlags({suggestedResponses: {enable: true}} as any);
|
|
109
|
+
|
|
110
|
+
const result = await apiAIAssistant.getRealTimeAssistance({
|
|
111
|
+
agentId: 'test-agent-id',
|
|
112
|
+
interactionId: 'interaction-1',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(sendEventSpy).toHaveBeenCalledTimes(1);
|
|
116
|
+
const [agentId, interactionId, eventType, eventName, metadata, languageCode, trackingId] =
|
|
117
|
+
sendEventSpy.mock.calls[0];
|
|
118
|
+
|
|
119
|
+
expect(agentId).toBe('test-agent-id');
|
|
120
|
+
expect(interactionId).toBe('interaction-1');
|
|
121
|
+
expect(eventType).toBe('CUSTOM_EVENT');
|
|
122
|
+
expect(eventName).toBe('GET_SUGGESTIONS');
|
|
123
|
+
expect(metadata).toBeUndefined();
|
|
124
|
+
expect(languageCode).toBe('en');
|
|
125
|
+
expect(typeof trackingId).toBe('string');
|
|
126
|
+
expect(trackingId.startsWith('WX_CC_SDK_')).toBe(true);
|
|
127
|
+
expect(result).toEqual({ok: true});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should request real-time assistance with extra context using sendEvent', async () => {
|
|
131
|
+
const sendEventSpy = jest.spyOn(apiAIAssistant, 'sendEvent').mockResolvedValue({ok: true});
|
|
132
|
+
apiAIAssistant.setAIFeatureFlags({suggestedResponses: {enable: true}} as any);
|
|
133
|
+
|
|
134
|
+
const result = await apiAIAssistant.getRealTimeAssistance({
|
|
135
|
+
agentId: 'test-agent-id',
|
|
136
|
+
interactionId: 'interaction-1',
|
|
137
|
+
context: 'Need assistance with credit card payment due date',
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
expect(sendEventSpy).toHaveBeenCalledTimes(1);
|
|
141
|
+
const [agentId, interactionId, eventType, eventName, metadata, languageCode, trackingId] =
|
|
142
|
+
sendEventSpy.mock.calls[0];
|
|
143
|
+
|
|
144
|
+
expect(agentId).toBe('test-agent-id');
|
|
145
|
+
expect(interactionId).toBe('interaction-1');
|
|
146
|
+
expect(eventType).toBe('CUSTOM_EVENT');
|
|
147
|
+
expect(eventName).toBe('ADD_SUGGESTIONS_EXTRA_CONTEXT');
|
|
148
|
+
expect(metadata).toEqual({context: 'Need assistance with credit card payment due date'});
|
|
149
|
+
expect(languageCode).toBe('en');
|
|
150
|
+
expect(typeof trackingId).toBe('string');
|
|
151
|
+
expect(trackingId.startsWith('WX_CC_SDK_')).toBe(true);
|
|
152
|
+
expect(result).toEqual({ok: true});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should treat whitespace-only context as GET_SUGGESTIONS', async () => {
|
|
156
|
+
const sendEventSpy = jest.spyOn(apiAIAssistant, 'sendEvent').mockResolvedValue({ok: true});
|
|
157
|
+
apiAIAssistant.setAIFeatureFlags({suggestedResponses: {enable: true}} as any);
|
|
158
|
+
|
|
159
|
+
const result = await apiAIAssistant.getRealTimeAssistance({
|
|
160
|
+
agentId: 'test-agent-id',
|
|
161
|
+
interactionId: 'interaction-1',
|
|
162
|
+
context: ' ',
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(sendEventSpy).toHaveBeenCalledTimes(1);
|
|
166
|
+
const [agentId, interactionId, eventType, eventName, metadata, languageCode, trackingId] =
|
|
167
|
+
sendEventSpy.mock.calls[0];
|
|
168
|
+
|
|
169
|
+
expect(agentId).toBe('test-agent-id');
|
|
170
|
+
expect(interactionId).toBe('interaction-1');
|
|
171
|
+
expect(eventType).toBe('CUSTOM_EVENT');
|
|
172
|
+
expect(eventName).toBe('GET_SUGGESTIONS');
|
|
173
|
+
expect(metadata).toEqual({context: ''});
|
|
174
|
+
expect(languageCode).toBe('en');
|
|
175
|
+
expect(typeof trackingId).toBe('string');
|
|
176
|
+
expect(trackingId.startsWith('WX_CC_SDK_')).toBe(true);
|
|
177
|
+
expect(result).toEqual({ok: true});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
[
|
|
181
|
+
RealTimeAssistanceUserActionId.LIKE,
|
|
182
|
+
RealTimeAssistanceUserActionId.DISLIKE,
|
|
183
|
+
RealTimeAssistanceUserActionId.COPY,
|
|
184
|
+
].forEach((actionId) => {
|
|
185
|
+
it(`should send real-time assistance user action for ${actionId}`, async () => {
|
|
186
|
+
(mockWebex.request as jest.Mock).mockResolvedValue({body: {ok: true}});
|
|
187
|
+
apiAIAssistant.setAIFeatureFlags({suggestedResponses: {enable: true}} as any);
|
|
188
|
+
|
|
189
|
+
const result = await apiAIAssistant.sendRealTimeAssistanceUserAction({
|
|
190
|
+
agentId: 'test-agent-id',
|
|
191
|
+
interactionId: 'interaction-1',
|
|
192
|
+
adaptiveCardId: 'adaptive-card-1',
|
|
193
|
+
actionId,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(mockWebex.request).toHaveBeenCalledTimes(1);
|
|
197
|
+
const requestArgs = (mockWebex.request as jest.Mock).mock.calls[0][0];
|
|
198
|
+
const eventData = requestArgs.body.eventDetails.data;
|
|
199
|
+
|
|
200
|
+
expect(requestArgs.uri).toBe('https://api-ai-assistant.produs1.ciscoccservice.com/event');
|
|
201
|
+
expect(requestArgs.method).toBe(HTTP_METHODS.POST);
|
|
202
|
+
expect(requestArgs.addAuthHeader).toBe(true);
|
|
203
|
+
expect(requestArgs.body.agentId).toBe('test-agent-id');
|
|
204
|
+
expect(requestArgs.body.orgId).toBe('test-org-id');
|
|
205
|
+
expect(requestArgs.body.eventType).toBe('CUSTOM_EVENT');
|
|
206
|
+
expect(requestArgs.body.eventName).toBe('SUGGESTED_RESPONSES_USER_ACTION');
|
|
207
|
+
expect(eventData.interactionId).toBe('interaction-1');
|
|
208
|
+
expect(eventData.adaptiveCardId).toBe('adaptive-card-1');
|
|
209
|
+
expect(eventData.userAction.actionType).toBe('Action.Submit');
|
|
210
|
+
expect(eventData.userAction.actionId).toBe(actionId);
|
|
211
|
+
expect(eventData.languageCode).toBe('en');
|
|
212
|
+
expect(typeof eventData.actionTimeStamp).toBe('string');
|
|
213
|
+
expect(eventData.trackingId.startsWith('WX_CC_SDK_')).toBe(true);
|
|
214
|
+
expect(result).toEqual({ok: true});
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
96
218
|
it('should fail when base URL mapping is not available', async () => {
|
|
97
219
|
(mockWebex.internal.services.get as jest.Mock).mockReturnValue('https://unknown-host.invalid');
|
|
98
220
|
|
|
@@ -103,7 +225,7 @@ describe('ApiAIAssistant', () => {
|
|
|
103
225
|
'interaction-1',
|
|
104
226
|
'CUSTOM_EVENT',
|
|
105
227
|
'GET_TRANSCRIPTS',
|
|
106
|
-
'STOP'
|
|
228
|
+
{action: 'STOP'}
|
|
107
229
|
);
|
|
108
230
|
} catch (_error) {
|
|
109
231
|
failed = true;
|
|
@@ -112,4 +234,172 @@ describe('ApiAIAssistant', () => {
|
|
|
112
234
|
expect(failed).toBe(true);
|
|
113
235
|
expect(LoggerProxy.error).toHaveBeenCalled();
|
|
114
236
|
});
|
|
237
|
+
|
|
238
|
+
it('should fail when realtime transcripts feature is disabled', async () => {
|
|
239
|
+
apiAIAssistant.setAIFeatureFlags({realtimeTranscripts: {enable: false}} as any);
|
|
240
|
+
let errorMessage = '';
|
|
241
|
+
|
|
242
|
+
try {
|
|
243
|
+
await apiAIAssistant.fetchHistoricTranscripts('test-agent-id', 'interaction-1');
|
|
244
|
+
} catch (error) {
|
|
245
|
+
errorMessage = (error as Error)?.message || '';
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
expect(errorMessage).toBe('Error while performing fetchHistoricTranscripts');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('should fail when real-time assistance feature is disabled', async () => {
|
|
252
|
+
apiAIAssistant.setAIFeatureFlags({suggestedResponses: {enable: false}} as any);
|
|
253
|
+
let errorMessage = '';
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
await apiAIAssistant.getRealTimeAssistance({
|
|
257
|
+
agentId: 'test-agent-id',
|
|
258
|
+
interactionId: 'interaction-1',
|
|
259
|
+
});
|
|
260
|
+
} catch (error) {
|
|
261
|
+
errorMessage = (error as Error)?.message || '';
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
expect(errorMessage).toBe('Error while performing getRealTimeAssistance');
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should fail to send real-time assistance user action when feature is disabled', async () => {
|
|
268
|
+
apiAIAssistant.setAIFeatureFlags({suggestedResponses: {enable: false}} as any);
|
|
269
|
+
let errorMessage = '';
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
await apiAIAssistant.sendRealTimeAssistanceUserAction({
|
|
273
|
+
agentId: 'test-agent-id',
|
|
274
|
+
interactionId: 'interaction-1',
|
|
275
|
+
adaptiveCardId: 'adaptive-card-1',
|
|
276
|
+
actionId: RealTimeAssistanceUserActionId.LIKE,
|
|
277
|
+
});
|
|
278
|
+
} catch (error) {
|
|
279
|
+
errorMessage = (error as Error)?.message || '';
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
expect(errorMessage).toBe('Error while performing sendRealTimeAssistanceUserAction');
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
describe('Agent Wellness Break actions', () => {
|
|
286
|
+
beforeEach(() => {
|
|
287
|
+
wellnessContext = {
|
|
288
|
+
isWellnessBreakEnabled: true,
|
|
289
|
+
agentId: 'test-agent-id',
|
|
290
|
+
agentSessionId: 'session-1',
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('does not expose wellness context mutation on the public assistant instance', () => {
|
|
295
|
+
expect(apiAIAssistant).not.toHaveProperty('setWellnessContext');
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('sends the exact REQUESTED body and resolves only for HTTP 202', async () => {
|
|
299
|
+
jest.spyOn(Date, 'now').mockReturnValue(1787640000000);
|
|
300
|
+
(mockWebex.request as jest.Mock).mockResolvedValue({statusCode: 202});
|
|
301
|
+
|
|
302
|
+
await expect(apiAIAssistant.requestWellnessBreak()).resolves.toBeUndefined();
|
|
303
|
+
|
|
304
|
+
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
305
|
+
uri: 'https://api-ai-assistant.produs1.ciscoccservice.com/event',
|
|
306
|
+
method: HTTP_METHODS.POST,
|
|
307
|
+
addAuthHeader: true,
|
|
308
|
+
body: {
|
|
309
|
+
agentId: 'test-agent-id',
|
|
310
|
+
orgId: 'test-org-id',
|
|
311
|
+
eventType: 'CUSTOM_EVENT',
|
|
312
|
+
eventName: 'WellnessBreakAction',
|
|
313
|
+
eventDetails: {
|
|
314
|
+
data: {
|
|
315
|
+
action: 'REQUESTED',
|
|
316
|
+
agentSessionId: 'session-1',
|
|
317
|
+
actionTimeStamp: 1787640000000,
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it.each([
|
|
325
|
+
WELLNESS_BREAK_USER_ACTIONS.ACCEPTED,
|
|
326
|
+
WELLNESS_BREAK_USER_ACTIONS.REJECTED,
|
|
327
|
+
WELLNESS_BREAK_USER_ACTIONS.NO_RESPONSE,
|
|
328
|
+
] as const)(
|
|
329
|
+
'sends the %s offer action',
|
|
330
|
+
async (action) => {
|
|
331
|
+
(mockWebex.request as jest.Mock).mockResolvedValue({statusCode: 202});
|
|
332
|
+
|
|
333
|
+
await apiAIAssistant.respondToWellnessBreak({action});
|
|
334
|
+
|
|
335
|
+
expect(
|
|
336
|
+
(mockWebex.request as jest.Mock).mock.calls[0][0].body.eventDetails.data.action
|
|
337
|
+
).toBe(action);
|
|
338
|
+
}
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
it('rejects disabled or incomplete internal session context before HTTP', async () => {
|
|
342
|
+
wellnessContext = {
|
|
343
|
+
isWellnessBreakEnabled: false,
|
|
344
|
+
agentId: 'test-agent-id',
|
|
345
|
+
agentSessionId: 'session-1',
|
|
346
|
+
};
|
|
347
|
+
await expect(apiAIAssistant.requestWellnessBreak()).rejects.toThrow(
|
|
348
|
+
'WELLNESS_BREAK_NOT_ENABLED'
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
wellnessContext = {
|
|
352
|
+
isWellnessBreakEnabled: true,
|
|
353
|
+
};
|
|
354
|
+
await expect(apiAIAssistant.requestWellnessBreak()).rejects.toThrow(
|
|
355
|
+
'WELLNESS_BREAK_AGENT_ID_REQUIRED'
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
wellnessContext = {
|
|
359
|
+
isWellnessBreakEnabled: true,
|
|
360
|
+
agentId: 'test-agent-id',
|
|
361
|
+
};
|
|
362
|
+
await expect(apiAIAssistant.requestWellnessBreak()).rejects.toThrow(
|
|
363
|
+
'WELLNESS_BREAK_AGENT_SESSION_REQUIRED'
|
|
364
|
+
);
|
|
365
|
+
expect(mockWebex.request).not.toHaveBeenCalled();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('rejects a missing organization before HTTP', async () => {
|
|
369
|
+
(mockWebex.credentials.getOrgId as jest.Mock).mockReturnValue(' ');
|
|
370
|
+
|
|
371
|
+
await expect(apiAIAssistant.requestWellnessBreak()).rejects.toThrow(
|
|
372
|
+
'WELLNESS_BREAK_ORG_ID_REQUIRED'
|
|
373
|
+
);
|
|
374
|
+
expect(mockWebex.request).not.toHaveBeenCalled();
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it.each([200, 204, 400, 401, 403, 404, 409, 429, 500])(
|
|
378
|
+
'rejects the non-202 HTTP status %i',
|
|
379
|
+
async (statusCode) => {
|
|
380
|
+
(mockWebex.request as jest.Mock).mockResolvedValue({statusCode});
|
|
381
|
+
|
|
382
|
+
await expect(apiAIAssistant.requestWellnessBreak()).rejects.toThrow(
|
|
383
|
+
`WELLNESS_BREAK_ACTION_UNEXPECTED_STATUS_${statusCode}`
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
it('rejects network failures through the structured error path', async () => {
|
|
389
|
+
(mockWebex.request as jest.Mock).mockRejectedValue(new Error('Network unavailable'));
|
|
390
|
+
|
|
391
|
+
await expect(apiAIAssistant.requestWellnessBreak()).rejects.toThrow(
|
|
392
|
+
'Error while performing requestWellnessBreak'
|
|
393
|
+
);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
it('rejects unsupported offer actions before HTTP', async () => {
|
|
397
|
+
await expect(
|
|
398
|
+
apiAIAssistant.respondToWellnessBreak({
|
|
399
|
+
action: 'REQUESTED',
|
|
400
|
+
} as unknown as Parameters<ApiAIAssistant['respondToWellnessBreak']>[0])
|
|
401
|
+
).rejects.toThrow('WELLNESS_BREAK_ACTION_INVALID');
|
|
402
|
+
expect(mockWebex.request).not.toHaveBeenCalled();
|
|
403
|
+
});
|
|
404
|
+
});
|
|
115
405
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import EntryPoint from '../../../../src/services/EntryPoint';
|
|
2
|
-
import {HTTP_METHODS, WebexSDK, IHttpResponse} from '../../../../src/types';
|
|
2
|
+
import {HTTP_METHODS, WebexSDK, IHttpResponse, EntryPointRecord} from '../../../../src/types';
|
|
3
3
|
import {METRIC_EVENT_NAMES} from '../../../../src/metrics/constants';
|
|
4
4
|
import WebexRequest from '../../../../src/services/core/WebexRequest';
|
|
5
5
|
import MetricsManager from '../../../../src/metrics/MetricsManager';
|
|
@@ -50,30 +50,38 @@ describe('EntryPoint', () => {
|
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
describe('getEntryPoints', () => {
|
|
53
|
-
const
|
|
53
|
+
const mockDialNumberMappings = [
|
|
54
54
|
{
|
|
55
|
-
id: '
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
orgId: 'test-org-id',
|
|
55
|
+
id: 'dial-number-1',
|
|
56
|
+
dialledNumber: '+1-555-0101',
|
|
57
|
+
entryPointId: 'entry1',
|
|
58
|
+
entryPointName: 'Test Entry Point 1',
|
|
60
59
|
},
|
|
61
60
|
{
|
|
62
|
-
id: '
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
orgId: 'test-org-id',
|
|
61
|
+
id: 'dial-number-2',
|
|
62
|
+
dialledNumber: '+1-555-0102',
|
|
63
|
+
entryPointId: 'entry2',
|
|
64
|
+
entryPointName: 'Test Entry Point 2',
|
|
67
65
|
},
|
|
68
66
|
];
|
|
67
|
+
const expectedEntryPoints: EntryPointRecord[] = [
|
|
68
|
+
{id: 'entry1', name: 'Test Entry Point 1', number: '+1-555-0101'},
|
|
69
|
+
{id: 'entry2', name: 'Test Entry Point 2', number: '+1-555-0102'},
|
|
70
|
+
];
|
|
71
|
+
const defaultResource =
|
|
72
|
+
'/organization/test-org-id/v3/dial-number?page=0&pageSize=100&attributes=id%2CdialledNumber%2CentryPointId%2CentryPointName&sort=entryPointName%2CASC&desktopProfileFilter=true&includeEntryPointName=true';
|
|
73
|
+
const requestHeaders = {
|
|
74
|
+
'X-ORGANIZATION-ID': 'test-org-id',
|
|
75
|
+
'x-ignore-internal-data': 'false',
|
|
76
|
+
};
|
|
69
77
|
|
|
70
78
|
const mockResponse: IHttpResponse = {
|
|
71
79
|
statusCode: 200,
|
|
72
80
|
method: 'GET',
|
|
73
|
-
url: '/organization/test-org-id/
|
|
81
|
+
url: '/organization/test-org-id/v3/dial-number',
|
|
74
82
|
headers: {} as any,
|
|
75
83
|
body: {
|
|
76
|
-
data:
|
|
84
|
+
data: mockDialNumberMappings,
|
|
77
85
|
meta: {
|
|
78
86
|
page: 0,
|
|
79
87
|
pageSize: 100,
|
|
@@ -99,11 +107,14 @@ describe('EntryPoint', () => {
|
|
|
99
107
|
|
|
100
108
|
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
101
109
|
service: 'wcc-api-gateway',
|
|
102
|
-
resource:
|
|
110
|
+
resource: defaultResource,
|
|
103
111
|
method: HTTP_METHODS.GET,
|
|
112
|
+
body: undefined,
|
|
113
|
+
headers: requestHeaders,
|
|
104
114
|
});
|
|
105
115
|
|
|
106
|
-
expect(result).toEqual(mockResponse.body);
|
|
116
|
+
expect(result).toEqual({...mockResponse.body, data: expectedEntryPoints});
|
|
117
|
+
expect(result.data[0].number).toBe('+1-555-0101');
|
|
107
118
|
expect(mockMetricsManager.timeEvent).toHaveBeenCalledWith(METRIC_EVENT_NAMES.ENTRYPOINT_FETCH_SUCCESS);
|
|
108
119
|
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
109
120
|
METRIC_EVENT_NAMES.ENTRYPOINT_FETCH_SUCCESS,
|
|
@@ -122,7 +133,7 @@ describe('EntryPoint', () => {
|
|
|
122
133
|
{module: 'EntryPoint', method: 'getEntryPoints'}
|
|
123
134
|
);
|
|
124
135
|
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
125
|
-
`Making API request to fetch entry points - resource:
|
|
136
|
+
`Making API request to fetch entry points - resource: ${defaultResource}, service: wcc-api-gateway`,
|
|
126
137
|
{module: 'EntryPoint', method: 'getEntryPoints'}
|
|
127
138
|
);
|
|
128
139
|
});
|
|
@@ -134,7 +145,7 @@ describe('EntryPoint', () => {
|
|
|
134
145
|
page: 1,
|
|
135
146
|
pageSize: 25,
|
|
136
147
|
search: 'test',
|
|
137
|
-
filter: '
|
|
148
|
+
filter: 'entryPointId=="entry1"',
|
|
138
149
|
attributes: 'id,name',
|
|
139
150
|
sortBy: 'name',
|
|
140
151
|
sortOrder: 'desc' as const,
|
|
@@ -144,8 +155,11 @@ describe('EntryPoint', () => {
|
|
|
144
155
|
|
|
145
156
|
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
146
157
|
service: 'wcc-api-gateway',
|
|
147
|
-
resource:
|
|
158
|
+
resource:
|
|
159
|
+
'/organization/test-org-id/v3/dial-number?page=1&pageSize=25&attributes=id%2CdialledNumber%2CentryPointId%2CentryPointName%2Cname&search=test&filter=entryPointId%3D%3D%22entry1%22&sort=entryPointName%2CDESC&desktopProfileFilter=true&includeEntryPointName=true',
|
|
148
160
|
method: HTTP_METHODS.GET,
|
|
161
|
+
body: undefined,
|
|
162
|
+
headers: requestHeaders,
|
|
149
163
|
});
|
|
150
164
|
|
|
151
165
|
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
@@ -162,6 +176,41 @@ describe('EntryPoint', () => {
|
|
|
162
176
|
);
|
|
163
177
|
});
|
|
164
178
|
|
|
179
|
+
it('should allow existing parameters to override the default entry-point mapping policy', async () => {
|
|
180
|
+
(mockWebex.request as jest.Mock).mockResolvedValue(mockResponse);
|
|
181
|
+
|
|
182
|
+
const result = await entryPointAPI.getEntryPoints({
|
|
183
|
+
page: 1,
|
|
184
|
+
pageSize: 25,
|
|
185
|
+
search: 'sales',
|
|
186
|
+
filter: 'entryPointId==entry1',
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
190
|
+
service: 'wcc-api-gateway',
|
|
191
|
+
resource:
|
|
192
|
+
'/organization/test-org-id/v3/dial-number?page=1&pageSize=25&attributes=id%2CdialledNumber%2CentryPointId%2CentryPointName&search=sales&filter=entryPointId%3D%3Dentry1&sort=entryPointName%2CASC&desktopProfileFilter=true&includeEntryPointName=true',
|
|
193
|
+
method: HTTP_METHODS.GET,
|
|
194
|
+
body: undefined,
|
|
195
|
+
headers: requestHeaders,
|
|
196
|
+
});
|
|
197
|
+
expect(result).toEqual({...mockResponse.body, data: expectedEntryPoints});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should issue every profile-scoped request directly', async () => {
|
|
201
|
+
(mockWebex.request as jest.Mock).mockResolvedValue(mockResponse);
|
|
202
|
+
|
|
203
|
+
await entryPointAPI.getEntryPoints();
|
|
204
|
+
await entryPointAPI.getEntryPoints();
|
|
205
|
+
|
|
206
|
+
expect(mockWebex.request).toHaveBeenCalledTimes(2);
|
|
207
|
+
expect(mockWebex.request).toHaveBeenLastCalledWith(
|
|
208
|
+
expect.objectContaining({
|
|
209
|
+
resource: expect.stringContaining('desktopProfileFilter=true'),
|
|
210
|
+
})
|
|
211
|
+
);
|
|
212
|
+
});
|
|
213
|
+
|
|
165
214
|
it('should handle API errors and track metrics', async () => {
|
|
166
215
|
(mockWebex.request as jest.Mock).mockRejectedValue(new Error('Internal Server Error'));
|
|
167
216
|
|
|
@@ -169,8 +218,10 @@ describe('EntryPoint', () => {
|
|
|
169
218
|
|
|
170
219
|
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
171
220
|
service: 'wcc-api-gateway',
|
|
172
|
-
resource:
|
|
221
|
+
resource: defaultResource,
|
|
173
222
|
method: HTTP_METHODS.GET,
|
|
223
|
+
body: undefined,
|
|
224
|
+
headers: requestHeaders,
|
|
174
225
|
});
|
|
175
226
|
|
|
176
227
|
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
@@ -187,22 +238,24 @@ describe('EntryPoint', () => {
|
|
|
187
238
|
expect(LoggerProxy.error).toHaveBeenCalled();
|
|
188
239
|
});
|
|
189
240
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
it('should not track metrics for subsequent pages in simple pagination', async () => {
|
|
241
|
+
it('should not track success metrics for subsequent pages under the default mapping policy', async () => {
|
|
193
242
|
(mockWebex.request as jest.Mock).mockResolvedValue(mockResponse);
|
|
194
243
|
|
|
195
244
|
const result = await entryPointAPI.getEntryPoints({page: 2});
|
|
196
|
-
expect(result).toEqual(mockResponse.body);
|
|
245
|
+
expect(result).toEqual({...mockResponse.body, data: expectedEntryPoints});
|
|
197
246
|
|
|
198
|
-
expect(mockMetricsManager.trackEvent).not.
|
|
247
|
+
expect(mockMetricsManager.trackEvent).not.toHaveBeenCalledWith(
|
|
248
|
+
METRIC_EVENT_NAMES.ENTRYPOINT_FETCH_SUCCESS,
|
|
249
|
+
expect.anything(),
|
|
250
|
+
expect.anything()
|
|
251
|
+
);
|
|
199
252
|
});
|
|
200
253
|
|
|
201
254
|
it('should track metrics for search requests on any page', async () => {
|
|
202
255
|
(mockWebex.request as jest.Mock).mockResolvedValue(mockResponse);
|
|
203
256
|
|
|
204
257
|
const result2 = await entryPointAPI.getEntryPoints({page: 2, search: 'test'});
|
|
205
|
-
expect(result2).toEqual(mockResponse.body);
|
|
258
|
+
expect(result2).toEqual({...mockResponse.body, data: expectedEntryPoints});
|
|
206
259
|
|
|
207
260
|
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
208
261
|
METRIC_EVENT_NAMES.ENTRYPOINT_FETCH_SUCCESS,
|
|
@@ -218,15 +271,11 @@ describe('EntryPoint', () => {
|
|
|
218
271
|
);
|
|
219
272
|
});
|
|
220
273
|
|
|
221
|
-
it('should
|
|
222
|
-
(mockWebex.request as jest.Mock).
|
|
223
|
-
|
|
224
|
-
await entryPointAPI.getEntryPoints({page: 0});
|
|
225
|
-
|
|
226
|
-
(mockWebex.request as jest.Mock).mockResolvedValueOnce({
|
|
274
|
+
it('should request the specified page', async () => {
|
|
275
|
+
(mockWebex.request as jest.Mock).mockResolvedValue({
|
|
227
276
|
...mockResponse,
|
|
228
277
|
body: {
|
|
229
|
-
data:
|
|
278
|
+
data: mockDialNumberMappings,
|
|
230
279
|
meta: {
|
|
231
280
|
page: 1,
|
|
232
281
|
pageSize: 100,
|
|
@@ -237,21 +286,19 @@ describe('EntryPoint', () => {
|
|
|
237
286
|
},
|
|
238
287
|
});
|
|
239
288
|
|
|
240
|
-
const callsBefore = (mockWebex.request as jest.Mock).mock.calls.length;
|
|
241
|
-
(LoggerProxy.log as jest.Mock).mockClear();
|
|
242
|
-
|
|
243
289
|
const result = await entryPointAPI.getEntryPoints({page: 1});
|
|
244
|
-
const callsAfter = (mockWebex.request as jest.Mock).mock.calls.length;
|
|
245
290
|
|
|
246
|
-
expect(callsAfter).toBe(callsBefore + 1);
|
|
247
291
|
expect(result.meta.page).toBe(1);
|
|
248
292
|
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
249
293
|
service: 'wcc-api-gateway',
|
|
250
|
-
resource:
|
|
294
|
+
resource:
|
|
295
|
+
'/organization/test-org-id/v3/dial-number?page=1&pageSize=100&attributes=id%2CdialledNumber%2CentryPointId%2CentryPointName&sort=entryPointName%2CASC&desktopProfileFilter=true&includeEntryPointName=true',
|
|
251
296
|
method: HTTP_METHODS.GET,
|
|
297
|
+
body: undefined,
|
|
298
|
+
headers: requestHeaders,
|
|
252
299
|
});
|
|
253
300
|
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
254
|
-
`Making API request to fetch entry points - resource: /organization/test-org-id/
|
|
301
|
+
`Making API request to fetch entry points - resource: /organization/test-org-id/v3/dial-number?page=1&pageSize=100&attributes=id%2CdialledNumber%2CentryPointId%2CentryPointName&sort=entryPointName%2CASC&desktopProfileFilter=true&includeEntryPointName=true, service: wcc-api-gateway`,
|
|
255
302
|
{module: 'EntryPoint', method: 'getEntryPoints'}
|
|
256
303
|
);
|
|
257
304
|
});
|