@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
@@ -169,26 +169,6 @@ describe('LocusMediaRequest.send()', () => {
169
169
  mockWebex.internal.newMetrics.submitClientEvent.resetHistory();
170
170
  };
171
171
 
172
- const checkMetrics = (expectedMetrics: boolean = true) => {
173
- if (expectedMetrics) {
174
- assert.calledWith(mockWebex.internal.newMetrics.submitClientEvent, {
175
- name: 'client.locus.media.request',
176
- options: {
177
- meetingId: 'meetingId',
178
- },
179
- });
180
-
181
- assert.calledWith(mockWebex.internal.newMetrics.submitClientEvent, {
182
- name: 'client.locus.media.response',
183
- options: {
184
- meetingId: 'meetingId',
185
- },
186
- });
187
- } else {
188
- assert.notCalled(mockWebex.internal.newMetrics.submitClientEvent);
189
- }
190
- };
191
-
192
172
  it('sends a roap message', async () => {
193
173
  const result = await sendRoapMessage('OFFER');
194
174
 
@@ -201,8 +181,6 @@ describe('LocusMediaRequest.send()', () => {
201
181
  upload: sinon.match.instanceOf(EventEmitter),
202
182
  download: sinon.match.instanceOf(EventEmitter),
203
183
  });
204
-
205
- checkMetrics();
206
184
  });
207
185
 
208
186
  it('sends correct metric event when roap message fails', async () => {
@@ -232,8 +210,6 @@ describe('LocusMediaRequest.send()', () => {
232
210
  upload: sinon.match.instanceOf(EventEmitter),
233
211
  download: sinon.match.instanceOf(EventEmitter),
234
212
  });
235
-
236
- checkMetrics(false);
237
213
  });
238
214
 
239
215
  it('sends a local mute request with sequence', async () => {
@@ -282,8 +258,6 @@ describe('LocusMediaRequest.send()', () => {
282
258
  upload: sinon.match.instanceOf(EventEmitter),
283
259
  download: sinon.match.instanceOf(EventEmitter),
284
260
  });
285
-
286
- checkMetrics(false);
287
261
  });
288
262
 
289
263
  it('sends a local mute request with the last audio/video mute values', async () => {
@@ -303,8 +277,6 @@ describe('LocusMediaRequest.send()', () => {
303
277
  upload: sinon.match.instanceOf(EventEmitter),
304
278
  download: sinon.match.instanceOf(EventEmitter),
305
279
  });
306
-
307
- checkMetrics(false);
308
280
  });
309
281
 
310
282
  it('sends only roap when roap and local mute are requested', async () => {
@@ -324,8 +296,6 @@ describe('LocusMediaRequest.send()', () => {
324
296
  upload: sinon.match.instanceOf(EventEmitter),
325
297
  download: sinon.match.instanceOf(EventEmitter),
326
298
  });
327
-
328
- checkMetrics();
329
299
  });
330
300
 
331
301
  describe('queueing', () => {
@@ -2,7 +2,6 @@ import sinon from 'sinon';
2
2
  import {assert} from '@webex/test-helper-chai';
3
3
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
4
4
  import {createMuteState, MuteState} from '@webex/plugin-meetings/src/meeting/muteState';
5
- import PermissionError from '@webex/plugin-meetings/src/common/errors/permission';
6
5
  import {AUDIO, VIDEO} from '@webex/plugin-meetings/src/constants';
7
6
 
8
7
  import testUtils from '../../../utils/testUtils';
@@ -39,7 +38,6 @@ describe('plugin-meetings', () => {
39
38
  unmuteAllowed: true,
40
39
  remoteVideoMuted: false,
41
40
  unmuteVideoAllowed: true,
42
-
43
41
  locusInfo: {
44
42
  handleLocusDelta: sinon.stub(),
45
43
  },
@@ -778,5 +776,78 @@ describe('plugin-meetings', () => {
778
776
  })
779
777
  );
780
778
  });
779
+
780
+ describe('#enable', () => {
781
+ let locusLocalMuteStub;
782
+ let locusRemoteMuteStub;
783
+
784
+ const resetStubHistory = () => {
785
+ locusLocalMuteStub.resetHistory();
786
+ locusRemoteMuteStub.resetHistory();
787
+ };
788
+
789
+ beforeEach(async () => {
790
+ locusLocalMuteStub = MeetingUtil.remoteUpdateAudioVideo;
791
+ locusRemoteMuteStub = meeting.members.muteMember;
792
+
793
+ // initialise the MuteState with the stream
794
+ audio.handleLocalStreamChange(meeting);
795
+ await testUtils.flushPromises();
796
+
797
+ resetStubHistory();
798
+ });
799
+
800
+ it('does not do anything if current state is already the same', async () => {
801
+ // set it up so that we are remotely muted (so that a sync to server would do a remote unmute)
802
+ audio.handleServerRemoteMuteUpdate(meeting, true, true);
803
+
804
+ // audio is already enabled and we call to enable it again
805
+ audio.enable(meeting, true);
806
+ await testUtils.flushPromises();
807
+
808
+ // nothing should happen (especially no remote unmute)
809
+ assert.notCalled(locusRemoteMuteStub);
810
+ assert.notCalled(locusLocalMuteStub);
811
+
812
+ // now disable audio
813
+ audio.enable(meeting, false);
814
+ await testUtils.flushPromises();
815
+
816
+ resetStubHistory();
817
+
818
+ // disable it again
819
+ audio.enable(meeting, false);
820
+ await testUtils.flushPromises();
821
+
822
+ // nothing should happen
823
+ assert.notCalled(locusRemoteMuteStub);
824
+ assert.notCalled(locusLocalMuteStub);
825
+ });
826
+
827
+ it('does necessary local and remote mute changes when called with a new state', async () => {
828
+ // initial state is audio enabled with nothing muted
829
+
830
+ // now we disable audio
831
+ audio.enable(meeting, false);
832
+ await testUtils.flushPromises();
833
+
834
+ // so only a local mute should be done
835
+ assert.notCalled(locusRemoteMuteStub);
836
+ assert.calledWith(locusLocalMuteStub, meeting, true, undefined);
837
+
838
+ resetStubHistory();
839
+
840
+ // now simulate additionally a remote mute
841
+ audio.state.server.remoteMute = true;
842
+
843
+ // and enable audio back
844
+ audio.enable(meeting, true);
845
+ await testUtils.flushPromises();
846
+
847
+ // both local and remote unmute should be done
848
+ assert.calledWith(locusRemoteMuteStub, meeting.members.selfId, false, true);
849
+ assert.calledWith(locusLocalMuteStub, meeting, false, undefined);
850
+ });
851
+ });
781
852
  });
782
853
  });
@@ -1,4 +1,5 @@
1
1
  import 'jsdom-global/register';
2
+ import {v4 as uuidv4} from 'uuid';
2
3
  import sinon from 'sinon';
3
4
  import {assert} from '@webex/test-helper-chai';
4
5
  import MockWebex from '@webex/test-helper-mock-webex';
@@ -205,7 +206,7 @@ describe('plugin-meetings', () => {
205
206
  roapMessage,
206
207
  reachability,
207
208
  permissionToken,
208
- clientMediaPreferences
209
+ clientMediaPreferences,
209
210
  });
210
211
  const requestParams = meetingsRequest.request.getCall(0).args[0];
211
212
 
@@ -630,6 +631,36 @@ describe('plugin-meetings', () => {
630
631
  });
631
632
  });
632
633
 
634
+ describe('#setPostMeetingDataConsent', () => {
635
+ [true, false].forEach((consent) => {
636
+ it(`sends request to set post meeting data consent with ${consent}`, async () => {
637
+ const locusUrl = `https://locus-test.wbx2.com/locus/api/v1/loci/${consent}`;
638
+ const selfId = uuidv4();
639
+ const deviceUrl = `https://wdm-test.wbx2.com/wdm/api/v1/devices/${consent}`;
640
+
641
+ const consentPromise = meetingsRequest.setPostMeetingDataConsent({
642
+ postMeetingDataConsent: consent,
643
+ locusUrl,
644
+ selfId,
645
+ deviceUrl,
646
+ });
647
+ assert.exists(consentPromise.then);
648
+ await consentPromise;
649
+
650
+ checkRequest({
651
+ method: 'PATCH',
652
+ uri: `${locusUrl}/participant/${selfId}/controls`,
653
+ body: {
654
+ consent: {
655
+ postMeetingDataConsent: consent,
656
+ deviceUrl,
657
+ },
658
+ },
659
+ });
660
+ });
661
+ });
662
+ });
663
+
633
664
  describe('#prepareLeaveMeetingRequestOptions', () => {
634
665
  it('returns expected result', async () => {
635
666
  const result = meetingsRequest.prepareLeaveMeetingRequestOptions({
@@ -66,7 +66,7 @@ describe('plugin-meetings', () => {
66
66
 
67
67
  describe('#cleanup', () => {
68
68
  it('do clean up on meeting object with LLM enabled', async () => {
69
- meeting.config = {enableAutomaticLLM : true};
69
+ meeting.config = {enableAutomaticLLM: true};
70
70
  await MeetingUtil.cleanUp(meeting);
71
71
  assert.calledOnce(meeting.cleanupLocalStreams);
72
72
  assert.calledOnce(meeting.closeRemoteStreams);
@@ -84,7 +84,7 @@ describe('plugin-meetings', () => {
84
84
  });
85
85
 
86
86
  it('do clean up on meeting object with LLM disabled', async () => {
87
- meeting.config = {enableAutomaticLLM : false};
87
+ meeting.config = {enableAutomaticLLM: false};
88
88
  await MeetingUtil.cleanUp(meeting);
89
89
  assert.calledOnce(meeting.cleanupLocalStreams);
90
90
  assert.calledOnce(meeting.closeRemoteStreams);
@@ -392,8 +392,7 @@ describe('plugin-meetings', () => {
392
392
  meetingJoinUrl: 'meetingJoinUrl',
393
393
  locusUrl: 'locusUrl',
394
394
  meetingRequest: {
395
- joinMeeting: sinon.stub().returns(
396
- Promise.resolve(joinMeetingResponse)),
395
+ joinMeeting: sinon.stub().returns(Promise.resolve(joinMeetingResponse)),
397
396
  },
398
397
  getWebexObject: sinon.stub().returns(webex),
399
398
  setLocus: sinon.stub(),
@@ -410,23 +409,29 @@ describe('plugin-meetings', () => {
410
409
  id: 'fake client media preferences',
411
410
  };
412
411
 
413
- webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(FAKE_REACHABILITY_REPORT);
414
- webex.meetings.reachability.getClientMediaPreferences.resolves(FAKE_CLIENT_MEDIA_PREFERENCES);
412
+ webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(
413
+ FAKE_REACHABILITY_REPORT
414
+ );
415
+ webex.meetings.reachability.getClientMediaPreferences.resolves(
416
+ FAKE_CLIENT_MEDIA_PREFERENCES
417
+ );
415
418
 
416
- sinon
417
- .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
418
- .get(() => true);
419
- sinon
420
- .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
421
- .get(() => true);
419
+ sinon.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4').get(() => true);
420
+ sinon.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6').get(() => true);
422
421
 
423
422
  await MeetingUtil.joinMeeting(meeting, {
424
423
  reachability: 'reachability',
425
424
  roapMessage: 'roapMessage',
426
425
  });
427
426
 
428
- assert.calledOnceWithExactly(webex.meetings.reachability.getReachabilityReportToAttachToRoap);
429
- assert.calledOnceWithExactly(webex.meetings.reachability.getClientMediaPreferences, meeting.isMultistream, IP_VERSION.ipv4_and_ipv6);
427
+ assert.calledOnceWithExactly(
428
+ webex.meetings.reachability.getReachabilityReportToAttachToRoap
429
+ );
430
+ assert.calledOnceWithExactly(
431
+ webex.meetings.reachability.getClientMediaPreferences,
432
+ meeting.isMultistream,
433
+ IP_VERSION.ipv4_and_ipv6
434
+ );
430
435
 
431
436
  assert.calledOnce(meeting.meetingRequest.joinMeeting);
432
437
  const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
@@ -436,9 +441,9 @@ describe('plugin-meetings', () => {
436
441
  assert.equal(parameter.clientMediaPreferences, FAKE_CLIENT_MEDIA_PREFERENCES);
437
442
  assert.equal(parameter.roapMessage, 'roapMessage');
438
443
 
439
- assert.calledOnce(meeting.setLocus)
444
+ assert.calledOnce(meeting.setLocus);
440
445
  const setLocusParameter = meeting.setLocus.getCall(0).args[0];
441
- assert.deepEqual(setLocusParameter, MeetingUtil.parseLocusJoin(joinMeetingResponse))
446
+ assert.deepEqual(setLocusParameter, MeetingUtil.parseLocusJoin(joinMeetingResponse));
442
447
 
443
448
  assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
444
449
  name: 'client.locus.join.request',
@@ -460,7 +465,6 @@ describe('plugin-meetings', () => {
460
465
  });
461
466
  });
462
467
 
463
-
464
468
  it('#Should call `meetingRequest.joinMeeting and handle a date header in the response : isoLocalClientMeetingJoinedTime', async () => {
465
469
  meeting.isMultistream = true;
466
470
 
@@ -471,30 +475,30 @@ describe('plugin-meetings', () => {
471
475
  id: 'fake client media preferences',
472
476
  };
473
477
 
474
- webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(FAKE_REACHABILITY_REPORT);
475
- webex.meetings.reachability.getClientMediaPreferences.resolves(FAKE_CLIENT_MEDIA_PREFERENCES);
478
+ webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(
479
+ FAKE_REACHABILITY_REPORT
480
+ );
481
+ webex.meetings.reachability.getClientMediaPreferences.resolves(
482
+ FAKE_CLIENT_MEDIA_PREFERENCES
483
+ );
476
484
 
477
- sinon
478
- .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
479
- .get(() => true);
480
- sinon
481
- .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
482
- .get(() => true);
485
+ sinon.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4').get(() => true);
486
+ sinon.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6').get(() => true);
483
487
 
484
488
  meeting.meetingRequest.joinMeeting.resolves({
485
489
  headers: {
486
- date: 'test'
490
+ date: 'test',
487
491
  },
488
492
  body: {
489
493
  mediaConnections: [{mediaId: 'test'}],
490
494
  locus: {
491
495
  url: 'test',
492
496
  self: {
493
- id: 'test'
494
- }
495
- }
496
- }
497
- })
497
+ id: 'test',
498
+ },
499
+ },
500
+ },
501
+ });
498
502
 
499
503
  await MeetingUtil.joinMeeting(meeting, {
500
504
  reachability: 'reachability',
@@ -740,6 +744,18 @@ describe('plugin-meetings', () => {
740
744
  });
741
745
  });
742
746
 
747
+ describe('requiresPostMeetingDataConsentPrompt', () => {
748
+ it('works as expected', () => {
749
+ assert.deepEqual(
750
+ MeetingUtil.requiresPostMeetingDataConsentPrompt([
751
+ 'SHOW_POST_MEETING_DATA_CONSENT_PROMPT',
752
+ ]),
753
+ true
754
+ );
755
+ assert.deepEqual(MeetingUtil.requiresPostMeetingDataConsentPrompt([]), false);
756
+ });
757
+ });
758
+
743
759
  describe('canUserRenameOthers', () => {
744
760
  it('works as expected', () => {
745
761
  assert.deepEqual(MeetingUtil.canUserRenameOthers(['CAN_RENAME_OTHERS']), true);
@@ -749,8 +765,38 @@ describe('plugin-meetings', () => {
749
765
 
750
766
  describe('canShareWhiteBoard', () => {
751
767
  it('works as expected', () => {
752
- assert.deepEqual(MeetingUtil.canShareWhiteBoard(['SHARE_WHITEBOARD']), true);
753
- assert.deepEqual(MeetingUtil.canShareWhiteBoard([]), false);
768
+ assert.deepEqual(
769
+ MeetingUtil.canShareWhiteBoard(['SHARE_WHITEBOARD'], {
770
+ [SELF_POLICY.SUPPORT_WHITEBOARD]: true,
771
+ }),
772
+ true
773
+ );
774
+ assert.deepEqual(
775
+ MeetingUtil.canShareWhiteBoard([], {
776
+ [SELF_POLICY.SUPPORT_WHITEBOARD]: true,
777
+ }),
778
+ false
779
+ );
780
+ assert.deepEqual(
781
+ MeetingUtil.canShareWhiteBoard(['SHARE_WHITEBOARD'], {
782
+ [SELF_POLICY.SUPPORT_WHITEBOARD]: false,
783
+ }),
784
+ false
785
+ );
786
+ assert.deepEqual(
787
+ MeetingUtil.canShareWhiteBoard([], {
788
+ [SELF_POLICY.SUPPORT_WHITEBOARD]: false,
789
+ }),
790
+ false
791
+ );
792
+ assert.deepEqual(MeetingUtil.canShareWhiteBoard(['SHARE_WHITEBOARD'], undefined), false);
793
+ });
794
+ });
795
+
796
+ describe('canMoveToLobby', () => {
797
+ it('works as expected', () => {
798
+ assert.deepEqual(MeetingUtil.canMoveToLobby(['MOVE_TO_LOBBY']), true);
799
+ assert.deepEqual(MeetingUtil.canMoveToLobby([]), false);
754
800
  });
755
801
  });
756
802
 
@@ -511,6 +511,7 @@ describe('plugin-meetings', () => {
511
511
  password: 'abc',
512
512
  captchaID: '999',
513
513
  captchaVerifyCode: 'aabbcc11',
514
+ disableWebRedirect: true,
514
515
  },
515
516
  });
516
517
  assert.deepEqual(result, requestResponse);
@@ -544,6 +545,7 @@ describe('plugin-meetings', () => {
544
545
  supportCountryList: true,
545
546
  meetingKey: '1234323',
546
547
  installedOrgID,
548
+ disableWebRedirect: true,
547
549
  },
548
550
  });
549
551
  assert.deepEqual(result, requestResponse);
@@ -578,6 +580,7 @@ describe('plugin-meetings', () => {
578
580
  supportCountryList: true,
579
581
  meetingKey: '1234323',
580
582
  locusId,
583
+ disableWebRedirect: true,
581
584
  },
582
585
  });
583
586
  assert.deepEqual(result, requestResponse);
@@ -613,6 +616,7 @@ describe('plugin-meetings', () => {
613
616
  supportCountryList: true,
614
617
  meetingKey: '1234323',
615
618
  ...extraParams,
619
+ disableWebRedirect: true,
616
620
  },
617
621
  });
618
622
  assert.deepEqual(result, requestResponse);
@@ -843,6 +847,7 @@ describe('plugin-meetings', () => {
843
847
  supportCountryList: true,
844
848
  meetingKey: '1234323',
845
849
  ...extraParams,
850
+ disableWebRedirect: true,
846
851
  },
847
852
  });
848
853
  assert.deepEqual(result, requestResponse);
@@ -922,6 +927,7 @@ describe('plugin-meetings', () => {
922
927
  supportCountryList: true,
923
928
  meetingKey: '1234323',
924
929
  ...extraParams,
930
+ disableWebRedirect: true,
925
931
  },
926
932
  });
927
933
  assert.deepEqual(result, requestResponse);
@@ -1065,6 +1071,41 @@ describe('plugin-meetings', () => {
1065
1071
  });
1066
1072
  });
1067
1073
 
1074
+ describe('should stop call fetchMeetingInfo if siteFullUrl is empty for 404 response', () => {
1075
+
1076
+ const runTest = async (wbxAppApiCode, expectedIsPasswordRequired) => {
1077
+ webex.request = sinon.stub().rejects({
1078
+ statusCode: 404,
1079
+ body: {
1080
+ code: wbxAppApiCode,
1081
+ message: 'Alternate Meeting Server',
1082
+ data: {
1083
+ 'siteFullUrl': ''
1084
+ }
1085
+ },
1086
+ });
1087
+
1088
+
1089
+ try {
1090
+ await meetingInfo.fetchMeetingInfo('1234323', DESTINATION_TYPE.MEETING_ID, 'abc', {
1091
+ id: '999',
1092
+ code: 'aabbcc11',
1093
+ });
1094
+ assert.fail('fetchMeetingInfo should have thrown, but has not done that');
1095
+ } catch (err) {
1096
+ assert(Metrics.sendBehavioralMetric.calledOnce);
1097
+ assert.deepEqual(err.body.data, {
1098
+ siteFullUrl: ''
1099
+ });
1100
+ }
1101
+ };
1102
+
1103
+ it('should throw MeetingInfoV2CaptchaError for 404 response (wbxappapi code 404100)', async () => {
1104
+ await runTest(404100, false);
1105
+ });
1106
+ });
1107
+
1108
+
1068
1109
  it('should throw an error and not fetch with an "empty" body', async () => {
1069
1110
  const body = {supportHostKey: 'foo', supportCountryList: 'bar'};
1070
1111
  const requestResponse = {statusCode: 200, body};
@@ -241,6 +241,25 @@ describe('plugin-meetings', () => {
241
241
  }
242
242
  );
243
243
  });
244
+
245
+ it('allows for disableWebRedirect', () => {
246
+
247
+ const res = MeetingInfoUtil.getRequestBody({
248
+ type: DESTINATION_TYPE.CONVERSATION_URL,
249
+ destination: 'https://conv-a.wbx2.com/conversation/api/v1/conversations/bfb49281',
250
+ disableWebRedirect: true,
251
+ });
252
+
253
+ assert.deepEqual(
254
+ res,
255
+ {
256
+ conversationUrl: 'https://conv-a.wbx2.com/conversation/api/v1/conversations/bfb49281',
257
+ supportHostKey: true,
258
+ supportCountryList: true,
259
+ disableWebRedirect: true,
260
+ }
261
+ );
262
+ });
244
263
  });
245
264
 
246
265
  describe('#getWebexSite', () => {
@@ -182,6 +182,15 @@ describe('plugin-meetings', () => {
182
182
  metrics: {
183
183
  submitClientMetrics: sinon.stub().returns(Promise.resolve()),
184
184
  },
185
+ newMetrics: {
186
+ submitClientEvent: sinon.stub(),
187
+ callDiagnosticLatencies: {
188
+ measureLatency: sinon.stub().returns(Promise.resolve()),
189
+ },
190
+ callDiagnosticMetrics: {
191
+ clearErrorCache: sinon.stub(),
192
+ },
193
+ },
185
194
  });
186
195
  webex.emit('ready');
187
196
  });
@@ -391,6 +400,45 @@ describe('plugin-meetings', () => {
391
400
  });
392
401
  });
393
402
 
403
+ describe('#_toggleDisableAudioMainDtx', () => {
404
+ it('should have _toggleDisableAudioMainDtx', () => {
405
+ assert.equal(typeof webex.meetings._toggleDisableAudioMainDtx, 'function');
406
+ });
407
+
408
+ describe('success', () => {
409
+ it('should update meetings to disable audio main dtx', () => {
410
+ webex.meetings._toggleDisableAudioMainDtx(true);
411
+ assert.equal(webex.meetings.config.experimental.disableAudioMainDtx, true);
412
+ });
413
+ });
414
+ });
415
+
416
+ describe('#_toggleEnableAudioTwccForMultistream', () => {
417
+ it('should have _toggleEnableAudioTwccForMultistream', () => {
418
+ assert.equal(typeof webex.meetings._toggleEnableAudioTwccForMultistream, 'function');
419
+ });
420
+
421
+ describe('success', () => {
422
+ it('should update meetings to enable audio twcc support', () => {
423
+ webex.meetings._toggleEnableAudioTwccForMultistream(true);
424
+ assert.equal(webex.meetings.config.enableAudioTwccForMultistream, true);
425
+ });
426
+ });
427
+ });
428
+
429
+ describe('#_toggleStopIceGatheringAfterFirstRelayCandidate', () => {
430
+ it('should have _toggleStopIceGatheringAfterFirstRelayCandidate', () => {
431
+ assert.equal(typeof webex.meetings._toggleStopIceGatheringAfterFirstRelayCandidate, 'function');
432
+ });
433
+
434
+ describe('success', () => {
435
+ it('should update meetings to stop ICE candidates gathering after first relay candidate', () => {
436
+ webex.meetings._toggleStopIceGatheringAfterFirstRelayCandidate(true);
437
+ assert.equal(webex.meetings.config.stopIceGatheringAfterFirstRelayCandidate, true);
438
+ });
439
+ });
440
+ });
441
+
394
442
  describe('Public API Contracts', () => {
395
443
  describe('#register', () => {
396
444
  it('emits an event and resolves when register succeeds', async () => {
@@ -583,6 +631,24 @@ describe('plugin-meetings', () => {
583
631
  await assert.isRejected(webex.meetings.unregister());
584
632
  });
585
633
 
634
+ it('does not reject when device.unregister fails with statusCode 404', (done) => {
635
+ webex.meetings.registered = true;
636
+ webex.internal.device.unregister = sinon.stub().rejects({statusCode: 404});
637
+ webex.meetings.unregister().then(() => {
638
+ assert.calledWith(
639
+ TriggerProxy.trigger,
640
+ sinon.match.instanceOf(Meetings),
641
+ {
642
+ file: 'meetings',
643
+ function: 'unregister',
644
+ },
645
+ 'meetings:unregistered'
646
+ );
647
+ assert.isFalse(webex.meetings.registered);
648
+ done();
649
+ });
650
+ });
651
+
586
652
  it('rejects when mercury.disconnect fails', async () => {
587
653
  webex.meetings.registered = true;
588
654
  webex.internal.mercury.disconnect = sinon.stub().returns(Promise.reject());
@@ -631,6 +697,7 @@ describe('plugin-meetings', () => {
631
697
  quality: 'LOW',
632
698
  authToken: 'fake_token',
633
699
  mirror: false,
700
+ canvasResolutionScaling: 1,
634
701
  });
635
702
  assert.exists(result.enable);
636
703
  assert.exists(result.disable);
@@ -646,6 +713,7 @@ describe('plugin-meetings', () => {
646
713
  quality: 'HIGH',
647
714
  blurStrength: 'STRONG',
648
715
  bgImageUrl: 'https://test.webex.com/landscape.5a535788.jpg',
716
+ canvasResolutionScaling: 1,
649
717
  };
650
718
 
651
719
  const result = await webex.meetings.createVirtualBackgroundEffect(effectOptions);
@@ -680,7 +748,6 @@ describe('plugin-meetings', () => {
680
748
  audioContext: {},
681
749
  authToken: 'fake_token',
682
750
  mode: 'WORKLET',
683
- env: 'prod',
684
751
  avoidSimd: false,
685
752
  });
686
753
  assert.exists(result.enable);