@webex/plugin-meetings 3.8.0-web-workers-keepalive.1 → 3.8.1-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +70 -6
  3. package/dist/breakouts/index.js.map +1 -1
  4. package/dist/common/errors/webex-errors.js +12 -2
  5. package/dist/common/errors/webex-errors.js.map +1 -1
  6. package/dist/config.js +4 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/constants.js +22 -123
  9. package/dist/constants.js.map +1 -1
  10. package/dist/controls-options-manager/enums.js +2 -0
  11. package/dist/controls-options-manager/enums.js.map +1 -1
  12. package/dist/controls-options-manager/types.js.map +1 -1
  13. package/dist/controls-options-manager/util.js +52 -0
  14. package/dist/controls-options-manager/util.js.map +1 -1
  15. package/dist/interpretation/index.js +1 -1
  16. package/dist/interpretation/siLanguage.js +1 -1
  17. package/dist/locus-info/controlsUtils.js +30 -10
  18. package/dist/locus-info/controlsUtils.js.map +1 -1
  19. package/dist/locus-info/index.js +83 -12
  20. package/dist/locus-info/index.js.map +1 -1
  21. package/dist/locus-info/selfUtils.js +432 -418
  22. package/dist/locus-info/selfUtils.js.map +1 -1
  23. package/dist/media/index.js +17 -17
  24. package/dist/media/index.js.map +1 -1
  25. package/dist/media/properties.js +94 -6
  26. package/dist/media/properties.js.map +1 -1
  27. package/dist/meeting/brbState.js +9 -2
  28. package/dist/meeting/brbState.js.map +1 -1
  29. package/dist/meeting/in-meeting-actions.js +17 -1
  30. package/dist/meeting/in-meeting-actions.js.map +1 -1
  31. package/dist/meeting/index.js +568 -328
  32. package/dist/meeting/index.js.map +1 -1
  33. package/dist/meeting/locusMediaRequest.js +0 -17
  34. package/dist/meeting/locusMediaRequest.js.map +1 -1
  35. package/dist/meeting/muteState.js +4 -4
  36. package/dist/meeting/muteState.js.map +1 -1
  37. package/dist/meeting/request.js +30 -0
  38. package/dist/meeting/request.js.map +1 -1
  39. package/dist/meeting/request.type.js.map +1 -1
  40. package/dist/meeting/util.js +9 -1
  41. package/dist/meeting/util.js.map +1 -1
  42. package/dist/meeting-info/meeting-info-v2.js +19 -13
  43. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  44. package/dist/meeting-info/utilv2.js +5 -1
  45. package/dist/meeting-info/utilv2.js.map +1 -1
  46. package/dist/meetings/index.js +76 -0
  47. package/dist/meetings/index.js.map +1 -1
  48. package/dist/meetings/util.js +14 -0
  49. package/dist/meetings/util.js.map +1 -1
  50. package/dist/member/index.js +45 -9
  51. package/dist/member/index.js.map +1 -1
  52. package/dist/member/types.js +3 -0
  53. package/dist/member/types.js.map +1 -1
  54. package/dist/member/util.js +335 -356
  55. package/dist/member/util.js.map +1 -1
  56. package/dist/members/collection.js.map +1 -1
  57. package/dist/members/index.js +137 -29
  58. package/dist/members/index.js.map +1 -1
  59. package/dist/members/request.js +38 -0
  60. package/dist/members/request.js.map +1 -1
  61. package/dist/members/util.js +36 -1
  62. package/dist/members/util.js.map +1 -1
  63. package/dist/metrics/constants.js +1 -0
  64. package/dist/metrics/constants.js.map +1 -1
  65. package/dist/reachability/clusterReachability.js +23 -31
  66. package/dist/reachability/clusterReachability.js.map +1 -1
  67. package/dist/reachability/index.js +42 -2
  68. package/dist/reachability/index.js.map +1 -1
  69. package/dist/reconnection-manager/index.js +2 -2
  70. package/dist/reconnection-manager/index.js.map +1 -1
  71. package/dist/roap/index.js.map +1 -1
  72. package/dist/roap/turnDiscovery.js +45 -27
  73. package/dist/roap/turnDiscovery.js.map +1 -1
  74. package/dist/roap/types.js +17 -0
  75. package/dist/roap/types.js.map +1 -0
  76. package/dist/types/common/errors/webex-errors.d.ts +7 -1
  77. package/dist/types/config.d.ts +2 -0
  78. package/dist/types/constants.d.ts +15 -85
  79. package/dist/types/controls-options-manager/enums.d.ts +3 -1
  80. package/dist/types/controls-options-manager/types.d.ts +7 -1
  81. package/dist/types/locus-info/index.d.ts +3 -3
  82. package/dist/types/locus-info/selfUtils.d.ts +216 -1
  83. package/dist/types/media/properties.d.ts +15 -0
  84. package/dist/types/meeting/in-meeting-actions.d.ts +16 -0
  85. package/dist/types/meeting/index.d.ts +35 -1
  86. package/dist/types/meeting/muteState.d.ts +0 -1
  87. package/dist/types/meeting/request.d.ts +12 -1
  88. package/dist/types/meeting/request.type.d.ts +6 -0
  89. package/dist/types/meeting/util.d.ts +3 -1
  90. package/dist/types/meeting-info/meeting-info-v2.d.ts +2 -1
  91. package/dist/types/meetings/index.d.ts +28 -0
  92. package/dist/types/member/index.d.ts +20 -6
  93. package/dist/types/member/types.d.ts +73 -14
  94. package/dist/types/member/util.d.ts +156 -1
  95. package/dist/types/members/collection.d.ts +6 -5
  96. package/dist/types/members/index.d.ts +32 -43
  97. package/dist/types/members/request.d.ts +26 -0
  98. package/dist/types/members/util.d.ts +27 -0
  99. package/dist/types/metrics/constants.d.ts +1 -0
  100. package/dist/types/reachability/clusterReachability.d.ts +2 -6
  101. package/dist/types/reachability/index.d.ts +8 -0
  102. package/dist/types/roap/index.d.ts +3 -2
  103. package/dist/types/roap/turnDiscovery.d.ts +5 -17
  104. package/dist/types/roap/types.d.ts +16 -0
  105. package/dist/webinar/index.js +1 -1
  106. package/package.json +24 -23
  107. package/src/breakouts/index.ts +69 -0
  108. package/src/common/errors/webex-errors.ts +8 -1
  109. package/src/config.ts +2 -0
  110. package/src/constants.ts +23 -90
  111. package/src/controls-options-manager/enums.ts +2 -0
  112. package/src/controls-options-manager/types.ts +11 -1
  113. package/src/controls-options-manager/util.ts +62 -0
  114. package/src/locus-info/controlsUtils.ts +48 -12
  115. package/src/locus-info/index.ts +88 -13
  116. package/src/locus-info/selfUtils.ts +496 -442
  117. package/src/media/index.ts +23 -21
  118. package/src/media/properties.ts +96 -0
  119. package/src/meeting/brbState.ts +11 -2
  120. package/src/meeting/in-meeting-actions.ts +32 -0
  121. package/src/meeting/index.ts +356 -87
  122. package/src/meeting/locusMediaRequest.ts +0 -18
  123. package/src/meeting/muteState.ts +4 -4
  124. package/src/meeting/request.ts +36 -1
  125. package/src/meeting/request.type.ts +7 -0
  126. package/src/meeting/util.ts +9 -1
  127. package/src/meeting-info/meeting-info-v2.ts +7 -2
  128. package/src/meeting-info/utilv2.ts +5 -0
  129. package/src/meetings/index.ts +76 -0
  130. package/src/meetings/util.ts +18 -0
  131. package/src/member/index.ts +57 -22
  132. package/src/member/types.ts +82 -16
  133. package/src/member/util.ts +357 -353
  134. package/src/members/collection.ts +4 -3
  135. package/src/members/index.ts +137 -18
  136. package/src/members/request.ts +44 -0
  137. package/src/members/util.ts +43 -1
  138. package/src/metrics/constants.ts +1 -0
  139. package/src/reachability/clusterReachability.ts +26 -25
  140. package/src/reachability/index.ts +55 -1
  141. package/src/reconnection-manager/index.ts +2 -2
  142. package/src/roap/index.ts +3 -7
  143. package/src/roap/turnDiscovery.ts +34 -39
  144. package/src/roap/types.ts +23 -0
  145. package/test/unit/spec/breakouts/index.ts +167 -95
  146. package/test/unit/spec/controls-options-manager/util.js +120 -0
  147. package/test/unit/spec/locus-info/controlsUtils.js +131 -9
  148. package/test/unit/spec/locus-info/index.js +195 -73
  149. package/test/unit/spec/locus-info/selfUtils.js +98 -24
  150. package/test/unit/spec/media/index.ts +150 -18
  151. package/test/unit/spec/media/properties.ts +130 -0
  152. package/test/unit/spec/meeting/brbState.ts +40 -2
  153. package/test/unit/spec/meeting/in-meeting-actions.ts +19 -4
  154. package/test/unit/spec/meeting/index.js +553 -36
  155. package/test/unit/spec/meeting/locusMediaRequest.ts +0 -30
  156. package/test/unit/spec/meeting/muteState.js +73 -2
  157. package/test/unit/spec/meeting/request.js +32 -1
  158. package/test/unit/spec/meeting/utils.js +79 -33
  159. package/test/unit/spec/meeting-info/meetinginfov2.js +41 -0
  160. package/test/unit/spec/meeting-info/utilv2.js +19 -0
  161. package/test/unit/spec/meetings/index.js +68 -1
  162. package/test/unit/spec/members/index.js +304 -78
  163. package/test/unit/spec/members/request.js +68 -22
  164. package/test/unit/spec/members/utils.js +75 -0
  165. package/test/unit/spec/reachability/clusterReachability.ts +41 -55
  166. package/test/unit/spec/reachability/index.ts +89 -0
  167. package/test/unit/spec/reconnection-manager/index.js +4 -4
  168. package/test/unit/spec/roap/turnDiscovery.ts +110 -28
@@ -32,58 +32,7 @@ sinon.assert.expose(chai.assert, {prefix: ''});
32
32
  describe('plugin-meetings', () => {
33
33
  let webex;
34
34
  let url1;
35
- const fakeMembersCollection = {
36
- test1: {
37
- namespace: 'Meetings',
38
- participant: {
39
- state: 'JOINED',
40
- type: 'USER',
41
- person: {
42
- id: '6eb08f8b-bf69-3251-a126-b161bead2d21',
43
- phoneNumber: '+18578675309',
44
- isExternal: true,
45
- primaryDisplayString: '+18578675309',
46
- },
47
- devices: [
48
- {
49
- url: 'https://fakeURL.com',
50
- deviceType: 'SIP',
51
- state: 'JOINED',
52
- intents: [null],
53
- correlationId: '1234',
54
- provisionalUrl: 'dialout:///fake',
55
- isSparkPstn: true,
56
- },
57
- {
58
- url: 'dialout:///fakeagain',
59
- deviceType: 'PROVISIONAL',
60
- state: 'JOINED',
61
- intents: [null],
62
- correlationId: '4321',
63
- isVideoCallback: false,
64
- clientUrl: 'https://fakeURL',
65
- provisionalType: 'DIAL_OUT_ONLY',
66
- dialingStatus: 'SUCCESS',
67
- },
68
- ],
69
- status: {
70
- audioStatus: 'SENDRECV',
71
- videoStatus: 'INACTIVE',
72
- },
73
- id: 'abc-123-abc-123',
74
- guest: true,
75
- resourceGuest: false,
76
- moderator: false,
77
- panelist: false,
78
- moveToLobbyNotAllowed: true,
79
- deviceUrl: 'https://fakeDeviceurl',
80
- },
81
- id: 'abc-123-abc-123',
82
- status: 'IN_MEETING',
83
- type: 'MEETING',
84
- isModerator: false,
85
- },
86
- };
35
+ let fakeMembersCollection;
87
36
 
88
37
  describe('members', () => {
89
38
  const sandbox = sinon.createSandbox();
@@ -92,6 +41,65 @@ describe('plugin-meetings', () => {
92
41
  let membersRequestSpy;
93
42
 
94
43
  beforeEach(() => {
44
+ fakeMembersCollection = {
45
+ test1: {
46
+ associatedUsers: new Set(),
47
+ namespace: 'Meetings',
48
+ participant: {
49
+ state: 'JOINED',
50
+ type: 'USER',
51
+ person: {
52
+ id: '6eb08f8b-bf69-3251-a126-b161bead2d21',
53
+ phoneNumber: '+18578675309',
54
+ isExternal: true,
55
+ primaryDisplayString: '+18578675309',
56
+ },
57
+ devices: [
58
+ {
59
+ url: 'https://fakeURL.com',
60
+ deviceType: 'SIP',
61
+ state: 'JOINED',
62
+ intents: [null],
63
+ correlationId: '1234',
64
+ provisionalUrl: 'dialout:///fake',
65
+ isSparkPstn: true,
66
+ },
67
+ {
68
+ url: 'dialout:///fakeagain',
69
+ deviceType: 'PROVISIONAL',
70
+ state: 'JOINED',
71
+ intents: [null],
72
+ correlationId: '4321',
73
+ isVideoCallback: false,
74
+ clientUrl: 'https://fakeURL',
75
+ provisionalType: 'DIAL_OUT_ONLY',
76
+ dialingStatus: 'SUCCESS',
77
+ },
78
+ ],
79
+ status: {
80
+ audioStatus: 'SENDRECV',
81
+ videoStatus: 'INACTIVE',
82
+ },
83
+ id: 'test1',
84
+ guest: true,
85
+ resourceGuest: false,
86
+ moderator: false,
87
+ panelist: false,
88
+ moveToLobbyNotAllowed: true,
89
+ deviceUrl: 'https://fakeDeviceurl',
90
+ url: 'fake participant url for test1',
91
+ },
92
+ id: 'test1',
93
+ status: 'IN_MEETING',
94
+ type: 'USER',
95
+ isModerator: false,
96
+ isHost: false,
97
+ isSelf: false,
98
+ isContentSharing: false,
99
+ pairedWith: {},
100
+ },
101
+ };
102
+
95
103
  webex = new MockWebex({
96
104
  children: {
97
105
  meetings: Meetings,
@@ -120,9 +128,9 @@ describe('plugin-meetings', () => {
120
128
  meeting = {
121
129
  request: sinon.mock().returns(Promise.resolve()),
122
130
  locusInfo: {
123
- sequence: {}
124
- }
125
- }
131
+ sequence: {},
132
+ },
133
+ };
126
134
 
127
135
  createMembers = (options) => new Members({locusUrl: options.url, meeting}, {parent: webex});
128
136
  });
@@ -157,6 +165,17 @@ describe('plugin-meetings', () => {
157
165
 
158
166
  assert.isRejected(members.addMember({email: 'test@cisco.com'}));
159
167
  });
168
+
169
+ it('should accept valid SIP email addresses', async () => {
170
+ sandbox.spy(MembersUtil, 'isInvalidInvitee');
171
+
172
+ const members = createMembers({url: true});
173
+
174
+ await members.addMember({email: 'sip:test@cisco.com'});
175
+
176
+ assert.calledOnce(MembersUtil.isInvalidInvitee);
177
+ assert.isFalse(MembersUtil.isInvalidInvitee({email: 'sip:test@cisco.com'}), 'SIP email should be valid');
178
+ });
160
179
  });
161
180
 
162
181
  describe('#admitMembers', () => {
@@ -280,6 +299,110 @@ describe('plugin-meetings', () => {
280
299
  }
281
300
  );
282
301
  });
302
+
303
+ describe('handles members with paired devices correctly', () => {
304
+ const runCheck = (propsForUpdate, expectedPropsOnPairedMember) => {
305
+ const members = createMembers({url: url1});
306
+
307
+ const DEVICE_PARTICIPANT_URL = 'fake participant url for test2';
308
+
309
+ members.membersCollection.setAll(fakeMembersCollection);
310
+
311
+ // simulate a locus update with a member that has a paired device
312
+ members.locusParticipantsUpdate({
313
+ ...propsForUpdate,
314
+ participants: [
315
+ {
316
+ id: 'test1',
317
+ type: 'USER',
318
+ person: {},
319
+ devices: [
320
+ {
321
+ intents: [
322
+ {
323
+ type: 'OBSERVE',
324
+ associatedWith: DEVICE_PARTICIPANT_URL,
325
+ },
326
+ ],
327
+ },
328
+ ],
329
+ },
330
+ {
331
+ id: 'test2',
332
+ type: 'RESOURCE_ROOM',
333
+ person: {},
334
+ devices: [
335
+ {
336
+ state: 'JOINED',
337
+ intents: [null],
338
+ },
339
+ ],
340
+ url: DEVICE_PARTICIPANT_URL,
341
+ },
342
+ ],
343
+ });
344
+
345
+ let member = members.membersCollection.get('test1');
346
+ assert.isDefined(member.pairedWith);
347
+ assert.strictEqual(member.pairedWith.participantUrl, DEVICE_PARTICIPANT_URL);
348
+ assert.strictEqual(member.pairedWith.memberId, 'test2');
349
+
350
+ let pairedDeviceMember = members.membersCollection.get('test2');
351
+ assert(pairedDeviceMember.associatedUsers.has(member.id));
352
+ assert.strictEqual(pairedDeviceMember.associatedUser, member.id);
353
+ assert.strictEqual(pairedDeviceMember.associatedUsers.size, 1);
354
+
355
+ assert.strictEqual(
356
+ pairedDeviceMember.isPairedWithSelf,
357
+ expectedPropsOnPairedMember.isPairedWithSelf
358
+ );
359
+ assert.strictEqual(pairedDeviceMember.isHost, expectedPropsOnPairedMember.isHost);
360
+
361
+ // now simulate the user and paired device leaving the meeting
362
+ members.locusParticipantsUpdate({
363
+ ...propsForUpdate,
364
+ participants: [
365
+ {
366
+ id: 'test1',
367
+ type: 'USER',
368
+ person: {},
369
+ devices: [],
370
+ },
371
+ {
372
+ id: 'test2',
373
+ type: 'RESOURCE_ROOM',
374
+ person: {},
375
+ devices: [],
376
+ },
377
+ ],
378
+ });
379
+
380
+ // and check that all the relevant properties were reset
381
+ member = members.membersCollection.get('test1');
382
+ assert.isDefined(member.pairedWith);
383
+ assert.isUndefined(member.pairedWith.participantUrl);
384
+ assert.isUndefined(member.pairedWith.memberId);
385
+
386
+ pairedDeviceMember = members.membersCollection.get('test2');
387
+ assert.strictEqual(pairedDeviceMember.associatedUser, null);
388
+ assert.strictEqual(pairedDeviceMember.associatedUsers.size, 0);
389
+
390
+ assert.strictEqual(pairedDeviceMember.isPairedWithSelf, false);
391
+ assert.strictEqual(pairedDeviceMember.isHost, false);
392
+ };
393
+
394
+ it('sets the right properties when a member has a paired device', () => {
395
+ runCheck({}, {isPairedWithSelf: false, isHost: false});
396
+ });
397
+
398
+ it('sets the right properties when a member has a paired device (isSelf)', () => {
399
+ runCheck({selfId: 'test1'}, {isPairedWithSelf: true, isHost: false});
400
+ });
401
+
402
+ it('sets the right properties when a member has a paired device (isHost)', () => {
403
+ runCheck({hostId: 'test1'}, {isPairedWithSelf: false, isHost: true});
404
+ });
405
+ });
283
406
  });
284
407
  describe('#sendDialPadKey', () => {
285
408
  it('should throw a rejection when calling sendDialPadKey with no tones', async () => {
@@ -342,6 +465,32 @@ describe('plugin-meetings', () => {
342
465
  });
343
466
  });
344
467
 
468
+ describe('#cancelSIPInvite', () => {
469
+ const memberId = uuid.v4();
470
+ it('should invoke cancelSIPInviteOptions from MembersUtil when cancelSIPInvite is called with valid params', async () => {
471
+ sandbox.spy(MembersUtil, 'cancelSIPInviteOptions');
472
+
473
+ const members = createMembers({url: url1});
474
+
475
+ await members.cancelSIPInvite({memberId});
476
+ assert.calledOnce(MembersUtil.cancelSIPInviteOptions);
477
+ });
478
+
479
+ it('should throw a rejection if there is no locus url', async () => {
480
+ const members = createMembers({url: false});
481
+
482
+ assert.isRejected(members.cancelSIPInvite({memberId}));
483
+ });
484
+
485
+ it('should throw a rejection if memberId is not provided', async () => {
486
+ const members = createMembers({url: url1});
487
+
488
+ assert.isRejected(members.cancelSIPInvite({}));
489
+ assert.isRejected(members.cancelSIPInvite({memberId: null}));
490
+ assert.isRejected(members.cancelSIPInvite({memberId: undefined}));
491
+ });
492
+ });
493
+
345
494
  describe('#assignRoles', () => {
346
495
  const fakeRoles = [
347
496
  {type: 'PRESENTER', hasRole: true},
@@ -349,7 +498,7 @@ describe('plugin-meetings', () => {
349
498
  {type: 'COHOST', hasRole: true},
350
499
  ];
351
500
 
352
- const resolvedValue = "it worked";
501
+ const resolvedValue = 'it worked';
353
502
 
354
503
  const genericMessage = 'Generic error from the API';
355
504
 
@@ -364,9 +513,13 @@ describe('plugin-meetings', () => {
364
513
  };
365
514
 
366
515
  if (errorCode) {
367
- spies.assignRolesMember = sandbox.stub(members.membersRequest, 'assignRolesMember').rejects({body: {errorCode}, message: genericMessage});
516
+ spies.assignRolesMember = sandbox
517
+ .stub(members.membersRequest, 'assignRolesMember')
518
+ .rejects({body: {errorCode}, message: genericMessage});
368
519
  } else {
369
- spies.assignRolesMember = sandbox.stub(members.membersRequest, 'assignRolesMember').resolves(resolvedValue);
520
+ spies.assignRolesMember = sandbox
521
+ .stub(members.membersRequest, 'assignRolesMember')
522
+ .resolves(resolvedValue);
370
523
  }
371
524
 
372
525
  return {members, spies};
@@ -378,7 +531,15 @@ describe('plugin-meetings', () => {
378
531
  assert.notCalled(spies.assignRolesMember);
379
532
  };
380
533
 
381
- const checkError = async (error, expectedMemberId, expectedRoles, expectedLocusUrl, resultPromise, expectedMessage, spies) => {
534
+ const checkError = async (
535
+ error,
536
+ expectedMemberId,
537
+ expectedRoles,
538
+ expectedLocusUrl,
539
+ resultPromise,
540
+ expectedMessage,
541
+ spies
542
+ ) => {
382
543
  await assert.isRejected(resultPromise, error, expectedMessage);
383
544
  assert.calledOnceWithExactly(
384
545
  spies.generateRoleAssignmentMemberOptions,
@@ -423,7 +584,7 @@ describe('plugin-meetings', () => {
423
584
  await checkInvalid(
424
585
  resultPromise,
425
586
  'The member id must be defined to assign the roles to a member.',
426
- spies,
587
+ spies
427
588
  );
428
589
  });
429
590
 
@@ -435,7 +596,7 @@ describe('plugin-meetings', () => {
435
596
  await checkInvalid(
436
597
  resultPromise,
437
598
  'The associated locus url for this meetings members object must be defined.',
438
- spies,
599
+ spies
439
600
  );
440
601
  });
441
602
 
@@ -452,7 +613,7 @@ describe('plugin-meetings', () => {
452
613
  url1,
453
614
  resultPromise,
454
615
  'Non converged meetings, PSTN or SIP users in converged meetings are not supported currently.',
455
- spies,
616
+ spies
456
617
  );
457
618
  });
458
619
 
@@ -469,7 +630,7 @@ describe('plugin-meetings', () => {
469
630
  url1,
470
631
  resultPromise,
471
632
  'Reclaim Host Role Not Allowed For Other Participants. Participants cannot claim host role in PMR meeting, space instant meeting or escalated instant meeting. However, the original host still can reclaim host role when it manually makes another participant to be the host.',
472
- spies,
633
+ spies
473
634
  );
474
635
  });
475
636
 
@@ -486,7 +647,7 @@ describe('plugin-meetings', () => {
486
647
  url1,
487
648
  resultPromise,
488
649
  'Host Key Not Specified Or Matched. The original host can reclaim the host role without entering the host key. However, any other person who claims the host role must enter the host key to get it.',
489
- spies,
650
+ spies
490
651
  );
491
652
  });
492
653
 
@@ -503,7 +664,7 @@ describe('plugin-meetings', () => {
503
664
  url1,
504
665
  resultPromise,
505
666
  'Participant Having Host Role Already. Participant who sends request to reclaim host role has already a host role.',
506
- spies,
667
+ spies
507
668
  );
508
669
  });
509
670
 
@@ -520,7 +681,7 @@ describe('plugin-meetings', () => {
520
681
  url1,
521
682
  resultPromise,
522
683
  genericMessage,
523
- spies,
684
+ spies
524
685
  );
525
686
  });
526
687
 
@@ -530,13 +691,7 @@ describe('plugin-meetings', () => {
530
691
 
531
692
  const resultPromise = members.assignRoles(memberId, fakeRoles);
532
693
 
533
- await checkValid(
534
- resultPromise,
535
- spies,
536
- memberId,
537
- fakeRoles,
538
- url1,
539
- );
694
+ await checkValid(resultPromise, spies, memberId, fakeRoles, url1);
540
695
  });
541
696
  });
542
697
 
@@ -661,19 +816,19 @@ describe('plugin-meetings', () => {
661
816
  spies,
662
817
  expectedRequestingMemberId,
663
818
  expectedLocusUrl,
664
- expectedRoles,
819
+ expectedRoles
665
820
  ) => {
666
821
  await assert.isFulfilled(resultPromise);
667
822
  assert.calledOnceWithExactly(
668
823
  spies.generateLowerAllHandsMemberOptions,
669
824
  expectedRequestingMemberId,
670
825
  expectedLocusUrl,
671
- expectedRoles,
826
+ expectedRoles
672
827
  );
673
828
  assert.calledOnceWithExactly(spies.lowerAllHandsMember, {
674
829
  requestingParticipantId: expectedRequestingMemberId,
675
830
  locusUrl: expectedLocusUrl,
676
- ...(expectedRoles !== undefined && { roles: expectedRoles })
831
+ ...(expectedRoles !== undefined && {roles: expectedRoles}),
677
832
  });
678
833
  assert.strictEqual(resultPromise, spies.lowerAllHandsMember.getCall(0).returnValue);
679
834
  };
@@ -714,7 +869,7 @@ describe('plugin-meetings', () => {
714
869
  it('should make the correct request when called with valid requestingMemberId and roles', async () => {
715
870
  const requestingMemberId = 'test-member-id';
716
871
  const roles = ['panelist', 'attendee'];
717
- const { members, spies } = setup('test-locus-url');
872
+ const {members, spies} = setup('test-locus-url');
718
873
 
719
874
  const resultPromise = members.lowerAllHands(requestingMemberId, roles);
720
875
 
@@ -724,7 +879,7 @@ describe('plugin-meetings', () => {
724
879
  it('should handle an empty roles array correctly', async () => {
725
880
  const requestingMemberId = 'test-member-id';
726
881
  const roles = [];
727
- const { members, spies } = setup('test-locus-url');
882
+ const {members, spies} = setup('test-locus-url');
728
883
 
729
884
  const resultPromise = members.lowerAllHands(requestingMemberId, roles);
730
885
 
@@ -977,5 +1132,76 @@ describe('plugin-meetings', () => {
977
1132
  );
978
1133
  });
979
1134
  });
1135
+
1136
+ describe('#moveToLobby', () => {
1137
+ const setup = (locusUrl) => {
1138
+ const members = createMembers({url: locusUrl});
1139
+
1140
+ const spies = {
1141
+ getMoveMemberToLobbyRequestBody: sandbox.spy(
1142
+ MembersUtil,
1143
+ 'getMoveMemberToLobbyRequestBody'
1144
+ ),
1145
+ moveToLobbyMember: sandbox.spy(members.membersRequest, 'moveToLobbyMember'),
1146
+ };
1147
+
1148
+ return {members, spies};
1149
+ };
1150
+
1151
+ const checkInvalid = async (resultPromise, expectedMessage, spies) => {
1152
+ await assert.isRejected(resultPromise, ParameterError, expectedMessage);
1153
+ assert.notCalled(spies.getMoveMemberToLobbyRequestBody);
1154
+ assert.notCalled(spies.moveToLobbyMember);
1155
+ };
1156
+
1157
+ const checkValid = async (resultPromise, spies, expectedMemberId, expectedLocusUrl) => {
1158
+ await assert.isFulfilled(resultPromise);
1159
+ assert.calledOnceWithExactly(spies.getMoveMemberToLobbyRequestBody, expectedMemberId);
1160
+ assert.calledOnceWithExactly(
1161
+ spies.moveToLobbyMember,
1162
+ {
1163
+ locusUrl: expectedLocusUrl,
1164
+ memberId: expectedMemberId,
1165
+ },
1166
+ {
1167
+ moveToLobby: {participantIds: [expectedMemberId]},
1168
+ }
1169
+ );
1170
+ assert.strictEqual(resultPromise, spies.moveToLobbyMember.getCall(0).returnValue);
1171
+ };
1172
+
1173
+ it('should not make a request if there is no member id', async () => {
1174
+ const {members, spies} = setup(url1);
1175
+
1176
+ const resultPromise = members.moveToLobby();
1177
+
1178
+ await checkInvalid(
1179
+ resultPromise,
1180
+ 'The member id must be defined to move the member to lobby.',
1181
+ spies
1182
+ );
1183
+ });
1184
+
1185
+ it('should not make a request if there is no locus url', async () => {
1186
+ const {members, spies} = setup();
1187
+
1188
+ const resultPromise = members.moveToLobby(uuid.v4());
1189
+
1190
+ await checkInvalid(
1191
+ resultPromise,
1192
+ 'The associated locus url for this meetings members object must be defined.',
1193
+ spies
1194
+ );
1195
+ });
1196
+
1197
+ it('should make the correct request when called with valid memberId and locusUrl', async () => {
1198
+ const memberId = uuid.v4();
1199
+ const {members, spies} = setup(url1);
1200
+
1201
+ const resultPromise = members.moveToLobby(memberId);
1202
+
1203
+ await checkValid(resultPromise, spies, memberId, url1);
1204
+ });
1205
+ });
980
1206
  });
981
1207
  });
@@ -9,7 +9,7 @@ import Meetings from '@webex/plugin-meetings';
9
9
  import MembersRequest from '@webex/plugin-meetings/src/members/request';
10
10
  import membersUtil from '@webex/plugin-meetings/src/members/util';
11
11
  import ParameterError from '@webex/plugin-meetings/src/common/errors/parameter';
12
- import { merge } from 'lodash';
12
+ import {merge} from 'lodash';
13
13
 
14
14
  const {assert} = chai;
15
15
 
@@ -65,10 +65,7 @@ describe('plugin-meetings', () => {
65
65
 
66
66
  const checkRequest = (expectedParams) => {
67
67
  assert.calledOnceWithExactly(locusDeltaRequestSpy, expectedParams);
68
- assert.calledOnceWithExactly(
69
- membersRequest.request,
70
- merge(expectedParams, {body: {sequence}})
71
- );
68
+ assert.calledOnceWithExactly(membersRequest.request, merge(expectedParams, {body: {sequence}}));
72
69
  };
73
70
 
74
71
  describe('members request library', () => {
@@ -98,8 +95,8 @@ describe('plugin-meetings', () => {
98
95
  },
99
96
  device: {
100
97
  url,
101
- }
102
- }
98
+ },
99
+ },
103
100
  });
104
101
  });
105
102
  });
@@ -120,9 +117,9 @@ describe('plugin-meetings', () => {
120
117
  uri: url1,
121
118
  body: {
122
119
  alertIfActive: undefined,
123
- invitees: [{address: '+18578675309'}]
124
- }
125
- })
120
+ invitees: [{address: '+18578675309'}],
121
+ },
122
+ });
126
123
  });
127
124
  });
128
125
 
@@ -133,16 +130,16 @@ describe('plugin-meetings', () => {
133
130
  memberIds: ['1', '2'],
134
131
  };
135
132
 
136
- await membersRequest.admitMember(options)
133
+ await membersRequest.admitMember(options);
137
134
 
138
135
  checkRequest({
139
136
  method: 'PUT',
140
137
  uri: 'https://example.com/12345/controls',
141
138
  body: {
142
139
  admit: {
143
- participantIds: options.memberIds
144
- }
145
- }
140
+ participantIds: options.memberIds,
141
+ },
142
+ },
146
143
  });
147
144
  });
148
145
  });
@@ -160,7 +157,7 @@ describe('plugin-meetings', () => {
160
157
  method: 'PUT',
161
158
  uri: 'https://example.com/12345/participant/member1/leave',
162
159
  body: {
163
- reason: undefined
160
+ reason: undefined,
164
161
  },
165
162
  });
166
163
  });
@@ -224,6 +221,29 @@ describe('plugin-meetings', () => {
224
221
  });
225
222
  });
226
223
 
224
+ describe('#cancelSIPInvite', () => {
225
+ const memberId = uuid.v4();
226
+ it('sends a PUT to the locus endpoint', async () => {
227
+ const options = {
228
+ invitee: {
229
+ memberId,
230
+ },
231
+ locusUrl: url1,
232
+ };
233
+
234
+ await membersRequest.cancelSIPInvite(options);
235
+
236
+ checkRequest({
237
+ method: 'PUT',
238
+ uri: url1,
239
+ body: {
240
+ actionType: 'REMOVE',
241
+ invitees: [{address: memberId}],
242
+ },
243
+ });
244
+ });
245
+ });
246
+
227
247
  describe('#assignRolesMember', () => {
228
248
  it('sends a assignRolesMember PATCH to the locus endpoint', async () => {
229
249
  const locusUrl = url1;
@@ -247,9 +267,9 @@ describe('plugin-meetings', () => {
247
267
  uri: `${locusUrl}/participant/${memberId}/controls`,
248
268
  body: {
249
269
  role: {
250
- roles
251
- }
252
- }
270
+ roles,
271
+ },
272
+ },
253
273
  });
254
274
  });
255
275
  });
@@ -272,9 +292,9 @@ describe('plugin-meetings', () => {
272
292
  uri: `${locusUrl}/participant/${memberId}/controls`,
273
293
  body: {
274
294
  hand: {
275
- raised: true
276
- }
277
- }
295
+ raised: true,
296
+ },
297
+ },
278
298
  });
279
299
  });
280
300
  });
@@ -406,7 +426,33 @@ describe('plugin-meetings', () => {
406
426
  body: {
407
427
  aliasValue,
408
428
  requestingParticipantId,
409
- }
429
+ },
430
+ });
431
+ });
432
+ });
433
+
434
+ describe('#moveToLobby', () => {
435
+ it('sends a moveToLobbyMember PATCH to the locus endpoint', async () => {
436
+ const locusUrl = url1;
437
+ const memberId = 'test1';
438
+ const options = {
439
+ locusUrl: locusUrl,
440
+ memberId,
441
+ };
442
+ const body = {
443
+ moveToLobby: {participantIds: [memberId]},
444
+ };
445
+
446
+ const getRequestParamsSpy = sandbox.spy(membersUtil, 'getMoveMemberToLobbyRequestParams');
447
+
448
+ await membersRequest.moveToLobbyMember(options, body);
449
+
450
+ assert.calledOnceWithExactly(getRequestParamsSpy, options, body);
451
+
452
+ checkRequest({
453
+ method: 'PATCH',
454
+ uri: `${locusUrl}/participant/${memberId}/controls`,
455
+ body: {moveToLobby: {participantIds: [memberId]}},
410
456
  });
411
457
  });
412
458
  });