@webex/contact-center 3.12.0-llmrefactor.2 → 3.12.0-llmrefactor.4
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 +5 -4
- package/ai-docs/ARCHITECTURE.md +1 -1
- package/ai-docs/CONTRACTS.md +6 -2
- package/ai-docs/SECURITY.md +1 -1
- package/ai-docs/contact-center-spec.md +22 -4
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/dist/cc.js +440 -10
- package/dist/cc.js.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +10 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +13 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +2 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +18 -15
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/AnswerCallOnWebexService.js +174 -0
- package/dist/services/AnswerCallOnWebexService.js.map +1 -0
- package/dist/services/EntryPoint.js +46 -68
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +27 -22
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/WebexCrossClientService.js +171 -0
- package/dist/services/WebexCrossClientService.js.map +1 -0
- package/dist/services/WxAppTelephonyMercurySync.js +93 -0
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
- package/dist/services/config/Util.js +3 -0
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +10 -6
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/types.js +4 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/WebexRequest.js +6 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +28 -14
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/task/Task.js +73 -7
- package/dist/services/task/Task.js.map +1 -1
- package/dist/services/task/TaskFactory.js +8 -4
- package/dist/services/task/TaskFactory.js.map +1 -1
- package/dist/services/task/TaskManager.js +353 -21
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/WebexCallingUtils.js +70 -0
- package/dist/services/task/WebexCallingUtils.js.map +1 -0
- package/dist/services/task/constants.js +4 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +29 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/digital/Digital.js +3 -2
- package/dist/services/task/digital/Digital.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +135 -37
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +6 -1
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +38 -11
- package/dist/services/task/state-machine/guards.js.map +1 -1
- package/dist/services/task/state-machine/types.js.map +1 -1
- package/dist/services/task/state-machine/uiControlsComputer.js +118 -18
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
- package/dist/services/task/types.js +16 -1
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +350 -14
- package/dist/services/task/voice/Voice.js.map +1 -1
- package/dist/services/task/voice/WebRTC.js +4 -1
- package/dist/services/task/voice/WebRTC.js.map +1 -1
- package/dist/services/task/voice/wxAppVoiceMethods.js +201 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
- package/dist/services/wxAppTelephonyUtils.js +19 -0
- package/dist/services/wxAppTelephonyUtils.js.map +1 -0
- package/dist/types/cc.d.ts +77 -4
- package/dist/types/config.d.ts +7 -0
- package/dist/types/constants.d.ts +8 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/metrics/constants.d.ts +2 -0
- package/dist/types/services/AddressBook.d.ts +2 -1
- package/dist/types/services/AnswerCallOnWebexService.d.ts +37 -0
- package/dist/types/services/EntryPoint.d.ts +7 -5
- package/dist/types/services/Queue.d.ts +5 -3
- package/dist/types/services/WebexCrossClientService.d.ts +28 -0
- package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
- package/dist/types/services/config/constants.d.ts +8 -5
- package/dist/types/services/config/types.d.ts +17 -4
- package/dist/types/services/core/Err.d.ts +2 -0
- package/dist/types/services/core/WebexRequest.d.ts +1 -0
- package/dist/types/services/core/types.d.ts +2 -0
- package/dist/types/services/task/Task.d.ts +20 -2
- package/dist/types/services/task/TaskFactory.d.ts +2 -1
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +3 -0
- package/dist/types/services/task/contact.d.ts +4 -0
- package/dist/types/services/task/digital/Digital.d.ts +2 -2
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +260 -56
- package/dist/types/services/task/state-machine/guards.d.ts +6 -5
- package/dist/types/services/task/state-machine/types.d.ts +9 -1
- package/dist/types/services/task/types.d.ts +81 -4
- package/dist/types/services/task/voice/Voice.d.ts +48 -9
- package/dist/types/services/task/voice/WebRTC.d.ts +2 -2
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +52 -0
- package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
- package/dist/types/types.d.ts +14 -8
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types.js +7 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +19 -5
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex.js +1 -1
- package/package.json +9 -9
- package/src/cc.ts +506 -9
- package/src/config.ts +7 -0
- package/src/constants.ts +8 -0
- package/src/index.ts +2 -0
- package/src/metrics/ai-docs/metrics-spec.md +9 -3
- package/src/metrics/behavioral-events.ts +14 -0
- package/src/metrics/constants.ts +2 -0
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +206 -0
- package/src/services/EntryPoint.ts +59 -60
- package/src/services/Queue.ts +29 -12
- package/src/services/WebexCrossClientService.ts +212 -0
- package/src/services/WxAppTelephonyMercurySync.ts +115 -0
- package/src/services/ai-docs/AGENTS.md +10 -10
- package/src/services/ai-docs/services-spec.md +6 -1
- package/src/services/config/Util.ts +3 -0
- package/src/services/config/ai-docs/AGENTS.md +1 -1
- package/src/services/config/ai-docs/ARCHITECTURE.md +2 -2
- package/src/services/config/ai-docs/config-spec.md +6 -0
- package/src/services/config/constants.ts +10 -6
- package/src/services/config/types.ts +16 -4
- package/src/services/core/Err.ts +1 -0
- package/src/services/core/WebexRequest.ts +3 -1
- package/src/services/core/ai-docs/core-spec.md +5 -1
- package/src/services/core/aqm-reqs.ts +30 -15
- package/src/services/core/types.ts +2 -0
- package/src/services/task/Task.ts +79 -8
- package/src/services/task/TaskFactory.ts +8 -3
- package/src/services/task/TaskManager.ts +522 -16
- package/src/services/task/WebexCallingUtils.ts +136 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +1 -0
- package/src/services/task/ai-docs/task-spec.md +152 -2
- package/src/services/task/constants.ts +3 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/digital/Digital.ts +4 -2
- package/src/services/task/state-machine/TaskStateMachine.ts +210 -63
- package/src/services/task/state-machine/actions.ts +5 -2
- package/src/services/task/state-machine/ai-docs/AGENTS.md +8 -4
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +17 -8
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +56 -24
- package/src/services/task/state-machine/guards.ts +64 -11
- package/src/services/task/state-machine/types.ts +16 -1
- package/src/services/task/state-machine/uiControlsComputer.ts +206 -32
- package/src/services/task/types.ts +114 -4
- package/src/services/task/voice/Voice.ts +462 -12
- package/src/services/task/voice/WebRTC.ts +5 -1
- package/src/services/task/voice/wxAppVoiceMethods.ts +307 -0
- package/src/services/wxAppTelephonyUtils.ts +14 -0
- package/src/types.ts +33 -9
- package/src/utils/AGENTS.md +21 -10
- package/src/utils/PageCache.ts +38 -5
- package/src/utils/ai-docs/utils-spec.md +21 -11
- package/test/unit/spec/cc.ts +1274 -0
- package/test/unit/spec/metrics/behavioral-events.ts +18 -0
- package/test/unit/spec/services/AddressBook.ts +37 -6
- package/test/unit/spec/services/AnswerCallOnWebexService.ts +223 -0
- package/test/unit/spec/services/EntryPoint.ts +87 -40
- package/test/unit/spec/services/Queue.ts +123 -12
- package/test/unit/spec/services/WebexCrossClientService.ts +261 -0
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +113 -0
- package/test/unit/spec/services/config/Util.ts +85 -0
- package/test/unit/spec/services/core/WebexRequest.ts +3 -1
- package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
- package/test/unit/spec/services/task/Task.ts +200 -0
- package/test/unit/spec/services/task/TaskFactory.ts +39 -2
- package/test/unit/spec/services/task/TaskManager.ts +1294 -1
- package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
- package/test/unit/spec/services/task/contact.ts +33 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +854 -72
- package/test/unit/spec/services/task/state-machine/guards.ts +210 -8
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +445 -7
- package/test/unit/spec/services/task/voice/Voice.ts +874 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +459 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
TaskState,
|
|
6
6
|
} from '../../../../../../src/services/task/state-machine';
|
|
7
7
|
import {createTaskData} from '../taskTestUtils';
|
|
8
|
+
import {guards} from '../../../../../../src/services/task/state-machine/guards';
|
|
8
9
|
|
|
9
10
|
const createConfig = () => ({
|
|
10
11
|
channelType: 'voice' as const,
|
|
@@ -106,6 +107,198 @@ describe('Task state machine', () => {
|
|
|
106
107
|
});
|
|
107
108
|
});
|
|
108
109
|
|
|
110
|
+
describe('partial lifecycle payloads', () => {
|
|
111
|
+
const createActiveMainCallTaskData = (isHold = false) =>
|
|
112
|
+
createTaskData({
|
|
113
|
+
agentId: 'agent-1',
|
|
114
|
+
interactionId: 'interaction-1',
|
|
115
|
+
mediaResourceId: 'main-media',
|
|
116
|
+
interaction: {
|
|
117
|
+
state: 'connected',
|
|
118
|
+
participants: {
|
|
119
|
+
'agent-1': {id: 'agent-1', pType: 'Agent', hasLeft: false},
|
|
120
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false},
|
|
121
|
+
},
|
|
122
|
+
media: {
|
|
123
|
+
'main-media': {
|
|
124
|
+
mediaResourceId: 'main-media',
|
|
125
|
+
mType: 'mainCall',
|
|
126
|
+
participants: ['agent-1', 'customer-1'],
|
|
127
|
+
isHold,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
} as any,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const createPartialMainCallTaskData = (isHold = false, omitSelf = false) =>
|
|
134
|
+
createTaskData({
|
|
135
|
+
agentId: 'agent-1',
|
|
136
|
+
interactionId: 'interaction-1',
|
|
137
|
+
mediaResourceId: 'main-media',
|
|
138
|
+
interaction: {
|
|
139
|
+
state: 'connected',
|
|
140
|
+
participants: omitSelf
|
|
141
|
+
? {'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false}}
|
|
142
|
+
: {
|
|
143
|
+
'agent-1': {id: 'agent-1', pType: 'Agent', hasLeft: false},
|
|
144
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false},
|
|
145
|
+
},
|
|
146
|
+
media: {
|
|
147
|
+
'main-media': {
|
|
148
|
+
mediaResourceId: 'main-media',
|
|
149
|
+
mType: 'mainCall',
|
|
150
|
+
participants: ['customer-1'],
|
|
151
|
+
isHold,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
} as any,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const startMachineWithEndSpy = () => {
|
|
158
|
+
const emitTaskEnd = jest.fn();
|
|
159
|
+
const service = createActor(
|
|
160
|
+
createTaskStateMachine({...createConfig(), agentId: 'agent-1'}, {actions: {emitTaskEnd}})
|
|
161
|
+
);
|
|
162
|
+
service.start();
|
|
163
|
+
|
|
164
|
+
return {service, emitTaskEnd};
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const enterTransientHoldState = (
|
|
168
|
+
service: ReturnType<typeof startMachine>,
|
|
169
|
+
state: TaskState.HOLD_INITIATING | TaskState.RESUME_INITIATING,
|
|
170
|
+
taskData: ReturnType<typeof createActiveMainCallTaskData>
|
|
171
|
+
) => {
|
|
172
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
173
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
174
|
+
service.send({type: TaskEvent.HOLD_INITIATED, mediaResourceId: 'main-media'});
|
|
175
|
+
|
|
176
|
+
if (state === TaskState.RESUME_INITIATING) {
|
|
177
|
+
service.send({type: TaskEvent.HOLD_SUCCESS, mediaResourceId: 'main-media'});
|
|
178
|
+
service.send({type: TaskEvent.UNHOLD_INITIATED, mediaResourceId: 'main-media'});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
expect(service.getSnapshot().value).toBe(state);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
it('keeps CONNECTED when another participant leave event has a partial mainCall', () => {
|
|
185
|
+
const {service, emitTaskEnd} = startMachineWithEndSpy();
|
|
186
|
+
const taskData = createActiveMainCallTaskData();
|
|
187
|
+
|
|
188
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
189
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
190
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONNECTED);
|
|
191
|
+
|
|
192
|
+
service.send({
|
|
193
|
+
type: TaskEvent.PARTICIPANT_LEAVE,
|
|
194
|
+
participantId: 'agent-2',
|
|
195
|
+
taskData: createPartialMainCallTaskData(false, true),
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONNECTED);
|
|
199
|
+
expect(emitTaskEnd).not.toHaveBeenCalled();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('terminates CONNECTED when an out-of-order participant leave identifies the current agent', () => {
|
|
203
|
+
const {service, emitTaskEnd} = startMachineWithEndSpy();
|
|
204
|
+
const taskData = createActiveMainCallTaskData();
|
|
205
|
+
|
|
206
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
207
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
208
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONNECTED);
|
|
209
|
+
|
|
210
|
+
service.send({
|
|
211
|
+
type: TaskEvent.PARTICIPANT_LEAVE,
|
|
212
|
+
participantId: 'agent-1',
|
|
213
|
+
taskData: createPartialMainCallTaskData(false, true),
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
217
|
+
expect(emitTaskEnd).toHaveBeenCalledTimes(1);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it.each([TaskState.HOLD_INITIATING, TaskState.RESUME_INITIATING])(
|
|
221
|
+
'terminates %s when a remote Drop identifies the current agent',
|
|
222
|
+
(state) => {
|
|
223
|
+
const {service, emitTaskEnd} = startMachineWithEndSpy();
|
|
224
|
+
const taskData = createActiveMainCallTaskData(state === TaskState.RESUME_INITIATING);
|
|
225
|
+
|
|
226
|
+
enterTransientHoldState(service, state, taskData);
|
|
227
|
+
service.send({
|
|
228
|
+
type: TaskEvent.PARTICIPANT_LEAVE,
|
|
229
|
+
participantId: 'agent-1',
|
|
230
|
+
taskData: createPartialMainCallTaskData(
|
|
231
|
+
state === TaskState.RESUME_INITIATING,
|
|
232
|
+
true
|
|
233
|
+
),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
237
|
+
expect(emitTaskEnd).toHaveBeenCalledTimes(1);
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
it.each([TaskState.HOLD_INITIATING, TaskState.RESUME_INITIATING])(
|
|
242
|
+
'keeps %s when ParticipantLeftConference identifies another participant',
|
|
243
|
+
(state) => {
|
|
244
|
+
const {service, emitTaskEnd} = startMachineWithEndSpy();
|
|
245
|
+
const taskData = createActiveMainCallTaskData(state === TaskState.RESUME_INITIATING);
|
|
246
|
+
|
|
247
|
+
enterTransientHoldState(service, state, taskData);
|
|
248
|
+
service.send({
|
|
249
|
+
type: TaskEvent.PARTICIPANT_LEAVE,
|
|
250
|
+
participantId: 'agent-2',
|
|
251
|
+
taskData: createPartialMainCallTaskData(
|
|
252
|
+
state === TaskState.RESUME_INITIATING,
|
|
253
|
+
true
|
|
254
|
+
),
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
expect(service.getSnapshot().value).toBe(state);
|
|
258
|
+
expect(emitTaskEnd).not.toHaveBeenCalled();
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
it('keeps HELD when another participant leave event omits self from its roster', () => {
|
|
263
|
+
const {service, emitTaskEnd} = startMachineWithEndSpy();
|
|
264
|
+
const taskData = createActiveMainCallTaskData(true);
|
|
265
|
+
|
|
266
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
267
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
268
|
+
service.send({type: TaskEvent.HOLD_INITIATED, mediaResourceId: 'main-media'});
|
|
269
|
+
service.send({type: TaskEvent.HOLD_SUCCESS, mediaResourceId: 'main-media'});
|
|
270
|
+
expect(service.getSnapshot().value).toBe(TaskState.HELD);
|
|
271
|
+
|
|
272
|
+
service.send({
|
|
273
|
+
type: TaskEvent.PARTICIPANT_LEAVE,
|
|
274
|
+
participantId: 'agent-2',
|
|
275
|
+
taskData: createPartialMainCallTaskData(true, true),
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
expect(service.getSnapshot().value).toBe(TaskState.HELD);
|
|
279
|
+
expect(emitTaskEnd).not.toHaveBeenCalled();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('keeps HELD when CONSULT_END has a partial mainCall', () => {
|
|
283
|
+
const {service, emitTaskEnd} = startMachineWithEndSpy();
|
|
284
|
+
const taskData = createActiveMainCallTaskData(true);
|
|
285
|
+
|
|
286
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
287
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
288
|
+
service.send({type: TaskEvent.HOLD_INITIATED, mediaResourceId: 'main-media'});
|
|
289
|
+
service.send({type: TaskEvent.HOLD_SUCCESS, mediaResourceId: 'main-media'});
|
|
290
|
+
expect(service.getSnapshot().value).toBe(TaskState.HELD);
|
|
291
|
+
|
|
292
|
+
service.send({
|
|
293
|
+
type: TaskEvent.CONSULT_END,
|
|
294
|
+
taskData: createPartialMainCallTaskData(true),
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
expect(service.getSnapshot().value).toBe(TaskState.HELD);
|
|
298
|
+
expect(emitTaskEnd).not.toHaveBeenCalled();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
109
302
|
describe('recording pause/resume events', () => {
|
|
110
303
|
it('toggles recordingPaused flag based on events', () => {
|
|
111
304
|
const service = startMachine();
|
|
@@ -180,6 +373,32 @@ describe('Task state machine', () => {
|
|
|
180
373
|
service.send({type: TaskEvent.WRAPUP_COMPLETE});
|
|
181
374
|
expect(service.getSnapshot().value).toBe(TaskState.COMPLETED);
|
|
182
375
|
});
|
|
376
|
+
|
|
377
|
+
it('emits task wrappedup before cleanup on COMPLETED entry', () => {
|
|
378
|
+
const actionOrder: string[] = [];
|
|
379
|
+
const actor = createActor(
|
|
380
|
+
createTaskStateMachine(createConfig(), {
|
|
381
|
+
actions: {
|
|
382
|
+
emitTaskWrappedup: () => {
|
|
383
|
+
actionOrder.push('emitTaskWrappedup');
|
|
384
|
+
},
|
|
385
|
+
cleanupResources: () => {
|
|
386
|
+
actionOrder.push('cleanupResources');
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
})
|
|
390
|
+
);
|
|
391
|
+
actor.start();
|
|
392
|
+
const taskData = createTaskData();
|
|
393
|
+
|
|
394
|
+
actor.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
395
|
+
actor.send({type: TaskEvent.ASSIGN, taskData});
|
|
396
|
+
actor.send({type: TaskEvent.TASK_WRAPUP});
|
|
397
|
+
actor.send({type: TaskEvent.WRAPUP_COMPLETE});
|
|
398
|
+
|
|
399
|
+
expect(actor.getSnapshot().value).toBe(TaskState.COMPLETED);
|
|
400
|
+
expect(actionOrder).toEqual(['emitTaskWrappedup', 'cleanupResources']);
|
|
401
|
+
});
|
|
183
402
|
});
|
|
184
403
|
|
|
185
404
|
describe('consult and conference flows', () => {
|
|
@@ -343,53 +562,53 @@ describe('Task state machine', () => {
|
|
|
343
562
|
expect(snapshot.context.consultFromConference).toBe(true);
|
|
344
563
|
});
|
|
345
564
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
},
|
|
372
|
-
media: {
|
|
373
|
-
'interaction-1': {
|
|
374
|
-
mediaResourceId: 'interaction-1',
|
|
375
|
-
mType: 'mainCall',
|
|
376
|
-
participants: ['agent-1', 'customer-1'],
|
|
377
|
-
isHold: true,
|
|
378
|
-
},
|
|
379
|
-
'consult-media-1': {
|
|
380
|
-
mediaResourceId: 'consult-media-1',
|
|
381
|
-
mType: 'consult',
|
|
382
|
-
participants: ['agent-1', 'agent-2'],
|
|
383
|
-
isHold: false,
|
|
565
|
+
it('hydrates consulted agent to CONSULTING when self consultState is consulting and main leg is held', () => {
|
|
566
|
+
const service = startMachine();
|
|
567
|
+
const taskData = createTaskData({
|
|
568
|
+
agentId: 'agent-2',
|
|
569
|
+
isConsulted: true,
|
|
570
|
+
interaction: {
|
|
571
|
+
state: 'conference',
|
|
572
|
+
mainInteractionId: 'interaction-1',
|
|
573
|
+
interactionId: 'interaction-1',
|
|
574
|
+
participants: {
|
|
575
|
+
'agent-1': {
|
|
576
|
+
id: 'agent-1',
|
|
577
|
+
pType: 'Agent',
|
|
578
|
+
hasLeft: false,
|
|
579
|
+
consultState: 'consulting',
|
|
580
|
+
isConsulted: false,
|
|
581
|
+
},
|
|
582
|
+
'agent-2': {
|
|
583
|
+
id: 'agent-2',
|
|
584
|
+
pType: 'Agent',
|
|
585
|
+
hasLeft: false,
|
|
586
|
+
consultState: 'consulting',
|
|
587
|
+
isConsulted: true,
|
|
588
|
+
},
|
|
589
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false},
|
|
384
590
|
},
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
591
|
+
media: {
|
|
592
|
+
'interaction-1': {
|
|
593
|
+
mediaResourceId: 'interaction-1',
|
|
594
|
+
mType: 'mainCall',
|
|
595
|
+
participants: ['agent-1', 'customer-1'],
|
|
596
|
+
isHold: true,
|
|
597
|
+
},
|
|
598
|
+
'consult-media-1': {
|
|
599
|
+
mediaResourceId: 'consult-media-1',
|
|
600
|
+
mType: 'consult',
|
|
601
|
+
participants: ['agent-1', 'agent-2'],
|
|
602
|
+
isHold: false,
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
} as any,
|
|
606
|
+
});
|
|
388
607
|
|
|
389
|
-
|
|
608
|
+
service.send({type: TaskEvent.HYDRATE, taskData});
|
|
390
609
|
|
|
391
|
-
|
|
392
|
-
|
|
610
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONSULTING);
|
|
611
|
+
});
|
|
393
612
|
|
|
394
613
|
it('hydrates to CONSULTING when consult is pending (self consultState is consultInitiated)', () => {
|
|
395
614
|
const service = startMachine();
|
|
@@ -1684,6 +1903,47 @@ describe('Task state machine', () => {
|
|
|
1684
1903
|
expect(service.getSnapshot().value).toBe(TaskState.CONNECTED);
|
|
1685
1904
|
});
|
|
1686
1905
|
|
|
1906
|
+
it('downgrades to CONNECTED on PARTICIPANT_LEAVE when the current agent remains', () => {
|
|
1907
|
+
const service = startMachine();
|
|
1908
|
+
const conferenceTaskData = createSingleAgentConferenceTaskData('conference');
|
|
1909
|
+
const connectedTaskData = createSingleAgentConferenceTaskData('connected');
|
|
1910
|
+
|
|
1911
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData: conferenceTaskData});
|
|
1912
|
+
service.send({type: TaskEvent.ASSIGN, taskData: conferenceTaskData});
|
|
1913
|
+
service.send({type: TaskEvent.CONFERENCE_START, taskData: conferenceTaskData});
|
|
1914
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONFERENCING);
|
|
1915
|
+
|
|
1916
|
+
service.send({
|
|
1917
|
+
type: TaskEvent.PARTICIPANT_LEAVE,
|
|
1918
|
+
participantId: 'agent-2',
|
|
1919
|
+
taskData: connectedTaskData,
|
|
1920
|
+
});
|
|
1921
|
+
|
|
1922
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONNECTED);
|
|
1923
|
+
});
|
|
1924
|
+
|
|
1925
|
+
it('terminates instead of downgrading when PARTICIPANT_LEAVE identifies the current agent', () => {
|
|
1926
|
+
const service = startMachine();
|
|
1927
|
+
const conferenceTaskData = createSingleAgentConferenceTaskData('conference');
|
|
1928
|
+
const connectedTaskData = {
|
|
1929
|
+
...createSingleAgentConferenceTaskData('connected'),
|
|
1930
|
+
wrapUpRequired: false,
|
|
1931
|
+
};
|
|
1932
|
+
|
|
1933
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData: conferenceTaskData});
|
|
1934
|
+
service.send({type: TaskEvent.ASSIGN, taskData: conferenceTaskData});
|
|
1935
|
+
service.send({type: TaskEvent.CONFERENCE_START, taskData: conferenceTaskData});
|
|
1936
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONFERENCING);
|
|
1937
|
+
|
|
1938
|
+
service.send({
|
|
1939
|
+
type: TaskEvent.PARTICIPANT_LEAVE,
|
|
1940
|
+
participantId: 'agent-1',
|
|
1941
|
+
taskData: connectedTaskData,
|
|
1942
|
+
});
|
|
1943
|
+
|
|
1944
|
+
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
1945
|
+
});
|
|
1946
|
+
|
|
1687
1947
|
it('returns to CONNECTED when CTQ cancel arrives before queue connects', () => {
|
|
1688
1948
|
const service = startMachine();
|
|
1689
1949
|
const taskData = createTaskData();
|
|
@@ -1820,10 +2080,8 @@ describe('Task state machine', () => {
|
|
|
1820
2080
|
service.send({type: TaskEvent.CONSULT_END, taskData});
|
|
1821
2081
|
expect(service.getSnapshot().value).toBe(TaskState.CONNECTED);
|
|
1822
2082
|
});
|
|
1823
|
-
|
|
1824
2083
|
});
|
|
1825
2084
|
|
|
1826
|
-
|
|
1827
2085
|
describe('CONFERENCING state CONSULT_FAILED ANOTHER_CONSULT_IN_PROGRESS (CAI-8329)', () => {
|
|
1828
2086
|
it('keeps hideBlindTransfer flag and hides transfer after secondary consult rejected from Agent Desktop', () => {
|
|
1829
2087
|
const service = startMachine();
|
|
@@ -1848,7 +2106,12 @@ describe('Task state machine', () => {
|
|
|
1848
2106
|
consultState: 'conferencing',
|
|
1849
2107
|
},
|
|
1850
2108
|
'+13159998059': {id: '+13159998059', pType: 'EP-DN', hasLeft: false},
|
|
1851
|
-
'+14696762938': {
|
|
2109
|
+
'+14696762938': {
|
|
2110
|
+
id: '+14696762938',
|
|
2111
|
+
pType: 'Customer',
|
|
2112
|
+
hasJoined: true,
|
|
2113
|
+
hasLeft: false,
|
|
2114
|
+
},
|
|
1852
2115
|
},
|
|
1853
2116
|
media: {
|
|
1854
2117
|
'interaction-1': {
|
|
@@ -1902,7 +2165,12 @@ describe('Task state machine', () => {
|
|
|
1902
2165
|
consultState: 'conferencing',
|
|
1903
2166
|
},
|
|
1904
2167
|
'+13159998059': {id: '+13159998059', pType: 'EP-DN', hasLeft: false},
|
|
1905
|
-
'+14696762938': {
|
|
2168
|
+
'+14696762938': {
|
|
2169
|
+
id: '+14696762938',
|
|
2170
|
+
pType: 'Customer',
|
|
2171
|
+
hasJoined: true,
|
|
2172
|
+
hasLeft: false,
|
|
2173
|
+
},
|
|
1906
2174
|
},
|
|
1907
2175
|
media: {
|
|
1908
2176
|
'interaction-1': {
|
|
@@ -1920,12 +2188,19 @@ describe('Task state machine', () => {
|
|
|
1920
2188
|
},
|
|
1921
2189
|
} as any,
|
|
1922
2190
|
});
|
|
1923
|
-
service.send({
|
|
2191
|
+
service.send({
|
|
2192
|
+
type: TaskEvent.CONSULT_FAILED,
|
|
2193
|
+
taskData: consultFailedTaskData,
|
|
2194
|
+
reason: 'ANOTHER_CONSULT_IN_PROGRESS',
|
|
2195
|
+
});
|
|
1924
2196
|
|
|
1925
2197
|
const snapshot = service.getSnapshot();
|
|
1926
2198
|
expect(snapshot.value).toBe(TaskState.CONFERENCING);
|
|
1927
2199
|
expect(snapshot.context.hideBlindTransferForEpDnPendingMerge).toBe(true);
|
|
1928
|
-
expect(snapshot.context.uiControls.main.transfer).toEqual({
|
|
2200
|
+
expect(snapshot.context.uiControls.main.transfer).toEqual({
|
|
2201
|
+
isVisible: false,
|
|
2202
|
+
isEnabled: false,
|
|
2203
|
+
});
|
|
1929
2204
|
expect(snapshot.context.uiControls.main.consult).toEqual({isVisible: true, isEnabled: false});
|
|
1930
2205
|
});
|
|
1931
2206
|
});
|
|
@@ -2126,6 +2401,50 @@ describe('Task state machine', () => {
|
|
|
2126
2401
|
service.send({type: TaskEvent.CONSULT_FAILED, taskData});
|
|
2127
2402
|
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
2128
2403
|
});
|
|
2404
|
+
|
|
2405
|
+
it('emits only consult-end when an unaccepted consulted offer is ended', () => {
|
|
2406
|
+
const emitTaskConsultEnd = jest.fn();
|
|
2407
|
+
const emitTaskEnd = jest.fn();
|
|
2408
|
+
const service = createActor(
|
|
2409
|
+
createTaskStateMachine(createConfig(), {
|
|
2410
|
+
actions: {emitTaskConsultEnd, emitTaskEnd},
|
|
2411
|
+
})
|
|
2412
|
+
);
|
|
2413
|
+
service.start();
|
|
2414
|
+
const taskData = createTaskData({isConsulted: true, consultingAgentId: 'agent-1'});
|
|
2415
|
+
|
|
2416
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
2417
|
+
service.send({type: TaskEvent.CONSULT_END, taskData});
|
|
2418
|
+
|
|
2419
|
+
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
2420
|
+
expect(emitTaskConsultEnd).toHaveBeenCalledTimes(1);
|
|
2421
|
+
expect(emitTaskEnd).not.toHaveBeenCalled();
|
|
2422
|
+
});
|
|
2423
|
+
|
|
2424
|
+
it('transitions to WRAPPING_UP on TASK_WRAPUP when wrapup is required', () => {
|
|
2425
|
+
const service = startMachine();
|
|
2426
|
+
const offerTaskData = createTaskData({
|
|
2427
|
+
interaction: {
|
|
2428
|
+
outboundType: 'OUTDIAL',
|
|
2429
|
+
} as any,
|
|
2430
|
+
});
|
|
2431
|
+
|
|
2432
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData: offerTaskData});
|
|
2433
|
+
expect(service.getSnapshot().value).toBe(TaskState.OFFERED);
|
|
2434
|
+
|
|
2435
|
+
const wrapupTaskData = createTaskData({
|
|
2436
|
+
agentId: 'agent-1',
|
|
2437
|
+
agentsPendingWrapUp: ['agent-1'],
|
|
2438
|
+
wrapUpRequired: true,
|
|
2439
|
+
interaction: {
|
|
2440
|
+
outboundType: 'OUTDIAL',
|
|
2441
|
+
state: 'wrapUp',
|
|
2442
|
+
isTerminated: true,
|
|
2443
|
+
} as any,
|
|
2444
|
+
});
|
|
2445
|
+
service.send({type: TaskEvent.TASK_WRAPUP, taskData: wrapupTaskData});
|
|
2446
|
+
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2447
|
+
});
|
|
2129
2448
|
});
|
|
2130
2449
|
|
|
2131
2450
|
describe('OUTBOUND_FAILED handling', () => {
|
|
@@ -2161,7 +2480,11 @@ describe('Task state machine', () => {
|
|
|
2161
2480
|
isTerminated: true,
|
|
2162
2481
|
} as any,
|
|
2163
2482
|
});
|
|
2164
|
-
service.send({
|
|
2483
|
+
service.send({
|
|
2484
|
+
type: TaskEvent.OUTBOUND_FAILED,
|
|
2485
|
+
taskData: failedTaskData,
|
|
2486
|
+
reason: 'CUSTOMER_BUSY',
|
|
2487
|
+
});
|
|
2165
2488
|
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
2166
2489
|
});
|
|
2167
2490
|
|
|
@@ -2184,23 +2507,235 @@ describe('Task state machine', () => {
|
|
|
2184
2507
|
isTerminated: true,
|
|
2185
2508
|
} as any,
|
|
2186
2509
|
});
|
|
2187
|
-
service.send({
|
|
2510
|
+
service.send({
|
|
2511
|
+
type: TaskEvent.OUTBOUND_FAILED,
|
|
2512
|
+
taskData: failedTaskData,
|
|
2513
|
+
reason: 'CUSTOMER_BUSY',
|
|
2514
|
+
});
|
|
2188
2515
|
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2189
2516
|
});
|
|
2190
|
-
});
|
|
2191
2517
|
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
const
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2518
|
+
it('transitions from CONNECTED to WRAPPING_UP on OUTBOUND_FAILED when wrapup is required', () => {
|
|
2519
|
+
const service = startMachine();
|
|
2520
|
+
const offerTaskData = createTaskData({
|
|
2521
|
+
interaction: {
|
|
2522
|
+
outboundType: 'OUTDIAL',
|
|
2523
|
+
} as any,
|
|
2524
|
+
});
|
|
2198
2525
|
|
|
2199
|
-
|
|
2200
|
-
|
|
2526
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData: offerTaskData});
|
|
2527
|
+
service.send({type: TaskEvent.ASSIGN, taskData: offerTaskData});
|
|
2528
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONNECTED);
|
|
2201
2529
|
|
|
2202
|
-
|
|
2203
|
-
|
|
2530
|
+
const failedTaskData = createTaskData({
|
|
2531
|
+
agentId: 'agent-1',
|
|
2532
|
+
agentsPendingWrapUp: ['agent-1'],
|
|
2533
|
+
interaction: {
|
|
2534
|
+
outboundType: 'OUTDIAL',
|
|
2535
|
+
isTerminated: true,
|
|
2536
|
+
} as any,
|
|
2537
|
+
});
|
|
2538
|
+
service.send({type: TaskEvent.OUTBOUND_FAILED, taskData: failedTaskData, reason: 'AGENT_ENDS'});
|
|
2539
|
+
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2540
|
+
});
|
|
2541
|
+
|
|
2542
|
+
it('transitions from HELD to WRAPPING_UP on OUTBOUND_FAILED when wrapup is required', () => {
|
|
2543
|
+
const service = startMachine();
|
|
2544
|
+
const taskData = createTaskData({
|
|
2545
|
+
interaction: {
|
|
2546
|
+
outboundType: 'OUTDIAL',
|
|
2547
|
+
} as any,
|
|
2548
|
+
});
|
|
2549
|
+
|
|
2550
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
2551
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
2552
|
+
service.send({type: TaskEvent.HOLD_INITIATED, mediaResourceId: taskData.mediaResourceId});
|
|
2553
|
+
service.send({type: TaskEvent.HOLD_SUCCESS, mediaResourceId: taskData.mediaResourceId});
|
|
2554
|
+
expect(service.getSnapshot().value).toBe(TaskState.HELD);
|
|
2555
|
+
|
|
2556
|
+
const failedTaskData = createTaskData({
|
|
2557
|
+
agentId: 'agent-1',
|
|
2558
|
+
agentsPendingWrapUp: ['agent-1'],
|
|
2559
|
+
interaction: {
|
|
2560
|
+
outboundType: 'OUTDIAL',
|
|
2561
|
+
isTerminated: true,
|
|
2562
|
+
} as any,
|
|
2563
|
+
});
|
|
2564
|
+
service.send({type: TaskEvent.OUTBOUND_FAILED, taskData: failedTaskData, reason: 'AGENT_ENDS'});
|
|
2565
|
+
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2566
|
+
});
|
|
2567
|
+
|
|
2568
|
+
it('transitions from CONSULTING to WRAPPING_UP on OUTBOUND_FAILED when wrapup is required', () => {
|
|
2569
|
+
const service = startMachine();
|
|
2570
|
+
const taskData = createTaskData({
|
|
2571
|
+
interaction: {
|
|
2572
|
+
outboundType: 'OUTDIAL',
|
|
2573
|
+
} as any,
|
|
2574
|
+
});
|
|
2575
|
+
|
|
2576
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
2577
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
2578
|
+
service.send({type: TaskEvent.CONSULT, destination: 'agent-42', destinationType: 'agent'});
|
|
2579
|
+
service.send({type: TaskEvent.CONSULT_SUCCESS, taskData});
|
|
2580
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONSULTING);
|
|
2581
|
+
|
|
2582
|
+
const failedTaskData = createTaskData({
|
|
2583
|
+
agentId: 'agent-1',
|
|
2584
|
+
agentsPendingWrapUp: ['agent-1'],
|
|
2585
|
+
interaction: {
|
|
2586
|
+
outboundType: 'OUTDIAL',
|
|
2587
|
+
isTerminated: true,
|
|
2588
|
+
} as any,
|
|
2589
|
+
});
|
|
2590
|
+
service.send({type: TaskEvent.OUTBOUND_FAILED, taskData: failedTaskData, reason: 'AGENT_ENDS'});
|
|
2591
|
+
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2592
|
+
});
|
|
2593
|
+
|
|
2594
|
+
it('transitions from CONFERENCING to WRAPPING_UP on OUTBOUND_FAILED when wrapup is required', () => {
|
|
2595
|
+
const service = startMachine();
|
|
2596
|
+
const taskData = createTaskData({
|
|
2597
|
+
consultingAgentId: 'agent-1',
|
|
2598
|
+
interaction: {
|
|
2599
|
+
outboundType: 'OUTDIAL',
|
|
2600
|
+
} as any,
|
|
2601
|
+
});
|
|
2602
|
+
|
|
2603
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
2604
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
2605
|
+
service.send({type: TaskEvent.CONSULT, destination: 'agent-42', destinationType: 'agent'});
|
|
2606
|
+
service.send({type: TaskEvent.CONSULT_SUCCESS, taskData});
|
|
2607
|
+
service.send({type: TaskEvent.MERGE_TO_CONFERENCE});
|
|
2608
|
+
service.send({type: TaskEvent.CONFERENCE_START});
|
|
2609
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONFERENCING);
|
|
2610
|
+
|
|
2611
|
+
const failedTaskData = createTaskData({
|
|
2612
|
+
agentId: 'agent-1',
|
|
2613
|
+
agentsPendingWrapUp: ['agent-1'],
|
|
2614
|
+
interaction: {
|
|
2615
|
+
outboundType: 'OUTDIAL',
|
|
2616
|
+
isTerminated: true,
|
|
2617
|
+
} as any,
|
|
2618
|
+
});
|
|
2619
|
+
service.send({type: TaskEvent.OUTBOUND_FAILED, taskData: failedTaskData, reason: 'AGENT_ENDS'});
|
|
2620
|
+
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2621
|
+
});
|
|
2622
|
+
|
|
2623
|
+
it('transitions from HOLD_INITIATING to WRAPPING_UP on OUTBOUND_FAILED when wrapup is required', () => {
|
|
2624
|
+
const service = startMachine();
|
|
2625
|
+
const taskData = createTaskData({
|
|
2626
|
+
interaction: {
|
|
2627
|
+
outboundType: 'OUTDIAL',
|
|
2628
|
+
} as any,
|
|
2629
|
+
});
|
|
2630
|
+
|
|
2631
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
2632
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
2633
|
+
service.send({type: TaskEvent.HOLD_INITIATED, mediaResourceId: taskData.mediaResourceId});
|
|
2634
|
+
expect(service.getSnapshot().value).toBe(TaskState.HOLD_INITIATING);
|
|
2635
|
+
|
|
2636
|
+
const failedTaskData = createTaskData({
|
|
2637
|
+
agentId: 'agent-1',
|
|
2638
|
+
agentsPendingWrapUp: ['agent-1'],
|
|
2639
|
+
interaction: {
|
|
2640
|
+
outboundType: 'OUTDIAL',
|
|
2641
|
+
isTerminated: true,
|
|
2642
|
+
} as any,
|
|
2643
|
+
});
|
|
2644
|
+
service.send({type: TaskEvent.OUTBOUND_FAILED, taskData: failedTaskData, reason: 'AGENT_ENDS'});
|
|
2645
|
+
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2646
|
+
});
|
|
2647
|
+
|
|
2648
|
+
it('transitions from RESUME_INITIATING to WRAPPING_UP on OUTBOUND_FAILED when wrapup is required', () => {
|
|
2649
|
+
const service = startMachine();
|
|
2650
|
+
const taskData = createTaskData({
|
|
2651
|
+
interaction: {
|
|
2652
|
+
outboundType: 'OUTDIAL',
|
|
2653
|
+
} as any,
|
|
2654
|
+
});
|
|
2655
|
+
|
|
2656
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
2657
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
2658
|
+
service.send({type: TaskEvent.HOLD_INITIATED, mediaResourceId: taskData.mediaResourceId});
|
|
2659
|
+
service.send({type: TaskEvent.HOLD_SUCCESS, mediaResourceId: taskData.mediaResourceId});
|
|
2660
|
+
service.send({type: TaskEvent.UNHOLD_INITIATED, mediaResourceId: taskData.mediaResourceId});
|
|
2661
|
+
expect(service.getSnapshot().value).toBe(TaskState.RESUME_INITIATING);
|
|
2662
|
+
|
|
2663
|
+
const failedTaskData = createTaskData({
|
|
2664
|
+
agentId: 'agent-1',
|
|
2665
|
+
agentsPendingWrapUp: ['agent-1'],
|
|
2666
|
+
interaction: {
|
|
2667
|
+
outboundType: 'OUTDIAL',
|
|
2668
|
+
isTerminated: true,
|
|
2669
|
+
} as any,
|
|
2670
|
+
});
|
|
2671
|
+
service.send({type: TaskEvent.OUTBOUND_FAILED, taskData: failedTaskData, reason: 'AGENT_ENDS'});
|
|
2672
|
+
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2673
|
+
});
|
|
2674
|
+
|
|
2675
|
+
it('transitions from CONSULT_INITIATING to WRAPPING_UP on OUTBOUND_FAILED when wrapup is required', () => {
|
|
2676
|
+
const service = startMachine();
|
|
2677
|
+
const taskData = createTaskData({
|
|
2678
|
+
interaction: {
|
|
2679
|
+
outboundType: 'OUTDIAL',
|
|
2680
|
+
} as any,
|
|
2681
|
+
});
|
|
2682
|
+
|
|
2683
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
2684
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
2685
|
+
service.send({type: TaskEvent.CONSULT, destination: 'agent-42', destinationType: 'agent'});
|
|
2686
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONSULT_INITIATING);
|
|
2687
|
+
|
|
2688
|
+
const failedTaskData = createTaskData({
|
|
2689
|
+
agentId: 'agent-1',
|
|
2690
|
+
agentsPendingWrapUp: ['agent-1'],
|
|
2691
|
+
interaction: {
|
|
2692
|
+
outboundType: 'OUTDIAL',
|
|
2693
|
+
isTerminated: true,
|
|
2694
|
+
} as any,
|
|
2695
|
+
});
|
|
2696
|
+
service.send({type: TaskEvent.OUTBOUND_FAILED, taskData: failedTaskData, reason: 'AGENT_ENDS'});
|
|
2697
|
+
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2698
|
+
});
|
|
2699
|
+
|
|
2700
|
+
it('transitions from CONF_INITIATING to WRAPPING_UP on OUTBOUND_FAILED when wrapup is required', () => {
|
|
2701
|
+
const service = startMachine();
|
|
2702
|
+
const taskData = createTaskData({
|
|
2703
|
+
consultingAgentId: 'agent-1',
|
|
2704
|
+
interaction: {
|
|
2705
|
+
outboundType: 'OUTDIAL',
|
|
2706
|
+
} as any,
|
|
2707
|
+
});
|
|
2708
|
+
|
|
2709
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData});
|
|
2710
|
+
service.send({type: TaskEvent.ASSIGN, taskData});
|
|
2711
|
+
service.send({type: TaskEvent.CONSULT, destination: 'agent-42', destinationType: 'agent'});
|
|
2712
|
+
service.send({type: TaskEvent.CONSULT_SUCCESS, taskData});
|
|
2713
|
+
service.send({type: TaskEvent.MERGE_TO_CONFERENCE});
|
|
2714
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONF_INITIATING);
|
|
2715
|
+
|
|
2716
|
+
const failedTaskData = createTaskData({
|
|
2717
|
+
agentId: 'agent-1',
|
|
2718
|
+
agentsPendingWrapUp: ['agent-1'],
|
|
2719
|
+
interaction: {
|
|
2720
|
+
outboundType: 'OUTDIAL',
|
|
2721
|
+
isTerminated: true,
|
|
2722
|
+
} as any,
|
|
2723
|
+
});
|
|
2724
|
+
service.send({type: TaskEvent.OUTBOUND_FAILED, taskData: failedTaskData, reason: 'AGENT_ENDS'});
|
|
2725
|
+
expect(service.getSnapshot().value).toBe(TaskState.WRAPPING_UP);
|
|
2726
|
+
});
|
|
2727
|
+
});
|
|
2728
|
+
|
|
2729
|
+
describe('CONSULTING state TRANSFER_CONFERENCE_SUCCESS desktop-initiated (CAI-8329)', () => {
|
|
2730
|
+
const startAgent2Machine = () => {
|
|
2731
|
+
const actor = createActor(createTaskStateMachine({...createConfig(), agentId: 'agent-2'}));
|
|
2732
|
+
actor.start();
|
|
2733
|
+
|
|
2734
|
+
return actor;
|
|
2735
|
+
};
|
|
2736
|
+
|
|
2737
|
+
const createSecondaryAgentConferenceBaseTaskData = () =>
|
|
2738
|
+
createTaskData({
|
|
2204
2739
|
agentId: 'agent-2',
|
|
2205
2740
|
isConsulted: true,
|
|
2206
2741
|
interactionId: 'interaction-1',
|
|
@@ -2292,7 +2827,54 @@ describe('Task state machine', () => {
|
|
|
2292
2827
|
} as any,
|
|
2293
2828
|
});
|
|
2294
2829
|
|
|
2295
|
-
const
|
|
2830
|
+
const createSecondaryAgentRemovedTaskData = () =>
|
|
2831
|
+
createTaskData({
|
|
2832
|
+
agentId: 'agent-2',
|
|
2833
|
+
isConsulted: true,
|
|
2834
|
+
interactionId: 'interaction-1',
|
|
2835
|
+
mediaResourceId: 'interaction-1',
|
|
2836
|
+
consultMediaResourceId: 'consult-media-1',
|
|
2837
|
+
interaction: {
|
|
2838
|
+
state: 'conference',
|
|
2839
|
+
owner: 'agent-1',
|
|
2840
|
+
mainInteractionId: 'interaction-1',
|
|
2841
|
+
interactionId: 'interaction-1',
|
|
2842
|
+
participants: {
|
|
2843
|
+
'agent-1': {
|
|
2844
|
+
id: 'agent-1',
|
|
2845
|
+
pType: 'Agent',
|
|
2846
|
+
hasLeft: false,
|
|
2847
|
+
consultState: 'conferencing',
|
|
2848
|
+
},
|
|
2849
|
+
'agent-3': {
|
|
2850
|
+
id: 'agent-3',
|
|
2851
|
+
pType: 'Agent',
|
|
2852
|
+
hasLeft: false,
|
|
2853
|
+
isConsulted: true,
|
|
2854
|
+
consultState: 'consulting',
|
|
2855
|
+
},
|
|
2856
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false},
|
|
2857
|
+
},
|
|
2858
|
+
media: {
|
|
2859
|
+
'arbitrary-main-media-key': {
|
|
2860
|
+
mediaResourceId: 'interaction-1',
|
|
2861
|
+
mType: 'mainCall',
|
|
2862
|
+
participants: ['agent-1', 'customer-1'],
|
|
2863
|
+
isHold: false,
|
|
2864
|
+
},
|
|
2865
|
+
'consult-media-1': {
|
|
2866
|
+
mediaResourceId: 'consult-media-1',
|
|
2867
|
+
mType: 'consult',
|
|
2868
|
+
participants: ['agent-2', 'agent-3'],
|
|
2869
|
+
isHold: false,
|
|
2870
|
+
},
|
|
2871
|
+
},
|
|
2872
|
+
} as any,
|
|
2873
|
+
});
|
|
2874
|
+
|
|
2875
|
+
const setupSecondaryAgentConsultingFromConference = (
|
|
2876
|
+
service: ReturnType<typeof startAgent2Machine>
|
|
2877
|
+
) => {
|
|
2296
2878
|
const conferenceTaskData = createSecondaryAgentConferenceBaseTaskData();
|
|
2297
2879
|
const consultingTaskData = createSecondaryAgentConsultingTaskData();
|
|
2298
2880
|
|
|
@@ -2339,7 +2921,10 @@ describe('Task state machine', () => {
|
|
|
2339
2921
|
setupSecondaryAgentDesktopConsultingFromConference(service);
|
|
2340
2922
|
|
|
2341
2923
|
const transferSuccessTaskData = createSecondaryAgentConsultingTaskData();
|
|
2342
|
-
service.send({
|
|
2924
|
+
service.send({
|
|
2925
|
+
type: TaskEvent.TRANSFER_CONFERENCE_SUCCESS,
|
|
2926
|
+
taskData: transferSuccessTaskData,
|
|
2927
|
+
});
|
|
2343
2928
|
|
|
2344
2929
|
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
2345
2930
|
});
|
|
@@ -2349,7 +2934,10 @@ describe('Task state machine', () => {
|
|
|
2349
2934
|
setupSecondaryAgentConsultingFromConference(service);
|
|
2350
2935
|
|
|
2351
2936
|
const transferSuccessTaskData = createSecondaryAgentConsultingTaskData();
|
|
2352
|
-
service.send({
|
|
2937
|
+
service.send({
|
|
2938
|
+
type: TaskEvent.TRANSFER_CONFERENCE_SUCCESS,
|
|
2939
|
+
taskData: transferSuccessTaskData,
|
|
2940
|
+
});
|
|
2353
2941
|
|
|
2354
2942
|
const snapshot = service.getSnapshot();
|
|
2355
2943
|
expect(snapshot.value).toBe(TaskState.TERMINATED);
|
|
@@ -2359,9 +2947,7 @@ describe('Task state machine', () => {
|
|
|
2359
2947
|
|
|
2360
2948
|
it('moves consultee to CONFERENCING when primary agent conference-transfers', () => {
|
|
2361
2949
|
const startAgent3Machine = () => {
|
|
2362
|
-
const actor = createActor(
|
|
2363
|
-
createTaskStateMachine({...createConfig(), agentId: 'agent-3'})
|
|
2364
|
-
);
|
|
2950
|
+
const actor = createActor(createTaskStateMachine({...createConfig(), agentId: 'agent-3'}));
|
|
2365
2951
|
actor.start();
|
|
2366
2952
|
|
|
2367
2953
|
return actor;
|
|
@@ -2524,7 +3110,10 @@ describe('Task state machine', () => {
|
|
|
2524
3110
|
expect(service.getSnapshot().value).toBe(TaskState.CONSULTING);
|
|
2525
3111
|
expect(service.getSnapshot().context.consultInitiator).toBe(false);
|
|
2526
3112
|
|
|
2527
|
-
service.send({
|
|
3113
|
+
service.send({
|
|
3114
|
+
type: TaskEvent.TRANSFER_CONFERENCE_SUCCESS,
|
|
3115
|
+
taskData: transferSuccessTaskData,
|
|
3116
|
+
});
|
|
2528
3117
|
expect(service.getSnapshot().value).toBe(TaskState.CONFERENCING);
|
|
2529
3118
|
});
|
|
2530
3119
|
|
|
@@ -2582,7 +3171,10 @@ describe('Task state machine', () => {
|
|
|
2582
3171
|
expect(service.getSnapshot().value).toBe(TaskState.CONFERENCING);
|
|
2583
3172
|
expect(service.getSnapshot().context.consultInitiator).toBe(false);
|
|
2584
3173
|
|
|
2585
|
-
service.send({
|
|
3174
|
+
service.send({
|
|
3175
|
+
type: TaskEvent.TRANSFER_CONFERENCE_SUCCESS,
|
|
3176
|
+
taskData: transferSuccessTaskData,
|
|
3177
|
+
});
|
|
2586
3178
|
expect(service.getSnapshot().value).toBe(TaskState.CONFERENCING);
|
|
2587
3179
|
});
|
|
2588
3180
|
|
|
@@ -2592,7 +3184,10 @@ describe('Task state machine', () => {
|
|
|
2592
3184
|
|
|
2593
3185
|
const transferSuccessTaskData = createSecondaryAgentConsultingTaskData();
|
|
2594
3186
|
service.send({type: TaskEvent.TRANSFER_CONFERENCE});
|
|
2595
|
-
service.send({
|
|
3187
|
+
service.send({
|
|
3188
|
+
type: TaskEvent.TRANSFER_CONFERENCE_SUCCESS,
|
|
3189
|
+
taskData: transferSuccessTaskData,
|
|
3190
|
+
});
|
|
2596
3191
|
|
|
2597
3192
|
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
2598
3193
|
});
|
|
@@ -2647,5 +3242,192 @@ describe('Task state machine', () => {
|
|
|
2647
3242
|
|
|
2648
3243
|
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
2649
3244
|
});
|
|
3245
|
+
|
|
3246
|
+
it('terminates secondary agent on PARTICIPANT_LEAVE while consult is initiating', () => {
|
|
3247
|
+
const service = startAgent2Machine();
|
|
3248
|
+
const conferenceTaskData = createSecondaryAgentConferenceBaseTaskData();
|
|
3249
|
+
|
|
3250
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData: conferenceTaskData});
|
|
3251
|
+
service.send({type: TaskEvent.ASSIGN, taskData: conferenceTaskData});
|
|
3252
|
+
service.send({type: TaskEvent.CONFERENCE_START, taskData: conferenceTaskData});
|
|
3253
|
+
service.send({type: TaskEvent.CONSULT, destination: 'agent-3', destinationType: 'agent'});
|
|
3254
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONSULT_INITIATING);
|
|
3255
|
+
expect(service.getSnapshot().context.taskData.interaction).toBe(
|
|
3256
|
+
conferenceTaskData.interaction
|
|
3257
|
+
);
|
|
3258
|
+
expect(service.getSnapshot().context.taskData.destAgentId).toBe('agent-3');
|
|
3259
|
+
|
|
3260
|
+
const participantLeaveEvent = {
|
|
3261
|
+
type: TaskEvent.PARTICIPANT_LEAVE,
|
|
3262
|
+
taskData: createSecondaryAgentRemovedTaskData(),
|
|
3263
|
+
} as const;
|
|
3264
|
+
expect(
|
|
3265
|
+
guards.didCurrentAgentLeaveMainInteraction({
|
|
3266
|
+
context: service.getSnapshot().context,
|
|
3267
|
+
event: participantLeaveEvent,
|
|
3268
|
+
})
|
|
3269
|
+
).toBe(true);
|
|
3270
|
+
|
|
3271
|
+
service.send(participantLeaveEvent);
|
|
3272
|
+
|
|
3273
|
+
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
3274
|
+
});
|
|
3275
|
+
|
|
3276
|
+
it('terminates secondary agent on CONSULT_END while consult is initiating', () => {
|
|
3277
|
+
const service = startAgent2Machine();
|
|
3278
|
+
const conferenceTaskData = createSecondaryAgentConferenceBaseTaskData();
|
|
3279
|
+
|
|
3280
|
+
service.send({type: TaskEvent.TASK_INCOMING, taskData: conferenceTaskData});
|
|
3281
|
+
service.send({type: TaskEvent.ASSIGN, taskData: conferenceTaskData});
|
|
3282
|
+
service.send({type: TaskEvent.CONFERENCE_START, taskData: conferenceTaskData});
|
|
3283
|
+
service.send({type: TaskEvent.CONSULT, destination: 'agent-3', destinationType: 'agent'});
|
|
3284
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONSULT_INITIATING);
|
|
3285
|
+
|
|
3286
|
+
const consultEndEvent = {
|
|
3287
|
+
type: TaskEvent.CONSULT_END,
|
|
3288
|
+
taskData: createSecondaryAgentRemovedTaskData(),
|
|
3289
|
+
} as const;
|
|
3290
|
+
expect(
|
|
3291
|
+
guards.didCurrentAgentLeaveMainInteraction({
|
|
3292
|
+
context: service.getSnapshot().context,
|
|
3293
|
+
event: consultEndEvent,
|
|
3294
|
+
})
|
|
3295
|
+
).toBe(true);
|
|
3296
|
+
|
|
3297
|
+
service.send(consultEndEvent);
|
|
3298
|
+
|
|
3299
|
+
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
3300
|
+
});
|
|
3301
|
+
|
|
3302
|
+
it('terminates a consulting secondary initiator when CONSULT_END removes it from mainCall', () => {
|
|
3303
|
+
const service = startAgent2Machine();
|
|
3304
|
+
setupSecondaryAgentConsultingFromConference(service);
|
|
3305
|
+
|
|
3306
|
+
service.send({
|
|
3307
|
+
type: TaskEvent.CONSULT_END,
|
|
3308
|
+
taskData: createSecondaryAgentRemovedTaskData(),
|
|
3309
|
+
});
|
|
3310
|
+
|
|
3311
|
+
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
3312
|
+
expect(service.getSnapshot().context.consultInitiator).toBe(false);
|
|
3313
|
+
expect(service.getSnapshot().context.consultDestinationAgentJoined).toBe(false);
|
|
3314
|
+
});
|
|
3315
|
+
|
|
3316
|
+
it('does not infer departure from a partial CONSULT_END payload', () => {
|
|
3317
|
+
const service = startAgent2Machine();
|
|
3318
|
+
setupSecondaryAgentConsultingFromConference(service);
|
|
3319
|
+
const partialTaskData = {
|
|
3320
|
+
...createTaskData({agentId: 'agent-2', interactionId: 'interaction-1'}),
|
|
3321
|
+
interaction: {
|
|
3322
|
+
state: 'conference',
|
|
3323
|
+
interactionId: 'interaction-1',
|
|
3324
|
+
mainInteractionId: 'interaction-1',
|
|
3325
|
+
},
|
|
3326
|
+
} as any;
|
|
3327
|
+
|
|
3328
|
+
const consultEndEvent = {type: TaskEvent.CONSULT_END, taskData: partialTaskData} as const;
|
|
3329
|
+
expect(service.getSnapshot().context.consultInitiator).toBe(true);
|
|
3330
|
+
expect(
|
|
3331
|
+
guards.didCurrentAgentLeaveMainInteraction({
|
|
3332
|
+
context: service.getSnapshot().context,
|
|
3333
|
+
event: consultEndEvent,
|
|
3334
|
+
})
|
|
3335
|
+
).toBe(false);
|
|
3336
|
+
|
|
3337
|
+
service.send(consultEndEvent);
|
|
3338
|
+
|
|
3339
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONNECTED);
|
|
3340
|
+
});
|
|
3341
|
+
|
|
3342
|
+
it('emits consult-end and task-end when AgentConsultEnded terminates the consulted agent', () => {
|
|
3343
|
+
const emitTaskConsultEnd = jest.fn();
|
|
3344
|
+
const emitTaskEnd = jest.fn();
|
|
3345
|
+
const cleanupResources = jest.fn();
|
|
3346
|
+
const service = createActor(
|
|
3347
|
+
createTaskStateMachine(
|
|
3348
|
+
{...createConfig(), agentId: 'agent-3'},
|
|
3349
|
+
{
|
|
3350
|
+
actions: {emitTaskConsultEnd, emitTaskEnd, cleanupResources},
|
|
3351
|
+
}
|
|
3352
|
+
)
|
|
3353
|
+
);
|
|
3354
|
+
service.start();
|
|
3355
|
+
|
|
3356
|
+
const consultingTaskData = createTaskData({
|
|
3357
|
+
agentId: 'agent-3',
|
|
3358
|
+
isConsulted: true,
|
|
3359
|
+
interactionId: 'consult-child',
|
|
3360
|
+
interaction: {
|
|
3361
|
+
state: 'consulting',
|
|
3362
|
+
owner: 'agent-1',
|
|
3363
|
+
interactionId: 'consult-child',
|
|
3364
|
+
mainInteractionId: 'interaction-1',
|
|
3365
|
+
participants: {
|
|
3366
|
+
'agent-1': {id: 'agent-1', pType: 'Agent', hasLeft: false},
|
|
3367
|
+
'agent-2': {
|
|
3368
|
+
id: 'agent-2',
|
|
3369
|
+
pType: 'Agent',
|
|
3370
|
+
hasLeft: false,
|
|
3371
|
+
consultState: 'consulting',
|
|
3372
|
+
},
|
|
3373
|
+
'agent-3': {
|
|
3374
|
+
id: 'agent-3',
|
|
3375
|
+
pType: 'Agent',
|
|
3376
|
+
hasLeft: false,
|
|
3377
|
+
isConsulted: true,
|
|
3378
|
+
consultState: 'consulting',
|
|
3379
|
+
},
|
|
3380
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false},
|
|
3381
|
+
},
|
|
3382
|
+
media: {
|
|
3383
|
+
'interaction-1': {
|
|
3384
|
+
mediaResourceId: 'interaction-1',
|
|
3385
|
+
mType: 'mainCall',
|
|
3386
|
+
participants: ['agent-1', 'agent-2', 'customer-1'],
|
|
3387
|
+
isHold: true,
|
|
3388
|
+
},
|
|
3389
|
+
'consult-child': {
|
|
3390
|
+
mediaResourceId: 'consult-child',
|
|
3391
|
+
mType: 'consult',
|
|
3392
|
+
participants: ['agent-2', 'agent-3'],
|
|
3393
|
+
isHold: false,
|
|
3394
|
+
},
|
|
3395
|
+
},
|
|
3396
|
+
} as any,
|
|
3397
|
+
});
|
|
3398
|
+
service.send({type: TaskEvent.HYDRATE, taskData: consultingTaskData});
|
|
3399
|
+
expect(service.getSnapshot().value).toBe(TaskState.CONSULTING);
|
|
3400
|
+
|
|
3401
|
+
const consultEndedTaskData = createTaskData({
|
|
3402
|
+
...consultingTaskData,
|
|
3403
|
+
type: 'AgentConsultEnded' as any,
|
|
3404
|
+
interaction: {
|
|
3405
|
+
...consultingTaskData.interaction,
|
|
3406
|
+
state: 'conference',
|
|
3407
|
+
participants: {
|
|
3408
|
+
'agent-1': {id: 'agent-1', pType: 'Agent', hasLeft: false},
|
|
3409
|
+
'agent-2': {id: 'agent-2', pType: 'Agent', hasLeft: false},
|
|
3410
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false},
|
|
3411
|
+
},
|
|
3412
|
+
media: {
|
|
3413
|
+
'interaction-1': {
|
|
3414
|
+
mediaResourceId: 'interaction-1',
|
|
3415
|
+
mType: 'mainCall',
|
|
3416
|
+
participants: ['agent-1', 'agent-2', 'customer-1'],
|
|
3417
|
+
isHold: false,
|
|
3418
|
+
},
|
|
3419
|
+
},
|
|
3420
|
+
} as any,
|
|
3421
|
+
});
|
|
3422
|
+
|
|
3423
|
+
service.send({type: TaskEvent.CONSULT_END, taskData: consultEndedTaskData});
|
|
3424
|
+
|
|
3425
|
+
expect(service.getSnapshot().value).toBe(TaskState.TERMINATED);
|
|
3426
|
+
expect(emitTaskConsultEnd).toHaveBeenCalledTimes(1);
|
|
3427
|
+
expect(emitTaskEnd).toHaveBeenCalledTimes(1);
|
|
3428
|
+
expect(cleanupResources).toHaveBeenCalledTimes(1);
|
|
3429
|
+
expect(service.getSnapshot().context.consultDestinationAgentJoined).toBe(false);
|
|
3430
|
+
expect(service.getSnapshot().context.consultInitiator).toBe(false);
|
|
3431
|
+
});
|
|
2650
3432
|
});
|
|
2651
3433
|
});
|