@webex/contact-center 3.11.0 → 3.12.0-llmrefactor.1
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 +882 -0
- package/AGENTS.md +94 -0
- package/ai-docs/ARCHITECTURE.md +168 -0
- package/ai-docs/CONTRACTS.md +46 -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 +48 -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 +341 -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 +379 -50
- package/dist/cc.js.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +22 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js +27 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +114 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +32 -3
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +318 -0
- package/dist/services/ApiAiAssistant.js.map +1 -0
- package/dist/services/UserPreference.js +427 -0
- package/dist/services/UserPreference.js.map +1 -0
- package/dist/services/agent/types.js.map +1 -1
- package/dist/services/config/Util.js +8 -4
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +35 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +41 -2
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +66 -8
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js +27 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +122 -25
- 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 +22 -6
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/connection-service.js +3 -1
- package/dist/services/core/websocket/connection-service.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +6 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +688 -0
- package/dist/services/task/Task.js.map +1 -0
- package/dist/services/task/TaskFactory.js +45 -0
- package/dist/services/task/TaskFactory.js.map +1 -0
- package/dist/services/task/TaskManager.js +751 -457
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +220 -23
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +23 -2
- 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/digital/Digital.js +77 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +873 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
- package/dist/services/task/state-machine/actions.js +567 -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 +382 -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 +603 -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 +227 -4
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1044 -0
- package/dist/services/task/voice/Voice.js.map +1 -0
- package/dist/services/task/voice/WebRTC.js +149 -0
- package/dist/services/task/voice/WebRTC.js.map +1 -0
- package/dist/types/cc.d.ts +894 -0
- package/dist/types/config.d.ts +72 -0
- package/dist/types/constants.d.ts +66 -0
- package/dist/types/index.d.ts +199 -0
- package/dist/types/logger-proxy.d.ts +71 -0
- package/dist/types/metrics/MetricsManager.d.ts +223 -0
- package/dist/types/metrics/behavioral-events.d.ts +29 -0
- package/dist/types/metrics/constants.d.ts +181 -0
- package/dist/types/services/AddressBook.d.ts +74 -0
- package/dist/types/services/ApiAiAssistant.d.ts +49 -0
- package/dist/types/services/EntryPoint.d.ts +67 -0
- package/dist/types/services/Queue.d.ts +76 -0
- package/dist/types/services/UserPreference.d.ts +118 -0
- package/dist/types/services/WebCallingService.d.ts +1 -0
- package/dist/types/services/agent/index.d.ts +46 -0
- package/dist/types/services/agent/types.d.ts +413 -0
- package/dist/types/services/config/Util.d.ts +20 -0
- package/dist/types/services/config/constants.d.ts +270 -0
- package/dist/types/services/config/index.d.ts +177 -0
- package/dist/types/services/config/types.d.ts +1368 -0
- package/dist/types/services/constants.d.ts +110 -0
- package/dist/types/services/core/Err.d.ts +125 -0
- package/dist/types/services/core/GlobalTypes.d.ts +58 -0
- package/dist/types/services/core/Utils.d.ts +121 -0
- package/dist/types/services/core/WebexRequest.d.ts +22 -0
- package/dist/types/services/core/aqm-reqs.d.ts +65 -0
- package/dist/types/services/core/constants.d.ts +99 -0
- package/dist/types/services/core/types.d.ts +47 -0
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +36 -0
- package/dist/types/services/core/websocket/connection-service.d.ts +27 -0
- package/dist/types/services/core/websocket/keepalive.worker.d.ts +2 -0
- package/dist/types/services/core/websocket/types.d.ts +37 -0
- package/dist/types/services/index.d.ts +54 -0
- package/dist/types/services/task/AutoWrapup.d.ts +40 -0
- package/dist/types/services/task/Task.d.ts +157 -0
- package/dist/types/services/task/TaskFactory.d.ts +12 -0
- package/dist/types/services/task/TaskManager.d.ts +1 -0
- package/dist/types/services/task/TaskUtils.d.ts +138 -0
- package/dist/types/services/task/constants.d.ts +91 -0
- package/dist/types/services/task/contact.d.ts +69 -0
- package/dist/types/services/task/dialer.d.ts +73 -0
- package/dist/types/services/task/digital/Digital.d.ts +22 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1194 -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 +102 -0
- package/dist/types/services/task/state-machine/index.d.ts +13 -0
- package/dist/types/services/task/state-machine/types.d.ts +269 -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 +1856 -0
- package/dist/types/services/task/voice/Voice.d.ts +184 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
- package/dist/types/types.d.ts +778 -0
- package/dist/types/utils/PageCache.d.ts +173 -0
- package/dist/types/webex-config.d.ts +53 -0
- package/dist/types/webex.d.ts +8 -0
- package/dist/types.js +130 -1
- package/dist/types.js.map +1 -1
- package/dist/webex.js +14 -2
- package/dist/webex.js.map +1 -1
- package/package.json +16 -12
- package/src/cc.ts +477 -51
- package/src/config.ts +6 -0
- package/src/constants.ts +21 -1
- package/src/index.ts +24 -5
- 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 +854 -0
- package/src/metrics/behavioral-events.ts +120 -0
- package/src/metrics/constants.ts +37 -3
- package/src/services/ApiAiAssistant.ts +412 -0
- package/src/services/UserPreference.ts +509 -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 +504 -0
- package/src/services/agent/types.ts +1 -1
- package/src/services/ai-docs/AGENTS.md +386 -0
- package/src/services/ai-docs/services-spec.md +492 -0
- package/src/services/config/Util.ts +10 -2
- 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 +669 -0
- package/src/services/config/constants.ts +37 -1
- package/src/services/config/index.ts +45 -1
- package/src/services/config/types.ts +241 -11
- package/src/services/constants.ts +29 -0
- package/src/services/core/Err.ts +3 -0
- package/src/services/core/Utils.ts +143 -30
- 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 +783 -0
- package/src/services/core/aqm-reqs.ts +100 -22
- package/src/services/core/websocket/WebSocketManager.ts +23 -6
- package/src/services/core/websocket/connection-service.ts +5 -1
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +4 -0
- package/src/services/task/Task.ts +837 -0
- package/src/services/task/TaskFactory.ts +55 -0
- package/src/services/task/TaskManager.ts +793 -521
- package/src/services/task/TaskUtils.ts +314 -24
- package/src/services/task/ai-docs/AGENTS.md +457 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +594 -0
- package/src/services/task/ai-docs/task-spec.md +1319 -0
- package/src/services/task/constants.ts +23 -0
- package/src/services/task/dialer.ts +136 -1
- package/src/services/task/digital/Digital.ts +95 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +1166 -0
- package/src/services/task/state-machine/actions.ts +738 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +458 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1137 -0
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2177 -0
- package/src/services/task/state-machine/constants.ts +172 -0
- package/src/services/task/state-machine/guards.ts +445 -0
- package/src/services/task/state-machine/index.ts +28 -0
- package/src/services/task/state-machine/types.ts +243 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +961 -0
- package/src/services/task/taskDataNormalizer.ts +137 -0
- package/src/services/task/types.ts +734 -71
- package/src/services/task/voice/Voice.ts +1270 -0
- package/src/services/task/voice/WebRTC.ts +187 -0
- package/src/types.ts +205 -2
- package/src/utils/AGENTS.md +278 -0
- package/src/utils/ai-docs/utils-spec.md +381 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +503 -43
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +273 -0
- package/test/unit/spec/services/UserPreference.ts +401 -0
- package/test/unit/spec/services/WebCallingService.ts +7 -1
- package/test/unit/spec/services/config/index.ts +85 -29
- package/test/unit/spec/services/core/Utils.ts +481 -2
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +137 -41
- package/test/unit/spec/services/core/websocket/connection-service.ts +3 -1
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +477 -0
- package/test/unit/spec/services/task/TaskFactory.ts +62 -0
- package/test/unit/spec/services/task/TaskManager.ts +1001 -1003
- package/test/unit/spec/services/task/TaskUtils.ts +235 -0
- package/test/unit/spec/services/task/dialer.ts +372 -96
- package/test/unit/spec/services/task/digital/Digital.ts +105 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +2651 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +637 -0
- package/test/unit/spec/services/task/state-machine/types.ts +18 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2663 -0
- package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
- package/test/unit/spec/services/task/voice/Voice.ts +649 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +235 -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/src/services/task/index.ts +0 -1801
- package/test/unit/spec/services/task/index.ts +0 -2184
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import {WebSocketManager} from '../../../../../../src/services/core/websocket/WebSocketManager';
|
|
3
3
|
import {WebexSDK, SubscribeRequest} from '../../../../../../src/types';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
RTD_SUBSCRIBE_API,
|
|
6
|
+
SUBSCRIBE_API,
|
|
7
|
+
WCC_API_GATEWAY,
|
|
8
|
+
} from '../../../../../../src/services/constants';
|
|
5
9
|
import {WEB_SOCKET_MANAGER_FILE} from '../../../../../../src/constants';
|
|
6
10
|
import LoggerProxy from '../../../../../../src/logger-proxy';
|
|
7
11
|
|
|
@@ -18,10 +22,10 @@ jest.mock('../../../../../../src/logger-proxy', () => ({
|
|
|
18
22
|
|
|
19
23
|
class MockWebSocket {
|
|
20
24
|
static inst: MockWebSocket;
|
|
21
|
-
onopen: () => void = () => {
|
|
22
|
-
onerror: (event: any) => void = () => {
|
|
23
|
-
onclose: (event: any) => void = () => {
|
|
24
|
-
onmessage: (msg: any) => void = () => {
|
|
25
|
+
onopen: () => void = () => {};
|
|
26
|
+
onerror: (event: any) => void = () => {};
|
|
27
|
+
onclose: (event: any) => void = () => {};
|
|
28
|
+
onmessage: (msg: any) => void = () => {};
|
|
25
29
|
close = jest.fn();
|
|
26
30
|
send = jest.fn();
|
|
27
31
|
|
|
@@ -37,7 +41,7 @@ class MockWebSocket {
|
|
|
37
41
|
class MockCustomEvent<T> extends Event {
|
|
38
42
|
detail: T;
|
|
39
43
|
|
|
40
|
-
constructor(event: string, params: {
|
|
44
|
+
constructor(event: string, params: {detail: T}) {
|
|
41
45
|
super(event);
|
|
42
46
|
this.detail = params.detail;
|
|
43
47
|
}
|
|
@@ -49,7 +53,7 @@ global.CustomEvent = MockCustomEvent as any;
|
|
|
49
53
|
class MockMessageEvent extends Event {
|
|
50
54
|
data: any;
|
|
51
55
|
|
|
52
|
-
constructor(type: string, eventInitDict: {
|
|
56
|
+
constructor(type: string, eventInitDict: {data: any}) {
|
|
53
57
|
super(type);
|
|
54
58
|
this.data = eventInitDict.data;
|
|
55
59
|
}
|
|
@@ -74,6 +78,14 @@ describe('WebSocketManager', () => {
|
|
|
74
78
|
|
|
75
79
|
mockWebex = {
|
|
76
80
|
request: jest.fn(),
|
|
81
|
+
credentials: {
|
|
82
|
+
getOrgId: jest.fn().mockReturnValue('test-org-id'),
|
|
83
|
+
},
|
|
84
|
+
internal: {
|
|
85
|
+
services: {
|
|
86
|
+
isIntegrationEnvironment: jest.fn().mockReturnValue(true), // INT environment by default
|
|
87
|
+
},
|
|
88
|
+
},
|
|
77
89
|
} as unknown as WebexSDK;
|
|
78
90
|
|
|
79
91
|
mockWorker = {
|
|
@@ -85,18 +97,18 @@ describe('WebSocketManager', () => {
|
|
|
85
97
|
global.WebSocket = MockWebSocket as any;
|
|
86
98
|
|
|
87
99
|
global.Blob = function (content: any[], options: any) {
|
|
88
|
-
return {
|
|
100
|
+
return {content, options};
|
|
89
101
|
} as any;
|
|
90
102
|
|
|
91
103
|
global.URL.createObjectURL = function (blob: Blob) {
|
|
92
104
|
return 'blob:http://localhost:3000/12345';
|
|
93
105
|
};
|
|
94
106
|
|
|
95
|
-
webSocketManager = new WebSocketManager({
|
|
107
|
+
webSocketManager = new WebSocketManager({webex: mockWebex});
|
|
96
108
|
|
|
97
109
|
setTimeout(() => {
|
|
98
110
|
MockWebSocket.inst.onopen();
|
|
99
|
-
MockWebSocket.inst.onmessage({
|
|
111
|
+
MockWebSocket.inst.onmessage({data: JSON.stringify({type: 'Welcome'})});
|
|
100
112
|
}, 1);
|
|
101
113
|
|
|
102
114
|
console.log = jest.fn();
|
|
@@ -107,22 +119,106 @@ describe('WebSocketManager', () => {
|
|
|
107
119
|
expect(webSocketManager).toBeDefined();
|
|
108
120
|
});
|
|
109
121
|
|
|
110
|
-
it('should register and connect to WebSocket', async () => {
|
|
122
|
+
it('should register and connect to WebSocket with X-ORGANIZATION-ID header for INT environment', async () => {
|
|
123
|
+
const subscribeResponse = {
|
|
124
|
+
body: {
|
|
125
|
+
webSocketUrl: 'wss://fake-url',
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Mock INT environment (services.isIntegrationEnvironment returns true)
|
|
130
|
+
(mockWebex.internal.services.isIntegrationEnvironment as jest.Mock).mockReturnValue(true);
|
|
131
|
+
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
132
|
+
|
|
133
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
134
|
+
|
|
135
|
+
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
136
|
+
service: WCC_API_GATEWAY,
|
|
137
|
+
resource: SUBSCRIBE_API,
|
|
138
|
+
method: 'POST',
|
|
139
|
+
body: fakeSubscribeRequest,
|
|
140
|
+
headers: {'X-ORGANIZATION-ID': 'test-org-id'},
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should connect rtd websocket', async () => {
|
|
145
|
+
const subscribeResponse = {
|
|
146
|
+
body: {
|
|
147
|
+
webSocketUrl: 'wss://fake-url',
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
152
|
+
|
|
153
|
+
await webSocketManager.initWebSocket({
|
|
154
|
+
body: fakeSubscribeRequest,
|
|
155
|
+
resource: RTD_SUBSCRIBE_API,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
159
|
+
service: WCC_API_GATEWAY,
|
|
160
|
+
resource: RTD_SUBSCRIBE_API,
|
|
161
|
+
method: 'POST',
|
|
162
|
+
body: fakeSubscribeRequest,
|
|
163
|
+
headers: {'X-ORGANIZATION-ID': 'test-org-id'},
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should register and connect to WebSocket without X-ORGANIZATION-ID header for production environment', async () => {
|
|
168
|
+
const subscribeResponse = {
|
|
169
|
+
body: {
|
|
170
|
+
webSocketUrl: 'wss://fake-url',
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
// Mock production environment (services.isIntegrationEnvironment returns false)
|
|
174
|
+
(mockWebex.internal.services.isIntegrationEnvironment as jest.Mock).mockReturnValue(false);
|
|
175
|
+
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
176
|
+
|
|
177
|
+
// Create new WebSocketManager instance with production mock
|
|
178
|
+
webSocketManager = new WebSocketManager({ webex: mockWebex });
|
|
179
|
+
|
|
180
|
+
setTimeout(() => {
|
|
181
|
+
MockWebSocket.inst.onopen();
|
|
182
|
+
MockWebSocket.inst.onmessage({ data: JSON.stringify({ type: "Welcome" }) });
|
|
183
|
+
}, 1);
|
|
184
|
+
|
|
185
|
+
await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
|
|
186
|
+
|
|
187
|
+
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
188
|
+
service: WCC_API_GATEWAY,
|
|
189
|
+
resource: SUBSCRIBE_API,
|
|
190
|
+
method: 'POST',
|
|
191
|
+
body: fakeSubscribeRequest,
|
|
192
|
+
headers: undefined,
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should not send X-ORGANIZATION-ID header when services.isIntegrationEnvironment is not available', async () => {
|
|
111
197
|
const subscribeResponse = {
|
|
112
198
|
body: {
|
|
113
199
|
webSocketUrl: 'wss://fake-url',
|
|
114
200
|
},
|
|
115
201
|
};
|
|
116
202
|
|
|
203
|
+
// Mock services not available (defaults to production behavior)
|
|
204
|
+
(mockWebex as any).internal = undefined;
|
|
117
205
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
118
206
|
|
|
119
|
-
|
|
207
|
+
webSocketManager = new WebSocketManager({ webex: mockWebex });
|
|
208
|
+
|
|
209
|
+
setTimeout(() => {
|
|
210
|
+
MockWebSocket.inst.onopen();
|
|
211
|
+
MockWebSocket.inst.onmessage({ data: JSON.stringify({ type: "Welcome" }) });
|
|
212
|
+
}, 1);
|
|
213
|
+
|
|
214
|
+
await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
|
|
120
215
|
|
|
121
216
|
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
122
217
|
service: WCC_API_GATEWAY,
|
|
123
218
|
resource: SUBSCRIBE_API,
|
|
124
219
|
method: 'POST',
|
|
125
220
|
body: fakeSubscribeRequest,
|
|
221
|
+
headers: undefined,
|
|
126
222
|
});
|
|
127
223
|
});
|
|
128
224
|
|
|
@@ -132,7 +228,7 @@ describe('WebSocketManager', () => {
|
|
|
132
228
|
(mockWebex.request as jest.Mock).mockRejectedValueOnce(error);
|
|
133
229
|
|
|
134
230
|
await expect(
|
|
135
|
-
webSocketManager.initWebSocket({ body: fakeSubscribeRequest })
|
|
231
|
+
webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API })
|
|
136
232
|
).rejects.toThrow(error);
|
|
137
233
|
|
|
138
234
|
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
@@ -155,12 +251,12 @@ describe('WebSocketManager', () => {
|
|
|
155
251
|
|
|
156
252
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
157
253
|
|
|
158
|
-
await webSocketManager.initWebSocket({
|
|
254
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
159
255
|
|
|
160
256
|
webSocketManager.close(true, 'Test reason');
|
|
161
257
|
|
|
162
258
|
expect(MockWebSocket.inst.close).toHaveBeenCalled();
|
|
163
|
-
expect(mockWorker.postMessage).toHaveBeenCalledWith({
|
|
259
|
+
expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
|
|
164
260
|
});
|
|
165
261
|
|
|
166
262
|
it('should handle WebSocket keepalive messages', async () => {
|
|
@@ -172,19 +268,19 @@ describe('WebSocketManager', () => {
|
|
|
172
268
|
|
|
173
269
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
174
270
|
|
|
175
|
-
await webSocketManager.initWebSocket({
|
|
271
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
176
272
|
|
|
177
273
|
setTimeout(() => {
|
|
178
274
|
MockWebSocket.inst.onopen();
|
|
179
|
-
MockWebSocket.inst.onmessage({
|
|
275
|
+
MockWebSocket.inst.onmessage({data: JSON.stringify({type: 'keepalive'})});
|
|
180
276
|
mockWorker.onmessage({
|
|
181
277
|
data: {
|
|
182
|
-
type: 'keepalive'
|
|
183
|
-
}
|
|
278
|
+
type: 'keepalive',
|
|
279
|
+
},
|
|
184
280
|
});
|
|
185
281
|
}, 1);
|
|
186
282
|
|
|
187
|
-
expect(MockWebSocket.inst.send).toHaveBeenCalledWith(JSON.stringify({
|
|
283
|
+
expect(MockWebSocket.inst.send).toHaveBeenCalledWith(JSON.stringify({keepalive: 'true'}));
|
|
188
284
|
});
|
|
189
285
|
|
|
190
286
|
it('should handle WebSocket close due to network issue', async () => {
|
|
@@ -196,7 +292,7 @@ describe('WebSocketManager', () => {
|
|
|
196
292
|
|
|
197
293
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
198
294
|
|
|
199
|
-
await webSocketManager.initWebSocket({
|
|
295
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
200
296
|
|
|
201
297
|
// Mock navigator.onLine to simulate network issue
|
|
202
298
|
Object.defineProperty(global, 'navigator', {
|
|
@@ -219,10 +315,10 @@ describe('WebSocketManager', () => {
|
|
|
219
315
|
// Wait for the close event to be handled
|
|
220
316
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
221
317
|
|
|
222
|
-
expect(mockWorker.postMessage).toHaveBeenCalledWith({
|
|
318
|
+
expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
|
|
223
319
|
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
224
320
|
'[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: network issue',
|
|
225
|
-
{
|
|
321
|
+
{module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
|
|
226
322
|
);
|
|
227
323
|
|
|
228
324
|
// Restore navigator.onLine to true
|
|
@@ -243,14 +339,14 @@ describe('WebSocketManager', () => {
|
|
|
243
339
|
|
|
244
340
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
245
341
|
|
|
246
|
-
await webSocketManager.initWebSocket({
|
|
342
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
247
343
|
|
|
248
344
|
const errorEvent = new Event('error');
|
|
249
345
|
MockWebSocket.inst.onerror(errorEvent);
|
|
250
346
|
|
|
251
347
|
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
252
348
|
'[WebSocketStatus] | event=socketConnectionFailed | WebSocket connection failed [object Event]',
|
|
253
|
-
{
|
|
349
|
+
{module: WEB_SOCKET_MANAGER_FILE, method: 'connect'}
|
|
254
350
|
);
|
|
255
351
|
});
|
|
256
352
|
|
|
@@ -263,17 +359,17 @@ describe('WebSocketManager', () => {
|
|
|
263
359
|
|
|
264
360
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
265
361
|
|
|
266
|
-
await webSocketManager.initWebSocket({
|
|
362
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
267
363
|
|
|
268
364
|
const messageEvent = new MessageEvent('message', {
|
|
269
|
-
data: JSON.stringify({
|
|
365
|
+
data: JSON.stringify({type: 'AGENT_MULTI_LOGIN'}),
|
|
270
366
|
});
|
|
271
367
|
MockWebSocket.inst.onmessage(messageEvent);
|
|
272
368
|
|
|
273
369
|
expect(MockWebSocket.inst.close).toHaveBeenCalled();
|
|
274
370
|
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
275
371
|
'[WebSocketStatus] | event=agentMultiLogin | WebSocket connection closed by agent multiLogin',
|
|
276
|
-
{
|
|
372
|
+
{module: WEB_SOCKET_MANAGER_FILE, method: 'connect'}
|
|
277
373
|
);
|
|
278
374
|
});
|
|
279
375
|
|
|
@@ -286,10 +382,10 @@ describe('WebSocketManager', () => {
|
|
|
286
382
|
|
|
287
383
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
288
384
|
|
|
289
|
-
await webSocketManager.initWebSocket({
|
|
385
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
290
386
|
|
|
291
387
|
const messageEvent = new MessageEvent('message', {
|
|
292
|
-
data: JSON.stringify({
|
|
388
|
+
data: JSON.stringify({type: 'Welcome', data: {someData: 'data'}}),
|
|
293
389
|
});
|
|
294
390
|
MockWebSocket.inst.onmessage(messageEvent);
|
|
295
391
|
|
|
@@ -305,7 +401,7 @@ describe('WebSocketManager', () => {
|
|
|
305
401
|
|
|
306
402
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
307
403
|
|
|
308
|
-
await webSocketManager.initWebSocket({
|
|
404
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
309
405
|
|
|
310
406
|
webSocketManager['forceCloseWebSocketOnTimeout'] = true;
|
|
311
407
|
|
|
@@ -324,10 +420,10 @@ describe('WebSocketManager', () => {
|
|
|
324
420
|
// Wait for the close event to be handled
|
|
325
421
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
326
422
|
|
|
327
|
-
expect(mockWorker.postMessage).toHaveBeenCalledWith({
|
|
423
|
+
expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
|
|
328
424
|
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
329
425
|
'[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: WebSocket auto close timed out. Forcefully closed websocket.',
|
|
330
|
-
{
|
|
426
|
+
{module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
|
|
331
427
|
);
|
|
332
428
|
});
|
|
333
429
|
|
|
@@ -340,7 +436,7 @@ describe('WebSocketManager', () => {
|
|
|
340
436
|
|
|
341
437
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
342
438
|
|
|
343
|
-
await webSocketManager.initWebSocket({
|
|
439
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
344
440
|
webSocketManager.shouldReconnect = false;
|
|
345
441
|
// Simulate the WebSocket close event
|
|
346
442
|
setTimeout(() => {
|
|
@@ -351,13 +447,13 @@ describe('WebSocketManager', () => {
|
|
|
351
447
|
target: MockWebSocket.inst,
|
|
352
448
|
});
|
|
353
449
|
}, 1);
|
|
354
|
-
|
|
450
|
+
|
|
355
451
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
356
452
|
|
|
357
|
-
expect(mockWorker.postMessage).toHaveBeenCalledWith({
|
|
453
|
+
expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
|
|
358
454
|
expect(LoggerProxy.error).not.toHaveBeenCalledWith(
|
|
359
455
|
'[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: no reconnect',
|
|
360
|
-
{
|
|
456
|
+
{module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
|
|
361
457
|
);
|
|
362
458
|
});
|
|
363
459
|
|
|
@@ -370,7 +466,7 @@ describe('WebSocketManager', () => {
|
|
|
370
466
|
|
|
371
467
|
(mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
|
|
372
468
|
|
|
373
|
-
await webSocketManager.initWebSocket({
|
|
469
|
+
await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
|
|
374
470
|
|
|
375
471
|
// Simulate the WebSocket close event
|
|
376
472
|
setTimeout(() => {
|
|
@@ -385,10 +481,10 @@ describe('WebSocketManager', () => {
|
|
|
385
481
|
// Wait for the close event to be handled
|
|
386
482
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
387
483
|
|
|
388
|
-
expect(mockWorker.postMessage).toHaveBeenCalledWith({
|
|
484
|
+
expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
|
|
389
485
|
expect(LoggerProxy.error).not.toHaveBeenCalledWith(
|
|
390
486
|
'[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: clean close',
|
|
391
|
-
{
|
|
487
|
+
{module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
|
|
392
488
|
);
|
|
393
489
|
});
|
|
394
|
-
});
|
|
490
|
+
});
|
|
@@ -4,6 +4,8 @@ import {SubscribeRequest} from '../../../../../../src/types';
|
|
|
4
4
|
import LoggerProxy from '../../../../../../src/logger-proxy';
|
|
5
5
|
import {CONNECTIVITY_CHECK_INTERVAL} from '../../../../../../src/services/core/constants';
|
|
6
6
|
import { CONNECTION_SERVICE_FILE } from '../../../../../../src/constants';
|
|
7
|
+
import {SUBSCRIBE_API} from '../../../../../../src/services/constants';
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
jest.mock('../../../../../../src/services/core/websocket/WebSocketManager');
|
|
9
11
|
jest.mock('../../../../../../src/logger-proxy', () => ({
|
|
@@ -109,7 +111,7 @@ describe('ConnectionService', () => {
|
|
|
109
111
|
'event=socketConnectionRetry | Trying to reconnect to websocket',
|
|
110
112
|
{module: CONNECTION_SERVICE_FILE, method: 'handleSocketClose'}
|
|
111
113
|
);
|
|
112
|
-
expect(mockWebSocketManager.initWebSocket).toHaveBeenCalledWith({body: mockSubscribeRequest});
|
|
114
|
+
expect(mockWebSocketManager.initWebSocket).toHaveBeenCalledWith({body: mockSubscribeRequest, resource: SUBSCRIBE_API});
|
|
113
115
|
});
|
|
114
116
|
|
|
115
117
|
describe('ConnectionService onPing', () => {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import AutoWrapup from '../../../../../src/services/task/AutoWrapup';
|
|
2
|
+
|
|
3
|
+
describe('AutoWrapup', () => {
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
jest.useFakeTimers();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
jest.useRealTimers();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('starts, reports running, and completes', () => {
|
|
13
|
+
const onComplete = jest.fn();
|
|
14
|
+
const timer = new AutoWrapup(1000, true);
|
|
15
|
+
|
|
16
|
+
expect(timer.allowCancelAutoWrapup).toBe(true);
|
|
17
|
+
expect(timer.isRunning()).toBe(false);
|
|
18
|
+
|
|
19
|
+
timer.start(onComplete);
|
|
20
|
+
expect(timer.isRunning()).toBe(true);
|
|
21
|
+
expect(timer.getTimeLeft()).toBeGreaterThan(0);
|
|
22
|
+
expect(timer.getTimeLeftSeconds()).toBeGreaterThan(0);
|
|
23
|
+
|
|
24
|
+
jest.advanceTimersByTime(1000);
|
|
25
|
+
expect(onComplete).toHaveBeenCalledTimes(1);
|
|
26
|
+
expect(timer.isRunning()).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('clear() is safe when not running and cancels an active timer', () => {
|
|
30
|
+
const onComplete = jest.fn();
|
|
31
|
+
const timer = new AutoWrapup(1000);
|
|
32
|
+
|
|
33
|
+
timer.clear(); // no-op
|
|
34
|
+
expect(timer.isRunning()).toBe(false);
|
|
35
|
+
|
|
36
|
+
timer.start(onComplete);
|
|
37
|
+
expect(timer.isRunning()).toBe(true);
|
|
38
|
+
|
|
39
|
+
timer.clear();
|
|
40
|
+
expect(timer.isRunning()).toBe(false);
|
|
41
|
+
|
|
42
|
+
jest.advanceTimersByTime(1000);
|
|
43
|
+
expect(onComplete).not.toHaveBeenCalled();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('start() replaces an existing timer', () => {
|
|
47
|
+
const onComplete1 = jest.fn();
|
|
48
|
+
const onComplete2 = jest.fn();
|
|
49
|
+
const timer = new AutoWrapup(1000);
|
|
50
|
+
|
|
51
|
+
timer.start(onComplete1);
|
|
52
|
+
jest.advanceTimersByTime(500);
|
|
53
|
+
|
|
54
|
+
timer.start(onComplete2);
|
|
55
|
+
jest.advanceTimersByTime(500);
|
|
56
|
+
expect(onComplete1).not.toHaveBeenCalled();
|
|
57
|
+
expect(onComplete2).not.toHaveBeenCalled();
|
|
58
|
+
|
|
59
|
+
jest.advanceTimersByTime(500);
|
|
60
|
+
expect(onComplete2).toHaveBeenCalledTimes(1);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|