@webex/plugin-meetings 3.0.0-beta.115 → 3.0.0-beta.117

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 (53) hide show
  1. package/dist/breakouts/breakout.js +23 -6
  2. package/dist/breakouts/breakout.js.map +1 -1
  3. package/dist/breakouts/index.js +178 -139
  4. package/dist/breakouts/index.js.map +1 -1
  5. package/dist/constants.js +1 -0
  6. package/dist/constants.js.map +1 -1
  7. package/dist/locus-info/mediaSharesUtils.js +15 -1
  8. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  9. package/dist/meeting/index.js +73 -103
  10. package/dist/meeting/index.js.map +1 -1
  11. package/dist/meeting/locusMediaRequest.js +3 -0
  12. package/dist/meeting/locusMediaRequest.js.map +1 -1
  13. package/dist/meeting/muteState.js +1 -1
  14. package/dist/meeting/muteState.js.map +1 -1
  15. package/dist/meeting/request.js +27 -20
  16. package/dist/meeting/request.js.map +1 -1
  17. package/dist/meeting/util.js +463 -426
  18. package/dist/meeting/util.js.map +1 -1
  19. package/dist/members/index.js +4 -1
  20. package/dist/members/index.js.map +1 -1
  21. package/dist/members/request.js +75 -45
  22. package/dist/members/request.js.map +1 -1
  23. package/dist/members/util.js +308 -317
  24. package/dist/members/util.js.map +1 -1
  25. package/dist/types/constants.d.ts +1 -0
  26. package/dist/types/meeting/index.d.ts +20 -21
  27. package/dist/types/meeting/locusMediaRequest.d.ts +2 -0
  28. package/dist/types/meeting/request.d.ts +16 -8
  29. package/dist/types/meeting/util.d.ts +75 -1
  30. package/dist/types/members/request.d.ts +56 -11
  31. package/dist/types/members/util.d.ts +209 -1
  32. package/package.json +19 -19
  33. package/src/breakouts/breakout.ts +26 -4
  34. package/src/breakouts/index.ts +32 -17
  35. package/src/constants.ts +1 -0
  36. package/src/locus-info/mediaSharesUtils.ts +16 -0
  37. package/src/meeting/index.ts +20 -42
  38. package/src/meeting/locusMediaRequest.ts +6 -0
  39. package/src/meeting/muteState.ts +1 -1
  40. package/src/meeting/request.ts +26 -17
  41. package/src/meeting/util.ts +446 -410
  42. package/src/members/index.ts +7 -1
  43. package/src/members/request.ts +61 -21
  44. package/src/members/util.ts +316 -326
  45. package/test/unit/spec/breakouts/breakout.ts +26 -7
  46. package/test/unit/spec/breakouts/index.ts +48 -3
  47. package/test/unit/spec/meeting/index.js +53 -33
  48. package/test/unit/spec/meeting/locusMediaRequest.ts +25 -3
  49. package/test/unit/spec/meeting/muteState.js +5 -2
  50. package/test/unit/spec/meeting/request.js +215 -42
  51. package/test/unit/spec/meeting/utils.js +151 -7
  52. package/test/unit/spec/members/index.js +22 -1
  53. package/test/unit/spec/members/request.js +167 -35
@@ -3,9 +3,13 @@ import {assert} from '@webex/test-helper-chai';
3
3
  import MockWebex from '@webex/test-helper-mock-webex';
4
4
  import Meetings from '@webex/plugin-meetings';
5
5
  import MeetingRequest from '@webex/plugin-meetings/src/meeting/request';
6
+ import uuid from 'uuid';
7
+ import { merge } from 'lodash';
8
+
6
9
 
7
10
  describe('plugin-meetings', () => {
8
11
  let meetingsRequest;
12
+ let locusDeltaRequestSpy;
9
13
 
10
14
  beforeEach(() => {
11
15
  const webex = new MockWebex({
@@ -28,34 +32,66 @@ describe('plugin-meetings', () => {
28
32
 
29
33
  webex.boundedStorage.get = sinon.mock().returns(Promise.resolve(JSON.stringify({anycastEntryPoint: "aws-eu-west-1"})))
30
34
 
35
+ const request = sinon.mock().returns(Promise.resolve({}));
36
+
31
37
  meetingsRequest = new MeetingRequest(
32
- {},
38
+ {
39
+ meeting: {
40
+ request,
41
+ locusInfo: {
42
+ sequence: {}
43
+ }
44
+ }
45
+ },
33
46
  {
34
47
  parent: webex,
35
48
  }
36
49
  );
37
50
 
38
- meetingsRequest.request = sinon.mock().returns(Promise.resolve({}));
51
+ meetingsRequest.request = request;
52
+ locusDeltaRequestSpy = sinon.spy(meetingsRequest, 'locusDeltaRequest');
39
53
  });
40
54
 
55
+ const checkRequest = (expectedParams) => {
56
+ assert.calledOnceWithExactly(locusDeltaRequestSpy, expectedParams);
57
+ assert.calledOnceWithExactly(meetingsRequest.request, merge(expectedParams, {body: {sequence: {}}}));
58
+ }
59
+
41
60
  describe('meeting request library', () => {
61
+
62
+ beforeEach(() => {
63
+ sinon.stub(uuid, 'v4').returns('12345');
64
+ });
65
+
66
+ afterEach(() => {
67
+ uuid.v4.restore();
68
+ });
69
+
42
70
  describe('#sendDTMF', () => {
43
71
  it('sends a POST to the sendDtmf locus endpoint', async () => {
44
72
  const locusUrl = 'locusURL';
45
73
  const deviceUrl = 'deviceUrl';
46
74
  const tones = '1234';
47
75
 
76
+
77
+
48
78
  await meetingsRequest.sendDTMF({
49
79
  locusUrl,
50
80
  deviceUrl,
51
81
  tones,
52
82
  });
53
- const requestParams = meetingsRequest.request.getCall(0).args[0];
54
83
 
55
- assert.equal(requestParams.method, 'POST');
56
- assert.equal(requestParams.uri, `${locusUrl}/sendDtmf`);
57
- assert.equal(requestParams.body.dtmf.tones, tones);
58
- assert.equal(requestParams.body.deviceUrl, deviceUrl);
84
+ checkRequest({
85
+ method: 'POST',
86
+ uri: `${locusUrl}/sendDtmf`,
87
+ body: {
88
+ deviceUrl: 'deviceUrl',
89
+ dtmf: {
90
+ correlationId: '12345',
91
+ tones: '1234',
92
+ },
93
+ },
94
+ });
59
95
  });
60
96
  });
61
97
 
@@ -72,14 +108,19 @@ describe('plugin-meetings', () => {
72
108
  main: {width: 640, height: 480},
73
109
  content: {width: 1280, height: 720},
74
110
  });
75
- const requestParams = meetingsRequest.request.getCall(0).args[0];
76
111
 
77
- assert.equal(requestParams.method, 'PUT');
78
- assert.equal(requestParams.uri, `${locusUrl}/controls`);
79
- assert.equal(requestParams.body.layout.type, layoutType);
80
- assert.equal(requestParams.body.layout.deviceUrl, deviceUrl);
81
- assert.deepEqual(requestParams.body.layout.layoutParams, {
82
- renderInfo: {main: {width: 640, height: 480}, content: {width: 1280, height: 720}},
112
+ checkRequest({
113
+ method: 'PUT',
114
+ uri: `${locusUrl}/controls`,
115
+ body: {
116
+ layout: {
117
+ deviceUrl,
118
+ type: layoutType,
119
+ layoutParams: {
120
+ renderInfo: {main: {width: 640, height: 480}, content: {width: 1280, height: 720}},
121
+ },
122
+ },
123
+ },
83
124
  });
84
125
  });
85
126
 
@@ -283,14 +324,20 @@ describe('plugin-meetings', () => {
283
324
  correlationId,
284
325
  dialInUrl,
285
326
  });
286
- const requestParams = meetingsRequest.request.getCall(0).args[0];
287
327
 
288
- assert.equal(requestParams.method, 'POST');
289
- assert.equal(requestParams.uri, `${locusUrl}/participant`);
290
- assert.equal(requestParams.body.device.url, dialInUrl);
291
- assert.equal(requestParams.body.device.deviceType, 'PROVISIONAL');
292
- assert.equal(requestParams.body.device.provisionalType, 'DIAL_IN');
293
- assert.equal(requestParams.body.device.clientUrl, 'clientUrl');
328
+ checkRequest({
329
+ method: 'POST',
330
+ uri: `${locusUrl}/participant`,
331
+ body: {
332
+ device: {
333
+ url: dialInUrl,
334
+ deviceType: 'PROVISIONAL',
335
+ provisionalType: 'DIAL_IN',
336
+ clientUrl,
337
+ },
338
+ correlationId
339
+ }
340
+ });
294
341
  });
295
342
 
296
343
  it('sends dial out pstn request', async () => {
@@ -307,15 +354,22 @@ describe('plugin-meetings', () => {
307
354
  dialOutUrl,
308
355
  phoneNumber,
309
356
  });
310
- const requestParams = meetingsRequest.request.getCall(0).args[0];
311
357
 
312
- assert.equal(requestParams.method, 'POST');
313
- assert.equal(requestParams.uri, `${locusUrl}/participant`);
314
- assert.equal(requestParams.body.device.url, dialOutUrl);
315
- assert.equal(requestParams.body.device.deviceType, 'PROVISIONAL');
316
- assert.equal(requestParams.body.device.provisionalType, 'DIAL_OUT');
317
- assert.equal(requestParams.body.device.clientUrl, 'clientUrl');
318
- assert.equal(requestParams.body.device.dialoutAddress, phoneNumber);
358
+ checkRequest({
359
+ method: 'POST',
360
+ uri: `${locusUrl}/participant`,
361
+ body: {
362
+ device: {
363
+ url: dialOutUrl,
364
+ deviceType: 'PROVISIONAL',
365
+ provisionalType: 'DIAL_OUT',
366
+ clientUrl,
367
+ dialoutAddress: phoneNumber,
368
+ },
369
+ correlationId,
370
+ },
371
+ });
372
+
319
373
  });
320
374
 
321
375
  it('sends disconnect phone audio request', async () => {
@@ -330,15 +384,96 @@ describe('plugin-meetings', () => {
330
384
  correlationId,
331
385
  phoneUrl,
332
386
  });
333
- const requestParams = meetingsRequest.request.getCall(0).args[0];
334
387
 
335
- assert.equal(requestParams.method, 'PUT');
336
- assert.equal(requestParams.uri, `${locusUrl}/participant/${selfId}/leave`);
337
- assert.equal(requestParams.body.device.url, phoneUrl);
338
- assert.equal(requestParams.body.device.deviceType, 'PROVISIONAL');
388
+ checkRequest({
389
+ method: 'PUT',
390
+ uri: `${locusUrl}/participant/${selfId}/leave`,
391
+ body: {
392
+ device: {
393
+ url: phoneUrl,
394
+ deviceType: 'PROVISIONAL'
395
+ },
396
+ correlationId
397
+ }
398
+ });
339
399
  });
340
400
  });
341
401
 
402
+ describe('#leaveMeeting', () => {
403
+ it('sends the request to leave the meeting', async () => {
404
+ const locusUrl = 'locusUrl';
405
+ const selfId = 'selfId';
406
+ const correlationId = 'random-uuid';
407
+ const resourceId = 'resourceId';
408
+ const deviceUrl = 'deviceUrl';
409
+
410
+ meetingsRequest.config.meetings.deviceType = 'deviceType';
411
+
412
+ await meetingsRequest.leaveMeeting({
413
+ locusUrl,
414
+ selfId,
415
+ deviceUrl,
416
+ resourceId,
417
+ correlationId,
418
+ });
419
+
420
+ checkRequest({
421
+ method: 'PUT',
422
+ uri: 'locusUrl/participant/selfId/leave',
423
+ body: {
424
+ device: {deviceType: 'deviceType', url: 'deviceUrl'},
425
+ usingResource: 'resourceId',
426
+ correlationId: 'random-uuid',
427
+ },
428
+ });
429
+ });
430
+ });
431
+
432
+ describe('#acknowledgeMeeting', () => {
433
+ it('sends the request to acknowledge the meeting', async () => {
434
+ const locusUrl = 'locusUrl';
435
+ const correlationId = 'random-uuid';
436
+ const deviceUrl = 'deviceUrl';
437
+
438
+ meetingsRequest.config.meetings.deviceType = 'deviceType';
439
+
440
+ await meetingsRequest.acknowledgeMeeting({
441
+ locusUrl,
442
+ deviceUrl,
443
+ correlationId,
444
+ });
445
+
446
+ checkRequest({
447
+ method: 'PUT',
448
+ uri: 'locusUrl/participant/alert',
449
+ body: {
450
+ device: {deviceType: 'deviceType', url: 'deviceUrl'},
451
+ correlationId: 'random-uuid',
452
+ },
453
+ });
454
+ });
455
+ });
456
+
457
+ describe('#lockMeeting', () => {
458
+ it('sends request to lock the meeting', async () => {
459
+ const locusUrl = 'locusURL';
460
+
461
+ await meetingsRequest.lockMeeting({
462
+ locusUrl,
463
+ lock: true,
464
+ });
465
+
466
+ checkRequest({
467
+ method: 'PATCH',
468
+ uri: `${locusUrl}/controls`,
469
+ body: {
470
+ lock: {locked: true}
471
+ }
472
+ });
473
+ });
474
+ });
475
+
476
+
342
477
  describe('#endMeetingForAll', () => {
343
478
  it('sends request to endMeetingForAll', async () => {
344
479
  const locusUrl = 'locusURL';
@@ -346,10 +481,11 @@ describe('plugin-meetings', () => {
346
481
  await meetingsRequest.endMeetingForAll({
347
482
  locusUrl,
348
483
  });
349
- const requestParams = meetingsRequest.request.getCall(0).args[0];
350
484
 
351
- assert.equal(requestParams.method, 'POST');
352
- assert.equal(requestParams.uri, `${locusUrl}/end`);
485
+ checkRequest({
486
+ method: 'POST',
487
+ uri: `${locusUrl}/end`,
488
+ });
353
489
  });
354
490
  });
355
491
 
@@ -402,16 +538,52 @@ describe('plugin-meetings', () => {
402
538
  locusUrl,
403
539
  requestingParticipantId,
404
540
  });
405
- const requestParams = meetingsRequest.request.getCall(0).args[0];
406
541
 
407
- assert.equal(requestParams.method, 'PUT');
408
- assert.equal(requestParams.uri, `${locusUrl}/controls`);
409
- assert.equal(requestParams.body.reactions.enabled, true);
410
- assert.equal(requestParams.body.requestingParticipantId, requestingParticipantId);
542
+ checkRequest({
543
+ method: 'PUT',
544
+ uri: `${locusUrl}/controls`,
545
+ body: {
546
+ reactions: {
547
+ enabled: true,
548
+ },
549
+ requestingParticipantId,
550
+ },
551
+ });
411
552
  });
412
553
  });
413
554
  });
414
555
 
556
+ describe('#declineMeeting', () => {
557
+
558
+ it('sends a request to decline the meeting', async () => {
559
+ const reason = 'reason';
560
+ const deviceUrl = 'deviceUrl';
561
+ const locusUrl = 'locusUrl';
562
+ meetingsRequest.config.meetings.deviceType = 'deviceType';
563
+
564
+ await meetingsRequest.declineMeeting({
565
+ locusUrl,
566
+ deviceUrl,
567
+ reason
568
+ });
569
+
570
+ const expectedBody = {
571
+ device: {
572
+ deviceType: 'deviceType',
573
+ url: deviceUrl,
574
+ },
575
+ reason,
576
+ };
577
+
578
+ checkRequest({
579
+ method: 'PUT',
580
+ uri: `${locusUrl}/participant/decline`,
581
+ body: expectedBody,
582
+ });
583
+ });
584
+
585
+ });
586
+
415
587
  describe('#getLocusStatusByUrl', () => {
416
588
  it('check locus status', async () => {
417
589
  const locusUrl = 'locusUrl';
@@ -423,6 +595,7 @@ describe('plugin-meetings', () => {
423
595
  })
424
596
  });
425
597
  });
598
+
426
599
  describe('#changeMeetingFloor', () => {
427
600
 
428
601
  it('change meeting floor', async () => {
@@ -133,11 +133,152 @@ describe('plugin-meetings', () => {
133
133
  });
134
134
  });
135
135
 
136
+ describe('addSequence', () => {
137
+ it('should add the sequence object to a request body', () => {
138
+ const body = {};
139
+
140
+ MeetingUtil.addSequence({
141
+ locusInfo: {
142
+ sequence: 'sequence'
143
+ }
144
+ }, body);
145
+
146
+ assert.deepEqual(body, {
147
+ sequence: 'sequence'
148
+ });
149
+ });
150
+
151
+ it('should work with an undefined meeting', () => {
152
+ const body = {};
153
+
154
+ MeetingUtil.addSequence(
155
+ undefined,
156
+ body
157
+ );
158
+
159
+ assert.deepEqual(body, {});
160
+ });
161
+
162
+ it('should work with an undefined locusInfo', () => {
163
+ const body = {};
164
+
165
+ MeetingUtil.addSequence({}, body);
166
+
167
+ assert.deepEqual(body, {});
168
+ });
169
+
170
+ it('should work with an undefined sequence', () => {
171
+ const body = {};
172
+
173
+ MeetingUtil.addSequence({locusInfo: {}}, body);
174
+
175
+ assert.deepEqual(body, {});
176
+ });
177
+ });
178
+
179
+ describe('updateLocusWithDelta', () => {
180
+ it('should call onDeltaLocus with the new delta locus', () => {
181
+ const meeting = {
182
+ locusInfo: {
183
+ onDeltaLocus: sinon.stub(),
184
+ }
185
+ }
186
+
187
+ const originalResponse = {
188
+ body: {
189
+ locus: 'locus'
190
+ }
191
+ };
192
+
193
+ const response = MeetingUtil.updateLocusWithDelta(meeting, originalResponse);
194
+
195
+ assert.deepEqual(response, originalResponse);
196
+ assert.calledOnceWithExactly(meeting.locusInfo.onDeltaLocus, 'locus');
197
+ });
198
+
199
+ it('should handle locus being missing from the response', () => {
200
+ const meeting = {
201
+ locusInfo: {
202
+ onDeltaLocus: sinon.stub(),
203
+ },
204
+ };
205
+
206
+ const originalResponse = {
207
+ body: {},
208
+ };
209
+
210
+ const response = MeetingUtil.updateLocusWithDelta(meeting, originalResponse);
211
+
212
+ assert.deepEqual(response, originalResponse);
213
+ assert.notCalled(meeting.locusInfo.onDeltaLocus);
214
+ });
215
+
216
+ it('should work with an undefined meeting', () => {
217
+ const originalResponse = {
218
+ body: {
219
+ locus: 'locus',
220
+ },
221
+ };
222
+
223
+ const response = MeetingUtil.updateLocusWithDelta(undefined, originalResponse);
224
+ assert.deepEqual(response, originalResponse);
225
+ });
226
+ });
227
+
228
+ describe('generateLocusDeltaRequest', () => {
229
+
230
+ afterEach(() => {
231
+ WeakRef.prototype.deref.restore();
232
+ });
233
+
234
+ it('generates the correct wrapper function', async () => {
235
+ const updateLocusWithDeltaSpy = sinon.spy(MeetingUtil, 'updateLocusWithDelta');
236
+ const addSequenceSpy = sinon.spy(MeetingUtil, 'addSequence');
237
+
238
+ const meeting = {
239
+ request: sinon.stub().returns(Promise.resolve('result')),
240
+ }
241
+
242
+ const locusDeltaRequest = MeetingUtil.generateLocusDeltaRequest(meeting);
243
+
244
+ const options = {
245
+ some: 'option',
246
+ body: {}
247
+ };
248
+
249
+ let result = await locusDeltaRequest(options);
250
+
251
+ assert.equal(result, 'result');
252
+ assert.calledOnceWithExactly(updateLocusWithDeltaSpy, meeting, 'result');
253
+ assert.calledOnceWithExactly(addSequenceSpy, meeting, options.body);
254
+
255
+ updateLocusWithDeltaSpy.resetHistory();
256
+ addSequenceSpy.resetHistory();
257
+
258
+ // body missing from options
259
+ result = await locusDeltaRequest({});
260
+ assert.equal(result, 'result');
261
+ assert.calledOnceWithExactly(updateLocusWithDeltaSpy, meeting, 'result');
262
+ assert.calledOnceWithExactly(addSequenceSpy, meeting, options.body);
263
+
264
+ // meeting disappears so the WeakRef returns undefined
265
+ sinon.stub(WeakRef.prototype, 'deref').returns(undefined);
266
+
267
+ result = await locusDeltaRequest(options);
268
+ assert.equal(result, undefined);
269
+
270
+ });
271
+
272
+ });
273
+
136
274
  describe('remoteUpdateAudioVideo', () => {
137
275
  it('#Should call meetingRequest.locusMediaRequest with correct parameters', async () => {
138
276
  const meeting = {
139
277
  mediaId: '12345',
140
278
  selfUrl: 'self url',
279
+ locusInfo: {
280
+ sequence: {},
281
+ },
141
282
  locusMediaRequest: {
142
283
  send: sinon.stub().resolves({body: {}, headers: {}}),
143
284
  },
@@ -145,13 +286,16 @@ describe('plugin-meetings', () => {
145
286
 
146
287
  await MeetingUtil.remoteUpdateAudioVideo(meeting, true, false);
147
288
 
148
- assert.calledOnce(meeting.locusMediaRequest.send);
149
- const parameter = meeting.locusMediaRequest.send.getCall(0).args[0];
150
-
151
- assert.equal(parameter.type, 'LocalMute');
152
- assert.equal(parameter.selfUrl, 'self url');
153
- assert.equal(parameter.mediaId, '12345');
154
- assert.deepEqual(parameter.muteOptions, {audioMuted: true, videoMuted :false});
289
+ assert.calledOnceWithExactly(meeting.locusMediaRequest.send, {
290
+ mediaId: '12345',
291
+ muteOptions: {
292
+ audioMuted: true,
293
+ videoMuted: false,
294
+ },
295
+ selfUrl: 'self url',
296
+ sequence: {},
297
+ type: 'LocalMute',
298
+ });
155
299
  });
156
300
  });
157
301
 
@@ -14,6 +14,7 @@ import ParameterError from '@webex/plugin-meetings/src/common/errors/parameter';
14
14
  import Meetings from '@webex/plugin-meetings';
15
15
  import Members from '@webex/plugin-meetings/src/members';
16
16
  import MembersUtil from '@webex/plugin-meetings/src/members/util';
17
+ import * as MembersRequestImport from '@webex/plugin-meetings/src/members/request';
17
18
  import Trigger from '@webex/plugin-meetings/src/common/events/trigger-proxy';
18
19
  import {EVENT_TRIGGERS} from '@webex/plugin-meetings/src/constants';
19
20
 
@@ -81,6 +82,8 @@ describe('plugin-meetings', () => {
81
82
  describe('members', () => {
82
83
  const sandbox = sinon.createSandbox();
83
84
  let createMembers;
85
+ let meeting;
86
+ let membersRequestSpy;
84
87
 
85
88
  beforeEach(() => {
86
89
  webex = new MockWebex({
@@ -106,13 +109,31 @@ describe('plugin-meetings', () => {
106
109
 
107
110
  url1 = `https://example.com/${uuid.v4()}`;
108
111
 
109
- createMembers = (options) => new Members({locusUrl: options.url}, {parent: webex});
112
+ membersRequestSpy = sinon.spy(MembersRequestImport, 'default');
113
+
114
+ meeting = {
115
+ request: sinon.mock().returns(Promise.resolve()),
116
+ locusInfo: {
117
+ sequence: {}
118
+ }
119
+ }
120
+
121
+ createMembers = (options) => new Members({locusUrl: options.url, meeting}, {parent: webex});
110
122
  });
111
123
 
112
124
  afterEach(() => {
125
+ membersRequestSpy.restore();
113
126
  sandbox.restore();
114
127
  });
115
128
 
129
+ describe('constructor', () => {
130
+ it('passes the meeting to the MembersRequest', () => {
131
+ createMembers({});
132
+
133
+ assert.calledOnceWithExactly(membersRequestSpy, {meeting}, {parent: webex});
134
+ });
135
+ });
136
+
116
137
  describe('#addMembers', () => {
117
138
  it('should invoke isInvalidInvitee and generateAddMemberOptions from MembersUtil when addMember is called with valid params', async () => {
118
139
  sandbox.spy(MembersUtil, 'isInvalidInvitee');