@webex/contact-center 3.8.1 → 3.9.0-next.10
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 +105 -63
- package/dist/cc.js.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/logger-proxy.js +24 -1
- package/dist/logger-proxy.js.map +1 -1
- package/dist/metrics/MetricsManager.js +1 -1
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +51 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +12 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +271 -0
- package/dist/services/AddressBook.js.map +1 -0
- package/dist/services/EntryPoint.js +227 -0
- package/dist/services/EntryPoint.js.map +1 -0
- package/dist/services/Queue.js +261 -0
- package/dist/services/Queue.js.map +1 -0
- package/dist/services/config/constants.js +24 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +1 -43
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +0 -5
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/GlobalTypes.js.map +1 -1
- package/dist/services/core/Utils.js +121 -2
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +0 -4
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +0 -4
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/task/TaskManager.js +1 -0
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/index.js +145 -71
- package/dist/services/task/index.js.map +1 -1
- package/dist/types/cc.d.ts +77 -43
- package/dist/types/index.d.ts +8 -3
- package/dist/types/metrics/constants.d.ts +7 -0
- package/dist/types/services/AddressBook.d.ts +74 -0
- package/dist/types/services/EntryPoint.d.ts +67 -0
- package/dist/types/services/Queue.d.ts +76 -0
- package/dist/types/services/config/constants.d.ts +23 -1
- package/dist/types/services/config/index.d.ts +1 -14
- package/dist/types/services/config/types.d.ts +0 -64
- package/dist/types/services/core/GlobalTypes.d.ts +25 -0
- package/dist/types/services/core/Utils.d.ts +27 -1
- package/dist/types/services/task/index.d.ts +1 -1
- package/dist/types/types.d.ts +162 -0
- package/dist/types/utils/PageCache.d.ts +173 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +192 -0
- package/dist/utils/PageCache.js.map +1 -0
- package/dist/webex.js +1 -1
- package/package.json +10 -10
- package/src/cc.ts +121 -81
- package/src/index.ts +19 -3
- package/src/logger-proxy.ts +24 -1
- package/src/metrics/MetricsManager.ts +1 -1
- package/src/metrics/behavioral-events.ts +54 -0
- package/src/metrics/constants.ts +15 -0
- package/src/services/AddressBook.ts +291 -0
- package/src/services/EntryPoint.ts +241 -0
- package/src/services/Queue.ts +277 -0
- package/src/services/config/constants.ts +26 -2
- package/src/services/config/index.ts +1 -55
- package/src/services/config/types.ts +0 -65
- package/src/services/core/GlobalTypes.ts +27 -0
- package/src/services/core/Utils.ts +155 -1
- package/src/services/core/aqm-reqs.ts +0 -5
- package/src/services/core/websocket/WebSocketManager.ts +0 -4
- package/src/services/task/TaskManager.ts +1 -0
- package/src/services/task/index.ts +172 -56
- package/src/types.ts +180 -0
- package/src/utils/PageCache.ts +252 -0
- package/test/unit/spec/cc.ts +30 -82
- package/test/unit/spec/metrics/MetricsManager.ts +0 -1
- package/test/unit/spec/metrics/behavioral-events.ts +14 -0
- package/test/unit/spec/services/AddressBook.ts +332 -0
- package/test/unit/spec/services/EntryPoint.ts +259 -0
- package/test/unit/spec/services/Queue.ts +323 -0
- package/test/unit/spec/services/config/index.ts +0 -71
- package/test/unit/spec/services/core/Utils.ts +50 -0
- package/test/unit/spec/services/core/aqm-reqs.ts +1 -3
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +0 -4
- package/test/unit/spec/services/task/TaskManager.ts +8 -1
- package/test/unit/spec/services/task/index.ts +226 -122
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import Queue from '../../../../src/services/Queue';
|
|
2
|
+
import {HTTP_METHODS, WebexSDK, IHttpResponse} from '../../../../src/types';
|
|
3
|
+
import {METRIC_EVENT_NAMES} from '../../../../src/metrics/constants';
|
|
4
|
+
import WebexRequest from '../../../../src/services/core/WebexRequest';
|
|
5
|
+
import MetricsManager from '../../../../src/metrics/MetricsManager';
|
|
6
|
+
import LoggerProxy from '../../../../src/logger-proxy';
|
|
7
|
+
|
|
8
|
+
jest.mock('../../../../src/metrics/MetricsManager');
|
|
9
|
+
jest.mock('../../../../src/logger-proxy');
|
|
10
|
+
|
|
11
|
+
describe('Queue', () => {
|
|
12
|
+
let queueAPI: Queue;
|
|
13
|
+
let mockWebex: WebexSDK;
|
|
14
|
+
let mockMetricsManager: jest.Mocked<MetricsManager>;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
jest.clearAllMocks();
|
|
18
|
+
|
|
19
|
+
(WebexRequest as any).instance = undefined;
|
|
20
|
+
mockWebex = {
|
|
21
|
+
credentials: {
|
|
22
|
+
getOrgId: jest.fn().mockReturnValue('test-org-id'),
|
|
23
|
+
},
|
|
24
|
+
request: jest.fn(),
|
|
25
|
+
internal: {
|
|
26
|
+
newMetrics: {
|
|
27
|
+
submitBehavioralEvent: jest.fn(),
|
|
28
|
+
submitOperationalEvent: jest.fn(),
|
|
29
|
+
submitBusinessEvent: jest.fn(),
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
ready: true,
|
|
33
|
+
once: jest.fn(),
|
|
34
|
+
} as unknown as WebexSDK;
|
|
35
|
+
|
|
36
|
+
mockMetricsManager = {
|
|
37
|
+
trackEvent: jest.fn(),
|
|
38
|
+
timeEvent: jest.fn(),
|
|
39
|
+
} as unknown as jest.Mocked<MetricsManager>;
|
|
40
|
+
(MetricsManager.getInstance as jest.Mock).mockReturnValue(mockMetricsManager);
|
|
41
|
+
|
|
42
|
+
queueAPI = new Queue(mockWebex);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('constructor', () => {
|
|
46
|
+
it('should initialize with all required dependencies', () => {
|
|
47
|
+
expect(WebexRequest.getInstance({webex: mockWebex})).toBeDefined();
|
|
48
|
+
expect(MetricsManager.getInstance).toHaveBeenCalledWith({webex: mockWebex});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('getQueues', () => {
|
|
53
|
+
const mockQueues = [
|
|
54
|
+
{
|
|
55
|
+
id: 'queue1',
|
|
56
|
+
name: 'Support Queue',
|
|
57
|
+
queueType: 'INBOUND' as const,
|
|
58
|
+
channelType: 'TELEPHONY' as const,
|
|
59
|
+
active: true,
|
|
60
|
+
organizationId: 'test-org-id',
|
|
61
|
+
checkAgentAvailability: true,
|
|
62
|
+
serviceLevelThreshold: 300,
|
|
63
|
+
maxActiveContacts: 10,
|
|
64
|
+
maxTimeInQueue: 3600,
|
|
65
|
+
defaultMusicInQueueMediaFileId: 'media123',
|
|
66
|
+
monitoringPermitted: true,
|
|
67
|
+
parkingPermitted: true,
|
|
68
|
+
recordingPermitted: true,
|
|
69
|
+
recordingAllCallsPermitted: false,
|
|
70
|
+
pauseRecordingPermitted: true,
|
|
71
|
+
controlFlowScriptUrl: 'https://example.com/script',
|
|
72
|
+
ivrRequeueUrl: 'https://example.com/requeue',
|
|
73
|
+
routingType: 'LONGEST_AVAILABLE_AGENT' as const,
|
|
74
|
+
queueRoutingType: 'TEAM_BASED' as const,
|
|
75
|
+
callDistributionGroups: [
|
|
76
|
+
{
|
|
77
|
+
agentGroups: [{teamId: 'team1'}],
|
|
78
|
+
order: 1,
|
|
79
|
+
duration: 30
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'queue2',
|
|
85
|
+
name: 'Sales Queue',
|
|
86
|
+
queueType: 'INBOUND' as const,
|
|
87
|
+
channelType: 'CHAT' as const,
|
|
88
|
+
active: true,
|
|
89
|
+
organizationId: 'test-org-id',
|
|
90
|
+
checkAgentAvailability: true,
|
|
91
|
+
serviceLevelThreshold: 300,
|
|
92
|
+
maxActiveContacts: 5,
|
|
93
|
+
maxTimeInQueue: 1800,
|
|
94
|
+
defaultMusicInQueueMediaFileId: 'media456',
|
|
95
|
+
monitoringPermitted: true,
|
|
96
|
+
parkingPermitted: false,
|
|
97
|
+
recordingPermitted: false,
|
|
98
|
+
recordingAllCallsPermitted: false,
|
|
99
|
+
pauseRecordingPermitted: false,
|
|
100
|
+
controlFlowScriptUrl: 'https://example.com/script2',
|
|
101
|
+
ivrRequeueUrl: 'https://example.com/requeue2',
|
|
102
|
+
routingType: 'SKILLS_BASED' as const,
|
|
103
|
+
queueRoutingType: 'SKILL_BASED' as const,
|
|
104
|
+
callDistributionGroups: [
|
|
105
|
+
{
|
|
106
|
+
agentGroups: [{teamId: 'team2'}],
|
|
107
|
+
order: 1,
|
|
108
|
+
duration: 60
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const mockResponse: IHttpResponse = {
|
|
115
|
+
statusCode: 200,
|
|
116
|
+
method: 'GET',
|
|
117
|
+
url: '/organization/test-org-id/v2/contact-service-queue',
|
|
118
|
+
headers: {} as any,
|
|
119
|
+
body: {
|
|
120
|
+
data: mockQueues,
|
|
121
|
+
meta: {
|
|
122
|
+
page: 0,
|
|
123
|
+
pageSize: 100,
|
|
124
|
+
totalPages: 1,
|
|
125
|
+
totalRecords: 2,
|
|
126
|
+
orgid: 'test-org-id',
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
beforeEach(() => {
|
|
132
|
+
jest.spyOn(Date, 'now').mockReturnValue(1000);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
afterEach(() => {
|
|
136
|
+
jest.restoreAllMocks();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should fetch contact service queues successfully with default parameters', async () => {
|
|
140
|
+
(mockWebex.request as jest.Mock).mockResolvedValue(mockResponse);
|
|
141
|
+
|
|
142
|
+
const result = await queueAPI.getQueues();
|
|
143
|
+
|
|
144
|
+
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
145
|
+
service: 'wcc-api-gateway',
|
|
146
|
+
resource: '/organization/test-org-id/v2/contact-service-queue?page=0&pageSize=100',
|
|
147
|
+
method: HTTP_METHODS.GET,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
expect(result).toEqual(mockResponse.body);
|
|
151
|
+
expect(mockMetricsManager.timeEvent).toHaveBeenCalledWith(METRIC_EVENT_NAMES.QUEUE_FETCH_SUCCESS);
|
|
152
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
153
|
+
METRIC_EVENT_NAMES.QUEUE_FETCH_SUCCESS,
|
|
154
|
+
{
|
|
155
|
+
orgId: 'test-org-id',
|
|
156
|
+
statusCode: 200,
|
|
157
|
+
recordCount: 2,
|
|
158
|
+
totalRecords: 2,
|
|
159
|
+
isSearchRequest: false,
|
|
160
|
+
isFirstPage: true,
|
|
161
|
+
},
|
|
162
|
+
['behavioral', 'operational']
|
|
163
|
+
);
|
|
164
|
+
expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching contact service queues', {
|
|
165
|
+
module: 'Queue',
|
|
166
|
+
method: 'getQueues',
|
|
167
|
+
data: expect.objectContaining({
|
|
168
|
+
orgId: 'test-org-id',
|
|
169
|
+
page: 0,
|
|
170
|
+
pageSize: 100,
|
|
171
|
+
isSearchRequest: false,
|
|
172
|
+
}),
|
|
173
|
+
});
|
|
174
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Making API request to fetch contact service queues', {
|
|
175
|
+
module: 'Queue',
|
|
176
|
+
method: 'getQueues',
|
|
177
|
+
data: expect.objectContaining({
|
|
178
|
+
resource: '/organization/test-org-id/v2/contact-service-queue?page=0&pageSize=100',
|
|
179
|
+
service: 'wcc-api-gateway',
|
|
180
|
+
}),
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should fetch queues with custom parameters', async () => {
|
|
185
|
+
(mockWebex.request as jest.Mock).mockResolvedValue(mockResponse);
|
|
186
|
+
|
|
187
|
+
const params = {
|
|
188
|
+
page: 1,
|
|
189
|
+
pageSize: 25,
|
|
190
|
+
search: 'support',
|
|
191
|
+
filter: 'queueType=="INBOUND"',
|
|
192
|
+
attributes: 'id,name,queueType',
|
|
193
|
+
sortBy: 'name',
|
|
194
|
+
sortOrder: 'desc' as const,
|
|
195
|
+
desktopProfileFilter: true,
|
|
196
|
+
provisioningView: false,
|
|
197
|
+
singleObjectResponse: true,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
await queueAPI.getQueues(params);
|
|
201
|
+
|
|
202
|
+
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
203
|
+
service: 'wcc-api-gateway',
|
|
204
|
+
resource: '/organization/test-org-id/v2/contact-service-queue?page=1&pageSize=25&filter=queueType%3D%3D%22INBOUND%22&attributes=id%2Cname%2CqueueType&search=support&sortBy=name&sortOrder=desc&desktopProfileFilter=true&provisioningView=false&singleObjectResponse=true',
|
|
205
|
+
method: HTTP_METHODS.GET,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
209
|
+
METRIC_EVENT_NAMES.QUEUE_FETCH_SUCCESS,
|
|
210
|
+
expect.objectContaining({
|
|
211
|
+
isSearchRequest: true,
|
|
212
|
+
isFirstPage: false,
|
|
213
|
+
}),
|
|
214
|
+
['behavioral', 'operational']
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should handle API errors and track metrics', async () => {
|
|
219
|
+
(mockWebex.request as jest.Mock).mockRejectedValue(new Error('Internal Server Error'));
|
|
220
|
+
|
|
221
|
+
await expect(queueAPI.getQueues()).rejects.toThrow('Internal Server Error');
|
|
222
|
+
|
|
223
|
+
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
224
|
+
service: 'wcc-api-gateway',
|
|
225
|
+
resource: '/organization/test-org-id/v2/contact-service-queue?page=0&pageSize=100',
|
|
226
|
+
method: HTTP_METHODS.GET,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
230
|
+
METRIC_EVENT_NAMES.QUEUE_FETCH_FAILED,
|
|
231
|
+
{
|
|
232
|
+
orgId: 'test-org-id',
|
|
233
|
+
error: 'Internal Server Error',
|
|
234
|
+
isSearchRequest: false,
|
|
235
|
+
page: 0,
|
|
236
|
+
pageSize: 100,
|
|
237
|
+
},
|
|
238
|
+
['behavioral', 'operational']
|
|
239
|
+
);
|
|
240
|
+
expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to fetch contact service queues', {
|
|
241
|
+
module: 'Queue',
|
|
242
|
+
method: 'getQueues',
|
|
243
|
+
data: expect.objectContaining({
|
|
244
|
+
orgId: 'test-org-id',
|
|
245
|
+
error: 'Internal Server Error',
|
|
246
|
+
isSearchRequest: false,
|
|
247
|
+
page: 0,
|
|
248
|
+
pageSize: 100,
|
|
249
|
+
}),
|
|
250
|
+
error: expect.any(Error),
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
it('should not track metrics for subsequent pages in simple pagination', async () => {
|
|
257
|
+
(mockWebex.request as jest.Mock).mockResolvedValue(mockResponse);
|
|
258
|
+
|
|
259
|
+
const result = await queueAPI.getQueues({page: 2});
|
|
260
|
+
expect(result).toEqual(mockResponse.body);
|
|
261
|
+
|
|
262
|
+
expect(mockMetricsManager.trackEvent).not.toHaveBeenCalled();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('should track metrics for search requests on any page', async () => {
|
|
266
|
+
(mockWebex.request as jest.Mock).mockResolvedValue(mockResponse);
|
|
267
|
+
|
|
268
|
+
const result2 = await queueAPI.getQueues({page: 2, search: 'test'});
|
|
269
|
+
expect(result2).toEqual(mockResponse.body);
|
|
270
|
+
|
|
271
|
+
expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
|
|
272
|
+
METRIC_EVENT_NAMES.QUEUE_FETCH_SUCCESS,
|
|
273
|
+
expect.objectContaining({
|
|
274
|
+
isSearchRequest: true,
|
|
275
|
+
isFirstPage: false,
|
|
276
|
+
}),
|
|
277
|
+
['behavioral', 'operational']
|
|
278
|
+
);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('should call API when requested page is not cached (cache miss)', async () => {
|
|
282
|
+
(mockWebex.request as jest.Mock).mockResolvedValueOnce(mockResponse);
|
|
283
|
+
|
|
284
|
+
await queueAPI.getQueues({page: 0});
|
|
285
|
+
|
|
286
|
+
(mockWebex.request as jest.Mock).mockResolvedValueOnce({
|
|
287
|
+
...mockResponse,
|
|
288
|
+
body: {
|
|
289
|
+
data: mockQueues,
|
|
290
|
+
meta: {
|
|
291
|
+
page: 1,
|
|
292
|
+
pageSize: 100,
|
|
293
|
+
totalPages: 2,
|
|
294
|
+
totalRecords: 2,
|
|
295
|
+
orgid: 'test-org-id',
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const callsBefore = (mockWebex.request as jest.Mock).mock.calls.length;
|
|
301
|
+
(LoggerProxy.log as jest.Mock).mockClear();
|
|
302
|
+
|
|
303
|
+
const result = await queueAPI.getQueues({page: 1});
|
|
304
|
+
const callsAfter = (mockWebex.request as jest.Mock).mock.calls.length;
|
|
305
|
+
|
|
306
|
+
expect(callsAfter).toBe(callsBefore + 1);
|
|
307
|
+
expect(result.meta.page).toBe(1);
|
|
308
|
+
expect(mockWebex.request).toHaveBeenCalledWith({
|
|
309
|
+
service: 'wcc-api-gateway',
|
|
310
|
+
resource: '/organization/test-org-id/v2/contact-service-queue?page=1&pageSize=100',
|
|
311
|
+
method: HTTP_METHODS.GET,
|
|
312
|
+
});
|
|
313
|
+
expect(LoggerProxy.log).toHaveBeenCalledWith('Making API request to fetch contact service queues', {
|
|
314
|
+
module: 'Queue',
|
|
315
|
+
method: 'getQueues',
|
|
316
|
+
data: expect.objectContaining({
|
|
317
|
+
resource: '/organization/test-org-id/v2/contact-service-queue?page=1&pageSize=100',
|
|
318
|
+
service: 'wcc-api-gateway',
|
|
319
|
+
}),
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
});
|
|
@@ -961,75 +961,4 @@ describe('AgentConfigService', () => {
|
|
|
961
961
|
);
|
|
962
962
|
});
|
|
963
963
|
});
|
|
964
|
-
|
|
965
|
-
describe('getQueues', () => {
|
|
966
|
-
const mockQueues = [
|
|
967
|
-
{id: 'queue1', name: 'Queue 1'},
|
|
968
|
-
{id: 'queue2', name: 'Queue 2'},
|
|
969
|
-
];
|
|
970
|
-
|
|
971
|
-
const mockError = new Error('API call failed');
|
|
972
|
-
|
|
973
|
-
beforeEach(() => {
|
|
974
|
-
jest.clearAllMocks();
|
|
975
|
-
});
|
|
976
|
-
|
|
977
|
-
it('should return a list of queues successfully', async () => {
|
|
978
|
-
const mockResponse = {statusCode: 200, body: {data: mockQueues}};
|
|
979
|
-
mockWebexRequest.request.mockResolvedValue(mockResponse);
|
|
980
|
-
|
|
981
|
-
const result = await agentConfigService.getQueues(mockOrgId, 0, 100, 'queue', 'id==someid');
|
|
982
|
-
|
|
983
|
-
expect(mockWebexRequest.request).toHaveBeenCalledWith({
|
|
984
|
-
service: mockWccAPIURL,
|
|
985
|
-
resource: `organization/${mockOrgId}/v2/contact-service-queue?page=0&pageSize=100&desktopProfileFilter=true&search=queue&filter=id==someid`,
|
|
986
|
-
method: 'GET',
|
|
987
|
-
});
|
|
988
|
-
expect(result).toEqual(mockQueues);
|
|
989
|
-
|
|
990
|
-
expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching queue list', {
|
|
991
|
-
module: CONFIG_FILE_NAME,
|
|
992
|
-
method: 'getQueues',
|
|
993
|
-
});
|
|
994
|
-
expect(LoggerProxy.log).toHaveBeenCalledWith('getQueues API success.', {
|
|
995
|
-
module: CONFIG_FILE_NAME,
|
|
996
|
-
method: 'getQueues',
|
|
997
|
-
});
|
|
998
|
-
});
|
|
999
|
-
|
|
1000
|
-
it('should throw an error if the API call fails', async () => {
|
|
1001
|
-
mockWebexRequest.request.mockRejectedValue(mockError);
|
|
1002
|
-
|
|
1003
|
-
await expect(agentConfigService.getQueues(mockOrgId, 0, 100)).rejects.toThrow(
|
|
1004
|
-
'API call failed'
|
|
1005
|
-
);
|
|
1006
|
-
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
1007
|
-
'getQueues API call failed with Error: API call failed',
|
|
1008
|
-
{module: CONFIG_FILE_NAME, method: 'getQueues'}
|
|
1009
|
-
);
|
|
1010
|
-
expect(mockWebexRequest.request).toHaveBeenCalledWith({
|
|
1011
|
-
service: mockWccAPIURL,
|
|
1012
|
-
resource: `organization/${mockOrgId}/v2/contact-service-queue?page=0&pageSize=100&desktopProfileFilter=true`,
|
|
1013
|
-
method: 'GET',
|
|
1014
|
-
});
|
|
1015
|
-
});
|
|
1016
|
-
|
|
1017
|
-
it('should throw an error if the API call returns a non-200 status code', async () => {
|
|
1018
|
-
const mockResponse = {statusCode: 500};
|
|
1019
|
-
mockWebexRequest.request.mockResolvedValue(mockResponse);
|
|
1020
|
-
|
|
1021
|
-
await expect(agentConfigService.getQueues(mockOrgId, 0, 100)).rejects.toThrow(
|
|
1022
|
-
'API call failed with 500'
|
|
1023
|
-
);
|
|
1024
|
-
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
1025
|
-
'getQueues API call failed with Error: API call failed with 500',
|
|
1026
|
-
{module: CONFIG_FILE_NAME, method: 'getQueues'}
|
|
1027
|
-
);
|
|
1028
|
-
expect(mockWebexRequest.request).toHaveBeenCalledWith({
|
|
1029
|
-
service: mockWccAPIURL,
|
|
1030
|
-
resource: `organization/${mockOrgId}/v2/contact-service-queue?page=0&pageSize=100&desktopProfileFilter=true`,
|
|
1031
|
-
method: 'GET',
|
|
1032
|
-
});
|
|
1033
|
-
});
|
|
1034
|
-
});
|
|
1035
964
|
});
|
|
@@ -276,4 +276,54 @@ describe('Utils', () => {
|
|
|
276
276
|
});
|
|
277
277
|
});
|
|
278
278
|
});
|
|
279
|
+
|
|
280
|
+
describe('getDestinationAgentId', () => {
|
|
281
|
+
const currentAgentId = 'agent-current-123';
|
|
282
|
+
|
|
283
|
+
it('returns another Agent id when present and not in wrap-up', () => {
|
|
284
|
+
const participants: any = {
|
|
285
|
+
[currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
|
|
286
|
+
agent1: {type: 'Agent', id: 'agent-1', isWrapUp: false},
|
|
287
|
+
customer1: {type: 'Customer', id: 'cust-1', isWrapUp: false},
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const result = Utils.getDestinationAgentId(participants, currentAgentId);
|
|
291
|
+
expect(result).toBe('agent-1');
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('ignores self and wrap-up participants', () => {
|
|
295
|
+
const participants: any = {
|
|
296
|
+
[currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
|
|
297
|
+
agentWrap: {type: 'Agent', id: 'agent-wrap', isWrapUp: true},
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const result = Utils.getDestinationAgentId(participants, currentAgentId);
|
|
301
|
+
expect(result).toBe('');
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('supports DN, EpDn and entryPoint types', () => {
|
|
305
|
+
const participantsDN: any = {
|
|
306
|
+
[currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
|
|
307
|
+
dn1: {type: 'DN', id: 'dn-1', isWrapUp: false},
|
|
308
|
+
};
|
|
309
|
+
expect(Utils.getDestinationAgentId(participantsDN, currentAgentId)).toBe('dn-1');
|
|
310
|
+
|
|
311
|
+
const participantsEpDn: any = {
|
|
312
|
+
[currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
|
|
313
|
+
epdn1: {type: 'EpDn', id: 'epdn-1', isWrapUp: false},
|
|
314
|
+
};
|
|
315
|
+
expect(Utils.getDestinationAgentId(participantsEpDn, currentAgentId)).toBe('epdn-1');
|
|
316
|
+
|
|
317
|
+
const participantsEntry: any = {
|
|
318
|
+
[currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
|
|
319
|
+
entry1: {type: 'entryPoint', id: 'entry-1', isWrapUp: false},
|
|
320
|
+
};
|
|
321
|
+
expect(Utils.getDestinationAgentId(participantsEntry, currentAgentId)).toBe('entry-1');
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it('returns empty string when participants is missing or empty', () => {
|
|
325
|
+
expect(Utils.getDestinationAgentId(undefined as any, currentAgentId)).toBe('');
|
|
326
|
+
expect(Utils.getDestinationAgentId({} as any, currentAgentId)).toBe('');
|
|
327
|
+
});
|
|
328
|
+
});
|
|
279
329
|
});
|
|
@@ -381,9 +381,7 @@ describe('AqmReqs', () => {
|
|
|
381
381
|
data: { type: 'KeepaliveEvent' },
|
|
382
382
|
})
|
|
383
383
|
);
|
|
384
|
-
|
|
385
|
-
expect(LoggerProxy.info).toHaveBeenCalledWith('Keepalive from web socket', {"method": "onMessage", "module": AQM_REQS_FILE});
|
|
386
|
-
|
|
384
|
+
|
|
387
385
|
// Unhandled event
|
|
388
386
|
webSocketManagerInstance.emit(
|
|
389
387
|
'message',
|
|
@@ -200,10 +200,6 @@ describe('WebSocketManager', () => {
|
|
|
200
200
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
201
201
|
|
|
202
202
|
expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
|
|
203
|
-
expect(LoggerProxy.info).toHaveBeenCalledWith(
|
|
204
|
-
'[WebSocketStatus] | desktop online status is false',
|
|
205
|
-
{ module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
|
|
206
|
-
);
|
|
207
203
|
expect(LoggerProxy.error).toHaveBeenCalledWith(
|
|
208
204
|
'[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: network issue',
|
|
209
205
|
{ module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
|
|
@@ -658,6 +658,13 @@ describe('TaskManager', () => {
|
|
|
658
658
|
});
|
|
659
659
|
|
|
660
660
|
it('should emit TASK_CONSULT_ACCEPTED event on AGENT_CONSULTING event', () => {
|
|
661
|
+
const initialConsultingPayload = {
|
|
662
|
+
data: {
|
|
663
|
+
...initalPayload.data,
|
|
664
|
+
type: CC_EVENTS.AGENT_OFFER_CONSULT,
|
|
665
|
+
},
|
|
666
|
+
};
|
|
667
|
+
|
|
661
668
|
const consultingPayload = {
|
|
662
669
|
data: {
|
|
663
670
|
...initalPayload.data,
|
|
@@ -672,8 +679,8 @@ describe('TaskManager', () => {
|
|
|
672
679
|
});
|
|
673
680
|
|
|
674
681
|
const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
|
|
682
|
+
webSocketManagerMock.emit('message', JSON.stringify(initialConsultingPayload));
|
|
675
683
|
webSocketManagerMock.emit('message', JSON.stringify(consultingPayload));
|
|
676
|
-
expect(taskManager.getTask(taskId).updateTaskData).toHaveBeenCalledWith(consultingPayload.data);
|
|
677
684
|
expect(taskManager.getTask(taskId).data.isConsulted).toBe(true);
|
|
678
685
|
expect(taskEmitSpy).toHaveBeenCalledWith(
|
|
679
686
|
TASK_EVENTS.TASK_CONSULT_ACCEPTED,
|