@webex/plugin-meetings 2.12.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.js +9 -2
- package/dist/constants.js.map +1 -1
- package/dist/meeting/effectsState.js +328 -0
- package/dist/meeting/effectsState.js.map +1 -0
- package/dist/meeting/index.js +190 -172
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +3 -1
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/package.json +7 -7
- package/src/constants.js +7 -0
- package/src/meeting/effectsState.js +206 -0
- package/src/meeting/index.js +98 -71
- package/src/meeting-info/meeting-info-v2.js +3 -1
- package/test/unit/spec/meeting/effectsState.js +292 -0
- package/test/unit/spec/meeting/index.js +54 -142
- package/test/unit/spec/meeting-info/meetinginfov2.js +21 -5
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
import {assert} from '@webex/test-helper-chai';
|
|
3
|
+
import sinon from 'sinon';
|
|
4
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
5
|
+
|
|
6
|
+
import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
|
|
7
|
+
import {BNR_STATUS} from '@webex/plugin-meetings/src/constants';
|
|
8
|
+
import Meeting from '@webex/plugin-meetings/src/meeting';
|
|
9
|
+
import Meetings from '@webex/plugin-meetings';
|
|
10
|
+
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
11
|
+
import MediaUtil from '@webex/plugin-meetings/src/media/util';
|
|
12
|
+
import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
|
|
13
|
+
import createEffectsState from '@webex/plugin-meetings/src/meeting/effectsState';
|
|
14
|
+
import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
|
|
15
|
+
import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
|
|
16
|
+
|
|
17
|
+
describe('plugin-meetings', () => {
|
|
18
|
+
const logger = {
|
|
19
|
+
info: () => {},
|
|
20
|
+
log: () => {},
|
|
21
|
+
error: () => {},
|
|
22
|
+
warn: () => {},
|
|
23
|
+
trace: () => {},
|
|
24
|
+
debug: () => {}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
sinon.stub(Metrics, 'sendBehavioralMetric');
|
|
29
|
+
});
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
sinon.restore();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
Object.defineProperty(global.window.navigator, 'mediaDevices', {
|
|
35
|
+
writable: true,
|
|
36
|
+
value: {
|
|
37
|
+
getSupportedConstraints: sinon.stub().returns({
|
|
38
|
+
sampleRate: true
|
|
39
|
+
})
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
LoggerConfig.set({verboseEvents: true, enable: false});
|
|
43
|
+
LoggerProxy.set(logger);
|
|
44
|
+
|
|
45
|
+
let webex;
|
|
46
|
+
let meeting;
|
|
47
|
+
let uuid1;
|
|
48
|
+
|
|
49
|
+
const fakeMediaTrack = () => ({
|
|
50
|
+
id: Date.now().toString(),
|
|
51
|
+
stop: () => {},
|
|
52
|
+
readyState: 'live',
|
|
53
|
+
enabled: true,
|
|
54
|
+
getSettings: () => ({
|
|
55
|
+
sampleRate: 48000
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
class FakeMediaStream {
|
|
60
|
+
constructor(tracks) {
|
|
61
|
+
this.active = false;
|
|
62
|
+
this.id = '5146425f-c240-48cc-b86b-27d422988fb7';
|
|
63
|
+
this.tracks = tracks;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
addTrack = () => undefined;
|
|
67
|
+
|
|
68
|
+
getAudioTracks = () => this.tracks;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
class FakeAudioContext {
|
|
72
|
+
constructor() {
|
|
73
|
+
this.state = 'running';
|
|
74
|
+
this.baseLatency = 0.005333333333333333;
|
|
75
|
+
this.currentTime = 2.7946666666666666;
|
|
76
|
+
this.sampleRate = 48000;
|
|
77
|
+
this.audioWorklet = {
|
|
78
|
+
addModule: async () => undefined,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onstatechange = null;
|
|
83
|
+
|
|
84
|
+
createMediaStreamSource() {
|
|
85
|
+
return {
|
|
86
|
+
connect: () => undefined,
|
|
87
|
+
mediaStream: {
|
|
88
|
+
getAudioTracks() {
|
|
89
|
+
// eslint-disable-next-line no-undef
|
|
90
|
+
return [new MediaStreamTrack()];
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
createMediaStreamDestination() {
|
|
97
|
+
return {
|
|
98
|
+
stream: {
|
|
99
|
+
getAudioTracks() {
|
|
100
|
+
// eslint-disable-next-line no-undef
|
|
101
|
+
return [new MediaStreamTrack()];
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
class FakeAudioWorkletNode {
|
|
109
|
+
constructor() {
|
|
110
|
+
this.port = {
|
|
111
|
+
postMessage: () => undefined,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
connect() {
|
|
116
|
+
/* placeholder method */
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
class FakeMediaStreamTrack {
|
|
121
|
+
constructor() {
|
|
122
|
+
this.kind = 'audio';
|
|
123
|
+
this.enabled = true;
|
|
124
|
+
this.label = 'Default - MacBook Pro Microphone (Built-in)';
|
|
125
|
+
this.muted = false;
|
|
126
|
+
this.readyState = 'live';
|
|
127
|
+
this.contentHint = '';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getSettings() {
|
|
131
|
+
return {
|
|
132
|
+
sampleRate: 48000
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
Object.defineProperty(global, 'MediaStream', {
|
|
137
|
+
writable: true,
|
|
138
|
+
value: FakeMediaStream,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
Object.defineProperty(global, 'AudioContext', {
|
|
142
|
+
writable: true,
|
|
143
|
+
value: FakeAudioContext,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
Object.defineProperty(global, 'AudioWorkletNode', {
|
|
147
|
+
writable: true,
|
|
148
|
+
value: FakeAudioWorkletNode,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
Object.defineProperty(global, 'MediaStreamTrack', {
|
|
152
|
+
writable: true,
|
|
153
|
+
value: FakeMediaStreamTrack,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
let effects;
|
|
157
|
+
|
|
158
|
+
beforeEach(() => {
|
|
159
|
+
webex = new MockWebex({
|
|
160
|
+
children: {
|
|
161
|
+
meetings: Meetings
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
MediaUtil.createPeerConnection = sinon.stub().returns({});
|
|
165
|
+
meeting = new Meeting(
|
|
166
|
+
{
|
|
167
|
+
userId: uuid1
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
parent: webex
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
effects = createEffectsState('BNR');
|
|
175
|
+
meeting.canUpdateMedia = sinon.stub().returns(true);
|
|
176
|
+
MeetingUtil.validateOptions = sinon.stub().returns(Promise.resolve());
|
|
177
|
+
MeetingUtil.updateTransceiver = sinon.stub();
|
|
178
|
+
|
|
179
|
+
meeting.addMedia = sinon.stub().returns(Promise.resolve());
|
|
180
|
+
meeting.getMediaStreams = sinon.stub().returns(Promise.resolve());
|
|
181
|
+
sinon.replace(meeting, 'addMedia', () => {
|
|
182
|
+
sinon.stub(meeting.mediaProperties, 'audioTrack').value(fakeMediaTrack());
|
|
183
|
+
sinon.stub(meeting.mediaProperties, 'mediaDirection').value({
|
|
184
|
+
receiveAudio: true
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('bnr effect library', () => {
|
|
190
|
+
beforeEach(async () => {
|
|
191
|
+
await meeting.getMediaStreams();
|
|
192
|
+
await meeting.addMedia();
|
|
193
|
+
});
|
|
194
|
+
describe('#enableBNR', () => {
|
|
195
|
+
it('should have #enableBnr', () => {
|
|
196
|
+
assert.exists(effects.enableBNR);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('does bnr effect enable on audio track', async () => {
|
|
200
|
+
assert.isTrue(await effects.handleClientRequest(true, meeting));
|
|
201
|
+
assert.equal(effects.state.bnr.enabled, BNR_STATUS.ENABLED);
|
|
202
|
+
|
|
203
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
204
|
+
assert.calledWith(
|
|
205
|
+
Metrics.sendBehavioralMetric,
|
|
206
|
+
BEHAVIORAL_METRICS.ENABLE_BNR_SUCCESS,
|
|
207
|
+
);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('does resolve request if bnr is already enabled', async () => {
|
|
211
|
+
effects.state.bnr.enabled = BNR_STATUS.ENABLED;
|
|
212
|
+
assert.isTrue(await effects.handleClientRequest(true, meeting));
|
|
213
|
+
assert.equal(effects.state.bnr.enabled, BNR_STATUS.ENABLED);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('if called twice, does bnr effect enable on audio track for the first request and resolves second', async () => {
|
|
217
|
+
Promise.all([effects.handleClientRequest(true, meeting), effects.handleClientRequest(true, meeting)])
|
|
218
|
+
.then((resolveFirst, resolveSecond) => {
|
|
219
|
+
assert.isTrue(resolveFirst);
|
|
220
|
+
assert.isTrue(resolveSecond);
|
|
221
|
+
assert.calledOnce(MediaUtil.createMediaStream);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should throw error for inappropriate sample rate and send error metrics', async () => {
|
|
226
|
+
const fakeMediaTrack1 = () => ({
|
|
227
|
+
id: Date.now().toString(),
|
|
228
|
+
stop: () => {},
|
|
229
|
+
readyState: 'live',
|
|
230
|
+
getSettings: () => ({
|
|
231
|
+
sampleRate: 49000
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
sinon.stub(meeting.mediaProperties, 'audioTrack').value(fakeMediaTrack1());
|
|
236
|
+
|
|
237
|
+
// eslint-disable-next-line no-undef
|
|
238
|
+
MediaUtil.createMediaStream = sinon.stub().returns(new MediaStream([fakeMediaTrack1()]));
|
|
239
|
+
try {
|
|
240
|
+
await effects.handleClientRequest(true, meeting);
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
244
|
+
assert.calledWith(
|
|
245
|
+
Metrics.sendBehavioralMetric,
|
|
246
|
+
BEHAVIORAL_METRICS.ENABLE_BNR_FAILURE, {
|
|
247
|
+
reason: err.message,
|
|
248
|
+
stack: err.stack
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
assert.equal(err.message, 'Sample rate of 49000 is not supported.');
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe('#disableBNR', () => {
|
|
257
|
+
beforeEach(() => {
|
|
258
|
+
effects.state.bnr.enabled = BNR_STATUS.ENABLED;
|
|
259
|
+
});
|
|
260
|
+
it('should have #disableBnr', () => {
|
|
261
|
+
assert.exists(effects.disableBNR);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('does bnr disable on audio track', async () => {
|
|
265
|
+
assert.isTrue(await effects.handleClientRequest(false, meeting));
|
|
266
|
+
assert.equal(effects.state.bnr.enabled, BNR_STATUS.NOT_ENABLED);
|
|
267
|
+
|
|
268
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
269
|
+
assert.calledWith(
|
|
270
|
+
Metrics.sendBehavioralMetric,
|
|
271
|
+
BEHAVIORAL_METRICS.DISABLE_BNR_SUCCESS,
|
|
272
|
+
);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('reject request for disable bnr if not enabled', async () => {
|
|
276
|
+
try {
|
|
277
|
+
await effects.handleClientRequest(false, meeting);
|
|
278
|
+
}
|
|
279
|
+
catch (e) {
|
|
280
|
+
assert.equal(e.message, 'Can not disable as BNR is not enabled');
|
|
281
|
+
assert.equal(effects.state.bnr.enabled, BNR_STATUS.ENABLED);
|
|
282
|
+
|
|
283
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
284
|
+
assert.calledWith(
|
|
285
|
+
Metrics.sendBehavioralMetric,
|
|
286
|
+
BEHAVIORAL_METRICS.DISABLE_BNR_FAILURE,
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
});
|
|
@@ -456,114 +456,25 @@ describe('plugin-meetings', () => {
|
|
|
456
456
|
});
|
|
457
457
|
});
|
|
458
458
|
describe('BNR', () => {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
class FakeAudioContext {
|
|
469
|
-
constructor() {
|
|
470
|
-
this.state = 'running';
|
|
471
|
-
this.baseLatency = 0.005333333333333333;
|
|
472
|
-
this.currentTime = 2.7946666666666666;
|
|
473
|
-
this.sampleRate = 48000;
|
|
474
|
-
this.audioWorklet = {
|
|
475
|
-
addModule: async () => undefined,
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
onstatechange = null;
|
|
480
|
-
|
|
481
|
-
createMediaStreamSource() {
|
|
482
|
-
return {
|
|
483
|
-
connect: () => undefined,
|
|
484
|
-
mediaStream: {
|
|
485
|
-
getAudioTracks() {
|
|
486
|
-
// eslint-disable-next-line no-undef
|
|
487
|
-
return [new MediaStreamTrack()];
|
|
488
|
-
},
|
|
489
|
-
},
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
createMediaStreamDestination() {
|
|
494
|
-
return {
|
|
495
|
-
stream: {
|
|
496
|
-
getAudioTracks() {
|
|
497
|
-
// eslint-disable-next-line no-undef
|
|
498
|
-
return [new MediaStreamTrack()];
|
|
499
|
-
},
|
|
500
|
-
},
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
class FakeAudioWorkletNode {
|
|
506
|
-
constructor() {
|
|
507
|
-
this.port = {
|
|
508
|
-
postMessage: () => undefined,
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
connect() {
|
|
513
|
-
/* placeholder method */
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
class FakeMediaStreamTrack {
|
|
518
|
-
constructor() {
|
|
519
|
-
this.kind = 'audio';
|
|
520
|
-
this.enabled = true;
|
|
521
|
-
this.label = 'Default - MacBook Pro Microphone (Built-in)';
|
|
522
|
-
this.muted = false;
|
|
523
|
-
this.readyState = 'live';
|
|
524
|
-
this.contentHint = '';
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
Object.defineProperty(global, 'MediaStream', {
|
|
528
|
-
writable: true,
|
|
529
|
-
value: FakeMediaStream,
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
Object.defineProperty(global, 'AudioContext', {
|
|
533
|
-
writable: true,
|
|
534
|
-
value: FakeAudioContext,
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
Object.defineProperty(global, 'AudioWorkletNode', {
|
|
538
|
-
writable: true,
|
|
539
|
-
value: FakeAudioWorkletNode,
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
Object.defineProperty(global, 'MediaStreamTrack', {
|
|
543
|
-
writable: true,
|
|
544
|
-
value: FakeMediaStreamTrack,
|
|
459
|
+
const fakeMediaTrack = () => ({
|
|
460
|
+
id: Date.now().toString(),
|
|
461
|
+
stop: () => {},
|
|
462
|
+
readyState: 'live',
|
|
463
|
+
enabled: true,
|
|
464
|
+
getSettings: () => ({
|
|
465
|
+
sampleRate: 48000
|
|
466
|
+
})
|
|
545
467
|
});
|
|
546
468
|
|
|
547
|
-
beforeEach(
|
|
548
|
-
meeting.canUpdateMedia = sinon.stub().returns(true);
|
|
549
|
-
MeetingUtil.validateOptions = sinon.stub().returns(Promise.resolve());
|
|
550
|
-
MeetingUtil.updateTransceiver = sinon.stub();
|
|
551
|
-
const fakeMediaTrack = () => ({
|
|
552
|
-
stop: () => {},
|
|
553
|
-
readyState: 'live',
|
|
554
|
-
getSettings: () => ({
|
|
555
|
-
sampleRate: 48000
|
|
556
|
-
})
|
|
557
|
-
});
|
|
558
|
-
|
|
469
|
+
beforeEach(() => {
|
|
559
470
|
meeting.getMediaStreams = sinon.stub().returns(Promise.resolve());
|
|
560
471
|
sinon.replace(meeting, 'addMedia', () => {
|
|
561
472
|
sinon.stub(meeting.mediaProperties, 'audioTrack').value(fakeMediaTrack());
|
|
473
|
+
sinon.stub(meeting.mediaProperties, 'mediaDirection').value({
|
|
474
|
+
receiveAudio: true
|
|
475
|
+
});
|
|
562
476
|
});
|
|
563
|
-
await meeting.getMediaStreams();
|
|
564
|
-
await meeting.addMedia();
|
|
565
477
|
});
|
|
566
|
-
|
|
567
478
|
describe('#enableBNR', () => {
|
|
568
479
|
it('should have #enableBnr', () => {
|
|
569
480
|
assert.exists(meeting.enableBNR);
|
|
@@ -578,67 +489,68 @@ describe('plugin-meetings', () => {
|
|
|
578
489
|
});
|
|
579
490
|
|
|
580
491
|
describe('after audio attached to meeting', () => {
|
|
581
|
-
|
|
582
|
-
const response = await meeting.enableBNR();
|
|
492
|
+
let handleClientRequest;
|
|
583
493
|
|
|
584
|
-
|
|
494
|
+
beforeEach(async () => {
|
|
495
|
+
await meeting.getMediaStreams();
|
|
496
|
+
await meeting.addMedia();
|
|
585
497
|
});
|
|
586
498
|
|
|
587
|
-
it('should throw error
|
|
588
|
-
const
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
});
|
|
499
|
+
it('should throw error if meeting audio is muted', async () => {
|
|
500
|
+
const handleClientRequest = (meeting, mute) => {
|
|
501
|
+
meeting.mediaProperties.audioTrack.enabled = !mute;
|
|
502
|
+
|
|
503
|
+
return Promise.resolve();
|
|
504
|
+
};
|
|
505
|
+
const isMuted = () => !meeting.mediaProperties.audioTrack.enabled;
|
|
595
506
|
|
|
596
|
-
|
|
507
|
+
meeting.locusInfo.parsedLocus = {self: {state: 'JOINED'}};
|
|
508
|
+
meeting.mediaId = 'mediaId';
|
|
509
|
+
meeting.audio = {handleClientRequest, isMuted};
|
|
510
|
+
await meeting.muteAudio();
|
|
597
511
|
await meeting.enableBNR().catch((err) => {
|
|
598
|
-
assert(
|
|
599
|
-
assert.calledWith(
|
|
600
|
-
Metrics.sendBehavioralMetric,
|
|
601
|
-
BEHAVIORAL_METRICS.ENABLE_BNR_FAILURE, {
|
|
602
|
-
reason: err.message,
|
|
603
|
-
stack: err.stack
|
|
604
|
-
}
|
|
605
|
-
);
|
|
606
|
-
assert.equal(err.message, 'Sample rate of 49000 is not supported.');
|
|
512
|
+
assert.equal(err.message, 'Cannot enable BNR while meeting is muted');
|
|
607
513
|
});
|
|
608
514
|
});
|
|
609
515
|
|
|
610
|
-
it('should
|
|
516
|
+
it('should return true on enable bnr success', async () => {
|
|
517
|
+
handleClientRequest = sinon.stub().returns(Promise.resolve(true));
|
|
518
|
+
meeting.effects = {handleClientRequest};
|
|
611
519
|
const response = await meeting.enableBNR();
|
|
612
520
|
|
|
613
|
-
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
614
|
-
assert.calledWith(
|
|
615
|
-
Metrics.sendBehavioralMetric,
|
|
616
|
-
BEHAVIORAL_METRICS.ENABLE_BNR_SUCCESS,
|
|
617
|
-
);
|
|
618
521
|
assert.equal(response, true);
|
|
619
522
|
});
|
|
620
523
|
});
|
|
621
524
|
});
|
|
622
525
|
|
|
623
526
|
describe('#disableBNR', () => {
|
|
624
|
-
|
|
625
|
-
|
|
527
|
+
describe('before audio attached to meeting', () => {
|
|
528
|
+
it('should have #disableBnr', () => {
|
|
529
|
+
assert.exists(meeting.disableBNR);
|
|
530
|
+
});
|
|
531
|
+
|
|
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
|
+
});
|
|
626
537
|
});
|
|
538
|
+
describe('after audio attached to meeting', () => {
|
|
539
|
+
beforeEach(async () => {
|
|
540
|
+
await meeting.getMediaStreams();
|
|
541
|
+
await meeting.addMedia();
|
|
542
|
+
});
|
|
627
543
|
|
|
628
|
-
|
|
629
|
-
|
|
544
|
+
let handleClientRequest;
|
|
545
|
+
let isBnrEnabled;
|
|
630
546
|
|
|
631
|
-
|
|
632
|
-
|
|
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();
|
|
633
552
|
|
|
634
|
-
|
|
635
|
-
await meeting.disableBNR().catch((err) => {
|
|
636
|
-
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
637
|
-
assert.calledWith(
|
|
638
|
-
Metrics.sendBehavioralMetric,
|
|
639
|
-
BEHAVIORAL_METRICS.DISABLE_BNR_FAILURE,
|
|
640
|
-
);
|
|
641
|
-
assert.equal(err.message, 'Can not disable as BNR is not enabled');
|
|
553
|
+
assert.equal(response, true);
|
|
642
554
|
});
|
|
643
555
|
});
|
|
644
556
|
});
|
|
@@ -88,10 +88,14 @@ describe('plugin-meetings', () => {
|
|
|
88
88
|
|
|
89
89
|
describe('#fetchMeetingInfo', () => {
|
|
90
90
|
it('should fetch meeting info for the destination type', async () => {
|
|
91
|
+
const body = {meetingKey: '1234323'};
|
|
92
|
+
const requestResponse = {statusCode: 200, body};
|
|
93
|
+
|
|
91
94
|
sinon.stub(MeetingInfoUtil, 'getDestinationType').returns(Promise.resolve({type: 'MEETING_ID', destination: '123456'}));
|
|
92
|
-
sinon.stub(MeetingInfoUtil, 'getRequestBody').returns(Promise.resolve(
|
|
95
|
+
sinon.stub(MeetingInfoUtil, 'getRequestBody').returns(Promise.resolve(body));
|
|
96
|
+
webex.request.resolves(requestResponse);
|
|
93
97
|
|
|
94
|
-
await meetingInfo.fetchMeetingInfo({
|
|
98
|
+
const result = await meetingInfo.fetchMeetingInfo({
|
|
95
99
|
type: _MEETING_ID_,
|
|
96
100
|
destination: '1234323'
|
|
97
101
|
});
|
|
@@ -99,28 +103,39 @@ describe('plugin-meetings', () => {
|
|
|
99
103
|
assert.calledWith(webex.request, {
|
|
100
104
|
method: 'POST', service: 'webex-appapi-service', resource: 'meetingInfo', body: {meetingKey: '1234323'}
|
|
101
105
|
});
|
|
106
|
+
assert.deepEqual(result, requestResponse);
|
|
102
107
|
|
|
103
108
|
MeetingInfoUtil.getDestinationType.restore();
|
|
104
109
|
MeetingInfoUtil.getRequestBody.restore();
|
|
105
110
|
});
|
|
111
|
+
|
|
106
112
|
it('should fetch meeting info for the personal meeting room type', async () => {
|
|
113
|
+
const body = {meetingKey: '1234323'};
|
|
114
|
+
const requestResponse = {statusCode: 200, body};
|
|
115
|
+
|
|
107
116
|
sinon.stub(MeetingInfoUtil, 'getDestinationType').returns(Promise.resolve({type: 'MEETING_ID', destination: '123456'}));
|
|
108
|
-
sinon.stub(MeetingInfoUtil, 'getRequestBody').returns(Promise.resolve(
|
|
117
|
+
sinon.stub(MeetingInfoUtil, 'getRequestBody').returns(Promise.resolve(body));
|
|
118
|
+
webex.request.resolves(requestResponse);
|
|
109
119
|
|
|
110
|
-
await meetingInfo.fetchMeetingInfo({
|
|
120
|
+
const result = await meetingInfo.fetchMeetingInfo({
|
|
111
121
|
type: _PERSONAL_ROOM_
|
|
112
122
|
});
|
|
113
123
|
|
|
114
124
|
assert.calledWith(webex.request, {
|
|
115
125
|
method: 'POST', service: 'webex-appapi-service', resource: 'meetingInfo', body: {meetingKey: '1234323'}
|
|
116
126
|
});
|
|
127
|
+
assert.deepEqual(result, requestResponse);
|
|
117
128
|
|
|
118
129
|
MeetingInfoUtil.getDestinationType.restore();
|
|
119
130
|
MeetingInfoUtil.getRequestBody.restore();
|
|
120
131
|
});
|
|
121
132
|
|
|
122
133
|
it('should fetch meeting info with provided password and captcha code', async () => {
|
|
123
|
-
|
|
134
|
+
const requestResponse = {statusCode: 200, body: {meetingKey: '1234323'}};
|
|
135
|
+
|
|
136
|
+
webex.request.resolves(requestResponse);
|
|
137
|
+
|
|
138
|
+
const result = await meetingInfo.fetchMeetingInfo('1234323', _MEETING_ID_, 'abc', {id: '999', code: 'aabbcc11'});
|
|
124
139
|
|
|
125
140
|
assert.calledWith(webex.request, {
|
|
126
141
|
method: 'POST',
|
|
@@ -134,6 +149,7 @@ describe('plugin-meetings', () => {
|
|
|
134
149
|
captchaVerifyCode: 'aabbcc11'
|
|
135
150
|
}
|
|
136
151
|
});
|
|
152
|
+
assert.deepEqual(result, requestResponse);
|
|
137
153
|
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
138
154
|
assert.calledWith(
|
|
139
155
|
Metrics.sendBehavioralMetric,
|