@webex/plugin-meetings 2.12.1 → 2.14.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.
- 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 +6 -10
- 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 +1 -4
- package/test/unit/spec/meeting/effectsState.js +292 -0
- package/test/unit/spec/meeting/index.js +64 -160
- package/test/unit/spec/meeting-info/meetinginfov2.js +13 -2
|
@@ -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
|
});
|
|
@@ -1420,7 +1332,7 @@ describe('plugin-meetings', () => {
|
|
|
1420
1332
|
|
|
1421
1333
|
sandbox.stub(meeting.mediaProperties, 'peerConnection').value({shareTransceiver: true});
|
|
1422
1334
|
sandbox.stub(MeetingUtil, 'getTrack').returns({videoTrack: true});
|
|
1423
|
-
|
|
1335
|
+
MeetingUtil.validateOptions = sinon.stub().returns(Promise.resolve(true));
|
|
1424
1336
|
sandbox.stub(meeting, 'canUpdateMedia').returns(true);
|
|
1425
1337
|
sandbox.stub(meeting, 'setLocalShareTrack');
|
|
1426
1338
|
|
|
@@ -1489,13 +1401,14 @@ describe('plugin-meetings', () => {
|
|
|
1489
1401
|
const SENDRECV = 'sendrecv';
|
|
1490
1402
|
const delay = 1e3;
|
|
1491
1403
|
|
|
1404
|
+
MeetingUtil.validateOptions = sinon.stub().returns(Promise.resolve(true));
|
|
1405
|
+
MeetingUtil.updateTransceiver = sinon.stub().returns(Promise.resolve(true));
|
|
1492
1406
|
sandbox.stub(meeting, 'canUpdateMedia').returns(true);
|
|
1493
1407
|
sandbox.stub(MeetingUtil, 'getTrack').returns({videoTrack: null});
|
|
1494
1408
|
sandbox.stub(meeting, 'setLocalShareTrack');
|
|
1495
1409
|
sandbox.stub(meeting, 'unsetLocalShareTrack');
|
|
1496
|
-
sandbox.stub(MeetingUtil, 'validateOptions').resolves(true);
|
|
1497
1410
|
sandbox.stub(meeting, 'checkForStopShare').returns(false);
|
|
1498
|
-
|
|
1411
|
+
|
|
1499
1412
|
sandbox.stub(meeting, 'isLocalShareLive').value(false);
|
|
1500
1413
|
sandbox.stub(meeting, 'handleShareTrackEnded');
|
|
1501
1414
|
sandbox.stub(meeting.mediaProperties, 'peerConnection').value({
|
|
@@ -2366,11 +2279,6 @@ describe('plugin-meetings', () => {
|
|
|
2366
2279
|
assert.equal(meeting.requiredCaptcha, null);
|
|
2367
2280
|
assert.calledTwice(TriggerProxy.trigger);
|
|
2368
2281
|
assert.calledWith(TriggerProxy.trigger, meeting, {file: 'meetings', function: 'fetchMeetingInfo'}, 'meeting:meetingInfoAvailable');
|
|
2369
|
-
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
2370
|
-
assert.calledWith(
|
|
2371
|
-
Metrics.sendBehavioralMetric,
|
|
2372
|
-
BEHAVIORAL_METRICS.VERIFY_PASSWORD_SUCCESS,
|
|
2373
|
-
);
|
|
2374
2282
|
});
|
|
2375
2283
|
|
|
2376
2284
|
it('calls meetingInfoProvider with all the right parameters and parses the result when random delay is applied', async () => {
|
|
@@ -2442,11 +2350,6 @@ describe('plugin-meetings', () => {
|
|
|
2442
2350
|
|
|
2443
2351
|
assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, null, null);
|
|
2444
2352
|
|
|
2445
|
-
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
2446
|
-
assert.calledWith(
|
|
2447
|
-
Metrics.sendBehavioralMetric,
|
|
2448
|
-
BEHAVIORAL_METRICS.VERIFY_PASSWORD_ERROR,
|
|
2449
|
-
);
|
|
2450
2353
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
|
2451
2354
|
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD);
|
|
2452
2355
|
assert.equal(meeting.requiredCaptcha, null);
|
|
@@ -2467,11 +2370,7 @@ describe('plugin-meetings', () => {
|
|
|
2467
2370
|
|
|
2468
2371
|
assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, 'aaa', null);
|
|
2469
2372
|
|
|
2470
|
-
|
|
2471
|
-
assert.calledWith(
|
|
2472
|
-
Metrics.sendBehavioralMetric,
|
|
2473
|
-
BEHAVIORAL_METRICS.VERIFY_CAPTCHA_ERROR,
|
|
2474
|
-
);
|
|
2373
|
+
|
|
2475
2374
|
assert.deepEqual(meeting.meetingInfo, {});
|
|
2476
2375
|
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD);
|
|
2477
2376
|
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
@@ -2625,6 +2524,11 @@ describe('plugin-meetings', () => {
|
|
|
2625
2524
|
meeting.fetchMeetingInfo = sinon.stub().resolves();
|
|
2626
2525
|
const result = await meeting.verifyPassword('password', 'captcha id');
|
|
2627
2526
|
|
|
2527
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
2528
|
+
assert.calledWith(
|
|
2529
|
+
Metrics.sendBehavioralMetric,
|
|
2530
|
+
BEHAVIORAL_METRICS.VERIFY_PASSWORD_SUCCESS,
|
|
2531
|
+
);
|
|
2628
2532
|
assert.equal(result.isPasswordValid, true);
|
|
2629
2533
|
assert.equal(result.requiredCaptcha, null);
|
|
2630
2534
|
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
|
|
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, '
|
|
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',
|