@webex/contact-center 3.10.0-next.8 → 3.10.0-set-bitrate.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cc.js +2 -1
- package/dist/cc.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/logger-proxy.js.map +1 -1
- package/dist/metrics/MetricsManager.js +2 -1
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +12 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +4 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +2 -3
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/EntryPoint.js +2 -3
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +2 -3
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/WebCallingService.js +1 -1
- package/dist/services/WebCallingService.js.map +1 -1
- package/dist/services/agent/index.js +1 -2
- package/dist/services/agent/index.js.map +1 -1
- package/dist/services/agent/types.js +10 -0
- package/dist/services/agent/types.js.map +1 -1
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +1 -1
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/GlobalTypes.js.map +1 -1
- package/dist/services/core/Utils.js +2 -3
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/WebexRequest.js +1 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +2 -3
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/constants.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +1 -2
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/connection-service.js +1 -1
- package/dist/services/core/websocket/connection-service.js.map +1 -1
- package/dist/services/core/websocket/keepalive.worker.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/AutoWrapup.js +1 -1
- package/dist/services/task/AutoWrapup.js.map +1 -1
- package/dist/services/task/TaskManager.js +121 -33
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +90 -1
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +3 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +0 -2
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/index.js +1 -1
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +375 -0
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/metrics/constants.d.ts +4 -0
- package/dist/types/services/task/TaskUtils.d.ts +42 -0
- package/dist/types/services/task/constants.d.ts +2 -0
- package/dist/types/services/task/types.d.ts +32 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +1 -1
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex-config.js.map +1 -1
- package/dist/webex.js +2 -2
- package/dist/webex.js.map +1 -1
- package/package.json +9 -9
- package/src/cc.ts +1 -0
- package/src/metrics/behavioral-events.ts +12 -0
- package/src/metrics/constants.ts +4 -0
- package/src/services/task/TaskManager.ts +135 -22
- package/src/services/task/TaskUtils.ts +109 -1
- package/src/services/task/constants.ts +2 -0
- package/src/services/task/types.ts +34 -0
- package/test/unit/spec/cc.ts +1 -0
- package/test/unit/spec/metrics/behavioral-events.ts +14 -0
- package/test/unit/spec/services/task/TaskManager.ts +378 -4
- package/test/unit/spec/services/task/TaskUtils.ts +305 -3
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
checkParticipantNotInInteraction,
|
|
2
3
|
getIsConferenceInProgress,
|
|
3
4
|
isParticipantInMainInteraction,
|
|
4
|
-
isPrimary,
|
|
5
|
-
|
|
5
|
+
isPrimary,
|
|
6
|
+
isAutoAnswerEnabled,
|
|
7
|
+
isWebRTCCall,
|
|
8
|
+
isDigitalOutbound,
|
|
9
|
+
hasAgentInitiatedOutdial,
|
|
10
|
+
shouldAutoAnswerTask,
|
|
11
|
+
} from '../../../../../src/services/task/TaskUtils';
|
|
12
|
+
import {ITask, Interaction, TaskData} from '../../../../../src/services/task/types';
|
|
13
|
+
import {LoginOption} from '../../../../../src/types';
|
|
6
14
|
|
|
7
15
|
describe('TaskUtils', () => {
|
|
8
16
|
let mockTask: ITask;
|
|
@@ -128,4 +136,298 @@ describe('TaskUtils', () => {
|
|
|
128
136
|
expect(getIsConferenceInProgress(mockTask.data)).toBe(false);
|
|
129
137
|
});
|
|
130
138
|
});
|
|
139
|
+
|
|
140
|
+
describe('Auto-Answer Helper Functions', () => {
|
|
141
|
+
let mockInteraction: Interaction;
|
|
142
|
+
|
|
143
|
+
beforeEach(() => {
|
|
144
|
+
mockInteraction = {
|
|
145
|
+
interactionId: 'interaction-123',
|
|
146
|
+
mediaType: 'telephony',
|
|
147
|
+
mediaChannel: 'telephony',
|
|
148
|
+
participants: {
|
|
149
|
+
[mockAgentId]: {
|
|
150
|
+
id: mockAgentId,
|
|
151
|
+
pType: 'Agent',
|
|
152
|
+
autoAnswerEnabled: false,
|
|
153
|
+
hasJoined: false,
|
|
154
|
+
hasLeft: false,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
owner: mockAgentId,
|
|
158
|
+
contactDirection: {type: 'INBOUND'},
|
|
159
|
+
outboundType: null,
|
|
160
|
+
callProcessingDetails: {
|
|
161
|
+
QMgrName: 'aqm',
|
|
162
|
+
taskToBeSelfServiced: 'false',
|
|
163
|
+
ani: '+1234567890',
|
|
164
|
+
displayAni: '+1234567890',
|
|
165
|
+
dnis: '+0987654321',
|
|
166
|
+
tenantId: 'tenant-123',
|
|
167
|
+
QueueId: 'queue-123',
|
|
168
|
+
vteamId: 'vteam-123',
|
|
169
|
+
customerName: 'Test Customer',
|
|
170
|
+
virtualTeamName: 'Test Team',
|
|
171
|
+
ronaTimeout: '30',
|
|
172
|
+
category: 'Support',
|
|
173
|
+
reason: 'General',
|
|
174
|
+
sourceNumber: '+1234567890',
|
|
175
|
+
sourcePage: 'web',
|
|
176
|
+
appUser: 'test-app',
|
|
177
|
+
customerNumber: '+1234567890',
|
|
178
|
+
reasonCode: '100',
|
|
179
|
+
IvrPath: '/ivr/path',
|
|
180
|
+
pathId: 'path-123',
|
|
181
|
+
fromAddress: 'customer@example.com',
|
|
182
|
+
},
|
|
183
|
+
previousVTeams: [],
|
|
184
|
+
state: 'new',
|
|
185
|
+
currentVTeam: 'vteam-123',
|
|
186
|
+
isFcManaged: false,
|
|
187
|
+
isTerminated: false,
|
|
188
|
+
orgId: 'org-123',
|
|
189
|
+
createdTimestamp: Date.now(),
|
|
190
|
+
media: {},
|
|
191
|
+
} as any;
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe('isAutoAnswerEnabled', () => {
|
|
195
|
+
it('should return true when autoAnswerEnabled is true', () => {
|
|
196
|
+
mockInteraction.participants[mockAgentId].autoAnswerEnabled = true;
|
|
197
|
+
expect(isAutoAnswerEnabled(mockInteraction, mockAgentId)).toBe(true);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should return false when autoAnswerEnabled is false', () => {
|
|
201
|
+
mockInteraction.participants[mockAgentId].autoAnswerEnabled = false;
|
|
202
|
+
expect(isAutoAnswerEnabled(mockInteraction, mockAgentId)).toBe(false);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should return false when autoAnswerEnabled is not set', () => {
|
|
206
|
+
delete mockInteraction.participants[mockAgentId].autoAnswerEnabled;
|
|
207
|
+
expect(isAutoAnswerEnabled(mockInteraction, mockAgentId)).toBe(false);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should return false when participant does not exist', () => {
|
|
211
|
+
expect(isAutoAnswerEnabled(mockInteraction, 'non-existent-agent')).toBe(false);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('isWebRTCCall', () => {
|
|
216
|
+
it('should return true for BROWSER login with telephony media type and webRTC enabled', () => {
|
|
217
|
+
expect(isWebRTCCall(mockInteraction, LoginOption.BROWSER, true)).toBe(true);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('should return false when webRTC is disabled', () => {
|
|
221
|
+
expect(isWebRTCCall(mockInteraction, LoginOption.BROWSER, false)).toBe(false);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should return false for AGENT_DN login', () => {
|
|
225
|
+
expect(isWebRTCCall(mockInteraction, LoginOption.AGENT_DN, true)).toBe(false);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should return false for EXTENSION login', () => {
|
|
229
|
+
expect(isWebRTCCall(mockInteraction, LoginOption.EXTENSION, true)).toBe(false);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should return false for BROWSER login with non-telephony media type', () => {
|
|
233
|
+
mockInteraction.mediaType = 'email';
|
|
234
|
+
expect(isWebRTCCall(mockInteraction, LoginOption.BROWSER, true)).toBe(false);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe('isDigitalOutbound', () => {
|
|
239
|
+
it('should return true for email outdial', () => {
|
|
240
|
+
mockInteraction.contactDirection = {type: 'OUTBOUND'};
|
|
241
|
+
mockInteraction.outboundType = 'OUTDIAL';
|
|
242
|
+
mockInteraction.mediaChannel = 'email';
|
|
243
|
+
expect(isDigitalOutbound(mockInteraction)).toBe(true);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should return true for SMS outdial', () => {
|
|
247
|
+
mockInteraction.contactDirection = {type: 'OUTBOUND'};
|
|
248
|
+
mockInteraction.outboundType = 'OUTDIAL';
|
|
249
|
+
mockInteraction.mediaChannel = 'sms';
|
|
250
|
+
expect(isDigitalOutbound(mockInteraction)).toBe(true);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should return false for telephony outdial', () => {
|
|
254
|
+
mockInteraction.contactDirection = {type: 'OUTBOUND'};
|
|
255
|
+
mockInteraction.outboundType = 'OUTDIAL';
|
|
256
|
+
mockInteraction.mediaChannel = 'telephony';
|
|
257
|
+
expect(isDigitalOutbound(mockInteraction)).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('should return false for inbound email', () => {
|
|
261
|
+
mockInteraction.contactDirection = {type: 'INBOUND'};
|
|
262
|
+
mockInteraction.mediaChannel = 'email';
|
|
263
|
+
expect(isDigitalOutbound(mockInteraction)).toBe(false);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('should return false when outboundType is not OUTDIAL', () => {
|
|
267
|
+
mockInteraction.contactDirection = {type: 'OUTBOUND'};
|
|
268
|
+
mockInteraction.outboundType = 'CALLBACK';
|
|
269
|
+
mockInteraction.mediaChannel = 'email';
|
|
270
|
+
expect(isDigitalOutbound(mockInteraction)).toBe(false);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
describe('hasAgentInitiatedOutdial', () => {
|
|
275
|
+
beforeEach(() => {
|
|
276
|
+
mockInteraction.contactDirection = {type: 'OUTBOUND'};
|
|
277
|
+
mockInteraction.outboundType = 'OUTDIAL';
|
|
278
|
+
mockInteraction.owner = mockAgentId;
|
|
279
|
+
mockInteraction.callProcessingDetails.outdialAgentId = mockAgentId;
|
|
280
|
+
mockInteraction.callProcessingDetails.BLIND_TRANSFER_IN_PROGRESS = false;
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('should return true for agent-initiated outdial', () => {
|
|
284
|
+
expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(true);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should return false when not outbound', () => {
|
|
288
|
+
mockInteraction.contactDirection = {type: 'INBOUND'};
|
|
289
|
+
expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('should return false when not OUTDIAL type', () => {
|
|
293
|
+
mockInteraction.outboundType = 'CALLBACK';
|
|
294
|
+
expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('should return false when outdialAgentId does not match', () => {
|
|
298
|
+
mockInteraction.callProcessingDetails.outdialAgentId = mockOtherAgentId;
|
|
299
|
+
expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('should return false when owner does not match', () => {
|
|
303
|
+
mockInteraction.owner = mockOtherAgentId;
|
|
304
|
+
expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('should return false when blind transfer is in progress', () => {
|
|
308
|
+
mockInteraction.callProcessingDetails.BLIND_TRANSFER_IN_PROGRESS = true;
|
|
309
|
+
expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe('shouldAutoAnswerTask', () => {
|
|
314
|
+
let mockTaskData: TaskData;
|
|
315
|
+
|
|
316
|
+
beforeEach(() => {
|
|
317
|
+
mockTaskData = {
|
|
318
|
+
interactionId: 'interaction-123',
|
|
319
|
+
agentId: mockAgentId,
|
|
320
|
+
interaction: mockInteraction,
|
|
321
|
+
} as any;
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
describe('WebRTC scenarios', () => {
|
|
325
|
+
beforeEach(() => {
|
|
326
|
+
mockInteraction.mediaType = 'telephony';
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('should return true when auto-answer is enabled for WebRTC call', () => {
|
|
330
|
+
mockInteraction.participants[mockAgentId].autoAnswerEnabled = true;
|
|
331
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
|
|
332
|
+
true
|
|
333
|
+
);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('should return true for agent-initiated WebRTC outdial', () => {
|
|
337
|
+
mockInteraction.contactDirection = {type: 'OUTBOUND'};
|
|
338
|
+
mockInteraction.outboundType = 'OUTDIAL';
|
|
339
|
+
mockInteraction.owner = mockAgentId;
|
|
340
|
+
mockInteraction.callProcessingDetails.outdialAgentId = mockAgentId;
|
|
341
|
+
mockInteraction.callProcessingDetails.BLIND_TRANSFER_IN_PROGRESS = false;
|
|
342
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
|
|
343
|
+
true
|
|
344
|
+
);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('should return false for WebRTC call without auto-answer or outdial', () => {
|
|
348
|
+
mockInteraction.participants[mockAgentId].autoAnswerEnabled = false;
|
|
349
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
|
|
350
|
+
false
|
|
351
|
+
);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it('should return false when webRTC is disabled', () => {
|
|
355
|
+
mockInteraction.participants[mockAgentId].autoAnswerEnabled = true;
|
|
356
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, false)).toBe(
|
|
357
|
+
false
|
|
358
|
+
);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it('should return false for non-BROWSER login', () => {
|
|
362
|
+
mockInteraction.participants[mockAgentId].autoAnswerEnabled = true;
|
|
363
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.AGENT_DN, true)).toBe(
|
|
364
|
+
false
|
|
365
|
+
);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe('Digital outbound scenarios', () => {
|
|
370
|
+
beforeEach(() => {
|
|
371
|
+
mockInteraction.contactDirection = {type: 'OUTBOUND'};
|
|
372
|
+
mockInteraction.outboundType = 'OUTDIAL';
|
|
373
|
+
mockInteraction.owner = mockAgentId;
|
|
374
|
+
mockInteraction.callProcessingDetails.outdialAgentId = mockAgentId;
|
|
375
|
+
mockInteraction.previousVTeams = [];
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('should return true for agent-initiated email outdial', () => {
|
|
379
|
+
mockInteraction.mediaType = 'email';
|
|
380
|
+
mockInteraction.mediaChannel = 'email';
|
|
381
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
|
|
382
|
+
true
|
|
383
|
+
);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('should return true for agent-initiated SMS outdial', () => {
|
|
387
|
+
mockInteraction.mediaType = 'sms';
|
|
388
|
+
mockInteraction.mediaChannel = 'sms';
|
|
389
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
|
|
390
|
+
true
|
|
391
|
+
);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it('should return false when digital outbound has previous vteams', () => {
|
|
395
|
+
mockInteraction.mediaType = 'email';
|
|
396
|
+
mockInteraction.mediaChannel = 'email';
|
|
397
|
+
mockInteraction.previousVTeams = ['vteam-1'];
|
|
398
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
|
|
399
|
+
false
|
|
400
|
+
);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it('should return false when digital outbound is not agent-initiated', () => {
|
|
404
|
+
mockInteraction.mediaType = 'email';
|
|
405
|
+
mockInteraction.mediaChannel = 'email';
|
|
406
|
+
mockInteraction.owner = mockOtherAgentId;
|
|
407
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
|
|
408
|
+
false
|
|
409
|
+
);
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
describe('Edge cases', () => {
|
|
414
|
+
it('should return false when interaction is null', () => {
|
|
415
|
+
mockTaskData.interaction = null as any;
|
|
416
|
+
expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
|
|
417
|
+
false
|
|
418
|
+
);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('should return false when agentId is null', () => {
|
|
422
|
+
expect(shouldAutoAnswerTask(mockTaskData, null as any, LoginOption.BROWSER, true)).toBe(
|
|
423
|
+
false
|
|
424
|
+
);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it('should return false when agentId is empty string', () => {
|
|
428
|
+
expect(shouldAutoAnswerTask(mockTaskData, '', LoginOption.BROWSER, true)).toBe(false);
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
});
|
|
131
433
|
});
|