@webex/plugin-meetings 3.7.0-next.5 → 3.7.0-next.50

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 (134) hide show
  1. package/dist/annotation/index.js +17 -0
  2. package/dist/annotation/index.js.map +1 -1
  3. package/dist/breakouts/breakout.js +1 -1
  4. package/dist/breakouts/index.js +1 -1
  5. package/dist/common/errors/{webinar-registration-error.js → join-webinar-error.js} +12 -12
  6. package/dist/common/errors/join-webinar-error.js.map +1 -0
  7. package/dist/common/errors/multistream-not-supported-error.js +53 -0
  8. package/dist/common/errors/multistream-not-supported-error.js.map +1 -0
  9. package/dist/config.js +1 -1
  10. package/dist/config.js.map +1 -1
  11. package/dist/constants.js +40 -5
  12. package/dist/constants.js.map +1 -1
  13. package/dist/index.js +16 -11
  14. package/dist/index.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/index.js +14 -3
  18. package/dist/locus-info/index.js.map +1 -1
  19. package/dist/locus-info/selfUtils.js +30 -17
  20. package/dist/locus-info/selfUtils.js.map +1 -1
  21. package/dist/meeting/in-meeting-actions.js +4 -0
  22. package/dist/meeting/in-meeting-actions.js.map +1 -1
  23. package/dist/meeting/index.js +944 -832
  24. package/dist/meeting/index.js.map +1 -1
  25. package/dist/meeting/locusMediaRequest.js +9 -0
  26. package/dist/meeting/locusMediaRequest.js.map +1 -1
  27. package/dist/meeting/request.js +30 -0
  28. package/dist/meeting/request.js.map +1 -1
  29. package/dist/meeting/request.type.js.map +1 -1
  30. package/dist/meeting/util.js +16 -16
  31. package/dist/meeting/util.js.map +1 -1
  32. package/dist/meeting-info/meeting-info-v2.js +29 -17
  33. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  34. package/dist/meeting-info/utilv2.js +1 -1
  35. package/dist/meeting-info/utilv2.js.map +1 -1
  36. package/dist/meetings/index.js +106 -55
  37. package/dist/meetings/index.js.map +1 -1
  38. package/dist/meetings/meetings.types.js +2 -0
  39. package/dist/meetings/meetings.types.js.map +1 -1
  40. package/dist/meetings/util.js +1 -1
  41. package/dist/meetings/util.js.map +1 -1
  42. package/dist/member/index.js +9 -0
  43. package/dist/member/index.js.map +1 -1
  44. package/dist/member/types.js.map +1 -1
  45. package/dist/member/util.js +39 -28
  46. package/dist/member/util.js.map +1 -1
  47. package/dist/metrics/constants.js +1 -1
  48. package/dist/metrics/constants.js.map +1 -1
  49. package/dist/multistream/remoteMedia.js +30 -15
  50. package/dist/multistream/remoteMedia.js.map +1 -1
  51. package/dist/multistream/sendSlotManager.js +24 -0
  52. package/dist/multistream/sendSlotManager.js.map +1 -1
  53. package/dist/recording-controller/enums.js +8 -4
  54. package/dist/recording-controller/enums.js.map +1 -1
  55. package/dist/recording-controller/index.js +18 -9
  56. package/dist/recording-controller/index.js.map +1 -1
  57. package/dist/recording-controller/util.js +13 -9
  58. package/dist/recording-controller/util.js.map +1 -1
  59. package/dist/roap/index.js +10 -8
  60. package/dist/roap/index.js.map +1 -1
  61. package/dist/types/annotation/index.d.ts +5 -0
  62. package/dist/types/common/errors/{webinar-registration-error.d.ts → join-webinar-error.d.ts} +2 -2
  63. package/dist/types/common/errors/multistream-not-supported-error.d.ts +17 -0
  64. package/dist/types/constants.d.ts +34 -1
  65. package/dist/types/index.d.ts +3 -3
  66. package/dist/types/locus-info/index.d.ts +2 -1
  67. package/dist/types/meeting/in-meeting-actions.d.ts +4 -0
  68. package/dist/types/meeting/index.d.ts +19 -12
  69. package/dist/types/meeting/locusMediaRequest.d.ts +4 -0
  70. package/dist/types/meeting/request.d.ts +12 -1
  71. package/dist/types/meeting/request.type.d.ts +6 -0
  72. package/dist/types/meeting/util.d.ts +1 -1
  73. package/dist/types/meeting-info/meeting-info-v2.d.ts +4 -4
  74. package/dist/types/meetings/index.d.ts +19 -1
  75. package/dist/types/meetings/meetings.types.d.ts +8 -0
  76. package/dist/types/member/index.d.ts +1 -0
  77. package/dist/types/member/types.d.ts +7 -0
  78. package/dist/types/metrics/constants.d.ts +1 -1
  79. package/dist/types/multistream/sendSlotManager.d.ts +8 -1
  80. package/dist/types/recording-controller/enums.d.ts +5 -2
  81. package/dist/types/recording-controller/index.d.ts +1 -0
  82. package/dist/types/recording-controller/util.d.ts +2 -1
  83. package/dist/webinar/index.js +354 -3
  84. package/dist/webinar/index.js.map +1 -1
  85. package/package.json +23 -22
  86. package/src/annotation/index.ts +16 -0
  87. package/src/common/errors/join-webinar-error.ts +24 -0
  88. package/src/common/errors/multistream-not-supported-error.ts +30 -0
  89. package/src/config.ts +1 -1
  90. package/src/constants.ts +39 -3
  91. package/src/index.ts +5 -3
  92. package/src/locus-info/index.ts +20 -3
  93. package/src/locus-info/selfUtils.ts +19 -6
  94. package/src/meeting/in-meeting-actions.ts +8 -0
  95. package/src/meeting/index.ts +246 -80
  96. package/src/meeting/locusMediaRequest.ts +7 -0
  97. package/src/meeting/request.ts +26 -1
  98. package/src/meeting/request.type.ts +7 -0
  99. package/src/meeting/util.ts +8 -10
  100. package/src/meeting-info/meeting-info-v2.ts +23 -11
  101. package/src/meeting-info/utilv2.ts +3 -1
  102. package/src/meetings/index.ts +77 -20
  103. package/src/meetings/meetings.types.ts +10 -0
  104. package/src/meetings/util.ts +2 -1
  105. package/src/member/index.ts +9 -0
  106. package/src/member/types.ts +8 -0
  107. package/src/member/util.ts +34 -24
  108. package/src/metrics/constants.ts +1 -1
  109. package/src/multistream/remoteMedia.ts +28 -15
  110. package/src/multistream/sendSlotManager.ts +31 -0
  111. package/src/recording-controller/enums.ts +5 -2
  112. package/src/recording-controller/index.ts +17 -4
  113. package/src/recording-controller/util.ts +20 -5
  114. package/src/roap/index.ts +10 -8
  115. package/src/webinar/index.ts +197 -3
  116. package/test/unit/spec/annotation/index.ts +46 -1
  117. package/test/unit/spec/locus-info/index.js +292 -60
  118. package/test/unit/spec/locus-info/selfConstant.js +7 -0
  119. package/test/unit/spec/locus-info/selfUtils.js +91 -1
  120. package/test/unit/spec/meeting/in-meeting-actions.ts +4 -0
  121. package/test/unit/spec/meeting/index.js +689 -105
  122. package/test/unit/spec/meeting/utils.js +22 -19
  123. package/test/unit/spec/meeting-info/meetinginfov2.js +9 -4
  124. package/test/unit/spec/meeting-info/utilv2.js +17 -0
  125. package/test/unit/spec/meetings/index.js +153 -18
  126. package/test/unit/spec/meetings/utils.js +10 -0
  127. package/test/unit/spec/member/util.js +52 -11
  128. package/test/unit/spec/multistream/remoteMedia.ts +11 -7
  129. package/test/unit/spec/recording-controller/index.js +61 -5
  130. package/test/unit/spec/recording-controller/util.js +39 -3
  131. package/test/unit/spec/roap/index.ts +47 -0
  132. package/test/unit/spec/webinar/index.ts +457 -0
  133. package/dist/common/errors/webinar-registration-error.js.map +0 -1
  134. package/src/common/errors/webinar-registration-error.ts +0 -27
@@ -26,7 +26,7 @@ describe('plugin-meetings', () => {
26
26
  webex.meetings.reachability = {
27
27
  getReachabilityReportToAttachToRoap: sinon.stub().resolves({}),
28
28
  getClientMediaPreferences: sinon.stub().resolves({}),
29
- };
29
+ };
30
30
 
31
31
  const logger = {
32
32
  info: sandbox.stub(),
@@ -165,21 +165,6 @@ describe('plugin-meetings', () => {
165
165
  assert(LoggerProxy.logger.log.called, 'log called');
166
166
  });
167
167
  });
168
-
169
- describe('#handleDeviceLogging', () => {
170
- it('should not log if called without devices', () => {
171
- MeetingUtil.handleDeviceLogging();
172
- assert(!LoggerProxy.logger.log.called, 'log not called');
173
- });
174
-
175
- it('should log device settings', () => {
176
- const mockDevices = [{deviceId: 'device-1'}, {deviceId: 'device-2'}];
177
-
178
- assert(MeetingUtil.handleDeviceLogging, 'is defined');
179
- MeetingUtil.handleDeviceLogging(mockDevices);
180
- assert(LoggerProxy.logger.log.called, 'log called');
181
- });
182
- });
183
168
  });
184
169
 
185
170
  describe('addSequence', () => {
@@ -424,17 +409,17 @@ describe('plugin-meetings', () => {
424
409
  const FAKE_CLIENT_MEDIA_PREFERENCES = {
425
410
  id: 'fake client media preferences',
426
411
  };
427
-
412
+
428
413
  webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(FAKE_REACHABILITY_REPORT);
429
414
  webex.meetings.reachability.getClientMediaPreferences.resolves(FAKE_CLIENT_MEDIA_PREFERENCES);
430
-
415
+
431
416
  sinon
432
417
  .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
433
418
  .get(() => true);
434
419
  sinon
435
420
  .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
436
421
  .get(() => true);
437
-
422
+
438
423
  await MeetingUtil.joinMeeting(meeting, {
439
424
  reachability: 'reachability',
440
425
  roapMessage: 'roapMessage',
@@ -484,6 +469,17 @@ describe('plugin-meetings', () => {
484
469
  assert.calledOnce(meeting.meetingRequest.joinMeeting);
485
470
  });
486
471
 
472
+ it('should not attach reachability if there is no roap message', async () => {
473
+ await MeetingUtil.joinMeeting(meeting, {});
474
+
475
+ assert.notCalled(webex.meetings.reachability.getReachabilityReportToAttachToRoap);
476
+ assert.calledOnce(meeting.meetingRequest.joinMeeting);
477
+
478
+ const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
479
+ assert.isUndefined(parameter.reachability);
480
+ assert.isUndefined(parameter.roapMessage);
481
+ });
482
+
487
483
  it('should handle failed clientMediaPreferences retrieval', async () => {
488
484
  webex.meetings.reachability.getClientMediaPreferences.rejects(new Error('fake error'));
489
485
  meeting.isMultistream = true;
@@ -775,6 +771,13 @@ describe('plugin-meetings', () => {
775
771
  });
776
772
  });
777
773
 
774
+ describe('canStartBreakout', () => {
775
+ it('works as expected', () => {
776
+ assert.deepEqual(MeetingUtil.canStartBreakout(['DISABLE_BREAKOUT_START']), false);
777
+ assert.deepEqual(MeetingUtil.canStartBreakout([]), true);
778
+ });
779
+ });
780
+
778
781
  describe('canBroadcastMessageToBreakout', () => {
779
782
  it('works as expected', () => {
780
783
  assert.deepEqual(
@@ -18,7 +18,7 @@ import MeetingInfo, {
18
18
  MeetingInfoV2CaptchaError,
19
19
  MeetingInfoV2AdhocMeetingError,
20
20
  MeetingInfoV2PolicyError,
21
- MeetingInfoV2WebinarRegistrationError,
21
+ MeetingInfoV2JoinWebinarError,
22
22
  } from '@webex/plugin-meetings/src/meeting-info/meeting-info-v2';
23
23
  import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
24
24
  import Metrics from '@webex/plugin-meetings/src/metrics';
@@ -895,9 +895,14 @@ describe('plugin-meetings', () => {
895
895
  {errorCode: 403021},
896
896
  {errorCode: 403022},
897
897
  {errorCode: 403024},
898
+ {errorCode: 403137},
899
+ {errorCode: 423007},
900
+ {errorCode: 403026},
901
+ {errorCode: 403037},
902
+ {errorCode: 403137},
898
903
  ],
899
904
  ({errorCode}) => {
900
- it(`should throw a MeetingInfoV2WebinarRegistrationError for error code ${errorCode}`, async () => {
905
+ it(`should throw a MeetingInfoV2JoinWebinarError for error code ${errorCode}`, async () => {
901
906
  const message = 'a message';
902
907
  const meetingInfoData = {meetingInfo: {registrationUrl: 'registrationUrl'}};
903
908
 
@@ -909,7 +914,7 @@ describe('plugin-meetings', () => {
909
914
  await meetingInfo.createAdhocSpaceMeeting(conversationUrl, installedOrgID);
910
915
  assert.fail('createAdhocSpaceMeeting should have thrown, but has not done that');
911
916
  } catch (err) {
912
- assert.instanceOf(err, MeetingInfoV2WebinarRegistrationError);
917
+ assert.instanceOf(err, MeetingInfoV2JoinWebinarError);
913
918
  assert.deepEqual(err.message, `${message}, code=${errorCode}`);
914
919
  assert.equal(err.wbxAppApiCode, errorCode);
915
920
  assert.deepEqual(err.meetingInfo, meetingInfoData);
@@ -917,7 +922,7 @@ describe('plugin-meetings', () => {
917
922
  assert(Metrics.sendBehavioralMetric.calledOnce);
918
923
  assert.calledWith(
919
924
  Metrics.sendBehavioralMetric,
920
- BEHAVIORAL_METRICS.WEBINAR_REGISTRATION_ERROR,
925
+ BEHAVIORAL_METRICS.JOIN_WEBINAR_ERROR,
921
926
  {code: errorCode}
922
927
  );
923
928
 
@@ -345,5 +345,22 @@ describe('plugin-meetings', () => {
345
345
  );
346
346
  });
347
347
  });
348
+
349
+ describe('#isMeetingLink', () => {
350
+ it('should return true for valid join meeting link with MTID', () => {
351
+ const result = MeetingInfoUtil.isMeetingLink('https://cisco.webex.com/cisco/j.php?MTID=m9fe0afd8c435e892afcce9ea25b97046');
352
+ expect(result).to.be.true;
353
+ });
354
+
355
+ it('should return true for valid join meeting link without cisco domain', () => {
356
+ const result = MeetingInfoUtil.isMeetingLink('https://test.webex.com/test/j.php?MTID=m9fe0afd8c435e892afcce9ea25b97046');
357
+ expect(result).to.be.true;
358
+ });
359
+
360
+ it('should return false for an invalid meeting link', () => {
361
+ const result = MeetingInfoUtil.isMeetingLink('https://test.webex.com/test/j.php?MiD=m9fe0afd8c435e892afcce9ea25b97046');
362
+ expect(result).to.be.false;
363
+ });
364
+ });
348
365
  });
349
366
  });
@@ -37,6 +37,7 @@ import {
37
37
  LOCUSINFO,
38
38
  EVENT_TRIGGERS,
39
39
  DESTINATION_TYPE,
40
+ INITIAL_REGISTRATION_STATUS,
40
41
  } from '../../../../src/constants';
41
42
  import CaptchaError from '@webex/plugin-meetings/src/common/errors/captcha-error';
42
43
  import {forEach} from 'lodash';
@@ -131,9 +132,9 @@ describe('plugin-meetings', () => {
131
132
  logger,
132
133
  people: {
133
134
  _getMe: sinon.stub().resolves({
134
- type: 'validuser',
135
+ type: 'validuser',
135
136
  }),
136
- }
137
+ },
137
138
  });
138
139
 
139
140
  startReachabilityStub = sinon.stub(webex.meetings, 'startReachability').resolves();
@@ -267,6 +268,33 @@ describe('plugin-meetings', () => {
267
268
  });
268
269
  });
269
270
 
271
+ describe('#_setLogUploadIntervalMultiplicationFactor', () => {
272
+ it('should have _setLogUploadIntervalMultiplicationFactor', () => {
273
+ assert.equal(typeof webex.meetings._setLogUploadIntervalMultiplicationFactor, 'function');
274
+ });
275
+
276
+ describe('success', () => {
277
+ it('should update the config', () => {
278
+ const someValue = 1.23;
279
+
280
+ webex.meetings._setLogUploadIntervalMultiplicationFactor(someValue);
281
+ assert.equal(webex.meetings.config.logUploadIntervalMultiplicationFactor, someValue);
282
+ });
283
+ });
284
+
285
+ describe('failure', () => {
286
+ it('should not accept non-number input', () => {
287
+ const logUploadIntervalMultiplicationFactor = webex.meetings.config.logUploadIntervalMultiplicationFactor;
288
+
289
+ webex.meetings._setLogUploadIntervalMultiplicationFactor('test');
290
+ assert.equal(
291
+ webex.meetings.config.logUploadIntervalMultiplicationFactor,
292
+ logUploadIntervalMultiplicationFactor
293
+ );
294
+ });
295
+ });
296
+ });
297
+
270
298
  describe('#_toggleUnifiedMeetings', () => {
271
299
  it('should have toggleUnifiedMeetings', () => {
272
300
  assert.equal(typeof webex.meetings._toggleUnifiedMeetings, 'function');
@@ -375,21 +403,21 @@ describe('plugin-meetings', () => {
375
403
  assert.isTrue(webex.meetings.registered);
376
404
  });
377
405
 
378
- it('rejects when SDK canAuthorize is false', () => {
406
+ it('rejects when SDK canAuthorize is false', async () => {
379
407
  webex.canAuthorize = false;
380
- assert.isRejected(webex.meetings.register());
408
+ await assert.isRejected(webex.meetings.register());
381
409
  });
382
410
 
383
- it('rejects when device.register fails', () => {
411
+ it('rejects when device.register fails', async () => {
384
412
  webex.canAuthorize = true;
385
413
  webex.internal.device.register = sinon.stub().returns(Promise.reject());
386
- assert.isRejected(webex.meetings.register());
414
+ await assert.isRejected(webex.meetings.register());
387
415
  });
388
416
 
389
- it('rejects when mercury.connect fails', () => {
417
+ it('rejects when mercury.connect fails', async () => {
390
418
  webex.canAuthorize = true;
391
419
  webex.internal.mercury.connect = sinon.stub().returns(Promise.reject());
392
- assert.isRejected(webex.meetings.register());
420
+ await assert.isRejected(webex.meetings.register());
393
421
  });
394
422
 
395
423
  it('resolves immediately if already registered', async () => {
@@ -420,6 +448,100 @@ describe('plugin-meetings', () => {
420
448
  includeDetails: CatalogDetails.features,
421
449
  });
422
450
  });
451
+
452
+ it('updates registration status as expected', async () => {
453
+ const clock = sinon.useFakeTimers();
454
+
455
+ const delay = (secs) => () =>
456
+ new Promise((resolve) => {
457
+ setTimeout(resolve, secs * 1000);
458
+ });
459
+
460
+ let i = 1;
461
+ sinon.stub(webex.meetings, 'fetchUserPreferredWebexSite').callsFake(delay(i++));
462
+ MeetingsUtil.checkH264Support.callsFake(delay(i++));
463
+ webex.meetings.startReachability.callsFake(delay(i++));
464
+ webex.internal.device.register.callsFake(delay(i++));
465
+ sinon.stub(webex.meetings, 'getGeoHint').callsFake(delay(i++));
466
+ webex.internal.mercury.connect.callsFake(delay(i++));
467
+
468
+ webex.canAuthorize = true;
469
+ webex.meetings.registered = false;
470
+
471
+ const registerPromise = webex.meetings.register({
472
+ includeDetails: CatalogDetails.features,
473
+ });
474
+
475
+ await clock.tick(1000);
476
+ await webex.meetings.fetchUserPreferredWebexSite;
477
+ assert.deepEqual(webex.meetings.registrationStatus, {
478
+ fetchWebexSite: true,
479
+ getGeoHint: false,
480
+ startReachability: false,
481
+ deviceRegister: false,
482
+ mercuryConnect: false,
483
+ checkH264Support: false,
484
+ });
485
+
486
+ await clock.tick(1000);
487
+ await MeetingsUtil.checkH264Support;
488
+ assert.deepEqual(webex.meetings.registrationStatus, {
489
+ fetchWebexSite: true,
490
+ getGeoHint: false,
491
+ startReachability: false,
492
+ deviceRegister: false,
493
+ mercuryConnect: false,
494
+ checkH264Support: true,
495
+ });
496
+
497
+ await clock.tick(1000);
498
+ await webex.meetings.startReachability;
499
+ assert.deepEqual(webex.meetings.registrationStatus, {
500
+ fetchWebexSite: true,
501
+ getGeoHint: false,
502
+ startReachability: true,
503
+ deviceRegister: false,
504
+ mercuryConnect: false,
505
+ checkH264Support: true,
506
+ });
507
+
508
+ await clock.tick(1000);
509
+ await webex.internal.device.register;
510
+ assert.deepEqual(webex.meetings.registrationStatus, {
511
+ fetchWebexSite: true,
512
+ getGeoHint: false,
513
+ startReachability: true,
514
+ deviceRegister: true,
515
+ mercuryConnect: false,
516
+ checkH264Support: true,
517
+ });
518
+
519
+ await clock.tick(1000);
520
+ await webex.meetings.getGeoHint;
521
+ assert.deepEqual(webex.meetings.registrationStatus, {
522
+ fetchWebexSite: true,
523
+ getGeoHint: true,
524
+ startReachability: true,
525
+ deviceRegister: true,
526
+ mercuryConnect: false,
527
+ checkH264Support: true,
528
+ });
529
+
530
+ await clock.tick(6000);
531
+ await webex.internal.mercury.connect;
532
+ assert.deepEqual(webex.meetings.registrationStatus, {
533
+ fetchWebexSite: true,
534
+ getGeoHint: true,
535
+ startReachability: true,
536
+ deviceRegister: true,
537
+ mercuryConnect: true,
538
+ checkH264Support: true,
539
+ });
540
+
541
+ await registerPromise;
542
+
543
+ clock.restore();
544
+ });
423
545
  });
424
546
 
425
547
  describe('#unregister', () => {
@@ -440,27 +562,36 @@ describe('plugin-meetings', () => {
440
562
  });
441
563
  });
442
564
 
443
- it('rejects when device.unregister fails', () => {
565
+ it('rejects when device.unregister fails', async () => {
444
566
  webex.meetings.registered = true;
445
567
  webex.internal.device.unregister = sinon.stub().returns(Promise.reject());
446
- assert.isRejected(webex.meetings.unregister());
568
+ await assert.isRejected(webex.meetings.unregister());
447
569
  });
448
570
 
449
- it('rejects when mercury.disconnect fails', () => {
571
+ it('rejects when mercury.disconnect fails', async () => {
450
572
  webex.meetings.registered = true;
451
573
  webex.internal.mercury.disconnect = sinon.stub().returns(Promise.reject());
452
- assert.isRejected(webex.meetings.unregister());
574
+ await assert.isRejected(webex.meetings.unregister());
453
575
  });
454
576
 
455
- it('resolves immediately if already registered', (done) => {
577
+ it('resolves immediately if not registered', (done) => {
456
578
  webex.meetings.registered = false;
457
579
  webex.meetings.unregister().then(() => {
458
- assert.notCalled(webex.internal.device.register);
459
- assert.notCalled(webex.internal.mercury.connect);
580
+ assert.notCalled(webex.internal.device.unregister);
581
+ assert.notCalled(webex.internal.mercury.disconnect);
460
582
  assert.isFalse(webex.meetings.registered);
461
583
  done();
462
584
  });
463
585
  });
586
+
587
+ it('resets registration status', (done) => {
588
+ webex.meetings.registered = true;
589
+ webex.meetings.registrationStatus = {foo: 'bar'};
590
+ webex.meetings.unregister().then(() => {
591
+ assert.deepEqual(webex.meetings.registrationStatus, INITIAL_REGISTRATION_STATUS);
592
+ done();
593
+ });
594
+ });
464
595
  });
465
596
 
466
597
  describe('virtual background effect', () => {
@@ -1985,6 +2116,8 @@ describe('plugin-meetings', () => {
1985
2116
  const meetingIds = {
1986
2117
  meetingId: meeting.id,
1987
2118
  correlationId: meeting.correlationId,
2119
+ roles: meeting.roles,
2120
+ callStateForMetrics: meeting.callStateForMetrics,
1988
2121
  };
1989
2122
 
1990
2123
  webex.meetings.destroy(meeting, test1);
@@ -2021,6 +2154,8 @@ describe('plugin-meetings', () => {
2021
2154
 
2022
2155
  assert.equal(deletedMeetingInfo.id, meetingIds.meetingId);
2023
2156
  assert.equal(deletedMeetingInfo.correlationId, meetingIds.correlationId);
2157
+ assert.equal(deletedMeetingInfo.roles, meetingIds.roles);
2158
+ assert.equal(deletedMeetingInfo.callStateForMetrics, meetingIds.callStateForMetrics);
2024
2159
  });
2025
2160
  });
2026
2161
 
@@ -2092,7 +2227,7 @@ describe('plugin-meetings', () => {
2092
2227
  );
2093
2228
  });
2094
2229
 
2095
- const setup = ({me = { type: 'validuser'}, user} = {}) => {
2230
+ const setup = ({me = {type: 'validuser'}, user} = {}) => {
2096
2231
  loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
2097
2232
  assert.deepEqual(webex.internal.services._getCatalog().getAllowedDomains(), []);
2098
2233
 
@@ -2113,9 +2248,9 @@ describe('plugin-meetings', () => {
2113
2248
 
2114
2249
  it('should not call request.getMeetingPreferences if user is a guest', async () => {
2115
2250
  setup({me: {type: 'appuser'}});
2116
-
2251
+
2117
2252
  await webex.meetings.fetchUserPreferredWebexSite();
2118
-
2253
+
2119
2254
  assert.equal(webex.meetings.preferredWebexSite, '');
2120
2255
  assert.deepEqual(webex.internal.services._getCatalog().getAllowedDomains(), []);
2121
2256
  assert.notCalled(webex.internal.services.getMeetingPreferences);
@@ -290,4 +290,14 @@ describe('plugin-meetings', () => {
290
290
  assert.equal(MeetingsUtil.isValidBreakoutLocus(newLocus), true);
291
291
  });
292
292
  });
293
+
294
+ describe('#getMediaServer', () => {
295
+ it('returns the contents of o-line lower cased', () => {
296
+ const sdp1 = 'v=0\r\no=homer 0 1 IN IP4 23.89.67.81\r\ns=-\r\nc=IN IP4 23.89.67.81\r\nb=TIAS:128000\r\nt=0 0\r\na=ice-lite\r\n'
297
+ assert.equal(MeetingsUtil.getMediaServer(sdp1), 'homer');
298
+
299
+ const sdp2 = 'v=0\r\no=HOMER 0 1 IN IP4 23.89.67.81\r\ns=-\r\nc=IN IP4 23.89.67.81\r\nb=TIAS:128000\r\nt=0 0\r\na=ice-lite\r\n'
300
+ assert.equal(MeetingsUtil.getMediaServer(sdp2), 'homer');
301
+ });
302
+ })
293
303
  });
@@ -5,13 +5,13 @@ import {_SEND_RECEIVE_, _RECEIVE_ONLY_} from '../../../../src/constants';
5
5
 
6
6
  describe('plugin-meetings', () => {
7
7
  describe('isHandRaised', () => {
8
- it('throws error when there is no participant', () => {
8
+ it('throws an error when there is no participant', () => {
9
9
  assert.throws(() => {
10
10
  MemberUtil.isHandRaised();
11
11
  }, 'Raise hand could not be processed, participant is undefined.');
12
12
  });
13
13
 
14
- it('returns false when controls is not there', () => {
14
+ it('returns false when controls are not present', () => {
15
15
  const participant = {};
16
16
 
17
17
  assert.isFalse(MemberUtil.isHandRaised(participant));
@@ -51,7 +51,7 @@ describe('plugin-meetings', () => {
51
51
  });
52
52
 
53
53
  describe('MemberUtil.canReclaimHost', () => {
54
- it('throws error when there is no participant', () => {
54
+ it('throws an error when there is no participant', () => {
55
55
  assert.throws(() => {
56
56
  MemberUtil.canReclaimHost();
57
57
  }, 'canReclaimHostRole could not be processed, participant is undefined.');
@@ -352,8 +352,49 @@ describe('plugin-meetings', () => {
352
352
  });
353
353
  });
354
354
 
355
+ describe('MemberUtil.isBrb', () => {
356
+ it('returns true when brb is enabled', () => {
357
+ const participant = {
358
+ controls: {
359
+ brb: {
360
+ enabled: true,
361
+ },
362
+ },
363
+ };
364
+
365
+ assert.isTrue(MemberUtil.isBrb(participant));
366
+ });
367
+
368
+ it('returns false when brb is disabled', () => {
369
+ const participant = {
370
+ controls: {
371
+ brb: {
372
+ enabled: false,
373
+ },
374
+ },
375
+ };
376
+
377
+ assert.isFalse(MemberUtil.isBrb(participant));
378
+ });
379
+
380
+
381
+ it('returns false when brb is not present', () => {
382
+ const participant = {
383
+ controls: {},
384
+ };
385
+
386
+ assert.isFalse(MemberUtil.isBrb(participant));
387
+ });
388
+
389
+ it('returns false when controls is not present', () => {
390
+ const participant = {};
391
+
392
+ assert.isFalse(MemberUtil.isBrb(participant));
393
+ });
394
+ });
395
+
355
396
  describe('MemberUtil.isBreakoutsSupported', () => {
356
- it('throws error when there is no participant', () => {
397
+ it('throws an error when there is no participant', () => {
357
398
  assert.throws(() => {
358
399
  MemberUtil.isBreakoutsSupported();
359
400
  }, 'Breakout support could not be processed, participant is undefined.');
@@ -377,7 +418,7 @@ describe('plugin-meetings', () => {
377
418
  });
378
419
 
379
420
  describe('MemberUtil.isLiveAnnotationSupported', () => {
380
- it('throws error when there is no participant', () => {
421
+ it('throws an error when there is no participant', () => {
381
422
  assert.throws(() => {
382
423
  MemberUtil.isLiveAnnotationSupported();
383
424
  }, 'LiveAnnotation support could not be processed, participant is undefined.');
@@ -401,7 +442,7 @@ describe('plugin-meetings', () => {
401
442
  });
402
443
 
403
444
  describe('MemberUtil.isInterpretationSupported', () => {
404
- it('throws error when there is no participant', () => {
445
+ it('throws an error when there is no participant', () => {
405
446
  assert.throws(() => {
406
447
  MemberUtil.isInterpretationSupported();
407
448
  }, 'Interpretation support could not be processed, participant is undefined.');
@@ -432,7 +473,7 @@ describe('plugin-meetings', () => {
432
473
  };
433
474
 
434
475
  describe('MemberUtil.isAudioMuted', () => {
435
- it('throws error when there is no participant', () => {
476
+ it('throws an error when there is no participant', () => {
436
477
  assert.throws(() => {
437
478
  MemberUtil.isAudioMuted();
438
479
  }, 'Audio could not be processed, participant is undefined.');
@@ -475,7 +516,7 @@ describe('plugin-meetings', () => {
475
516
  });
476
517
 
477
518
  describe('MemberUtil.isVideoMuted', () => {
478
- it('throws error when there is no participant', () => {
519
+ it('throws an error when there is no participant', () => {
479
520
  assert.throws(() => {
480
521
  MemberUtil.isVideoMuted();
481
522
  }, 'Video could not be processed, participant is undefined.');
@@ -519,7 +560,7 @@ describe('plugin-meetings', () => {
519
560
  });
520
561
 
521
562
  describe('extractMediaStatus', () => {
522
- it('throws error when there is no participant', () => {
563
+ it('throws an error when there is no participant', () => {
523
564
  assert.throws(() => {
524
565
  MemberUtil.extractMediaStatus()
525
566
  }, 'Media status could not be extracted, participant is undefined.');
@@ -529,7 +570,7 @@ describe('extractMediaStatus', () => {
529
570
  const participant = {
530
571
  status: {}
531
572
  };
532
-
573
+
533
574
  const mediaStatus = MemberUtil.extractMediaStatus(participant)
534
575
 
535
576
  assert.deepEqual(mediaStatus, {audio: undefined, video: undefined});
@@ -542,7 +583,7 @@ describe('extractMediaStatus', () => {
542
583
  videoStatus: 'SENDRECV'
543
584
  }
544
585
  };
545
-
586
+
546
587
  const mediaStatus = MemberUtil.extractMediaStatus(participant)
547
588
 
548
589
  assert.deepEqual(mediaStatus, {audio: 'RECVONLY', video: 'SENDRECV'});
@@ -249,14 +249,18 @@ describe('RemoteMedia', () => {
249
249
 
250
250
  forEach(
251
251
  [
252
- {height: 134, fs: 60},
253
- {height: 135, fs: 240},
254
- {height: 269, fs: 240},
255
- {height: 270, fs: 920},
256
- {height: 539, fs: 920},
257
- {height: 540, fs: 3600},
252
+ {height: 90, fs: 60}, // 90p
253
+ {height: 98, fs: 60},
254
+ {height: 99, fs: 240}, // 180p
255
+ {height: 180, fs: 240},
256
+ {height: 197, fs: 240},
257
+ {height: 198, fs: 920}, // 360p
258
+ {height: 360, fs: 920},
259
+ {height: 395, fs: 920},
260
+ {height: 396, fs: 3600}, // 720p
258
261
  {height: 720, fs: 3600},
259
- {height: 721, fs: 8192},
262
+ {height: 721, fs: 8192}, // 1080p
263
+ {height: 1080, fs: 8192},
260
264
  ],
261
265
  ({height, fs}) => {
262
266
  it(`sets the max fs to ${fs} correctly when height is ${height}`, () => {