@webex/contact-center 3.12.0-next.8 → 3.12.0-next.80
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/AGENTS.md +438 -0
- package/ai-docs/README.md +131 -0
- package/ai-docs/RULES.md +455 -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 +265 -29
- package/dist/cc.js.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +16 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +101 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +23 -4
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +74 -3
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/UserPreference.js +427 -0
- package/dist/services/UserPreference.js.map +1 -0
- package/dist/services/config/Util.js +3 -3
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +23 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/types.js +49 -9
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +107 -32
- package/dist/services/core/Utils.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 +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 +725 -526
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +162 -26
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +9 -2
- package/dist/services/task/constants.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 +77 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +837 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
- package/dist/services/task/state-machine/actions.js +543 -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 +340 -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 +553 -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 +212 -4
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1042 -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 +94 -1
- package/dist/types/config.d.ts +6 -0
- package/dist/types/constants.d.ts +16 -1
- package/dist/types/index.d.ts +21 -6
- package/dist/types/metrics/constants.d.ts +19 -1
- package/dist/types/services/ApiAiAssistant.d.ts +11 -3
- package/dist/types/services/UserPreference.d.ts +118 -0
- package/dist/types/services/config/constants.d.ts +21 -0
- package/dist/types/services/config/types.d.ts +171 -10
- package/dist/types/services/core/Err.d.ts +4 -0
- package/dist/types/services/core/Utils.d.ts +33 -13
- 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 +157 -0
- package/dist/types/services/task/TaskFactory.d.ts +12 -0
- package/dist/types/services/task/TaskUtils.d.ts +46 -2
- package/dist/types/services/task/constants.d.ts +7 -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 +1144 -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 +90 -0
- package/dist/types/services/task/state-machine/index.d.ts +13 -0
- package/dist/types/services/task/state-machine/types.d.ts +267 -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 +603 -66
- 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 +94 -0
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +85 -0
- package/dist/types.js.map +1 -1
- package/dist/webex.js +14 -2
- package/dist/webex.js.map +1 -1
- package/package.json +15 -12
- package/src/cc.ts +329 -30
- package/src/config.ts +6 -0
- package/src/constants.ts +16 -1
- package/src/index.ts +23 -5
- package/src/metrics/ai-docs/AGENTS.md +348 -0
- package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
- package/src/metrics/behavioral-events.ts +106 -0
- package/src/metrics/constants.ts +23 -4
- package/src/services/ApiAiAssistant.ts +104 -3
- package/src/services/UserPreference.ts +509 -0
- package/src/services/agent/ai-docs/AGENTS.md +238 -0
- package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
- package/src/services/ai-docs/AGENTS.md +384 -0
- package/src/services/config/Util.ts +3 -3
- package/src/services/config/ai-docs/AGENTS.md +253 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
- package/src/services/config/constants.ts +25 -1
- package/src/services/config/types.ts +174 -11
- package/src/services/core/Err.ts +2 -0
- package/src/services/core/Utils.ts +123 -37
- package/src/services/core/ai-docs/AGENTS.md +379 -0
- package/src/services/core/ai-docs/ARCHITECTURE.md +696 -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 +837 -0
- package/src/services/task/TaskFactory.ts +55 -0
- package/src/services/task/TaskManager.ts +738 -613
- package/src/services/task/TaskUtils.ts +205 -25
- package/src/services/task/ai-docs/AGENTS.md +455 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +585 -0
- package/src/services/task/constants.ts +7 -0
- package/src/services/task/dialer.ts +80 -0
- package/src/services/task/digital/Digital.ts +95 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +1077 -0
- package/src/services/task/state-machine/actions.ts +685 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
- package/src/services/task/state-machine/constants.ts +172 -0
- package/src/services/task/state-machine/guards.ts +406 -0
- package/src/services/task/state-machine/index.ts +28 -0
- package/src/services/task/state-machine/types.ts +241 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +867 -0
- package/src/services/task/taskDataNormalizer.ts +137 -0
- package/src/services/task/types.ts +710 -71
- package/src/services/task/voice/Voice.ts +1267 -0
- package/src/services/task/voice/WebRTC.ts +187 -0
- package/src/types.ts +122 -2
- package/src/utils/AGENTS.md +276 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +343 -23
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +122 -17
- 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 +30 -30
- package/test/unit/spec/services/core/Utils.ts +425 -8
- 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 +477 -0
- package/test/unit/spec/services/task/TaskFactory.ts +62 -0
- package/test/unit/spec/services/task/TaskManager.ts +832 -1702
- package/test/unit/spec/services/task/TaskUtils.ts +206 -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 +1825 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +479 -0
- package/test/unit/spec/services/task/state-machine/types.ts +18 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2020 -0
- package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
- package/test/unit/spec/services/task/voice/Voice.ts +631 -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/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
package/test/unit/spec/cc.ts
CHANGED
|
@@ -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;
|
|
@@ -109,6 +110,14 @@ describe('webex.cc', () => {
|
|
|
109
110
|
cancelCtq: jest.fn(),
|
|
110
111
|
};
|
|
111
112
|
|
|
113
|
+
mockApiAIAssistant = {
|
|
114
|
+
sendEvent: jest.fn(),
|
|
115
|
+
getSuggestedResponse: jest.fn(),
|
|
116
|
+
fetchHistoricTranscripts: jest.fn(),
|
|
117
|
+
setAIFeatureFlags: jest.fn(),
|
|
118
|
+
setAgentId: jest.fn(),
|
|
119
|
+
};
|
|
120
|
+
|
|
112
121
|
// Mock Services instance
|
|
113
122
|
const mockServicesInstance = {
|
|
114
123
|
agent: {
|
|
@@ -139,6 +148,8 @@ describe('webex.cc', () => {
|
|
|
139
148
|
dialer: {
|
|
140
149
|
startOutdial: jest.fn(),
|
|
141
150
|
acceptPreviewContact: jest.fn(),
|
|
151
|
+
skipPreviewContact: jest.fn(),
|
|
152
|
+
removePreviewContact: jest.fn(),
|
|
142
153
|
},
|
|
143
154
|
apiAIAssistant: {
|
|
144
155
|
sendEvent: jest.fn(),
|
|
@@ -147,17 +158,17 @@ describe('webex.cc', () => {
|
|
|
147
158
|
};
|
|
148
159
|
|
|
149
160
|
mockTaskManager = {
|
|
161
|
+
apiAIAssistant: mockApiAIAssistant,
|
|
150
162
|
contact: mockContact,
|
|
151
163
|
call: undefined,
|
|
152
164
|
taskCollection: {},
|
|
153
165
|
webCallingService: undefined,
|
|
154
166
|
webSocketManager: mockWebSocketManager,
|
|
155
167
|
task: undefined,
|
|
168
|
+
setConfigFlags: jest.fn(),
|
|
156
169
|
setWrapupData: jest.fn(),
|
|
157
170
|
setAgentId: jest.fn(),
|
|
158
171
|
setWebRtcEnabled: jest.fn(),
|
|
159
|
-
handleRealtimeTranscriptEvent: jest.fn(),
|
|
160
|
-
setApiAIAssistant: jest.fn(),
|
|
161
172
|
registerIncomingCallEvent: jest.fn(),
|
|
162
173
|
registerTaskListeners: jest.fn(),
|
|
163
174
|
getTask: jest.fn(),
|
|
@@ -200,6 +211,35 @@ describe('webex.cc', () => {
|
|
|
200
211
|
webex.emit('ready');
|
|
201
212
|
});
|
|
202
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
|
+
|
|
203
243
|
describe('cc.getDeviceId', () => {
|
|
204
244
|
it('should return dialNumber when loginOption is EXTENSION', () => {
|
|
205
245
|
const loginOption = LoginOption.EXTENSION;
|
|
@@ -267,7 +307,7 @@ describe('webex.cc', () => {
|
|
|
267
307
|
isAgentAvailableAfterOutdial: false,
|
|
268
308
|
isCampaignManagementEnabled: false,
|
|
269
309
|
outDialEp: '',
|
|
270
|
-
|
|
310
|
+
isEndTaskEnabled: false,
|
|
271
311
|
isEndConsultEnabled: false,
|
|
272
312
|
agentDbId: '',
|
|
273
313
|
allowConsultToQueue: false,
|
|
@@ -300,7 +340,7 @@ describe('webex.cc', () => {
|
|
|
300
340
|
const result = await webex.cc.register();
|
|
301
341
|
|
|
302
342
|
// Verify logging calls
|
|
303
|
-
expect(LoggerProxy.
|
|
343
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting CC SDK registration', {
|
|
304
344
|
module: CC_FILE,
|
|
305
345
|
method: 'register',
|
|
306
346
|
});
|
|
@@ -334,6 +374,10 @@ describe('webex.cc', () => {
|
|
|
334
374
|
TASK_EVENTS.TASK_HYDRATE,
|
|
335
375
|
expect.any(Function)
|
|
336
376
|
);
|
|
377
|
+
expect(mockTaskManager.on).toHaveBeenCalledWith(
|
|
378
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
379
|
+
expect.any(Function)
|
|
380
|
+
);
|
|
337
381
|
expect(mockWebSocketManager.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
338
382
|
expect(webex.cc.services.rtdWebSocketManager.initWebSocket).toHaveBeenCalledWith({
|
|
339
383
|
body: {
|
|
@@ -354,6 +398,13 @@ describe('webex.cc', () => {
|
|
|
354
398
|
module: CC_FILE,
|
|
355
399
|
method: 'connectWebsocket',
|
|
356
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
|
+
});
|
|
357
408
|
expect(reloadSpy).toHaveBeenCalled();
|
|
358
409
|
expect(result).toEqual(mockAgentProfile);
|
|
359
410
|
expect(mockMetricsManager.timeEvent).toHaveBeenCalledWith([
|
|
@@ -413,7 +464,7 @@ describe('webex.cc', () => {
|
|
|
413
464
|
|
|
414
465
|
await expect(webex.cc.register()).rejects.toThrow('Error while performing register');
|
|
415
466
|
|
|
416
|
-
expect(LoggerProxy.
|
|
467
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting CC SDK registration', {
|
|
417
468
|
module: CC_FILE,
|
|
418
469
|
method: 'register',
|
|
419
470
|
});
|
|
@@ -482,6 +533,10 @@ describe('webex.cc', () => {
|
|
|
482
533
|
TASK_EVENTS.TASK_HYDRATE,
|
|
483
534
|
expect.any(Function)
|
|
484
535
|
);
|
|
536
|
+
expect(mockTaskManager.on).toHaveBeenCalledWith(
|
|
537
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
538
|
+
expect.any(Function)
|
|
539
|
+
);
|
|
485
540
|
expect(mockWebSocketManager.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
486
541
|
|
|
487
542
|
expect(configSpy).toHaveBeenCalled();
|
|
@@ -493,6 +548,36 @@ describe('webex.cc', () => {
|
|
|
493
548
|
expect(result).toEqual(mockAgentProfile);
|
|
494
549
|
});
|
|
495
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
|
+
|
|
496
581
|
it('should not attempt for mercury connection when webrtc is disabled', async () => {
|
|
497
582
|
mockAgentProfile.webRtcEnabled = false;
|
|
498
583
|
mockAgentProfile.aiFeature = {realtimeTranscripts: {enable: false}} as any;
|
|
@@ -661,10 +746,8 @@ describe('webex.cc', () => {
|
|
|
661
746
|
|
|
662
747
|
expect(emitSpy).toHaveBeenCalledTimes(1);
|
|
663
748
|
expect(emitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_INCOMING, mockTask);
|
|
664
|
-
// Verify message
|
|
665
|
-
const messageCallback =
|
|
666
|
-
(call) => call[0] === 'message'
|
|
667
|
-
)[1];
|
|
749
|
+
// Verify websocket message handling
|
|
750
|
+
const messageCallback = webex.cc['handleWebsocketMessage'];
|
|
668
751
|
const agentStateChangeEventData = {
|
|
669
752
|
type: CC_EVENTS.AGENT_STATE_CHANGE,
|
|
670
753
|
data: {some: 'data'},
|
|
@@ -692,6 +775,59 @@ describe('webex.cc', () => {
|
|
|
692
775
|
);
|
|
693
776
|
});
|
|
694
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
|
+
|
|
695
831
|
it('should not attempt mobius registration for LoginOption.BROWSER if webrtc is disabled', async () => {
|
|
696
832
|
const options = {
|
|
697
833
|
teamId: 'teamId',
|
|
@@ -814,10 +950,13 @@ describe('webex.cc', () => {
|
|
|
814
950
|
const result = await webex.cc.stationLogin(options);
|
|
815
951
|
|
|
816
952
|
// Verify logging calls
|
|
817
|
-
expect(LoggerProxy.
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
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
|
+
);
|
|
821
960
|
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
822
961
|
`Agent station login completed successfully agentId: ${mockData.data.agentId} loginOption: ${mockData.data.loginOption} teamId: ${mockData.data.teamId}`,
|
|
823
962
|
{
|
|
@@ -868,10 +1007,13 @@ describe('webex.cc', () => {
|
|
|
868
1007
|
|
|
869
1008
|
await expect(webex.cc.stationLogin(options)).rejects.toThrow(error.details.data.reason);
|
|
870
1009
|
|
|
871
|
-
expect(LoggerProxy.
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
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
|
+
);
|
|
875
1017
|
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
876
1018
|
`stationLogin failed with reason: ${error.details.data.reason}`,
|
|
877
1019
|
{module: CC_FILE, method: 'stationLogin', trackingId: error.details.trackingId}
|
|
@@ -1210,11 +1352,11 @@ describe('webex.cc', () => {
|
|
|
1210
1352
|
const webSocketManagerOnSpy = jest.spyOn(webex.cc.services.webSocketManager, 'on');
|
|
1211
1353
|
await webex.cc['silentRelogin']();
|
|
1212
1354
|
|
|
1213
|
-
expect(LoggerProxy.
|
|
1355
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1214
1356
|
module: CC_FILE,
|
|
1215
1357
|
method: 'silentRelogin',
|
|
1216
1358
|
});
|
|
1217
|
-
expect(LoggerProxy.
|
|
1359
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith(
|
|
1218
1360
|
'event=requestAutoStateChange | Requesting state change to available on socket reconnect',
|
|
1219
1361
|
{module: CC_FILE, method: 'silentRelogin'}
|
|
1220
1362
|
);
|
|
@@ -1259,7 +1401,7 @@ describe('webex.cc', () => {
|
|
|
1259
1401
|
|
|
1260
1402
|
jest.spyOn(webex.cc.services.agent, 'reload').mockRejectedValue(error);
|
|
1261
1403
|
await webex.cc['silentRelogin']();
|
|
1262
|
-
expect(LoggerProxy.
|
|
1404
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1263
1405
|
module: CC_FILE,
|
|
1264
1406
|
method: 'silentRelogin',
|
|
1265
1407
|
});
|
|
@@ -1274,7 +1416,7 @@ describe('webex.cc', () => {
|
|
|
1274
1416
|
jest.spyOn(webex.cc.services.agent, 'reload').mockRejectedValue(error);
|
|
1275
1417
|
|
|
1276
1418
|
await expect(webex.cc['silentRelogin']()).rejects.toThrow(error);
|
|
1277
|
-
expect(LoggerProxy.
|
|
1419
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1278
1420
|
module: CC_FILE,
|
|
1279
1421
|
method: 'silentRelogin',
|
|
1280
1422
|
});
|
|
@@ -1316,7 +1458,7 @@ describe('webex.cc', () => {
|
|
|
1316
1458
|
|
|
1317
1459
|
await webex.cc['silentRelogin']();
|
|
1318
1460
|
|
|
1319
|
-
expect(LoggerProxy.
|
|
1461
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Starting silent relogin process', {
|
|
1320
1462
|
module: CC_FILE,
|
|
1321
1463
|
method: 'silentRelogin',
|
|
1322
1464
|
});
|
|
@@ -1500,6 +1642,27 @@ describe('webex.cc', () => {
|
|
|
1500
1642
|
});
|
|
1501
1643
|
});
|
|
1502
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
|
+
|
|
1503
1666
|
describe('uploadLogs', () => {
|
|
1504
1667
|
it('should upload logs successfully', async () => {
|
|
1505
1668
|
const uploadLogsMock = jest.spyOn(webex.cc.webexRequest, 'uploadLogs').mockResolvedValue({
|
|
@@ -1529,6 +1692,7 @@ describe('webex.cc', () => {
|
|
|
1529
1692
|
|
|
1530
1693
|
describe('unregister', () => {
|
|
1531
1694
|
let mockWebSocketManager;
|
|
1695
|
+
let mockRTDWebSocketManager;
|
|
1532
1696
|
let mercuryDisconnectSpy;
|
|
1533
1697
|
let deviceUnregisterSpy;
|
|
1534
1698
|
|
|
@@ -1545,8 +1709,15 @@ describe('webex.cc', () => {
|
|
|
1545
1709
|
off: jest.fn(),
|
|
1546
1710
|
on: jest.fn(),
|
|
1547
1711
|
};
|
|
1712
|
+
mockRTDWebSocketManager = {
|
|
1713
|
+
isSocketClosed: false,
|
|
1714
|
+
close: jest.fn(),
|
|
1715
|
+
off: jest.fn(),
|
|
1716
|
+
on: jest.fn(),
|
|
1717
|
+
};
|
|
1548
1718
|
|
|
1549
1719
|
webex.cc.services.webSocketManager = mockWebSocketManager;
|
|
1720
|
+
webex.cc.services.rtdWebSocketManager = mockRTDWebSocketManager;
|
|
1550
1721
|
|
|
1551
1722
|
webex.internal = webex.internal || {};
|
|
1552
1723
|
webex.internal.mercury = {
|
|
@@ -1580,6 +1751,10 @@ describe('webex.cc', () => {
|
|
|
1580
1751
|
TASK_EVENTS.TASK_HYDRATE,
|
|
1581
1752
|
expect.any(Function)
|
|
1582
1753
|
);
|
|
1754
|
+
expect(mockTaskManager.off).toHaveBeenCalledWith(
|
|
1755
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
1756
|
+
expect.any(Function)
|
|
1757
|
+
);
|
|
1583
1758
|
expect(mockWebSocketManager.off).toHaveBeenCalledWith('message', expect.any(Function));
|
|
1584
1759
|
expect(webex.cc.services.rtdWebSocketManager.off).toHaveBeenCalledWith(
|
|
1585
1760
|
'message',
|
|
@@ -1636,6 +1811,13 @@ describe('webex.cc', () => {
|
|
|
1636
1811
|
const [, hydrateCallback] = hydrateCalls[0];
|
|
1637
1812
|
expect(hydrateCallback).toBe(webex.cc['handleTaskHydrate']);
|
|
1638
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
|
+
|
|
1639
1821
|
const messageCalls = mockWebSocketManager.off.mock.calls.filter(([evt]) => evt === 'message');
|
|
1640
1822
|
expect(messageCalls).toHaveLength(1);
|
|
1641
1823
|
const [, messageCallback] = messageCalls[0];
|
|
@@ -1661,6 +1843,10 @@ describe('webex.cc', () => {
|
|
|
1661
1843
|
TASK_EVENTS.TASK_HYDRATE,
|
|
1662
1844
|
expect.any(Function)
|
|
1663
1845
|
);
|
|
1846
|
+
expect(mockTaskManager.off).toHaveBeenCalledWith(
|
|
1847
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
1848
|
+
expect.any(Function)
|
|
1849
|
+
);
|
|
1664
1850
|
expect(mockWebSocketManager.off).toHaveBeenCalledWith('message', expect.any(Function));
|
|
1665
1851
|
expect(webex.cc.services.connectionService.off).toHaveBeenCalledWith(
|
|
1666
1852
|
'connectionLost',
|
|
@@ -1670,6 +1856,7 @@ describe('webex.cc', () => {
|
|
|
1670
1856
|
expect(webex.internal.mercury.off).not.toHaveBeenCalled();
|
|
1671
1857
|
expect(mercuryDisconnectSpy).not.toHaveBeenCalled();
|
|
1672
1858
|
expect(deviceUnregisterSpy).not.toHaveBeenCalled();
|
|
1859
|
+
expect(mockRTDWebSocketManager.close).toHaveBeenCalledWith(false, 'Unregistering the SDK');
|
|
1673
1860
|
});
|
|
1674
1861
|
|
|
1675
1862
|
it('should skip internal mercury cleanup when loginVoiceOptions does not include BROWSER', async () => {
|
|
@@ -1687,6 +1874,7 @@ describe('webex.cc', () => {
|
|
|
1687
1874
|
expect(deviceUnregisterSpy).not.toHaveBeenCalled();
|
|
1688
1875
|
|
|
1689
1876
|
expect(mockWebSocketManager.close).toHaveBeenCalledWith(false, 'Unregistering the SDK');
|
|
1877
|
+
expect(mockRTDWebSocketManager.close).toHaveBeenCalledWith(false, 'Unregistering the SDK');
|
|
1690
1878
|
expect(webex.cc.agentConfig).toBeNull();
|
|
1691
1879
|
});
|
|
1692
1880
|
|
|
@@ -1704,6 +1892,10 @@ describe('webex.cc', () => {
|
|
|
1704
1892
|
TASK_EVENTS.TASK_HYDRATE,
|
|
1705
1893
|
expect.any(Function)
|
|
1706
1894
|
);
|
|
1895
|
+
expect(mockTaskManager.off).toHaveBeenCalledWith(
|
|
1896
|
+
TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE,
|
|
1897
|
+
expect.any(Function)
|
|
1898
|
+
);
|
|
1707
1899
|
|
|
1708
1900
|
expect(LoggerProxy.error).toHaveBeenCalledWith(`Error during deregister: ${mockError}`, {
|
|
1709
1901
|
module: CC_FILE,
|
|
@@ -1726,7 +1918,7 @@ describe('webex.cc', () => {
|
|
|
1726
1918
|
|
|
1727
1919
|
beforeEach(() => {
|
|
1728
1920
|
emitSpy = jest.spyOn(webex.cc, 'emit');
|
|
1729
|
-
messageCallback =
|
|
1921
|
+
messageCallback = webex.cc['handleWebsocketMessage'];
|
|
1730
1922
|
});
|
|
1731
1923
|
|
|
1732
1924
|
it('should emit AGENT_STATION_LOGIN_SUCCESS on CC_EVENTS.AGENT_STATION_LOGIN_SUCCESS with mapped payload', () => {
|
|
@@ -2320,4 +2512,132 @@ describe('webex.cc', () => {
|
|
|
2320
2512
|
expect(getErrorDetailsSpy).toHaveBeenCalledWith(error, 'acceptPreviewContact', CC_FILE);
|
|
2321
2513
|
});
|
|
2322
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
|
+
});
|
|
2323
2643
|
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import LoggerProxy from '../../../src/logger-proxy';
|
|
2
|
+
|
|
3
|
+
describe('LoggerProxy', () => {
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
// Reset between tests
|
|
6
|
+
(LoggerProxy as any).logger = undefined;
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('no-ops when logger is not initialized', () => {
|
|
10
|
+
expect(() => {
|
|
11
|
+
LoggerProxy.log('msg');
|
|
12
|
+
LoggerProxy.info('msg');
|
|
13
|
+
LoggerProxy.warn('msg');
|
|
14
|
+
LoggerProxy.trace('msg');
|
|
15
|
+
LoggerProxy.error('msg');
|
|
16
|
+
}).not.toThrow();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('routes calls to the injected logger with formatted context', () => {
|
|
20
|
+
const logger = {
|
|
21
|
+
log: jest.fn(),
|
|
22
|
+
info: jest.fn(),
|
|
23
|
+
warn: jest.fn(),
|
|
24
|
+
trace: jest.fn(),
|
|
25
|
+
error: jest.fn(),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
LoggerProxy.initialize(logger as any);
|
|
29
|
+
|
|
30
|
+
LoggerProxy.log('hello', {module: 'm', method: 'fn', interactionId: 'i', trackingId: 't'});
|
|
31
|
+
expect(logger.log).toHaveBeenCalled();
|
|
32
|
+
expect(String(logger.log.mock.calls[0][0])).toContain('module:m - method:fn');
|
|
33
|
+
expect(String(logger.log.mock.calls[0][0])).toContain('interactionId:i');
|
|
34
|
+
expect(String(logger.log.mock.calls[0][0])).toContain('trackingId:t');
|
|
35
|
+
|
|
36
|
+
LoggerProxy.info('hello', {module: 'm', method: 'fn'});
|
|
37
|
+
LoggerProxy.warn('hello', {module: 'm', method: 'fn'});
|
|
38
|
+
LoggerProxy.trace('hello', {module: 'm', method: 'fn'});
|
|
39
|
+
LoggerProxy.error('hello', {module: 'm', method: 'fn'});
|
|
40
|
+
expect(logger.info).toHaveBeenCalled();
|
|
41
|
+
expect(logger.warn).toHaveBeenCalled();
|
|
42
|
+
expect(logger.trace).toHaveBeenCalled();
|
|
43
|
+
expect(logger.error).toHaveBeenCalled();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('handles unserializable data and different error shapes', () => {
|
|
47
|
+
const logger = {
|
|
48
|
+
log: jest.fn(),
|
|
49
|
+
info: jest.fn(),
|
|
50
|
+
warn: jest.fn(),
|
|
51
|
+
trace: jest.fn(),
|
|
52
|
+
error: jest.fn(),
|
|
53
|
+
};
|
|
54
|
+
LoggerProxy.initialize(logger as any);
|
|
55
|
+
|
|
56
|
+
const circular: any = {};
|
|
57
|
+
circular.self = circular;
|
|
58
|
+
|
|
59
|
+
LoggerProxy.info('msg', {module: 'm', method: 'fn', data: circular, error: 'oops'});
|
|
60
|
+
expect(String(logger.info.mock.calls[0][0])).toContain('data:[object]');
|
|
61
|
+
expect(String(logger.info.mock.calls[0][0])).toContain('error:oops');
|
|
62
|
+
|
|
63
|
+
const err = new Error('boom');
|
|
64
|
+
LoggerProxy.error('msg', {module: 'm', method: 'fn', error: err});
|
|
65
|
+
const errorLine = String(logger.error.mock.calls[0][0]);
|
|
66
|
+
expect(errorLine).toContain('error:Error:boom');
|
|
67
|
+
expect(errorLine).toContain('stack:');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|