@webex/plugin-meetings 3.0.0-stream-classes.4 → 3.0.0-test.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.
Files changed (239) hide show
  1. package/README.md +12 -0
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/common/errors/no-meeting-info.js +51 -0
  5. package/dist/common/errors/no-meeting-info.js.map +1 -0
  6. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  7. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  8. package/dist/common/errors/webex-errors.js +23 -3
  9. package/dist/common/errors/webex-errors.js.map +1 -1
  10. package/dist/common/logs/request.js +5 -1
  11. package/dist/common/logs/request.js.map +1 -1
  12. package/dist/config.js +1 -1
  13. package/dist/config.js.map +1 -1
  14. package/dist/constants.js +69 -9
  15. package/dist/constants.js.map +1 -1
  16. package/dist/index.js +11 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/interceptors/index.js +15 -0
  19. package/dist/interceptors/index.js.map +1 -0
  20. package/dist/interceptors/locusRetry.js +93 -0
  21. package/dist/interceptors/locusRetry.js.map +1 -0
  22. package/dist/interpretation/index.js +16 -2
  23. package/dist/interpretation/index.js.map +1 -1
  24. package/dist/interpretation/siLanguage.js +1 -1
  25. package/dist/locus-info/index.js +40 -11
  26. package/dist/locus-info/index.js.map +1 -1
  27. package/dist/locus-info/mediaSharesUtils.js +15 -1
  28. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  29. package/dist/locus-info/parser.js +42 -21
  30. package/dist/locus-info/parser.js.map +1 -1
  31. package/dist/media/index.js +10 -6
  32. package/dist/media/index.js.map +1 -1
  33. package/dist/media/properties.js +13 -3
  34. package/dist/media/properties.js.map +1 -1
  35. package/dist/mediaQualityMetrics/config.js +135 -330
  36. package/dist/mediaQualityMetrics/config.js.map +1 -1
  37. package/dist/meeting/in-meeting-actions.js +4 -0
  38. package/dist/meeting/in-meeting-actions.js.map +1 -1
  39. package/dist/meeting/index.js +2187 -1074
  40. package/dist/meeting/index.js.map +1 -1
  41. package/dist/meeting/muteState.js +37 -25
  42. package/dist/meeting/muteState.js.map +1 -1
  43. package/dist/meeting/request.js +34 -19
  44. package/dist/meeting/request.js.map +1 -1
  45. package/dist/meeting/util.js +71 -0
  46. package/dist/meeting/util.js.map +1 -1
  47. package/dist/meeting-info/index.js +48 -23
  48. package/dist/meeting-info/index.js.map +1 -1
  49. package/dist/meeting-info/meeting-info-v2.js +25 -4
  50. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  51. package/dist/meeting-info/utilv2.js +1 -1
  52. package/dist/meeting-info/utilv2.js.map +1 -1
  53. package/dist/meetings/collection.js +17 -0
  54. package/dist/meetings/collection.js.map +1 -1
  55. package/dist/meetings/index.js +142 -57
  56. package/dist/meetings/index.js.map +1 -1
  57. package/dist/meetings/util.js +2 -6
  58. package/dist/meetings/util.js.map +1 -1
  59. package/dist/member/index.js +9 -0
  60. package/dist/member/index.js.map +1 -1
  61. package/dist/member/util.js +11 -0
  62. package/dist/member/util.js.map +1 -1
  63. package/dist/members/index.js +17 -1
  64. package/dist/members/index.js.map +1 -1
  65. package/dist/members/types.js.map +1 -1
  66. package/dist/members/util.js +15 -4
  67. package/dist/members/util.js.map +1 -1
  68. package/dist/metrics/constants.js +15 -1
  69. package/dist/metrics/constants.js.map +1 -1
  70. package/dist/multistream/mediaRequestManager.js +1 -1
  71. package/dist/multistream/mediaRequestManager.js.map +1 -1
  72. package/dist/multistream/remoteMediaGroup.js +16 -2
  73. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  74. package/dist/multistream/remoteMediaManager.js +222 -73
  75. package/dist/multistream/remoteMediaManager.js.map +1 -1
  76. package/dist/multistream/sendSlotManager.js +22 -0
  77. package/dist/multistream/sendSlotManager.js.map +1 -1
  78. package/dist/reachability/clusterReachability.js +356 -0
  79. package/dist/reachability/clusterReachability.js.map +1 -0
  80. package/dist/reachability/index.js +262 -432
  81. package/dist/reachability/index.js.map +1 -1
  82. package/dist/reachability/request.js +1 -1
  83. package/dist/reachability/request.js.map +1 -1
  84. package/dist/reachability/util.js +29 -0
  85. package/dist/reachability/util.js.map +1 -0
  86. package/dist/reconnection-manager/index.js +113 -96
  87. package/dist/reconnection-manager/index.js.map +1 -1
  88. package/dist/roap/index.js +57 -25
  89. package/dist/roap/index.js.map +1 -1
  90. package/dist/roap/request.js +5 -13
  91. package/dist/roap/request.js.map +1 -1
  92. package/dist/roap/turnDiscovery.js +173 -81
  93. package/dist/roap/turnDiscovery.js.map +1 -1
  94. package/dist/rtcMetrics/index.js +68 -6
  95. package/dist/rtcMetrics/index.js.map +1 -1
  96. package/dist/statsAnalyzer/index.js +338 -289
  97. package/dist/statsAnalyzer/index.js.map +1 -1
  98. package/dist/statsAnalyzer/mqaUtil.js +296 -156
  99. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  100. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  101. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  102. package/dist/types/common/errors/webex-errors.d.ts +13 -1
  103. package/dist/types/common/logs/request.d.ts +2 -0
  104. package/dist/types/config.d.ts +1 -1
  105. package/dist/types/constants.d.ts +66 -13
  106. package/dist/types/index.d.ts +1 -1
  107. package/dist/types/interceptors/index.d.ts +2 -0
  108. package/dist/types/interceptors/locusRetry.d.ts +27 -0
  109. package/dist/types/locus-info/index.d.ts +1 -1
  110. package/dist/types/locus-info/parser.d.ts +3 -2
  111. package/dist/types/mediaQualityMetrics/config.d.ts +99 -223
  112. package/dist/types/meeting/in-meeting-actions.d.ts +4 -0
  113. package/dist/types/meeting/index.d.ts +285 -34
  114. package/dist/types/meeting/locusMediaRequest.d.ts +1 -2
  115. package/dist/types/meeting/muteState.d.ts +2 -8
  116. package/dist/types/meeting/request.d.ts +4 -1
  117. package/dist/types/meeting/util.d.ts +25 -1
  118. package/dist/types/meeting-info/index.d.ts +7 -0
  119. package/dist/types/meeting-info/meeting-info-v2.d.ts +1 -0
  120. package/dist/types/meetings/collection.d.ts +9 -0
  121. package/dist/types/meetings/index.d.ts +42 -14
  122. package/dist/types/member/index.d.ts +1 -0
  123. package/dist/types/members/types.d.ts +1 -0
  124. package/dist/types/members/util.d.ts +5 -0
  125. package/dist/types/metrics/constants.d.ts +15 -0
  126. package/dist/types/multistream/mediaRequestManager.d.ts +2 -0
  127. package/dist/types/multistream/remoteMediaGroup.d.ts +2 -0
  128. package/dist/types/multistream/remoteMediaManager.d.ts +25 -1
  129. package/dist/types/multistream/sendSlotManager.d.ts +9 -0
  130. package/dist/types/reachability/clusterReachability.d.ts +109 -0
  131. package/dist/types/reachability/index.d.ts +59 -112
  132. package/dist/types/reachability/request.d.ts +1 -1
  133. package/dist/types/reachability/util.d.ts +8 -0
  134. package/dist/types/reconnection-manager/index.d.ts +10 -0
  135. package/dist/types/roap/index.d.ts +2 -1
  136. package/dist/types/roap/request.d.ts +2 -1
  137. package/dist/types/roap/turnDiscovery.d.ts +21 -4
  138. package/dist/types/rtcMetrics/index.d.ts +15 -1
  139. package/dist/types/statsAnalyzer/index.d.ts +28 -11
  140. package/dist/types/statsAnalyzer/mqaUtil.d.ts +28 -4
  141. package/dist/types/webinar/collection.d.ts +16 -0
  142. package/dist/types/webinar/index.d.ts +5 -0
  143. package/dist/webinar/collection.js +44 -0
  144. package/dist/webinar/collection.js.map +1 -0
  145. package/dist/webinar/index.js +69 -0
  146. package/dist/webinar/index.js.map +1 -0
  147. package/package.json +3 -2
  148. package/src/common/errors/no-meeting-info.ts +24 -0
  149. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  150. package/src/common/errors/webex-errors.ts +19 -2
  151. package/src/common/logs/request.ts +5 -1
  152. package/src/config.ts +1 -1
  153. package/src/constants.ts +71 -6
  154. package/src/index.ts +5 -0
  155. package/src/interceptors/index.ts +3 -0
  156. package/src/interceptors/locusRetry.ts +67 -0
  157. package/src/interpretation/index.ts +18 -1
  158. package/src/locus-info/index.ts +52 -16
  159. package/src/locus-info/mediaSharesUtils.ts +16 -0
  160. package/src/locus-info/parser.ts +47 -21
  161. package/src/media/index.ts +8 -6
  162. package/src/media/properties.ts +17 -2
  163. package/src/mediaQualityMetrics/config.ts +103 -238
  164. package/src/meeting/in-meeting-actions.ts +8 -0
  165. package/src/meeting/index.ts +1510 -529
  166. package/src/meeting/muteState.ts +34 -20
  167. package/src/meeting/request.ts +19 -1
  168. package/src/meeting/util.ts +97 -0
  169. package/src/meeting-info/index.ts +47 -20
  170. package/src/meeting-info/meeting-info-v2.ts +27 -5
  171. package/src/meeting-info/utilv2.ts +1 -1
  172. package/src/meetings/collection.ts +13 -0
  173. package/src/meetings/index.ts +112 -31
  174. package/src/meetings/util.ts +2 -8
  175. package/src/member/index.ts +9 -0
  176. package/src/member/util.ts +14 -0
  177. package/src/members/index.ts +29 -2
  178. package/src/members/types.ts +1 -0
  179. package/src/members/util.ts +15 -1
  180. package/src/metrics/constants.ts +14 -0
  181. package/src/multistream/mediaRequestManager.ts +4 -1
  182. package/src/multistream/remoteMediaGroup.ts +19 -0
  183. package/src/multistream/remoteMediaManager.ts +141 -18
  184. package/src/multistream/sendSlotManager.ts +29 -0
  185. package/src/reachability/clusterReachability.ts +320 -0
  186. package/src/reachability/index.ts +221 -382
  187. package/src/reachability/request.ts +1 -1
  188. package/src/reachability/util.ts +24 -0
  189. package/src/reconnection-manager/index.ts +87 -83
  190. package/src/roap/index.ts +60 -24
  191. package/src/roap/request.ts +3 -16
  192. package/src/roap/turnDiscovery.ts +112 -39
  193. package/src/rtcMetrics/index.ts +71 -5
  194. package/src/statsAnalyzer/index.ts +430 -427
  195. package/src/statsAnalyzer/mqaUtil.ts +317 -168
  196. package/src/webinar/collection.ts +31 -0
  197. package/src/webinar/index.ts +62 -0
  198. package/test/integration/spec/converged-space-meetings.js +7 -7
  199. package/test/integration/spec/journey.js +86 -104
  200. package/test/integration/spec/space-meeting.js +9 -9
  201. package/test/unit/spec/interceptors/locusRetry.ts +131 -0
  202. package/test/unit/spec/interpretation/index.ts +36 -3
  203. package/test/unit/spec/locus-info/index.js +205 -12
  204. package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
  205. package/test/unit/spec/locus-info/mediaSharesUtils.ts +10 -0
  206. package/test/unit/spec/locus-info/parser.js +54 -13
  207. package/test/unit/spec/media/index.ts +20 -4
  208. package/test/unit/spec/media/properties.ts +2 -2
  209. package/test/unit/spec/meeting/in-meeting-actions.ts +4 -0
  210. package/test/unit/spec/meeting/index.js +4027 -1075
  211. package/test/unit/spec/meeting/muteState.js +219 -67
  212. package/test/unit/spec/meeting/request.js +63 -12
  213. package/test/unit/spec/meeting/utils.js +93 -0
  214. package/test/unit/spec/meeting-info/index.js +180 -61
  215. package/test/unit/spec/meeting-info/meetinginfov2.js +196 -53
  216. package/test/unit/spec/meetings/collection.js +12 -0
  217. package/test/unit/spec/meetings/index.js +619 -206
  218. package/test/unit/spec/meetings/utils.js +35 -12
  219. package/test/unit/spec/member/index.js +8 -7
  220. package/test/unit/spec/member/util.js +32 -0
  221. package/test/unit/spec/members/index.js +130 -17
  222. package/test/unit/spec/members/utils.js +26 -0
  223. package/test/unit/spec/multistream/mediaRequestManager.ts +20 -2
  224. package/test/unit/spec/multistream/remoteMediaGroup.ts +80 -1
  225. package/test/unit/spec/multistream/remoteMediaManager.ts +210 -3
  226. package/test/unit/spec/multistream/sendSlotManager.ts +50 -18
  227. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  228. package/test/unit/spec/reachability/index.ts +505 -135
  229. package/test/unit/spec/reachability/util.ts +40 -0
  230. package/test/unit/spec/reconnection-manager/index.js +74 -17
  231. package/test/unit/spec/roap/index.ts +181 -61
  232. package/test/unit/spec/roap/request.ts +27 -3
  233. package/test/unit/spec/roap/turnDiscovery.ts +362 -101
  234. package/test/unit/spec/rtcMetrics/index.ts +57 -3
  235. package/test/unit/spec/stats-analyzer/index.js +1225 -12
  236. package/test/unit/spec/webinar/collection.ts +13 -0
  237. package/test/unit/spec/webinar/index.ts +60 -0
  238. package/test/utils/integrationTestUtils.js +4 -4
  239. package/test/utils/webex-test-users.js +12 -4
@@ -3,6 +3,10 @@
3
3
  */
4
4
  import 'jsdom-global/register';
5
5
 
6
+ // Polyfill for crypto: https://github.com/jsdom/jsdom/issues/1612#issuecomment-663210638
7
+ import {Crypto} from '@peculiar/webcrypto';
8
+ global.crypto = new Crypto();
9
+
6
10
  import Device from '@webex/internal-plugin-device';
7
11
  import Mercury from '@webex/internal-plugin-mercury';
8
12
  import {assert} from '@webex/test-helper-chai';
@@ -13,7 +17,7 @@ import StaticConfig from '@webex/plugin-meetings/src/common/config';
13
17
  import TriggerProxy from '@webex/plugin-meetings/src/common/events/trigger-proxy';
14
18
  import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
15
19
  import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
16
- import Meeting from '@webex/plugin-meetings/src/meeting';
20
+ import Meeting, {CallStateForMetrics} from '@webex/plugin-meetings/src/meeting';
17
21
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
18
22
  import Meetings from '@webex/plugin-meetings/src/meetings';
19
23
  import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
@@ -32,10 +36,11 @@ import {
32
36
  EVENT_TRIGGERS,
33
37
  } from '../../../../src/constants';
34
38
  import CaptchaError from '@webex/plugin-meetings/src/common/errors/captcha-error';
35
- import { forEach } from 'lodash';
39
+ import {forEach} from 'lodash';
36
40
  import PasswordError from '@webex/plugin-meetings/src/common/errors/password-error';
37
41
  import PermissionError from '@webex/plugin-meetings/src/common/errors/permission';
38
- import {NoiseReductionEffect,VirtualBackgroundEffect} from '@webex/media-helpers';
42
+ import {NoiseReductionEffect, VirtualBackgroundEffect} from '@webex/media-helpers';
43
+ import NoMeetingInfoError from '../../../../src/common/errors/no-meeting-info';
39
44
 
40
45
  describe('plugin-meetings', () => {
41
46
  const logger = {
@@ -74,7 +79,7 @@ describe('plugin-meetings', () => {
74
79
  describe('meetings index', () => {
75
80
  beforeEach(() => {
76
81
  MeetingsUtil.checkH264Support = sinon.stub();
77
- uuid1 = uuid.v4();
82
+ uuid1 = uuid.v4();
78
83
  url1 = `https://example.com/${uuid.v4()}`;
79
84
  uri1 = `test-${uuid.v4()}@example.com`;
80
85
  test1 = `test-${uuid.v4()}`;
@@ -235,30 +240,15 @@ describe('plugin-meetings', () => {
235
240
  });
236
241
  });
237
242
 
238
- describe('#_toggleTurnDiscovery', () => {
239
- it('should have toggleAdhocMeetings', () => {
240
- assert.equal(typeof webex.meetings._toggleTurnDiscovery, 'function');
243
+ describe('#_toggleTcpReachability', () => {
244
+ it('should have _toggleTcpReachability', () => {
245
+ assert.equal(typeof webex.meetings._toggleTcpReachability, 'function');
241
246
  });
242
247
 
243
248
  describe('success', () => {
244
- it('should update meetings to do TURN discovery', () => {
245
- webex.meetings._toggleTurnDiscovery(true);
246
- assert.equal(webex.meetings.config.experimental.enableTurnDiscovery, true);
247
-
248
- webex.meetings._toggleTurnDiscovery(false);
249
- assert.equal(webex.meetings.config.experimental.enableTurnDiscovery, false);
250
- });
251
- });
252
-
253
- describe('failure', () => {
254
- it('should not accept non boolean input', () => {
255
- const currentEnableTurnDiscovery = webex.meetings.config.experimental.enableTurnDiscovery;
256
-
257
- webex.meetings._toggleTurnDiscovery('test');
258
- assert.equal(
259
- webex.meetings.config.experimental.enableAdhocMeetings,
260
- currentEnableTurnDiscovery
261
- );
249
+ it('should update meetings to do TCP reachability', () => {
250
+ webex.meetings._toggleTcpReachability(true);
251
+ assert.equal(webex.meetings.config.experimental.enableTcpReachability, true);
262
252
  });
263
253
  });
264
254
  });
@@ -360,24 +350,24 @@ describe('plugin-meetings', () => {
360
350
  beforeEach(() => {
361
351
  webex.credentials = {
362
352
  supertoken: {
363
- access_token: "fake_token"
364
- }
353
+ access_token: 'fake_token',
354
+ },
365
355
  };
366
- })
356
+ });
367
357
 
368
358
  it('creates background effect', async () => {
369
359
  const result = await webex.meetings.createVirtualBackgroundEffect();
370
360
 
371
361
  assert.exists(result);
372
362
  assert.instanceOf(result, VirtualBackgroundEffect);
373
- assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'isLoaded', 'options']);
363
+ assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'options']);
374
364
  assert.deepEqual(result.options, {
375
365
  mode: 'BLUR',
376
366
  blurStrength: 'STRONG',
377
367
  generator: 'worker',
378
368
  quality: 'LOW',
379
369
  authToken: 'fake_token',
380
- mirror: false
370
+ mirror: false,
381
371
  });
382
372
  assert.exists(result.enable);
383
373
  assert.exists(result.disable);
@@ -386,35 +376,35 @@ describe('plugin-meetings', () => {
386
376
 
387
377
  it('creates background effect with custom options passed', async () => {
388
378
  const effectOptions = {
389
- generator: "local",
379
+ generator: 'local',
390
380
  frameRate: 45,
391
- mode: "IMAGE",
381
+ mode: 'IMAGE',
392
382
  mirror: false,
393
- quality: "HIGH",
394
- blurStrength: "STRONG",
395
- bgImageUrl: "https://test.webex.com/landscape.5a535788.jpg",
383
+ quality: 'HIGH',
384
+ blurStrength: 'STRONG',
385
+ bgImageUrl: 'https://test.webex.com/landscape.5a535788.jpg',
396
386
  };
397
387
 
398
388
  const result = await webex.meetings.createVirtualBackgroundEffect(effectOptions);
399
389
 
400
390
  assert.exists(result);
401
391
  assert.instanceOf(result, VirtualBackgroundEffect);
402
- assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'isLoaded', 'options']);
403
- assert.deepEqual(result.options, {...effectOptions, authToken: "fake_token"});
392
+ assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'options']);
393
+ assert.deepEqual(result.options, {...effectOptions, authToken: 'fake_token'});
404
394
  assert.exists(result.enable);
405
395
  assert.exists(result.disable);
406
396
  assert.exists(result.dispose);
407
397
  });
408
- })
398
+ });
409
399
 
410
400
  describe('noise reduction effect', () => {
411
401
  beforeEach(() => {
412
402
  webex.credentials = {
413
403
  supertoken: {
414
- access_token: "fake_token"
415
- }
404
+ access_token: 'fake_token',
405
+ },
416
406
  };
417
- })
407
+ });
418
408
 
419
409
  it('creates noise reduction effect', async () => {
420
410
  const result = await webex.meetings.createNoiseReductionEffect({audioContext: {}});
@@ -424,7 +414,7 @@ describe('plugin-meetings', () => {
424
414
  assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
425
415
  assert.deepEqual(result.options, {
426
416
  authToken: 'fake_token',
427
- audioContext: {}
417
+ audioContext: {},
428
418
  });
429
419
  assert.exists(result.enable);
430
420
  assert.exists(result.disable);
@@ -434,8 +424,8 @@ describe('plugin-meetings', () => {
434
424
  it('creates noise reduction effect with custom options passed', async () => {
435
425
  const effectOptions = {
436
426
  audioContext: {},
437
- mode: "WORKLET",
438
- env: "prod"
427
+ mode: 'WORKLET',
428
+ env: 'prod',
439
429
  };
440
430
 
441
431
  const result = await webex.meetings.createNoiseReductionEffect(effectOptions);
@@ -443,12 +433,12 @@ describe('plugin-meetings', () => {
443
433
  assert.exists(result);
444
434
  assert.instanceOf(result, NoiseReductionEffect);
445
435
  assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
446
- assert.deepEqual(result.options, {...effectOptions, authToken: "fake_token"});
436
+ assert.deepEqual(result.options, {...effectOptions, authToken: 'fake_token'});
447
437
  assert.exists(result.enable);
448
438
  assert.exists(result.disable);
449
439
  assert.exists(result.dispose);
450
440
  });
451
- })
441
+ });
452
442
 
453
443
  describe('gets', () => {
454
444
  describe('#getReachability', () => {
@@ -458,10 +448,7 @@ describe('plugin-meetings', () => {
458
448
  it('gets the reachability data instance from webex.meetings', () => {
459
449
  const reachability = webex.meetings.getReachability();
460
450
 
461
- assert.exists(
462
- reachability,
463
- 'reachability is defined'
464
- );
451
+ assert.exists(reachability, 'reachability is defined');
465
452
  assert.instanceOf(reachability, Reachability, 'should be a reachability instance');
466
453
  });
467
454
  });
@@ -524,6 +511,27 @@ describe('plugin-meetings', () => {
524
511
  it('should have #syncMeetings', () => {
525
512
  assert.exists(webex.meetings.syncMeetings);
526
513
  });
514
+ it('should do nothing and return a resolved promise if unverified guest', async () => {
515
+ webex.meetings.request.getActiveMeetings = sinon.stub().returns(
516
+ Promise.resolve({
517
+ loci: [
518
+ {
519
+ url: url1,
520
+ },
521
+ ],
522
+ })
523
+ );
524
+ webex.credentials.isUnverifiedGuest = true;
525
+ LoggerProxy.logger.info = sinon.stub();
526
+
527
+ await webex.meetings.syncMeetings();
528
+
529
+ assert.notCalled(webex.meetings.request.getActiveMeetings);
530
+ assert.calledWith(
531
+ LoggerProxy.logger.info,
532
+ 'Meetings:index#syncMeetings --> skipping meeting sync as unverified guest'
533
+ );
534
+ });
527
535
  describe('succesful requests', () => {
528
536
  beforeEach(() => {
529
537
  webex.meetings.request.getActiveMeetings = sinon.stub().returns(
@@ -537,7 +545,6 @@ describe('plugin-meetings', () => {
537
545
  );
538
546
  });
539
547
  describe('when meeting is returned', () => {
540
-
541
548
  beforeEach(() => {
542
549
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
543
550
  locusInfo,
@@ -586,43 +593,71 @@ describe('plugin-meetings', () => {
586
593
  });
587
594
  });
588
595
  });
589
- describe('destory non active meeting', () => {
590
- let initialSetup;
591
- let parse;
596
+ describe('when destroying meeting is needed', () => {
592
597
  let destroySpy;
593
598
 
599
+ const meetingCollectionMeetings = {
600
+ stillValidLocusMeeting: {
601
+ locusUrl: 'still-valid-locus-url',
602
+ sendCallAnalyzerMetrics: sinon.stub(),
603
+ },
604
+ noLongerValidLocusMeeting: {
605
+ locusUrl: 'no-longer-valid-locus-url',
606
+ sendCallAnalyzerMetrics: sinon.stub(),
607
+ },
608
+ otherNonLocusMeeting1: {
609
+ locusUrl: null,
610
+ sendCallAnalyzerMetrics: sinon.stub(),
611
+ },
612
+ otherNonLocusMeeting2: {
613
+ locusUrl: undefined,
614
+ sendCallAnalyzerMetrics: sinon.stub(),
615
+ },
616
+ };
617
+
594
618
  beforeEach(() => {
595
619
  destroySpy = sinon.spy(webex.meetings, 'destroy');
596
- initialSetup = sinon.stub().returns(true);
597
- webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
598
- locusInfo,
599
- sendCallAnalyzerMetrics: sinon.stub(),
600
- });
601
- webex.meetings.meetingCollection.getAll = sinon.stub().returns({
602
- meetingutk: {
603
- locusUrl: 'fdfdjfdhj',
604
- sendCallAnalyzerMetrics: sinon.stub(),
605
- },
606
- });
607
- webex.meetings.create = sinon.stub().returns(
608
- Promise.resolve({
609
- locusInfo: {
610
- initialSetup,
611
- },
612
- sendCallAnalyzerMetrics: sinon.stub(),
613
- })
614
- );
620
+ webex.meetings.meetingCollection.getAll = sinon
621
+ .stub()
622
+ .returns(meetingCollectionMeetings);
615
623
  webex.meetings.request.getActiveMeetings = sinon.stub().returns(
616
624
  Promise.resolve({
617
- loci: [],
625
+ loci: [{url: 'still-valid-locus-url'}],
618
626
  })
619
627
  );
620
628
  MeetingUtil.cleanUp = sinon.stub().returns(Promise.resolve());
621
629
  });
622
- it('destroy non active meetings', async () => {
630
+
631
+ it('destroy any meeting that has no active locus url if keepOnlyLocusMeetings is not defined', async () => {
623
632
  await webex.meetings.syncMeetings();
624
633
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
625
- assert.calledOnce(destroySpy);
634
+ assert.calledOnce(webex.meetings.meetingCollection.getAll);
635
+ assert.calledWith(destroySpy, meetingCollectionMeetings.noLongerValidLocusMeeting);
636
+ assert.calledWith(destroySpy, meetingCollectionMeetings.otherNonLocusMeeting1);
637
+ assert.calledWith(destroySpy, meetingCollectionMeetings.otherNonLocusMeeting2);
638
+ assert.callCount(destroySpy, 3);
639
+
640
+ assert.callCount(MeetingUtil.cleanUp, 3);
641
+ });
642
+
643
+ it('destroy any meeting that has no active locus url if keepOnlyLocusMeetings === true', async () => {
644
+ await webex.meetings.syncMeetings({keepOnlyLocusMeetings: true});
645
+ assert.calledOnce(webex.meetings.request.getActiveMeetings);
646
+ assert.calledOnce(webex.meetings.meetingCollection.getAll);
647
+ assert.calledWith(destroySpy, meetingCollectionMeetings.noLongerValidLocusMeeting);
648
+ assert.calledWith(destroySpy, meetingCollectionMeetings.otherNonLocusMeeting1);
649
+ assert.calledWith(destroySpy, meetingCollectionMeetings.otherNonLocusMeeting2);
650
+ assert.callCount(destroySpy, 3);
651
+
652
+ assert.callCount(MeetingUtil.cleanUp, 3);
653
+ });
654
+
655
+ it('destroy any LOCUS meetings that have no active locus url if keepOnlyLocusMeetings === false', async () => {
656
+ await webex.meetings.syncMeetings({keepOnlyLocusMeetings: false});
657
+ assert.calledOnce(webex.meetings.request.getActiveMeetings);
658
+ assert.calledOnce(webex.meetings.meetingCollection.getAll);
659
+ assert.calledWith(destroySpy, meetingCollectionMeetings.noLongerValidLocusMeeting);
660
+ assert.callCount(destroySpy, 1);
626
661
 
627
662
  assert.calledOnce(MeetingUtil.cleanUp);
628
663
  });
@@ -662,28 +697,139 @@ describe('plugin-meetings', () => {
662
697
  });
663
698
  });
664
699
 
665
- it('calls createMeeting and returns its promise', async () => {
666
- const FAKE_USE_RANDOM_DELAY = true;
667
- const correlationId = 'my-correlationId';
668
- const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId);
700
+ const FAKE_USE_RANDOM_DELAY = true;
701
+ const correlationId = 'my-correlationId';
702
+ const callStateForMetrics = {
703
+ correlationId: 'my-correlationId2',
704
+ joinTrigger: 'my-join-trigger',
705
+ loginType: 'my-login-type',
706
+ };
707
+
708
+ it('should call setCallStateForMetrics on any pre-existing meeting', async () => {
709
+ const fakeMeeting = {setCallStateForMetrics: sinon.mock()};
710
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns(fakeMeeting);
711
+ await webex.meetings.create(
712
+ test1,
713
+ test2,
714
+ FAKE_USE_RANDOM_DELAY,
715
+ {},
716
+ correlationId,
717
+ true,
718
+ callStateForMetrics
719
+ );
720
+ assert.calledOnceWithExactly(fakeMeeting.setCallStateForMetrics, {
721
+ ...callStateForMetrics,
722
+ correlationId,
723
+ });
724
+ });
725
+
726
+ const checkCallCreateMeeting = async (createParameters, createMeetingParameters) => {
727
+ const create = webex.meetings.create(...createParameters);
669
728
 
670
729
  assert.exists(create.then);
671
730
  await create;
672
731
  assert.calledOnce(webex.meetings.createMeeting);
673
- assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId);
732
+ assert.calledWith(webex.meetings.createMeeting, ...createMeetingParameters);
733
+ };
734
+
735
+ it('calls createMeeting and returns its promise', async () => {
736
+ await checkCallCreateMeeting(
737
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, true],
738
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, {correlationId}, true]
739
+ );
740
+ });
741
+
742
+ it('calls createMeeting, pass the meeting info param and returns its promise', async () => {
743
+ const meetingInfo = {};
744
+ await checkCallCreateMeeting(
745
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, true, undefined, meetingInfo],
746
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, {correlationId}, true, meetingInfo]
747
+ );
748
+ });
749
+
750
+ it('calls createMeeting, pass the meeting info and meetingLookupURL param and returns its promise', async () => {
751
+ const meetingInfo = {};
752
+ await checkCallCreateMeeting(
753
+ [
754
+ test1,
755
+ test2,
756
+ FAKE_USE_RANDOM_DELAY,
757
+ {},
758
+ correlationId,
759
+ true,
760
+ undefined,
761
+ meetingInfo,
762
+ 'meetingLookupURL',
763
+ ],
764
+ [
765
+ test1,
766
+ test2,
767
+ FAKE_USE_RANDOM_DELAY,
768
+ {},
769
+ {correlationId},
770
+ true,
771
+ meetingInfo,
772
+ 'meetingLookupURL',
773
+ ]
774
+ );
775
+ });
776
+
777
+ it('calls createMeeting when failOnMissingMeetinginfo is undefined and returns its promise', async () => {
778
+ await checkCallCreateMeeting(
779
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, undefined],
780
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, {correlationId}, false]
781
+ );
782
+ });
783
+
784
+ it('calls createMeeting when failOnMissingMeetinginfo is false and returns its promise', async () => {
785
+ await checkCallCreateMeeting(
786
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, false],
787
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, {correlationId}, false]
788
+ );
789
+ });
790
+
791
+ it('calls createMeeting with callStateForMetrics and returns its promise', async () => {
792
+ await checkCallCreateMeeting(
793
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, undefined, true, callStateForMetrics],
794
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, callStateForMetrics, true]
795
+ );
796
+ });
797
+
798
+ it('calls createMeeting with callStateForMetrics overwritten with correlationId and returns its promise', async () => {
799
+ await checkCallCreateMeeting(
800
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, true, callStateForMetrics],
801
+ [test1, test2, FAKE_USE_RANDOM_DELAY, {}, {...callStateForMetrics, correlationId}, true]
802
+ );
674
803
  });
675
804
 
676
805
  it('calls createMeeting with extra info params and returns its promise', async () => {
677
806
  const FAKE_USE_RANDOM_DELAY = false;
678
807
  const correlationId = 'my-correlationId';
679
808
 
680
- const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
681
- const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
809
+ const FAKE_INFO_EXTRA_PARAMS = {
810
+ mtid: 'm9fe0afd8c435e892afcce9ea25b97046',
811
+ joinTXId: 'TSmrX61wNF',
812
+ };
813
+ const create = webex.meetings.create(
814
+ test1,
815
+ test2,
816
+ FAKE_USE_RANDOM_DELAY,
817
+ FAKE_INFO_EXTRA_PARAMS,
818
+ correlationId
819
+ );
682
820
 
683
821
  assert.exists(create.then);
684
822
  await create;
685
823
  assert.calledOnce(webex.meetings.createMeeting);
686
- assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
824
+ assert.calledWith(
825
+ webex.meetings.createMeeting,
826
+ test1,
827
+ test2,
828
+ FAKE_USE_RANDOM_DELAY,
829
+ FAKE_INFO_EXTRA_PARAMS,
830
+ {correlationId},
831
+ false
832
+ );
687
833
  });
688
834
 
689
835
  it('creates a new meeting when a scheduled meeting exists in the conversation', async () => {
@@ -779,7 +925,6 @@ describe('plugin-meetings', () => {
779
925
  });
780
926
  describe('#handleLocusEvent', () => {
781
927
  describe('there was a meeting', () => {
782
-
783
928
  beforeEach(() => {
784
929
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
785
930
  locusInfo,
@@ -845,7 +990,7 @@ describe('plugin-meetings', () => {
845
990
  },
846
991
  },
847
992
  info: {
848
- webExMeetingId
993
+ webExMeetingId,
849
994
  },
850
995
  },
851
996
  eventType: 'locus.difference',
@@ -853,7 +998,11 @@ describe('plugin-meetings', () => {
853
998
  });
854
999
  assert.callCount(webex.meetings.meetingCollection.getByKey, 6);
855
1000
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
856
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
1001
+ assert.calledWith(
1002
+ webex.meetings.meetingCollection.getByKey,
1003
+ 'meetingNumber',
1004
+ webExMeetingId
1005
+ );
857
1006
  assert.calledOnce(initialSetup);
858
1007
  assert.calledWith(initialSetup, {
859
1008
  id: uuid1,
@@ -868,7 +1017,7 @@ describe('plugin-meetings', () => {
868
1017
  },
869
1018
  },
870
1019
  info: {
871
- webExMeetingId
1020
+ webExMeetingId,
872
1021
  },
873
1022
  });
874
1023
  });
@@ -882,7 +1031,7 @@ describe('plugin-meetings', () => {
882
1031
  },
883
1032
  },
884
1033
  info: {
885
- webExMeetingId
1034
+ webExMeetingId,
886
1035
  },
887
1036
  },
888
1037
  eventType: 'locus.difference',
@@ -890,7 +1039,11 @@ describe('plugin-meetings', () => {
890
1039
  });
891
1040
  assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
892
1041
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
893
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
1042
+ assert.calledWith(
1043
+ webex.meetings.meetingCollection.getByKey,
1044
+ 'meetingNumber',
1045
+ webExMeetingId
1046
+ );
894
1047
  assert.calledOnce(initialSetup);
895
1048
  assert.calledWith(initialSetup, {
896
1049
  id: uuid1,
@@ -900,7 +1053,7 @@ describe('plugin-meetings', () => {
900
1053
  },
901
1054
  },
902
1055
  info: {
903
- webExMeetingId
1056
+ webExMeetingId,
904
1057
  },
905
1058
  });
906
1059
  });
@@ -947,7 +1100,7 @@ describe('plugin-meetings', () => {
947
1100
  },
948
1101
  },
949
1102
  info: {
950
- webExMeetingId
1103
+ webExMeetingId,
951
1104
  },
952
1105
  },
953
1106
  eventType: test1,
@@ -955,7 +1108,11 @@ describe('plugin-meetings', () => {
955
1108
  });
956
1109
  assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
957
1110
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
958
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
1111
+ assert.calledWith(
1112
+ webex.meetings.meetingCollection.getByKey,
1113
+ 'meetingNumber',
1114
+ webExMeetingId
1115
+ );
959
1116
  assert.calledOnce(initialSetup);
960
1117
  assert.calledWith(initialSetup, {
961
1118
  id: uuid1,
@@ -965,7 +1122,7 @@ describe('plugin-meetings', () => {
965
1122
  },
966
1123
  },
967
1124
  info: {
968
- webExMeetingId
1125
+ webExMeetingId,
969
1126
  },
970
1127
  });
971
1128
  });
@@ -1037,7 +1194,10 @@ describe('plugin-meetings', () => {
1037
1194
  });
1038
1195
  describe('successful MeetingInfo.#fetchMeetingInfo', () => {
1039
1196
  let clock, setTimeoutSpy, fakeMeetingStartTimeString, FAKE_TIME_TO_START;
1040
- const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
1197
+ const FAKE_INFO_EXTRA_PARAMS = {
1198
+ mtid: 'm9fe0afd8c435e892afcce9ea25b97046',
1199
+ joinTXId: 'TSmrX61wNF',
1200
+ };
1041
1201
 
1042
1202
  beforeEach(() => {
1043
1203
  clock = sinon.useFakeTimers();
@@ -1068,13 +1228,36 @@ describe('plugin-meetings', () => {
1068
1228
  destination,
1069
1229
  type,
1070
1230
  extraParams = {},
1071
- expectedMeetingData = {}
1231
+ expectedMeetingData = {},
1232
+ sendCAevents = false,
1233
+ injectMeetingInfo = false
1072
1234
  ) => {
1073
- assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1235
+ if (injectMeetingInfo) {
1236
+ assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
1237
+ } else {
1238
+ assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1239
+ }
1240
+
1074
1241
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1075
1242
  assert.notCalled(setTimeoutSpy);
1076
1243
  assert.callCount(TriggerProxy.trigger, 5);
1077
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type, null, null, undefined, undefined, extraParams, {meetingId: meeting.id});
1244
+
1245
+ if (injectMeetingInfo) {
1246
+ assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
1247
+ } else {
1248
+ assert.calledWith(
1249
+ webex.meetings.meetingInfo.fetchMeetingInfo,
1250
+ destination,
1251
+ type,
1252
+ null,
1253
+ null,
1254
+ undefined,
1255
+ undefined,
1256
+ extraParams,
1257
+ {meetingId: meeting.id, sendCAevents}
1258
+ );
1259
+ }
1260
+
1078
1261
  assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1079
1262
 
1080
1263
  if (expectedMeetingData.permissionToken) {
@@ -1083,9 +1266,21 @@ describe('plugin-meetings', () => {
1083
1266
  if (expectedMeetingData.meetingJoinUrl) {
1084
1267
  assert.equal(meeting.meetingJoinUrl, expectedMeetingData.meetingJoinUrl);
1085
1268
  }
1086
- if(expectedMeetingData.correlationId) {
1269
+ if (expectedMeetingData.correlationId) {
1087
1270
  assert.equal(meeting.correlationId, expectedMeetingData.correlationId);
1088
1271
  }
1272
+ if (expectedMeetingData.callStateForMetrics) {
1273
+ assert.deepEqual(
1274
+ meeting.callStateForMetrics,
1275
+ expectedMeetingData.callStateForMetrics
1276
+ );
1277
+ }
1278
+ if (expectedMeetingData.meetingLookupUrl) {
1279
+ assert.equal(
1280
+ meeting.meetingInfo.meetingLookupUrl,
1281
+ expectedMeetingData.meetingLookupUrl
1282
+ );
1283
+ }
1089
1284
  assert.equal(meeting.destination, destination);
1090
1285
  assert.equal(meeting.destinationType, type);
1091
1286
  assert.calledWith(
@@ -1118,14 +1313,93 @@ describe('plugin-meetings', () => {
1118
1313
  correlationId: meeting.id,
1119
1314
  };
1120
1315
 
1121
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
1316
+ checkCreateWithoutDelay(
1317
+ meeting,
1318
+ 'test destination',
1319
+ 'test type',
1320
+ {},
1321
+ expectedMeetingData
1322
+ );
1323
+ });
1324
+
1325
+ it('accepts injected meeting info', async () => {
1326
+ const meetingInfo = {
1327
+ permissionToken: 'PT',
1328
+ meetingJoinUrl: 'meetingJoinUrl',
1329
+ };
1330
+
1331
+ const meeting = await webex.meetings.createMeeting(
1332
+ 'test destination',
1333
+ 'test type',
1334
+ false,
1335
+ {},
1336
+ undefined,
1337
+ false,
1338
+ meetingInfo
1339
+ );
1340
+
1341
+ const expectedMeetingData = {
1342
+ ...meetingInfo,
1343
+ correlationId: meeting.id,
1344
+ };
1345
+
1346
+ checkCreateWithoutDelay(
1347
+ meeting,
1348
+ 'test destination',
1349
+ 'test type',
1350
+ {},
1351
+ expectedMeetingData,
1352
+ false,
1353
+ true
1354
+ );
1355
+ });
1356
+
1357
+ it('accepts injected meeting info with meeting lookup url', async () => {
1358
+ const meetingInfo = {
1359
+ permissionToken: 'PT',
1360
+ meetingJoinUrl: 'meetingJoinUrl',
1361
+ };
1362
+
1363
+ const meeting = await webex.meetings.createMeeting(
1364
+ 'test destination',
1365
+ 'test type',
1366
+ false,
1367
+ {},
1368
+ undefined,
1369
+ false,
1370
+ meetingInfo,
1371
+ 'meetingLookupUrl'
1372
+ );
1373
+
1374
+ const expectedMeetingData = {
1375
+ ...meetingInfo,
1376
+ meetingLookupUrl: 'meetingLookupUrl',
1377
+ correlationId: meeting.id,
1378
+ };
1379
+
1380
+ checkCreateWithoutDelay(
1381
+ meeting,
1382
+ 'test destination',
1383
+ 'test type',
1384
+ {},
1385
+ expectedMeetingData,
1386
+ false,
1387
+ true
1388
+ );
1122
1389
  });
1123
1390
 
1124
1391
  [undefined, FAKE_INFO_EXTRA_PARAMS].forEach((infoExtraParams) => {
1125
1392
  const infoExtraParamsProvided = infoExtraParams !== undefined;
1126
1393
 
1127
- it(`creates the meeting from a successful meeting info fetch meeting resolve testing${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1128
- const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, infoExtraParams);
1394
+ it(`creates the meeting from a successful meeting info fetch meeting resolve testing${
1395
+ infoExtraParamsProvided ? ' with infoExtraParams' : ''
1396
+ }`, async () => {
1397
+ const meeting = await webex.meetings.createMeeting(
1398
+ 'test destination',
1399
+ 'test type',
1400
+ false,
1401
+ infoExtraParams
1402
+ );
1129
1403
  const expectedMeetingData = {
1130
1404
  permissionToken: 'PT',
1131
1405
  meetingJoinUrl: 'meetingJoinUrl',
@@ -1136,10 +1410,18 @@ describe('plugin-meetings', () => {
1136
1410
  Meeting,
1137
1411
  'createMeeting should eventually resolve to a Meeting Object'
1138
1412
  );
1139
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', infoExtraParamsProvided ? infoExtraParams : {}, expectedMeetingData);
1413
+ checkCreateWithoutDelay(
1414
+ meeting,
1415
+ 'test destination',
1416
+ 'test type',
1417
+ infoExtraParamsProvided ? infoExtraParams : {},
1418
+ expectedMeetingData
1419
+ );
1140
1420
  });
1141
1421
 
1142
- it(`creates the meeting from a successful meeting info fetch with random delay${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1422
+ it(`creates the meeting from a successful meeting info fetch with random delay${
1423
+ infoExtraParamsProvided ? ' with infoExtraParams' : ''
1424
+ }`, async () => {
1143
1425
  const FAKE_LOCUS_MEETING = {
1144
1426
  conversationUrl: 'locusConvURL',
1145
1427
  url: 'locusUrl',
@@ -1199,6 +1481,8 @@ describe('plugin-meetings', () => {
1199
1481
 
1200
1482
  // When timer expires
1201
1483
  clock.tick(FAKE_TIME_TO_START);
1484
+ await testUtils.flushPromises();
1485
+
1202
1486
  assert.calledWith(
1203
1487
  webex.meetings.meetingInfo.fetchMeetingInfo,
1204
1488
  FAKE_LOCUS_MEETING,
@@ -1227,7 +1511,7 @@ describe('plugin-meetings', () => {
1227
1511
  'meeting:meetingInfoAvailable'
1228
1512
  );
1229
1513
  });
1230
- })
1514
+ });
1231
1515
 
1232
1516
  it('creates the meeting from a successful meeting info fetch that has no random delay because it is active', async () => {
1233
1517
  const FAKE_LOCUS_MEETING = {
@@ -1328,14 +1612,59 @@ describe('plugin-meetings', () => {
1328
1612
  });
1329
1613
 
1330
1614
  it('creates meeting with the correlationId provided', async () => {
1331
- const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, {}, 'my-correlationId');
1615
+ const meeting = await webex.meetings.createMeeting(
1616
+ 'test destination',
1617
+ 'test type',
1618
+ false,
1619
+ {},
1620
+ {correlationId: 'my-correlationId'}
1621
+ );
1332
1622
 
1333
1623
  const expectedMeetingData = {
1334
1624
  correlationId: 'my-correlationId',
1335
1625
  };
1336
1626
 
1337
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
1338
- })
1627
+ checkCreateWithoutDelay(
1628
+ meeting,
1629
+ 'test destination',
1630
+ 'test type',
1631
+ {},
1632
+ expectedMeetingData,
1633
+ true
1634
+ );
1635
+ });
1636
+
1637
+ it('creates meeting with the callStateForMetrics provided', async () => {
1638
+ const meeting = await webex.meetings.createMeeting(
1639
+ 'test destination',
1640
+ 'test type',
1641
+ false,
1642
+ {},
1643
+ {
1644
+ correlationId: 'my-correlationId',
1645
+ joinTrigger: 'my-join-trigger',
1646
+ loginType: 'my-login-type',
1647
+ }
1648
+ );
1649
+
1650
+ const expectedMeetingData = {
1651
+ correlationId: 'my-correlationId',
1652
+ callStateForMetrics: {
1653
+ correlationId: 'my-correlationId',
1654
+ joinTrigger: 'my-join-trigger',
1655
+ loginType: 'my-login-type',
1656
+ },
1657
+ };
1658
+
1659
+ checkCreateWithoutDelay(
1660
+ meeting,
1661
+ 'test destination',
1662
+ 'test type',
1663
+ {},
1664
+ expectedMeetingData,
1665
+ true
1666
+ );
1667
+ });
1339
1668
  });
1340
1669
 
1341
1670
  describe('rejected MeetingInfo.#fetchMeetingInfo', () => {
@@ -1345,37 +1674,72 @@ describe('plugin-meetings', () => {
1345
1674
  webex.meetings.meetingInfo.fetchMeetingInfo = sinon
1346
1675
  .stub()
1347
1676
  .returns(Promise.reject(new Error('test')));
1677
+ webex.meetings.destroy = sinon.stub().returns(Promise.resolve());
1678
+ webex.meetings.createMeeting = sinon.spy(webex.meetings.createMeeting);
1348
1679
  });
1349
- it('creates the meeting from a rejected meeting info fetch', async () => {
1350
- const meeting = await webex.meetings.createMeeting('test destination', 'test type');
1351
1680
 
1352
- assert.instanceOf(
1353
- meeting,
1354
- Meeting,
1355
- 'createMeeting should eventually resolve to a Meeting Object'
1356
- );
1357
- assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1358
- assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1359
- assert.calledThrice(TriggerProxy.trigger);
1360
- assert.calledWith(
1361
- webex.meetings.meetingInfo.fetchMeetingInfo,
1362
- 'test destination',
1363
- 'test type'
1364
- );
1365
- assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1366
- assert.calledWith(
1367
- TriggerProxy.trigger,
1368
- sinon.match.instanceOf(Meetings),
1369
- {
1370
- file: 'meetings',
1371
- function: 'createMeeting',
1372
- },
1373
- 'meeting:added',
1374
- {
1375
- meeting: sinon.match.instanceOf(Meeting),
1376
- type: 'test meeting added type',
1681
+ const checkCreateMeetingWithNoMeetingInfo = async (failOnMissingMeetingInfo, destroy) => {
1682
+ try {
1683
+ const meeting = await webex.meetings.createMeeting(
1684
+ 'test destination',
1685
+ 'test type',
1686
+ undefined,
1687
+ undefined,
1688
+ undefined,
1689
+ failOnMissingMeetingInfo
1690
+ );
1691
+
1692
+ assert.instanceOf(
1693
+ meeting,
1694
+ Meeting,
1695
+ 'createMeeting should eventually resolve to a Meeting Object'
1696
+ );
1697
+ assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1698
+ assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1699
+ assert.calledThrice(TriggerProxy.trigger);
1700
+ assert.calledWith(
1701
+ webex.meetings.meetingInfo.fetchMeetingInfo,
1702
+ 'test destination',
1703
+ 'test type'
1704
+ );
1705
+
1706
+ if (destroy) {
1707
+ assert.calledWith(
1708
+ webex.meetings.destroy,
1709
+ sinon.match.instanceOf(Meeting),
1710
+ 'MISSING_MEETING_INFO'
1711
+ );
1712
+ assert.notCalled(MeetingsUtil.getMeetingAddedType);
1713
+ assert.notCalled(TriggerProxy.trigger);
1714
+ assert.throw(webex.meetings.createMeeting, 'meeting information not found');
1715
+ } else {
1716
+ assert.notCalled(webex.meetings.destroy);
1717
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1718
+ assert.calledWith(
1719
+ TriggerProxy.trigger,
1720
+ sinon.match.instanceOf(Meetings),
1721
+ {
1722
+ file: 'meetings',
1723
+ function: 'createMeeting',
1724
+ },
1725
+ 'meeting:added',
1726
+ {
1727
+ meeting: sinon.match.instanceOf(Meeting),
1728
+ type: 'test meeting added type',
1729
+ }
1730
+ );
1377
1731
  }
1378
- );
1732
+ } catch (err) {
1733
+ assert.instanceOf(err, NoMeetingInfoError);
1734
+ }
1735
+ };
1736
+
1737
+ it('creates the meeting from a rejected meeting info fetch', async () => {
1738
+ checkCreateMeetingWithNoMeetingInfo(false, false);
1739
+ });
1740
+
1741
+ it('creates the meeting from a rejected meeting info fetch and destroys it if failOnMissingMeetingInfo', async () => {
1742
+ checkCreateMeetingWithNoMeetingInfo(true, true);
1379
1743
  });
1380
1744
  });
1381
1745
 
@@ -1513,7 +1877,6 @@ describe('plugin-meetings', () => {
1513
1877
  });
1514
1878
 
1515
1879
  describe('#fetchUserPreferredWebexSite', () => {
1516
-
1517
1880
  let loggerProxySpy;
1518
1881
 
1519
1882
  it('should call request.getMeetingPreferences to get the preferred webex site ', async () => {
@@ -1531,12 +1894,10 @@ describe('plugin-meetings', () => {
1531
1894
  getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
1532
1895
  },
1533
1896
  user: {
1534
- get: sinon.stub().returns(
1535
- Promise.resolve(user)
1536
- ),
1897
+ get: sinon.stub().returns(Promise.resolve(user)),
1537
1898
  },
1538
1899
  });
1539
- }
1900
+ };
1540
1901
 
1541
1902
  it('should not fail if UserPreferred info is not fetched ', async () => {
1542
1903
  setup();
@@ -1573,24 +1934,27 @@ describe('plugin-meetings', () => {
1573
1934
  assert.notCalled(loggerProxySpy);
1574
1935
  });
1575
1936
 
1576
- forEach([
1577
- {user: undefined},
1578
- {user: {userPreferences: {}}},
1579
- {user: {userPreferences: {userPreferencesItems: {}}}},
1580
- {user: {userPreferences: {userPreferencesItems: {preferredWebExSite: undefined}}}},
1581
- ], ({user}) => {
1582
- it(`should handle invalid user data ${user}`, async () => {
1583
- setup({user});
1584
-
1585
- await webex.meetings.fetchUserPreferredWebexSite();
1586
-
1587
- assert.equal(webex.meetings.preferredWebexSite, '');
1588
- assert.calledOnceWithExactly(
1589
- loggerProxySpy,
1590
- 'Failed to fetch preferred site from user - no site will be set'
1591
- );
1592
- });
1593
- });
1937
+ forEach(
1938
+ [
1939
+ {user: undefined},
1940
+ {user: {userPreferences: {}}},
1941
+ {user: {userPreferences: {userPreferencesItems: {}}}},
1942
+ {user: {userPreferences: {userPreferencesItems: {preferredWebExSite: undefined}}}},
1943
+ ],
1944
+ ({user}) => {
1945
+ it(`should handle invalid user data ${user}`, async () => {
1946
+ setup({user});
1947
+
1948
+ await webex.meetings.fetchUserPreferredWebexSite();
1949
+
1950
+ assert.equal(webex.meetings.preferredWebexSite, '');
1951
+ assert.calledOnceWithExactly(
1952
+ loggerProxySpy,
1953
+ 'Failed to fetch preferred site from user - no site will be set'
1954
+ );
1955
+ });
1956
+ }
1957
+ );
1594
1958
 
1595
1959
  it('should handle a get user failure', async () => {
1596
1960
  setup();
@@ -1605,7 +1969,6 @@ describe('plugin-meetings', () => {
1605
1969
  'Failed to fetch preferred site from user - no site will be set'
1606
1970
  );
1607
1971
  });
1608
-
1609
1972
  });
1610
1973
  });
1611
1974
 
@@ -1701,7 +2064,7 @@ describe('plugin-meetings', () => {
1701
2064
  newLocus = {
1702
2065
  controls: {},
1703
2066
  self: {},
1704
- }
2067
+ };
1705
2068
  });
1706
2069
  afterEach(() => {
1707
2070
  sinon.restore();
@@ -1732,16 +2095,24 @@ describe('plugin-meetings', () => {
1732
2095
  });
1733
2096
 
1734
2097
  it('if newLocus replaceAt time is expired, then return false', () => {
1735
- sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({joinedWith: {replaces: [{
1736
- replaceAt: '2023-03-27T02:17:02.506Z',
1737
- }]}});
2098
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({
2099
+ joinedWith: {
2100
+ replaces: [
2101
+ {
2102
+ replaceAt: '2023-03-27T02:17:02.506Z',
2103
+ },
2104
+ ],
2105
+ },
2106
+ });
1738
2107
  newLocus.self.state = 'JOINED';
1739
2108
  sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(true);
1740
2109
  sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1741
- replaces: [{
1742
- replaceAt: '2023-03-27T02:17:01.506Z'
1743
- }]
1744
- })
2110
+ replaces: [
2111
+ {
2112
+ replaceAt: '2023-03-27T02:17:01.506Z',
2113
+ },
2114
+ ],
2115
+ });
1745
2116
 
1746
2117
  LoggerProxy.logger.log = sinon.stub();
1747
2118
  const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
@@ -1830,7 +2201,7 @@ describe('plugin-meetings', () => {
1830
2201
  newLocus = {
1831
2202
  controls: {},
1832
2203
  self: {},
1833
- }
2204
+ };
1834
2205
  });
1835
2206
  afterEach(() => {
1836
2207
  sinon.restore();
@@ -1896,13 +2267,13 @@ describe('plugin-meetings', () => {
1896
2267
  self: {
1897
2268
  callbackInfo: {
1898
2269
  callbackAddress: 'address1',
1899
- }
2270
+ },
1900
2271
  },
1901
2272
  info: {
1902
2273
  webExMeetingId: '123456',
1903
2274
  isUnifiedSpaceMeeting: false,
1904
2275
  },
1905
- conversationUrl: 'conversationUrl1'
2276
+ conversationUrl: 'conversationUrl1',
1906
2277
  };
1907
2278
 
1908
2279
  sinon.stub(MeetingsUtil, 'checkForCorrelationId').returns('correlationId1');
@@ -1916,9 +2287,17 @@ describe('plugin-meetings', () => {
1916
2287
  assert.isNull(result);
1917
2288
  assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1918
2289
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1919
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
2290
+ assert.calledWith(
2291
+ webex.meetings.meetingCollection.getByKey,
2292
+ 'correlationId',
2293
+ 'correlationId1'
2294
+ );
1920
2295
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1921
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
2296
+ assert.calledWith(
2297
+ webex.meetings.meetingCollection.getByKey,
2298
+ 'conversationUrl',
2299
+ 'conversationUrl1'
2300
+ );
1922
2301
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1923
2302
  });
1924
2303
 
@@ -1928,7 +2307,7 @@ describe('plugin-meetings', () => {
1928
2307
  const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1929
2308
  assert.isNull(result);
1930
2309
  assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1931
- })
2310
+ });
1932
2311
 
1933
2312
  it('check the calls when meeting found by key: locusUrl', () => {
1934
2313
  mockGetByKey('locusUrl');
@@ -1944,7 +2323,11 @@ describe('plugin-meetings', () => {
1944
2323
  assert.deepEqual(result, mockReturnMeeting);
1945
2324
  assert.callCount(webex.meetings.meetingCollection.getByKey, 2);
1946
2325
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1947
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
2326
+ assert.calledWith(
2327
+ webex.meetings.meetingCollection.getByKey,
2328
+ 'correlationId',
2329
+ 'correlationId1'
2330
+ );
1948
2331
  });
1949
2332
 
1950
2333
  it('check the calls when meeting found by key: sipUri', () => {
@@ -1953,7 +2336,11 @@ describe('plugin-meetings', () => {
1953
2336
  assert.deepEqual(result, mockReturnMeeting);
1954
2337
  assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
1955
2338
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1956
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
2339
+ assert.calledWith(
2340
+ webex.meetings.meetingCollection.getByKey,
2341
+ 'correlationId',
2342
+ 'correlationId1'
2343
+ );
1957
2344
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1958
2345
  });
1959
2346
 
@@ -1963,9 +2350,17 @@ describe('plugin-meetings', () => {
1963
2350
  assert.deepEqual(result, mockReturnMeeting);
1964
2351
  assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1965
2352
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1966
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
2353
+ assert.calledWith(
2354
+ webex.meetings.meetingCollection.getByKey,
2355
+ 'correlationId',
2356
+ 'correlationId1'
2357
+ );
1967
2358
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1968
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
2359
+ assert.calledWith(
2360
+ webex.meetings.meetingCollection.getByKey,
2361
+ 'conversationUrl',
2362
+ 'conversationUrl1'
2363
+ );
1969
2364
  });
1970
2365
 
1971
2366
  it('check the calls when meeting found by key: meetingNumber', () => {
@@ -1974,9 +2369,17 @@ describe('plugin-meetings', () => {
1974
2369
  assert.deepEqual(result, mockReturnMeeting);
1975
2370
  assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1976
2371
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1977
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
2372
+ assert.calledWith(
2373
+ webex.meetings.meetingCollection.getByKey,
2374
+ 'correlationId',
2375
+ 'correlationId1'
2376
+ );
1978
2377
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1979
- assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
2378
+ assert.calledWith(
2379
+ webex.meetings.meetingCollection.getByKey,
2380
+ 'conversationUrl',
2381
+ 'conversationUrl1'
2382
+ );
1980
2383
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1981
2384
  });
1982
2385
  });
@@ -1991,18 +2394,18 @@ describe('plugin-meetings', () => {
1991
2394
  controls: {
1992
2395
  breakout: {
1993
2396
  sessionType: 'MAIN',
1994
- url: 'breakoutUnifiedUrl1'
1995
- }
1996
- }
2397
+ url: 'breakoutUnifiedUrl1',
2398
+ },
2399
+ },
1997
2400
  };
1998
2401
  breakoutLocus = {
1999
2402
  url: 'breakoutUrl1',
2000
2403
  controls: {
2001
2404
  breakout: {
2002
2405
  sessionType: 'BREAKOUT',
2003
- url: 'breakoutUnifiedUrl1'
2004
- }
2005
- }
2406
+ url: 'breakoutUnifiedUrl1',
2407
+ },
2408
+ },
2006
2409
  };
2007
2410
  lociArray = [mainLocus, breakoutLocus];
2008
2411
 
@@ -2045,8 +2448,8 @@ describe('plugin-meetings', () => {
2045
2448
  breakout: {
2046
2449
  sessionType: 'BREAKOUT',
2047
2450
  url: 'breakoutUnifiedUrl1',
2048
- }
2049
- }
2451
+ },
2452
+ },
2050
2453
  };
2051
2454
 
2052
2455
  webex.meetings.handleLocusEvent = sinon.stub();
@@ -2076,8 +2479,8 @@ describe('plugin-meetings', () => {
2076
2479
  breakout: {
2077
2480
  sessionType: 'MAIN',
2078
2481
  url: 'breakoutUnifiedUrl2',
2079
- }
2080
- }
2482
+ },
2483
+ },
2081
2484
  });
2082
2485
  assert.notCalled(webex.meetings.handleLocusEvent);
2083
2486
  });
@@ -2089,10 +2492,13 @@ describe('plugin-meetings', () => {
2089
2492
  breakout: {
2090
2493
  sessionType: 'MAIN',
2091
2494
  url: 'breakoutUnifiedUrl1',
2092
- }
2093
- }
2495
+ },
2496
+ },
2497
+ });
2498
+ assert.calledWith(webex.meetings.handleLocusEvent, {
2499
+ locus: breakoutLocus,
2500
+ locusUrl: breakoutLocus.url,
2094
2501
  });
2095
- assert.calledWith(webex.meetings.handleLocusEvent, {locus: breakoutLocus, locusUrl: breakoutLocus.url});
2096
2502
  });
2097
2503
  });
2098
2504
 
@@ -2116,17 +2522,16 @@ describe('plugin-meetings', () => {
2116
2522
  meeting.locusId = 'locus id';
2117
2523
  meeting.correlationId = 'correlation id';
2118
2524
  meeting.locusInfo = {
2119
- fullState: { lastActive: 'last active'},
2120
- info: { webExMeetingId: 'meeting id'}
2121
- }
2525
+ fullState: {lastActive: 'last active', sessionId: 'locus session id'},
2526
+ info: {webExMeetingId: 'meeting id'},
2527
+ };
2122
2528
  });
2123
2529
 
2124
2530
  afterEach(() => {
2125
2531
  sinon.restore();
2126
- })
2532
+ });
2127
2533
 
2128
2534
  it('sends metrics on success', async () => {
2129
-
2130
2535
  await meeting.uploadLogs();
2131
2536
 
2132
2537
  await testUtils.flushPromises();
@@ -2137,6 +2542,8 @@ describe('plugin-meetings', () => {
2137
2542
  feedbackId: 'correlation id',
2138
2543
  locusId: 'locus id',
2139
2544
  meetingId: 'meeting id',
2545
+ autoupload: true,
2546
+ locussessionid: 'locus session id',
2140
2547
  });
2141
2548
  });
2142
2549
 
@@ -2147,14 +2554,20 @@ describe('plugin-meetings', () => {
2147
2554
 
2148
2555
  await testUtils.flushPromises();
2149
2556
 
2150
- assert.calledOnceWithExactly(metricsSpy, 'js_sdk_upload_logs_failure', sinon.match({
2151
- callStart: 'last active',
2152
- correlationId: 'correlation id',
2153
- feedbackId: 'correlation id',
2154
- locusId: 'locus id',
2155
- meetingId: 'meeting id',
2156
- reason: 'fake error',
2157
- }));
2557
+ assert.calledOnceWithExactly(
2558
+ metricsSpy,
2559
+ 'js_sdk_upload_logs_failure',
2560
+ sinon.match({
2561
+ callStart: 'last active',
2562
+ correlationId: 'correlation id',
2563
+ feedbackId: 'correlation id',
2564
+ locusId: 'locus id',
2565
+ meetingId: 'meeting id',
2566
+ reason: 'fake error',
2567
+ autoupload: true,
2568
+ locussessionid: 'locus session id',
2569
+ })
2570
+ );
2158
2571
  });
2159
2572
  });
2160
2573
  });