@webex/plugin-meetings 3.0.0-beta.27 → 3.0.0-beta.29

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 (33) hide show
  1. package/dist/breakouts/breakout.js +22 -1
  2. package/dist/breakouts/breakout.js.map +1 -1
  3. package/dist/breakouts/index.js +59 -1
  4. package/dist/breakouts/index.js.map +1 -1
  5. package/dist/breakouts/request.js +78 -0
  6. package/dist/breakouts/request.js.map +1 -0
  7. package/dist/breakouts/utils.js +23 -0
  8. package/dist/breakouts/utils.js.map +1 -0
  9. package/dist/members/index.js +1 -0
  10. package/dist/members/index.js.map +1 -1
  11. package/dist/multistream/receiveSlot.js +9 -0
  12. package/dist/multistream/receiveSlot.js.map +1 -1
  13. package/dist/multistream/receiveSlotManager.js +15 -0
  14. package/dist/multistream/receiveSlotManager.js.map +1 -1
  15. package/dist/types/breakouts/request.d.ts +22 -0
  16. package/dist/types/breakouts/utils.d.ts +1 -0
  17. package/dist/types/multistream/receiveSlot.d.ts +3 -1
  18. package/dist/types/multistream/receiveSlotManager.d.ts +5 -0
  19. package/package.json +18 -18
  20. package/src/breakouts/README.md +2 -2
  21. package/src/breakouts/breakout.ts +20 -0
  22. package/src/breakouts/index.ts +58 -2
  23. package/src/breakouts/request.ts +55 -0
  24. package/src/breakouts/utils.ts +15 -0
  25. package/src/members/index.ts +2 -0
  26. package/src/multistream/receiveSlot.ts +8 -1
  27. package/src/multistream/receiveSlotManager.ts +12 -0
  28. package/test/unit/spec/breakouts/breakout.ts +32 -4
  29. package/test/unit/spec/breakouts/index.ts +105 -10
  30. package/test/unit/spec/breakouts/request.ts +104 -0
  31. package/test/unit/spec/breakouts/utils.js +21 -0
  32. package/test/unit/spec/multistream/receiveSlot.ts +36 -0
  33. package/test/unit/spec/multistream/receiveSlotManager.ts +28 -0
@@ -0,0 +1,55 @@
1
+ import {StatelessWebexPlugin} from '@webex/webex-core';
2
+ import LoggerProxy from '../common/logs/logger-proxy';
3
+ import {getBroadcastRoles} from './utils';
4
+ import {HTTP_VERBS} from '../constants';
5
+
6
+ /**
7
+ * @class BreakoutRequest
8
+ */
9
+ export default class BreakoutRequest extends StatelessWebexPlugin {
10
+ /**
11
+ * Broadcast message to all breakout session's participants
12
+ * @param {String} url
13
+ * @param {String} message
14
+ * @param {Object} options
15
+ * @param {string} groupId
16
+ * @param {string} sessionId
17
+ * @returns {Promise}
18
+ */
19
+ broadcast({
20
+ url,
21
+ message,
22
+ options,
23
+ groupId,
24
+ sessionId,
25
+ }: {
26
+ url: string;
27
+ message: string;
28
+ options?: object;
29
+ groupId: string;
30
+ sessionId?: string;
31
+ }) {
32
+ const roles = getBroadcastRoles(options);
33
+ const params = {
34
+ id: groupId,
35
+ recipientRoles: roles.length ? roles : undefined,
36
+ sessions: sessionId ? [{id: sessionId}] : undefined,
37
+ };
38
+
39
+ // @ts-ignore
40
+ return this.request({
41
+ method: HTTP_VERBS.POST,
42
+ uri: `${url}/message`,
43
+ body: {
44
+ message,
45
+ groups: [params],
46
+ },
47
+ }).catch((error) => {
48
+ if (error.body && error.body.errorCode === 201409036 && error.statusCode === 409) {
49
+ LoggerProxy.logger.info(`Breakouts#broadcast --> no joined participants`);
50
+ } else {
51
+ throw error;
52
+ }
53
+ });
54
+ }
55
+ }
@@ -0,0 +1,15 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export const getBroadcastRoles = (options): string[] => {
3
+ const recipientRoles = [];
4
+ if (!options || (!options.cohosts && !options.presenters)) {
5
+ return recipientRoles;
6
+ }
7
+ if (options.cohosts) {
8
+ recipientRoles.push('COHOST');
9
+ }
10
+ if (options.presenters) {
11
+ recipientRoles.push('PRESENTER');
12
+ }
13
+
14
+ return recipientRoles;
15
+ };
@@ -296,6 +296,8 @@ export default class Members extends StatelessWebexPlugin {
296
296
  const delta = this.handleLocusInfoUpdatedParticipants(payload);
297
297
  const full = this.handleMembersUpdate(delta); // SDK should propagate the full list for both delta and non delta updates
298
298
 
299
+ this.receiveSlotManager.updateMemberIds();
300
+
299
301
  Trigger.trigger(
300
302
  this,
301
303
  {
@@ -91,7 +91,7 @@ export class ReceiveSlot extends EventsScope {
91
91
  /**
92
92
  * registers event handlers with the underlying ReceiveSlot
93
93
  */
94
- setupEventListeners() {
94
+ private setupEventListeners() {
95
95
  const scope = {
96
96
  file: 'meeting/receiveSlot',
97
97
  function: 'setupEventListeners',
@@ -116,6 +116,13 @@ export class ReceiveSlot extends EventsScope {
116
116
  );
117
117
  }
118
118
 
119
+ /** Tries to find the member id for this receive slot if it hasn't got one */
120
+ public findMemberId() {
121
+ if (this.#memberId === undefined && this.#csi) {
122
+ this.#memberId = this.findMemberIdCallback(this.#csi);
123
+ }
124
+ }
125
+
119
126
  /**
120
127
  * The MediaStream object associated with this slot.
121
128
  *
@@ -141,4 +141,16 @@ export class ReceiveSlotManager {
141
141
  numFreeSlots,
142
142
  };
143
143
  }
144
+
145
+ /**
146
+ * Tries to find the member id on all allocated receive slots
147
+ * This function should be called when new members are added to the meeting.
148
+ */
149
+ updateMemberIds() {
150
+ Object.keys(this.allocatedSlots).forEach((key) => {
151
+ this.allocatedSlots[key].forEach((slot: ReceiveSlot) => {
152
+ slot.findMemberId();
153
+ });
154
+ });
155
+ }
144
156
  }
@@ -35,7 +35,7 @@ describe('plugin-meetings', () => {
35
35
  describe('#join', () => {
36
36
  it('makes the request as expected', async () => {
37
37
  const result = await breakout.join()
38
-
38
+
39
39
  assert.calledOnceWithExactly(webex.request, {
40
40
  method: 'POST',
41
41
  uri: 'url/move',
@@ -44,7 +44,7 @@ describe('plugin-meetings', () => {
44
44
  sessionId: 'sessionId'
45
45
  }
46
46
  });
47
-
47
+
48
48
  assert.equal(result, 'REQUEST_RETURN_VALUE')
49
49
  });
50
50
  });
@@ -88,7 +88,7 @@ describe('plugin-meetings', () => {
88
88
  describe('#askForHelp', () => {
89
89
  it('makes the request as expected', async () => {
90
90
  const result = await breakout.askForHelp()
91
-
91
+
92
92
  assert.calledOnceWithExactly(webex.request, {
93
93
  method: 'POST',
94
94
  uri: 'url/help',
@@ -97,7 +97,35 @@ describe('plugin-meetings', () => {
97
97
  sessionId: 'sessionId'
98
98
  }
99
99
  });
100
-
100
+
101
+ assert.equal(result, 'REQUEST_RETURN_VALUE')
102
+ });
103
+ });
104
+
105
+ describe('#broadcast', () => {
106
+ it('makes the request as expected', async () => {
107
+ breakout.breakoutRequest.broadcast = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
108
+ let result = await breakout.broadcast('hello')
109
+ assert.calledWithExactly(breakout.breakoutRequest.broadcast, {
110
+ url: 'url',
111
+ message: 'hello',
112
+ options: undefined,
113
+ groupId: 'groupId',
114
+ sessionId: 'sessionId'
115
+ });
116
+
117
+ assert.equal(result, 'REQUEST_RETURN_VALUE')
118
+
119
+ result = await breakout.broadcast('hello', {presenters: true, cohosts: true})
120
+
121
+ assert.calledWithExactly(breakout.breakoutRequest.broadcast, {
122
+ url: 'url',
123
+ message: 'hello',
124
+ options: {presenters: true, cohosts: true},
125
+ groupId: 'groupId',
126
+ sessionId: 'sessionId'
127
+ });
128
+
101
129
  assert.equal(result, 'REQUEST_RETURN_VALUE')
102
130
  });
103
131
  });
@@ -1,4 +1,4 @@
1
- import {assert} from '@webex/test-helper-chai';
1
+ import {assert, expect} from '@webex/test-helper-chai';
2
2
  import Breakout from '@webex/plugin-meetings/src/breakouts/breakout';
3
3
  import Breakouts from '@webex/plugin-meetings/src/breakouts';
4
4
  import BreakoutCollection from '@webex/plugin-meetings/src/breakouts/collection';
@@ -20,9 +20,11 @@ describe('plugin-meetings', () => {
20
20
  webex.internal.llm.on = sinon.stub();
21
21
  webex.internal.mercury.on = sinon.stub();
22
22
  breakouts = new Breakouts({}, {parent: webex});
23
+ breakouts.groupId = 'groupId';
24
+ breakouts.sessionId = 'sessionId';
25
+ breakouts.url = 'url';
23
26
  breakouts.locusUrl = 'locusUrl';
24
27
  breakouts.breakoutServiceUrl = 'breakoutServiceUrl';
25
- breakouts.url = 'url';
26
28
  webex.request = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
27
29
  });
28
30
 
@@ -31,7 +33,7 @@ describe('plugin-meetings', () => {
31
33
  assert.equal(breakouts.namespace, 'Meetings');
32
34
  });
33
35
 
34
- it('emits BREAKOUTS_CLOSING event when the status is CLOSING', () => {
36
+ it('emits BREAKOUTS_CLOSING event when the status is CLOSING', () => {
35
37
  let called = false;
36
38
  breakouts.listenTo(breakouts, BREAKOUTS.EVENTS.BREAKOUTS_CLOSING, () => {
37
39
  called = true;
@@ -58,7 +60,7 @@ describe('plugin-meetings', () => {
58
60
  it('triggers message event when a message received', () => {
59
61
  const call = webex.internal.llm.on.getCall(0);
60
62
  const callback = call.args[1];
61
-
63
+
62
64
  assert.equal(call.args[0], 'event:breakout.message');
63
65
 
64
66
  let message;
@@ -90,7 +92,7 @@ describe('plugin-meetings', () => {
90
92
  it('triggers member update event when a roster received', () => {
91
93
  const call = webex.internal.mercury.on.getCall(0);
92
94
  const callback = call.args[1];
93
-
95
+
94
96
  assert.equal(call.args[0], 'event:breakout.roster');
95
97
 
96
98
  let called = false;
@@ -204,9 +206,9 @@ describe('plugin-meetings', () => {
204
206
  describe('#cleanUp', () => {
205
207
  it('stops listening', () => {
206
208
  breakouts.stopListening = sinon.stub();
207
-
209
+
208
210
  breakouts.cleanUp();
209
-
211
+
210
212
  assert.calledOnceWithExactly(breakouts.stopListening);
211
213
  });
212
214
  });
@@ -230,7 +232,7 @@ describe('plugin-meetings', () => {
230
232
  });
231
233
 
232
234
  describe('#queryRosters', () => {
233
-
235
+
234
236
  it('makes the expected query', async () => {
235
237
 
236
238
  webex.request.returns(Promise.resolve({
@@ -249,7 +251,7 @@ describe('plugin-meetings', () => {
249
251
  breakouts.handleRosterUpdate = sinon.stub();
250
252
 
251
253
  const result = await breakouts.queryRosters();
252
-
254
+
253
255
  assert.calledOnceWithExactly(webex.request, {
254
256
  uri: 'url/roster',
255
257
  qs: { locusUrl: 'dGVzdA==' }
@@ -293,6 +295,67 @@ describe('plugin-meetings', () => {
293
295
  });
294
296
  });
295
297
 
298
+ describe('#getMainSession', () => {
299
+ it('returns main session as expect', () => {
300
+ breakouts.updateBreakout({
301
+ sessionId: 'sessionId',
302
+ groupId: 'groupId',
303
+ sessionType: 'sessionType',
304
+ url: 'url',
305
+ name: 'name',
306
+ allowBackToMain: true,
307
+ delayCloseTime: 10,
308
+ enableBreakoutSession: true,
309
+ startTime: 'startTime',
310
+ status: 'active',
311
+ locusUrl: 'locusUrl'
312
+ });
313
+ const payload = {
314
+ breakoutSessions: {
315
+ active: [{sessionId: 'sessionId1'}],
316
+ }
317
+ }
318
+ breakouts.updateBreakoutSessions(payload);
319
+
320
+ breakouts.set('sessionType', BREAKOUTS.SESSION_TYPES.MAIN);
321
+ let result = breakouts.getMainSession();
322
+ assert.equal(result.sessionId, 'sessionId');
323
+
324
+ const payload2 = {
325
+ breakoutSessions: {
326
+ active: [{sessionId: 'sessionId1', sessionType: BREAKOUTS.SESSION_TYPES.MAIN}],
327
+ }
328
+ }
329
+ breakouts.updateBreakoutSessions(payload2);
330
+ breakouts.set('sessionType', 'BREAKOUT');
331
+ result = breakouts.getMainSession();
332
+ assert.equal(result.sessionId, 'sessionId1');
333
+ });
334
+ it('throw error if cannot find main session', () => {
335
+ const fn = () => {
336
+ breakouts.getMainSession();
337
+ }
338
+ expect(fn).to.throw(/no main session found/);
339
+ });
340
+ });
341
+
342
+ describe('#askAllToReturn', () => {
343
+ it('makes the request as expected', async () => {
344
+ breakouts.set('sessionType', BREAKOUTS.SESSION_TYPES.MAIN);
345
+ breakouts.currentBreakoutSession.sessionId = 'sessionId';
346
+ breakouts.currentBreakoutSession.groupId = 'groupId';
347
+ const result = await breakouts.askAllToReturn();
348
+ assert.calledOnceWithExactly(webex.request, {
349
+ method: 'POST',
350
+ uri: 'url/requestMove',
351
+ body: {
352
+ groupId: 'groupId',
353
+ sessionId: 'sessionId'
354
+ }
355
+ });
356
+ });
357
+ });
358
+
296
359
  describe('#breakoutServiceUrlUpdate', () => {
297
360
  it('sets the breakoutService url', () => {
298
361
  breakouts.breakoutServiceUrlUpdate('newBreakoutServiceUrl');
@@ -313,7 +376,7 @@ describe('plugin-meetings', () => {
313
376
  }}))
314
377
  breakouts.updateBreakout = sinon.stub().resolves();
315
378
  breakouts.doToggleBreakout = sinon.stub().resolves();
316
-
379
+
317
380
  await breakouts.toggleBreakout(false);
318
381
  assert.calledOnceWithExactly(breakouts.enableBreakouts);
319
382
  assert.calledOnceWithExactly(breakouts.updateBreakout, {
@@ -351,6 +414,38 @@ describe('plugin-meetings', () => {
351
414
  });
352
415
  });
353
416
 
417
+ describe('#broadcast', () => {
418
+ it('makes the request as expected', async () => {
419
+ breakouts.breakoutRequest.broadcast = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
420
+ let result = await breakouts.broadcast('hello');
421
+ assert.calledWithExactly(breakouts.breakoutRequest.broadcast, {
422
+ url: 'url',
423
+ message: 'hello',
424
+ options: undefined,
425
+ groupId: 'groupId'
426
+ });
427
+
428
+ assert.equal(result, 'REQUEST_RETURN_VALUE');
429
+
430
+ result = await breakouts.broadcast('hello', {presenters: true, cohosts: true});
431
+ assert.calledWithExactly(breakouts.breakoutRequest.broadcast, {
432
+ url: 'url',
433
+ groupId: 'groupId',
434
+ message: 'hello',
435
+ options: {presenters: true, cohosts: true}
436
+ });
437
+ assert.equal(result, 'REQUEST_RETURN_VALUE')
438
+ });
439
+
440
+ it('throw error if no breakout group id found', () => {
441
+ breakouts.set('sessionType', BREAKOUTS.SESSION_TYPES.MAIN);
442
+ const fn = () => {
443
+ breakouts.broadcast('hello');
444
+ }
445
+ expect(fn).to.throw(/no breakout session found/);
446
+ });
447
+ });
448
+
354
449
  describe('doToggleBreakout', () => {
355
450
  it('makes the request as expected', async () => {
356
451
  const result = await breakouts.doToggleBreakout(true);
@@ -0,0 +1,104 @@
1
+ import sinon from 'sinon';
2
+ import {assert, expect} from '@webex/test-helper-chai';
3
+ import MockWebex from '@webex/test-helper-mock-webex';
4
+ import BreakoutRequest from "@webex/plugin-meetings/src/breakouts/request";
5
+ import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
6
+
7
+ describe('plugin-meetings', () => {
8
+ describe('BreakoutRequest', () => {
9
+ let webex;
10
+ let breakoutRequest;
11
+ beforeEach(() => {
12
+ // @ts-ignore
13
+ webex = new MockWebex({});
14
+ // @ts-ignore
15
+ breakoutRequest = new BreakoutRequest({webex});
16
+ webex.request = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
17
+ });
18
+
19
+ describe('#broadcast', () => {
20
+ it('makes request as expected', async () => {
21
+ let result = await breakoutRequest.broadcast({url: 'url', message: 'hello', groupId: 'groupId'});
22
+ assert.calledWithExactly(webex.request, {
23
+ method: 'POST',
24
+ uri: 'url/message',
25
+ body: {
26
+ message: 'hello',
27
+ groups: [{
28
+ id: 'groupId',
29
+ recipientRoles: undefined,
30
+ sessions: undefined
31
+ }],
32
+ }
33
+ });
34
+ assert.equal(result, 'REQUEST_RETURN_VALUE');
35
+
36
+ result = await breakoutRequest.broadcast({
37
+ url: 'url',
38
+ message: 'hello',
39
+ groupId: 'groupId',
40
+ options: {
41
+ presenters: true,
42
+ cohosts: true
43
+ }
44
+ });
45
+ assert.calledWithExactly(webex.request, {
46
+ method: 'POST',
47
+ uri: 'url/message',
48
+ body: {
49
+ message: 'hello',
50
+ groups: [{
51
+ id: 'groupId',
52
+ recipientRoles: ['COHOST', 'PRESENTER'],
53
+ sessions: undefined
54
+ }]
55
+ }
56
+ });
57
+ assert.equal(result, 'REQUEST_RETURN_VALUE');
58
+
59
+ result = await breakoutRequest.broadcast({
60
+ url: 'url',
61
+ message: 'hello',
62
+ groupId: 'groupId',
63
+ options: {
64
+ presenters: true,
65
+ cohosts: true
66
+ },
67
+ sessionId: 'sessionId'
68
+ });
69
+
70
+ assert.calledWithExactly(webex.request, {
71
+ method: 'POST',
72
+ uri: 'url/message',
73
+ body: {
74
+ message: 'hello',
75
+ groups: [{
76
+ id: 'groupId',
77
+ recipientRoles: ['COHOST', 'PRESENTER'],
78
+ sessions: [{id: 'sessionId'}]
79
+ }]
80
+ }
81
+ });
82
+ assert.equal(result, 'REQUEST_RETURN_VALUE');
83
+ });
84
+
85
+ it('catch 409 error and log', async () => {
86
+ const error = {statusCode: 409, body: {errorCode: 201409036}};
87
+ webex.request.rejects(error);
88
+ LoggerProxy.logger.info = sinon.stub();
89
+ await breakoutRequest.broadcast({url: 'url', message: 'hello', groupId: 'groupId'});
90
+ assert.calledOnceWithExactly(
91
+ LoggerProxy.logger.info,
92
+ 'Breakouts#broadcast --> no joined participants'
93
+ );
94
+
95
+ const otherError = new Error('something wrong');
96
+ webex.request.rejects(otherError);
97
+ LoggerProxy.logger.error = sinon.stub();
98
+ await breakoutRequest.broadcast({url: 'url', message: 'hello', groupId: 'groupId'}).catch((error) => {
99
+ assert.equal(error.toString(), 'Error: something wrong');
100
+ });
101
+ });
102
+ });
103
+ });
104
+ });
@@ -0,0 +1,21 @@
1
+ import {assert} from '@webex/test-helper-chai';
2
+ import {getBroadcastRoles} from '@webex/plugin-meetings/src/breakouts/utils'
3
+ describe('plugin-meetings', () => {
4
+ describe('Breakouts utils', () => {
5
+ describe('#getBroadcastRoles', () => {
6
+ it('return expect roles', () => {
7
+ let roles = getBroadcastRoles();
8
+ assert.deepEqual(roles, []);
9
+
10
+ roles = getBroadcastRoles({cohosts: true});
11
+ assert.deepEqual(roles, ['COHOST']);
12
+
13
+ roles = getBroadcastRoles({presenters: true});
14
+ assert.deepEqual(roles, ['PRESENTER']);
15
+
16
+ roles = getBroadcastRoles({presenters: true, cohosts: true});
17
+ assert.deepEqual(roles, ['COHOST', 'PRESENTER']);
18
+ });
19
+ });
20
+ });
21
+ });
@@ -101,4 +101,40 @@ describe('ReceiveSlot', () => {
101
101
  assert.strictEqual(receiveSlot.csi, undefined);
102
102
  assert.strictEqual(receiveSlot.sourceState, 'no source');
103
103
  });
104
+
105
+ describe('findMemberId()', () => {
106
+ it('doesn\'t do anything if csi is not set', () => {
107
+ // by default the receiveSlot does not have any csi or member id
108
+ receiveSlot.findMemberId();
109
+
110
+ assert.notCalled(findMemberIdCallbackStub);
111
+ });
112
+
113
+ it('finds a member id if member id is undefined and CSI is known', () => {
114
+ // setup receiveSlot to have a csi without a member id
115
+ const csi = 12345;
116
+ fakeWcmeSlot.emit(WcmeReceiveSlotEvents.SourceUpdate, 'live', csi);
117
+ findMemberIdCallbackStub.reset();
118
+
119
+ receiveSlot.findMemberId();
120
+
121
+ assert.calledOnce(findMemberIdCallbackStub);
122
+ assert.calledWith(findMemberIdCallbackStub, csi);
123
+ });
124
+
125
+ it('doesn\'t do anything if member id already set', () => {
126
+ // setup receiveSlot to have a csi and a member id
127
+ const csi = 12345;
128
+ const memberId = '12345678-1234-5678-9012-345678901234';
129
+
130
+ findMemberIdCallbackStub.returns(memberId);
131
+
132
+ fakeWcmeSlot.emit(WcmeReceiveSlotEvents.SourceUpdate, 'live', csi);
133
+ findMemberIdCallbackStub.reset();
134
+
135
+ receiveSlot.findMemberId();
136
+
137
+ assert.notCalled(findMemberIdCallbackStub);
138
+ });
139
+ });
104
140
  });
@@ -1,6 +1,7 @@
1
1
  import sinon from 'sinon';
2
2
  import {assert} from '@webex/test-helper-chai';
3
3
  import {MediaType} from '@webex/internal-media-core';
4
+ import {ReceiveSlot} from '@webex/plugin-meetings/src/multistream/receiveSlot';
4
5
  import {ReceiveSlotManager} from '@webex/plugin-meetings/src/multistream/receiveSlotManager';
5
6
  import * as ReceiveSlotModule from '@webex/plugin-meetings/src/multistream/receiveSlot';
6
7
 
@@ -30,6 +31,7 @@ describe('ReceiveSlotManager', () => {
30
31
  const fakeReceiveSlot = {
31
32
  id: `fake sdk receive slot ${fakeReceiveSlots.length + 1}`,
32
33
  mediaType,
34
+ findMemberId: sinon.stub(),
33
35
  };
34
36
 
35
37
  fakeReceiveSlots.push(fakeReceiveSlot);
@@ -170,4 +172,30 @@ describe('ReceiveSlotManager', () => {
170
172
  numFreeSlots: {'VIDEO-MAIN': 1},
171
173
  });
172
174
  });
175
+
176
+ describe('updateMemberIds', () => {
177
+
178
+ it('calls findMemberId() on all allocated receive slots', async () => {
179
+ const audioSlots: ReceiveSlot[] = [];
180
+ const videoSlots: ReceiveSlot[] = [];
181
+
182
+ // allocate a bunch of receive slots
183
+ audioSlots.push(await receiveSlotManager.allocateSlot(MediaType.AudioMain));
184
+ audioSlots.push(await receiveSlotManager.allocateSlot(MediaType.AudioMain));
185
+ videoSlots.push(await receiveSlotManager.allocateSlot(MediaType.VideoMain));
186
+ videoSlots.push(await receiveSlotManager.allocateSlot(MediaType.VideoMain));
187
+ videoSlots.push(await receiveSlotManager.allocateSlot(MediaType.VideoMain));
188
+
189
+ receiveSlotManager.updateMemberIds();
190
+
191
+ assert.strictEqual(audioSlots.length, 2);
192
+ assert.strictEqual(videoSlots.length, 3);
193
+
194
+ assert.strictEqual(fakeReceiveSlots.length, audioSlots.length + videoSlots.length);
195
+
196
+ fakeReceiveSlots.forEach(slot => {
197
+ assert.calledOnce(slot.findMemberId);
198
+ });
199
+ });
200
+ });
173
201
  });