@webex/plugin-meetings 3.8.1-next.3 → 3.8.1-next.31

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 (80) hide show
  1. package/README.md +26 -13
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/constants.js +21 -2
  5. package/dist/constants.js.map +1 -1
  6. package/dist/interpretation/index.js +1 -1
  7. package/dist/interpretation/siLanguage.js +1 -1
  8. package/dist/locus-info/index.js +38 -84
  9. package/dist/locus-info/index.js.map +1 -1
  10. package/dist/media/index.js +2 -2
  11. package/dist/media/index.js.map +1 -1
  12. package/dist/meeting/brbState.js +14 -12
  13. package/dist/meeting/brbState.js.map +1 -1
  14. package/dist/meeting/index.js +169 -66
  15. package/dist/meeting/index.js.map +1 -1
  16. package/dist/meeting/request.js +19 -0
  17. package/dist/meeting/request.js.map +1 -1
  18. package/dist/meeting/request.type.js.map +1 -1
  19. package/dist/meetings/index.js +35 -33
  20. package/dist/meetings/index.js.map +1 -1
  21. package/dist/members/index.js +8 -6
  22. package/dist/members/index.js.map +1 -1
  23. package/dist/members/request.js +3 -3
  24. package/dist/members/request.js.map +1 -1
  25. package/dist/members/util.js +18 -6
  26. package/dist/members/util.js.map +1 -1
  27. package/dist/multistream/mediaRequestManager.js +1 -1
  28. package/dist/multistream/mediaRequestManager.js.map +1 -1
  29. package/dist/multistream/remoteMedia.js +34 -5
  30. package/dist/multistream/remoteMedia.js.map +1 -1
  31. package/dist/multistream/remoteMediaGroup.js +42 -2
  32. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  33. package/dist/multistream/sendSlotManager.js +32 -2
  34. package/dist/multistream/sendSlotManager.js.map +1 -1
  35. package/dist/reachability/index.js +5 -10
  36. package/dist/reachability/index.js.map +1 -1
  37. package/dist/types/constants.d.ts +19 -0
  38. package/dist/types/locus-info/index.d.ts +0 -9
  39. package/dist/types/meeting/brbState.d.ts +0 -1
  40. package/dist/types/meeting/index.d.ts +28 -4
  41. package/dist/types/meeting/request.d.ts +9 -1
  42. package/dist/types/meeting/request.type.d.ts +74 -0
  43. package/dist/types/members/index.d.ts +8 -3
  44. package/dist/types/members/request.d.ts +1 -1
  45. package/dist/types/members/util.d.ts +5 -2
  46. package/dist/types/multistream/remoteMedia.d.ts +20 -1
  47. package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
  48. package/dist/types/multistream/sendSlotManager.d.ts +16 -0
  49. package/dist/types/reachability/index.d.ts +2 -2
  50. package/dist/webinar/index.js +1 -1
  51. package/package.json +24 -24
  52. package/src/constants.ts +20 -0
  53. package/src/locus-info/index.ts +47 -82
  54. package/src/media/index.ts +2 -2
  55. package/src/meeting/brbState.ts +9 -7
  56. package/src/meeting/index.ts +126 -23
  57. package/src/meeting/request.ts +16 -0
  58. package/src/meeting/request.type.ts +64 -0
  59. package/src/meetings/index.ts +3 -2
  60. package/src/members/index.ts +7 -5
  61. package/src/members/request.ts +2 -2
  62. package/src/members/util.ts +14 -3
  63. package/src/multistream/mediaRequestManager.ts +7 -7
  64. package/src/multistream/remoteMedia.ts +34 -4
  65. package/src/multistream/remoteMediaGroup.ts +37 -2
  66. package/src/multistream/sendSlotManager.ts +34 -2
  67. package/src/reachability/index.ts +5 -13
  68. package/test/unit/spec/locus-info/index.js +177 -83
  69. package/test/unit/spec/media/index.ts +107 -0
  70. package/test/unit/spec/meeting/brbState.ts +9 -9
  71. package/test/unit/spec/meeting/index.js +606 -55
  72. package/test/unit/spec/meeting/request.js +71 -0
  73. package/test/unit/spec/meetings/index.js +1 -0
  74. package/test/unit/spec/members/index.js +32 -9
  75. package/test/unit/spec/members/request.js +2 -2
  76. package/test/unit/spec/members/utils.js +27 -7
  77. package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
  78. package/test/unit/spec/multistream/remoteMedia.ts +66 -2
  79. package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
  80. package/test/unit/spec/reachability/index.ts +2 -6
@@ -826,4 +826,75 @@ describe('plugin-meetings', () => {
826
826
  });
827
827
  });
828
828
  });
829
+
830
+ describe('#synchronizeStage', () => {
831
+ [
832
+ ['an unset stage', {overrideDefault: false}],
833
+ [
834
+ 'a minimally set stage',
835
+ {
836
+ overrideDefault: true,
837
+ lockAttendeeViewOnStageOnly: false,
838
+ stageParameters: {
839
+ activeSpeakerProportion: 0.5,
840
+ showActiveSpeaker: {show: false, order: 0},
841
+ stageManagerType: 0,
842
+ },
843
+ },
844
+ ],
845
+ [
846
+ 'a fully set stage',
847
+ {
848
+ overrideDefault: true,
849
+ lockAttendeeViewOnStageOnly: true,
850
+ stageParameters: {
851
+ activeSpeakerProportion: 0.6,
852
+ importantParticipants: [
853
+ {mainCsi: 11111111, participantId: uuidv4(), order: 1},
854
+ {mainCsi: 22222222, participantId: uuidv4(), order: 2},
855
+ {mainCsi: 33333333, participantId: uuidv4(), order: 3},
856
+ {mainCsi: 44444444, participantId: uuidv4(), order: 4},
857
+ {mainCsi: 55555555, participantId: uuidv4(), order: 5},
858
+ {mainCsi: 66666666, participantId: uuidv4(), order: 6},
859
+ {mainCsi: 77777777, participantId: uuidv4(), order: 7},
860
+ {mainCsi: 88888888, participantId: uuidv4(), order: 8},
861
+ ],
862
+ showActiveSpeaker: {show: true, order: 0},
863
+ stageManagerType: 7,
864
+ },
865
+ customLayouts: {
866
+ background: {url: `https://test.wbx2.com/background/${uuidv4()}.jpg`},
867
+ logo: {url: `https://test.wbx2.com/logo/${uuidv4()}.png`, position: 'UpperMiddle'},
868
+ },
869
+ nameLabelStyle: {
870
+ accentColor: '#00A3FF',
871
+ background: {color: 'rgba(0, 163, 255, 1)'},
872
+ border: {color: 'rgba(0, 163, 255, 1)'},
873
+ content: {
874
+ displayName: {color: 'rgba(255, 255, 255, 0.95)'},
875
+ subtitle: {color: 'rgba(255, 255, 255, 0.7)'},
876
+ },
877
+ decoration: {color: 'rgba(255, 255, 255, 0.95)'},
878
+ fadeOut: {delay: 15},
879
+ type: 'PrimaryInverted',
880
+ },
881
+ },
882
+ ],
883
+ ].forEach(([description, videoLayout]) => {
884
+ it(`sends request to synchronize the stage with ${description} video layout`, async () => {
885
+ const locusUrl = `https://locus-test.wbx2.com/locus/api/v1/loci/${uuidv4()}`;
886
+
887
+ const synchronizePromise = meetingsRequest.synchronizeStage(locusUrl, videoLayout);
888
+
889
+ assert.exists(synchronizePromise.then);
890
+ await synchronizePromise;
891
+
892
+ checkRequest({
893
+ method: 'PATCH',
894
+ uri: `${locusUrl}/controls`,
895
+ body: {videoLayout},
896
+ });
897
+ });
898
+ });
899
+ });
829
900
  });
@@ -1716,6 +1716,7 @@ describe('plugin-meetings', () => {
1716
1716
  {file: 'meetings', function: 'fetchMeetingInfo'},
1717
1717
  'meeting:meetingInfoAvailable'
1718
1718
  );
1719
+ assert.equal(webex.meetings.meetingCollection.get(meeting.id), meeting);
1719
1720
  };
1720
1721
 
1721
1722
  it('creates the meeting from a successful meeting info fetch promise testing', async () => {
@@ -176,6 +176,20 @@ describe('plugin-meetings', () => {
176
176
  assert.calledOnce(MembersUtil.isInvalidInvitee);
177
177
  assert.isFalse(MembersUtil.isInvalidInvitee({email: 'sip:test@cisco.com'}), 'SIP email should be valid');
178
178
  });
179
+
180
+ it('should accept valid phone with isInternalNumber', async () => {
181
+ sandbox.spy(MembersUtil, 'isInvalidInvitee');
182
+
183
+ const members = createMembers({url: true});
184
+
185
+ await members.addMember({phoneNumber: '+8618578675309', isInternalNumber: false});
186
+
187
+ assert.calledOnce(MembersUtil.isInvalidInvitee);
188
+ assert.isFalse(MembersUtil.isInvalidInvitee({ phoneNumber: '+8618578675309', isInternalNumber: false }));
189
+ assert.isTrue(MembersUtil.isInvalidInvitee({ phoneNumber: '18578675309', isInternalNumber: false }));
190
+ assert.isFalse(MembersUtil.isInvalidInvitee({phoneNumber: '18578675309', isInternalNumber: true}));
191
+ assert.isTrue(MembersUtil.isInvalidInvitee({phoneNumber: '+8618578675309', isInternalNumber: true}));
192
+ });
179
193
  });
180
194
 
181
195
  describe('#admitMembers', () => {
@@ -465,29 +479,38 @@ describe('plugin-meetings', () => {
465
479
  });
466
480
  });
467
481
 
468
- describe('#cancelSIPInvite', () => {
482
+ describe('#cancelInviteByMemberId', () => {
469
483
  const memberId = uuid.v4();
470
- it('should invoke cancelSIPInviteOptions from MembersUtil when cancelSIPInvite is called with valid params', async () => {
471
- sandbox.spy(MembersUtil, 'cancelSIPInviteOptions');
484
+ it('should invoke cancelInviteByMemberIdOptions from MembersUtil when cancelInviteByMemberId is called with valid params', async () => {
485
+ sandbox.spy(MembersUtil, 'cancelInviteByMemberIdOptions');
486
+
487
+ const members = createMembers({url: url1});
488
+
489
+ await members.cancelInviteByMemberId({memberId});
490
+ assert.calledOnce(MembersUtil.cancelInviteByMemberIdOptions);
491
+ });
492
+
493
+ it('should invoke cancelInviteByMemberIdOptions from MembersUtil when cancelInviteByMemberId is called with isInternalNumber', async () => {
494
+ sandbox.spy(MembersUtil, 'cancelInviteByMemberIdOptions');
472
495
 
473
496
  const members = createMembers({url: url1});
474
497
 
475
- await members.cancelSIPInvite({memberId});
476
- assert.calledOnce(MembersUtil.cancelSIPInviteOptions);
498
+ await members.cancelInviteByMemberId({memberId, isInternalNumber: true});
499
+ assert.calledOnce(MembersUtil.cancelInviteByMemberIdOptions);
477
500
  });
478
501
 
479
502
  it('should throw a rejection if there is no locus url', async () => {
480
503
  const members = createMembers({url: false});
481
504
 
482
- assert.isRejected(members.cancelSIPInvite({memberId}));
505
+ assert.isRejected(members.cancelInviteByMemberId({memberId}));
483
506
  });
484
507
 
485
508
  it('should throw a rejection if memberId is not provided', async () => {
486
509
  const members = createMembers({url: url1});
487
510
 
488
- assert.isRejected(members.cancelSIPInvite({}));
489
- assert.isRejected(members.cancelSIPInvite({memberId: null}));
490
- assert.isRejected(members.cancelSIPInvite({memberId: undefined}));
511
+ assert.isRejected(members.cancelInviteByMemberId({}));
512
+ assert.isRejected(members.cancelInviteByMemberId({memberId: null}));
513
+ assert.isRejected(members.cancelInviteByMemberId({memberId: undefined}));
491
514
  });
492
515
  });
493
516
 
@@ -221,7 +221,7 @@ describe('plugin-meetings', () => {
221
221
  });
222
222
  });
223
223
 
224
- describe('#cancelSIPInvite', () => {
224
+ describe('#cancelInviteByMemberId', () => {
225
225
  const memberId = uuid.v4();
226
226
  it('sends a PUT to the locus endpoint', async () => {
227
227
  const options = {
@@ -231,7 +231,7 @@ describe('plugin-meetings', () => {
231
231
  locusUrl: url1,
232
232
  };
233
233
 
234
- await membersRequest.cancelSIPInvite(options);
234
+ await membersRequest.cancelInviteByMemberId(options);
235
235
 
236
236
  checkRequest({
237
237
  method: 'PUT',
@@ -302,6 +302,26 @@ describe('plugin-meetings', () => {
302
302
  });
303
303
  });
304
304
 
305
+ it('returns the correct body with phone number and isInternalNumber', () => {
306
+ const options = {
307
+ invitee: {
308
+ phoneNumber: '1234567890',
309
+ isInternalNumber: false
310
+ },
311
+ alertIfActive: false,
312
+ };
313
+
314
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
315
+ invitees: [
316
+ {
317
+ address: '1234567890',
318
+ isInternalNumber: false
319
+ },
320
+ ],
321
+ alertIfActive: false,
322
+ });
323
+ });
324
+
305
325
  it('returns the correct body with fallback to email', () => {
306
326
  const options = {
307
327
  invitee: {
@@ -391,14 +411,14 @@ describe('plugin-meetings', () => {
391
411
  });
392
412
  });
393
413
 
394
- describe('#cancelSIPInviteOptions', () => {
414
+ describe('#cancelInviteByMemberIdOptions', () => {
395
415
  it('returns the correct options', () => {
396
416
  const locusUrl = 'TestLocusUrl';
397
417
  const memberId = 'test';
398
- const invitee = {memberId};
418
+ const invitee = {memberId, isInternalNumber: false};
399
419
 
400
420
  assert.deepEqual(
401
- MembersUtil.cancelSIPInviteOptions(
421
+ MembersUtil.cancelInviteByMemberIdOptions(
402
422
  invitee,
403
423
  locusUrl
404
424
  ),
@@ -410,22 +430,22 @@ describe('plugin-meetings', () => {
410
430
  });
411
431
  });
412
432
 
413
- describe('#generateCancelSIPInviteRequestParams', () => {
433
+ describe('#generateCancelInviteByMemberIdRequestParams', () => {
414
434
  it('returns the correct params', () => {
415
435
  const locusUrl = 'TestLocusUrl';
416
436
  const memberId = 'test';
417
437
  const options = {
418
438
  locusUrl,
419
- invitee: {memberId}
439
+ invitee: {memberId, isInternalNumber: false}
420
440
  };
421
441
  const body = {
422
442
  actionType: 'REMOVE',
423
- invitees: [{address: options.invitee.memberId}],
443
+ invitees: [{address: options.invitee.memberId, isInternalNumber: false}],
424
444
  };
425
445
 
426
446
  const uri = options.locusUrl;
427
447
 
428
- assert.deepEqual(MembersUtil.generateCancelSIPInviteRequestParams(options), {
448
+ assert.deepEqual(MembersUtil.generateCancelInviteByMemberIdRequestParams(options), {
429
449
  method: HTTP_VERBS.PUT,
430
450
  uri,
431
451
  body,
@@ -3,7 +3,7 @@ import {MediaRequestManager} from '@webex/plugin-meetings/src/multistream/mediaR
3
3
  import {ReceiveSlot} from '@webex/plugin-meetings/src/multistream/receiveSlot';
4
4
  import sinon from 'sinon';
5
5
  import {assert} from '@webex/test-helper-chai';
6
- import {getMaxFs} from '@webex/plugin-meetings/src/multistream/remoteMedia';
6
+ import {getMaxFs, MAX_FS_VALUES} from '@webex/plugin-meetings/src/multistream/remoteMedia';
7
7
  import FakeTimers from '@sinonjs/fake-timers';
8
8
  import * as InternalMediaCoreModule from '@webex/internal-media-core';
9
9
  import { expect } from 'chai';
@@ -36,12 +36,15 @@ describe('MediaRequestManager', () => {
36
36
  const CROSS_POLICY_DUPLICATION = true;
37
37
  const MAX_FPS = 3000;
38
38
  const MAX_FS_360p = 920;
39
+ const MAX_FS_540p = 2040;
39
40
  const MAX_FS_720p = 3600;
40
41
  const MAX_FS_1080p = 8192;
41
42
  const MAX_MBPS_360p = 27600;
43
+ const MAX_MBPS_540p = 61200;
42
44
  const MAX_MBPS_720p = 108000;
43
45
  const MAX_MBPS_1080p = 245760;
44
46
  const MAX_PAYLOADBITSPS_360p = 640000;
47
+ const MAX_PAYLOADBITSPS_540p = 880000;
45
48
  const MAX_PAYLOADBITSPS_720p = 2500000;
46
49
  const MAX_PAYLOADBITSPS_1080p = 4000000;
47
50
 
@@ -82,7 +85,14 @@ describe('MediaRequestManager', () => {
82
85
  });
83
86
 
84
87
  // helper function for adding an active speaker request
85
- const addActiveSpeakerRequest = (priority, receiveSlots, maxFs, commit = false, preferLiveVideo = true, namedMediaGroups = undefined) =>
88
+ const addActiveSpeakerRequest = (
89
+ priority,
90
+ receiveSlots,
91
+ maxFs,
92
+ commit = false,
93
+ preferLiveVideo = true,
94
+ namedMediaGroups = undefined
95
+ ) =>
86
96
  mediaRequestManager.addRequest(
87
97
  {
88
98
  policyInfo: {
@@ -216,6 +226,9 @@ describe('MediaRequestManager', () => {
216
226
  },
217
227
  false
218
228
  );
229
+
230
+
231
+
219
232
  mediaRequestManager.addRequest(
220
233
  {
221
234
  policyInfo: {
@@ -892,15 +905,15 @@ describe('MediaRequestManager', () => {
892
905
  // request 10 "large" 1080p streams
893
906
  addActiveSpeakerRequest(255, fakeReceiveSlots.slice(0, 10), getMaxFs('large'), true);
894
907
 
895
- // check that resulting requests are 10 "small" 360p streams
908
+ // check that resulting requests are 10 540p streams
896
909
  checkMediaRequestsSent([
897
910
  {
898
911
  policy: 'active-speaker',
899
912
  priority: 255,
900
913
  receiveSlots: fakeWcmeSlots.slice(0, 10),
901
- maxPayloadBitsPerSecond: MAX_PAYLOADBITSPS_360p,
902
- maxFs: getMaxFs('small'),
903
- maxMbps: MAX_MBPS_360p,
914
+ maxPayloadBitsPerSecond: MAX_PAYLOADBITSPS_540p,
915
+ maxFs: MAX_FS_VALUES['540p'],
916
+ maxMbps: MAX_MBPS_540p,
904
917
  },
905
918
  ]);
906
919
  });
@@ -3,7 +3,7 @@ import 'jsdom-global/register';
3
3
  import EventEmitter from 'events';
4
4
 
5
5
  import {MediaType} from '@webex/internal-media-core';
6
- import {RemoteMedia, RemoteMediaEvents} from '@webex/plugin-meetings/src/multistream/remoteMedia';
6
+ import {RemoteMedia, RemoteMediaEvents, RemoteVideoResolution} from '@webex/plugin-meetings/src/multistream/remoteMedia';
7
7
  import {ReceiveSlotEvents} from '@webex/plugin-meetings/src/multistream/receiveSlot';
8
8
  import sinon from 'sinon';
9
9
  import {assert} from '@webex/test-helper-chai';
@@ -257,7 +257,9 @@ describe('RemoteMedia', () => {
257
257
  {height: 198, fs: 920}, // 360p
258
258
  {height: 360, fs: 920},
259
259
  {height: 395, fs: 920},
260
- {height: 396, fs: 3600}, // 720p
260
+ {height: 396, fs: 2040}, // 540p
261
+ {height: 540, fs: 2040},
262
+ {height: 610, fs: 3600}, // 720p
261
263
  {height: 720, fs: 3600},
262
264
  {height: 721, fs: 8192}, // 1080p
263
265
  {height: 1080, fs: 8192},
@@ -271,4 +273,66 @@ describe('RemoteMedia', () => {
271
273
  }
272
274
  );
273
275
  });
276
+
277
+ describe('getEffectiveMaxFs()', () => {
278
+ it('returns maxFrameSize when it is greater than 0', () => {
279
+ remoteMedia.setSizeHint(960, 540);
280
+
281
+ const result = remoteMedia.getEffectiveMaxFs();
282
+
283
+ assert.strictEqual(result, 2040);
284
+ });
285
+
286
+ it('returns getMaxFs result when maxFrameSize is 0 and resolution is provided', () => {
287
+ remoteMedia.setSizeHint(0, 0);
288
+
289
+ // remoteMedia was created with {resolution: 'medium'} in beforeEach
290
+
291
+ const result = remoteMedia.getEffectiveMaxFs();
292
+
293
+ // 'medium' resolution should map to 720p which is 3600
294
+ assert.strictEqual(result, 3600);
295
+ });
296
+
297
+ it('returns undefined when maxFrameSize is 0 and no resolution is provided', () => {
298
+ remoteMedia.setSizeHint(0, 0);
299
+
300
+ // Create a new RemoteMedia without resolution option
301
+ const remoteMediaWithoutResolution = new RemoteMedia(fakeReceiveSlot, fakeMediaRequestManager);
302
+
303
+ const result = remoteMediaWithoutResolution.getEffectiveMaxFs();
304
+
305
+ assert.strictEqual(result, undefined);
306
+ });
307
+
308
+ it('prioritizes maxFrameSize over resolution option', () => {
309
+ remoteMedia.setSizeHint(640, 360);
310
+ // remoteMedia was created with {resolution: 'medium'} in beforeEach
311
+
312
+ const result = remoteMedia.getEffectiveMaxFs();
313
+
314
+ // Should return maxFrameSize (500) instead of resolution-based value (3600)
315
+ assert.strictEqual(result, 920);
316
+ });
317
+
318
+ it('works correctly with different resolution options', () => {
319
+ const testCases: Array<{ resolution: RemoteVideoResolution; expected: number }> = [
320
+ { resolution: 'thumbnail', expected: 60 },
321
+ { resolution: 'very small', expected: 240 },
322
+ { resolution: 'small', expected: 920 },
323
+ { resolution: 'medium', expected: 3600 },
324
+ { resolution: 'large', expected: 8192 },
325
+ { resolution: 'best', expected: 8192 },
326
+ ];
327
+
328
+ testCases.forEach(({ resolution, expected }) => {
329
+ const testRemoteMedia = new RemoteMedia(fakeReceiveSlot, fakeMediaRequestManager, { resolution });
330
+ testRemoteMedia.setSizeHint(0, 0); // Ensure maxFrameSize doesn't interfere
331
+
332
+ const result = testRemoteMedia.getEffectiveMaxFs();
333
+
334
+ assert.strictEqual(result, expected, `Failed for resolution: ${resolution}`);
335
+ });
336
+ });
337
+ });
274
338
  });
@@ -272,4 +272,63 @@ describe('SendSlotsManager', () => {
272
272
  expect(() => sendSlotsManager.getSlot(MediaType.VideoSlides)).to.throw();
273
273
  });
274
274
  });
275
+
276
+ describe('sourceStateOverride', () => {
277
+ let mediaConnection: MultistreamRoapMediaConnection;
278
+ beforeEach(() => {
279
+ mediaConnection = {
280
+ createSendSlot: sinon.stub().returns({
281
+ setSourceStateOverride: sinon.stub().resolves(),
282
+ clearSourceStateOverride: sinon.stub().resolves(),
283
+ }),
284
+ } as MultistreamRoapMediaConnection;
285
+ });
286
+
287
+ it(`can set source state override for ${MediaType.VideoMain}`, () => {
288
+ const slot: any = sendSlotsManager.createSlot(mediaConnection, MediaType.VideoMain);
289
+
290
+ const set = () => sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
291
+
292
+ expect(set).not.to.throw();
293
+ expect(slot.setSourceStateOverride.calledWith('away')).to.be.true;
294
+ });
295
+
296
+ [MediaType.VideoSlides, MediaType.AudioMain, MediaType.AudioSlides].forEach((mediaType) => {
297
+ it(`can't set source state override for ${mediaType}`, () => {
298
+ const slot: any = sendSlotsManager.createSlot(mediaConnection, mediaType);
299
+
300
+ const set = () => sendSlotsManager.setSourceStateOverride(mediaType, 'away');
301
+
302
+ expect(set).to.throw();
303
+ expect(slot.setSourceStateOverride.called).to.be.false;
304
+ });
305
+ });
306
+
307
+ it("can't set source state override for non-existing slot", () => {
308
+ const set = () => sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
309
+ expect(set).to.throw(`Slot for ${MediaType.VideoMain} does not exist`);
310
+ });
311
+
312
+ it('can clear source state override', () => {
313
+ const slot: any = sendSlotsManager.createSlot(mediaConnection, MediaType.VideoMain);
314
+ sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
315
+
316
+ expect(slot.setSourceStateOverride.calledWith('away')).to.be.true;
317
+ expect(slot.clearSourceStateOverride.called).to.be.false;
318
+
319
+ sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, null);
320
+ expect(slot.clearSourceStateOverride.called).to.be.true;
321
+ });
322
+
323
+ it("won't set source state override if it didn't change", () => {
324
+ const slot: any = sendSlotsManager.createSlot(mediaConnection, MediaType.VideoMain);
325
+ sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
326
+
327
+ expect(slot.setSourceStateOverride.calledWith('away')).to.be.true;
328
+ slot.setSourceStateOverride.resetHistory();
329
+
330
+ sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
331
+ expect(slot.setSourceStateOverride.called).to.be.false;
332
+ });
333
+ });
275
334
  });
@@ -2764,14 +2764,10 @@ describe('isSubnetReachable', () => {
2764
2764
  });
2765
2765
 
2766
2766
  it('returns true if the subnet is reachable', () => {
2767
- assert(reachability.isSubnetReachable('1.2.3.4'));
2767
+ assert(reachability.isSubnetReachable('1'));
2768
2768
  });
2769
2769
 
2770
2770
  it(`returns false if the subnet is unreachable`, () => {
2771
- assert(!reachability.isSubnetReachable('11.2.3.4'));
2772
- });
2773
-
2774
- it('returns null if the subnet is not provided', () => {
2775
- assert.isNull(reachability.isSubnetReachable(undefined));
2771
+ assert(!reachability.isSubnetReachable('11'));
2776
2772
  });
2777
2773
  });