@webex/plugin-meetings 3.0.0-beta.18 → 3.0.0-beta.180

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 (410) hide show
  1. package/README.md +45 -7
  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 +114 -14
  9. package/dist/breakouts/breakout.js.map +1 -1
  10. package/dist/breakouts/edit-lock-error.js +52 -0
  11. package/dist/breakouts/edit-lock-error.js.map +1 -0
  12. package/dist/breakouts/events.js +45 -0
  13. package/dist/breakouts/events.js.map +1 -0
  14. package/dist/breakouts/index.js +841 -19
  15. package/dist/breakouts/index.js.map +1 -1
  16. package/dist/breakouts/request.js +78 -0
  17. package/dist/breakouts/request.js.map +1 -0
  18. package/dist/breakouts/utils.js +67 -0
  19. package/dist/breakouts/utils.js.map +1 -0
  20. package/dist/common/errors/webex-errors.js +3 -2
  21. package/dist/common/errors/webex-errors.js.map +1 -1
  22. package/dist/common/logs/logger-proxy.js +1 -1
  23. package/dist/common/logs/logger-proxy.js.map +1 -1
  24. package/dist/config.js +3 -8
  25. package/dist/config.js.map +1 -1
  26. package/dist/constants.js +172 -30
  27. package/dist/constants.js.map +1 -1
  28. package/dist/controls-options-manager/constants.js +14 -0
  29. package/dist/controls-options-manager/constants.js.map +1 -0
  30. package/dist/controls-options-manager/enums.js +27 -0
  31. package/dist/controls-options-manager/enums.js.map +1 -0
  32. package/dist/controls-options-manager/index.js +297 -0
  33. package/dist/controls-options-manager/index.js.map +1 -0
  34. package/dist/controls-options-manager/types.js +7 -0
  35. package/dist/controls-options-manager/types.js.map +1 -0
  36. package/dist/controls-options-manager/util.js +300 -0
  37. package/dist/controls-options-manager/util.js.map +1 -0
  38. package/dist/index.js +107 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/interpretation/collection.js +23 -0
  41. package/dist/interpretation/collection.js.map +1 -0
  42. package/dist/interpretation/index.js +352 -0
  43. package/dist/interpretation/index.js.map +1 -0
  44. package/dist/interpretation/siLanguage.js +25 -0
  45. package/dist/interpretation/siLanguage.js.map +1 -0
  46. package/dist/locus-info/controlsUtils.js +91 -2
  47. package/dist/locus-info/controlsUtils.js.map +1 -1
  48. package/dist/locus-info/index.js +302 -41
  49. package/dist/locus-info/index.js.map +1 -1
  50. package/dist/locus-info/mediaSharesUtils.js +43 -1
  51. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  52. package/dist/locus-info/parser.js +1 -1
  53. package/dist/locus-info/parser.js.map +1 -1
  54. package/dist/locus-info/selfUtils.js +89 -14
  55. package/dist/locus-info/selfUtils.js.map +1 -1
  56. package/dist/media/index.js +39 -134
  57. package/dist/media/index.js.map +1 -1
  58. package/dist/media/properties.js +29 -90
  59. package/dist/media/properties.js.map +1 -1
  60. package/dist/mediaQualityMetrics/config.js +505 -493
  61. package/dist/mediaQualityMetrics/config.js.map +1 -1
  62. package/dist/meeting/in-meeting-actions.js +76 -2
  63. package/dist/meeting/in-meeting-actions.js.map +1 -1
  64. package/dist/meeting/index.js +2610 -2465
  65. package/dist/meeting/index.js.map +1 -1
  66. package/dist/meeting/locusMediaRequest.js +291 -0
  67. package/dist/meeting/locusMediaRequest.js.map +1 -0
  68. package/dist/meeting/muteState.js +229 -124
  69. package/dist/meeting/muteState.js.map +1 -1
  70. package/dist/meeting/request.js +189 -146
  71. package/dist/meeting/request.js.map +1 -1
  72. package/dist/meeting/util.js +478 -414
  73. package/dist/meeting/util.js.map +1 -1
  74. package/dist/meeting-info/index.js +48 -7
  75. package/dist/meeting-info/index.js.map +1 -1
  76. package/dist/meeting-info/meeting-info-v2.js +171 -51
  77. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  78. package/dist/meeting-info/utilv2.js +20 -5
  79. package/dist/meeting-info/utilv2.js.map +1 -1
  80. package/dist/meetings/collection.js +22 -0
  81. package/dist/meetings/collection.js.map +1 -1
  82. package/dist/meetings/index.js +350 -65
  83. package/dist/meetings/index.js.map +1 -1
  84. package/dist/meetings/meetings.types.js +7 -0
  85. package/dist/meetings/meetings.types.js.map +1 -0
  86. package/dist/meetings/request.js +2 -0
  87. package/dist/meetings/request.js.map +1 -1
  88. package/dist/meetings/util.js +88 -1
  89. package/dist/meetings/util.js.map +1 -1
  90. package/dist/member/index.js +49 -0
  91. package/dist/member/index.js.map +1 -1
  92. package/dist/member/types.js +25 -0
  93. package/dist/member/types.js.map +1 -0
  94. package/dist/member/util.js +98 -2
  95. package/dist/member/util.js.map +1 -1
  96. package/dist/members/collection.js +10 -0
  97. package/dist/members/collection.js.map +1 -1
  98. package/dist/members/index.js +86 -5
  99. package/dist/members/index.js.map +1 -1
  100. package/dist/members/request.js +106 -38
  101. package/dist/members/request.js.map +1 -1
  102. package/dist/members/types.js +15 -0
  103. package/dist/members/types.js.map +1 -0
  104. package/dist/members/util.js +316 -233
  105. package/dist/members/util.js.map +1 -1
  106. package/dist/metrics/constants.js +3 -5
  107. package/dist/metrics/constants.js.map +1 -1
  108. package/dist/metrics/index.js +1 -468
  109. package/dist/metrics/index.js.map +1 -1
  110. package/dist/multistream/mediaRequestManager.js +238 -49
  111. package/dist/multistream/mediaRequestManager.js.map +1 -1
  112. package/dist/multistream/receiveSlot.js +49 -16
  113. package/dist/multistream/receiveSlot.js.map +1 -1
  114. package/dist/multistream/receiveSlotManager.js +48 -30
  115. package/dist/multistream/receiveSlotManager.js.map +1 -1
  116. package/dist/multistream/remoteMedia.js +44 -18
  117. package/dist/multistream/remoteMedia.js.map +1 -1
  118. package/dist/multistream/remoteMediaGroup.js +60 -3
  119. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  120. package/dist/multistream/remoteMediaManager.js +173 -59
  121. package/dist/multistream/remoteMediaManager.js.map +1 -1
  122. package/dist/networkQualityMonitor/index.js +4 -2
  123. package/dist/networkQualityMonitor/index.js.map +1 -1
  124. package/dist/reachability/index.js +72 -27
  125. package/dist/reachability/index.js.map +1 -1
  126. package/dist/reachability/request.js +12 -5
  127. package/dist/reachability/request.js.map +1 -1
  128. package/dist/reactions/reactions.js +2 -2
  129. package/dist/reactions/reactions.js.map +1 -1
  130. package/dist/reactions/reactions.type.js +18 -18
  131. package/dist/reactions/reactions.type.js.map +1 -1
  132. package/dist/reconnection-manager/index.js +196 -155
  133. package/dist/reconnection-manager/index.js.map +1 -1
  134. package/dist/recording-controller/index.js +21 -1
  135. package/dist/recording-controller/index.js.map +1 -1
  136. package/dist/recording-controller/util.js +9 -8
  137. package/dist/recording-controller/util.js.map +1 -1
  138. package/dist/roap/index.js +21 -29
  139. package/dist/roap/index.js.map +1 -1
  140. package/dist/roap/request.js +110 -89
  141. package/dist/roap/request.js.map +1 -1
  142. package/dist/roap/turnDiscovery.js +93 -36
  143. package/dist/roap/turnDiscovery.js.map +1 -1
  144. package/dist/statsAnalyzer/global.js +1 -93
  145. package/dist/statsAnalyzer/global.js.map +1 -1
  146. package/dist/statsAnalyzer/index.js +326 -311
  147. package/dist/statsAnalyzer/index.js.map +1 -1
  148. package/dist/statsAnalyzer/mqaUtil.js +90 -53
  149. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  150. package/dist/types/annotation/annotation.types.d.ts +42 -0
  151. package/dist/types/annotation/constants.d.ts +31 -0
  152. package/dist/types/annotation/index.d.ts +117 -0
  153. package/dist/types/breakouts/breakout.d.ts +8 -0
  154. package/dist/types/breakouts/collection.d.ts +5 -0
  155. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  156. package/dist/types/breakouts/events.d.ts +8 -0
  157. package/dist/types/breakouts/index.d.ts +5 -0
  158. package/dist/types/breakouts/request.d.ts +22 -0
  159. package/dist/types/breakouts/utils.d.ts +15 -0
  160. package/dist/types/common/browser-detection.d.ts +9 -0
  161. package/dist/types/common/collection.d.ts +48 -0
  162. package/dist/types/common/config.d.ts +2 -0
  163. package/dist/types/common/errors/captcha-error.d.ts +15 -0
  164. package/dist/types/common/errors/intent-to-join.d.ts +16 -0
  165. package/dist/types/common/errors/join-meeting.d.ts +17 -0
  166. package/dist/types/common/errors/media.d.ts +15 -0
  167. package/dist/types/common/errors/parameter.d.ts +15 -0
  168. package/dist/types/common/errors/password-error.d.ts +15 -0
  169. package/dist/types/common/errors/permission.d.ts +14 -0
  170. package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
  171. package/dist/types/common/errors/reconnection.d.ts +15 -0
  172. package/dist/types/common/errors/stats.d.ts +15 -0
  173. package/dist/types/common/errors/webex-errors.d.ts +69 -0
  174. package/dist/types/common/errors/webex-meetings-error.d.ts +20 -0
  175. package/dist/types/common/events/events-scope.d.ts +17 -0
  176. package/dist/types/common/events/events.d.ts +12 -0
  177. package/dist/types/common/events/trigger-proxy.d.ts +2 -0
  178. package/dist/types/common/events/util.d.ts +2 -0
  179. package/dist/types/common/logs/logger-config.d.ts +2 -0
  180. package/dist/types/common/logs/logger-proxy.d.ts +2 -0
  181. package/dist/types/common/logs/request.d.ts +34 -0
  182. package/dist/types/common/queue.d.ts +32 -0
  183. package/dist/types/config.d.ts +72 -0
  184. package/dist/types/constants.d.ts +1016 -0
  185. package/dist/types/controls-options-manager/constants.d.ts +4 -0
  186. package/dist/types/controls-options-manager/enums.d.ts +15 -0
  187. package/dist/types/controls-options-manager/index.d.ts +136 -0
  188. package/dist/types/controls-options-manager/types.d.ts +43 -0
  189. package/dist/types/controls-options-manager/util.d.ts +1 -0
  190. package/dist/types/index.d.ts +7 -0
  191. package/dist/types/interpretation/collection.d.ts +5 -0
  192. package/dist/types/interpretation/index.d.ts +5 -0
  193. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  194. package/dist/types/locus-info/controlsUtils.d.ts +2 -0
  195. package/dist/types/locus-info/embeddedAppsUtils.d.ts +2 -0
  196. package/dist/types/locus-info/fullState.d.ts +2 -0
  197. package/dist/types/locus-info/hostUtils.d.ts +2 -0
  198. package/dist/types/locus-info/index.d.ts +315 -0
  199. package/dist/types/locus-info/infoUtils.d.ts +2 -0
  200. package/dist/types/locus-info/mediaSharesUtils.d.ts +2 -0
  201. package/dist/types/locus-info/parser.d.ts +212 -0
  202. package/dist/types/locus-info/selfUtils.d.ts +2 -0
  203. package/dist/types/media/index.d.ts +34 -0
  204. package/dist/types/media/properties.d.ts +93 -0
  205. package/dist/types/media/util.d.ts +2 -0
  206. package/dist/types/mediaQualityMetrics/config.d.ts +365 -0
  207. package/dist/types/meeting/in-meeting-actions.d.ts +149 -0
  208. package/dist/types/meeting/index.d.ts +1467 -0
  209. package/dist/types/meeting/locusMediaRequest.d.ts +70 -0
  210. package/dist/types/meeting/muteState.d.ts +184 -0
  211. package/dist/types/meeting/request.d.ts +270 -0
  212. package/dist/types/meeting/request.type.d.ts +11 -0
  213. package/dist/types/meeting/state.d.ts +9 -0
  214. package/dist/types/meeting/util.d.ts +77 -0
  215. package/dist/types/meeting-info/collection.d.ts +20 -0
  216. package/dist/types/meeting-info/index.d.ts +62 -0
  217. package/dist/types/meeting-info/meeting-info-v2.d.ts +122 -0
  218. package/dist/types/meeting-info/request.d.ts +22 -0
  219. package/dist/types/meeting-info/util.d.ts +2 -0
  220. package/dist/types/meeting-info/utilv2.d.ts +2 -0
  221. package/dist/types/meetings/collection.d.ts +31 -0
  222. package/dist/types/meetings/index.d.ts +365 -0
  223. package/dist/types/meetings/meetings.types.d.ts +4 -0
  224. package/dist/types/meetings/request.d.ts +27 -0
  225. package/dist/types/meetings/util.d.ts +18 -0
  226. package/dist/types/member/index.d.ts +159 -0
  227. package/dist/types/member/types.d.ts +32 -0
  228. package/dist/types/member/util.d.ts +2 -0
  229. package/dist/types/members/collection.d.ts +29 -0
  230. package/dist/types/members/index.d.ts +353 -0
  231. package/dist/types/members/request.d.ts +114 -0
  232. package/dist/types/members/types.d.ts +24 -0
  233. package/dist/types/members/util.d.ts +210 -0
  234. package/dist/types/metrics/constants.d.ts +55 -0
  235. package/dist/types/metrics/index.d.ts +45 -0
  236. package/dist/types/multistream/mediaRequestManager.d.ts +118 -0
  237. package/dist/types/multistream/receiveSlot.d.ts +68 -0
  238. package/dist/types/multistream/receiveSlotManager.d.ts +56 -0
  239. package/dist/types/multistream/remoteMedia.d.ts +72 -0
  240. package/dist/types/multistream/remoteMediaGroup.d.ts +47 -0
  241. package/dist/types/multistream/remoteMediaManager.d.ts +277 -0
  242. package/dist/types/networkQualityMonitor/index.d.ts +70 -0
  243. package/dist/types/personal-meeting-room/index.d.ts +47 -0
  244. package/dist/types/personal-meeting-room/request.d.ts +14 -0
  245. package/dist/types/personal-meeting-room/util.d.ts +2 -0
  246. package/dist/types/reachability/index.d.ts +152 -0
  247. package/dist/types/reachability/request.d.ts +37 -0
  248. package/dist/types/reactions/constants.d.ts +3 -0
  249. package/dist/types/reactions/reactions.d.ts +4 -0
  250. package/dist/types/reactions/reactions.type.d.ts +52 -0
  251. package/dist/types/reconnection-manager/index.d.ts +126 -0
  252. package/dist/types/recording-controller/enums.d.ts +7 -0
  253. package/dist/types/recording-controller/index.d.ts +208 -0
  254. package/dist/types/recording-controller/util.d.ts +14 -0
  255. package/dist/types/roap/index.d.ts +77 -0
  256. package/dist/types/roap/request.d.ts +36 -0
  257. package/dist/types/roap/turnDiscovery.d.ts +91 -0
  258. package/dist/types/statsAnalyzer/global.d.ts +36 -0
  259. package/dist/types/statsAnalyzer/index.d.ts +200 -0
  260. package/dist/types/statsAnalyzer/mqaUtil.d.ts +24 -0
  261. package/dist/types/transcription/index.d.ts +64 -0
  262. package/package.json +26 -23
  263. package/src/annotation/annotation.types.ts +50 -0
  264. package/src/annotation/constants.ts +36 -0
  265. package/src/annotation/index.ts +328 -0
  266. package/src/breakouts/README.md +44 -14
  267. package/src/breakouts/breakout.ts +87 -9
  268. package/src/breakouts/edit-lock-error.ts +25 -0
  269. package/src/breakouts/events.ts +56 -0
  270. package/src/breakouts/index.ts +710 -10
  271. package/src/breakouts/request.ts +55 -0
  272. package/src/breakouts/utils.ts +57 -0
  273. package/src/common/errors/webex-errors.ts +6 -2
  274. package/src/common/logs/logger-proxy.ts +1 -1
  275. package/src/config.ts +2 -7
  276. package/src/constants.ts +157 -21
  277. package/src/controls-options-manager/constants.ts +5 -0
  278. package/src/controls-options-manager/enums.ts +18 -0
  279. package/src/controls-options-manager/index.ts +278 -0
  280. package/src/controls-options-manager/types.ts +59 -0
  281. package/src/controls-options-manager/util.ts +286 -0
  282. package/src/index.ts +39 -0
  283. package/src/interpretation/README.md +60 -0
  284. package/src/interpretation/collection.ts +19 -0
  285. package/src/interpretation/index.ts +318 -0
  286. package/src/interpretation/siLanguage.ts +18 -0
  287. package/src/locus-info/controlsUtils.ts +108 -0
  288. package/src/locus-info/index.ts +316 -38
  289. package/src/locus-info/mediaSharesUtils.ts +48 -0
  290. package/src/locus-info/parser.ts +1 -1
  291. package/src/locus-info/selfUtils.ts +81 -5
  292. package/src/media/index.ts +77 -142
  293. package/src/media/properties.ts +49 -90
  294. package/src/mediaQualityMetrics/config.ts +379 -377
  295. package/src/meeting/in-meeting-actions.ts +151 -3
  296. package/src/meeting/index.ts +1919 -2002
  297. package/src/meeting/locusMediaRequest.ts +309 -0
  298. package/src/meeting/muteState.ts +228 -132
  299. package/src/meeting/request.ts +96 -65
  300. package/src/meeting/util.ts +464 -396
  301. package/src/meeting-info/index.ts +54 -8
  302. package/src/meeting-info/meeting-info-v2.ts +148 -14
  303. package/src/meeting-info/utilv2.ts +13 -3
  304. package/src/meetings/collection.ts +20 -0
  305. package/src/meetings/index.ts +386 -84
  306. package/src/meetings/meetings.types.ts +12 -0
  307. package/src/meetings/request.ts +2 -0
  308. package/src/meetings/util.ts +103 -4
  309. package/src/member/index.ts +49 -0
  310. package/src/member/types.ts +38 -0
  311. package/src/member/util.ts +103 -0
  312. package/src/members/collection.ts +8 -0
  313. package/src/members/index.ts +107 -6
  314. package/src/members/request.ts +97 -17
  315. package/src/members/types.ts +28 -0
  316. package/src/members/util.ts +319 -240
  317. package/src/metrics/constants.ts +2 -4
  318. package/src/metrics/index.ts +1 -490
  319. package/src/multistream/mediaRequestManager.ts +289 -79
  320. package/src/multistream/receiveSlot.ts +55 -18
  321. package/src/multistream/receiveSlotManager.ts +42 -20
  322. package/src/multistream/remoteMedia.ts +28 -2
  323. package/src/multistream/remoteMediaGroup.ts +59 -0
  324. package/src/multistream/remoteMediaManager.ts +113 -32
  325. package/src/networkQualityMonitor/index.ts +6 -6
  326. package/src/reachability/index.ts +62 -15
  327. package/src/reachability/request.ts +10 -5
  328. package/src/reactions/reactions.ts +4 -4
  329. package/src/reactions/reactions.type.ts +3 -3
  330. package/src/reconnection-manager/index.ts +68 -43
  331. package/src/recording-controller/index.ts +20 -2
  332. package/src/recording-controller/util.ts +26 -9
  333. package/src/roap/index.ts +21 -30
  334. package/src/roap/request.ts +101 -95
  335. package/src/roap/turnDiscovery.ts +47 -25
  336. package/src/statsAnalyzer/global.ts +1 -94
  337. package/src/statsAnalyzer/index.ts +376 -386
  338. package/src/statsAnalyzer/mqaUtil.ts +100 -99
  339. package/test/integration/spec/converged-space-meetings.js +233 -0
  340. package/test/integration/spec/journey.js +336 -259
  341. package/test/integration/spec/space-meeting.js +77 -4
  342. package/test/unit/spec/annotation/index.ts +418 -0
  343. package/test/unit/spec/breakouts/breakout.ts +142 -24
  344. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  345. package/test/unit/spec/breakouts/events.ts +89 -0
  346. package/test/unit/spec/breakouts/index.ts +1545 -48
  347. package/test/unit/spec/breakouts/request.ts +104 -0
  348. package/test/unit/spec/breakouts/utils.js +72 -0
  349. package/test/unit/spec/controls-options-manager/index.js +287 -0
  350. package/test/unit/spec/controls-options-manager/util.js +518 -0
  351. package/test/unit/spec/fixture/locus.js +1 -0
  352. package/test/unit/spec/interpretation/collection.ts +15 -0
  353. package/test/unit/spec/interpretation/index.ts +570 -0
  354. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  355. package/test/unit/spec/locus-info/controlsUtils.js +316 -43
  356. package/test/unit/spec/locus-info/index.js +707 -22
  357. package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
  358. package/test/unit/spec/locus-info/selfConstant.js +27 -4
  359. package/test/unit/spec/locus-info/selfUtils.js +208 -17
  360. package/test/unit/spec/media/index.ts +129 -23
  361. package/test/unit/spec/meeting/in-meeting-actions.ts +75 -3
  362. package/test/unit/spec/meeting/index.js +2728 -1397
  363. package/test/unit/spec/meeting/locusMediaRequest.ts +436 -0
  364. package/test/unit/spec/meeting/muteState.js +370 -208
  365. package/test/unit/spec/meeting/request.js +338 -43
  366. package/test/unit/spec/meeting/utils.js +378 -55
  367. package/test/unit/spec/meeting-info/index.js +181 -0
  368. package/test/unit/spec/meeting-info/meetinginfov2.js +383 -5
  369. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  370. package/test/unit/spec/meetings/collection.js +14 -0
  371. package/test/unit/spec/meetings/index.js +846 -121
  372. package/test/unit/spec/meetings/utils.js +206 -2
  373. package/test/unit/spec/member/index.js +58 -4
  374. package/test/unit/spec/member/util.js +415 -33
  375. package/test/unit/spec/members/index.js +320 -1
  376. package/test/unit/spec/members/request.js +206 -27
  377. package/test/unit/spec/members/utils.js +184 -0
  378. package/test/unit/spec/metrics/index.js +1 -50
  379. package/test/unit/spec/multistream/mediaRequestManager.ts +803 -162
  380. package/test/unit/spec/multistream/receiveSlot.ts +72 -13
  381. package/test/unit/spec/multistream/receiveSlotManager.ts +58 -28
  382. package/test/unit/spec/multistream/remoteMedia.ts +30 -0
  383. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  384. package/test/unit/spec/multistream/remoteMediaManager.ts +318 -0
  385. package/test/unit/spec/networkQualityMonitor/index.js +4 -4
  386. package/test/unit/spec/reachability/index.ts +125 -8
  387. package/test/unit/spec/reachability/request.js +66 -0
  388. package/test/unit/spec/reconnection-manager/index.js +59 -6
  389. package/test/unit/spec/recording-controller/index.js +294 -218
  390. package/test/unit/spec/recording-controller/util.js +223 -96
  391. package/test/unit/spec/roap/index.ts +26 -51
  392. package/test/unit/spec/roap/request.ts +196 -85
  393. package/test/unit/spec/roap/turnDiscovery.ts +30 -7
  394. package/test/unit/spec/stats-analyzer/index.js +92 -41
  395. package/test/utils/constants.js +9 -0
  396. package/test/utils/integrationTestUtils.js +46 -0
  397. package/test/utils/testUtils.js +0 -45
  398. package/test/utils/webex-config.js +4 -0
  399. package/test/utils/webex-test-users.js +6 -3
  400. package/dist/meeting/effectsState.js +0 -262
  401. package/dist/meeting/effectsState.js.map +0 -1
  402. package/dist/metrics/config.js +0 -299
  403. package/dist/metrics/config.js.map +0 -1
  404. package/dist/multistream/multistreamMedia.js +0 -110
  405. package/dist/multistream/multistreamMedia.js.map +0 -1
  406. package/src/index.js +0 -15
  407. package/src/meeting/effectsState.ts +0 -211
  408. package/src/metrics/config.ts +0 -495
  409. package/src/multistream/multistreamMedia.ts +0 -97
  410. package/test/unit/spec/meeting/effectsState.js +0 -285
@@ -11,6 +11,7 @@ import sinon from 'sinon';
11
11
  import uuid from 'uuid';
12
12
  import StaticConfig from '@webex/plugin-meetings/src/common/config';
13
13
  import TriggerProxy from '@webex/plugin-meetings/src/common/events/trigger-proxy';
14
+ import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
14
15
  import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
15
16
  import Meeting from '@webex/plugin-meetings/src/meeting';
16
17
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
@@ -29,6 +30,11 @@ import {
29
30
  LOCUSINFO,
30
31
  EVENT_TRIGGERS,
31
32
  } from '../../../../src/constants';
33
+ import CaptchaError from '@webex/plugin-meetings/src/common/errors/captcha-error';
34
+ import { forEach } from 'lodash';
35
+ import PasswordError from '@webex/plugin-meetings/src/common/errors/password-error';
36
+ import PermissionError from '@webex/plugin-meetings/src/common/errors/permission';
37
+ import {NoiseReductionEffect,VirtualBackgroundEffect} from '@webex/media-helpers';
32
38
 
33
39
  describe('plugin-meetings', () => {
34
40
  const logger = {
@@ -60,15 +66,20 @@ describe('plugin-meetings', () => {
60
66
  let url1;
61
67
  let test1;
62
68
  let test2;
69
+ let locusInfo;
63
70
 
64
71
  describe('meetings index', () => {
65
72
  beforeEach(() => {
66
73
  MeetingsUtil.checkH264Support = sinon.stub();
67
- uuid1 = uuid.v4();
74
+ uuid1 = uuid.v4();
68
75
  url1 = `https://example.com/${uuid.v4()}`;
69
76
  uri1 = `test-${uuid.v4()}@example.com`;
70
77
  test1 = `test-${uuid.v4()}`;
71
78
  test2 = `test2-${uuid.v4()}`;
79
+ locusInfo = {
80
+ parse: sinon.stub().returns(true),
81
+ updateMainSessionLocusCache: sinon.stub(),
82
+ };
72
83
  webex = new MockWebex({
73
84
  children: {
74
85
  device: Device,
@@ -151,6 +162,10 @@ describe('plugin-meetings', () => {
151
162
  webex.emit('ready');
152
163
  });
153
164
 
165
+ afterEach(() => {
166
+ sinon.restore();
167
+ });
168
+
154
169
  it('has a webex instance with a meetings property', () => {
155
170
  assert.exists(webex, 'webex was initialized with children');
156
171
  assert.exists(webex.meetings, 'meetings child was set up on the webex instance');
@@ -338,6 +353,100 @@ describe('plugin-meetings', () => {
338
353
  });
339
354
  });
340
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
+
341
450
  describe('gets', () => {
342
451
  describe('#getReachability', () => {
343
452
  it('should have #getReachability', () => {
@@ -443,21 +552,17 @@ describe('plugin-meetings', () => {
443
552
  );
444
553
  });
445
554
  describe('when meeting is returned', () => {
446
- let parse;
447
555
 
448
556
  beforeEach(() => {
449
- parse = sinon.stub().returns(true);
450
557
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
451
- locusInfo: {
452
- parse,
453
- },
558
+ locusInfo,
454
559
  });
455
560
  });
456
561
  it('tests the sync meeting calls for existing meeting', async () => {
457
562
  await webex.meetings.syncMeetings();
458
563
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
459
564
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
460
- assert.calledOnce(parse);
565
+ assert.calledOnce(locusInfo.parse);
461
566
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
462
567
  });
463
568
  });
@@ -470,6 +575,7 @@ describe('plugin-meetings', () => {
470
575
  webex.meetings.create = sinon.stub().returns(
471
576
  Promise.resolve({
472
577
  locusInfo: {
578
+ ...locusInfo,
473
579
  initialSetup,
474
580
  },
475
581
  })
@@ -478,7 +584,7 @@ describe('plugin-meetings', () => {
478
584
  it('tests the sync meeting calls for not existing meeting', async () => {
479
585
  await webex.meetings.syncMeetings();
480
586
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
481
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
587
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
482
588
  assert.calledOnce(initialSetup);
483
589
  assert.calledOnce(webex.meetings.create);
484
590
  assert.calledWith(webex.meetings.request.getActiveMeetings);
@@ -502,12 +608,9 @@ describe('plugin-meetings', () => {
502
608
 
503
609
  beforeEach(() => {
504
610
  destroySpy = sinon.spy(webex.meetings, 'destroy');
505
- parse = sinon.stub().returns(true);
506
611
  initialSetup = sinon.stub().returns(true);
507
612
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
508
- locusInfo: {
509
- parse,
510
- },
613
+ locusInfo,
511
614
  sendCallAnalyzerMetrics: sinon.stub(),
512
615
  });
513
616
  webex.meetings.meetingCollection.getAll = sinon.stub().returns({
@@ -581,7 +684,18 @@ describe('plugin-meetings', () => {
581
684
  assert.exists(create.then);
582
685
  await create;
583
686
  assert.calledOnce(webex.meetings.createMeeting);
584
- assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY);
687
+ assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, {});
688
+ });
689
+
690
+ it('calls createMeeting with extra info params and returns its promise', async () => {
691
+ const FAKE_USE_RANDOM_DELAY = false;
692
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
693
+ const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS);
694
+
695
+ assert.exists(create.then);
696
+ await create;
697
+ assert.calledOnce(webex.meetings.createMeeting);
698
+ assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS);
585
699
  });
586
700
 
587
701
  it('creates a new meeting when a scheduled meeting exists in the conversation', async () => {
@@ -677,45 +791,52 @@ describe('plugin-meetings', () => {
677
791
  });
678
792
  describe('#handleLocusEvent', () => {
679
793
  describe('there was a meeting', () => {
680
- let parse;
681
794
 
682
795
  beforeEach(() => {
683
- parse = sinon.stub().returns(true);
684
796
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
685
- locusInfo: {
686
- parse,
687
- },
797
+ locusInfo,
688
798
  });
689
799
  });
690
- it('should parse the meeting info', () => {
800
+ it('should parse the meeting info and update main session locus cache', () => {
801
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(false);
691
802
  webex.meetings.handleLocusEvent({
692
803
  locusUrl: url1,
693
804
  });
694
805
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
695
806
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
696
- assert.calledOnce(parse);
807
+ assert.calledOnce(locusInfo.parse);
808
+ assert.calledOnce(locusInfo.updateMainSessionLocusCache);
697
809
  assert.calledWith(
698
- parse,
810
+ locusInfo.parse,
699
811
  {
700
- locusInfo: {
701
- parse,
702
- },
812
+ locusInfo,
703
813
  },
704
814
  {
705
815
  locusUrl: url1,
706
816
  }
707
817
  );
708
818
  });
819
+
820
+ it('should not update main session locus cache', () => {
821
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(true);
822
+ webex.meetings.handleLocusEvent({
823
+ locusUrl: url1,
824
+ });
825
+ assert.notCalled(locusInfo.updateMainSessionLocusCache);
826
+ });
709
827
  });
710
828
  describe('there was not a meeting', () => {
711
829
  let initialSetup;
830
+ const webExMeetingId = '123456';
712
831
 
713
832
  beforeEach(() => {
714
833
  initialSetup = sinon.stub().returns(true);
715
834
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
716
835
  webex.meetings.create = sinon.stub().returns(
717
836
  Promise.resolve({
837
+ id: 'meeting-id',
718
838
  locusInfo: {
839
+ ...locusInfo,
719
840
  initialSetup,
720
841
  },
721
842
  })
@@ -735,12 +856,16 @@ describe('plugin-meetings', () => {
735
856
  callbackAddress: uri1,
736
857
  },
737
858
  },
859
+ info: {
860
+ webExMeetingId
861
+ },
738
862
  },
739
863
  eventType: 'locus.difference',
740
864
  locusUrl: url1,
741
865
  });
742
- assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
866
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 6);
743
867
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
868
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
744
869
  assert.calledOnce(initialSetup);
745
870
  assert.calledWith(initialSetup, {
746
871
  id: uuid1,
@@ -754,6 +879,9 @@ describe('plugin-meetings', () => {
754
879
  callbackAddress: uri1,
755
880
  },
756
881
  },
882
+ info: {
883
+ webExMeetingId
884
+ },
757
885
  });
758
886
  });
759
887
  it('should setup the meeting by difference event without replaces', async () => {
@@ -765,12 +893,16 @@ describe('plugin-meetings', () => {
765
893
  callbackAddress: uri1,
766
894
  },
767
895
  },
896
+ info: {
897
+ webExMeetingId
898
+ },
768
899
  },
769
900
  eventType: 'locus.difference',
770
901
  locusUrl: url1,
771
902
  });
772
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
903
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
773
904
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
905
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
774
906
  assert.calledOnce(initialSetup);
775
907
  assert.calledWith(initialSetup, {
776
908
  id: uuid1,
@@ -779,8 +911,44 @@ describe('plugin-meetings', () => {
779
911
  callbackAddress: uri1,
780
912
  },
781
913
  },
914
+ info: {
915
+ webExMeetingId
916
+ },
917
+ });
918
+ });
919
+
920
+ it('sends client event correctly on finally', async () => {
921
+ webex.meetings.getMeetingByType = sinon.stub().returns(true);
922
+
923
+ await webex.meetings.handleLocusEvent({
924
+ locus: {
925
+ id: uuid1,
926
+ self: {
927
+ callBackInfo: {
928
+ callbackAddress: uri1,
929
+ },
930
+ },
931
+ info: {
932
+ webExMeetingId,
933
+ },
934
+ },
935
+ eventType: 'locus.difference',
936
+ locusUrl: url1,
937
+ });
938
+
939
+ await testUtils.flushPromises();
940
+
941
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
942
+ name: 'client.call.remote-started',
943
+ payload: {
944
+ trigger: 'mercury-event',
945
+ },
946
+ options: {
947
+ meetingId: 'meeting-id',
948
+ },
782
949
  });
783
950
  });
951
+
784
952
  it('should setup the meeting by a not difference event', async () => {
785
953
  await webex.meetings.handleLocusEvent({
786
954
  locus: {
@@ -790,12 +958,16 @@ describe('plugin-meetings', () => {
790
958
  callbackAddress: uri1,
791
959
  },
792
960
  },
961
+ info: {
962
+ webExMeetingId
963
+ },
793
964
  },
794
965
  eventType: test1,
795
966
  locusUrl: url1,
796
967
  });
797
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
968
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
798
969
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
970
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
799
971
  assert.calledOnce(initialSetup);
800
972
  assert.calledWith(initialSetup, {
801
973
  id: uuid1,
@@ -804,6 +976,9 @@ describe('plugin-meetings', () => {
804
976
  callbackAddress: uri1,
805
977
  },
806
978
  },
979
+ info: {
980
+ webExMeetingId
981
+ },
807
982
  });
808
983
  });
809
984
 
@@ -826,7 +1001,7 @@ describe('plugin-meetings', () => {
826
1001
 
827
1002
  it('should not try to match USM meetings by conversation url', async () => {
828
1003
  await webex.meetings.handleLocusEvent(generateFakeLocusData(true));
829
- assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
1004
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
830
1005
  assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, [
831
1006
  'locusUrl',
832
1007
  url1,
@@ -843,7 +1018,7 @@ describe('plugin-meetings', () => {
843
1018
  });
844
1019
  it('should try to match non-USM meetings by conversation url', async () => {
845
1020
  await webex.meetings.handleLocusEvent(generateFakeLocusData(false));
846
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1021
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
847
1022
  assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, [
848
1023
  'locusUrl',
849
1024
  url1,
@@ -874,6 +1049,7 @@ describe('plugin-meetings', () => {
874
1049
  });
875
1050
  describe('successful MeetingInfo.#fetchMeetingInfo', () => {
876
1051
  let clock, setTimeoutSpy, fakeMeetingStartTimeString, FAKE_TIME_TO_START;
1052
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
877
1053
 
878
1054
  beforeEach(() => {
879
1055
  clock = sinon.useFakeTimers();
@@ -903,13 +1079,14 @@ describe('plugin-meetings', () => {
903
1079
  meeting,
904
1080
  destination,
905
1081
  type,
1082
+ extraParams = {},
906
1083
  expectedMeetingData = {}
907
1084
  ) => {
908
1085
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
909
1086
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
910
1087
  assert.notCalled(setTimeoutSpy);
911
1088
  assert.calledThrice(TriggerProxy.trigger);
912
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type);
1089
+ assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type, null, null, undefined, undefined, extraParams, {meetingId: meeting.id});
913
1090
  assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
914
1091
 
915
1092
  if (expectedMeetingData.permissionToken) {
@@ -949,106 +1126,116 @@ describe('plugin-meetings', () => {
949
1126
  meetingJoinUrl: 'meetingJoinUrl',
950
1127
  };
951
1128
 
952
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
1129
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
953
1130
  });
954
1131
 
955
- it('creates the meeting from a successful meeting info fetch meeting resolve testing', async () => {
956
- const meeting = await webex.meetings.createMeeting('test destination', 'test type');
957
- const expectedMeetingData = {
958
- permissionToken: 'PT',
959
- meetingJoinUrl: 'meetingJoinUrl',
960
- };
1132
+ [undefined, FAKE_INFO_EXTRA_PARAMS].forEach((infoExtraParams) => {
1133
+ const infoExtraParamsProvided = infoExtraParams !== undefined;
961
1134
 
962
- assert.instanceOf(
963
- meeting,
964
- Meeting,
965
- 'createMeeting should eventually resolve to a Meeting Object'
966
- );
967
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
968
- });
1135
+ it(`creates the meeting from a successful meeting info fetch meeting resolve testing${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1136
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, infoExtraParams);
1137
+ const expectedMeetingData = {
1138
+ permissionToken: 'PT',
1139
+ meetingJoinUrl: 'meetingJoinUrl',
1140
+ };
969
1141
 
970
- it('creates the meeting from a successful meeting info fetch with random delay', async () => {
971
- const FAKE_LOCUS_MEETING = {
972
- conversationUrl: 'locusConvURL',
973
- url: 'locusUrl',
974
- info: {
975
- webExMeetingId: 'locusMeetingId',
976
- sipUri: 'locusSipUri',
977
- owner: 'locusOwner',
978
- },
979
- meeting: {
980
- startTime: fakeMeetingStartTimeString,
981
- },
982
- fullState: {
983
- active: false,
984
- },
985
- };
1142
+ assert.instanceOf(
1143
+ meeting,
1144
+ Meeting,
1145
+ 'createMeeting should eventually resolve to a Meeting Object'
1146
+ );
1147
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', infoExtraParamsProvided ? infoExtraParams : {}, expectedMeetingData);
1148
+ });
986
1149
 
987
- const meeting = await webex.meetings.createMeeting(
988
- FAKE_LOCUS_MEETING,
989
- 'test type',
990
- true
991
- );
1150
+ it(`creates the meeting from a successful meeting info fetch with random delay${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1151
+ const FAKE_LOCUS_MEETING = {
1152
+ conversationUrl: 'locusConvURL',
1153
+ url: 'locusUrl',
1154
+ info: {
1155
+ webExMeetingId: 'locusMeetingId',
1156
+ sipUri: 'locusSipUri',
1157
+ owner: 'locusOwner',
1158
+ },
1159
+ meeting: {
1160
+ startTime: fakeMeetingStartTimeString,
1161
+ },
1162
+ fullState: {
1163
+ active: false,
1164
+ },
1165
+ };
992
1166
 
993
- assert.instanceOf(
994
- meeting,
995
- Meeting,
996
- 'createMeeting should eventually resolve to a Meeting Object'
997
- );
998
- assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
999
- assert.calledOnce(setTimeoutSpy);
1000
-
1001
- // Parse meeting info with locus object
1002
- assert.equal(meeting.conversationUrl, 'locusConvURL');
1003
- assert.equal(meeting.locusUrl, 'locusUrl');
1004
- assert.equal(meeting.sipUri, 'locusSipUri');
1005
- assert.equal(meeting.meetingNumber, 'locusMeetingId');
1006
- assert.isUndefined(meeting.meetingJoinUrl);
1007
- assert.equal(meeting.owner, 'locusOwner');
1008
- assert.isUndefined(meeting.permissionToken);
1009
-
1010
- // Add meeting and send trigger
1011
- assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1012
- assert.calledTwice(TriggerProxy.trigger);
1013
- assert.calledWith(
1014
- TriggerProxy.trigger,
1015
- sinon.match.instanceOf(Meetings),
1016
- {
1017
- file: 'meetings',
1018
- function: 'createMeeting',
1019
- },
1020
- 'meeting:added',
1021
- {
1022
- meeting: sinon.match.instanceOf(Meeting),
1023
- type: 'test meeting added type',
1024
- }
1025
- );
1167
+ const meeting = await webex.meetings.createMeeting(
1168
+ FAKE_LOCUS_MEETING,
1169
+ 'test type',
1170
+ true,
1171
+ infoExtraParams
1172
+ );
1026
1173
 
1027
- // When timer expires
1028
- clock.tick(FAKE_TIME_TO_START);
1029
- assert.calledWith(
1030
- webex.meetings.meetingInfo.fetchMeetingInfo,
1031
- FAKE_LOCUS_MEETING,
1032
- 'test type'
1033
- );
1174
+ assert.instanceOf(
1175
+ meeting,
1176
+ Meeting,
1177
+ 'createMeeting should eventually resolve to a Meeting Object'
1178
+ );
1179
+ assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
1180
+ assert.calledOnce(setTimeoutSpy);
1181
+
1182
+ // Parse meeting info with locus object
1183
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1184
+ assert.equal(meeting.locusUrl, 'locusUrl');
1185
+ assert.equal(meeting.sipUri, 'locusSipUri');
1186
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1187
+ assert.isUndefined(meeting.meetingJoinUrl);
1188
+ assert.equal(meeting.owner, 'locusOwner');
1189
+ assert.isUndefined(meeting.permissionToken);
1190
+
1191
+ // Add meeting and send trigger
1192
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1193
+ assert.calledTwice(TriggerProxy.trigger);
1194
+ assert.calledWith(
1195
+ TriggerProxy.trigger,
1196
+ sinon.match.instanceOf(Meetings),
1197
+ {
1198
+ file: 'meetings',
1199
+ function: 'createMeeting',
1200
+ },
1201
+ 'meeting:added',
1202
+ {
1203
+ meeting: sinon.match.instanceOf(Meeting),
1204
+ type: 'test meeting added type',
1205
+ }
1206
+ );
1034
1207
 
1035
- // Parse meeting info is called again with new meeting info
1036
- await testUtils.flushPromises();
1037
- assert.equal(meeting.conversationUrl, 'locusConvURL');
1038
- assert.equal(meeting.locusUrl, 'locusUrl');
1039
- assert.equal(meeting.sipUri, 'locusSipUri');
1040
- assert.equal(meeting.meetingNumber, 'locusMeetingId');
1041
- assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
1042
- assert.equal(meeting.owner, 'locusOwner');
1043
- assert.equal(meeting.permissionToken, 'PT');
1208
+ // When timer expires
1209
+ clock.tick(FAKE_TIME_TO_START);
1210
+ assert.calledWith(
1211
+ webex.meetings.meetingInfo.fetchMeetingInfo,
1212
+ FAKE_LOCUS_MEETING,
1213
+ 'test type',
1214
+ null,
1215
+ null,
1216
+ undefined,
1217
+ undefined,
1218
+ infoExtraParamsProvided ? infoExtraParams : {}
1219
+ );
1044
1220
 
1045
- assert.calledWith(
1046
- TriggerProxy.trigger,
1047
- meeting,
1048
- {file: 'meetings', function: 'fetchMeetingInfo'},
1049
- 'meeting:meetingInfoAvailable'
1050
- );
1051
- });
1221
+ // Parse meeting info is called again with new meeting info
1222
+ await testUtils.flushPromises();
1223
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1224
+ assert.equal(meeting.locusUrl, 'locusUrl');
1225
+ assert.equal(meeting.sipUri, 'locusSipUri');
1226
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1227
+ assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
1228
+ assert.equal(meeting.owner, 'locusOwner');
1229
+ assert.equal(meeting.permissionToken, 'PT');
1230
+
1231
+ assert.calledWith(
1232
+ TriggerProxy.trigger,
1233
+ meeting,
1234
+ {file: 'meetings', function: 'fetchMeetingInfo'},
1235
+ 'meeting:meetingInfoAvailable'
1236
+ );
1237
+ });
1238
+ })
1052
1239
 
1053
1240
  it('creates the meeting from a successful meeting info fetch that has no random delay because it is active', async () => {
1054
1241
  const FAKE_LOCUS_MEETING = {
@@ -1189,6 +1376,63 @@ describe('plugin-meetings', () => {
1189
1376
  );
1190
1377
  });
1191
1378
  });
1379
+
1380
+ describe('rejected MeetingInfo.#fetchMeetingInfo - does not log for known Error types', () => {
1381
+ forEach(
1382
+ [
1383
+ {
1384
+ error: new CaptchaError(),
1385
+ debugLogMessage:
1386
+ 'Meetings:index#createMeeting --> Debug CaptchaError: Captcha is required. fetching /meetingInfo for creation.',
1387
+ },
1388
+ {
1389
+ error: new PasswordError(),
1390
+ debugLogMessage:
1391
+ 'Meetings:index#createMeeting --> Debug PasswordError: Password is required, please use verifyPassword() fetching /meetingInfo for creation.',
1392
+ },
1393
+ {
1394
+ error: new PermissionError(),
1395
+ debugLogMessage:
1396
+ 'Meetings:index#createMeeting --> Debug PermissionError: Not allowed to execute the function, some properties on server, or local client state do not allow you to complete this action. fetching /meetingInfo for creation.',
1397
+ },
1398
+ {
1399
+ error: new Error(),
1400
+ infoLogMessage: true,
1401
+ debugLogMessage:
1402
+ 'Meetings:index#createMeeting --> Debug Error fetching /meetingInfo for creation.',
1403
+ },
1404
+ ],
1405
+ ({error, debugLogMessage, infoLogMessage}) => {
1406
+ it('creates the meeting from a rejected meeting info fetch', async () => {
1407
+ webex.meetings.meetingInfo.fetchMeetingInfo = sinon
1408
+ .stub()
1409
+ .returns(Promise.reject(error));
1410
+
1411
+ LoggerProxy.logger.debug = sinon.stub();
1412
+ LoggerProxy.logger.info = sinon.stub();
1413
+
1414
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type');
1415
+
1416
+ assert.instanceOf(
1417
+ meeting,
1418
+ Meeting,
1419
+ 'createMeeting should eventually resolve to a Meeting Object'
1420
+ );
1421
+
1422
+ assert.calledWith(LoggerProxy.logger.debug, debugLogMessage);
1423
+
1424
+ if (infoLogMessage) {
1425
+ assert.calledWith(
1426
+ LoggerProxy.logger.info,
1427
+ 'Meetings:index#createMeeting --> Info Unable to fetch meeting info for test destination.'
1428
+ );
1429
+ } else {
1430
+ assert.notCalled(LoggerProxy.logger.info);
1431
+ }
1432
+ });
1433
+ }
1434
+ );
1435
+ });
1192
1436
  });
1193
1437
  });
1194
1438
  describe('Public Event Triggers', () => {
@@ -1267,6 +1511,9 @@ describe('plugin-meetings', () => {
1267
1511
  });
1268
1512
 
1269
1513
  describe('#fetchUserPreferredWebexSite', () => {
1514
+
1515
+ let loggerProxySpy;
1516
+
1270
1517
  it('should call request.getMeetingPreferences to get the preferred webex site ', async () => {
1271
1518
  assert.isDefined(webex.meetings.preferredWebexSite);
1272
1519
  await webex.meetings.fetchUserPreferredWebexSite();
@@ -1274,7 +1521,24 @@ describe('plugin-meetings', () => {
1274
1521
  assert.equal(webex.meetings.preferredWebexSite, 'go.webex.com');
1275
1522
  });
1276
1523
 
1524
+ const setup = ({user} = {}) => {
1525
+ loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
1526
+
1527
+ Object.assign(webex.internal, {
1528
+ services: {
1529
+ getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
1530
+ },
1531
+ user: {
1532
+ get: sinon.stub().returns(
1533
+ Promise.resolve(user)
1534
+ ),
1535
+ },
1536
+ });
1537
+ }
1538
+
1277
1539
  it('should not fail if UserPreferred info is not fetched ', async () => {
1540
+ setup();
1541
+
1278
1542
  Object.assign(webex.internal, {
1279
1543
  services: {
1280
1544
  getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
@@ -1284,7 +1548,62 @@ describe('plugin-meetings', () => {
1284
1548
  await webex.meetings.fetchUserPreferredWebexSite().then(() => {
1285
1549
  assert.equal(webex.meetings.preferredWebexSite, '');
1286
1550
  });
1551
+ assert.calledOnceWithExactly(
1552
+ loggerProxySpy,
1553
+ 'Failed to fetch preferred site from user - no site will be set'
1554
+ );
1555
+ });
1556
+
1557
+ it('should fall back to fetching the site from the user', async () => {
1558
+ setup({
1559
+ user: {
1560
+ userPreferences: {
1561
+ userPreferencesItems: {
1562
+ preferredWebExSite: 'site.webex.com',
1563
+ },
1564
+ },
1565
+ },
1566
+ });
1567
+
1568
+ await webex.meetings.fetchUserPreferredWebexSite();
1569
+
1570
+ assert.equal(webex.meetings.preferredWebexSite, 'site.webex.com');
1571
+ assert.notCalled(loggerProxySpy);
1572
+ });
1573
+
1574
+ forEach([
1575
+ {user: undefined},
1576
+ {user: {userPreferences: {}}},
1577
+ {user: {userPreferences: {userPreferencesItems: {}}}},
1578
+ {user: {userPreferences: {userPreferencesItems: {preferredWebExSite: undefined}}}},
1579
+ ], ({user}) => {
1580
+ it(`should handle invalid user data ${user}`, async () => {
1581
+ setup({user});
1582
+
1583
+ await webex.meetings.fetchUserPreferredWebexSite();
1584
+
1585
+ assert.equal(webex.meetings.preferredWebexSite, '');
1586
+ assert.calledOnceWithExactly(
1587
+ loggerProxySpy,
1588
+ 'Failed to fetch preferred site from user - no site will be set'
1589
+ );
1590
+ });
1591
+ });
1592
+
1593
+ it('should handle a get user failure', async () => {
1594
+ setup();
1595
+
1596
+ webex.internal.user.get.rejects(new Error());
1597
+
1598
+ await webex.meetings.fetchUserPreferredWebexSite();
1599
+
1600
+ assert.equal(webex.meetings.preferredWebexSite, '');
1601
+ assert.calledOnceWithExactly(
1602
+ loggerProxySpy,
1603
+ 'Failed to fetch preferred site from user - no site will be set'
1604
+ );
1287
1605
  });
1606
+
1288
1607
  });
1289
1608
  });
1290
1609
 
@@ -1368,5 +1687,411 @@ describe('plugin-meetings', () => {
1368
1687
  );
1369
1688
  });
1370
1689
  });
1690
+
1691
+ describe('#isNeedHandleMainLocus', () => {
1692
+ let meeting;
1693
+ let newLocus;
1694
+ beforeEach(() => {
1695
+ meeting = {
1696
+ controls: {},
1697
+ self: {},
1698
+ };
1699
+ newLocus = {
1700
+ controls: {},
1701
+ self: {},
1702
+ }
1703
+ });
1704
+ afterEach(() => {
1705
+ sinon.restore();
1706
+ });
1707
+ it('check normal case will return true', () => {
1708
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns(null);
1709
+ LoggerProxy.logger.log = sinon.stub();
1710
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1711
+ assert.equal(result, true);
1712
+ assert.calledWith(
1713
+ LoggerProxy.logger.log,
1714
+ 'Meetings:index#isNeedHandleMainLocus --> this is a normal main session locusDTO update case'
1715
+ );
1716
+ });
1717
+
1718
+ it('check self joined and joined on this device, return true', () => {
1719
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns(null);
1720
+ newLocus.self.state = 'JOINED';
1721
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(true);
1722
+
1723
+ LoggerProxy.logger.log = sinon.stub();
1724
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1725
+ assert.equal(result, true);
1726
+ assert.calledWith(
1727
+ LoggerProxy.logger.log,
1728
+ 'Meetings:index#isNeedHandleMainLocus --> self this device shown as JOINED in the main session'
1729
+ );
1730
+ });
1731
+
1732
+ it('if newLocus replaceAt time is expired, then return false', () => {
1733
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({joinedWith: {replaces: [{
1734
+ replaceAt: '2023-03-27T02:17:02.506Z',
1735
+ }]}});
1736
+ newLocus.self.state = 'JOINED';
1737
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(true);
1738
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1739
+ replaces: [{
1740
+ replaceAt: '2023-03-27T02:17:01.506Z'
1741
+ }]
1742
+ })
1743
+
1744
+ LoggerProxy.logger.log = sinon.stub();
1745
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1746
+ assert.equal(result, false);
1747
+ assert.calledWith(
1748
+ LoggerProxy.logger.log,
1749
+ `Meetings:index#isNeedHandleMainLocus --> this is expired main joined status locus_dto replacedAt 2023-03-27T02:17:01.506Z bo replacedAt 2023-03-27T02:17:02.506Z`
1750
+ );
1751
+ });
1752
+
1753
+ it('check current is in breakout join with this device, return false', () => {
1754
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({
1755
+ joinedWith: {
1756
+ correlationId: '111',
1757
+ },
1758
+ });
1759
+ newLocus.controls.breakout = {url: 'url'};
1760
+ meeting.correlationId = '111';
1761
+
1762
+ LoggerProxy.logger.log = sinon.stub();
1763
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1764
+ assert.equal(result, false);
1765
+ assert.calledWith(
1766
+ LoggerProxy.logger.log,
1767
+ `Meetings:index#isNeedHandleMainLocus --> there is active breakout session and joined on this device, and don't need to handle main session: url`
1768
+ );
1769
+ });
1770
+
1771
+ it('check self is moved and removed, return false', () => {
1772
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1773
+ newLocus.self.state = 'LEFT';
1774
+ newLocus.self.reason = 'MOVED';
1775
+ newLocus.self.removed = true;
1776
+ LoggerProxy.logger.log = sinon.stub();
1777
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1778
+ assert.equal(result, false);
1779
+ assert.calledWith(
1780
+ LoggerProxy.logger.log,
1781
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1782
+ );
1783
+ });
1784
+
1785
+ it('check self is moved and device resource removed, return false', () => {
1786
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1787
+ newLocus.self.state = 'LEFT';
1788
+ newLocus.self.reason = 'MOVED';
1789
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1790
+ state: 'LEFT',
1791
+ reason: 'MOVED',
1792
+ });
1793
+ LoggerProxy.logger.log = sinon.stub();
1794
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1795
+ assert.equal(result, false);
1796
+ assert.calledWith(
1797
+ LoggerProxy.logger.log,
1798
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1799
+ );
1800
+ });
1801
+
1802
+ it('check self is joined but device resource removed, return false', () => {
1803
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1804
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(false);
1805
+ newLocus.self.state = 'JOINED';
1806
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1807
+ state: 'LEFT',
1808
+ reason: 'MOVED',
1809
+ });
1810
+ LoggerProxy.logger.log = sinon.stub();
1811
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1812
+ assert.equal(result, false);
1813
+ assert.calledWith(
1814
+ LoggerProxy.logger.log,
1815
+ 'Meetings:index#isNeedHandleMainLocus --> self device left&moved in main locus with self joined status, not need to handle'
1816
+ );
1817
+ });
1818
+ });
1819
+
1820
+ describe('#isNeedHandleLocusDTO', () => {
1821
+ let meeting;
1822
+ let newLocus;
1823
+ beforeEach(() => {
1824
+ meeting = {
1825
+ controls: {},
1826
+ self: {},
1827
+ };
1828
+ newLocus = {
1829
+ controls: {},
1830
+ self: {},
1831
+ }
1832
+ });
1833
+ afterEach(() => {
1834
+ sinon.restore();
1835
+ });
1836
+ it('initial DTO , joined breakout session, return true', () => {
1837
+ newLocus.controls.breakout = {
1838
+ sessionType: 'BREAKOUT',
1839
+ };
1840
+ newLocus.self.state = 'JOINED';
1841
+ newLocus.fullState = {
1842
+ active: true,
1843
+ };
1844
+ LoggerProxy.logger.log = sinon.stub();
1845
+ const result = webex.meetings.isNeedHandleLocusDTO(null, newLocus);
1846
+ assert.equal(result, true);
1847
+ assert.calledWith(
1848
+ LoggerProxy.logger.log,
1849
+ `Meetings:index#isNeedHandleLocusDTO --> the first breakout session locusDTO active status: true`
1850
+ );
1851
+ });
1852
+ it('others go to check isNeedHandleMainLocus', () => {
1853
+ newLocus.controls.breakout = {
1854
+ sessionType: 'MAIN',
1855
+ };
1856
+ newLocus.self.state = 'JOINED';
1857
+
1858
+ LoggerProxy.logger.log = sinon.stub();
1859
+ const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
1860
+ assert.equal(result, true);
1861
+ assert.calledWith(
1862
+ LoggerProxy.logger.log,
1863
+ 'Meetings:index#isNeedHandleMainLocus --> this is a normal main session locusDTO update case'
1864
+ );
1865
+ });
1866
+ it('joined breakout session, self status is moved, return false', () => {
1867
+ newLocus.controls.breakout = {
1868
+ sessionType: 'BREAKOUT',
1869
+ };
1870
+ newLocus.self.state = 'LEFT';
1871
+ newLocus.self.reason = 'MOVED';
1872
+
1873
+ LoggerProxy.logger.log = sinon.stub();
1874
+ const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
1875
+ assert.equal(result, false);
1876
+ });
1877
+ });
1878
+
1879
+ describe('#getCorrespondingMeetingByLocus', () => {
1880
+ let locus;
1881
+ let mockReturnMeeting = {meeting: 'meeting1'};
1882
+ const mockGetByKey = (keyWillReturnMeeting) => {
1883
+ webex.meetings.meetingCollection.getByKey = sinon.stub().callsFake((key) => {
1884
+ if (key === keyWillReturnMeeting) {
1885
+ return mockReturnMeeting;
1886
+ }
1887
+ return null;
1888
+ });
1889
+ };
1890
+
1891
+ beforeEach(() => {
1892
+ locus = {
1893
+ controls: {},
1894
+ self: {
1895
+ callbackInfo: {
1896
+ callbackAddress: 'address1',
1897
+ }
1898
+ },
1899
+ info: {
1900
+ webExMeetingId: '123456',
1901
+ isUnifiedSpaceMeeting: false,
1902
+ },
1903
+ conversationUrl: 'conversationUrl1'
1904
+ };
1905
+
1906
+ sinon.stub(MeetingsUtil, 'checkForCorrelationId').returns('correlationId1');
1907
+ });
1908
+ afterEach(() => {
1909
+ sinon.restore();
1910
+ });
1911
+ it('check the calls when no meeting found in meetingCollection', () => {
1912
+ mockGetByKey();
1913
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1914
+ assert.isNull(result);
1915
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1916
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1917
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1918
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1919
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1920
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1921
+ });
1922
+
1923
+ it('not try getByKey "conversationUrl" when isUnifiedSpaceMeeting is true', () => {
1924
+ mockGetByKey();
1925
+ locus.info.isUnifiedSpaceMeeting = true;
1926
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1927
+ assert.isNull(result);
1928
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1929
+ })
1930
+
1931
+ it('check the calls when meeting found by key: locusUrl', () => {
1932
+ mockGetByKey('locusUrl');
1933
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1934
+ assert.deepEqual(result, mockReturnMeeting);
1935
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 1);
1936
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1937
+ });
1938
+
1939
+ it('check the calls when meeting found by key: correlationId', () => {
1940
+ mockGetByKey('correlationId');
1941
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1942
+ assert.deepEqual(result, mockReturnMeeting);
1943
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 2);
1944
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1945
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1946
+ });
1947
+
1948
+ it('check the calls when meeting found by key: sipUri', () => {
1949
+ mockGetByKey('sipUri');
1950
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1951
+ assert.deepEqual(result, mockReturnMeeting);
1952
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
1953
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1954
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1955
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1956
+ });
1957
+
1958
+ it('check the calls when meeting found by key: conversationUrl', () => {
1959
+ mockGetByKey('conversationUrl');
1960
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1961
+ assert.deepEqual(result, mockReturnMeeting);
1962
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1963
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1964
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1965
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1966
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1967
+ });
1968
+
1969
+ it('check the calls when meeting found by key: meetingNumber', () => {
1970
+ mockGetByKey('meetingNumber');
1971
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1972
+ assert.deepEqual(result, mockReturnMeeting);
1973
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1974
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1975
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1976
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1977
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1978
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1979
+ });
1980
+ });
1981
+
1982
+ describe('#sortLocusArrayToUpdate', () => {
1983
+ let lociArray;
1984
+ let mainLocus;
1985
+ let breakoutLocus;
1986
+ beforeEach(() => {
1987
+ mainLocus = {
1988
+ url: 'mainUrl1',
1989
+ controls: {
1990
+ breakout: {
1991
+ sessionType: 'MAIN',
1992
+ url: 'breakoutUnifiedUrl1'
1993
+ }
1994
+ }
1995
+ };
1996
+ breakoutLocus = {
1997
+ url: 'breakoutUrl1',
1998
+ controls: {
1999
+ breakout: {
2000
+ sessionType: 'BREAKOUT',
2001
+ url: 'breakoutUnifiedUrl1'
2002
+ }
2003
+ }
2004
+ };
2005
+ lociArray = [mainLocus, breakoutLocus];
2006
+
2007
+ sinon.stub(MeetingsUtil, 'isValidBreakoutLocus').callsFake((locus) => {
2008
+ return locus.url === 'breakoutUrl1';
2009
+ });
2010
+ });
2011
+ afterEach(() => {
2012
+ sinon.restore();
2013
+ });
2014
+
2015
+ it('if both main and breakout locus is in array for non-exist meeting, return main locus to create first', () => {
2016
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
2017
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2018
+ assert.deepEqual(result, [mainLocus]);
2019
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, [breakoutLocus]);
2020
+ });
2021
+
2022
+ it('if both main and breakout locus is in array for an exist meeting, return all locus', () => {
2023
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2024
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2025
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2026
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, []);
2027
+ });
2028
+
2029
+ it('if the breakout locus has no associated main locus, return all', () => {
2030
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2031
+ breakoutLocus.controls.breakout.url = 'testUrl';
2032
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2033
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2034
+ });
2035
+ });
2036
+
2037
+ describe('#checkHandleBreakoutLocus', () => {
2038
+ let breakoutLocus;
2039
+ beforeEach(() => {
2040
+ breakoutLocus = {
2041
+ url: 'breakoutUrl1',
2042
+ controls: {
2043
+ breakout: {
2044
+ sessionType: 'BREAKOUT',
2045
+ url: 'breakoutUnifiedUrl1',
2046
+ }
2047
+ }
2048
+ };
2049
+
2050
+ webex.meetings.handleLocusEvent = sinon.stub();
2051
+ });
2052
+ afterEach(() => {
2053
+ sinon.restore();
2054
+ });
2055
+ it('do nothing if new created locus is null/no cached breakouts for updating', () => {
2056
+ webex.meetings.checkHandleBreakoutLocus(null);
2057
+ webex.meetings.breakoutLocusForHandleLater = null;
2058
+ webex.meetings.checkHandleBreakoutLocus({});
2059
+ webex.meetings.breakoutLocusForHandleLater = [];
2060
+ webex.meetings.checkHandleBreakoutLocus({});
2061
+ assert.notCalled(webex.meetings.handleLocusEvent);
2062
+ });
2063
+
2064
+ it('do nothing if new created locus is breakout locus', () => {
2065
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2066
+ webex.meetings.checkHandleBreakoutLocus(breakoutLocus);
2067
+ assert.notCalled(webex.meetings.handleLocusEvent);
2068
+ });
2069
+
2070
+ it('do nothing if no cached locus is associated with the new created locus', () => {
2071
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2072
+ webex.meetings.checkHandleBreakoutLocus({
2073
+ controls: {
2074
+ breakout: {
2075
+ sessionType: 'MAIN',
2076
+ url: 'breakoutUnifiedUrl2',
2077
+ }
2078
+ }
2079
+ });
2080
+ assert.notCalled(webex.meetings.handleLocusEvent);
2081
+ });
2082
+
2083
+ it('update the cached breakout locus which associate the new created locus', () => {
2084
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2085
+ webex.meetings.checkHandleBreakoutLocus({
2086
+ controls: {
2087
+ breakout: {
2088
+ sessionType: 'MAIN',
2089
+ url: 'breakoutUnifiedUrl1',
2090
+ }
2091
+ }
2092
+ });
2093
+ assert.calledWith(webex.meetings.handleLocusEvent, {locus: breakoutLocus, locusUrl: breakoutLocus.url});
2094
+ });
2095
+ });
1371
2096
  });
1372
2097
  });