@webex/contact-center 3.12.0-task-refactor.5 → 3.12.0-task-refactor.6
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/services/task/TaskUtils.js +8 -6
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +71 -13
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +85 -13
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +35 -0
- package/dist/services/task/state-machine/guards.js.map +1 -1
- package/dist/services/task/state-machine/uiControlsComputer.js +69 -7
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1 -1
- package/dist/services/task/voice/Voice.js.map +1 -1
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +60 -8
- package/dist/types/services/task/state-machine/guards.d.ts +5 -0
- package/dist/webex.js +1 -1
- package/package.json +1 -1
- package/src/services/task/TaskUtils.ts +8 -6
- package/src/services/task/state-machine/TaskStateMachine.ts +94 -15
- package/src/services/task/state-machine/actions.ts +148 -24
- package/src/services/task/state-machine/guards.ts +46 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +150 -9
- package/src/services/task/voice/Voice.ts +4 -1
- package/test/unit/spec/services/WebCallingService.ts +7 -1
- package/test/unit/spec/services/task/TaskUtils.ts +16 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +512 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +88 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +929 -0
- package/test/unit/spec/services/task/voice/Voice.ts +20 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -144,16 +144,27 @@ function computeVoiceInteractionUIControls(
|
|
|
144
144
|
Boolean(selfAgentId) &&
|
|
145
145
|
Boolean(mainCallId) &&
|
|
146
146
|
Boolean(interaction?.media?.[mainCallId]?.participants?.includes(selfAgentId as string));
|
|
147
|
+
const consultMedia = Object.values(interaction?.media ?? {}).find(
|
|
148
|
+
(media: any) =>
|
|
149
|
+
media?.mediaResourceId === taskData?.consultMediaResourceId || media?.mType === 'consult'
|
|
150
|
+
) as {participants?: string[]} | undefined;
|
|
151
|
+
const selfParticipant = selfAgentId ? interaction?.participants?.[selfAgentId] : null;
|
|
152
|
+
const selfInConsultCall =
|
|
153
|
+
Boolean(selfAgentId) && Boolean(consultMedia?.participants?.includes(selfAgentId as string));
|
|
147
154
|
const conferenceActive = isConferencing || conferenceFromBackend || consultFromConference;
|
|
148
155
|
// Treat consult initiator as "in conference" even if mainCall participant list lags while consulting.
|
|
149
156
|
const inConference = conferenceActive && (isConferencing || selfInMainCall || consultInitiator);
|
|
150
157
|
|
|
151
158
|
// Check if this is a consulted agent (must be after isConsulting is computed).
|
|
152
|
-
const isSoleAgentOnCall =
|
|
159
|
+
const isSoleAgentOnCall =
|
|
160
|
+
participantCount <= 1 && selfInMainCall && !isConsulting && !inConference;
|
|
153
161
|
const isConsulted =
|
|
154
162
|
inConference || isSoleAgentOnCall
|
|
155
163
|
? false
|
|
156
|
-
: getIsConsultedAgentForControls(taskData, context, isConsulting)
|
|
164
|
+
: getIsConsultedAgentForControls(taskData, context, isConsulting) ||
|
|
165
|
+
(!consultInitiator &&
|
|
166
|
+
(selfParticipant?.isConsulted === true ||
|
|
167
|
+
selfParticipant?.consultState === 'consulting'));
|
|
157
168
|
|
|
158
169
|
// Active call = can perform call operations
|
|
159
170
|
const isActive =
|
|
@@ -173,12 +184,91 @@ function computeVoiceInteractionUIControls(
|
|
|
173
184
|
taskData?.consultMediaResourceId ||
|
|
174
185
|
Object.values(interaction?.media ?? {}).some((media: any) => media?.mType === 'consult')
|
|
175
186
|
);
|
|
187
|
+
const selfConsultPendingOnConsultMedia =
|
|
188
|
+
selfParticipant?.consultState === 'consultInitiated' &&
|
|
189
|
+
!taskData?.isConsulted &&
|
|
190
|
+
hasConsultMedia;
|
|
191
|
+
const ownerParticipant = interaction?.owner
|
|
192
|
+
? interaction.participants?.[interaction.owner]
|
|
193
|
+
: undefined;
|
|
194
|
+
const otherAgentConsultInProgress = Boolean(
|
|
195
|
+
interaction?.participants &&
|
|
196
|
+
Object.values(interaction.participants).some((participant: any) => {
|
|
197
|
+
if (!participant || participant.hasLeft) return false;
|
|
198
|
+
if (participant.id === selfAgentId) return false;
|
|
199
|
+
if (participant.pType !== 'AGENT') return false;
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
participant.consultState === 'consultInitiated' ||
|
|
203
|
+
participant.consultState === 'consultReserved' ||
|
|
204
|
+
participant.consultState === 'consulting' ||
|
|
205
|
+
participant.currentState === 'consulting'
|
|
206
|
+
);
|
|
207
|
+
})
|
|
208
|
+
);
|
|
209
|
+
const isHydratedConferenceConsultPending =
|
|
210
|
+
inConference && selfConsultPendingOnConsultMedia && !consultDestinationAgentJoined;
|
|
176
211
|
const hasParallelConsultLeg =
|
|
177
212
|
consultOwnedBySelf &&
|
|
178
213
|
!isConsulting &&
|
|
179
214
|
!isConsulted &&
|
|
180
215
|
(consultInProgress || consultCallHeld || hasConsultMedia);
|
|
216
|
+
const activeLegForConferenceConsult = consultCallHeld ? 'main' : 'consult';
|
|
217
|
+
const isCurrentLegActive = currentLeg === activeLegForConferenceConsult;
|
|
218
|
+
const isConferenceConsultTransferContext =
|
|
219
|
+
inConference && consultInitiator && hasConsultMedia && isConsultDestinationReady;
|
|
181
220
|
const consultLegOnHold = isConsulting && consultCallHeld;
|
|
221
|
+
const callProcessingDetails = interaction?.callProcessingDetails as
|
|
222
|
+
| {conferenceHoldParticipant?: boolean | string}
|
|
223
|
+
| undefined;
|
|
224
|
+
const conferenceHoldParticipant =
|
|
225
|
+
callProcessingDetails?.conferenceHoldParticipant === true ||
|
|
226
|
+
callProcessingDetails?.conferenceHoldParticipant === 'true';
|
|
227
|
+
const postDeclineHeldMainLeg =
|
|
228
|
+
consultInitiator &&
|
|
229
|
+
!consultDestinationAgentJoined &&
|
|
230
|
+
isHeld &&
|
|
231
|
+
inConference &&
|
|
232
|
+
conferenceHoldParticipant;
|
|
233
|
+
const postConsultCompletedHeldMainLeg =
|
|
234
|
+
selfParticipant?.consultState === 'consultCompleted' && isHeld && inConference && !isConsulting;
|
|
235
|
+
const nonOwnerPostConsultCompletedHeldMainLeg =
|
|
236
|
+
isHeld &&
|
|
237
|
+
inConference &&
|
|
238
|
+
!isConsulting &&
|
|
239
|
+
!consultInitiator &&
|
|
240
|
+
Boolean(selfAgentId) &&
|
|
241
|
+
Boolean(interaction?.owner) &&
|
|
242
|
+
selfAgentId !== interaction?.owner &&
|
|
243
|
+
ownerParticipant?.consultState === 'consultCompleted';
|
|
244
|
+
const isConsultPendingBeforeJoin =
|
|
245
|
+
selfParticipant?.consultState === 'consultInitiated' && !consultDestinationAgentJoined;
|
|
246
|
+
const hideExitConferenceWhileConsultPending =
|
|
247
|
+
currentLeg === 'main' &&
|
|
248
|
+
inConference &&
|
|
249
|
+
isConsultPendingBeforeJoin &&
|
|
250
|
+
(consultFromConference ||
|
|
251
|
+
consultInitiator ||
|
|
252
|
+
taskData?.type === 'AgentConsultCreated' ||
|
|
253
|
+
consultInProgress ||
|
|
254
|
+
isConsulting);
|
|
255
|
+
const hideExitConferenceDuringActiveConsultFromConference =
|
|
256
|
+
inConference &&
|
|
257
|
+
consultInitiator &&
|
|
258
|
+
consultDestinationAgentJoined &&
|
|
259
|
+
(isConsulting ||
|
|
260
|
+
taskData?.type === 'AgentConsulting' ||
|
|
261
|
+
selfParticipant?.consultState === 'consulting');
|
|
262
|
+
const forceHeldPostConsultControls =
|
|
263
|
+
!hideExitConferenceWhileConsultPending &&
|
|
264
|
+
(postDeclineHeldMainLeg || postConsultCompletedHeldMainLeg);
|
|
265
|
+
const selfOnConsultLeg =
|
|
266
|
+
selfParticipant?.consultState === 'consulting' ||
|
|
267
|
+
selfParticipant?.currentState === 'consulting';
|
|
268
|
+
const showMainLegConferenceControlsDuringConsult =
|
|
269
|
+
currentLeg === 'main' && inConference && consultInProgress && !selfOnConsultLeg;
|
|
270
|
+
const allowHeldMainLegControlsForNonInitiator =
|
|
271
|
+
showMainLegConferenceControlsDuringConsult && !isHydratedConferenceConsultPending;
|
|
182
272
|
|
|
183
273
|
return {
|
|
184
274
|
// Accept/Decline: Voice tasks in offered state
|
|
@@ -198,6 +288,7 @@ function computeVoiceInteractionUIControls(
|
|
|
198
288
|
// Hold: visible in connected/held/conference, disabled in conference/consulting
|
|
199
289
|
hold: (() => {
|
|
200
290
|
if (!hasFullControls) return DISABLED;
|
|
291
|
+
if (forceHeldPostConsultControls) return VISIBLE_ENABLED;
|
|
201
292
|
if (consultOwnedBySelf && (isConsulting || hasParallelConsultLeg || consultCallHeld)) {
|
|
202
293
|
return DISABLED;
|
|
203
294
|
}
|
|
@@ -216,6 +307,7 @@ function computeVoiceInteractionUIControls(
|
|
|
216
307
|
mute: (() => {
|
|
217
308
|
if (!isWebrtc) return DISABLED;
|
|
218
309
|
if (isWrappingUp) return DISABLED;
|
|
310
|
+
if (currentLeg === 'consult' && !selfInConsultCall) return DISABLED;
|
|
219
311
|
if (isConsulting) return VISIBLE_ENABLED;
|
|
220
312
|
|
|
221
313
|
if (isConnected || isHeld || isConferencing) {
|
|
@@ -229,6 +321,9 @@ function computeVoiceInteractionUIControls(
|
|
|
229
321
|
|
|
230
322
|
// End: varies by state; during consulting only on main leg (consult held)
|
|
231
323
|
end: (() => {
|
|
324
|
+
if (allowHeldMainLegControlsForNonInitiator) return VISIBLE_ENABLED;
|
|
325
|
+
if (showMainLegConferenceControlsDuringConsult) return VISIBLE_DISABLED;
|
|
326
|
+
if (isHydratedConferenceConsultPending && currentLeg === 'main') return VISIBLE_DISABLED;
|
|
232
327
|
if (!config.isEndTaskEnabled) return DISABLED;
|
|
233
328
|
if (hasParallelConsultLeg) {
|
|
234
329
|
return isConnected && isEpDnConsult ? VISIBLE_ENABLED : VISIBLE_DISABLED;
|
|
@@ -242,6 +337,7 @@ function computeVoiceInteractionUIControls(
|
|
|
242
337
|
|
|
243
338
|
if (inConference) {
|
|
244
339
|
if (isConsulted) return DISABLED;
|
|
340
|
+
if (forceHeldPostConsultControls) return VISIBLE_DISABLED;
|
|
245
341
|
|
|
246
342
|
if (consultInProgress) return VISIBLE_DISABLED;
|
|
247
343
|
|
|
@@ -255,6 +351,11 @@ function computeVoiceInteractionUIControls(
|
|
|
255
351
|
|
|
256
352
|
// Transfer: connected/held/conference
|
|
257
353
|
transfer: (() => {
|
|
354
|
+
if (isHydratedConferenceConsultPending) return VISIBLE_DISABLED;
|
|
355
|
+
if (isConferenceConsultTransferContext && currentLeg === 'main' && isCurrentLegActive) {
|
|
356
|
+
return DISABLED;
|
|
357
|
+
}
|
|
358
|
+
if (inConference && isConsulting && consultInitiator) return DISABLED;
|
|
258
359
|
if (hasParallelConsultLeg) {
|
|
259
360
|
if (!customerPresent) return DISABLED;
|
|
260
361
|
if (state === TaskState.CONNECTED) return VISIBLE_ENABLED;
|
|
@@ -282,6 +383,7 @@ function computeVoiceInteractionUIControls(
|
|
|
282
383
|
consult: (() => {
|
|
283
384
|
const isConnectedOrHeld = state === TaskState.CONNECTED || state === TaskState.HELD;
|
|
284
385
|
|
|
386
|
+
if (inConference && nonOwnerPostConsultCompletedHeldMainLeg) return VISIBLE_DISABLED;
|
|
285
387
|
if (hasParallelConsultLeg) return DISABLED;
|
|
286
388
|
if (!hasFullControls || !(isConnectedOrHeld || inConference)) {
|
|
287
389
|
return DISABLED;
|
|
@@ -293,7 +395,11 @@ function computeVoiceInteractionUIControls(
|
|
|
293
395
|
if (participantCount <= 1) return VISIBLE_DISABLED;
|
|
294
396
|
// Real conference: consult enabled if conditions met
|
|
295
397
|
const canFromConference =
|
|
296
|
-
!maxParticipants &&
|
|
398
|
+
!maxParticipants &&
|
|
399
|
+
customerPresent &&
|
|
400
|
+
!consultInProgress &&
|
|
401
|
+
!otherAgentConsultInProgress &&
|
|
402
|
+
!isConsulting;
|
|
297
403
|
|
|
298
404
|
return {isVisible: true, isEnabled: canFromConference};
|
|
299
405
|
}
|
|
@@ -339,6 +445,7 @@ function computeVoiceInteractionUIControls(
|
|
|
339
445
|
// Conference: during consulting, enabled on both legs when agent joined
|
|
340
446
|
// Label changes based on leg: "Conference" on main leg, "Merge" on consult leg
|
|
341
447
|
conference: (() => {
|
|
448
|
+
if (isHydratedConferenceConsultPending && currentLeg === 'main') return VISIBLE_DISABLED;
|
|
342
449
|
if (hasParallelConsultLeg) {
|
|
343
450
|
if (!customerPresent) return DISABLED;
|
|
344
451
|
if (state === TaskState.CONNECTED) {
|
|
@@ -361,9 +468,15 @@ function computeVoiceInteractionUIControls(
|
|
|
361
468
|
|
|
362
469
|
// ExitConference: in conference with multiple agents in main call
|
|
363
470
|
exitConference: (() => {
|
|
471
|
+
if (hideExitConferenceWhileConsultPending) return DISABLED;
|
|
472
|
+
if (allowHeldMainLegControlsForNonInitiator) return VISIBLE_ENABLED;
|
|
473
|
+
if (showMainLegConferenceControlsDuringConsult) return VISIBLE_DISABLED;
|
|
474
|
+
if (hideExitConferenceDuringActiveConsultFromConference) return DISABLED;
|
|
475
|
+
if (forceHeldPostConsultControls) return VISIBLE_DISABLED;
|
|
364
476
|
if (isConsulted && !isConferencing) return DISABLED;
|
|
365
477
|
if (!inConference) return DISABLED;
|
|
366
478
|
if (participantCount <= 1) return DISABLED;
|
|
479
|
+
if (consultInProgress) return VISIBLE_DISABLED;
|
|
367
480
|
const consultingFromConference = consultInitiator && isConsulting && conferenceFromBackend;
|
|
368
481
|
|
|
369
482
|
return consultingFromConference ? VISIBLE_DISABLED : VISIBLE_ENABLED;
|
|
@@ -371,8 +484,19 @@ function computeVoiceInteractionUIControls(
|
|
|
371
484
|
|
|
372
485
|
// TransferConference: in conference with active consult, owner consulting from conference
|
|
373
486
|
transferConference: (() => {
|
|
374
|
-
if (
|
|
375
|
-
|
|
487
|
+
if (isConferenceConsultTransferContext && !isCurrentLegActive) return VISIBLE_DISABLED;
|
|
488
|
+
const consultLegTransferAvailable =
|
|
489
|
+
currentLeg === 'consult' && inConference && consultInitiator && hasConsultMedia;
|
|
490
|
+
const selfConsultingOnParticipantState = selfParticipant?.consultState === 'consulting';
|
|
491
|
+
const conferenceTransferAvailable =
|
|
492
|
+
consultLegTransferAvailable ||
|
|
493
|
+
(inConference &&
|
|
494
|
+
consultInitiator &&
|
|
495
|
+
hasConsultMedia &&
|
|
496
|
+
(isConsulting || consultInProgress || selfConsultingOnParticipantState));
|
|
497
|
+
if (consultLegOnHold) return DISABLED;
|
|
498
|
+
if (hasParallelConsultLeg && !conferenceTransferAvailable) return DISABLED;
|
|
499
|
+
if (!conferenceTransferAvailable && (!inConference || !isConsulting)) return DISABLED;
|
|
376
500
|
if (!consultInitiator || isConsulted) return DISABLED;
|
|
377
501
|
|
|
378
502
|
return isConsultDestinationReady ? VISIBLE_ENABLED : VISIBLE_DISABLED;
|
|
@@ -380,6 +504,7 @@ function computeVoiceInteractionUIControls(
|
|
|
380
504
|
|
|
381
505
|
// MergeToConference: mirrors conference control, enabled on both legs
|
|
382
506
|
mergeToConference: (() => {
|
|
507
|
+
if (isHydratedConferenceConsultPending && currentLeg === 'consult') return VISIBLE_DISABLED;
|
|
383
508
|
if (!isConsulting || !consultInitiator) return DISABLED;
|
|
384
509
|
if (!customerPresent) return VISIBLE_DISABLED;
|
|
385
510
|
if (consultLegOnHold) return VISIBLE_DISABLED;
|
|
@@ -389,6 +514,7 @@ function computeVoiceInteractionUIControls(
|
|
|
389
514
|
|
|
390
515
|
// Switch: visible only on the currently active leg
|
|
391
516
|
switch: (() => {
|
|
517
|
+
if (isHydratedConferenceConsultPending && currentLeg === 'consult') return VISIBLE_DISABLED;
|
|
392
518
|
if (!customerPresent && hasParallelConsultLeg) return DISABLED;
|
|
393
519
|
if (currentLeg === 'consult') {
|
|
394
520
|
if (!isConsulting || !consultInitiator || consultCallHeld) return DISABLED;
|
|
@@ -472,10 +598,18 @@ function getVoiceLegState(
|
|
|
472
598
|
taskData?.consultMediaResourceId ||
|
|
473
599
|
Object.values(interaction?.media ?? {}).some((media: any) => media?.mType === 'consult')
|
|
474
600
|
);
|
|
601
|
+
const selfParticipant = selfAgentId ? interaction?.participants?.[selfAgentId] : null;
|
|
602
|
+
const selfConsultPendingOnConsultMedia =
|
|
603
|
+
selfParticipant?.consultState === 'consultInitiated' &&
|
|
604
|
+
!taskData?.isConsulted &&
|
|
605
|
+
hasConsultMedia;
|
|
606
|
+
const selfConsultingOnConsultMedia =
|
|
607
|
+
selfParticipant?.consultState === 'consulting' && hasConsultMedia;
|
|
475
608
|
const hasConsultLeg = Boolean(
|
|
476
|
-
|
|
477
|
-
!taskData?.isConsulted
|
|
478
|
-
|
|
609
|
+
!interaction?.isTerminated &&
|
|
610
|
+
((consultOwnedBySelf && !taskData?.isConsulted) ||
|
|
611
|
+
selfConsultingOnConsultMedia ||
|
|
612
|
+
selfConsultPendingOnConsultMedia) &&
|
|
479
613
|
(consultInProgress || isConsultingState || context.consultCallHeld || hasConsultMedia)
|
|
480
614
|
);
|
|
481
615
|
|
|
@@ -488,10 +622,17 @@ function getVoiceLegState(
|
|
|
488
622
|
};
|
|
489
623
|
}
|
|
490
624
|
|
|
625
|
+
let mainState = TaskState.HELD;
|
|
626
|
+
if (currentState === TaskState.CONFERENCING) {
|
|
627
|
+
mainState = TaskState.CONFERENCING;
|
|
628
|
+
} else if (context.consultCallHeld) {
|
|
629
|
+
mainState = TaskState.CONNECTED;
|
|
630
|
+
}
|
|
631
|
+
|
|
491
632
|
return {
|
|
492
633
|
hasConsultLeg: true,
|
|
493
634
|
activeLeg: context.consultCallHeld ? 'main' : 'consult',
|
|
494
|
-
mainState
|
|
635
|
+
mainState,
|
|
495
636
|
consultState: isConsultingState ? currentState : TaskState.CONSULTING,
|
|
496
637
|
};
|
|
497
638
|
}
|
|
@@ -150,7 +150,10 @@ export default class Voice extends Task implements IVoice {
|
|
|
150
150
|
});
|
|
151
151
|
throw error;
|
|
152
152
|
}
|
|
153
|
-
} else if (
|
|
153
|
+
} else if (
|
|
154
|
+
!state.matches(TaskState.HELD) &&
|
|
155
|
+
!(state.matches(TaskState.CONFERENCING) && mediaHoldState === true)
|
|
156
|
+
) {
|
|
154
157
|
const error = new Error(`Cannot resume call in current state: ${currentState}`);
|
|
155
158
|
LoggerProxy.error('Resume operation not allowed', {
|
|
156
159
|
module: CC_FILE,
|
|
@@ -200,11 +200,17 @@ describe('WebCallingService', () => {
|
|
|
200
200
|
|
|
201
201
|
it('should reject if registration times out', async () => {
|
|
202
202
|
line = callingClient.getLines().line1 as ILine;
|
|
203
|
+
jest.spyOn(global, 'setTimeout').mockImplementation(((handler: TimerHandler) => {
|
|
204
|
+
if (typeof handler === 'function') {
|
|
205
|
+
handler();
|
|
206
|
+
}
|
|
207
|
+
return 0 as unknown as NodeJS.Timeout;
|
|
208
|
+
}) as typeof setTimeout);
|
|
203
209
|
|
|
204
210
|
const promise = webRTCCalling.registerWebCallingLine();
|
|
205
211
|
|
|
206
212
|
await expect(promise).rejects.toThrow('WebCallingService Registration timed out');
|
|
207
|
-
}
|
|
213
|
+
});
|
|
208
214
|
|
|
209
215
|
it('should handle incoming calls', async () => {
|
|
210
216
|
line = callingClient.getLines().line1 as ILine;
|
|
@@ -450,6 +450,14 @@ describe('TaskUtils', () => {
|
|
|
450
450
|
expect(getIsCustomerInCall(interaction, interactionId)).toBe(true);
|
|
451
451
|
});
|
|
452
452
|
|
|
453
|
+
it('getIsCustomerInCall returns false when participants map is missing', () => {
|
|
454
|
+
const interaction = createInteraction(
|
|
455
|
+
{[interactionId]: {mType: 'mainCall', participants: ['c1']}},
|
|
456
|
+
undefined
|
|
457
|
+
);
|
|
458
|
+
expect(getIsCustomerInCall(interaction, interactionId)).toBe(false);
|
|
459
|
+
});
|
|
460
|
+
|
|
453
461
|
it('getConferenceParticipantsCount counts active agents only', () => {
|
|
454
462
|
const interaction = createInteraction(
|
|
455
463
|
{[interactionId]: {mType: 'mainCall', participants: ['a1', 'a2', 'c1']}},
|
|
@@ -458,6 +466,14 @@ describe('TaskUtils', () => {
|
|
|
458
466
|
expect(getConferenceParticipantsCount(interaction, interactionId)).toBe(2);
|
|
459
467
|
});
|
|
460
468
|
|
|
469
|
+
it('getConferenceParticipantsCount returns 0 when participants map is missing', () => {
|
|
470
|
+
const interaction = createInteraction(
|
|
471
|
+
{[interactionId]: {mType: 'mainCall', participants: ['a1', 'a2', 'c1']}},
|
|
472
|
+
undefined
|
|
473
|
+
);
|
|
474
|
+
expect(getConferenceParticipantsCount(interaction, interactionId)).toBe(0);
|
|
475
|
+
});
|
|
476
|
+
|
|
461
477
|
it('isSecondaryAgent returns true for consult with parentInteractionId', () => {
|
|
462
478
|
const interaction = createInteraction();
|
|
463
479
|
interaction.callProcessingDetails = {relationshipType: 'consult', parentInteractionId: 'parent-456'};
|