@webex/plugin-meetings 3.0.0-bnr.4 → 3.0.0-stream-classes.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 (303) hide show
  1. package/README.md +46 -8
  2. package/dist/annotation/annotation.types.js +7 -0
  3. package/dist/annotation/annotation.types.js.map +1 -0
  4. package/dist/annotation/constants.js +49 -0
  5. package/dist/annotation/constants.js.map +1 -0
  6. package/dist/annotation/index.js +342 -0
  7. package/dist/annotation/index.js.map +1 -0
  8. package/dist/breakouts/breakout.js +70 -32
  9. package/dist/breakouts/breakout.js.map +1 -1
  10. package/dist/breakouts/events.js +45 -0
  11. package/dist/breakouts/events.js.map +1 -0
  12. package/dist/breakouts/index.js +422 -217
  13. package/dist/breakouts/index.js.map +1 -1
  14. package/dist/breakouts/utils.js +12 -1
  15. package/dist/breakouts/utils.js.map +1 -1
  16. package/dist/common/errors/webex-errors.js +3 -2
  17. package/dist/common/errors/webex-errors.js.map +1 -1
  18. package/dist/common/logs/logger-proxy.js +1 -1
  19. package/dist/common/logs/logger-proxy.js.map +1 -1
  20. package/dist/common/logs/request.d.ts +1 -1
  21. package/dist/common/queue.js +24 -9
  22. package/dist/common/queue.js.map +1 -1
  23. package/dist/config.js +1 -7
  24. package/dist/config.js.map +1 -1
  25. package/dist/constants.js +118 -24
  26. package/dist/constants.js.map +1 -1
  27. package/dist/controls-options-manager/enums.js +2 -0
  28. package/dist/controls-options-manager/enums.js.map +1 -1
  29. package/dist/controls-options-manager/index.js +19 -14
  30. package/dist/controls-options-manager/index.js.map +1 -1
  31. package/dist/controls-options-manager/types.js.map +1 -1
  32. package/dist/controls-options-manager/util.js +80 -11
  33. package/dist/controls-options-manager/util.js.map +1 -1
  34. package/dist/index.js +62 -20
  35. package/dist/index.js.map +1 -1
  36. package/dist/interpretation/collection.js +23 -0
  37. package/dist/interpretation/collection.js.map +1 -0
  38. package/dist/interpretation/index.js +366 -0
  39. package/dist/interpretation/index.js.map +1 -0
  40. package/dist/interpretation/siLanguage.js +25 -0
  41. package/dist/interpretation/siLanguage.js.map +1 -0
  42. package/dist/locus-info/controlsUtils.js +71 -1
  43. package/dist/locus-info/controlsUtils.js.map +1 -1
  44. package/dist/locus-info/index.js +305 -57
  45. package/dist/locus-info/index.js.map +1 -1
  46. package/dist/locus-info/infoUtils.js +7 -1
  47. package/dist/locus-info/infoUtils.js.map +1 -1
  48. package/dist/locus-info/mediaSharesUtils.js +43 -1
  49. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  50. package/dist/locus-info/parser.js +219 -63
  51. package/dist/locus-info/parser.js.map +1 -1
  52. package/dist/locus-info/selfUtils.js +44 -22
  53. package/dist/locus-info/selfUtils.js.map +1 -1
  54. package/dist/media/index.js +57 -104
  55. package/dist/media/index.js.map +1 -1
  56. package/dist/media/properties.js +60 -121
  57. package/dist/media/properties.js.map +1 -1
  58. package/dist/meeting/in-meeting-actions.js +61 -3
  59. package/dist/meeting/in-meeting-actions.js.map +1 -1
  60. package/dist/meeting/index.js +2530 -2534
  61. package/dist/meeting/index.js.map +1 -1
  62. package/dist/meeting/locusMediaRequest.js +292 -0
  63. package/dist/meeting/locusMediaRequest.js.map +1 -0
  64. package/dist/meeting/muteState.js +125 -205
  65. package/dist/meeting/muteState.js.map +1 -1
  66. package/dist/meeting/request.js +150 -150
  67. package/dist/meeting/request.js.map +1 -1
  68. package/dist/meeting/util.js +568 -438
  69. package/dist/meeting/util.js.map +1 -1
  70. package/dist/meeting-info/index.js +48 -7
  71. package/dist/meeting-info/index.js.map +1 -1
  72. package/dist/meeting-info/meeting-info-v2.js +94 -38
  73. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  74. package/dist/meeting-info/utilv2.js +4 -2
  75. package/dist/meeting-info/utilv2.js.map +1 -1
  76. package/dist/meetings/index.d.ts +0 -2
  77. package/dist/meetings/index.js +260 -85
  78. package/dist/meetings/index.js.map +1 -1
  79. package/dist/meetings/meetings.types.js +7 -0
  80. package/dist/meetings/meetings.types.js.map +1 -0
  81. package/dist/meetings/util.js +42 -7
  82. package/dist/meetings/util.js.map +1 -1
  83. package/dist/member/index.d.ts +2 -0
  84. package/dist/member/index.js +26 -0
  85. package/dist/member/index.js.map +1 -1
  86. package/dist/member/member.types.d.ts +11 -0
  87. package/dist/member/member.types.js +18 -0
  88. package/dist/member/member.types.js.map +1 -0
  89. package/dist/member/types.js +11 -1
  90. package/dist/member/types.js.map +1 -1
  91. package/dist/member/util.js +60 -23
  92. package/dist/member/util.js.map +1 -1
  93. package/dist/members/index.js +4 -1
  94. package/dist/members/index.js.map +1 -1
  95. package/dist/members/request.js +75 -45
  96. package/dist/members/request.js.map +1 -1
  97. package/dist/members/util.js +308 -317
  98. package/dist/members/util.js.map +1 -1
  99. package/dist/metrics/config.js +1 -3
  100. package/dist/metrics/config.js.map +1 -1
  101. package/dist/metrics/constants.js +1 -0
  102. package/dist/metrics/constants.js.map +1 -1
  103. package/dist/metrics/index.d.ts +1 -1
  104. package/dist/metrics/index.js +1 -451
  105. package/dist/metrics/index.js.map +1 -1
  106. package/dist/multistream/mediaRequestManager.js +136 -40
  107. package/dist/multistream/mediaRequestManager.js.map +1 -1
  108. package/dist/multistream/receiveSlot.js.map +1 -1
  109. package/dist/multistream/receiveSlotManager.js +4 -4
  110. package/dist/multistream/receiveSlotManager.js.map +1 -1
  111. package/dist/multistream/remoteMedia.js.map +1 -1
  112. package/dist/multistream/remoteMediaGroup.js +60 -3
  113. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  114. package/dist/multistream/remoteMediaManager.js +36 -0
  115. package/dist/multistream/remoteMediaManager.js.map +1 -1
  116. package/dist/multistream/sendSlotManager.js +233 -0
  117. package/dist/multistream/sendSlotManager.js.map +1 -0
  118. package/dist/reachability/index.js +18 -3
  119. package/dist/reachability/index.js.map +1 -1
  120. package/dist/reachability/request.js +5 -3
  121. package/dist/reachability/request.js.map +1 -1
  122. package/dist/reconnection-manager/index.js +181 -153
  123. package/dist/reconnection-manager/index.js.map +1 -1
  124. package/dist/recording-controller/index.js +21 -2
  125. package/dist/recording-controller/index.js.map +1 -1
  126. package/dist/recording-controller/util.js +9 -8
  127. package/dist/recording-controller/util.js.map +1 -1
  128. package/dist/roap/index.js +25 -32
  129. package/dist/roap/index.js.map +1 -1
  130. package/dist/roap/request.js +42 -51
  131. package/dist/roap/request.js.map +1 -1
  132. package/dist/roap/turnDiscovery.js +97 -38
  133. package/dist/roap/turnDiscovery.js.map +1 -1
  134. package/dist/rtcMetrics/constants.js +12 -0
  135. package/dist/rtcMetrics/constants.js.map +1 -0
  136. package/dist/rtcMetrics/index.js +117 -0
  137. package/dist/rtcMetrics/index.js.map +1 -0
  138. package/dist/statsAnalyzer/index.js +0 -1
  139. package/dist/statsAnalyzer/index.js.map +1 -1
  140. package/dist/types/annotation/annotation.types.d.ts +43 -0
  141. package/dist/types/annotation/constants.d.ts +31 -0
  142. package/dist/types/annotation/index.d.ts +124 -0
  143. package/dist/types/breakouts/events.d.ts +2 -0
  144. package/dist/types/breakouts/utils.d.ts +7 -0
  145. package/dist/types/common/errors/webex-errors.d.ts +1 -1
  146. package/dist/types/config.d.ts +0 -6
  147. package/dist/types/constants.d.ts +51 -21
  148. package/dist/types/controls-options-manager/enums.d.ts +2 -0
  149. package/dist/types/controls-options-manager/index.d.ts +1 -1
  150. package/dist/types/controls-options-manager/types.d.ts +7 -1
  151. package/dist/types/index.d.ts +1 -1
  152. package/dist/types/interpretation/collection.d.ts +5 -0
  153. package/dist/types/interpretation/index.d.ts +5 -0
  154. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  155. package/dist/types/locus-info/index.d.ts +39 -1
  156. package/dist/types/media/index.d.ts +2 -0
  157. package/dist/types/media/properties.d.ts +16 -38
  158. package/dist/types/meeting/in-meeting-actions.d.ts +46 -2
  159. package/dist/types/meeting/index.d.ts +179 -379
  160. package/dist/types/meeting/locusMediaRequest.d.ts +70 -0
  161. package/dist/types/meeting/muteState.d.ts +39 -40
  162. package/dist/types/meeting/request.d.ts +25 -26
  163. package/dist/types/meeting/util.d.ts +74 -1
  164. package/dist/types/meeting-info/meeting-info-v2.d.ts +14 -3
  165. package/dist/types/meetings/index.d.ts +49 -1
  166. package/dist/types/meetings/meetings.types.d.ts +4 -0
  167. package/dist/types/member/index.d.ts +2 -0
  168. package/dist/types/members/request.d.ts +56 -11
  169. package/dist/types/members/util.d.ts +209 -1
  170. package/dist/types/metrics/config.d.ts +26 -2
  171. package/dist/types/metrics/constants.d.ts +1 -0
  172. package/dist/types/metrics/index.d.ts +17 -0
  173. package/dist/types/multistream/mediaRequestManager.d.ts +27 -10
  174. package/dist/types/multistream/receiveSlot.d.ts +3 -3
  175. package/dist/types/multistream/remoteMedia.d.ts +2 -2
  176. package/dist/types/multistream/remoteMediaManager.d.ts +14 -0
  177. package/dist/types/roap/request.d.ts +6 -8
  178. package/dist/types/roap/turnDiscovery.d.ts +18 -1
  179. package/package.json +3 -2
  180. package/src/annotation/annotation.types.ts +50 -0
  181. package/src/annotation/constants.ts +36 -0
  182. package/src/annotation/index.ts +328 -0
  183. package/src/breakouts/README.md +3 -2
  184. package/src/breakouts/breakout.ts +62 -27
  185. package/src/breakouts/events.ts +56 -0
  186. package/src/breakouts/index.ts +244 -64
  187. package/src/breakouts/utils.ts +13 -0
  188. package/src/common/errors/webex-errors.ts +6 -2
  189. package/src/common/logs/logger-proxy.ts +1 -1
  190. package/src/common/queue.ts +22 -8
  191. package/src/config.ts +0 -6
  192. package/src/constants.ts +111 -19
  193. package/src/controls-options-manager/enums.ts +2 -0
  194. package/src/controls-options-manager/index.ts +13 -10
  195. package/src/controls-options-manager/types.ts +10 -0
  196. package/src/controls-options-manager/util.ts +82 -11
  197. package/src/index.ts +18 -11
  198. package/src/interpretation/README.md +60 -0
  199. package/src/interpretation/collection.ts +19 -0
  200. package/src/interpretation/index.ts +332 -0
  201. package/src/interpretation/siLanguage.ts +18 -0
  202. package/src/locus-info/controlsUtils.ts +81 -0
  203. package/src/locus-info/index.ts +318 -57
  204. package/src/locus-info/infoUtils.ts +10 -2
  205. package/src/locus-info/mediaSharesUtils.ts +48 -0
  206. package/src/locus-info/parser.ts +224 -39
  207. package/src/locus-info/selfUtils.ts +32 -20
  208. package/src/media/index.ts +94 -108
  209. package/src/media/properties.ts +69 -109
  210. package/src/meeting/in-meeting-actions.ts +120 -4
  211. package/src/meeting/index.ts +1967 -2120
  212. package/src/meeting/locusMediaRequest.ts +314 -0
  213. package/src/meeting/muteState.ts +119 -194
  214. package/src/meeting/request.ts +122 -115
  215. package/src/meeting/util.ts +549 -413
  216. package/src/meeting-info/index.ts +54 -8
  217. package/src/meeting-info/meeting-info-v2.ts +89 -24
  218. package/src/meeting-info/utilv2.ts +6 -2
  219. package/src/meetings/index.ts +247 -87
  220. package/src/meetings/meetings.types.ts +12 -0
  221. package/src/meetings/util.ts +47 -12
  222. package/src/member/index.ts +28 -1
  223. package/src/member/types.ts +14 -0
  224. package/src/member/util.ts +75 -26
  225. package/src/members/index.ts +7 -1
  226. package/src/members/request.ts +61 -21
  227. package/src/members/util.ts +316 -326
  228. package/src/metrics/constants.ts +1 -0
  229. package/src/metrics/index.ts +1 -474
  230. package/src/multistream/mediaRequestManager.ts +183 -67
  231. package/src/multistream/receiveSlot.ts +4 -4
  232. package/src/multistream/receiveSlotManager.ts +4 -4
  233. package/src/multistream/remoteMedia.ts +2 -2
  234. package/src/multistream/remoteMediaGroup.ts +59 -0
  235. package/src/multistream/remoteMediaManager.ts +33 -0
  236. package/src/multistream/sendSlotManager.ts +170 -0
  237. package/src/reachability/index.ts +15 -4
  238. package/src/reachability/request.ts +7 -3
  239. package/src/reconnection-manager/index.ts +36 -29
  240. package/src/recording-controller/index.ts +20 -3
  241. package/src/recording-controller/util.ts +26 -9
  242. package/src/roap/index.ts +25 -30
  243. package/src/roap/request.ts +44 -51
  244. package/src/roap/turnDiscovery.ts +51 -25
  245. package/src/rtcMetrics/constants.ts +3 -0
  246. package/src/rtcMetrics/index.ts +100 -0
  247. package/src/statsAnalyzer/index.ts +0 -1
  248. package/test/integration/spec/converged-space-meetings.js +60 -3
  249. package/test/integration/spec/journey.js +336 -259
  250. package/test/integration/spec/space-meeting.js +76 -3
  251. package/test/unit/spec/annotation/index.ts +418 -0
  252. package/test/unit/spec/breakouts/breakout.ts +85 -26
  253. package/test/unit/spec/breakouts/events.ts +89 -0
  254. package/test/unit/spec/breakouts/index.ts +636 -98
  255. package/test/unit/spec/breakouts/utils.js +19 -1
  256. package/test/unit/spec/common/queue.js +31 -2
  257. package/test/unit/spec/controls-options-manager/index.js +8 -1
  258. package/test/unit/spec/controls-options-manager/util.js +576 -397
  259. package/test/unit/spec/fixture/locus.js +1 -0
  260. package/test/unit/spec/interpretation/collection.ts +15 -0
  261. package/test/unit/spec/interpretation/index.ts +589 -0
  262. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  263. package/test/unit/spec/locus-info/controlsUtils.js +195 -1
  264. package/test/unit/spec/locus-info/index.js +950 -45
  265. package/test/unit/spec/locus-info/infoUtils.js +37 -15
  266. package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
  267. package/test/unit/spec/locus-info/parser.js +62 -22
  268. package/test/unit/spec/locus-info/selfConstant.js +19 -0
  269. package/test/unit/spec/locus-info/selfUtils.js +131 -26
  270. package/test/unit/spec/media/index.ts +82 -79
  271. package/test/unit/spec/meeting/in-meeting-actions.ts +60 -2
  272. package/test/unit/spec/meeting/index.js +3208 -1734
  273. package/test/unit/spec/meeting/locusMediaRequest.ts +443 -0
  274. package/test/unit/spec/meeting/muteState.js +328 -417
  275. package/test/unit/spec/meeting/request.js +393 -48
  276. package/test/unit/spec/meeting/utils.js +552 -76
  277. package/test/unit/spec/meeting-info/index.js +181 -0
  278. package/test/unit/spec/meeting-info/meetinginfov2.js +258 -20
  279. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  280. package/test/unit/spec/meetings/index.js +631 -145
  281. package/test/unit/spec/meetings/utils.js +164 -9
  282. package/test/unit/spec/member/index.js +44 -14
  283. package/test/unit/spec/member/util.js +296 -155
  284. package/test/unit/spec/members/index.js +23 -3
  285. package/test/unit/spec/members/request.js +167 -35
  286. package/test/unit/spec/metrics/index.js +1 -50
  287. package/test/unit/spec/multistream/mediaRequestManager.ts +366 -8
  288. package/test/unit/spec/multistream/receiveSlot.ts +1 -1
  289. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  290. package/test/unit/spec/multistream/remoteMediaManager.ts +123 -0
  291. package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
  292. package/test/unit/spec/reachability/index.ts +66 -5
  293. package/test/unit/spec/reachability/request.js +3 -1
  294. package/test/unit/spec/reconnection-manager/index.js +55 -5
  295. package/test/unit/spec/recording-controller/index.js +294 -218
  296. package/test/unit/spec/recording-controller/util.js +223 -96
  297. package/test/unit/spec/roap/index.ts +21 -48
  298. package/test/unit/spec/roap/request.ts +74 -60
  299. package/test/unit/spec/roap/turnDiscovery.ts +30 -6
  300. package/test/unit/spec/rtcMetrics/index.ts +68 -0
  301. package/test/utils/integrationTestUtils.js +46 -0
  302. package/test/utils/testUtils.js +0 -60
  303. package/src/metrics/config.ts +0 -487
@@ -34,6 +34,7 @@ import CaptchaError from '@webex/plugin-meetings/src/common/errors/captcha-error
34
34
  import { forEach } from 'lodash';
35
35
  import PasswordError from '@webex/plugin-meetings/src/common/errors/password-error';
36
36
  import PermissionError from '@webex/plugin-meetings/src/common/errors/permission';
37
+ import {NoiseReductionEffect,VirtualBackgroundEffect} from '@webex/media-helpers';
37
38
 
38
39
  describe('plugin-meetings', () => {
39
40
  const logger = {
@@ -56,7 +57,7 @@ describe('plugin-meetings', () => {
56
57
  verboseEvents: true,
57
58
  enable: false,
58
59
  });
59
- TriggerProxy.trigger = sinon.stub().returns(true);
60
+ sinon.stub(TriggerProxy, 'trigger').returns(true);
60
61
  });
61
62
 
62
63
  let webex;
@@ -65,15 +66,20 @@ describe('plugin-meetings', () => {
65
66
  let url1;
66
67
  let test1;
67
68
  let test2;
69
+ let locusInfo;
68
70
 
69
71
  describe('meetings index', () => {
70
72
  beforeEach(() => {
71
73
  MeetingsUtil.checkH264Support = sinon.stub();
72
- uuid1 = uuid.v4();
74
+ uuid1 = uuid.v4();
73
75
  url1 = `https://example.com/${uuid.v4()}`;
74
76
  uri1 = `test-${uuid.v4()}@example.com`;
75
77
  test1 = `test-${uuid.v4()}`;
76
78
  test2 = `test2-${uuid.v4()}`;
79
+ locusInfo = {
80
+ parse: sinon.stub().returns(true),
81
+ updateMainSessionLocusCache: sinon.stub(),
82
+ };
77
83
  webex = new MockWebex({
78
84
  children: {
79
85
  device: Device,
@@ -156,6 +162,10 @@ describe('plugin-meetings', () => {
156
162
  webex.emit('ready');
157
163
  });
158
164
 
165
+ afterEach(() => {
166
+ sinon.restore();
167
+ });
168
+
159
169
  it('has a webex instance with a meetings property', () => {
160
170
  assert.exists(webex, 'webex was initialized with children');
161
171
  assert.exists(webex.meetings, 'meetings child was set up on the webex instance');
@@ -343,37 +353,113 @@ describe('plugin-meetings', () => {
343
353
  });
344
354
  });
345
355
 
356
+ describe('virtual background effect', () => {
357
+ beforeEach(() => {
358
+ webex.credentials = {
359
+ supertoken: {
360
+ access_token: "fake_token"
361
+ }
362
+ };
363
+ })
364
+
365
+ it('creates background effect', async () => {
366
+ const result = await webex.meetings.createVirtualBackgroundEffect();
367
+
368
+ assert.exists(result);
369
+ assert.instanceOf(result, VirtualBackgroundEffect);
370
+ assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'isLoaded', 'options']);
371
+ assert.deepEqual(result.options, {
372
+ mode: 'BLUR',
373
+ blurStrength: 'STRONG',
374
+ generator: 'worker',
375
+ quality: 'LOW',
376
+ authToken: 'fake_token',
377
+ mirror: false
378
+ });
379
+ assert.exists(result.enable);
380
+ assert.exists(result.disable);
381
+ assert.exists(result.dispose);
382
+ });
383
+
384
+ it('creates background effect with custom options passed', async () => {
385
+ const effectOptions = {
386
+ generator: "local",
387
+ frameRate: 45,
388
+ mode: "IMAGE",
389
+ mirror: false,
390
+ quality: "HIGH",
391
+ blurStrength: "STRONG",
392
+ bgImageUrl: "https://test.webex.com/landscape.5a535788.jpg",
393
+ };
394
+
395
+ const result = await webex.meetings.createVirtualBackgroundEffect(effectOptions);
396
+
397
+ assert.exists(result);
398
+ assert.instanceOf(result, VirtualBackgroundEffect);
399
+ assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'isLoaded', 'options']);
400
+ assert.deepEqual(result.options, {...effectOptions, authToken: "fake_token"});
401
+ assert.exists(result.enable);
402
+ assert.exists(result.disable);
403
+ assert.exists(result.dispose);
404
+ });
405
+ })
406
+
407
+ describe('noise reduction effect', () => {
408
+ beforeEach(() => {
409
+ webex.credentials = {
410
+ supertoken: {
411
+ access_token: "fake_token"
412
+ }
413
+ };
414
+ })
415
+
416
+ it('creates noise reduction effect', async () => {
417
+ const result = await webex.meetings.createNoiseReductionEffect({audioContext: {}});
418
+
419
+ assert.exists(result);
420
+ assert.instanceOf(result, NoiseReductionEffect);
421
+ assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
422
+ assert.deepEqual(result.options, {
423
+ authToken: 'fake_token',
424
+ audioContext: {}
425
+ });
426
+ assert.exists(result.enable);
427
+ assert.exists(result.disable);
428
+ assert.exists(result.dispose);
429
+ });
430
+
431
+ it('creates noise reduction effect with custom options passed', async () => {
432
+ const effectOptions = {
433
+ audioContext: {},
434
+ mode: "WORKLET",
435
+ env: "prod"
436
+ };
437
+
438
+ const result = await webex.meetings.createNoiseReductionEffect(effectOptions);
439
+
440
+ assert.exists(result);
441
+ assert.instanceOf(result, NoiseReductionEffect);
442
+ assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
443
+ assert.deepEqual(result.options, {...effectOptions, authToken: "fake_token"});
444
+ assert.exists(result.enable);
445
+ assert.exists(result.disable);
446
+ assert.exists(result.dispose);
447
+ });
448
+ })
449
+
346
450
  describe('gets', () => {
347
451
  describe('#getReachability', () => {
348
452
  it('should have #getReachability', () => {
349
453
  assert.exists(webex.meetings.getReachability);
350
454
  });
351
- describe('before #setReachability', () => {
352
- it('does not get a reachability instance', () => {
353
- const reachability = webex.meetings.getReachability();
455
+ it('gets the reachability data instance from webex.meetings', () => {
456
+ const reachability = webex.meetings.getReachability();
354
457
 
355
- assert.notExists(
356
- reachability,
357
- 'reachability is undefined because #setReachability has not been called'
358
- );
359
- });
360
- });
361
- describe('after #setReachability', () => {
362
- beforeEach(() => {
363
- webex.meetings.setReachability();
364
- const reachabilityMocker = webex.meetings.getReachability();
365
-
366
- sinon.stub(reachabilityMocker, 'gatherReachability').returns(true);
367
- });
368
- it('gets the reachability data instance from webex.meetings', () => {
369
- const reachability = webex.meetings.getReachability();
370
-
371
- assert.exists(
372
- reachability,
373
- 'reachability is defined because #setReachability has been called'
374
- );
375
- assert.instanceOf(reachability, Reachability, 'should be a reachability instance');
376
- });
458
+ assert.exists(
459
+ reachability,
460
+ 'reachability is defined'
461
+ );
462
+ assert.instanceOf(reachability, Reachability, 'should be a reachability instance');
377
463
  });
378
464
  });
379
465
  describe('#getPersonalMeetingRoom', () => {
@@ -448,21 +534,17 @@ describe('plugin-meetings', () => {
448
534
  );
449
535
  });
450
536
  describe('when meeting is returned', () => {
451
- let parse;
452
537
 
453
538
  beforeEach(() => {
454
- parse = sinon.stub().returns(true);
455
539
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
456
- locusInfo: {
457
- parse,
458
- },
540
+ locusInfo,
459
541
  });
460
542
  });
461
543
  it('tests the sync meeting calls for existing meeting', async () => {
462
544
  await webex.meetings.syncMeetings();
463
545
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
464
546
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
465
- assert.calledOnce(parse);
547
+ assert.calledOnce(locusInfo.parse);
466
548
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
467
549
  });
468
550
  });
@@ -475,6 +557,7 @@ describe('plugin-meetings', () => {
475
557
  webex.meetings.create = sinon.stub().returns(
476
558
  Promise.resolve({
477
559
  locusInfo: {
560
+ ...locusInfo,
478
561
  initialSetup,
479
562
  },
480
563
  })
@@ -507,12 +590,9 @@ describe('plugin-meetings', () => {
507
590
 
508
591
  beforeEach(() => {
509
592
  destroySpy = sinon.spy(webex.meetings, 'destroy');
510
- parse = sinon.stub().returns(true);
511
593
  initialSetup = sinon.stub().returns(true);
512
594
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
513
- locusInfo: {
514
- parse,
515
- },
595
+ locusInfo,
516
596
  sendCallAnalyzerMetrics: sinon.stub(),
517
597
  });
518
598
  webex.meetings.meetingCollection.getAll = sinon.stub().returns({
@@ -581,12 +661,26 @@ describe('plugin-meetings', () => {
581
661
 
582
662
  it('calls createMeeting and returns its promise', async () => {
583
663
  const FAKE_USE_RANDOM_DELAY = true;
584
- const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY);
664
+ const correlationId = 'my-correlationId';
665
+ const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId);
585
666
 
586
667
  assert.exists(create.then);
587
668
  await create;
588
669
  assert.calledOnce(webex.meetings.createMeeting);
589
- assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY);
670
+ assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId);
671
+ });
672
+
673
+ it('calls createMeeting with extra info params and returns its promise', async () => {
674
+ const FAKE_USE_RANDOM_DELAY = false;
675
+ const correlationId = 'my-correlationId';
676
+
677
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
678
+ const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
679
+
680
+ assert.exists(create.then);
681
+ await create;
682
+ assert.calledOnce(webex.meetings.createMeeting);
683
+ assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
590
684
  });
591
685
 
592
686
  it('creates a new meeting when a scheduled meeting exists in the conversation', async () => {
@@ -682,35 +776,39 @@ describe('plugin-meetings', () => {
682
776
  });
683
777
  describe('#handleLocusEvent', () => {
684
778
  describe('there was a meeting', () => {
685
- let parse;
686
779
 
687
780
  beforeEach(() => {
688
- parse = sinon.stub().returns(true);
689
781
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
690
- locusInfo: {
691
- parse,
692
- },
782
+ locusInfo,
693
783
  });
694
784
  });
695
- it('should parse the meeting info', () => {
785
+ it('should parse the meeting info and update main session locus cache', () => {
786
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(false);
696
787
  webex.meetings.handleLocusEvent({
697
788
  locusUrl: url1,
698
789
  });
699
790
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
700
791
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
701
- assert.calledOnce(parse);
792
+ assert.calledOnce(locusInfo.parse);
793
+ assert.calledOnce(locusInfo.updateMainSessionLocusCache);
702
794
  assert.calledWith(
703
- parse,
795
+ locusInfo.parse,
704
796
  {
705
- locusInfo: {
706
- parse,
707
- },
797
+ locusInfo,
708
798
  },
709
799
  {
710
800
  locusUrl: url1,
711
801
  }
712
802
  );
713
803
  });
804
+
805
+ it('should not update main session locus cache', () => {
806
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(true);
807
+ webex.meetings.handleLocusEvent({
808
+ locusUrl: url1,
809
+ });
810
+ assert.notCalled(locusInfo.updateMainSessionLocusCache);
811
+ });
714
812
  });
715
813
  describe('there was not a meeting', () => {
716
814
  let initialSetup;
@@ -721,7 +819,9 @@ describe('plugin-meetings', () => {
721
819
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
722
820
  webex.meetings.create = sinon.stub().returns(
723
821
  Promise.resolve({
822
+ id: 'meeting-id',
724
823
  locusInfo: {
824
+ ...locusInfo,
725
825
  initialSetup,
726
826
  },
727
827
  })
@@ -801,6 +901,39 @@ describe('plugin-meetings', () => {
801
901
  },
802
902
  });
803
903
  });
904
+
905
+ it('sends client event correctly on finally', async () => {
906
+ webex.meetings.getMeetingByType = sinon.stub().returns(true);
907
+
908
+ await webex.meetings.handleLocusEvent({
909
+ locus: {
910
+ id: uuid1,
911
+ self: {
912
+ callBackInfo: {
913
+ callbackAddress: uri1,
914
+ },
915
+ },
916
+ info: {
917
+ webExMeetingId,
918
+ },
919
+ },
920
+ eventType: 'locus.difference',
921
+ locusUrl: url1,
922
+ });
923
+
924
+ await testUtils.flushPromises();
925
+
926
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
927
+ name: 'client.call.remote-started',
928
+ payload: {
929
+ trigger: 'mercury-event',
930
+ },
931
+ options: {
932
+ meetingId: 'meeting-id',
933
+ },
934
+ });
935
+ });
936
+
804
937
  it('should setup the meeting by a not difference event', async () => {
805
938
  await webex.meetings.handleLocusEvent({
806
939
  locus: {
@@ -901,6 +1034,7 @@ describe('plugin-meetings', () => {
901
1034
  });
902
1035
  describe('successful MeetingInfo.#fetchMeetingInfo', () => {
903
1036
  let clock, setTimeoutSpy, fakeMeetingStartTimeString, FAKE_TIME_TO_START;
1037
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
904
1038
 
905
1039
  beforeEach(() => {
906
1040
  clock = sinon.useFakeTimers();
@@ -930,13 +1064,14 @@ describe('plugin-meetings', () => {
930
1064
  meeting,
931
1065
  destination,
932
1066
  type,
1067
+ extraParams = {},
933
1068
  expectedMeetingData = {}
934
1069
  ) => {
935
1070
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
936
1071
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
937
1072
  assert.notCalled(setTimeoutSpy);
938
- assert.calledThrice(TriggerProxy.trigger);
939
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type);
1073
+ assert.callCount(TriggerProxy.trigger, 5);
1074
+ assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type, null, null, undefined, undefined, extraParams, {meetingId: meeting.id});
940
1075
  assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
941
1076
 
942
1077
  if (expectedMeetingData.permissionToken) {
@@ -945,6 +1080,9 @@ describe('plugin-meetings', () => {
945
1080
  if (expectedMeetingData.meetingJoinUrl) {
946
1081
  assert.equal(meeting.meetingJoinUrl, expectedMeetingData.meetingJoinUrl);
947
1082
  }
1083
+ if(expectedMeetingData.correlationId) {
1084
+ assert.equal(meeting.correlationId, expectedMeetingData.correlationId);
1085
+ }
948
1086
  assert.equal(meeting.destination, destination);
949
1087
  assert.equal(meeting.destinationType, type);
950
1088
  assert.calledWith(
@@ -974,108 +1112,119 @@ describe('plugin-meetings', () => {
974
1112
  const expectedMeetingData = {
975
1113
  permissionToken: 'PT',
976
1114
  meetingJoinUrl: 'meetingJoinUrl',
1115
+ correlationId: meeting.id,
977
1116
  };
978
1117
 
979
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
1118
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
980
1119
  });
981
1120
 
982
- it('creates the meeting from a successful meeting info fetch meeting resolve testing', async () => {
983
- const meeting = await webex.meetings.createMeeting('test destination', 'test type');
984
- const expectedMeetingData = {
985
- permissionToken: 'PT',
986
- meetingJoinUrl: 'meetingJoinUrl',
987
- };
1121
+ [undefined, FAKE_INFO_EXTRA_PARAMS].forEach((infoExtraParams) => {
1122
+ const infoExtraParamsProvided = infoExtraParams !== undefined;
988
1123
 
989
- assert.instanceOf(
990
- meeting,
991
- Meeting,
992
- 'createMeeting should eventually resolve to a Meeting Object'
993
- );
994
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
995
- });
1124
+ it(`creates the meeting from a successful meeting info fetch meeting resolve testing${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1125
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, infoExtraParams);
1126
+ const expectedMeetingData = {
1127
+ permissionToken: 'PT',
1128
+ meetingJoinUrl: 'meetingJoinUrl',
1129
+ };
996
1130
 
997
- it('creates the meeting from a successful meeting info fetch with random delay', async () => {
998
- const FAKE_LOCUS_MEETING = {
999
- conversationUrl: 'locusConvURL',
1000
- url: 'locusUrl',
1001
- info: {
1002
- webExMeetingId: 'locusMeetingId',
1003
- sipUri: 'locusSipUri',
1004
- owner: 'locusOwner',
1005
- },
1006
- meeting: {
1007
- startTime: fakeMeetingStartTimeString,
1008
- },
1009
- fullState: {
1010
- active: false,
1011
- },
1012
- };
1131
+ assert.instanceOf(
1132
+ meeting,
1133
+ Meeting,
1134
+ 'createMeeting should eventually resolve to a Meeting Object'
1135
+ );
1136
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', infoExtraParamsProvided ? infoExtraParams : {}, expectedMeetingData);
1137
+ });
1013
1138
 
1014
- const meeting = await webex.meetings.createMeeting(
1015
- FAKE_LOCUS_MEETING,
1016
- 'test type',
1017
- true
1018
- );
1139
+ it(`creates the meeting from a successful meeting info fetch with random delay${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1140
+ const FAKE_LOCUS_MEETING = {
1141
+ conversationUrl: 'locusConvURL',
1142
+ url: 'locusUrl',
1143
+ info: {
1144
+ webExMeetingId: 'locusMeetingId',
1145
+ sipUri: 'locusSipUri',
1146
+ owner: 'locusOwner',
1147
+ },
1148
+ meeting: {
1149
+ startTime: fakeMeetingStartTimeString,
1150
+ },
1151
+ fullState: {
1152
+ active: false,
1153
+ },
1154
+ };
1019
1155
 
1020
- assert.instanceOf(
1021
- meeting,
1022
- Meeting,
1023
- 'createMeeting should eventually resolve to a Meeting Object'
1024
- );
1025
- assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
1026
- assert.calledOnce(setTimeoutSpy);
1027
-
1028
- // Parse meeting info with locus object
1029
- assert.equal(meeting.conversationUrl, 'locusConvURL');
1030
- assert.equal(meeting.locusUrl, 'locusUrl');
1031
- assert.equal(meeting.sipUri, 'locusSipUri');
1032
- assert.equal(meeting.meetingNumber, 'locusMeetingId');
1033
- assert.isUndefined(meeting.meetingJoinUrl);
1034
- assert.equal(meeting.owner, 'locusOwner');
1035
- assert.isUndefined(meeting.permissionToken);
1036
-
1037
- // Add meeting and send trigger
1038
- assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1039
- assert.calledTwice(TriggerProxy.trigger);
1040
- assert.calledWith(
1041
- TriggerProxy.trigger,
1042
- sinon.match.instanceOf(Meetings),
1043
- {
1044
- file: 'meetings',
1045
- function: 'createMeeting',
1046
- },
1047
- 'meeting:added',
1048
- {
1049
- meeting: sinon.match.instanceOf(Meeting),
1050
- type: 'test meeting added type',
1051
- }
1052
- );
1156
+ const meeting = await webex.meetings.createMeeting(
1157
+ FAKE_LOCUS_MEETING,
1158
+ 'test type',
1159
+ true,
1160
+ infoExtraParams
1161
+ );
1053
1162
 
1054
- // When timer expires
1055
- clock.tick(FAKE_TIME_TO_START);
1056
- assert.calledWith(
1057
- webex.meetings.meetingInfo.fetchMeetingInfo,
1058
- FAKE_LOCUS_MEETING,
1059
- 'test type'
1060
- );
1163
+ assert.instanceOf(
1164
+ meeting,
1165
+ Meeting,
1166
+ 'createMeeting should eventually resolve to a Meeting Object'
1167
+ );
1168
+ assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
1169
+ assert.calledOnce(setTimeoutSpy);
1170
+
1171
+ // Parse meeting info with locus object
1172
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1173
+ assert.equal(meeting.locusUrl, 'locusUrl');
1174
+ assert.equal(meeting.sipUri, 'locusSipUri');
1175
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1176
+ assert.isUndefined(meeting.meetingJoinUrl);
1177
+ assert.equal(meeting.owner, 'locusOwner');
1178
+ assert.isUndefined(meeting.permissionToken);
1179
+
1180
+ // Add meeting and send trigger
1181
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1182
+ assert.calledTwice(TriggerProxy.trigger);
1183
+ assert.calledWith(
1184
+ TriggerProxy.trigger,
1185
+ sinon.match.instanceOf(Meetings),
1186
+ {
1187
+ file: 'meetings',
1188
+ function: 'createMeeting',
1189
+ },
1190
+ 'meeting:added',
1191
+ {
1192
+ meeting: sinon.match.instanceOf(Meeting),
1193
+ type: 'test meeting added type',
1194
+ }
1195
+ );
1061
1196
 
1062
- // Parse meeting info is called again with new meeting info
1063
- await testUtils.flushPromises();
1064
- assert.equal(meeting.conversationUrl, 'locusConvURL');
1065
- assert.equal(meeting.locusUrl, 'locusUrl');
1066
- assert.equal(meeting.sipUri, 'locusSipUri');
1067
- assert.equal(meeting.meetingNumber, 'locusMeetingId');
1068
- assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
1069
- assert.equal(meeting.owner, 'locusOwner');
1070
- assert.equal(meeting.permissionToken, 'PT');
1197
+ // When timer expires
1198
+ clock.tick(FAKE_TIME_TO_START);
1199
+ assert.calledWith(
1200
+ webex.meetings.meetingInfo.fetchMeetingInfo,
1201
+ FAKE_LOCUS_MEETING,
1202
+ 'test type',
1203
+ null,
1204
+ null,
1205
+ undefined,
1206
+ undefined,
1207
+ infoExtraParamsProvided ? infoExtraParams : {}
1208
+ );
1071
1209
 
1072
- assert.calledWith(
1073
- TriggerProxy.trigger,
1074
- meeting,
1075
- {file: 'meetings', function: 'fetchMeetingInfo'},
1076
- 'meeting:meetingInfoAvailable'
1077
- );
1078
- });
1210
+ // Parse meeting info is called again with new meeting info
1211
+ await testUtils.flushPromises();
1212
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1213
+ assert.equal(meeting.locusUrl, 'locusUrl');
1214
+ assert.equal(meeting.sipUri, 'locusSipUri');
1215
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1216
+ assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
1217
+ assert.equal(meeting.owner, 'locusOwner');
1218
+ assert.equal(meeting.permissionToken, 'PT');
1219
+
1220
+ assert.calledWith(
1221
+ TriggerProxy.trigger,
1222
+ meeting,
1223
+ {file: 'meetings', function: 'fetchMeetingInfo'},
1224
+ 'meeting:meetingInfoAvailable'
1225
+ );
1226
+ });
1227
+ })
1079
1228
 
1080
1229
  it('creates the meeting from a successful meeting info fetch that has no random delay because it is active', async () => {
1081
1230
  const FAKE_LOCUS_MEETING = {
@@ -1174,6 +1323,16 @@ describe('plugin-meetings', () => {
1174
1323
  );
1175
1324
  checkCreateWithoutDelay(meeting, FAKE_LOCUS_MEETING, 'test type');
1176
1325
  });
1326
+
1327
+ it('creates meeting with the correlationId provided', async () => {
1328
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, {}, 'my-correlationId');
1329
+
1330
+ const expectedMeetingData = {
1331
+ correlationId: 'my-correlationId',
1332
+ };
1333
+
1334
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
1335
+ })
1177
1336
  });
1178
1337
 
1179
1338
  describe('rejected MeetingInfo.#fetchMeetingInfo', () => {
@@ -1194,7 +1353,7 @@ describe('plugin-meetings', () => {
1194
1353
  );
1195
1354
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1196
1355
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1197
- assert.calledTwice(TriggerProxy.trigger);
1356
+ assert.calledThrice(TriggerProxy.trigger);
1198
1357
  assert.calledWith(
1199
1358
  webex.meetings.meetingInfo.fetchMeetingInfo,
1200
1359
  'test destination',
@@ -1351,6 +1510,9 @@ describe('plugin-meetings', () => {
1351
1510
  });
1352
1511
 
1353
1512
  describe('#fetchUserPreferredWebexSite', () => {
1513
+
1514
+ let loggerProxySpy;
1515
+
1354
1516
  it('should call request.getMeetingPreferences to get the preferred webex site ', async () => {
1355
1517
  assert.isDefined(webex.meetings.preferredWebexSite);
1356
1518
  await webex.meetings.fetchUserPreferredWebexSite();
@@ -1358,7 +1520,24 @@ describe('plugin-meetings', () => {
1358
1520
  assert.equal(webex.meetings.preferredWebexSite, 'go.webex.com');
1359
1521
  });
1360
1522
 
1523
+ const setup = ({user} = {}) => {
1524
+ loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
1525
+
1526
+ Object.assign(webex.internal, {
1527
+ services: {
1528
+ getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
1529
+ },
1530
+ user: {
1531
+ get: sinon.stub().returns(
1532
+ Promise.resolve(user)
1533
+ ),
1534
+ },
1535
+ });
1536
+ }
1537
+
1361
1538
  it('should not fail if UserPreferred info is not fetched ', async () => {
1539
+ setup();
1540
+
1362
1541
  Object.assign(webex.internal, {
1363
1542
  services: {
1364
1543
  getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
@@ -1368,7 +1547,62 @@ describe('plugin-meetings', () => {
1368
1547
  await webex.meetings.fetchUserPreferredWebexSite().then(() => {
1369
1548
  assert.equal(webex.meetings.preferredWebexSite, '');
1370
1549
  });
1550
+ assert.calledOnceWithExactly(
1551
+ loggerProxySpy,
1552
+ 'Failed to fetch preferred site from user - no site will be set'
1553
+ );
1371
1554
  });
1555
+
1556
+ it('should fall back to fetching the site from the user', async () => {
1557
+ setup({
1558
+ user: {
1559
+ userPreferences: {
1560
+ userPreferencesItems: {
1561
+ preferredWebExSite: 'site.webex.com',
1562
+ },
1563
+ },
1564
+ },
1565
+ });
1566
+
1567
+ await webex.meetings.fetchUserPreferredWebexSite();
1568
+
1569
+ assert.equal(webex.meetings.preferredWebexSite, 'site.webex.com');
1570
+ assert.notCalled(loggerProxySpy);
1571
+ });
1572
+
1573
+ forEach([
1574
+ {user: undefined},
1575
+ {user: {userPreferences: {}}},
1576
+ {user: {userPreferences: {userPreferencesItems: {}}}},
1577
+ {user: {userPreferences: {userPreferencesItems: {preferredWebExSite: undefined}}}},
1578
+ ], ({user}) => {
1579
+ it(`should handle invalid user data ${user}`, async () => {
1580
+ setup({user});
1581
+
1582
+ await webex.meetings.fetchUserPreferredWebexSite();
1583
+
1584
+ assert.equal(webex.meetings.preferredWebexSite, '');
1585
+ assert.calledOnceWithExactly(
1586
+ loggerProxySpy,
1587
+ 'Failed to fetch preferred site from user - no site will be set'
1588
+ );
1589
+ });
1590
+ });
1591
+
1592
+ it('should handle a get user failure', async () => {
1593
+ setup();
1594
+
1595
+ webex.internal.user.get.rejects(new Error());
1596
+
1597
+ await webex.meetings.fetchUserPreferredWebexSite();
1598
+
1599
+ assert.equal(webex.meetings.preferredWebexSite, '');
1600
+ assert.calledOnceWithExactly(
1601
+ loggerProxySpy,
1602
+ 'Failed to fetch preferred site from user - no site will be set'
1603
+ );
1604
+ });
1605
+
1372
1606
  });
1373
1607
  });
1374
1608
 
@@ -1543,7 +1777,41 @@ describe('plugin-meetings', () => {
1543
1777
  assert.equal(result, false);
1544
1778
  assert.calledWith(
1545
1779
  LoggerProxy.logger.log,
1546
- 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status, not need to handle'
1780
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1781
+ );
1782
+ });
1783
+
1784
+ it('check self is moved and device resource removed, return false', () => {
1785
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1786
+ newLocus.self.state = 'LEFT';
1787
+ newLocus.self.reason = 'MOVED';
1788
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1789
+ state: 'LEFT',
1790
+ reason: 'MOVED',
1791
+ });
1792
+ LoggerProxy.logger.log = sinon.stub();
1793
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1794
+ assert.equal(result, false);
1795
+ assert.calledWith(
1796
+ LoggerProxy.logger.log,
1797
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1798
+ );
1799
+ });
1800
+
1801
+ it('check self is joined but device resource removed, return false', () => {
1802
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1803
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(false);
1804
+ newLocus.self.state = 'JOINED';
1805
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1806
+ state: 'LEFT',
1807
+ reason: 'MOVED',
1808
+ });
1809
+ LoggerProxy.logger.log = sinon.stub();
1810
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1811
+ assert.equal(result, false);
1812
+ assert.calledWith(
1813
+ LoggerProxy.logger.log,
1814
+ 'Meetings:index#isNeedHandleMainLocus --> self device left&moved in main locus with self joined status, not need to handle'
1547
1815
  );
1548
1816
  });
1549
1817
  });
@@ -1606,5 +1874,223 @@ describe('plugin-meetings', () => {
1606
1874
  assert.equal(result, false);
1607
1875
  });
1608
1876
  });
1877
+
1878
+ describe('#getCorrespondingMeetingByLocus', () => {
1879
+ let locus;
1880
+ let mockReturnMeeting = {meeting: 'meeting1'};
1881
+ const mockGetByKey = (keyWillReturnMeeting) => {
1882
+ webex.meetings.meetingCollection.getByKey = sinon.stub().callsFake((key) => {
1883
+ if (key === keyWillReturnMeeting) {
1884
+ return mockReturnMeeting;
1885
+ }
1886
+ return null;
1887
+ });
1888
+ };
1889
+
1890
+ beforeEach(() => {
1891
+ locus = {
1892
+ controls: {},
1893
+ self: {
1894
+ callbackInfo: {
1895
+ callbackAddress: 'address1',
1896
+ }
1897
+ },
1898
+ info: {
1899
+ webExMeetingId: '123456',
1900
+ isUnifiedSpaceMeeting: false,
1901
+ },
1902
+ conversationUrl: 'conversationUrl1'
1903
+ };
1904
+
1905
+ sinon.stub(MeetingsUtil, 'checkForCorrelationId').returns('correlationId1');
1906
+ });
1907
+ afterEach(() => {
1908
+ sinon.restore();
1909
+ });
1910
+ it('check the calls when no meeting found in meetingCollection', () => {
1911
+ mockGetByKey();
1912
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1913
+ assert.isNull(result);
1914
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1915
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1916
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1917
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1918
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1919
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1920
+ });
1921
+
1922
+ it('not try getByKey "conversationUrl" when isUnifiedSpaceMeeting is true', () => {
1923
+ mockGetByKey();
1924
+ locus.info.isUnifiedSpaceMeeting = true;
1925
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1926
+ assert.isNull(result);
1927
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1928
+ })
1929
+
1930
+ it('check the calls when meeting found by key: locusUrl', () => {
1931
+ mockGetByKey('locusUrl');
1932
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1933
+ assert.deepEqual(result, mockReturnMeeting);
1934
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 1);
1935
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1936
+ });
1937
+
1938
+ it('check the calls when meeting found by key: correlationId', () => {
1939
+ mockGetByKey('correlationId');
1940
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1941
+ assert.deepEqual(result, mockReturnMeeting);
1942
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 2);
1943
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1944
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1945
+ });
1946
+
1947
+ it('check the calls when meeting found by key: sipUri', () => {
1948
+ mockGetByKey('sipUri');
1949
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1950
+ assert.deepEqual(result, mockReturnMeeting);
1951
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
1952
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1953
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1954
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1955
+ });
1956
+
1957
+ it('check the calls when meeting found by key: conversationUrl', () => {
1958
+ mockGetByKey('conversationUrl');
1959
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1960
+ assert.deepEqual(result, mockReturnMeeting);
1961
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1962
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1963
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1964
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1965
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1966
+ });
1967
+
1968
+ it('check the calls when meeting found by key: meetingNumber', () => {
1969
+ mockGetByKey('meetingNumber');
1970
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1971
+ assert.deepEqual(result, mockReturnMeeting);
1972
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1973
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1974
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1975
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1976
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1977
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1978
+ });
1979
+ });
1980
+
1981
+ describe('#sortLocusArrayToUpdate', () => {
1982
+ let lociArray;
1983
+ let mainLocus;
1984
+ let breakoutLocus;
1985
+ beforeEach(() => {
1986
+ mainLocus = {
1987
+ url: 'mainUrl1',
1988
+ controls: {
1989
+ breakout: {
1990
+ sessionType: 'MAIN',
1991
+ url: 'breakoutUnifiedUrl1'
1992
+ }
1993
+ }
1994
+ };
1995
+ breakoutLocus = {
1996
+ url: 'breakoutUrl1',
1997
+ controls: {
1998
+ breakout: {
1999
+ sessionType: 'BREAKOUT',
2000
+ url: 'breakoutUnifiedUrl1'
2001
+ }
2002
+ }
2003
+ };
2004
+ lociArray = [mainLocus, breakoutLocus];
2005
+
2006
+ sinon.stub(MeetingsUtil, 'isValidBreakoutLocus').callsFake((locus) => {
2007
+ return locus.url === 'breakoutUrl1';
2008
+ });
2009
+ });
2010
+ afterEach(() => {
2011
+ sinon.restore();
2012
+ });
2013
+
2014
+ it('if both main and breakout locus is in array for non-exist meeting, return main locus to create first', () => {
2015
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
2016
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2017
+ assert.deepEqual(result, [mainLocus]);
2018
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, [breakoutLocus]);
2019
+ });
2020
+
2021
+ it('if both main and breakout locus is in array for an exist meeting, return all locus', () => {
2022
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2023
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2024
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2025
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, []);
2026
+ });
2027
+
2028
+ it('if the breakout locus has no associated main locus, return all', () => {
2029
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2030
+ breakoutLocus.controls.breakout.url = 'testUrl';
2031
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2032
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2033
+ });
2034
+ });
2035
+
2036
+ describe('#checkHandleBreakoutLocus', () => {
2037
+ let breakoutLocus;
2038
+ beforeEach(() => {
2039
+ breakoutLocus = {
2040
+ url: 'breakoutUrl1',
2041
+ controls: {
2042
+ breakout: {
2043
+ sessionType: 'BREAKOUT',
2044
+ url: 'breakoutUnifiedUrl1',
2045
+ }
2046
+ }
2047
+ };
2048
+
2049
+ webex.meetings.handleLocusEvent = sinon.stub();
2050
+ });
2051
+ afterEach(() => {
2052
+ sinon.restore();
2053
+ });
2054
+ it('do nothing if new created locus is null/no cached breakouts for updating', () => {
2055
+ webex.meetings.checkHandleBreakoutLocus(null);
2056
+ webex.meetings.breakoutLocusForHandleLater = null;
2057
+ webex.meetings.checkHandleBreakoutLocus({});
2058
+ webex.meetings.breakoutLocusForHandleLater = [];
2059
+ webex.meetings.checkHandleBreakoutLocus({});
2060
+ assert.notCalled(webex.meetings.handleLocusEvent);
2061
+ });
2062
+
2063
+ it('do nothing if new created locus is breakout locus', () => {
2064
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2065
+ webex.meetings.checkHandleBreakoutLocus(breakoutLocus);
2066
+ assert.notCalled(webex.meetings.handleLocusEvent);
2067
+ });
2068
+
2069
+ it('do nothing if no cached locus is associated with the new created locus', () => {
2070
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2071
+ webex.meetings.checkHandleBreakoutLocus({
2072
+ controls: {
2073
+ breakout: {
2074
+ sessionType: 'MAIN',
2075
+ url: 'breakoutUnifiedUrl2',
2076
+ }
2077
+ }
2078
+ });
2079
+ assert.notCalled(webex.meetings.handleLocusEvent);
2080
+ });
2081
+
2082
+ it('update the cached breakout locus which associate the new created locus', () => {
2083
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2084
+ webex.meetings.checkHandleBreakoutLocus({
2085
+ controls: {
2086
+ breakout: {
2087
+ sessionType: 'MAIN',
2088
+ url: 'breakoutUnifiedUrl1',
2089
+ }
2090
+ }
2091
+ });
2092
+ assert.calledWith(webex.meetings.handleLocusEvent, {locus: breakoutLocus, locusUrl: breakoutLocus.url});
2093
+ });
2094
+ });
1609
2095
  });
1610
2096
  });