@webex/contact-center 3.11.0 → 3.12.0-llmrefactor.2
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
package/test/unit/spec/cc.ts
CHANGED
|
@@ -15,7 +15,7 @@ import type {ContactServiceQueuesResponse} from '../../../src/types';
|
|
|
15
15
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
16
16
|
import {StationLoginSuccess, AGENT_EVENTS} from '../../../src/services/agent/types';
|
|
17
17
|
import {SetStateResponse} from '../../../src/types';
|
|
18
|
-
import {AGENT, WEB_RTC_PREFIX} from '../../../src/services/constants';
|
|
18
|
+
import {AGENT, SUBSCRIBE_API, WEB_RTC_PREFIX} from '../../../src/services/constants';
|
|
19
19
|
import Services from '../../../src/services';
|
|
20
20
|
import config from '../../../src/config';
|
|
21
21
|
import {CC_EVENTS} from '../../../src/services/config/types';
|
|
@@ -59,6 +59,7 @@ global.URL.createObjectURL = jest.fn(() => 'blob:http://localhost:3000/12345');
|
|
|
59
59
|
|
|
60
60
|
describe('webex.cc', () => {
|
|
61
61
|
let webex;
|
|
62
|
+
let mockApiAIAssistant;
|
|
62
63
|
let mockContact;
|
|
63
64
|
let mockTaskManager;
|
|
64
65
|
let mockMetricsManager;
|
|
@@ -88,6 +89,8 @@ describe('webex.cc', () => {
|
|
|
88
89
|
initWebSocket: jest.fn(),
|
|
89
90
|
on: jest.fn(),
|
|
90
91
|
off: jest.fn(),
|
|
92
|
+
close: jest.fn(),
|
|
93
|
+
isSocketClosed: false,
|
|
91
94
|
};
|
|
92
95
|
|
|
93
96
|
mockContact = {
|
|
@@ -107,6 +110,14 @@ describe('webex.cc', () => {
|
|
|
107
110
|
cancelCtq: jest.fn(),
|
|
108
111
|
};
|
|
109
112
|
|
|
113
|
+
mockApiAIAssistant = {
|
|
114
|
+
sendEvent: jest.fn(),
|
|
115
|
+
getRealTimeAssistance: jest.fn(),
|
|
116
|
+
fetchHistoricTranscripts: jest.fn(),
|
|
117
|
+
setAIFeatureFlags: jest.fn(),
|
|
118
|
+
setAgentId: jest.fn(),
|
|
119
|
+
};
|
|
120
|
+
|
|
110
121
|
// Mock Services instance
|
|
111
122
|
const mockServicesInstance = {
|
|
112
123
|
agent: {
|
|
@@ -121,6 +132,13 @@ describe('webex.cc', () => {
|
|
|
121
132
|
getOutdialAniEntries: jest.fn(),
|
|
122
133
|
},
|
|
123
134
|
webSocketManager: mockWebSocketManager,
|
|
135
|
+
rtdWebSocketManager: {
|
|
136
|
+
initWebSocket: jest.fn().mockResolvedValue({}),
|
|
137
|
+
on: jest.fn(),
|
|
138
|
+
off: jest.fn(),
|
|
139
|
+
close: jest.fn(),
|
|
140
|
+
isSocketClosed: false,
|
|
141
|
+
},
|
|
124
142
|
connectionService: {
|
|
125
143
|
on: jest.fn(),
|
|
126
144
|
off: jest.fn(),
|
|
@@ -129,16 +147,25 @@ describe('webex.cc', () => {
|
|
|
129
147
|
|
|
130
148
|
dialer: {
|
|
131
149
|
startOutdial: jest.fn(),
|
|
150
|
+
acceptPreviewContact: jest.fn(),
|
|
151
|
+
skipPreviewContact: jest.fn(),
|
|
152
|
+
removePreviewContact: jest.fn(),
|
|
153
|
+
},
|
|
154
|
+
apiAIAssistant: {
|
|
155
|
+
sendEvent: jest.fn(),
|
|
156
|
+
fetchHistoricTranscripts: jest.fn(),
|
|
132
157
|
},
|
|
133
158
|
};
|
|
134
159
|
|
|
135
160
|
mockTaskManager = {
|
|
161
|
+
apiAIAssistant: mockApiAIAssistant,
|
|
136
162
|
contact: mockContact,
|
|
137
163
|
call: undefined,
|
|
138
164
|
taskCollection: {},
|
|
139
165
|
webCallingService: undefined,
|
|
140
166
|
webSocketManager: mockWebSocketManager,
|
|
141
167
|
task: undefined,
|
|
168
|
+
setConfigFlags: jest.fn(),
|
|
142
169
|
setWrapupData: jest.fn(),
|
|
143
170
|
setAgentId: jest.fn(),
|
|
144
171
|
setWebRtcEnabled: jest.fn(),
|
|
@@ -184,6 +211,35 @@ describe('webex.cc', () => {
|
|
|
184
211
|
webex.emit('ready');
|
|
185
212
|
});
|
|
186
213
|
|
|
214
|
+
it('should throw when WebRTC registration is disabled without multi-login', () => {
|
|
215
|
+
const invalidWebex = MockWebex({
|
|
216
|
+
children: {
|
|
217
|
+
mercury: Mercury,
|
|
218
|
+
},
|
|
219
|
+
logger: {
|
|
220
|
+
log: jest.fn(),
|
|
221
|
+
error: jest.fn(),
|
|
222
|
+
info: jest.fn(),
|
|
223
|
+
},
|
|
224
|
+
credentials: {
|
|
225
|
+
getOrgId: jest.fn(() => 'mockOrgId'),
|
|
226
|
+
},
|
|
227
|
+
config: {
|
|
228
|
+
...config,
|
|
229
|
+
cc: {
|
|
230
|
+
...config.cc,
|
|
231
|
+
allowMultiLogin: false,
|
|
232
|
+
disableWebRTCRegistration: true,
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
once: jest.fn((event, callback) => callback()),
|
|
236
|
+
}) as unknown as WebexSDK;
|
|
237
|
+
|
|
238
|
+
expect(() => new ContactCenter({parent: invalidWebex})).toThrow(
|
|
239
|
+
'Invalid Contact Center configuration: disableWebRTCRegistration cannot be true when allowMultiLogin is false. Enable allowMultiLogin or allow WebRTC registration so an SDK instance can receive Mobius/WebRTC task events.'
|
|
240
|
+
);
|
|
241
|
+
});
|
|
242
|
+
|
|
187
243
|
describe('cc.getDeviceId', () => {
|
|
188
244
|
it('should return dialNumber when loginOption is EXTENSION', () => {
|
|
189
245
|
const loginOption = LoginOption.EXTENSION;
|
|
@@ -251,7 +307,7 @@ describe('webex.cc', () => {
|
|
|
251
307
|
isAgentAvailableAfterOutdial: false,
|
|
252
308
|
isCampaignManagementEnabled: false,
|
|
253
309
|
outDialEp: '',
|
|
254
|
-
|
|
310
|
+
isEndTaskEnabled: false,
|
|
255
311
|
isEndConsultEnabled: false,
|
|
256
312
|
agentDbId: '',
|
|
257
313
|
allowConsultToQueue: false,
|
|
@@ -262,6 +318,7 @@ describe('webex.cc', () => {
|
|
|
262
318
|
};
|
|
263
319
|
|
|
264
320
|
it('should register successfully and return agent profile', async () => {
|
|
321
|
+
mockAgentProfile.aiFeature = {realtimeTranscripts: {enable: true}} as any;
|
|
265
322
|
const mercuryConnect = jest.spyOn(webex.internal.mercury, 'connect').mockResolvedValue(true);
|
|
266
323
|
const connectWebsocketSpy = jest.spyOn(webex.cc, 'connectWebsocket');
|
|
267
324
|
const setupEventListenersSpy = jest.spyOn(webex.cc, 'setupEventListeners');
|
|
@@ -283,7 +340,7 @@ describe('webex.cc', () => {
|
|
|
283
340
|
const result = await webex.cc.register();
|
|
284
341
|
|
|
285
342
|
// Verify logging calls
|
|
286
|
-
expect(LoggerProxy.
|
|
343
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting CC SDK registration', {
|
|
287
344
|
module: CC_FILE,
|
|
288
345
|
method: 'register',
|
|
289
346
|
});
|
|
@@ -305,6 +362,7 @@ describe('webex.cc', () => {
|
|
|
305
362
|
clientType: 'WebexCCSDK',
|
|
306
363
|
allowMultiLogin: false,
|
|
307
364
|
},
|
|
365
|
+
resource: SUBSCRIBE_API,
|
|
308
366
|
});
|
|
309
367
|
|
|
310
368
|
// TODO: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-626777 Implement the de-register method and close the listener there
|
|
@@ -316,13 +374,37 @@ describe('webex.cc', () => {
|
|
|
316
374
|
TASK_EVENTS.TASK_HYDRATE,
|
|
317
375
|
expect.any(Function)
|
|
318
376
|
);
|
|
377
|
+
expect(mockTaskManager.on).toHaveBeenCalledWith(
|
|
378
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
379
|
+
expect.any(Function)
|
|
380
|
+
);
|
|
319
381
|
expect(mockWebSocketManager.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
382
|
+
expect(webex.cc.services.rtdWebSocketManager.initWebSocket).toHaveBeenCalledWith({
|
|
383
|
+
body: {
|
|
384
|
+
force: true,
|
|
385
|
+
isKeepAliveEnabled: false,
|
|
386
|
+
clientType: 'WebexCCSDK',
|
|
387
|
+
allowMultiLogin: false,
|
|
388
|
+
},
|
|
389
|
+
resource: 'v1/realtime/subscribe',
|
|
390
|
+
});
|
|
391
|
+
expect(webex.cc.services.rtdWebSocketManager.on).toHaveBeenCalledWith(
|
|
392
|
+
'message',
|
|
393
|
+
expect.any(Function)
|
|
394
|
+
);
|
|
320
395
|
|
|
321
396
|
expect(configSpy).toHaveBeenCalled();
|
|
322
397
|
expect(LoggerProxy.log).toHaveBeenCalledWith('Agent config is fetched successfully', {
|
|
323
398
|
module: CC_FILE,
|
|
324
399
|
method: 'connectWebsocket',
|
|
325
400
|
});
|
|
401
|
+
expect(mockTaskManager.setConfigFlags).toHaveBeenCalledWith({
|
|
402
|
+
isEndTaskEnabled: mockAgentProfile.isEndTaskEnabled,
|
|
403
|
+
isEndConsultEnabled: mockAgentProfile.isEndConsultEnabled,
|
|
404
|
+
webRtcEnabled: mockAgentProfile.webRtcEnabled,
|
|
405
|
+
autoWrapup: mockAgentProfile.wrapUpData.wrapUpProps.autoWrapup ?? false,
|
|
406
|
+
aiFeature: mockAgentProfile.aiFeature,
|
|
407
|
+
});
|
|
326
408
|
expect(reloadSpy).toHaveBeenCalled();
|
|
327
409
|
expect(result).toEqual(mockAgentProfile);
|
|
328
410
|
expect(mockMetricsManager.timeEvent).toHaveBeenCalledWith([
|
|
@@ -360,6 +442,7 @@ describe('webex.cc', () => {
|
|
|
360
442
|
clientType: 'WebexCCSDK',
|
|
361
443
|
allowMultiLogin: true,
|
|
362
444
|
},
|
|
445
|
+
resource: SUBSCRIBE_API,
|
|
363
446
|
});
|
|
364
447
|
expect(configSpy).toHaveBeenCalled();
|
|
365
448
|
expect(LoggerProxy.log).toHaveBeenCalledWith('Agent config is fetched successfully', {
|
|
@@ -381,7 +464,7 @@ describe('webex.cc', () => {
|
|
|
381
464
|
|
|
382
465
|
await expect(webex.cc.register()).rejects.toThrow('Error while performing register');
|
|
383
466
|
|
|
384
|
-
expect(LoggerProxy.
|
|
467
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting CC SDK registration', {
|
|
385
468
|
module: CC_FILE,
|
|
386
469
|
method: 'register',
|
|
387
470
|
});
|
|
@@ -439,6 +522,7 @@ describe('webex.cc', () => {
|
|
|
439
522
|
clientType: 'WebexCCSDK',
|
|
440
523
|
allowMultiLogin: false,
|
|
441
524
|
},
|
|
525
|
+
resource: SUBSCRIBE_API,
|
|
442
526
|
});
|
|
443
527
|
|
|
444
528
|
expect(mockTaskManager.on).toHaveBeenCalledWith(
|
|
@@ -449,6 +533,10 @@ describe('webex.cc', () => {
|
|
|
449
533
|
TASK_EVENTS.TASK_HYDRATE,
|
|
450
534
|
expect.any(Function)
|
|
451
535
|
);
|
|
536
|
+
expect(mockTaskManager.on).toHaveBeenCalledWith(
|
|
537
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
538
|
+
expect.any(Function)
|
|
539
|
+
);
|
|
452
540
|
expect(mockWebSocketManager.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
453
541
|
|
|
454
542
|
expect(configSpy).toHaveBeenCalled();
|
|
@@ -460,8 +548,39 @@ describe('webex.cc', () => {
|
|
|
460
548
|
expect(result).toEqual(mockAgentProfile);
|
|
461
549
|
});
|
|
462
550
|
|
|
551
|
+
it('should skip mercury connection when disableWebRTCRegistration is enabled', async () => {
|
|
552
|
+
webex.cc.$config = {
|
|
553
|
+
...webex.cc.$config,
|
|
554
|
+
allowAutomatedRelogin: false,
|
|
555
|
+
disableWebRTCRegistration: true,
|
|
556
|
+
};
|
|
557
|
+
mockAgentProfile.webRtcEnabled = true;
|
|
558
|
+
const mercurySpy = jest.spyOn(webex.internal.mercury, 'connect');
|
|
559
|
+
const connectWebsocketSpy = jest.spyOn(webex.cc, 'connectWebsocket');
|
|
560
|
+
const setupEventListenersSpy = jest.spyOn(webex.cc, 'setupEventListeners');
|
|
561
|
+
jest.spyOn(webex.cc.services.config, 'getAgentConfig').mockResolvedValue(mockAgentProfile);
|
|
562
|
+
mockWebSocketManager.initWebSocket.mockResolvedValue({
|
|
563
|
+
agentId: 'agent123',
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
const result = await webex.cc.register();
|
|
567
|
+
|
|
568
|
+
expect(connectWebsocketSpy).toHaveBeenCalled();
|
|
569
|
+
expect(setupEventListenersSpy).toHaveBeenCalled();
|
|
570
|
+
expect(mercurySpy).not.toHaveBeenCalled();
|
|
571
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith(
|
|
572
|
+
'Skipping Mobius registration because disableWebRTCRegistration is enabled',
|
|
573
|
+
{
|
|
574
|
+
module: CC_FILE,
|
|
575
|
+
method: 'connectWebsocket',
|
|
576
|
+
}
|
|
577
|
+
);
|
|
578
|
+
expect(result).toEqual(mockAgentProfile);
|
|
579
|
+
});
|
|
580
|
+
|
|
463
581
|
it('should not attempt for mercury connection when webrtc is disabled', async () => {
|
|
464
582
|
mockAgentProfile.webRtcEnabled = false;
|
|
583
|
+
mockAgentProfile.aiFeature = {realtimeTranscripts: {enable: false}} as any;
|
|
465
584
|
const mercurySpy = jest.spyOn(webex.internal.mercury, 'connect');
|
|
466
585
|
const connectWebsocketSpy = jest.spyOn(webex.cc, 'connectWebsocket');
|
|
467
586
|
const setupEventListenersSpy = jest.spyOn(webex.cc, 'setupEventListeners');
|
|
@@ -491,12 +610,39 @@ describe('webex.cc', () => {
|
|
|
491
610
|
clientType: 'WebexCCSDK',
|
|
492
611
|
allowMultiLogin: false,
|
|
493
612
|
},
|
|
613
|
+
resource: SUBSCRIBE_API,
|
|
494
614
|
});
|
|
495
615
|
|
|
496
616
|
expect(configSpy).toHaveBeenCalled();
|
|
497
617
|
expect(mercurySpy).not.toHaveBeenCalled();
|
|
618
|
+
expect(webex.cc.services.rtdWebSocketManager.initWebSocket).not.toHaveBeenCalled();
|
|
498
619
|
expect(result).toEqual(mockAgentProfile);
|
|
499
620
|
});
|
|
621
|
+
|
|
622
|
+
it('should not connect RTD websocket when realtime transcripts feature is disabled', async () => {
|
|
623
|
+
mockAgentProfile.aiFeature = {realtimeTranscripts: {enable: false}} as any;
|
|
624
|
+
jest.spyOn(webex.internal.mercury, 'connect').mockResolvedValue(true);
|
|
625
|
+
jest.spyOn(webex.cc.services.agent, 'reload').mockResolvedValue({
|
|
626
|
+
data: {
|
|
627
|
+
auxCodeId: 'auxCodeId',
|
|
628
|
+
agentId: 'agentId',
|
|
629
|
+
deviceType: LoginOption.EXTENSION,
|
|
630
|
+
dn: '12345',
|
|
631
|
+
},
|
|
632
|
+
});
|
|
633
|
+
jest.spyOn(webex.cc.services.config, 'getAgentConfig').mockResolvedValue(mockAgentProfile);
|
|
634
|
+
mockWebSocketManager.initWebSocket.mockResolvedValue({
|
|
635
|
+
agentId: 'agent123',
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
await webex.cc.register();
|
|
639
|
+
|
|
640
|
+
expect(webex.cc.services.rtdWebSocketManager.initWebSocket).not.toHaveBeenCalled();
|
|
641
|
+
expect(webex.cc.services.rtdWebSocketManager.on).not.toHaveBeenCalledWith(
|
|
642
|
+
'message',
|
|
643
|
+
expect.any(Function)
|
|
644
|
+
);
|
|
645
|
+
});
|
|
500
646
|
});
|
|
501
647
|
|
|
502
648
|
describe('stationLogin', () => {
|
|
@@ -600,10 +746,8 @@ describe('webex.cc', () => {
|
|
|
600
746
|
|
|
601
747
|
expect(emitSpy).toHaveBeenCalledTimes(1);
|
|
602
748
|
expect(emitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_INCOMING, mockTask);
|
|
603
|
-
// Verify message
|
|
604
|
-
const messageCallback =
|
|
605
|
-
(call) => call[0] === 'message'
|
|
606
|
-
)[1];
|
|
749
|
+
// Verify websocket message handling
|
|
750
|
+
const messageCallback = webex.cc['handleWebsocketMessage'];
|
|
607
751
|
const agentStateChangeEventData = {
|
|
608
752
|
type: CC_EVENTS.AGENT_STATE_CHANGE,
|
|
609
753
|
data: {some: 'data'},
|
|
@@ -631,6 +775,59 @@ describe('webex.cc', () => {
|
|
|
631
775
|
);
|
|
632
776
|
});
|
|
633
777
|
|
|
778
|
+
it('should skip web calling line registration when disableWebRTCRegistration is enabled', async () => {
|
|
779
|
+
const options = {
|
|
780
|
+
teamId: 'teamId',
|
|
781
|
+
loginOption: LoginOption.BROWSER,
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
webex.cc.$config = {
|
|
785
|
+
...webex.cc.$config,
|
|
786
|
+
disableWebRTCRegistration: true,
|
|
787
|
+
};
|
|
788
|
+
webex.cc.agentConfig = {
|
|
789
|
+
agentId: 'agentId',
|
|
790
|
+
webRtcEnabled: true,
|
|
791
|
+
loginVoiceOptions: ['BROWSER', 'EXTENSION', 'AGENT_DN'],
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
const registerWebCallingLineSpy = jest.spyOn(
|
|
795
|
+
webex.cc.webCallingService,
|
|
796
|
+
'registerWebCallingLine'
|
|
797
|
+
);
|
|
798
|
+
|
|
799
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
800
|
+
data: {
|
|
801
|
+
loginOption: LoginOption.BROWSER,
|
|
802
|
+
agentId: 'agentId',
|
|
803
|
+
teamId: 'teamId',
|
|
804
|
+
siteId: 'siteId',
|
|
805
|
+
roles: [AGENT],
|
|
806
|
+
channelsMap: {
|
|
807
|
+
chat: [],
|
|
808
|
+
email: [],
|
|
809
|
+
social: [],
|
|
810
|
+
telephony: [],
|
|
811
|
+
},
|
|
812
|
+
},
|
|
813
|
+
trackingId: 'notifs_52628',
|
|
814
|
+
orgId: 'orgId',
|
|
815
|
+
type: 'StationLoginSuccess',
|
|
816
|
+
eventType: 'STATION_LOGIN',
|
|
817
|
+
} as unknown as StationLoginSuccess);
|
|
818
|
+
|
|
819
|
+
await webex.cc.stationLogin(options);
|
|
820
|
+
|
|
821
|
+
expect(registerWebCallingLineSpy).not.toHaveBeenCalled();
|
|
822
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith(
|
|
823
|
+
'Skipping web calling line registration because disableWebRTCRegistration is enabled',
|
|
824
|
+
{
|
|
825
|
+
module: CC_FILE,
|
|
826
|
+
method: 'stationLogin',
|
|
827
|
+
}
|
|
828
|
+
);
|
|
829
|
+
});
|
|
830
|
+
|
|
634
831
|
it('should not attempt mobius registration for LoginOption.BROWSER if webrtc is disabled', async () => {
|
|
635
832
|
const options = {
|
|
636
833
|
teamId: 'teamId',
|
|
@@ -753,10 +950,13 @@ describe('webex.cc', () => {
|
|
|
753
950
|
const result = await webex.cc.stationLogin(options);
|
|
754
951
|
|
|
755
952
|
// Verify logging calls
|
|
756
|
-
expect(LoggerProxy.
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
953
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
954
|
+
`Starting agent station login | loginOption: ${options.loginOption} teamId: ${options.teamId}`,
|
|
955
|
+
{
|
|
956
|
+
module: CC_FILE,
|
|
957
|
+
method: 'stationLogin',
|
|
958
|
+
}
|
|
959
|
+
);
|
|
760
960
|
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
761
961
|
`Agent station login completed successfully agentId: ${mockData.data.agentId} loginOption: ${mockData.data.loginOption} teamId: ${mockData.data.teamId}`,
|
|
762
962
|
{
|
|
@@ -807,10 +1007,13 @@ describe('webex.cc', () => {
|
|
|
807
1007
|
|
|
808
1008
|
await expect(webex.cc.stationLogin(options)).rejects.toThrow(error.details.data.reason);
|
|
809
1009
|
|
|
810
|
-
expect(LoggerProxy.
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
1010
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
1011
|
+
`Starting agent station login | loginOption: ${options.loginOption} teamId: ${options.teamId}`,
|
|
1012
|
+
{
|
|
1013
|
+
module: CC_FILE,
|
|
1014
|
+
method: 'stationLogin',
|
|
1015
|
+
}
|
|
1016
|
+
);
|
|
814
1017
|
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
815
1018
|
`stationLogin failed with reason: ${error.details.data.reason}`,
|
|
816
1019
|
{module: CC_FILE, method: 'stationLogin', trackingId: error.details.trackingId}
|
|
@@ -1149,11 +1352,11 @@ describe('webex.cc', () => {
|
|
|
1149
1352
|
const webSocketManagerOnSpy = jest.spyOn(webex.cc.services.webSocketManager, 'on');
|
|
1150
1353
|
await webex.cc['silentRelogin']();
|
|
1151
1354
|
|
|
1152
|
-
expect(LoggerProxy.
|
|
1355
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1153
1356
|
module: CC_FILE,
|
|
1154
1357
|
method: 'silentRelogin',
|
|
1155
1358
|
});
|
|
1156
|
-
expect(LoggerProxy.
|
|
1359
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
1157
1360
|
'event=requestAutoStateChange | Requesting state change to available on socket reconnect',
|
|
1158
1361
|
{module: CC_FILE, method: 'silentRelogin'}
|
|
1159
1362
|
);
|
|
@@ -1198,7 +1401,7 @@ describe('webex.cc', () => {
|
|
|
1198
1401
|
|
|
1199
1402
|
jest.spyOn(webex.cc.services.agent, 'reload').mockRejectedValue(error);
|
|
1200
1403
|
await webex.cc['silentRelogin']();
|
|
1201
|
-
expect(LoggerProxy.
|
|
1404
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1202
1405
|
module: CC_FILE,
|
|
1203
1406
|
method: 'silentRelogin',
|
|
1204
1407
|
});
|
|
@@ -1213,7 +1416,7 @@ describe('webex.cc', () => {
|
|
|
1213
1416
|
jest.spyOn(webex.cc.services.agent, 'reload').mockRejectedValue(error);
|
|
1214
1417
|
|
|
1215
1418
|
await expect(webex.cc['silentRelogin']()).rejects.toThrow(error);
|
|
1216
|
-
expect(LoggerProxy.
|
|
1419
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1217
1420
|
module: CC_FILE,
|
|
1218
1421
|
method: 'silentRelogin',
|
|
1219
1422
|
});
|
|
@@ -1255,7 +1458,7 @@ describe('webex.cc', () => {
|
|
|
1255
1458
|
|
|
1256
1459
|
await webex.cc['silentRelogin']();
|
|
1257
1460
|
|
|
1258
|
-
expect(LoggerProxy.
|
|
1461
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1259
1462
|
module: CC_FILE,
|
|
1260
1463
|
method: 'silentRelogin',
|
|
1261
1464
|
});
|
|
@@ -1439,6 +1642,27 @@ describe('webex.cc', () => {
|
|
|
1439
1642
|
});
|
|
1440
1643
|
});
|
|
1441
1644
|
|
|
1645
|
+
describe('getQueues', () => {
|
|
1646
|
+
it('delegates to the queue service when successful', async () => {
|
|
1647
|
+
const mockQueuesResponse = [{queueId: 'queue1', queueName: 'Queue 1'}];
|
|
1648
|
+
const queueSpy = jest
|
|
1649
|
+
.spyOn(webex.cc.queue, 'getQueues')
|
|
1650
|
+
.mockResolvedValue(mockQueuesResponse as any);
|
|
1651
|
+
|
|
1652
|
+
const result = await webex.cc.getQueues({page: 1});
|
|
1653
|
+
|
|
1654
|
+
expect(queueSpy).toHaveBeenCalledWith({page: 1});
|
|
1655
|
+
expect(result).toBe(mockQueuesResponse);
|
|
1656
|
+
});
|
|
1657
|
+
|
|
1658
|
+
it('propagates queue service errors', async () => {
|
|
1659
|
+
const error = new Error('Test error.');
|
|
1660
|
+
jest.spyOn(webex.cc.queue, 'getQueues').mockRejectedValue(error);
|
|
1661
|
+
|
|
1662
|
+
await expect(webex.cc.getQueues()).rejects.toThrow('Test error.');
|
|
1663
|
+
});
|
|
1664
|
+
});
|
|
1665
|
+
|
|
1442
1666
|
describe('uploadLogs', () => {
|
|
1443
1667
|
it('should upload logs successfully', async () => {
|
|
1444
1668
|
const uploadLogsMock = jest.spyOn(webex.cc.webexRequest, 'uploadLogs').mockResolvedValue({
|
|
@@ -1468,6 +1692,7 @@ describe('webex.cc', () => {
|
|
|
1468
1692
|
|
|
1469
1693
|
describe('unregister', () => {
|
|
1470
1694
|
let mockWebSocketManager;
|
|
1695
|
+
let mockRTDWebSocketManager;
|
|
1471
1696
|
let mercuryDisconnectSpy;
|
|
1472
1697
|
let deviceUnregisterSpy;
|
|
1473
1698
|
|
|
@@ -1484,8 +1709,15 @@ describe('webex.cc', () => {
|
|
|
1484
1709
|
off: jest.fn(),
|
|
1485
1710
|
on: jest.fn(),
|
|
1486
1711
|
};
|
|
1712
|
+
mockRTDWebSocketManager = {
|
|
1713
|
+
isSocketClosed: false,
|
|
1714
|
+
close: jest.fn(),
|
|
1715
|
+
off: jest.fn(),
|
|
1716
|
+
on: jest.fn(),
|
|
1717
|
+
};
|
|
1487
1718
|
|
|
1488
1719
|
webex.cc.services.webSocketManager = mockWebSocketManager;
|
|
1720
|
+
webex.cc.services.rtdWebSocketManager = mockRTDWebSocketManager;
|
|
1489
1721
|
|
|
1490
1722
|
webex.internal = webex.internal || {};
|
|
1491
1723
|
webex.internal.mercury = {
|
|
@@ -1502,6 +1734,13 @@ describe('webex.cc', () => {
|
|
|
1502
1734
|
});
|
|
1503
1735
|
|
|
1504
1736
|
it('should unregister successfully and clean up all resources when webrtc is enabled', async () => {
|
|
1737
|
+
webex.cc.services.rtdWebSocketManager = {
|
|
1738
|
+
isSocketClosed: false,
|
|
1739
|
+
close: jest.fn(),
|
|
1740
|
+
off: jest.fn(),
|
|
1741
|
+
on: jest.fn(),
|
|
1742
|
+
} as any;
|
|
1743
|
+
|
|
1505
1744
|
await webex.cc.deregister();
|
|
1506
1745
|
|
|
1507
1746
|
expect(mockTaskManager.off).toHaveBeenCalledWith(
|
|
@@ -1512,13 +1751,25 @@ describe('webex.cc', () => {
|
|
|
1512
1751
|
TASK_EVENTS.TASK_HYDRATE,
|
|
1513
1752
|
expect.any(Function)
|
|
1514
1753
|
);
|
|
1754
|
+
expect(mockTaskManager.off).toHaveBeenCalledWith(
|
|
1755
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
1756
|
+
expect.any(Function)
|
|
1757
|
+
);
|
|
1515
1758
|
expect(mockWebSocketManager.off).toHaveBeenCalledWith('message', expect.any(Function));
|
|
1759
|
+
expect(webex.cc.services.rtdWebSocketManager.off).toHaveBeenCalledWith(
|
|
1760
|
+
'message',
|
|
1761
|
+
expect.any(Function)
|
|
1762
|
+
);
|
|
1516
1763
|
expect(webex.cc.services.connectionService.off).toHaveBeenCalledWith(
|
|
1517
1764
|
'connectionLost',
|
|
1518
1765
|
expect.any(Function)
|
|
1519
1766
|
);
|
|
1520
1767
|
|
|
1521
1768
|
expect(mockWebSocketManager.close).toHaveBeenCalledWith(false, 'Unregistering the SDK');
|
|
1769
|
+
expect(webex.cc.services.rtdWebSocketManager.close).toHaveBeenCalledWith(
|
|
1770
|
+
false,
|
|
1771
|
+
'Unregistering the RTD websocket'
|
|
1772
|
+
);
|
|
1522
1773
|
expect(webex.cc.agentConfig).toBeNull();
|
|
1523
1774
|
|
|
1524
1775
|
expect(webex.internal.mercury.off).toHaveBeenCalledWith('online');
|
|
@@ -1560,6 +1811,13 @@ describe('webex.cc', () => {
|
|
|
1560
1811
|
const [, hydrateCallback] = hydrateCalls[0];
|
|
1561
1812
|
expect(hydrateCallback).toBe(webex.cc['handleTaskHydrate']);
|
|
1562
1813
|
|
|
1814
|
+
const multiLoginHydrateCalls = mockTaskManager.off.mock.calls.filter(
|
|
1815
|
+
([evt]) => evt === TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE
|
|
1816
|
+
);
|
|
1817
|
+
expect(multiLoginHydrateCalls).toHaveLength(1);
|
|
1818
|
+
const [, multiLoginHydrateCallback] = multiLoginHydrateCalls[0];
|
|
1819
|
+
expect(multiLoginHydrateCallback).toBe(webex.cc['handleTaskMultiLoginHydrate']);
|
|
1820
|
+
|
|
1563
1821
|
const messageCalls = mockWebSocketManager.off.mock.calls.filter(([evt]) => evt === 'message');
|
|
1564
1822
|
expect(messageCalls).toHaveLength(1);
|
|
1565
1823
|
const [, messageCallback] = messageCalls[0];
|
|
@@ -1585,6 +1843,10 @@ describe('webex.cc', () => {
|
|
|
1585
1843
|
TASK_EVENTS.TASK_HYDRATE,
|
|
1586
1844
|
expect.any(Function)
|
|
1587
1845
|
);
|
|
1846
|
+
expect(mockTaskManager.off).toHaveBeenCalledWith(
|
|
1847
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
1848
|
+
expect.any(Function)
|
|
1849
|
+
);
|
|
1588
1850
|
expect(mockWebSocketManager.off).toHaveBeenCalledWith('message', expect.any(Function));
|
|
1589
1851
|
expect(webex.cc.services.connectionService.off).toHaveBeenCalledWith(
|
|
1590
1852
|
'connectionLost',
|
|
@@ -1594,6 +1856,7 @@ describe('webex.cc', () => {
|
|
|
1594
1856
|
expect(webex.internal.mercury.off).not.toHaveBeenCalled();
|
|
1595
1857
|
expect(mercuryDisconnectSpy).not.toHaveBeenCalled();
|
|
1596
1858
|
expect(deviceUnregisterSpy).not.toHaveBeenCalled();
|
|
1859
|
+
expect(mockRTDWebSocketManager.close).toHaveBeenCalledWith(false, 'Unregistering the SDK');
|
|
1597
1860
|
});
|
|
1598
1861
|
|
|
1599
1862
|
it('should skip internal mercury cleanup when loginVoiceOptions does not include BROWSER', async () => {
|
|
@@ -1611,6 +1874,7 @@ describe('webex.cc', () => {
|
|
|
1611
1874
|
expect(deviceUnregisterSpy).not.toHaveBeenCalled();
|
|
1612
1875
|
|
|
1613
1876
|
expect(mockWebSocketManager.close).toHaveBeenCalledWith(false, 'Unregistering the SDK');
|
|
1877
|
+
expect(mockRTDWebSocketManager.close).toHaveBeenCalledWith(false, 'Unregistering the SDK');
|
|
1614
1878
|
expect(webex.cc.agentConfig).toBeNull();
|
|
1615
1879
|
});
|
|
1616
1880
|
|
|
@@ -1628,6 +1892,10 @@ describe('webex.cc', () => {
|
|
|
1628
1892
|
TASK_EVENTS.TASK_HYDRATE,
|
|
1629
1893
|
expect.any(Function)
|
|
1630
1894
|
);
|
|
1895
|
+
expect(mockTaskManager.off).toHaveBeenCalledWith(
|
|
1896
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
1897
|
+
expect.any(Function)
|
|
1898
|
+
);
|
|
1631
1899
|
|
|
1632
1900
|
expect(LoggerProxy.error).toHaveBeenCalledWith(`Error during deregister: ${mockError}`, {
|
|
1633
1901
|
module: CC_FILE,
|
|
@@ -1650,7 +1918,7 @@ describe('webex.cc', () => {
|
|
|
1650
1918
|
|
|
1651
1919
|
beforeEach(() => {
|
|
1652
1920
|
emitSpy = jest.spyOn(webex.cc, 'emit');
|
|
1653
|
-
messageCallback =
|
|
1921
|
+
messageCallback = webex.cc['handleWebsocketMessage'];
|
|
1654
1922
|
});
|
|
1655
1923
|
|
|
1656
1924
|
it('should emit AGENT_STATION_LOGIN_SUCCESS on CC_EVENTS.AGENT_STATION_LOGIN_SUCCESS with mapped payload', () => {
|
|
@@ -1850,7 +2118,7 @@ describe('webex.cc', () => {
|
|
|
1850
2118
|
);
|
|
1851
2119
|
|
|
1852
2120
|
expect(webex.cc.stationLogout).toHaveBeenCalledWith({
|
|
1853
|
-
logoutReason: 'User requested agent
|
|
2121
|
+
logoutReason: 'User requested agent profile update',
|
|
1854
2122
|
});
|
|
1855
2123
|
expect(webex.cc.stationLogin).toHaveBeenCalledWith({
|
|
1856
2124
|
teamId: 'teamId',
|
|
@@ -1934,24 +2202,26 @@ describe('webex.cc', () => {
|
|
|
1934
2202
|
});
|
|
1935
2203
|
});
|
|
1936
2204
|
|
|
1937
|
-
it('should
|
|
1938
|
-
webex.cc.webCallingService.loginOption = LoginOption.
|
|
2205
|
+
it('should allow update when loginOption and teamId are unchanged (e.g. dialNumber or profile refresh)', async () => {
|
|
2206
|
+
webex.cc.webCallingService.loginOption = LoginOption.AGENT_DN;
|
|
1939
2207
|
const data = {
|
|
1940
2208
|
teamId: 'teamId',
|
|
1941
|
-
loginOption: LoginOption.
|
|
1942
|
-
dialNumber: '',
|
|
2209
|
+
loginOption: LoginOption.AGENT_DN,
|
|
2210
|
+
dialNumber: '1234',
|
|
1943
2211
|
};
|
|
1944
|
-
const
|
|
1945
|
-
|
|
2212
|
+
const logoutSpy = jest.spyOn(webex.cc, 'stationLogout').mockResolvedValue({});
|
|
2213
|
+
const loginSpy = jest.spyOn(webex.cc, 'stationLogin').mockResolvedValue({
|
|
2214
|
+
type: 'AgentDeviceTypeUpdateSuccess',
|
|
2215
|
+
} as any);
|
|
1946
2216
|
|
|
1947
|
-
await expect(webex.cc.updateAgentProfile(data)).
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
2217
|
+
await expect(webex.cc.updateAgentProfile(data)).resolves.toBeDefined();
|
|
2218
|
+
expect(logoutSpy).toHaveBeenCalledWith({
|
|
2219
|
+
logoutReason: 'User requested agent profile update',
|
|
2220
|
+
});
|
|
2221
|
+
expect(loginSpy).toHaveBeenCalledWith({
|
|
2222
|
+
teamId: data.teamId,
|
|
2223
|
+
loginOption: data.loginOption,
|
|
2224
|
+
dialNumber: data.dialNumber,
|
|
1955
2225
|
});
|
|
1956
2226
|
});
|
|
1957
2227
|
|
|
@@ -2104,7 +2374,9 @@ describe('webex.cc', () => {
|
|
|
2104
2374
|
const detailedError = new Error('Detailed service error');
|
|
2105
2375
|
getErrorDetailsSpy.mockReturnValue({error: detailedError});
|
|
2106
2376
|
|
|
2107
|
-
await expect(webex.cc.getOutdialAniEntries(mockParams)).rejects.toThrow(
|
|
2377
|
+
await expect(webex.cc.getOutdialAniEntries(mockParams)).rejects.toThrow(
|
|
2378
|
+
'Detailed service error'
|
|
2379
|
+
);
|
|
2108
2380
|
|
|
2109
2381
|
// Verify failure metrics are tracked
|
|
2110
2382
|
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
@@ -2128,11 +2400,7 @@ describe('webex.cc', () => {
|
|
|
2128
2400
|
);
|
|
2129
2401
|
|
|
2130
2402
|
// Verify getErrorDetails was called
|
|
2131
|
-
expect(getErrorDetailsSpy).toHaveBeenCalledWith(
|
|
2132
|
-
mockError,
|
|
2133
|
-
'getOutdialAniEntries',
|
|
2134
|
-
CC_FILE
|
|
2135
|
-
);
|
|
2403
|
+
expect(getErrorDetailsSpy).toHaveBeenCalledWith(mockError, 'getOutdialAniEntries', CC_FILE);
|
|
2136
2404
|
});
|
|
2137
2405
|
|
|
2138
2406
|
it('should throw error when orgId is not found', async () => {
|
|
@@ -2180,4 +2448,196 @@ describe('webex.cc', () => {
|
|
|
2180
2448
|
);
|
|
2181
2449
|
});
|
|
2182
2450
|
});
|
|
2451
|
+
|
|
2452
|
+
describe('acceptPreviewContact', () => {
|
|
2453
|
+
const previewPayload = {
|
|
2454
|
+
interactionId: 'interaction-123',
|
|
2455
|
+
campaignId: 'campaign-456',
|
|
2456
|
+
};
|
|
2457
|
+
|
|
2458
|
+
it('should accept preview contact successfully', async () => {
|
|
2459
|
+
const mockResponse = {trackingId: 'track-123'} as AgentContact;
|
|
2460
|
+
|
|
2461
|
+
const acceptPreviewContactMock = jest
|
|
2462
|
+
.spyOn(webex.cc.services.dialer, 'acceptPreviewContact')
|
|
2463
|
+
.mockResolvedValue(mockResponse);
|
|
2464
|
+
|
|
2465
|
+
const result = await webex.cc.acceptPreviewContact(previewPayload);
|
|
2466
|
+
|
|
2467
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Accepting campaign preview contact', {
|
|
2468
|
+
module: CC_FILE,
|
|
2469
|
+
method: 'acceptPreviewContact',
|
|
2470
|
+
});
|
|
2471
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
2472
|
+
'Campaign preview contact accepted successfully',
|
|
2473
|
+
{
|
|
2474
|
+
module: CC_FILE,
|
|
2475
|
+
method: 'acceptPreviewContact',
|
|
2476
|
+
trackingId: 'track-123',
|
|
2477
|
+
interactionId: previewPayload.interactionId,
|
|
2478
|
+
}
|
|
2479
|
+
);
|
|
2480
|
+
|
|
2481
|
+
expect(acceptPreviewContactMock).toHaveBeenCalledWith({data: previewPayload});
|
|
2482
|
+
expect(result).toEqual(mockResponse);
|
|
2483
|
+
});
|
|
2484
|
+
|
|
2485
|
+
it('should handle error during acceptPreviewContact', async () => {
|
|
2486
|
+
getErrorDetailsSpy.mockRestore();
|
|
2487
|
+
getErrorDetailsSpy = jest.spyOn(Utils, 'getErrorDetails');
|
|
2488
|
+
|
|
2489
|
+
const error = {
|
|
2490
|
+
details: {
|
|
2491
|
+
trackingId: '1234',
|
|
2492
|
+
data: {
|
|
2493
|
+
reason: 'Error while performing acceptPreviewContact',
|
|
2494
|
+
},
|
|
2495
|
+
},
|
|
2496
|
+
};
|
|
2497
|
+
|
|
2498
|
+
jest.spyOn(webex.cc.services.dialer, 'acceptPreviewContact').mockRejectedValue(error);
|
|
2499
|
+
|
|
2500
|
+
await expect(webex.cc.acceptPreviewContact(previewPayload)).rejects.toThrow(
|
|
2501
|
+
error.details.data.reason
|
|
2502
|
+
);
|
|
2503
|
+
|
|
2504
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Accepting campaign preview contact', {
|
|
2505
|
+
module: CC_FILE,
|
|
2506
|
+
method: 'acceptPreviewContact',
|
|
2507
|
+
});
|
|
2508
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
2509
|
+
`acceptPreviewContact failed with reason: ${error.details.data.reason}`,
|
|
2510
|
+
{module: CC_FILE, method: 'acceptPreviewContact', trackingId: error.details.trackingId}
|
|
2511
|
+
);
|
|
2512
|
+
expect(getErrorDetailsSpy).toHaveBeenCalledWith(error, 'acceptPreviewContact', CC_FILE);
|
|
2513
|
+
});
|
|
2514
|
+
});
|
|
2515
|
+
|
|
2516
|
+
describe('skipPreviewContact', () => {
|
|
2517
|
+
const previewPayload = {
|
|
2518
|
+
interactionId: 'interaction-123',
|
|
2519
|
+
campaignId: 'campaign-456',
|
|
2520
|
+
};
|
|
2521
|
+
|
|
2522
|
+
it('should skip preview contact successfully', async () => {
|
|
2523
|
+
const mockResponse = {trackingId: 'track-123'} as AgentContact;
|
|
2524
|
+
|
|
2525
|
+
const skipPreviewContactMock = jest
|
|
2526
|
+
.spyOn(webex.cc.services.dialer, 'skipPreviewContact')
|
|
2527
|
+
.mockResolvedValue(mockResponse);
|
|
2528
|
+
|
|
2529
|
+
const result = await webex.cc.skipPreviewContact(previewPayload);
|
|
2530
|
+
|
|
2531
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Skipping campaign preview contact', {
|
|
2532
|
+
module: CC_FILE,
|
|
2533
|
+
method: 'skipPreviewContact',
|
|
2534
|
+
});
|
|
2535
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
2536
|
+
'Campaign preview contact skipped successfully',
|
|
2537
|
+
{
|
|
2538
|
+
module: CC_FILE,
|
|
2539
|
+
method: 'skipPreviewContact',
|
|
2540
|
+
trackingId: 'track-123',
|
|
2541
|
+
interactionId: previewPayload.interactionId,
|
|
2542
|
+
}
|
|
2543
|
+
);
|
|
2544
|
+
|
|
2545
|
+
expect(skipPreviewContactMock).toHaveBeenCalledWith({data: previewPayload});
|
|
2546
|
+
expect(result).toEqual(mockResponse);
|
|
2547
|
+
});
|
|
2548
|
+
|
|
2549
|
+
it('should handle error during skipPreviewContact', async () => {
|
|
2550
|
+
getErrorDetailsSpy.mockRestore();
|
|
2551
|
+
getErrorDetailsSpy = jest.spyOn(Utils, 'getErrorDetails');
|
|
2552
|
+
|
|
2553
|
+
const error = {
|
|
2554
|
+
details: {
|
|
2555
|
+
trackingId: '1234',
|
|
2556
|
+
data: {
|
|
2557
|
+
reason: 'Error while performing skipPreviewContact',
|
|
2558
|
+
},
|
|
2559
|
+
},
|
|
2560
|
+
};
|
|
2561
|
+
|
|
2562
|
+
jest.spyOn(webex.cc.services.dialer, 'skipPreviewContact').mockRejectedValue(error);
|
|
2563
|
+
|
|
2564
|
+
await expect(webex.cc.skipPreviewContact(previewPayload)).rejects.toThrow(
|
|
2565
|
+
error.details.data.reason
|
|
2566
|
+
);
|
|
2567
|
+
|
|
2568
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Skipping campaign preview contact', {
|
|
2569
|
+
module: CC_FILE,
|
|
2570
|
+
method: 'skipPreviewContact',
|
|
2571
|
+
});
|
|
2572
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
2573
|
+
`skipPreviewContact failed with reason: ${error.details.data.reason}`,
|
|
2574
|
+
{module: CC_FILE, method: 'skipPreviewContact', trackingId: error.details.trackingId}
|
|
2575
|
+
);
|
|
2576
|
+
expect(getErrorDetailsSpy).toHaveBeenCalledWith(error, 'skipPreviewContact', CC_FILE);
|
|
2577
|
+
});
|
|
2578
|
+
});
|
|
2579
|
+
|
|
2580
|
+
describe('removePreviewContact', () => {
|
|
2581
|
+
const previewPayload = {
|
|
2582
|
+
interactionId: 'interaction-123',
|
|
2583
|
+
campaignId: 'campaign-456',
|
|
2584
|
+
};
|
|
2585
|
+
|
|
2586
|
+
it('should remove preview contact successfully', async () => {
|
|
2587
|
+
const mockResponse = {trackingId: 'track-123'} as AgentContact;
|
|
2588
|
+
|
|
2589
|
+
const removePreviewContactMock = jest
|
|
2590
|
+
.spyOn(webex.cc.services.dialer, 'removePreviewContact')
|
|
2591
|
+
.mockResolvedValue(mockResponse);
|
|
2592
|
+
|
|
2593
|
+
const result = await webex.cc.removePreviewContact(previewPayload);
|
|
2594
|
+
|
|
2595
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Removing campaign preview contact', {
|
|
2596
|
+
module: CC_FILE,
|
|
2597
|
+
method: 'removePreviewContact',
|
|
2598
|
+
});
|
|
2599
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
2600
|
+
'Campaign preview contact removed successfully',
|
|
2601
|
+
{
|
|
2602
|
+
module: CC_FILE,
|
|
2603
|
+
method: 'removePreviewContact',
|
|
2604
|
+
trackingId: 'track-123',
|
|
2605
|
+
interactionId: previewPayload.interactionId,
|
|
2606
|
+
}
|
|
2607
|
+
);
|
|
2608
|
+
|
|
2609
|
+
expect(removePreviewContactMock).toHaveBeenCalledWith({data: previewPayload});
|
|
2610
|
+
expect(result).toEqual(mockResponse);
|
|
2611
|
+
});
|
|
2612
|
+
|
|
2613
|
+
it('should handle error during removePreviewContact', async () => {
|
|
2614
|
+
getErrorDetailsSpy.mockRestore();
|
|
2615
|
+
getErrorDetailsSpy = jest.spyOn(Utils, 'getErrorDetails');
|
|
2616
|
+
|
|
2617
|
+
const error = {
|
|
2618
|
+
details: {
|
|
2619
|
+
trackingId: '1234',
|
|
2620
|
+
data: {
|
|
2621
|
+
reason: 'Error while performing removePreviewContact',
|
|
2622
|
+
},
|
|
2623
|
+
},
|
|
2624
|
+
};
|
|
2625
|
+
|
|
2626
|
+
jest.spyOn(webex.cc.services.dialer, 'removePreviewContact').mockRejectedValue(error);
|
|
2627
|
+
|
|
2628
|
+
await expect(webex.cc.removePreviewContact(previewPayload)).rejects.toThrow(
|
|
2629
|
+
error.details.data.reason
|
|
2630
|
+
);
|
|
2631
|
+
|
|
2632
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Removing campaign preview contact', {
|
|
2633
|
+
module: CC_FILE,
|
|
2634
|
+
method: 'removePreviewContact',
|
|
2635
|
+
});
|
|
2636
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
2637
|
+
`removePreviewContact failed with reason: ${error.details.data.reason}`,
|
|
2638
|
+
{module: CC_FILE, method: 'removePreviewContact', trackingId: error.details.trackingId}
|
|
2639
|
+
);
|
|
2640
|
+
expect(getErrorDetailsSpy).toHaveBeenCalledWith(error, 'removePreviewContact', CC_FILE);
|
|
2641
|
+
});
|
|
2642
|
+
});
|
|
2183
2643
|
});
|