@webex/plugin-meetings 2.13.0 → 2.14.2

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.
@@ -466,108 +466,7 @@ describe('plugin-meetings', () => {
466
466
  })
467
467
  });
468
468
 
469
- class FakeMediaStream {
470
- constructor(tracks) {
471
- this.active = false;
472
- this.id = '5146425f-c240-48cc-b86b-27d422988fb7';
473
- this.tracks = tracks;
474
- }
475
-
476
- addTrack = () => undefined;
477
-
478
- getAudioTracks = () => this.tracks;
479
- }
480
-
481
- class FakeAudioContext {
482
- constructor() {
483
- this.state = 'running';
484
- this.baseLatency = 0.005333333333333333;
485
- this.currentTime = 2.7946666666666666;
486
- this.sampleRate = 48000;
487
- this.audioWorklet = {
488
- addModule: async () => undefined,
489
- };
490
- }
491
-
492
- onstatechange = null;
493
-
494
- createMediaStreamSource() {
495
- return {
496
- connect: () => undefined,
497
- mediaStream: {
498
- getAudioTracks() {
499
- // eslint-disable-next-line no-undef
500
- return [new MediaStreamTrack()];
501
- },
502
- },
503
- };
504
- }
505
-
506
- createMediaStreamDestination() {
507
- return {
508
- stream: {
509
- getAudioTracks() {
510
- // eslint-disable-next-line no-undef
511
- return [new MediaStreamTrack()];
512
- },
513
- },
514
- };
515
- }
516
- }
517
-
518
- class FakeAudioWorkletNode {
519
- constructor() {
520
- this.port = {
521
- postMessage: () => undefined,
522
- };
523
- }
524
-
525
- connect() {
526
- /* placeholder method */
527
- }
528
- }
529
-
530
- class FakeMediaStreamTrack {
531
- constructor() {
532
- this.kind = 'audio';
533
- this.enabled = true;
534
- this.label = 'Default - MacBook Pro Microphone (Built-in)';
535
- this.muted = false;
536
- this.readyState = 'live';
537
- this.contentHint = '';
538
- }
539
-
540
- getSettings() {
541
- return {
542
- sampleRate: 48000
543
- };
544
- }
545
- }
546
- Object.defineProperty(global, 'MediaStream', {
547
- writable: true,
548
- value: FakeMediaStream,
549
- });
550
-
551
- Object.defineProperty(global, 'AudioContext', {
552
- writable: true,
553
- value: FakeAudioContext,
554
- });
555
-
556
- Object.defineProperty(global, 'AudioWorkletNode', {
557
- writable: true,
558
- value: FakeAudioWorkletNode,
559
- });
560
-
561
- Object.defineProperty(global, 'MediaStreamTrack', {
562
- writable: true,
563
- value: FakeMediaStreamTrack,
564
- });
565
-
566
469
  beforeEach(() => {
567
- meeting.canUpdateMedia = sinon.stub().returns(true);
568
- MeetingUtil.validateOptions = sinon.stub().returns(Promise.resolve());
569
- MeetingUtil.updateTransceiver = sinon.stub();
570
-
571
470
  meeting.getMediaStreams = sinon.stub().returns(Promise.resolve());
572
471
  sinon.replace(meeting, 'addMedia', () => {
573
472
  sinon.stub(meeting.mediaProperties, 'audioTrack').value(fakeMediaTrack());
@@ -575,11 +474,7 @@ describe('plugin-meetings', () => {
575
474
  receiveAudio: true
576
475
  });
577
476
  });
578
-
579
- // eslint-disable-next-line no-undef
580
- MediaUtil.createMediaStream = sinon.stub().returns(new MediaStream([fakeMediaTrack()]));
581
477
  });
582
-
583
478
  describe('#enableBNR', () => {
584
479
  it('should have #enableBnr', () => {
585
480
  assert.exists(meeting.enableBNR);
@@ -594,26 +489,14 @@ describe('plugin-meetings', () => {
594
489
  });
595
490
 
596
491
  describe('after audio attached to meeting', () => {
492
+ let handleClientRequest;
493
+
597
494
  beforeEach(async () => {
598
495
  await meeting.getMediaStreams();
599
496
  await meeting.addMedia();
600
497
  });
601
498
 
602
- it('should return true for appropriate sample rate', async () => {
603
- const response = await meeting.enableBNR();
604
-
605
- assert(Metrics.sendBehavioralMetric.calledOnce);
606
- assert.calledWith(
607
- Metrics.sendBehavioralMetric,
608
- BEHAVIORAL_METRICS.ENABLE_BNR_SUCCESS,
609
- );
610
-
611
- assert.equal(response, true);
612
- });
613
-
614
499
  it('should throw error if meeting audio is muted', async () => {
615
- await meeting.getMediaStreams();
616
- await meeting.addMedia();
617
500
  const handleClientRequest = (meeting, mute) => {
618
501
  meeting.mediaProperties.audioTrack.enabled = !mute;
619
502
 
@@ -621,82 +504,53 @@ describe('plugin-meetings', () => {
621
504
  };
622
505
  const isMuted = () => !meeting.mediaProperties.audioTrack.enabled;
623
506
 
507
+ meeting.locusInfo.parsedLocus = {self: {state: 'JOINED'}};
624
508
  meeting.mediaId = 'mediaId';
625
509
  meeting.audio = {handleClientRequest, isMuted};
626
- meeting.locusInfo.parsedLocus = {self: {state: 'JOINED'}};
627
510
  await meeting.muteAudio();
628
511
  await meeting.enableBNR().catch((err) => {
629
- assert(Metrics.sendBehavioralMetric.calledOnce);
630
- assert.calledWith(
631
- Metrics.sendBehavioralMetric,
632
- BEHAVIORAL_METRICS.ENABLE_BNR_FAILURE, {
633
- reason: err.message,
634
- stack: err.stack
635
- }
636
- );
637
512
  assert.equal(err.message, 'Cannot enable BNR while meeting is muted');
638
513
  });
639
514
  });
640
515
 
641
- it('should throw error for inappropriate sample rate and send error metrics', async () => {
642
- const fakeMediaTrack = () => ({
643
- id: Date.now().toString(),
644
- stop: () => {},
645
- readyState: 'live',
646
- getSettings: () => ({
647
- sampleRate: 49000
648
- })
649
- });
516
+ it('should return true on enable bnr success', async () => {
517
+ handleClientRequest = sinon.stub().returns(Promise.resolve(true));
518
+ meeting.effects = {handleClientRequest};
519
+ const response = await meeting.enableBNR();
650
520
 
651
- sinon.stub(meeting.mediaProperties, 'audioTrack').value(fakeMediaTrack());
652
-
653
- // eslint-disable-next-line no-undef
654
- MediaUtil.createMediaStream = sinon.stub().returns(new MediaStream([fakeMediaTrack()]));
655
-
656
- await meeting.enableBNR()
657
- .then(() => {
658
- assert.fail('The expected Error was not thrown.');
659
- })
660
- .catch((err) => {
661
- assert(Metrics.sendBehavioralMetric.calledOnce);
662
- assert.calledWith(
663
- Metrics.sendBehavioralMetric,
664
- BEHAVIORAL_METRICS.ENABLE_BNR_FAILURE, {
665
- reason: err.message,
666
- stack: err.stack
667
- }
668
- );
669
- assert.equal(err.message, 'Sample rate of 49000 is not supported.');
670
- });
521
+ assert.equal(response, true);
671
522
  });
672
523
  });
673
524
  });
674
525
 
675
526
  describe('#disableBNR', () => {
676
- beforeEach(async () => {
677
- await meeting.getMediaStreams();
678
- await meeting.addMedia();
679
- });
527
+ describe('before audio attached to meeting', () => {
528
+ it('should have #disableBnr', () => {
529
+ assert.exists(meeting.disableBNR);
530
+ });
680
531
 
681
- it('should have #disableBnr', () => {
682
- assert.exists(meeting.disableBNR);
532
+ it('should throw no audio error', async () => {
533
+ await meeting.disableBNR().catch((err) => {
534
+ assert.equal(err.toString(), 'Error: Meeting doesn\'t have an audioTrack attached');
535
+ });
536
+ });
683
537
  });
538
+ describe('after audio attached to meeting', () => {
539
+ beforeEach(async () => {
540
+ await meeting.getMediaStreams();
541
+ await meeting.addMedia();
542
+ });
684
543
 
685
- it('should return true if bnr is disabled on bnr enabled track', async () => {
686
- await meeting.enableBNR();
687
- const response = await meeting.disableBNR();
544
+ let handleClientRequest;
545
+ let isBnrEnabled;
688
546
 
689
- assert.equal(response, true);
690
- });
547
+ it('should return true on disable bnr success', async () => {
548
+ handleClientRequest = sinon.stub().returns(Promise.resolve(true));
549
+ isBnrEnabled = sinon.stub().returns(Promise.resolve(true));
550
+ meeting.effects = {handleClientRequest, isBnrEnabled};
551
+ const response = await meeting.disableBNR();
691
552
 
692
- it('should throw error if bnr is not enabled before disabling and send error metrics', async () => {
693
- await meeting.disableBNR().catch((err) => {
694
- assert(Metrics.sendBehavioralMetric.calledOnce);
695
- assert.calledWith(
696
- Metrics.sendBehavioralMetric,
697
- BEHAVIORAL_METRICS.DISABLE_BNR_FAILURE,
698
- );
699
- assert.equal(err.message, 'Can not disable as BNR is not enabled');
553
+ assert.equal(response, true);
700
554
  });
701
555
  });
702
556
  });
@@ -870,16 +724,12 @@ describe('plugin-meetings', () => {
870
724
  });
871
725
  describe('#isTranscriptionSupported', () => {
872
726
  it('should return false if the feature is not supported for the meeting', () => {
873
- meeting.policy = {
874
- WEBEX_ASSISTANT_STATUS_INACTIVE: true
875
- };
727
+ meeting.locusInfo.controls = {transcribe: {transcribing: false}};
876
728
 
877
729
  assert.equal(meeting.isTranscriptionSupported(), false);
878
730
  });
879
731
  it('should return true if webex assitant is enabled', () => {
880
- meeting.policy = {
881
- WEBEX_ASSISTANT_STATUS_ACTIVE: true
882
- };
732
+ meeting.locusInfo.controls = {transcribe: {transcribing: true}};
883
733
 
884
734
  assert.equal(meeting.isTranscriptionSupported(), true);
885
735
  });
@@ -1478,7 +1328,7 @@ describe('plugin-meetings', () => {
1478
1328
 
1479
1329
  sandbox.stub(meeting.mediaProperties, 'peerConnection').value({shareTransceiver: true});
1480
1330
  sandbox.stub(MeetingUtil, 'getTrack').returns({videoTrack: true});
1481
- sandbox.stub(MeetingUtil, 'validateOptions').resolves(true);
1331
+ MeetingUtil.validateOptions = sinon.stub().returns(Promise.resolve(true));
1482
1332
  sandbox.stub(meeting, 'canUpdateMedia').returns(true);
1483
1333
  sandbox.stub(meeting, 'setLocalShareTrack');
1484
1334
 
@@ -1547,13 +1397,14 @@ describe('plugin-meetings', () => {
1547
1397
  const SENDRECV = 'sendrecv';
1548
1398
  const delay = 1e3;
1549
1399
 
1400
+ MeetingUtil.validateOptions = sinon.stub().returns(Promise.resolve(true));
1401
+ MeetingUtil.updateTransceiver = sinon.stub().returns(Promise.resolve(true));
1550
1402
  sandbox.stub(meeting, 'canUpdateMedia').returns(true);
1551
1403
  sandbox.stub(MeetingUtil, 'getTrack').returns({videoTrack: null});
1552
1404
  sandbox.stub(meeting, 'setLocalShareTrack');
1553
1405
  sandbox.stub(meeting, 'unsetLocalShareTrack');
1554
- sandbox.stub(MeetingUtil, 'validateOptions').resolves(true);
1555
1406
  sandbox.stub(meeting, 'checkForStopShare').returns(false);
1556
- sandbox.stub(MeetingUtil, 'updateTransceiver').resolves(true);
1407
+
1557
1408
  sandbox.stub(meeting, 'isLocalShareLive').value(false);
1558
1409
  sandbox.stub(meeting, 'handleShareTrackEnded');
1559
1410
  sandbox.stub(meeting.mediaProperties, 'peerConnection').value({
@@ -2424,11 +2275,6 @@ describe('plugin-meetings', () => {
2424
2275
  assert.equal(meeting.requiredCaptcha, null);
2425
2276
  assert.calledTwice(TriggerProxy.trigger);
2426
2277
  assert.calledWith(TriggerProxy.trigger, meeting, {file: 'meetings', function: 'fetchMeetingInfo'}, 'meeting:meetingInfoAvailable');
2427
- assert(Metrics.sendBehavioralMetric.calledOnce);
2428
- assert.calledWith(
2429
- Metrics.sendBehavioralMetric,
2430
- BEHAVIORAL_METRICS.VERIFY_PASSWORD_SUCCESS,
2431
- );
2432
2278
  });
2433
2279
 
2434
2280
  it('calls meetingInfoProvider with all the right parameters and parses the result when random delay is applied', async () => {
@@ -2500,11 +2346,6 @@ describe('plugin-meetings', () => {
2500
2346
 
2501
2347
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, null, null);
2502
2348
 
2503
- assert(Metrics.sendBehavioralMetric.calledOnce);
2504
- assert.calledWith(
2505
- Metrics.sendBehavioralMetric,
2506
- BEHAVIORAL_METRICS.VERIFY_PASSWORD_ERROR,
2507
- );
2508
2349
  assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
2509
2350
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD);
2510
2351
  assert.equal(meeting.requiredCaptcha, null);
@@ -2525,11 +2366,7 @@ describe('plugin-meetings', () => {
2525
2366
 
2526
2367
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, 'aaa', null);
2527
2368
 
2528
- assert(Metrics.sendBehavioralMetric.calledOnce);
2529
- assert.calledWith(
2530
- Metrics.sendBehavioralMetric,
2531
- BEHAVIORAL_METRICS.VERIFY_CAPTCHA_ERROR,
2532
- );
2369
+
2533
2370
  assert.deepEqual(meeting.meetingInfo, {});
2534
2371
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD);
2535
2372
  assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
@@ -2683,6 +2520,11 @@ describe('plugin-meetings', () => {
2683
2520
  meeting.fetchMeetingInfo = sinon.stub().resolves();
2684
2521
  const result = await meeting.verifyPassword('password', 'captcha id');
2685
2522
 
2523
+ assert(Metrics.sendBehavioralMetric.calledOnce);
2524
+ assert.calledWith(
2525
+ Metrics.sendBehavioralMetric,
2526
+ BEHAVIORAL_METRICS.VERIFY_PASSWORD_SUCCESS,
2527
+ );
2686
2528
  assert.equal(result.isPasswordValid, true);
2687
2529
  assert.equal(result.requiredCaptcha, null);
2688
2530
  assert.equal(result.failureReason, MEETING_INFO_FAILURE_REASON.NONE);
@@ -177,16 +177,17 @@ describe('plugin-meetings', () => {
177
177
  meetingInfo.createAdhocSpaceMeeting.restore();
178
178
  });
179
179
 
180
+
180
181
  it('should throw an error MeetingInfoV2AdhocMeetingError if not able to start adhoc meeting for a conversation', async () => {
181
182
  webex.config.meetings.experimental.enableAdhocMeetings = true;
182
183
 
183
- webex.request = sinon.stub().rejects({statusCode: 403, body: {code: 400000, message: 'Input is invalid'}});
184
+ webex.request = sinon.stub().rejects({statusCode: 403, body: {code: 400000}});
184
185
  try {
185
186
  await meetingInfo.createAdhocSpaceMeeting('conversationUrl');
186
187
  }
187
188
  catch (err) {
188
189
  assert.instanceOf(err, MeetingInfoV2AdhocMeetingError);
189
- assert.deepEqual(err.message, 'Input is invalid, code=400000');
190
+ assert.deepEqual(err.message, 'Failed starting the adhoc meeting, Please contact support team , code=400000');
190
191
  assert.equal(err.wbxAppApiCode, 400000);
191
192
  }
192
193
  });
@@ -201,6 +202,11 @@ describe('plugin-meetings', () => {
201
202
  assert.fail('fetchMeetingInfo should have thrown, but has not done that');
202
203
  }
203
204
  catch (err) {
205
+ assert(Metrics.sendBehavioralMetric.calledOnce);
206
+ assert.calledWith(
207
+ Metrics.sendBehavioralMetric,
208
+ BEHAVIORAL_METRICS.VERIFY_PASSWORD_ERROR,
209
+ );
204
210
  assert.instanceOf(err, MeetingInfoV2PasswordError);
205
211
  assert.deepEqual(err.meetingInfo, FAKE_MEETING_INFO);
206
212
  assert.equal(err.wbxAppApiCode, 403000);
@@ -226,6 +232,11 @@ describe('plugin-meetings', () => {
226
232
  assert.fail('fetchMeetingInfo should have thrown, but has not done that');
227
233
  }
228
234
  catch (err) {
235
+ assert(Metrics.sendBehavioralMetric.calledOnce);
236
+ assert.calledWith(
237
+ Metrics.sendBehavioralMetric,
238
+ BEHAVIORAL_METRICS.VERIFY_CAPTCHA_ERROR,
239
+ );
229
240
  assert.instanceOf(err, MeetingInfoV2CaptchaError);
230
241
  assert.deepEqual(err.captchaInfo, {
231
242
  captchaId: 'fake_captcha_id',