@webex/plugin-meetings 3.0.0-beta.3 → 3.0.0-beta.300

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 (601) hide show
  1. package/README.md +46 -8
  2. package/UPGRADING.md +9 -9
  3. package/browsers.js +19 -24
  4. package/dist/annotation/annotation.types.js +7 -0
  5. package/dist/annotation/annotation.types.js.map +1 -0
  6. package/dist/annotation/constants.js +49 -0
  7. package/dist/annotation/constants.js.map +1 -0
  8. package/dist/annotation/index.js +342 -0
  9. package/dist/annotation/index.js.map +1 -0
  10. package/dist/breakouts/breakout.js +216 -0
  11. package/dist/breakouts/breakout.js.map +1 -0
  12. package/dist/breakouts/collection.js +23 -0
  13. package/dist/breakouts/collection.js.map +1 -0
  14. package/dist/breakouts/edit-lock-error.js +52 -0
  15. package/dist/breakouts/edit-lock-error.js.map +1 -0
  16. package/dist/breakouts/events.js +45 -0
  17. package/dist/breakouts/events.js.map +1 -0
  18. package/dist/breakouts/index.js +1048 -0
  19. package/dist/breakouts/index.js.map +1 -0
  20. package/dist/breakouts/request.js +78 -0
  21. package/dist/breakouts/request.js.map +1 -0
  22. package/dist/breakouts/utils.js +67 -0
  23. package/dist/breakouts/utils.js.map +1 -0
  24. package/dist/common/browser-detection.js +1 -20
  25. package/dist/common/browser-detection.js.map +1 -1
  26. package/dist/common/collection.js +5 -20
  27. package/dist/common/collection.js.map +1 -1
  28. package/dist/common/config.js +0 -7
  29. package/dist/common/config.js.map +1 -1
  30. package/dist/common/errors/captcha-error.js +10 -24
  31. package/dist/common/errors/captcha-error.js.map +1 -1
  32. package/dist/common/errors/intent-to-join.js +11 -24
  33. package/dist/common/errors/intent-to-join.js.map +1 -1
  34. package/dist/common/errors/join-meeting.js +12 -25
  35. package/dist/common/errors/join-meeting.js.map +1 -1
  36. package/dist/common/errors/media.js +10 -24
  37. package/dist/common/errors/media.js.map +1 -1
  38. package/dist/common/errors/no-meeting-info.js +51 -0
  39. package/dist/common/errors/no-meeting-info.js.map +1 -0
  40. package/dist/common/errors/parameter.js +5 -33
  41. package/dist/common/errors/parameter.js.map +1 -1
  42. package/dist/common/errors/password-error.js +10 -24
  43. package/dist/common/errors/password-error.js.map +1 -1
  44. package/dist/common/errors/permission.js +9 -23
  45. package/dist/common/errors/permission.js.map +1 -1
  46. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  47. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  48. package/dist/common/errors/reconnection-in-progress.js +0 -17
  49. package/dist/common/errors/reconnection-in-progress.js.map +1 -1
  50. package/dist/common/errors/reconnection.js +10 -24
  51. package/dist/common/errors/reconnection.js.map +1 -1
  52. package/dist/common/errors/stats.js +10 -24
  53. package/dist/common/errors/stats.js.map +1 -1
  54. package/dist/common/errors/webex-errors.js +54 -48
  55. package/dist/common/errors/webex-errors.js.map +1 -1
  56. package/dist/common/errors/webex-meetings-error.js +5 -25
  57. package/dist/common/errors/webex-meetings-error.js.map +1 -1
  58. package/dist/common/events/events-scope.js +0 -22
  59. package/dist/common/events/events-scope.js.map +1 -1
  60. package/dist/common/events/events.js +0 -23
  61. package/dist/common/events/events.js.map +1 -1
  62. package/dist/common/events/trigger-proxy.js +0 -12
  63. package/dist/common/events/trigger-proxy.js.map +1 -1
  64. package/dist/common/events/util.js +0 -15
  65. package/dist/common/events/util.js.map +1 -1
  66. package/dist/common/logs/logger-config.js +0 -4
  67. package/dist/common/logs/logger-config.js.map +1 -1
  68. package/dist/common/logs/logger-proxy.js +1 -8
  69. package/dist/common/logs/logger-proxy.js.map +1 -1
  70. package/dist/common/logs/request.js +41 -60
  71. package/dist/common/logs/request.js.map +1 -1
  72. package/dist/common/queue.js +28 -23
  73. package/dist/common/queue.js.map +1 -1
  74. package/dist/config.js +9 -15
  75. package/dist/config.js.map +1 -1
  76. package/dist/constants.js +315 -68
  77. package/dist/constants.js.map +1 -1
  78. package/dist/controls-options-manager/constants.js +14 -0
  79. package/dist/controls-options-manager/constants.js.map +1 -0
  80. package/dist/controls-options-manager/enums.js +27 -0
  81. package/dist/controls-options-manager/enums.js.map +1 -0
  82. package/dist/controls-options-manager/index.js +297 -0
  83. package/dist/controls-options-manager/index.js.map +1 -0
  84. package/dist/controls-options-manager/types.js +7 -0
  85. package/dist/controls-options-manager/types.js.map +1 -0
  86. package/dist/controls-options-manager/util.js +319 -0
  87. package/dist/controls-options-manager/util.js.map +1 -0
  88. package/dist/index.js +114 -17
  89. package/dist/index.js.map +1 -1
  90. package/dist/interpretation/collection.js +23 -0
  91. package/dist/interpretation/collection.js.map +1 -0
  92. package/dist/interpretation/index.js +366 -0
  93. package/dist/interpretation/index.js.map +1 -0
  94. package/dist/interpretation/siLanguage.js +25 -0
  95. package/dist/interpretation/siLanguage.js.map +1 -0
  96. package/dist/locus-info/controlsUtils.js +101 -29
  97. package/dist/locus-info/controlsUtils.js.map +1 -1
  98. package/dist/locus-info/embeddedAppsUtils.js +3 -26
  99. package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
  100. package/dist/locus-info/fullState.js +0 -15
  101. package/dist/locus-info/fullState.js.map +1 -1
  102. package/dist/locus-info/hostUtils.js +4 -12
  103. package/dist/locus-info/hostUtils.js.map +1 -1
  104. package/dist/locus-info/index.js +561 -246
  105. package/dist/locus-info/index.js.map +1 -1
  106. package/dist/locus-info/infoUtils.js +10 -38
  107. package/dist/locus-info/infoUtils.js.map +1 -1
  108. package/dist/locus-info/mediaSharesUtils.js +68 -38
  109. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  110. package/dist/locus-info/parser.js +314 -163
  111. package/dist/locus-info/parser.js.map +1 -1
  112. package/dist/locus-info/selfUtils.js +110 -92
  113. package/dist/locus-info/selfUtils.js.map +1 -1
  114. package/dist/media/index.js +103 -231
  115. package/dist/media/index.js.map +1 -1
  116. package/dist/media/properties.js +137 -222
  117. package/dist/media/properties.js.map +1 -1
  118. package/dist/media/util.js +2 -9
  119. package/dist/media/util.js.map +1 -1
  120. package/dist/mediaQualityMetrics/config.js +505 -495
  121. package/dist/mediaQualityMetrics/config.js.map +1 -1
  122. package/dist/meeting/in-meeting-actions.js +93 -14
  123. package/dist/meeting/in-meeting-actions.js.map +1 -1
  124. package/dist/meeting/index.js +4624 -3740
  125. package/dist/meeting/index.js.map +1 -1
  126. package/dist/meeting/locusMediaRequest.js +292 -0
  127. package/dist/meeting/locusMediaRequest.js.map +1 -0
  128. package/dist/meeting/muteState.js +249 -184
  129. package/dist/meeting/muteState.js.map +1 -1
  130. package/dist/meeting/request.js +400 -346
  131. package/dist/meeting/request.js.map +1 -1
  132. package/dist/meeting/request.type.js +7 -0
  133. package/dist/meeting/request.type.js.map +1 -0
  134. package/dist/meeting/state.js +21 -31
  135. package/dist/meeting/state.js.map +1 -1
  136. package/dist/meeting/util.js +598 -586
  137. package/dist/meeting/util.js.map +1 -1
  138. package/dist/meeting-info/collection.js +6 -25
  139. package/dist/meeting-info/collection.js.map +1 -1
  140. package/dist/meeting-info/index.js +87 -39
  141. package/dist/meeting-info/index.js.map +1 -1
  142. package/dist/meeting-info/meeting-info-v2.js +349 -283
  143. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  144. package/dist/meeting-info/request.js +3 -15
  145. package/dist/meeting-info/request.js.map +1 -1
  146. package/dist/meeting-info/util.js +98 -183
  147. package/dist/meeting-info/util.js.map +1 -1
  148. package/dist/meeting-info/utilv2.js +143 -234
  149. package/dist/meeting-info/utilv2.js.map +1 -1
  150. package/dist/meetings/collection.js +26 -19
  151. package/dist/meetings/collection.js.map +1 -1
  152. package/dist/meetings/index.js +813 -596
  153. package/dist/meetings/index.js.map +1 -1
  154. package/dist/meetings/meetings.types.js +7 -0
  155. package/dist/meetings/meetings.types.js.map +1 -0
  156. package/dist/meetings/request.js +26 -41
  157. package/dist/meetings/request.js.map +1 -1
  158. package/dist/meetings/util.js +183 -156
  159. package/dist/meetings/util.js.map +1 -1
  160. package/dist/member/index.js +135 -85
  161. package/dist/member/index.js.map +1 -1
  162. package/dist/member/types.js +25 -0
  163. package/dist/member/types.js.map +1 -0
  164. package/dist/member/util.js +158 -88
  165. package/dist/member/util.js.map +1 -1
  166. package/dist/members/collection.js +13 -12
  167. package/dist/members/collection.js.map +1 -1
  168. package/dist/members/index.js +194 -204
  169. package/dist/members/index.js.map +1 -1
  170. package/dist/members/request.js +113 -68
  171. package/dist/members/request.js.map +1 -1
  172. package/dist/members/types.js +15 -0
  173. package/dist/members/types.js.map +1 -0
  174. package/dist/members/util.js +324 -259
  175. package/dist/members/util.js.map +1 -1
  176. package/dist/metrics/constants.js +14 -7
  177. package/dist/metrics/constants.js.map +1 -1
  178. package/dist/metrics/index.js +11 -558
  179. package/dist/metrics/index.js.map +1 -1
  180. package/dist/multistream/mediaRequestManager.js +263 -50
  181. package/dist/multistream/mediaRequestManager.js.map +1 -1
  182. package/dist/multistream/receiveSlot.js +58 -65
  183. package/dist/multistream/receiveSlot.js.map +1 -1
  184. package/dist/multistream/receiveSlotManager.js +76 -95
  185. package/dist/multistream/receiveSlotManager.js.map +1 -1
  186. package/dist/multistream/remoteMedia.js +62 -76
  187. package/dist/multistream/remoteMedia.js.map +1 -1
  188. package/dist/multistream/remoteMediaGroup.js +66 -43
  189. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  190. package/dist/multistream/remoteMediaManager.js +536 -439
  191. package/dist/multistream/remoteMediaManager.js.map +1 -1
  192. package/dist/multistream/sendSlotManager.js +233 -0
  193. package/dist/multistream/sendSlotManager.js.map +1 -0
  194. package/dist/networkQualityMonitor/index.js +40 -59
  195. package/dist/networkQualityMonitor/index.js.map +1 -1
  196. package/dist/personal-meeting-room/index.js +21 -45
  197. package/dist/personal-meeting-room/index.js.map +1 -1
  198. package/dist/personal-meeting-room/request.js +1 -31
  199. package/dist/personal-meeting-room/request.js.map +1 -1
  200. package/dist/personal-meeting-room/util.js +0 -13
  201. package/dist/personal-meeting-room/util.js.map +1 -1
  202. package/dist/reachability/index.js +322 -200
  203. package/dist/reachability/index.js.map +1 -1
  204. package/dist/reachability/request.js +20 -26
  205. package/dist/reachability/request.js.map +1 -1
  206. package/dist/reactions/constants.js +13 -0
  207. package/dist/reactions/constants.js.map +1 -0
  208. package/dist/reactions/reactions.js +109 -0
  209. package/dist/reactions/reactions.js.map +1 -0
  210. package/dist/reactions/reactions.type.js +36 -0
  211. package/dist/reactions/reactions.type.js.map +1 -0
  212. package/dist/reconnection-manager/index.js +388 -476
  213. package/dist/reconnection-manager/index.js.map +1 -1
  214. package/dist/recording-controller/enums.js +17 -0
  215. package/dist/recording-controller/enums.js.map +1 -0
  216. package/dist/recording-controller/index.js +362 -0
  217. package/dist/recording-controller/index.js.map +1 -0
  218. package/dist/recording-controller/util.js +64 -0
  219. package/dist/recording-controller/util.js.map +1 -0
  220. package/dist/roap/index.js +99 -94
  221. package/dist/roap/index.js.map +1 -1
  222. package/dist/roap/request.js +131 -135
  223. package/dist/roap/request.js.map +1 -1
  224. package/dist/roap/turnDiscovery.js +151 -101
  225. package/dist/roap/turnDiscovery.js.map +1 -1
  226. package/dist/rtcMetrics/constants.js +12 -0
  227. package/dist/rtcMetrics/constants.js.map +1 -0
  228. package/dist/rtcMetrics/index.js +117 -0
  229. package/dist/rtcMetrics/index.js.map +1 -0
  230. package/dist/statsAnalyzer/global.js +1 -95
  231. package/dist/statsAnalyzer/global.js.map +1 -1
  232. package/dist/statsAnalyzer/index.js +416 -497
  233. package/dist/statsAnalyzer/index.js.map +1 -1
  234. package/dist/statsAnalyzer/mqaUtil.js +145 -88
  235. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  236. package/dist/transcription/index.js +22 -47
  237. package/dist/transcription/index.js.map +1 -1
  238. package/dist/types/annotation/annotation.types.d.ts +42 -0
  239. package/dist/types/annotation/constants.d.ts +31 -0
  240. package/dist/types/annotation/index.d.ts +117 -0
  241. package/dist/types/breakouts/breakout.d.ts +8 -0
  242. package/dist/types/breakouts/collection.d.ts +5 -0
  243. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  244. package/dist/types/breakouts/events.d.ts +8 -0
  245. package/dist/types/breakouts/index.d.ts +5 -0
  246. package/dist/types/breakouts/request.d.ts +22 -0
  247. package/dist/types/breakouts/utils.d.ts +15 -0
  248. package/dist/types/common/browser-detection.d.ts +9 -0
  249. package/dist/types/common/collection.d.ts +48 -0
  250. package/dist/types/common/config.d.ts +2 -0
  251. package/dist/types/common/errors/captcha-error.d.ts +15 -0
  252. package/dist/types/common/errors/intent-to-join.d.ts +16 -0
  253. package/dist/types/common/errors/join-meeting.d.ts +17 -0
  254. package/dist/types/common/errors/media.d.ts +15 -0
  255. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  256. package/dist/types/common/errors/parameter.d.ts +15 -0
  257. package/dist/types/common/errors/password-error.d.ts +15 -0
  258. package/dist/types/common/errors/permission.d.ts +14 -0
  259. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  260. package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
  261. package/dist/types/common/errors/reconnection.d.ts +15 -0
  262. package/dist/types/common/errors/stats.d.ts +15 -0
  263. package/dist/types/common/errors/webex-errors.d.ts +93 -0
  264. package/dist/types/common/errors/webex-meetings-error.d.ts +20 -0
  265. package/dist/types/common/events/events-scope.d.ts +17 -0
  266. package/dist/types/common/events/events.d.ts +12 -0
  267. package/dist/types/common/events/trigger-proxy.d.ts +2 -0
  268. package/dist/types/common/events/util.d.ts +2 -0
  269. package/dist/types/common/logs/logger-config.d.ts +2 -0
  270. package/dist/types/common/logs/logger-proxy.d.ts +2 -0
  271. package/dist/types/common/logs/request.d.ts +36 -0
  272. package/dist/types/common/queue.d.ts +34 -0
  273. package/dist/types/config.d.ts +71 -0
  274. package/dist/types/constants.d.ts +1066 -0
  275. package/dist/types/controls-options-manager/constants.d.ts +4 -0
  276. package/dist/types/controls-options-manager/enums.d.ts +15 -0
  277. package/dist/types/controls-options-manager/index.d.ts +136 -0
  278. package/dist/types/controls-options-manager/types.d.ts +43 -0
  279. package/dist/types/controls-options-manager/util.d.ts +1 -0
  280. package/dist/types/index.d.ts +7 -0
  281. package/dist/types/interpretation/collection.d.ts +5 -0
  282. package/dist/types/interpretation/index.d.ts +5 -0
  283. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  284. package/dist/types/locus-info/controlsUtils.d.ts +2 -0
  285. package/dist/types/locus-info/embeddedAppsUtils.d.ts +2 -0
  286. package/dist/types/locus-info/fullState.d.ts +2 -0
  287. package/dist/types/locus-info/hostUtils.d.ts +2 -0
  288. package/dist/types/locus-info/index.d.ts +322 -0
  289. package/dist/types/locus-info/infoUtils.d.ts +2 -0
  290. package/dist/types/locus-info/mediaSharesUtils.d.ts +2 -0
  291. package/dist/types/locus-info/parser.d.ts +273 -0
  292. package/dist/types/locus-info/selfUtils.d.ts +2 -0
  293. package/dist/types/media/index.d.ts +34 -0
  294. package/dist/types/media/properties.d.ts +93 -0
  295. package/dist/types/media/util.d.ts +2 -0
  296. package/dist/types/mediaQualityMetrics/config.d.ts +365 -0
  297. package/dist/types/meeting/in-meeting-actions.d.ts +163 -0
  298. package/dist/types/meeting/index.d.ts +1676 -0
  299. package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
  300. package/dist/types/meeting/muteState.d.ts +184 -0
  301. package/dist/types/meeting/request.d.ts +290 -0
  302. package/dist/types/meeting/request.type.d.ts +11 -0
  303. package/dist/types/meeting/state.d.ts +9 -0
  304. package/dist/types/meeting/util.d.ts +102 -0
  305. package/dist/types/meeting-info/collection.d.ts +20 -0
  306. package/dist/types/meeting-info/index.d.ts +69 -0
  307. package/dist/types/meeting-info/meeting-info-v2.d.ts +123 -0
  308. package/dist/types/meeting-info/request.d.ts +22 -0
  309. package/dist/types/meeting-info/util.d.ts +2 -0
  310. package/dist/types/meeting-info/utilv2.d.ts +2 -0
  311. package/dist/types/meetings/collection.d.ts +31 -0
  312. package/dist/types/meetings/index.d.ts +367 -0
  313. package/dist/types/meetings/meetings.types.d.ts +4 -0
  314. package/dist/types/meetings/request.d.ts +27 -0
  315. package/dist/types/meetings/util.d.ts +18 -0
  316. package/dist/types/member/index.d.ts +160 -0
  317. package/dist/types/member/types.d.ts +32 -0
  318. package/dist/types/member/util.d.ts +2 -0
  319. package/dist/types/members/collection.d.ts +29 -0
  320. package/dist/types/members/index.d.ts +353 -0
  321. package/dist/types/members/request.d.ts +114 -0
  322. package/dist/types/members/types.d.ts +25 -0
  323. package/dist/types/members/util.d.ts +215 -0
  324. package/dist/types/metrics/constants.d.ts +65 -0
  325. package/dist/types/metrics/index.d.ts +45 -0
  326. package/dist/types/multistream/mediaRequestManager.d.ts +118 -0
  327. package/dist/types/multistream/receiveSlot.d.ts +68 -0
  328. package/dist/types/multistream/receiveSlotManager.d.ts +56 -0
  329. package/dist/types/multistream/remoteMedia.d.ts +72 -0
  330. package/dist/types/multistream/remoteMediaGroup.d.ts +47 -0
  331. package/dist/types/multistream/remoteMediaManager.d.ts +285 -0
  332. package/dist/types/multistream/sendSlotManager.d.ts +61 -0
  333. package/dist/types/networkQualityMonitor/index.d.ts +70 -0
  334. package/dist/types/personal-meeting-room/index.d.ts +47 -0
  335. package/dist/types/personal-meeting-room/request.d.ts +14 -0
  336. package/dist/types/personal-meeting-room/util.d.ts +2 -0
  337. package/dist/types/reachability/index.d.ts +194 -0
  338. package/dist/types/reachability/request.d.ts +39 -0
  339. package/dist/types/reactions/constants.d.ts +3 -0
  340. package/dist/types/reactions/reactions.d.ts +4 -0
  341. package/dist/types/reactions/reactions.type.d.ts +52 -0
  342. package/dist/types/reconnection-manager/index.d.ts +126 -0
  343. package/dist/types/recording-controller/enums.d.ts +7 -0
  344. package/dist/types/recording-controller/index.d.ts +207 -0
  345. package/dist/types/recording-controller/util.d.ts +14 -0
  346. package/dist/types/roap/index.d.ts +78 -0
  347. package/dist/types/roap/request.d.ts +39 -0
  348. package/dist/types/roap/turnDiscovery.d.ts +92 -0
  349. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  350. package/dist/types/rtcMetrics/index.d.ts +47 -0
  351. package/dist/types/statsAnalyzer/global.d.ts +36 -0
  352. package/dist/types/statsAnalyzer/index.d.ts +201 -0
  353. package/dist/types/statsAnalyzer/mqaUtil.d.ts +24 -0
  354. package/dist/types/transcription/index.d.ts +64 -0
  355. package/dist/types/webinar/collection.d.ts +16 -0
  356. package/dist/types/webinar/index.d.ts +5 -0
  357. package/dist/webinar/collection.js +44 -0
  358. package/dist/webinar/collection.js.map +1 -0
  359. package/dist/webinar/index.js +69 -0
  360. package/dist/webinar/index.js.map +1 -0
  361. package/internal-README.md +7 -6
  362. package/package.json +29 -21
  363. package/src/annotation/annotation.types.ts +50 -0
  364. package/src/annotation/constants.ts +36 -0
  365. package/src/annotation/index.ts +328 -0
  366. package/src/breakouts/README.md +220 -0
  367. package/src/breakouts/breakout.ts +188 -0
  368. package/src/breakouts/collection.ts +19 -0
  369. package/src/breakouts/edit-lock-error.ts +25 -0
  370. package/src/breakouts/events.ts +56 -0
  371. package/src/breakouts/index.ts +925 -0
  372. package/src/breakouts/request.ts +55 -0
  373. package/src/breakouts/utils.ts +57 -0
  374. package/src/common/{browser-detection.js → browser-detection.ts} +9 -6
  375. package/src/common/collection.ts +9 -7
  376. package/src/common/{config.js → config.ts} +1 -1
  377. package/src/common/errors/{captcha-error.js → captcha-error.ts} +11 -7
  378. package/src/common/errors/{intent-to-join.js → intent-to-join.ts} +12 -7
  379. package/src/common/errors/{join-meeting.js → join-meeting.ts} +17 -8
  380. package/src/common/errors/{media.js → media.ts} +11 -7
  381. package/src/common/errors/no-meeting-info.ts +24 -0
  382. package/src/common/errors/parameter.ts +11 -7
  383. package/src/common/errors/{password-error.js → password-error.ts} +11 -7
  384. package/src/common/errors/{permission.js → permission.ts} +10 -6
  385. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  386. package/src/common/errors/{reconnection.js → reconnection.ts} +11 -7
  387. package/src/common/errors/{stats.js → stats.ts} +11 -7
  388. package/src/common/errors/{webex-errors.js → webex-errors.ts} +51 -8
  389. package/src/common/errors/{webex-meetings-error.js → webex-meetings-error.ts} +4 -2
  390. package/src/common/events/{events-scope.js → events-scope.ts} +6 -2
  391. package/src/common/events/{events.js → events.ts} +5 -1
  392. package/src/common/events/{trigger-proxy.js → trigger-proxy.ts} +9 -5
  393. package/src/common/events/{util.js → util.ts} +2 -3
  394. package/src/common/logs/{logger-config.js → logger-config.ts} +1 -2
  395. package/src/common/logs/logger-proxy.ts +44 -0
  396. package/src/common/logs/{request.js → request.ts} +26 -9
  397. package/src/common/queue.ts +22 -9
  398. package/src/{config.js → config.ts} +18 -19
  399. package/src/constants.ts +260 -22
  400. package/src/controls-options-manager/constants.ts +5 -0
  401. package/src/controls-options-manager/enums.ts +18 -0
  402. package/src/controls-options-manager/index.ts +278 -0
  403. package/src/controls-options-manager/types.ts +59 -0
  404. package/src/controls-options-manager/util.ts +300 -0
  405. package/src/index.ts +40 -0
  406. package/src/interpretation/README.md +60 -0
  407. package/src/interpretation/collection.ts +19 -0
  408. package/src/interpretation/index.ts +332 -0
  409. package/src/interpretation/siLanguage.ts +18 -0
  410. package/src/locus-info/controlsUtils.ts +222 -0
  411. package/src/locus-info/{embeddedAppsUtils.js → embeddedAppsUtils.ts} +5 -6
  412. package/src/locus-info/{fullState.js → fullState.ts} +16 -12
  413. package/src/locus-info/{hostUtils.js → hostUtils.ts} +9 -8
  414. package/src/locus-info/{index.js → index.ts} +557 -119
  415. package/src/locus-info/{infoUtils.js → infoUtils.ts} +29 -10
  416. package/src/locus-info/{mediaSharesUtils.js → mediaSharesUtils.ts} +81 -17
  417. package/src/locus-info/{parser.js → parser.ts} +303 -104
  418. package/src/locus-info/{selfUtils.js → selfUtils.ts} +199 -68
  419. package/src/media/index.ts +458 -0
  420. package/src/media/properties.ts +283 -0
  421. package/src/media/{util.js → util.ts} +2 -2
  422. package/src/mediaQualityMetrics/config.ts +384 -0
  423. package/src/meeting/in-meeting-actions.ts +191 -3
  424. package/src/meeting/index.ts +7882 -0
  425. package/src/meeting/locusMediaRequest.ts +313 -0
  426. package/src/meeting/muteState.ts +451 -0
  427. package/src/meeting/{request.js → request.ts} +421 -220
  428. package/src/meeting/request.type.ts +13 -0
  429. package/src/meeting/{state.js → state.ts} +50 -35
  430. package/src/meeting/util.ts +697 -0
  431. package/src/meeting-info/{collection.js → collection.ts} +6 -2
  432. package/src/meeting-info/index.ts +210 -0
  433. package/src/meeting-info/meeting-info-v2.ts +429 -0
  434. package/src/meeting-info/{request.js → request.ts} +14 -4
  435. package/src/meeting-info/{util.js → util.ts} +60 -51
  436. package/src/meeting-info/{utilv2.js → utilv2.ts} +78 -71
  437. package/src/meetings/{collection.js → collection.ts} +26 -3
  438. package/src/meetings/index.ts +1470 -0
  439. package/src/meetings/meetings.types.ts +12 -0
  440. package/src/meetings/{request.js → request.ts} +34 -25
  441. package/src/meetings/{util.js → util.ts} +132 -37
  442. package/src/member/{index.js → index.ts} +160 -56
  443. package/src/member/types.ts +38 -0
  444. package/src/member/util.ts +397 -0
  445. package/src/members/{collection.js → collection.ts} +10 -2
  446. package/src/members/{index.js → index.ts} +351 -146
  447. package/src/members/request.ts +255 -0
  448. package/src/members/types.ts +29 -0
  449. package/src/members/util.ts +353 -0
  450. package/src/metrics/{constants.js → constants.ts} +12 -6
  451. package/src/metrics/index.ts +73 -0
  452. package/src/multistream/mediaRequestManager.ts +337 -63
  453. package/src/multistream/receiveSlot.ts +69 -26
  454. package/src/multistream/receiveSlotManager.ts +66 -42
  455. package/src/multistream/remoteMedia.ts +40 -5
  456. package/src/multistream/remoteMediaGroup.ts +63 -3
  457. package/src/multistream/remoteMediaManager.ts +300 -66
  458. package/src/multistream/sendSlotManager.ts +170 -0
  459. package/src/networkQualityMonitor/{index.js → index.ts} +41 -29
  460. package/src/personal-meeting-room/{index.js → index.ts} +28 -19
  461. package/src/personal-meeting-room/{request.js → request.ts} +13 -4
  462. package/src/personal-meeting-room/{util.js → util.ts} +4 -4
  463. package/src/reachability/index.ts +671 -0
  464. package/src/reachability/request.ts +50 -35
  465. package/src/reactions/constants.ts +4 -0
  466. package/src/reactions/reactions.ts +104 -0
  467. package/src/reactions/reactions.type.ts +62 -0
  468. package/src/reconnection-manager/{index.js → index.ts} +258 -138
  469. package/src/recording-controller/enums.ts +8 -0
  470. package/src/recording-controller/index.ts +332 -0
  471. package/src/recording-controller/util.ts +75 -0
  472. package/src/roap/{index.js → index.ts} +127 -79
  473. package/src/roap/request.ts +153 -0
  474. package/src/roap/turnDiscovery.ts +109 -47
  475. package/src/rtcMetrics/constants.ts +3 -0
  476. package/src/rtcMetrics/index.ts +100 -0
  477. package/src/statsAnalyzer/global.ts +37 -0
  478. package/src/statsAnalyzer/index.ts +1250 -0
  479. package/src/statsAnalyzer/mqaUtil.ts +292 -0
  480. package/src/transcription/{index.js → index.ts} +46 -39
  481. package/src/webinar/collection.ts +31 -0
  482. package/src/webinar/index.ts +62 -0
  483. package/test/integration/spec/converged-space-meetings.js +233 -0
  484. package/test/integration/spec/journey.js +790 -530
  485. package/test/integration/spec/space-meeting.js +391 -204
  486. package/test/integration/spec/transcription.js +7 -8
  487. package/test/unit/spec/annotation/index.ts +418 -0
  488. package/test/unit/spec/breakouts/breakout.ts +237 -0
  489. package/test/unit/spec/breakouts/collection.ts +15 -0
  490. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  491. package/test/unit/spec/breakouts/events.ts +89 -0
  492. package/test/unit/spec/breakouts/index.ts +1790 -0
  493. package/test/unit/spec/breakouts/request.ts +104 -0
  494. package/test/unit/spec/breakouts/utils.js +72 -0
  495. package/test/unit/spec/common/browser-detection.js +9 -28
  496. package/test/unit/spec/common/queue.js +31 -2
  497. package/test/unit/spec/controls-options-manager/index.js +287 -0
  498. package/test/unit/spec/controls-options-manager/util.js +582 -0
  499. package/test/unit/spec/fixture/locus.js +93 -90
  500. package/test/unit/spec/interpretation/collection.ts +15 -0
  501. package/test/unit/spec/interpretation/index.ts +589 -0
  502. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  503. package/test/unit/spec/locus-info/controlsUtils.js +325 -32
  504. package/test/unit/spec/locus-info/embeddedAppsUtils.js +8 -6
  505. package/test/unit/spec/locus-info/index.js +1390 -17
  506. package/test/unit/spec/locus-info/infoUtils.js +71 -40
  507. package/test/unit/spec/locus-info/lib/BasicSeqCmp.json +88 -430
  508. package/test/unit/spec/locus-info/lib/SeqCmp.json +529 -685
  509. package/test/unit/spec/locus-info/mediaSharesUtils.ts +32 -0
  510. package/test/unit/spec/locus-info/parser.js +119 -44
  511. package/test/unit/spec/locus-info/selfConstant.js +120 -103
  512. package/test/unit/spec/locus-info/selfUtils.js +296 -12
  513. package/test/unit/spec/media/index.ts +128 -77
  514. package/test/unit/spec/media/properties.ts +11 -11
  515. package/test/unit/spec/meeting/in-meeting-actions.ts +92 -3
  516. package/test/unit/spec/meeting/index.js +7433 -2752
  517. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  518. package/test/unit/spec/meeting/muteState.js +420 -211
  519. package/test/unit/spec/meeting/request.js +545 -79
  520. package/test/unit/spec/meeting/utils.js +722 -174
  521. package/test/unit/spec/meeting-info/index.js +300 -0
  522. package/test/unit/spec/meeting-info/meetinginfov2.js +624 -76
  523. package/test/unit/spec/meeting-info/request.js +7 -9
  524. package/test/unit/spec/meeting-info/util.js +11 -12
  525. package/test/unit/spec/meeting-info/utilv2.js +131 -74
  526. package/test/unit/spec/meetings/collection.js +15 -1
  527. package/test/unit/spec/meetings/index.js +1365 -377
  528. package/test/unit/spec/meetings/utils.js +216 -14
  529. package/test/unit/spec/member/index.js +61 -7
  530. package/test/unit/spec/member/util.js +526 -26
  531. package/test/unit/spec/members/index.js +536 -55
  532. package/test/unit/spec/members/request.js +228 -40
  533. package/test/unit/spec/members/utils.js +217 -4
  534. package/test/unit/spec/metrics/index.js +12 -66
  535. package/test/unit/spec/multistream/mediaRequestManager.ts +1012 -109
  536. package/test/unit/spec/multistream/receiveSlot.ts +77 -18
  537. package/test/unit/spec/multistream/receiveSlotManager.ts +69 -39
  538. package/test/unit/spec/multistream/remoteMedia.ts +40 -2
  539. package/test/unit/spec/multistream/remoteMediaGroup.ts +271 -5
  540. package/test/unit/spec/multistream/remoteMediaManager.ts +738 -65
  541. package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
  542. package/test/unit/spec/networkQualityMonitor/index.js +24 -18
  543. package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +2 -7
  544. package/test/unit/spec/reachability/index.ts +598 -26
  545. package/test/unit/spec/reachability/request.js +68 -0
  546. package/test/unit/spec/reconnection-manager/index.js +181 -12
  547. package/test/unit/spec/recording-controller/index.js +307 -0
  548. package/test/unit/spec/recording-controller/util.js +229 -0
  549. package/test/unit/spec/roap/index.ts +179 -64
  550. package/test/unit/spec/roap/request.ts +232 -0
  551. package/test/unit/spec/roap/turnDiscovery.ts +123 -58
  552. package/test/unit/spec/rtcMetrics/index.ts +73 -0
  553. package/test/unit/spec/stats-analyzer/index.js +199 -60
  554. package/test/unit/spec/webinar/collection.ts +13 -0
  555. package/test/unit/spec/webinar/index.ts +60 -0
  556. package/test/utils/cmr.js +44 -42
  557. package/test/utils/constants.js +9 -0
  558. package/test/utils/integrationTestUtils.js +46 -0
  559. package/test/utils/testUtils.js +63 -99
  560. package/test/utils/webex-config.js +22 -18
  561. package/test/utils/webex-test-users.js +57 -50
  562. package/tsconfig.json +6 -0
  563. package/dist/media/internal-media-core-wrapper.js +0 -22
  564. package/dist/media/internal-media-core-wrapper.js.map +0 -1
  565. package/dist/meeting/effectsState.js +0 -327
  566. package/dist/meeting/effectsState.js.map +0 -1
  567. package/dist/metrics/config.js +0 -301
  568. package/dist/metrics/config.js.map +0 -1
  569. package/dist/multistream/multistreamMedia.js +0 -116
  570. package/dist/multistream/multistreamMedia.js.map +0 -1
  571. package/dist/peer-connection-manager/util.js +0 -124
  572. package/dist/peer-connection-manager/util.js.map +0 -1
  573. package/src/common/logs/logger-proxy.js +0 -33
  574. package/src/index.js +0 -15
  575. package/src/locus-info/controlsUtils.js +0 -102
  576. package/src/media/index.js +0 -459
  577. package/src/media/internal-media-core-wrapper.ts +0 -9
  578. package/src/media/properties.js +0 -289
  579. package/src/mediaQualityMetrics/config.js +0 -382
  580. package/src/meeting/effectsState.js +0 -205
  581. package/src/meeting/index.js +0 -6284
  582. package/src/meeting/muteState.js +0 -318
  583. package/src/meeting/util.js +0 -506
  584. package/src/meeting-info/index.js +0 -131
  585. package/src/meeting-info/meeting-info-v2.js +0 -255
  586. package/src/meetings/index.js +0 -1015
  587. package/src/member/util.js +0 -254
  588. package/src/members/request.js +0 -131
  589. package/src/members/util.js +0 -258
  590. package/src/metrics/config.js +0 -324
  591. package/src/metrics/index.js +0 -530
  592. package/src/multistream/multistreamMedia.ts +0 -92
  593. package/src/peer-connection-manager/util.ts +0 -117
  594. package/src/reachability/index.js +0 -464
  595. package/src/roap/request.js +0 -127
  596. package/src/statsAnalyzer/global.js +0 -133
  597. package/src/statsAnalyzer/index.js +0 -1006
  598. package/src/statsAnalyzer/mqaUtil.js +0 -173
  599. package/test/unit/spec/meeting/effectsState.js +0 -291
  600. package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +0 -389
  601. /package/src/common/errors/{reconnection-in-progress.js → reconnection-in-progress.ts} +0 -0
@@ -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';
@@ -19,6 +20,7 @@ import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
19
20
  import MeetingsUtil from '@webex/plugin-meetings/src/meetings/util';
20
21
  import PersonalMeetingRoom from '@webex/plugin-meetings/src/personal-meeting-room';
21
22
  import Reachability from '@webex/plugin-meetings/src/reachability';
23
+ import Metrics from '@webex/plugin-meetings/src/metrics';
22
24
 
23
25
  import testUtils from '../../../utils/testUtils';
24
26
  import {
@@ -27,8 +29,14 @@ import {
27
29
  ONLINE,
28
30
  ROAP,
29
31
  LOCUSINFO,
30
- EVENT_TRIGGERS
32
+ EVENT_TRIGGERS,
31
33
  } from '../../../../src/constants';
34
+ import CaptchaError from '@webex/plugin-meetings/src/common/errors/captcha-error';
35
+ import { forEach } from 'lodash';
36
+ import PasswordError from '@webex/plugin-meetings/src/common/errors/password-error';
37
+ import PermissionError from '@webex/plugin-meetings/src/common/errors/permission';
38
+ import {NoiseReductionEffect,VirtualBackgroundEffect} from '@webex/media-helpers';
39
+ import NoMeetingInfoError from '../../../../src/common/errors/no-meeting-info';
32
40
 
33
41
  describe('plugin-meetings', () => {
34
42
  const logger = {
@@ -37,19 +45,23 @@ describe('plugin-meetings', () => {
37
45
  error: () => {},
38
46
  warn: () => {},
39
47
  trace: () => {},
40
- debug: () => {}
48
+ debug: () => {},
41
49
  };
42
50
 
51
+ let triggerProxyStub;
52
+
43
53
  beforeEach(() => {
44
54
  StaticConfig.set({
45
55
  bandwidth: {
46
- audio: 50, video: 500
47
- }
56
+ audio: 50,
57
+ video: 500,
58
+ },
48
59
  });
49
60
  LoggerConfig.set({
50
- verboseEvents: true, enable: false
61
+ verboseEvents: true,
62
+ enable: false,
51
63
  });
52
- TriggerProxy.trigger = sinon.stub().returns(true);
64
+ triggerProxyStub = sinon.stub(TriggerProxy, 'trigger').returns(true);
53
65
  });
54
66
 
55
67
  let webex;
@@ -58,26 +70,30 @@ describe('plugin-meetings', () => {
58
70
  let url1;
59
71
  let test1;
60
72
  let test2;
73
+ let locusInfo;
61
74
 
62
75
  describe('meetings index', () => {
63
76
  beforeEach(() => {
64
77
  MeetingsUtil.checkH264Support = sinon.stub();
65
- uuid1 = uuid.v4();
78
+ uuid1 = uuid.v4();
66
79
  url1 = `https://example.com/${uuid.v4()}`;
67
80
  uri1 = `test-${uuid.v4()}@example.com`;
68
81
  test1 = `test-${uuid.v4()}`;
69
82
  test2 = `test2-${uuid.v4()}`;
83
+ locusInfo = {
84
+ parse: sinon.stub().returns(true),
85
+ updateMainSessionLocusCache: sinon.stub(),
86
+ };
70
87
  webex = new MockWebex({
71
88
  children: {
72
89
  device: Device,
73
90
  mercury: Mercury,
74
- meetings: Meetings
75
- }
91
+ meetings: Meetings,
92
+ },
76
93
  });
77
94
 
78
-
79
95
  Object.assign(webex, {
80
- logging: logger
96
+ logging: logger,
81
97
  });
82
98
 
83
99
  Object.assign(webex.meetings.config, {
@@ -86,68 +102,74 @@ describe('plugin-meetings', () => {
86
102
  // the server supports, minimums have to be tested
87
103
  audio: 64000,
88
104
  video: 4000000,
89
- startBitrate: 2000
105
+ startBitrate: 2000,
90
106
  },
91
107
  experimental: {
92
- enableUnifiedMeetings: true
108
+ enableUnifiedMeetings: true,
93
109
  },
94
110
  logging: {
95
111
  enable: true,
96
- verboseEvents: true
97
- }
112
+ verboseEvents: true,
113
+ },
98
114
  });
99
115
 
100
116
  Object.assign(webex, {
101
- logger
117
+ logger,
102
118
  });
103
119
 
104
120
  Object.assign(webex.meetings, {
105
- startReachability: sinon.stub().returns(Promise.resolve())
121
+ startReachability: sinon.stub().returns(Promise.resolve()),
106
122
  });
107
123
 
108
124
  Object.assign(webex.internal, {
125
+ llm: {on: sinon.stub()},
109
126
  device: {
110
127
  deviceType: 'FAKE_DEVICE',
111
128
  register: sinon.stub().returns(Promise.resolve()),
112
- unregister: sinon.stub().returns(Promise.resolve())
129
+ unregister: sinon.stub().returns(Promise.resolve()),
113
130
  },
114
131
  mercury: {
115
132
  connect: sinon.stub().returns(Promise.resolve()),
116
133
  disconnect: sinon.stub().returns(Promise.resolve()),
117
134
  on: () => {},
118
- off: () => {}
135
+ off: () => {},
119
136
  },
120
137
  services: {
121
- getMeetingPreferences: sinon.stub().returns(Promise.resolve({
122
- sites: [
123
- {
124
- siteUrl: 'site1-example.webex.com',
125
- default: false
126
- },
127
- {
128
- siteUrl: 'site2-example.webex.com',
129
- default: false
130
- },
131
- {
132
- siteUrl: 'site3-example.webex.com',
133
- default: false
134
- },
135
- {
136
- siteUrl: 'go.webex.com',
137
- default: true
138
- }
139
- ]
140
- })),
141
- fetchClientRegionInfo: sinon.stub().returns(Promise.resolve())
138
+ getMeetingPreferences: sinon.stub().returns(
139
+ Promise.resolve({
140
+ sites: [
141
+ {
142
+ siteUrl: 'site1-example.webex.com',
143
+ default: false,
144
+ },
145
+ {
146
+ siteUrl: 'site2-example.webex.com',
147
+ default: false,
148
+ },
149
+ {
150
+ siteUrl: 'site3-example.webex.com',
151
+ default: false,
152
+ },
153
+ {
154
+ siteUrl: 'go.webex.com',
155
+ default: true,
156
+ },
157
+ ],
158
+ })
159
+ ),
160
+ fetchClientRegionInfo: sinon.stub().returns(Promise.resolve()),
142
161
  },
143
162
  metrics: {
144
- submitClientMetrics: sinon.stub().returns(Promise.resolve())
145
- }
146
-
163
+ submitClientMetrics: sinon.stub().returns(Promise.resolve()),
164
+ },
147
165
  });
148
166
  webex.emit('ready');
149
167
  });
150
168
 
169
+ afterEach(() => {
170
+ sinon.restore();
171
+ });
172
+
151
173
  it('has a webex instance with a meetings property', () => {
152
174
  assert.exists(webex, 'webex was initialized with children');
153
175
  assert.exists(webex.meetings, 'meetings child was set up on the webex instance');
@@ -177,10 +199,14 @@ describe('plugin-meetings', () => {
177
199
 
178
200
  describe('failure', () => {
179
201
  it('should not accept non boolean input', () => {
180
- const currentEnableUnifiedMeetings = webex.meetings.config.experimental.enableUnifiedMeetings;
202
+ const currentEnableUnifiedMeetings =
203
+ webex.meetings.config.experimental.enableUnifiedMeetings;
181
204
 
182
205
  webex.meetings._toggleUnifiedMeetings('test');
183
- assert.equal(webex.meetings.config.experimental.enableUnifiedMeetings, currentEnableUnifiedMeetings);
206
+ assert.equal(
207
+ webex.meetings.config.experimental.enableUnifiedMeetings,
208
+ currentEnableUnifiedMeetings
209
+ );
184
210
  });
185
211
  });
186
212
  });
@@ -202,43 +228,25 @@ describe('plugin-meetings', () => {
202
228
  const currentEnableAdhocMeetings = webex.meetings.config.experimental.enableAdhocMeetings;
203
229
 
204
230
  webex.meetings._toggleAdhocMeetings('test');
205
- assert.equal(webex.meetings.config.experimental.enableAdhocMeetings, currentEnableAdhocMeetings);
206
- });
207
- });
208
- });
209
-
210
- describe('#_toggleTurnDiscovery', () => {
211
- it('should have toggleAdhocMeetings', () => {
212
- assert.equal(typeof webex.meetings._toggleTurnDiscovery, 'function');
213
- });
214
-
215
- describe('success', () => {
216
- it('should update meetings to do TURN discovery', () => {
217
- webex.meetings._toggleTurnDiscovery(true);
218
- assert.equal(webex.meetings.config.experimental.enableTurnDiscovery, true);
219
-
220
- webex.meetings._toggleTurnDiscovery(false);
221
- assert.equal(webex.meetings.config.experimental.enableTurnDiscovery, false);
222
- });
223
- });
224
-
225
- describe('failure', () => {
226
- it('should not accept non boolean input', () => {
227
- const currentEnableTurnDiscovery = webex.meetings.config.experimental.enableTurnDiscovery;
228
-
229
- webex.meetings._toggleTurnDiscovery('test');
230
- assert.equal(webex.meetings.config.experimental.enableAdhocMeetings, currentEnableTurnDiscovery);
231
+ assert.equal(
232
+ webex.meetings.config.experimental.enableAdhocMeetings,
233
+ currentEnableAdhocMeetings
234
+ );
231
235
  });
232
236
  });
233
237
  });
234
238
 
235
-
236
239
  describe('Public API Contracts', () => {
237
240
  describe('#register', () => {
238
241
  it('emits an event and resolves when register succeeds', async () => {
239
242
  webex.canAuthorize = true;
240
243
  await webex.meetings.register();
241
- assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {file: 'meetings', function: 'register'}, 'meetings:registered');
244
+ assert.calledWith(
245
+ TriggerProxy.trigger,
246
+ sinon.match.instanceOf(Meetings),
247
+ {file: 'meetings', function: 'register'},
248
+ 'meetings:registered'
249
+ );
242
250
  assert.isTrue(webex.meetings.registered);
243
251
  });
244
252
 
@@ -284,9 +292,15 @@ describe('plugin-meetings', () => {
284
292
  it('emits an event and resolves when unregister succeeds', (done) => {
285
293
  webex.meetings.registered = true;
286
294
  webex.meetings.unregister().then(() => {
287
- assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {
288
- file: 'meetings', function: 'unregister'
289
- }, 'meetings:unregistered');
295
+ assert.calledWith(
296
+ TriggerProxy.trigger,
297
+ sinon.match.instanceOf(Meetings),
298
+ {
299
+ file: 'meetings',
300
+ function: 'unregister',
301
+ },
302
+ 'meetings:unregistered'
303
+ );
290
304
  assert.isFalse(webex.meetings.registered);
291
305
  done();
292
306
  });
@@ -315,31 +329,113 @@ describe('plugin-meetings', () => {
315
329
  });
316
330
  });
317
331
 
332
+ describe('virtual background effect', () => {
333
+ beforeEach(() => {
334
+ webex.credentials = {
335
+ supertoken: {
336
+ access_token: "fake_token"
337
+ }
338
+ };
339
+ })
340
+
341
+ it('creates background effect', async () => {
342
+ const result = await webex.meetings.createVirtualBackgroundEffect();
343
+
344
+ assert.exists(result);
345
+ assert.instanceOf(result, VirtualBackgroundEffect);
346
+ assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'options']);
347
+ assert.deepEqual(result.options, {
348
+ mode: 'BLUR',
349
+ blurStrength: 'STRONG',
350
+ generator: 'worker',
351
+ quality: 'LOW',
352
+ authToken: 'fake_token',
353
+ mirror: false
354
+ });
355
+ assert.exists(result.enable);
356
+ assert.exists(result.disable);
357
+ assert.exists(result.dispose);
358
+ });
359
+
360
+ it('creates background effect with custom options passed', async () => {
361
+ const effectOptions = {
362
+ generator: "local",
363
+ frameRate: 45,
364
+ mode: "IMAGE",
365
+ mirror: false,
366
+ quality: "HIGH",
367
+ blurStrength: "STRONG",
368
+ bgImageUrl: "https://test.webex.com/landscape.5a535788.jpg",
369
+ };
370
+
371
+ const result = await webex.meetings.createVirtualBackgroundEffect(effectOptions);
372
+
373
+ assert.exists(result);
374
+ assert.instanceOf(result, VirtualBackgroundEffect);
375
+ assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'options']);
376
+ assert.deepEqual(result.options, {...effectOptions, authToken: "fake_token"});
377
+ assert.exists(result.enable);
378
+ assert.exists(result.disable);
379
+ assert.exists(result.dispose);
380
+ });
381
+ })
382
+
383
+ describe('noise reduction effect', () => {
384
+ beforeEach(() => {
385
+ webex.credentials = {
386
+ supertoken: {
387
+ access_token: "fake_token"
388
+ }
389
+ };
390
+ })
391
+
392
+ it('creates noise reduction effect', async () => {
393
+ const result = await webex.meetings.createNoiseReductionEffect({audioContext: {}});
394
+
395
+ assert.exists(result);
396
+ assert.instanceOf(result, NoiseReductionEffect);
397
+ assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
398
+ assert.deepEqual(result.options, {
399
+ authToken: 'fake_token',
400
+ audioContext: {}
401
+ });
402
+ assert.exists(result.enable);
403
+ assert.exists(result.disable);
404
+ assert.exists(result.dispose);
405
+ });
406
+
407
+ it('creates noise reduction effect with custom options passed', async () => {
408
+ const effectOptions = {
409
+ audioContext: {},
410
+ mode: "WORKLET",
411
+ env: "prod"
412
+ };
413
+
414
+ const result = await webex.meetings.createNoiseReductionEffect(effectOptions);
415
+
416
+ assert.exists(result);
417
+ assert.instanceOf(result, NoiseReductionEffect);
418
+ assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
419
+ assert.deepEqual(result.options, {...effectOptions, authToken: "fake_token"});
420
+ assert.exists(result.enable);
421
+ assert.exists(result.disable);
422
+ assert.exists(result.dispose);
423
+ });
424
+ })
425
+
318
426
  describe('gets', () => {
319
427
  describe('#getReachability', () => {
320
428
  it('should have #getReachability', () => {
321
429
  assert.exists(webex.meetings.getReachability);
322
430
  });
323
- describe('before #setReachability', () => {
324
- it('does not get a reachability instance', () => {
325
- const reachability = webex.meetings.getReachability();
326
-
327
- assert.notExists(reachability, 'reachability is undefined because #setReachability has not been called');
328
- });
329
- });
330
- describe('after #setReachability', () => {
331
- beforeEach(() => {
332
- webex.meetings.setReachability();
333
- const reachabilityMocker = webex.meetings.getReachability();
431
+ it('gets the reachability data instance from webex.meetings', () => {
432
+ const reachability = webex.meetings.getReachability();
334
433
 
335
- sinon.stub(reachabilityMocker, 'gatherReachability').returns(true);
336
- });
337
- it('gets the reachability data instance from webex.meetings', () => {
338
- const reachability = webex.meetings.getReachability();
339
-
340
- assert.exists(reachability, 'reachability is defined because #setReachability has been called');
341
- assert.instanceOf(reachability, Reachability, 'should be a reachability instance');
342
- });
434
+ assert.exists(
435
+ reachability,
436
+ 'reachability is defined'
437
+ );
438
+ assert.instanceOf(reachability, Reachability, 'should be a reachability instance');
343
439
  });
344
440
  });
345
441
  describe('#getPersonalMeetingRoom', () => {
@@ -349,8 +445,15 @@ describe('plugin-meetings', () => {
349
445
  it('gets the personal meeting room instance from webex.meetings', () => {
350
446
  const personalMeetingRoom = webex.meetings.getPersonalMeetingRoom();
351
447
 
352
- assert.exists(personalMeetingRoom, 'personal meeting room instance is set up at object creation');
353
- assert.instanceOf(personalMeetingRoom, PersonalMeetingRoom, 'should be a personal meeting room instance');
448
+ assert.exists(
449
+ personalMeetingRoom,
450
+ 'personal meeting room instance is set up at object creation'
451
+ );
452
+ assert.instanceOf(
453
+ personalMeetingRoom,
454
+ PersonalMeetingRoom,
455
+ 'should be a personal meeting room instance'
456
+ );
354
457
  });
355
458
  });
356
459
  describe('Static shortcut proxy methods', () => {
@@ -379,11 +482,11 @@ describe('plugin-meetings', () => {
379
482
  describe('#getAllMeetings', () => {
380
483
  it('calls MeetingCollection to get all meetings with supplied options', () => {
381
484
  webex.meetings.getAllMeetings({
382
- test: test1
485
+ test: test1,
383
486
  });
384
487
  assert.calledOnce(webex.meetings.meetingCollection.getAll);
385
488
  assert.calledWith(webex.meetings.meetingCollection.getAll, {
386
- test: test1
489
+ test: test1,
387
490
  });
388
491
  });
389
492
  });
@@ -396,28 +499,28 @@ describe('plugin-meetings', () => {
396
499
  });
397
500
  describe('succesful requests', () => {
398
501
  beforeEach(() => {
399
- webex.meetings.request.getActiveMeetings = sinon.stub().returns(Promise.resolve({
400
- loci: [{
401
- url: url1
402
- }]
403
- }));
502
+ webex.meetings.request.getActiveMeetings = sinon.stub().returns(
503
+ Promise.resolve({
504
+ loci: [
505
+ {
506
+ url: url1,
507
+ },
508
+ ],
509
+ })
510
+ );
404
511
  });
405
512
  describe('when meeting is returned', () => {
406
- let parse;
407
513
 
408
514
  beforeEach(() => {
409
- parse = sinon.stub().returns(true);
410
515
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
411
- locusInfo: {
412
- parse
413
- }
516
+ locusInfo,
414
517
  });
415
518
  });
416
519
  it('tests the sync meeting calls for existing meeting', async () => {
417
520
  await webex.meetings.syncMeetings();
418
521
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
419
522
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
420
- assert.calledOnce(parse);
523
+ assert.calledOnce(locusInfo.parse);
421
524
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
422
525
  });
423
526
  });
@@ -427,25 +530,32 @@ describe('plugin-meetings', () => {
427
530
  beforeEach(() => {
428
531
  initialSetup = sinon.stub().returns(true);
429
532
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns(null);
430
- webex.meetings.create = sinon.stub().returns(Promise.resolve({
431
- locusInfo: {
432
- initialSetup
433
- }
434
- }));
533
+ webex.meetings.create = sinon.stub().returns(
534
+ Promise.resolve({
535
+ locusInfo: {
536
+ ...locusInfo,
537
+ initialSetup,
538
+ },
539
+ })
540
+ );
435
541
  });
436
542
  it('tests the sync meeting calls for not existing meeting', async () => {
437
543
  await webex.meetings.syncMeetings();
438
544
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
439
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
545
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
440
546
  assert.calledOnce(initialSetup);
441
547
  assert.calledOnce(webex.meetings.create);
442
548
  assert.calledWith(webex.meetings.request.getActiveMeetings);
443
549
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
444
- assert.calledWith(webex.meetings.create, {
445
- url: url1
446
- }, 'LOCUS_ID');
550
+ assert.calledWith(
551
+ webex.meetings.create,
552
+ {
553
+ url: url1,
554
+ },
555
+ 'LOCUS_ID'
556
+ );
447
557
  assert.calledWith(initialSetup, {
448
- url: url1
558
+ url: url1,
449
559
  });
450
560
  });
451
561
  });
@@ -456,28 +566,30 @@ describe('plugin-meetings', () => {
456
566
 
457
567
  beforeEach(() => {
458
568
  destroySpy = sinon.spy(webex.meetings, 'destroy');
459
- parse = sinon.stub().returns(true);
460
569
  initialSetup = sinon.stub().returns(true);
461
570
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
462
- locusInfo: {
463
- parse
464
- },
465
- sendCallAnalyzerMetrics: sinon.stub()
571
+ locusInfo,
572
+ sendCallAnalyzerMetrics: sinon.stub(),
466
573
  });
467
574
  webex.meetings.meetingCollection.getAll = sinon.stub().returns({
468
575
  meetingutk: {
469
- locusUrl: 'fdfdjfdhj', sendCallAnalyzerMetrics: sinon.stub()
470
- }
471
- });
472
- webex.meetings.create = sinon.stub().returns(Promise.resolve({
473
- locusInfo: {
474
- initialSetup
576
+ locusUrl: 'fdfdjfdhj',
577
+ sendCallAnalyzerMetrics: sinon.stub(),
475
578
  },
476
- sendCallAnalyzerMetrics: sinon.stub()
477
- }));
478
- webex.meetings.request.getActiveMeetings = sinon.stub().returns(Promise.resolve({
479
- loci: []
480
- }));
579
+ });
580
+ webex.meetings.create = sinon.stub().returns(
581
+ Promise.resolve({
582
+ locusInfo: {
583
+ initialSetup,
584
+ },
585
+ sendCallAnalyzerMetrics: sinon.stub(),
586
+ })
587
+ );
588
+ webex.meetings.request.getActiveMeetings = sinon.stub().returns(
589
+ Promise.resolve({
590
+ loci: [],
591
+ })
592
+ );
481
593
  MeetingUtil.cleanUp = sinon.stub().returns(Promise.resolve());
482
594
  });
483
595
  it('destroy non active meetings', async () => {
@@ -499,43 +611,65 @@ describe('plugin-meetings', () => {
499
611
  beforeEach(() => {
500
612
  infoOptions = {
501
613
  destination: 'dest-example',
502
- type: 'CONVERSATION_URL'
614
+ type: 'CONVERSATION_URL',
503
615
  };
504
616
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns();
505
- webex.meetings.createMeeting = sinon.stub().returns(Promise.resolve({
506
- on: () => true
507
- }));
617
+ webex.meetings.createMeeting = sinon.stub().returns(
618
+ Promise.resolve({
619
+ on: () => true,
620
+ })
621
+ );
508
622
  });
509
623
 
510
- it('should call MeetingInfo#fetchInfoOptions() with proper params',
511
- () => {
512
- webex.meetings.meetingInfo.fetchInfoOptions = sinon.stub().resolves(
513
- infoOptions
514
- );
624
+ it('should call MeetingInfo#fetchInfoOptions() with proper params', () => {
625
+ webex.meetings.meetingInfo.fetchInfoOptions = sinon.stub().resolves(infoOptions);
515
626
 
516
- return webex.meetings.create(
627
+ return webex.meetings.create(infoOptions.destination, infoOptions.type).then(() => {
628
+ assert.calledWith(
629
+ webex.meetings.meetingInfo.fetchInfoOptions,
517
630
  infoOptions.destination,
518
631
  infoOptions.type
519
- )
520
- .then(() => {
521
- assert.calledWith(
522
- webex.meetings.meetingInfo.fetchInfoOptions,
523
- infoOptions.destination,
524
- infoOptions.type
525
- );
632
+ );
526
633
 
527
- assert.calledTwice(webex.meetings.meetingCollection.getByKey);
528
- });
634
+ assert.calledTwice(webex.meetings.meetingCollection.getByKey);
529
635
  });
636
+ });
637
+
638
+ const FAKE_USE_RANDOM_DELAY = true;
639
+ const correlationId = 'my-correlationId';
640
+
641
+ const checkCallCreateMeeting = async (createParameters, createMeetingParameters) => {
642
+ const create = webex.meetings.create(...createParameters);
643
+
644
+ assert.exists(create.then);
645
+ await create;
646
+ assert.calledOnce(webex.meetings.createMeeting);
647
+ assert.calledWith(webex.meetings.createMeeting, ...createMeetingParameters);
648
+ }
530
649
 
531
650
  it('calls createMeeting and returns its promise', async () => {
532
- const FAKE_USE_RANDOM_DELAY = true;
533
- const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY);
651
+ checkCallCreateMeeting([test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, true], [test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, true]);
652
+ });
653
+
654
+ it('calls createMeeting when failOnMissingMeetinginfo is undefined and returns its promise', async () => {
655
+ checkCallCreateMeeting([test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, undefined], [test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, false]);
656
+ });
657
+
658
+ it('calls createMeeting when failOnMissingMeetinginfo is false and returns its promise', async () => {
659
+ checkCallCreateMeeting([test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, false], [test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId, false]);
660
+ });
661
+
662
+ it('calls createMeeting with extra info params and returns its promise', async () => {
663
+ const FAKE_USE_RANDOM_DELAY = false;
664
+ const correlationId = 'my-correlationId';
665
+
666
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
667
+ const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
534
668
 
535
669
  assert.exists(create.then);
536
670
  await create;
537
671
  assert.calledOnce(webex.meetings.createMeeting);
538
- assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY);
672
+ assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
539
673
  });
540
674
 
541
675
  it('creates a new meeting when a scheduled meeting exists in the conversation', async () => {
@@ -565,9 +699,9 @@ describe('plugin-meetings', () => {
565
699
  return undefined;
566
700
  });
567
701
 
568
- webex.meetings.meetingInfo.fetchInfoOptions = sinon.stub().resolves(
569
- scheduledMeetingFixture
570
- );
702
+ webex.meetings.meetingInfo.fetchInfoOptions = sinon
703
+ .stub()
704
+ .resolves(scheduledMeetingFixture);
571
705
 
572
706
  webex.meetings.meetingCollection.set(scheduledMeetingFixture);
573
707
 
@@ -602,99 +736,126 @@ describe('plugin-meetings', () => {
602
736
  it('doesnt call handle locus mercury for a locus roap event', () => {
603
737
  webex.meetings.handleLocusMercury({
604
738
  data: {
605
- eventType: 'locus.message.roap'
606
- }
739
+ eventType: 'locus.message.roap',
740
+ },
607
741
  });
608
742
  assert.notCalled(webex.meetings.handleLocusEvent);
609
743
  });
610
744
  it('doesnt call handle locus mercury for an undefined eventType', () => {
611
745
  webex.meetings.handleLocusMercury({
612
- data: {
613
- }
746
+ data: {},
614
747
  });
615
748
  assert.notCalled(webex.meetings.handleLocusEvent);
616
749
  });
617
750
  it('calls handle locus mercury for all locus events', () => {
618
751
  webex.meetings.handleLocusMercury({
619
752
  data: {
620
- eventType: test1
621
- }
753
+ eventType: test1,
754
+ },
622
755
  });
623
756
  assert.calledOnce(webex.meetings.handleLocusEvent);
624
- assert.calledWith(webex.meetings.handleLocusEvent, {
625
- eventType: test1
626
- }, true);
757
+ assert.calledWith(
758
+ webex.meetings.handleLocusEvent,
759
+ {
760
+ eventType: test1,
761
+ },
762
+ true
763
+ );
627
764
  });
628
765
  });
629
766
  describe('#handleLocusEvent', () => {
630
767
  describe('there was a meeting', () => {
631
- let parse;
632
768
 
633
769
  beforeEach(() => {
634
- parse = sinon.stub().returns(true);
635
770
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
636
- locusInfo: {
637
- parse
638
- }
771
+ locusInfo,
639
772
  });
640
773
  });
641
- it('should parse the meeting info', () => {
774
+ it('should parse the meeting info and update main session locus cache', () => {
775
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(false);
642
776
  webex.meetings.handleLocusEvent({
643
- locusUrl: url1
777
+ locusUrl: url1,
644
778
  });
645
779
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
646
780
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
647
- assert.calledOnce(parse);
648
- assert.calledWith(parse, {
649
- locusInfo: {
650
- parse
781
+ assert.calledOnce(locusInfo.parse);
782
+ assert.calledOnce(locusInfo.updateMainSessionLocusCache);
783
+ assert.calledWith(
784
+ locusInfo.parse,
785
+ {
786
+ locusInfo,
787
+ },
788
+ {
789
+ locusUrl: url1,
651
790
  }
652
- }, {
653
- locusUrl: url1
791
+ );
792
+ });
793
+
794
+ it('should not update main session locus cache', () => {
795
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(true);
796
+ webex.meetings.handleLocusEvent({
797
+ locusUrl: url1,
654
798
  });
799
+ assert.notCalled(locusInfo.updateMainSessionLocusCache);
655
800
  });
656
801
  });
657
802
  describe('there was not a meeting', () => {
658
803
  let initialSetup;
804
+ const webExMeetingId = '123456';
659
805
 
660
806
  beforeEach(() => {
661
807
  initialSetup = sinon.stub().returns(true);
662
808
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
663
- webex.meetings.create = sinon.stub().returns(Promise.resolve({
664
- locusInfo: {
665
- initialSetup
666
- }
667
- }));
809
+ webex.meetings.create = sinon.stub().returns(
810
+ Promise.resolve({
811
+ id: 'meeting-id',
812
+ locusInfo: {
813
+ ...locusInfo,
814
+ initialSetup,
815
+ },
816
+ })
817
+ );
668
818
  });
669
819
  it('should setup the meeting by difference event', async () => {
670
820
  await webex.meetings.handleLocusEvent({
671
821
  locus: {
672
822
  id: uuid1,
673
- replaces: [{
674
- locusUrl: 'http:locusUrl'
675
- }],
823
+ replaces: [
824
+ {
825
+ locusUrl: 'http:locusUrl',
826
+ },
827
+ ],
676
828
  self: {
677
829
  callBackInfo: {
678
- callbackAddress: uri1
679
- }
680
- }
830
+ callbackAddress: uri1,
831
+ },
832
+ },
833
+ info: {
834
+ webExMeetingId
835
+ },
681
836
  },
682
837
  eventType: 'locus.difference',
683
- locusUrl: url1
838
+ locusUrl: url1,
684
839
  });
685
- assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
840
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 6);
686
841
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
842
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
687
843
  assert.calledOnce(initialSetup);
688
844
  assert.calledWith(initialSetup, {
689
845
  id: uuid1,
690
- replaces: [{
691
- locusUrl: 'http:locusUrl'
692
- }],
846
+ replaces: [
847
+ {
848
+ locusUrl: 'http:locusUrl',
849
+ },
850
+ ],
693
851
  self: {
694
852
  callBackInfo: {
695
- callbackAddress: uri1
696
- }
697
- }
853
+ callbackAddress: uri1,
854
+ },
855
+ },
856
+ info: {
857
+ webExMeetingId
858
+ },
698
859
  });
699
860
  });
700
861
  it('should setup the meeting by difference event without replaces', async () => {
@@ -703,48 +864,95 @@ describe('plugin-meetings', () => {
703
864
  id: uuid1,
704
865
  self: {
705
866
  callBackInfo: {
706
- callbackAddress: uri1
707
- }
708
- }
867
+ callbackAddress: uri1,
868
+ },
869
+ },
870
+ info: {
871
+ webExMeetingId
872
+ },
709
873
  },
710
874
  eventType: 'locus.difference',
711
- locusUrl: url1
875
+ locusUrl: url1,
712
876
  });
713
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
877
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
714
878
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
879
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
715
880
  assert.calledOnce(initialSetup);
716
881
  assert.calledWith(initialSetup, {
717
882
  id: uuid1,
718
883
  self: {
719
884
  callBackInfo: {
720
- callbackAddress: uri1
721
- }
722
- }
885
+ callbackAddress: uri1,
886
+ },
887
+ },
888
+ info: {
889
+ webExMeetingId
890
+ },
723
891
  });
724
892
  });
893
+
894
+ it('sends client event correctly on finally', async () => {
895
+ webex.meetings.getMeetingByType = sinon.stub().returns(true);
896
+
897
+ await webex.meetings.handleLocusEvent({
898
+ locus: {
899
+ id: uuid1,
900
+ self: {
901
+ callBackInfo: {
902
+ callbackAddress: uri1,
903
+ },
904
+ },
905
+ info: {
906
+ webExMeetingId,
907
+ },
908
+ },
909
+ eventType: 'locus.difference',
910
+ locusUrl: url1,
911
+ });
912
+
913
+ await testUtils.flushPromises();
914
+
915
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
916
+ name: 'client.call.remote-started',
917
+ payload: {
918
+ trigger: 'mercury-event',
919
+ },
920
+ options: {
921
+ meetingId: 'meeting-id',
922
+ },
923
+ });
924
+ });
925
+
725
926
  it('should setup the meeting by a not difference event', async () => {
726
927
  await webex.meetings.handleLocusEvent({
727
928
  locus: {
728
929
  id: uuid1,
729
930
  self: {
730
931
  callBackInfo: {
731
- callbackAddress: uri1
732
- }
733
- }
932
+ callbackAddress: uri1,
933
+ },
934
+ },
935
+ info: {
936
+ webExMeetingId
937
+ },
734
938
  },
735
939
  eventType: test1,
736
- locusUrl: url1
940
+ locusUrl: url1,
737
941
  });
738
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
942
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
739
943
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
944
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
740
945
  assert.calledOnce(initialSetup);
741
946
  assert.calledWith(initialSetup, {
742
947
  id: uuid1,
743
948
  self: {
744
949
  callBackInfo: {
745
- callbackAddress: uri1
746
- }
747
- }
950
+ callbackAddress: uri1,
951
+ },
952
+ },
953
+ info: {
954
+ webExMeetingId
955
+ },
748
956
  });
749
957
  });
750
958
 
@@ -753,13 +961,13 @@ describe('plugin-meetings', () => {
753
961
  id: uuid1,
754
962
  self: {
755
963
  callbackInfo: {
756
- callbackAddress: uri1
757
- }
964
+ callbackAddress: uri1,
965
+ },
758
966
  },
759
967
  info: {
760
- isUnifiedSpaceMeeting
968
+ isUnifiedSpaceMeeting,
761
969
  },
762
- conversationUrl: 'fakeConvoUrl'
970
+ conversationUrl: 'fakeConvoUrl',
763
971
  },
764
972
  eventType: test1,
765
973
  locusUrl: url1,
@@ -767,19 +975,40 @@ describe('plugin-meetings', () => {
767
975
 
768
976
  it('should not try to match USM meetings by conversation url', async () => {
769
977
  await webex.meetings.handleLocusEvent(generateFakeLocusData(true));
770
- assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
771
- assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, ['locusUrl', url1]);
772
- assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(1).args, ['correlationId', false]);
773
- assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(2).args, ['sipUri', uri1]);
978
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
979
+ assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, [
980
+ 'locusUrl',
981
+ url1,
982
+ ]);
983
+ assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(1).args, [
984
+ 'correlationId',
985
+ false,
986
+ ]);
987
+ assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(2).args, [
988
+ 'sipUri',
989
+ uri1,
990
+ ]);
774
991
  assert.calledOnce(initialSetup);
775
992
  });
776
993
  it('should try to match non-USM meetings by conversation url', async () => {
777
994
  await webex.meetings.handleLocusEvent(generateFakeLocusData(false));
778
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
779
- assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, ['locusUrl', url1]);
780
- assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(1).args, ['correlationId', false]);
781
- assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(2).args, ['sipUri', uri1]);
782
- assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(3).args, ['conversationUrl', 'fakeConvoUrl']);
995
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
996
+ assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, [
997
+ 'locusUrl',
998
+ url1,
999
+ ]);
1000
+ assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(1).args, [
1001
+ 'correlationId',
1002
+ false,
1003
+ ]);
1004
+ assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(2).args, [
1005
+ 'sipUri',
1006
+ uri1,
1007
+ ]);
1008
+ assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(3).args, [
1009
+ 'conversationUrl',
1010
+ 'fakeConvoUrl',
1011
+ ]);
783
1012
  assert.calledOnce(initialSetup);
784
1013
  });
785
1014
  });
@@ -794,15 +1023,19 @@ describe('plugin-meetings', () => {
794
1023
  });
795
1024
  describe('successful MeetingInfo.#fetchMeetingInfo', () => {
796
1025
  let clock, setTimeoutSpy, fakeMeetingStartTimeString, FAKE_TIME_TO_START;
1026
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
797
1027
 
798
1028
  beforeEach(() => {
799
1029
  clock = sinon.useFakeTimers();
800
1030
  setTimeoutSpy = sinon.spy(clock, 'setTimeout');
801
- webex.meetings.meetingInfo.fetchMeetingInfo = sinon.stub().returns(Promise.resolve({
802
- body: {
803
- permissionToken: 'PT', meetingJoinUrl: 'meetingJoinUrl'
804
- }
805
- }));
1031
+ webex.meetings.meetingInfo.fetchMeetingInfo = sinon.stub().returns(
1032
+ Promise.resolve({
1033
+ body: {
1034
+ permissionToken: 'PT',
1035
+ meetingJoinUrl: 'meetingJoinUrl',
1036
+ },
1037
+ })
1038
+ );
806
1039
  const nowTimeStamp = Date.now();
807
1040
 
808
1041
  FAKE_TIME_TO_START = 0.1 * 60 * 1000;
@@ -816,12 +1049,19 @@ describe('plugin-meetings', () => {
816
1049
  clock.restore();
817
1050
  });
818
1051
 
819
- const checkCreateWithoutDelay = (meeting, destination, type, expectedMeetingData = {}) => {
1052
+ const checkCreateWithoutDelay = (
1053
+ meeting,
1054
+ destination,
1055
+ type,
1056
+ extraParams = {},
1057
+ expectedMeetingData = {},
1058
+ sendCAevents = false,
1059
+ ) => {
820
1060
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
821
1061
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
822
1062
  assert.notCalled(setTimeoutSpy);
823
- assert.calledThrice(TriggerProxy.trigger);
824
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type);
1063
+ assert.callCount(TriggerProxy.trigger, 5);
1064
+ assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type, null, null, undefined, undefined, extraParams, {meetingId: meeting.id, sendCAevents});
825
1065
  assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
826
1066
 
827
1067
  if (expectedMeetingData.permissionToken) {
@@ -830,14 +1070,30 @@ describe('plugin-meetings', () => {
830
1070
  if (expectedMeetingData.meetingJoinUrl) {
831
1071
  assert.equal(meeting.meetingJoinUrl, expectedMeetingData.meetingJoinUrl);
832
1072
  }
1073
+ if(expectedMeetingData.correlationId) {
1074
+ assert.equal(meeting.correlationId, expectedMeetingData.correlationId);
1075
+ }
833
1076
  assert.equal(meeting.destination, destination);
834
1077
  assert.equal(meeting.destinationType, type);
835
- assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {
836
- file: 'meetings', function: 'createMeeting'
837
- }, 'meeting:added', {
838
- meeting: sinon.match.instanceOf(Meeting), type: 'test meeting added type'
839
- });
840
- assert.calledWith(TriggerProxy.trigger, meeting, {file: 'meetings', function: 'fetchMeetingInfo'}, 'meeting:meetingInfoAvailable');
1078
+ assert.calledWith(
1079
+ TriggerProxy.trigger,
1080
+ sinon.match.instanceOf(Meetings),
1081
+ {
1082
+ file: 'meetings',
1083
+ function: 'createMeeting',
1084
+ },
1085
+ 'meeting:added',
1086
+ {
1087
+ meeting: sinon.match.instanceOf(Meeting),
1088
+ type: 'test meeting added type',
1089
+ }
1090
+ );
1091
+ assert.calledWith(
1092
+ TriggerProxy.trigger,
1093
+ meeting,
1094
+ {file: 'meetings', function: 'fetchMeetingInfo'},
1095
+ 'meeting:meetingInfoAvailable'
1096
+ );
841
1097
  };
842
1098
 
843
1099
  it('creates the meeting from a successful meeting info fetch promise testing', async () => {
@@ -845,80 +1101,120 @@ describe('plugin-meetings', () => {
845
1101
 
846
1102
  const expectedMeetingData = {
847
1103
  permissionToken: 'PT',
848
- meetingJoinUrl: 'meetingJoinUrl'
1104
+ meetingJoinUrl: 'meetingJoinUrl',
1105
+ correlationId: meeting.id,
849
1106
  };
850
1107
 
851
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
1108
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
852
1109
  });
853
1110
 
854
- it('creates the meeting from a successful meeting info fetch meeting resolve testing', async () => {
855
- const meeting = await webex.meetings.createMeeting('test destination', 'test type');
856
- const expectedMeetingData = {
857
- permissionToken: 'PT',
858
- meetingJoinUrl: 'meetingJoinUrl'
859
- };
860
-
861
- assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
862
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
863
- });
864
-
865
- it('creates the meeting from a successful meeting info fetch with random delay', async () => {
866
- const FAKE_LOCUS_MEETING = {
867
- conversationUrl: 'locusConvURL',
868
- url: 'locusUrl',
869
- info: {
870
- webExMeetingId: 'locusMeetingId',
871
- sipUri: 'locusSipUri',
872
- owner: 'locusOwner'
873
- },
874
- meeting: {
875
- startTime: fakeMeetingStartTimeString
876
- },
877
- fullState: {
878
- active: false
879
- }
880
- };
881
-
882
- const meeting = await webex.meetings.createMeeting(FAKE_LOCUS_MEETING, 'test type', true);
883
-
884
- assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
885
- assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
886
- assert.calledOnce(setTimeoutSpy);
887
-
888
- // Parse meeting info with locus object
889
- assert.equal(meeting.conversationUrl, 'locusConvURL');
890
- assert.equal(meeting.locusUrl, 'locusUrl');
891
- assert.equal(meeting.sipUri, 'locusSipUri');
892
- assert.equal(meeting.meetingNumber, 'locusMeetingId');
893
- assert.isUndefined(meeting.meetingJoinUrl);
894
- assert.equal(meeting.owner, 'locusOwner');
895
- assert.isUndefined(meeting.permissionToken);
896
-
897
- // Add meeting and send trigger
898
- assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
899
- assert.calledTwice(TriggerProxy.trigger);
900
- assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {
901
- file: 'meetings', function: 'createMeeting'
902
- }, 'meeting:added', {
903
- meeting: sinon.match.instanceOf(Meeting), type: 'test meeting added type'
1111
+ [undefined, FAKE_INFO_EXTRA_PARAMS].forEach((infoExtraParams) => {
1112
+ const infoExtraParamsProvided = infoExtraParams !== undefined;
1113
+
1114
+ it(`creates the meeting from a successful meeting info fetch meeting resolve testing${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1115
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, infoExtraParams);
1116
+ const expectedMeetingData = {
1117
+ permissionToken: 'PT',
1118
+ meetingJoinUrl: 'meetingJoinUrl',
1119
+ };
1120
+
1121
+ assert.instanceOf(
1122
+ meeting,
1123
+ Meeting,
1124
+ 'createMeeting should eventually resolve to a Meeting Object'
1125
+ );
1126
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', infoExtraParamsProvided ? infoExtraParams : {}, expectedMeetingData);
904
1127
  });
905
1128
 
906
- // When timer expires
907
- clock.tick(FAKE_TIME_TO_START);
908
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, FAKE_LOCUS_MEETING, 'test type');
909
-
910
- // Parse meeting info is called again with new meeting info
911
- await testUtils.flushPromises();
912
- assert.equal(meeting.conversationUrl, 'locusConvURL');
913
- assert.equal(meeting.locusUrl, 'locusUrl');
914
- assert.equal(meeting.sipUri, 'locusSipUri');
915
- assert.equal(meeting.meetingNumber, 'locusMeetingId');
916
- assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
917
- assert.equal(meeting.owner, 'locusOwner');
918
- assert.equal(meeting.permissionToken, 'PT');
919
-
920
- assert.calledWith(TriggerProxy.trigger, meeting, {file: 'meetings', function: 'fetchMeetingInfo'}, 'meeting:meetingInfoAvailable');
921
- });
1129
+ it(`creates the meeting from a successful meeting info fetch with random delay${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1130
+ const FAKE_LOCUS_MEETING = {
1131
+ conversationUrl: 'locusConvURL',
1132
+ url: 'locusUrl',
1133
+ info: {
1134
+ webExMeetingId: 'locusMeetingId',
1135
+ sipUri: 'locusSipUri',
1136
+ owner: 'locusOwner',
1137
+ },
1138
+ meeting: {
1139
+ startTime: fakeMeetingStartTimeString,
1140
+ },
1141
+ fullState: {
1142
+ active: false,
1143
+ },
1144
+ };
1145
+
1146
+ const meeting = await webex.meetings.createMeeting(
1147
+ FAKE_LOCUS_MEETING,
1148
+ 'test type',
1149
+ true,
1150
+ infoExtraParams
1151
+ );
1152
+
1153
+ assert.instanceOf(
1154
+ meeting,
1155
+ Meeting,
1156
+ 'createMeeting should eventually resolve to a Meeting Object'
1157
+ );
1158
+ assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
1159
+ assert.calledOnce(setTimeoutSpy);
1160
+
1161
+ // Parse meeting info with locus object
1162
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1163
+ assert.equal(meeting.locusUrl, 'locusUrl');
1164
+ assert.equal(meeting.sipUri, 'locusSipUri');
1165
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1166
+ assert.isUndefined(meeting.meetingJoinUrl);
1167
+ assert.equal(meeting.owner, 'locusOwner');
1168
+ assert.isUndefined(meeting.permissionToken);
1169
+
1170
+ // Add meeting and send trigger
1171
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1172
+ assert.calledTwice(TriggerProxy.trigger);
1173
+ assert.calledWith(
1174
+ TriggerProxy.trigger,
1175
+ sinon.match.instanceOf(Meetings),
1176
+ {
1177
+ file: 'meetings',
1178
+ function: 'createMeeting',
1179
+ },
1180
+ 'meeting:added',
1181
+ {
1182
+ meeting: sinon.match.instanceOf(Meeting),
1183
+ type: 'test meeting added type',
1184
+ }
1185
+ );
1186
+
1187
+ // When timer expires
1188
+ clock.tick(FAKE_TIME_TO_START);
1189
+ assert.calledWith(
1190
+ webex.meetings.meetingInfo.fetchMeetingInfo,
1191
+ FAKE_LOCUS_MEETING,
1192
+ 'test type',
1193
+ null,
1194
+ null,
1195
+ undefined,
1196
+ undefined,
1197
+ infoExtraParamsProvided ? infoExtraParams : {}
1198
+ );
1199
+
1200
+ // Parse meeting info is called again with new meeting info
1201
+ await testUtils.flushPromises();
1202
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1203
+ assert.equal(meeting.locusUrl, 'locusUrl');
1204
+ assert.equal(meeting.sipUri, 'locusSipUri');
1205
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1206
+ assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
1207
+ assert.equal(meeting.owner, 'locusOwner');
1208
+ assert.equal(meeting.permissionToken, 'PT');
1209
+
1210
+ assert.calledWith(
1211
+ TriggerProxy.trigger,
1212
+ meeting,
1213
+ {file: 'meetings', function: 'fetchMeetingInfo'},
1214
+ 'meeting:meetingInfoAvailable'
1215
+ );
1216
+ });
1217
+ })
922
1218
 
923
1219
  it('creates the meeting from a successful meeting info fetch that has no random delay because it is active', async () => {
924
1220
  const FAKE_LOCUS_MEETING = {
@@ -927,19 +1223,27 @@ describe('plugin-meetings', () => {
927
1223
  info: {
928
1224
  webExMeetingId: 'locusMeetingId',
929
1225
  sipUri: 'locusSipUri',
930
- owner: 'locusOwner'
1226
+ owner: 'locusOwner',
931
1227
  },
932
1228
  meeting: {
933
- startTime: fakeMeetingStartTimeString
1229
+ startTime: fakeMeetingStartTimeString,
934
1230
  },
935
1231
  fullState: {
936
- active: true
937
- }
1232
+ active: true,
1233
+ },
938
1234
  };
939
1235
 
940
- const meeting = await webex.meetings.createMeeting(FAKE_LOCUS_MEETING, 'test type', true);
1236
+ const meeting = await webex.meetings.createMeeting(
1237
+ FAKE_LOCUS_MEETING,
1238
+ 'test type',
1239
+ true
1240
+ );
941
1241
 
942
- assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
1242
+ assert.instanceOf(
1243
+ meeting,
1244
+ Meeting,
1245
+ 'createMeeting should eventually resolve to a Meeting Object'
1246
+ );
943
1247
  checkCreateWithoutDelay(meeting, FAKE_LOCUS_MEETING, 'test type');
944
1248
  });
945
1249
 
@@ -950,27 +1254,35 @@ describe('plugin-meetings', () => {
950
1254
  info: {
951
1255
  webExMeetingId: 'locusMeetingId',
952
1256
  sipUri: 'locusSipUri',
953
- owner: 'locusOwner'
1257
+ owner: 'locusOwner',
954
1258
  },
955
1259
  meeting: {
956
- startTime: fakeMeetingStartTimeString - (1 * 60 * 60 * 1000)
1260
+ startTime: fakeMeetingStartTimeString - 1 * 60 * 60 * 1000,
957
1261
  },
958
1262
  fullState: {
959
- active: false
960
- }
1263
+ active: false,
1264
+ },
961
1265
  };
962
1266
 
963
- const meeting = await webex.meetings.createMeeting(FAKE_LOCUS_MEETING, 'test type', true);
1267
+ const meeting = await webex.meetings.createMeeting(
1268
+ FAKE_LOCUS_MEETING,
1269
+ 'test type',
1270
+ true
1271
+ );
964
1272
 
965
- assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
1273
+ assert.instanceOf(
1274
+ meeting,
1275
+ Meeting,
1276
+ 'createMeeting should eventually resolve to a Meeting Object'
1277
+ );
966
1278
  checkCreateWithoutDelay(meeting, FAKE_LOCUS_MEETING, 'test type');
967
1279
  });
968
1280
 
969
1281
  it('creates the meeting from a successful meeting info fetch that has no random delay because enableUnifiedMeetings is disabled', async () => {
970
1282
  Object.assign(webex.meetings.config, {
971
1283
  experimental: {
972
- enableUnifiedMeetings: false
973
- }
1284
+ enableUnifiedMeetings: false,
1285
+ },
974
1286
  });
975
1287
  const FAKE_LOCUS_MEETING = {
976
1288
  conversationUrl: 'locusConvURL',
@@ -978,45 +1290,164 @@ describe('plugin-meetings', () => {
978
1290
  info: {
979
1291
  webExMeetingId: 'locusMeetingId',
980
1292
  sipUri: 'locusSipUri',
981
- owner: 'locusOwner'
1293
+ owner: 'locusOwner',
982
1294
  },
983
1295
  meeting: {
984
- startTime: fakeMeetingStartTimeString
1296
+ startTime: fakeMeetingStartTimeString,
985
1297
  },
986
1298
  fullState: {
987
- active: false
988
- }
1299
+ active: false,
1300
+ },
989
1301
  };
990
1302
 
991
- const meeting = await webex.meetings.createMeeting(FAKE_LOCUS_MEETING, 'test type', true);
1303
+ const meeting = await webex.meetings.createMeeting(
1304
+ FAKE_LOCUS_MEETING,
1305
+ 'test type',
1306
+ true
1307
+ );
992
1308
 
993
- assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
1309
+ assert.instanceOf(
1310
+ meeting,
1311
+ Meeting,
1312
+ 'createMeeting should eventually resolve to a Meeting Object'
1313
+ );
994
1314
  checkCreateWithoutDelay(meeting, FAKE_LOCUS_MEETING, 'test type');
995
1315
  });
1316
+
1317
+ it('creates meeting with the correlationId provided', async () => {
1318
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, {}, 'my-correlationId');
1319
+
1320
+ const expectedMeetingData = {
1321
+ correlationId: 'my-correlationId',
1322
+ };
1323
+
1324
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData, true);
1325
+ })
996
1326
  });
997
1327
 
998
1328
  describe('rejected MeetingInfo.#fetchMeetingInfo', () => {
999
1329
  beforeEach(() => {
1000
1330
  console.error = sinon.stub().returns(false);
1001
1331
  TriggerProxy.trigger.reset();
1002
- webex.meetings.meetingInfo.fetchMeetingInfo = sinon.stub().returns(Promise.reject(new Error('test')));
1332
+ webex.meetings.meetingInfo.fetchMeetingInfo = sinon
1333
+ .stub()
1334
+ .returns(Promise.reject(new Error('test')));
1335
+ webex.meetings.destroy = sinon
1336
+ .stub()
1337
+ .returns(Promise.resolve());
1338
+ webex.meetings.createMeeting = sinon.spy(webex.meetings.createMeeting);
1003
1339
  });
1340
+
1341
+ const checkCreateMeetingWithNoMeetingInfo = async (failOnMissingMeetingInfo, destroy) => {
1342
+ try {
1343
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', undefined, undefined, undefined, failOnMissingMeetingInfo);
1344
+
1345
+ assert.instanceOf(
1346
+ meeting,
1347
+ Meeting,
1348
+ 'createMeeting should eventually resolve to a Meeting Object'
1349
+ );
1350
+ assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1351
+ assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1352
+ assert.calledThrice(TriggerProxy.trigger);
1353
+ assert.calledWith(
1354
+ webex.meetings.meetingInfo.fetchMeetingInfo,
1355
+ 'test destination',
1356
+ 'test type'
1357
+ );
1358
+
1359
+ if (destroy) {
1360
+ assert.calledWith(webex.meetings.destroy, sinon.match.instanceOf(Meeting), 'MISSING_MEETING_INFO')
1361
+ assert.notCalled(MeetingsUtil.getMeetingAddedType);
1362
+ assert.notCalled(TriggerProxy.trigger);
1363
+ assert.throw(webex.meetings.createMeeting, 'meeting information not found');
1364
+ } else {
1365
+ assert.notCalled(webex.meetings.destroy);
1366
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1367
+ assert.calledWith(
1368
+ TriggerProxy.trigger,
1369
+ sinon.match.instanceOf(Meetings),
1370
+ {
1371
+ file: 'meetings',
1372
+ function: 'createMeeting',
1373
+ },
1374
+ 'meeting:added',
1375
+ {
1376
+ meeting: sinon.match.instanceOf(Meeting),
1377
+ type: 'test meeting added type',
1378
+ }
1379
+ );
1380
+ }
1381
+ } catch (err) {
1382
+ assert.instanceOf(err, NoMeetingInfoError);
1383
+ }
1384
+ }
1385
+
1004
1386
  it('creates the meeting from a rejected meeting info fetch', async () => {
1005
- const meeting = await webex.meetings.createMeeting('test destination', 'test type');
1387
+ checkCreateMeetingWithNoMeetingInfo(false, false);
1388
+ });
1006
1389
 
1007
- assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
1008
- assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1009
- assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1010
- assert.calledTwice(TriggerProxy.trigger);
1011
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, 'test destination', 'test type');
1012
- assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1013
- assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {
1014
- file: 'meetings', function: 'createMeeting'
1015
- }, 'meeting:added', {
1016
- meeting: sinon.match.instanceOf(Meeting), type: 'test meeting added type'
1017
- });
1390
+ it('creates the meeting from a rejected meeting info fetch and destroys it if failOnMissingMeetingInfo', async () => {
1391
+ checkCreateMeetingWithNoMeetingInfo(true, true);
1018
1392
  });
1019
1393
  });
1394
+
1395
+ describe('rejected MeetingInfo.#fetchMeetingInfo - does not log for known Error types', () => {
1396
+ forEach(
1397
+ [
1398
+ {
1399
+ error: new CaptchaError(),
1400
+ debugLogMessage:
1401
+ 'Meetings:index#createMeeting --> Debug CaptchaError: Captcha is required. fetching /meetingInfo for creation.',
1402
+ },
1403
+ {
1404
+ error: new PasswordError(),
1405
+ debugLogMessage:
1406
+ 'Meetings:index#createMeeting --> Debug PasswordError: Password is required, please use verifyPassword() fetching /meetingInfo for creation.',
1407
+ },
1408
+ {
1409
+ error: new PermissionError(),
1410
+ debugLogMessage:
1411
+ '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.',
1412
+ },
1413
+ {
1414
+ error: new Error(),
1415
+ infoLogMessage: true,
1416
+ debugLogMessage:
1417
+ 'Meetings:index#createMeeting --> Debug Error fetching /meetingInfo for creation.',
1418
+ },
1419
+ ],
1420
+ ({error, debugLogMessage, infoLogMessage}) => {
1421
+ it('creates the meeting from a rejected meeting info fetch', async () => {
1422
+ webex.meetings.meetingInfo.fetchMeetingInfo = sinon
1423
+ .stub()
1424
+ .returns(Promise.reject(error));
1425
+
1426
+ LoggerProxy.logger.debug = sinon.stub();
1427
+ LoggerProxy.logger.info = sinon.stub();
1428
+
1429
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type');
1430
+
1431
+ assert.instanceOf(
1432
+ meeting,
1433
+ Meeting,
1434
+ 'createMeeting should eventually resolve to a Meeting Object'
1435
+ );
1436
+
1437
+ assert.calledWith(LoggerProxy.logger.debug, debugLogMessage);
1438
+
1439
+ if (infoLogMessage) {
1440
+ assert.calledWith(
1441
+ LoggerProxy.logger.info,
1442
+ 'Meetings:index#createMeeting --> Info Unable to fetch meeting info for test destination.'
1443
+ );
1444
+ } else {
1445
+ assert.notCalled(LoggerProxy.logger.info);
1446
+ }
1447
+ });
1448
+ }
1449
+ );
1450
+ });
1020
1451
  });
1021
1452
  });
1022
1453
  describe('Public Event Triggers', () => {
@@ -1039,11 +1470,19 @@ describe('plugin-meetings', () => {
1039
1470
 
1040
1471
  assert.calledOnce(webex.meetings.meetingCollection.delete);
1041
1472
  assert.calledWith(webex.meetings.meetingCollection.delete, meeting.id);
1042
- assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {
1043
- file: 'meetings', function: 'destroy'
1044
- }, 'meeting:removed', {
1045
- meetingId: meeting.id, reason: test1
1046
- });
1473
+ assert.calledWith(
1474
+ TriggerProxy.trigger,
1475
+ sinon.match.instanceOf(Meetings),
1476
+ {
1477
+ file: 'meetings',
1478
+ function: 'destroy',
1479
+ },
1480
+ 'meeting:removed',
1481
+ {
1482
+ meetingId: meeting.id,
1483
+ reason: test1,
1484
+ }
1485
+ );
1047
1486
  });
1048
1487
  });
1049
1488
 
@@ -1068,7 +1507,8 @@ describe('plugin-meetings', () => {
1068
1507
  it('should trigger event upon mercury disconnect', () => {
1069
1508
  const {meetings} = webex;
1070
1509
  const SCOPE = {
1071
- file: 'meetings/index', function: 'handleMercuryOffline'
1510
+ file: 'meetings/index',
1511
+ function: 'handleMercuryOffline',
1072
1512
  };
1073
1513
  const EVENT = 'network:disconnected';
1074
1514
 
@@ -1086,6 +1526,9 @@ describe('plugin-meetings', () => {
1086
1526
  });
1087
1527
 
1088
1528
  describe('#fetchUserPreferredWebexSite', () => {
1529
+
1530
+ let loggerProxySpy;
1531
+
1089
1532
  it('should call request.getMeetingPreferences to get the preferred webex site ', async () => {
1090
1533
  assert.isDefined(webex.meetings.preferredWebexSite);
1091
1534
  await webex.meetings.fetchUserPreferredWebexSite();
@@ -1093,19 +1536,89 @@ describe('plugin-meetings', () => {
1093
1536
  assert.equal(webex.meetings.preferredWebexSite, 'go.webex.com');
1094
1537
  });
1095
1538
 
1539
+ const setup = ({user} = {}) => {
1540
+ loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
1541
+
1542
+ Object.assign(webex.internal, {
1543
+ services: {
1544
+ getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
1545
+ },
1546
+ user: {
1547
+ get: sinon.stub().returns(
1548
+ Promise.resolve(user)
1549
+ ),
1550
+ },
1551
+ });
1552
+ }
1553
+
1096
1554
  it('should not fail if UserPreferred info is not fetched ', async () => {
1555
+ setup();
1556
+
1097
1557
  Object.assign(webex.internal, {
1098
1558
  services: {
1099
1559
  getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
1100
1560
  },
1561
+ });
1101
1562
 
1563
+ await webex.meetings.fetchUserPreferredWebexSite().then(() => {
1564
+ assert.equal(webex.meetings.preferredWebexSite, '');
1102
1565
  });
1566
+ assert.calledOnceWithExactly(
1567
+ loggerProxySpy,
1568
+ 'Failed to fetch preferred site from user - no site will be set'
1569
+ );
1570
+ });
1103
1571
 
1104
- await webex.meetings.fetchUserPreferredWebexSite()
1105
- .then(() => {
1106
- assert.equal(webex.meetings.preferredWebexSite, '');
1107
- });
1572
+ it('should fall back to fetching the site from the user', async () => {
1573
+ setup({
1574
+ user: {
1575
+ userPreferences: {
1576
+ userPreferencesItems: {
1577
+ preferredWebExSite: 'site.webex.com',
1578
+ },
1579
+ },
1580
+ },
1581
+ });
1582
+
1583
+ await webex.meetings.fetchUserPreferredWebexSite();
1584
+
1585
+ assert.equal(webex.meetings.preferredWebexSite, 'site.webex.com');
1586
+ assert.notCalled(loggerProxySpy);
1587
+ });
1588
+
1589
+ forEach([
1590
+ {user: undefined},
1591
+ {user: {userPreferences: {}}},
1592
+ {user: {userPreferences: {userPreferencesItems: {}}}},
1593
+ {user: {userPreferences: {userPreferencesItems: {preferredWebExSite: undefined}}}},
1594
+ ], ({user}) => {
1595
+ it(`should handle invalid user data ${user}`, async () => {
1596
+ setup({user});
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
+ );
1605
+ });
1606
+ });
1607
+
1608
+ it('should handle a get user failure', async () => {
1609
+ setup();
1610
+
1611
+ webex.internal.user.get.rejects(new Error());
1612
+
1613
+ await webex.meetings.fetchUserPreferredWebexSite();
1614
+
1615
+ assert.equal(webex.meetings.preferredWebexSite, '');
1616
+ assert.calledOnceWithExactly(
1617
+ loggerProxySpy,
1618
+ 'Failed to fetch preferred site from user - no site will be set'
1619
+ );
1108
1620
  });
1621
+
1109
1622
  });
1110
1623
  });
1111
1624
 
@@ -1120,11 +1633,14 @@ describe('plugin-meetings', () => {
1120
1633
  TriggerProxy.trigger.reset();
1121
1634
  // clock = sinon.useFakeTimers();
1122
1635
  // setTimeoutSpy = sinon.spy(clock, 'setTimeout');
1123
- webex.meetings.meetingInfo.fetchMeetingInfo = sinon.stub().returns(Promise.resolve({
1124
- body: {
1125
- permissionToken: 'PT', meetingJoinUrl: 'meetingJoinUrl'
1126
- }
1127
- }));
1636
+ webex.meetings.meetingInfo.fetchMeetingInfo = sinon.stub().returns(
1637
+ Promise.resolve({
1638
+ body: {
1639
+ permissionToken: 'PT',
1640
+ meetingJoinUrl: 'meetingJoinUrl',
1641
+ },
1642
+ })
1643
+ );
1128
1644
 
1129
1645
  meeting = await webex.meetings.createMeeting('test destination', 'test type');
1130
1646
 
@@ -1132,37 +1648,37 @@ describe('plugin-meetings', () => {
1132
1648
  });
1133
1649
 
1134
1650
  it('triggers correct event when CONTROLS_ENTRY_EXIT_TONE_UPDATED emitted', async () => {
1135
- await meeting.locusInfo.emitScoped(
1136
- {},
1137
- LOCUSINFO.EVENTS.CONTROLS_ENTRY_EXIT_TONE_UPDATED,
1138
- {entryExitTone: 'foo'}
1139
- );
1651
+ await meeting.locusInfo.emitScoped({}, LOCUSINFO.EVENTS.CONTROLS_ENTRY_EXIT_TONE_UPDATED, {
1652
+ entryExitTone: 'foo',
1653
+ });
1140
1654
 
1141
1655
  assert.calledOnce(TriggerProxy.trigger);
1142
- assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting),
1656
+ assert.calledWith(
1657
+ TriggerProxy.trigger,
1658
+ sinon.match.instanceOf(Meeting),
1143
1659
  {
1144
1660
  file: 'meeting/index',
1145
- function: 'setupLocusControlsListener'
1661
+ function: 'setupLocusControlsListener',
1146
1662
  },
1147
1663
  EVENT_TRIGGERS.MEETING_ENTRY_EXIT_TONE_UPDATE,
1148
- {entryExitTone: 'foo'});
1664
+ {entryExitTone: 'foo'}
1665
+ );
1149
1666
  });
1150
1667
 
1151
1668
  const checkSelfTrigger = async (inEvent, outEvent) => {
1152
- await meeting.locusInfo.emitScoped(
1153
- {},
1154
- inEvent,
1155
- {foo: 'bar'}
1156
- );
1669
+ await meeting.locusInfo.emitScoped({}, inEvent, {foo: 'bar'});
1157
1670
 
1158
1671
  assert.calledOnce(TriggerProxy.trigger);
1159
- assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting),
1672
+ assert.calledWith(
1673
+ TriggerProxy.trigger,
1674
+ sinon.match.instanceOf(Meeting),
1160
1675
  {
1161
1676
  file: 'meeting/index',
1162
- function: 'setUpLocusInfoSelfListener'
1677
+ function: 'setUpLocusInfoSelfListener',
1163
1678
  },
1164
1679
  outEvent,
1165
- {payload: {foo: 'bar'}});
1680
+ {payload: {foo: 'bar'}}
1681
+ );
1166
1682
  };
1167
1683
 
1168
1684
  it('triggers correct event when SELF_CANNOT_VIEW_PARTICIPANT_LIST_CHANGE emitted', async () => {
@@ -1186,5 +1702,477 @@ describe('plugin-meetings', () => {
1186
1702
  );
1187
1703
  });
1188
1704
  });
1705
+
1706
+ describe('#isNeedHandleMainLocus', () => {
1707
+ let meeting;
1708
+ let newLocus;
1709
+ beforeEach(() => {
1710
+ meeting = {
1711
+ controls: {},
1712
+ self: {},
1713
+ };
1714
+ newLocus = {
1715
+ controls: {},
1716
+ self: {},
1717
+ }
1718
+ });
1719
+ afterEach(() => {
1720
+ sinon.restore();
1721
+ });
1722
+ it('check normal case will return true', () => {
1723
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns(null);
1724
+ LoggerProxy.logger.log = sinon.stub();
1725
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1726
+ assert.equal(result, true);
1727
+ assert.calledWith(
1728
+ LoggerProxy.logger.log,
1729
+ 'Meetings:index#isNeedHandleMainLocus --> this is a normal main session locusDTO update case'
1730
+ );
1731
+ });
1732
+
1733
+ it('check self joined and joined on this device, return true', () => {
1734
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns(null);
1735
+ newLocus.self.state = 'JOINED';
1736
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(true);
1737
+
1738
+ LoggerProxy.logger.log = sinon.stub();
1739
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1740
+ assert.equal(result, true);
1741
+ assert.calledWith(
1742
+ LoggerProxy.logger.log,
1743
+ 'Meetings:index#isNeedHandleMainLocus --> self this device shown as JOINED in the main session'
1744
+ );
1745
+ });
1746
+
1747
+ it('if newLocus replaceAt time is expired, then return false', () => {
1748
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({joinedWith: {replaces: [{
1749
+ replaceAt: '2023-03-27T02:17:02.506Z',
1750
+ }]}});
1751
+ newLocus.self.state = 'JOINED';
1752
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(true);
1753
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1754
+ replaces: [{
1755
+ replaceAt: '2023-03-27T02:17:01.506Z'
1756
+ }]
1757
+ })
1758
+
1759
+ LoggerProxy.logger.log = sinon.stub();
1760
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1761
+ assert.equal(result, false);
1762
+ assert.calledWith(
1763
+ LoggerProxy.logger.log,
1764
+ `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`
1765
+ );
1766
+ });
1767
+
1768
+ it('check current is in breakout join with this device, return false', () => {
1769
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({
1770
+ joinedWith: {
1771
+ correlationId: '111',
1772
+ },
1773
+ });
1774
+ newLocus.controls.breakout = {url: 'url'};
1775
+ meeting.correlationId = '111';
1776
+
1777
+ LoggerProxy.logger.log = sinon.stub();
1778
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1779
+ assert.equal(result, false);
1780
+ assert.calledWith(
1781
+ LoggerProxy.logger.log,
1782
+ `Meetings:index#isNeedHandleMainLocus --> there is active breakout session and joined on this device, and don't need to handle main session: url`
1783
+ );
1784
+ });
1785
+
1786
+ it('check self is moved and removed, return false', () => {
1787
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1788
+ newLocus.self.state = 'LEFT';
1789
+ newLocus.self.reason = 'MOVED';
1790
+ newLocus.self.removed = true;
1791
+ LoggerProxy.logger.log = sinon.stub();
1792
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1793
+ assert.equal(result, false);
1794
+ assert.calledWith(
1795
+ LoggerProxy.logger.log,
1796
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1797
+ );
1798
+ });
1799
+
1800
+ it('check self is moved and device resource removed, return false', () => {
1801
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1802
+ newLocus.self.state = 'LEFT';
1803
+ newLocus.self.reason = 'MOVED';
1804
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1805
+ state: 'LEFT',
1806
+ reason: 'MOVED',
1807
+ });
1808
+ LoggerProxy.logger.log = sinon.stub();
1809
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1810
+ assert.equal(result, false);
1811
+ assert.calledWith(
1812
+ LoggerProxy.logger.log,
1813
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1814
+ );
1815
+ });
1816
+
1817
+ it('check self is joined but device resource removed, return false', () => {
1818
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1819
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(false);
1820
+ newLocus.self.state = 'JOINED';
1821
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1822
+ state: 'LEFT',
1823
+ reason: 'MOVED',
1824
+ });
1825
+ LoggerProxy.logger.log = sinon.stub();
1826
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1827
+ assert.equal(result, false);
1828
+ assert.calledWith(
1829
+ LoggerProxy.logger.log,
1830
+ 'Meetings:index#isNeedHandleMainLocus --> self device left&moved in main locus with self joined status, not need to handle'
1831
+ );
1832
+ });
1833
+ });
1834
+
1835
+ describe('#isNeedHandleLocusDTO', () => {
1836
+ let meeting;
1837
+ let newLocus;
1838
+ beforeEach(() => {
1839
+ meeting = {
1840
+ controls: {},
1841
+ self: {},
1842
+ };
1843
+ newLocus = {
1844
+ controls: {},
1845
+ self: {},
1846
+ }
1847
+ });
1848
+ afterEach(() => {
1849
+ sinon.restore();
1850
+ });
1851
+ it('initial DTO , joined breakout session, return true', () => {
1852
+ newLocus.controls.breakout = {
1853
+ sessionType: 'BREAKOUT',
1854
+ };
1855
+ newLocus.self.state = 'JOINED';
1856
+ newLocus.fullState = {
1857
+ active: true,
1858
+ };
1859
+ LoggerProxy.logger.log = sinon.stub();
1860
+ const result = webex.meetings.isNeedHandleLocusDTO(null, newLocus);
1861
+ assert.equal(result, true);
1862
+ assert.calledWith(
1863
+ LoggerProxy.logger.log,
1864
+ `Meetings:index#isNeedHandleLocusDTO --> the first breakout session locusDTO active status: true`
1865
+ );
1866
+ });
1867
+ it('others go to check isNeedHandleMainLocus', () => {
1868
+ newLocus.controls.breakout = {
1869
+ sessionType: 'MAIN',
1870
+ };
1871
+ newLocus.self.state = 'JOINED';
1872
+
1873
+ LoggerProxy.logger.log = sinon.stub();
1874
+ const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
1875
+ assert.equal(result, true);
1876
+ assert.calledWith(
1877
+ LoggerProxy.logger.log,
1878
+ 'Meetings:index#isNeedHandleMainLocus --> this is a normal main session locusDTO update case'
1879
+ );
1880
+ });
1881
+ it('joined breakout session, self status is moved, return false', () => {
1882
+ newLocus.controls.breakout = {
1883
+ sessionType: 'BREAKOUT',
1884
+ };
1885
+ newLocus.self.state = 'LEFT';
1886
+ newLocus.self.reason = 'MOVED';
1887
+
1888
+ LoggerProxy.logger.log = sinon.stub();
1889
+ const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
1890
+ assert.equal(result, false);
1891
+ });
1892
+ });
1893
+
1894
+ describe('#getCorrespondingMeetingByLocus', () => {
1895
+ let locus;
1896
+ let mockReturnMeeting = {meeting: 'meeting1'};
1897
+ const mockGetByKey = (keyWillReturnMeeting) => {
1898
+ webex.meetings.meetingCollection.getByKey = sinon.stub().callsFake((key) => {
1899
+ if (key === keyWillReturnMeeting) {
1900
+ return mockReturnMeeting;
1901
+ }
1902
+ return null;
1903
+ });
1904
+ };
1905
+
1906
+ beforeEach(() => {
1907
+ locus = {
1908
+ controls: {},
1909
+ self: {
1910
+ callbackInfo: {
1911
+ callbackAddress: 'address1',
1912
+ }
1913
+ },
1914
+ info: {
1915
+ webExMeetingId: '123456',
1916
+ isUnifiedSpaceMeeting: false,
1917
+ },
1918
+ conversationUrl: 'conversationUrl1'
1919
+ };
1920
+
1921
+ sinon.stub(MeetingsUtil, 'checkForCorrelationId').returns('correlationId1');
1922
+ });
1923
+ afterEach(() => {
1924
+ sinon.restore();
1925
+ });
1926
+ it('check the calls when no meeting found in meetingCollection', () => {
1927
+ mockGetByKey();
1928
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1929
+ assert.isNull(result);
1930
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1931
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1932
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1933
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1934
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1935
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1936
+ });
1937
+
1938
+ it('not try getByKey "conversationUrl" when isUnifiedSpaceMeeting is true', () => {
1939
+ mockGetByKey();
1940
+ locus.info.isUnifiedSpaceMeeting = true;
1941
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1942
+ assert.isNull(result);
1943
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1944
+ })
1945
+
1946
+ it('check the calls when meeting found by key: locusUrl', () => {
1947
+ mockGetByKey('locusUrl');
1948
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1949
+ assert.deepEqual(result, mockReturnMeeting);
1950
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 1);
1951
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1952
+ });
1953
+
1954
+ it('check the calls when meeting found by key: correlationId', () => {
1955
+ mockGetByKey('correlationId');
1956
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1957
+ assert.deepEqual(result, mockReturnMeeting);
1958
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 2);
1959
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1960
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1961
+ });
1962
+
1963
+ it('check the calls when meeting found by key: sipUri', () => {
1964
+ mockGetByKey('sipUri');
1965
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1966
+ assert.deepEqual(result, mockReturnMeeting);
1967
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
1968
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1969
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1970
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1971
+ });
1972
+
1973
+ it('check the calls when meeting found by key: conversationUrl', () => {
1974
+ mockGetByKey('conversationUrl');
1975
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1976
+ assert.deepEqual(result, mockReturnMeeting);
1977
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1978
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1979
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1980
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1981
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1982
+ });
1983
+
1984
+ it('check the calls when meeting found by key: meetingNumber', () => {
1985
+ mockGetByKey('meetingNumber');
1986
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1987
+ assert.deepEqual(result, mockReturnMeeting);
1988
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1989
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1990
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1991
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1992
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1993
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1994
+ });
1995
+ });
1996
+
1997
+ describe('#sortLocusArrayToUpdate', () => {
1998
+ let lociArray;
1999
+ let mainLocus;
2000
+ let breakoutLocus;
2001
+ beforeEach(() => {
2002
+ mainLocus = {
2003
+ url: 'mainUrl1',
2004
+ controls: {
2005
+ breakout: {
2006
+ sessionType: 'MAIN',
2007
+ url: 'breakoutUnifiedUrl1'
2008
+ }
2009
+ }
2010
+ };
2011
+ breakoutLocus = {
2012
+ url: 'breakoutUrl1',
2013
+ controls: {
2014
+ breakout: {
2015
+ sessionType: 'BREAKOUT',
2016
+ url: 'breakoutUnifiedUrl1'
2017
+ }
2018
+ }
2019
+ };
2020
+ lociArray = [mainLocus, breakoutLocus];
2021
+
2022
+ sinon.stub(MeetingsUtil, 'isValidBreakoutLocus').callsFake((locus) => {
2023
+ return locus.url === 'breakoutUrl1';
2024
+ });
2025
+ });
2026
+ afterEach(() => {
2027
+ sinon.restore();
2028
+ });
2029
+
2030
+ it('if both main and breakout locus is in array for non-exist meeting, return main locus to create first', () => {
2031
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
2032
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2033
+ assert.deepEqual(result, [mainLocus]);
2034
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, [breakoutLocus]);
2035
+ });
2036
+
2037
+ it('if both main and breakout locus is in array for an exist meeting, return all locus', () => {
2038
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2039
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2040
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2041
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, []);
2042
+ });
2043
+
2044
+ it('if the breakout locus has no associated main locus, return all', () => {
2045
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2046
+ breakoutLocus.controls.breakout.url = 'testUrl';
2047
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2048
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2049
+ });
2050
+ });
2051
+
2052
+ describe('#checkHandleBreakoutLocus', () => {
2053
+ let breakoutLocus;
2054
+ beforeEach(() => {
2055
+ breakoutLocus = {
2056
+ url: 'breakoutUrl1',
2057
+ controls: {
2058
+ breakout: {
2059
+ sessionType: 'BREAKOUT',
2060
+ url: 'breakoutUnifiedUrl1',
2061
+ }
2062
+ }
2063
+ };
2064
+
2065
+ webex.meetings.handleLocusEvent = sinon.stub();
2066
+ });
2067
+ afterEach(() => {
2068
+ sinon.restore();
2069
+ });
2070
+ it('do nothing if new created locus is null/no cached breakouts for updating', () => {
2071
+ webex.meetings.checkHandleBreakoutLocus(null);
2072
+ webex.meetings.breakoutLocusForHandleLater = null;
2073
+ webex.meetings.checkHandleBreakoutLocus({});
2074
+ webex.meetings.breakoutLocusForHandleLater = [];
2075
+ webex.meetings.checkHandleBreakoutLocus({});
2076
+ assert.notCalled(webex.meetings.handleLocusEvent);
2077
+ });
2078
+
2079
+ it('do nothing if new created locus is breakout locus', () => {
2080
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2081
+ webex.meetings.checkHandleBreakoutLocus(breakoutLocus);
2082
+ assert.notCalled(webex.meetings.handleLocusEvent);
2083
+ });
2084
+
2085
+ it('do nothing if no cached locus is associated with the new created locus', () => {
2086
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2087
+ webex.meetings.checkHandleBreakoutLocus({
2088
+ controls: {
2089
+ breakout: {
2090
+ sessionType: 'MAIN',
2091
+ url: 'breakoutUnifiedUrl2',
2092
+ }
2093
+ }
2094
+ });
2095
+ assert.notCalled(webex.meetings.handleLocusEvent);
2096
+ });
2097
+
2098
+ it('update the cached breakout locus which associate the new created locus', () => {
2099
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2100
+ webex.meetings.checkHandleBreakoutLocus({
2101
+ controls: {
2102
+ breakout: {
2103
+ sessionType: 'MAIN',
2104
+ url: 'breakoutUnifiedUrl1',
2105
+ }
2106
+ }
2107
+ });
2108
+ assert.calledWith(webex.meetings.handleLocusEvent, {locus: breakoutLocus, locusUrl: breakoutLocus.url});
2109
+ });
2110
+ });
2111
+
2112
+ describe('uploading of logs', () => {
2113
+ let metricsSpy;
2114
+ let meeting;
2115
+
2116
+ beforeEach(async () => {
2117
+ webex.meetings.config.autoUploadLogs = true;
2118
+ webex.meetings.loggerRequest.uploadLogs = sinon.stub().resolves();
2119
+
2120
+ sinon.stub(webex.meetings.meetingInfo, 'fetchInfoOptions').resolves({});
2121
+ sinon.stub(webex.meetings.meetingInfo, 'fetchMeetingInfo').resolves({});
2122
+
2123
+ triggerProxyStub.restore();
2124
+
2125
+ metricsSpy = sinon.stub(Metrics, 'sendBehavioralMetric');
2126
+
2127
+ meeting = await webex.meetings.create('test');
2128
+
2129
+ meeting.locusId = 'locus id';
2130
+ meeting.correlationId = 'correlation id';
2131
+ meeting.locusInfo = {
2132
+ fullState: { lastActive: 'last active', sessionId: 'locus session id'},
2133
+ info: { webExMeetingId: 'meeting id'}
2134
+ }
2135
+ });
2136
+
2137
+ afterEach(() => {
2138
+ sinon.restore();
2139
+ })
2140
+
2141
+ it('sends metrics on success', async () => {
2142
+
2143
+ await meeting.uploadLogs();
2144
+
2145
+ await testUtils.flushPromises();
2146
+
2147
+ assert.calledOnceWithExactly(metricsSpy, 'js_sdk_upload_logs_success', {
2148
+ callStart: 'last active',
2149
+ correlationId: 'correlation id',
2150
+ feedbackId: 'correlation id',
2151
+ locusId: 'locus id',
2152
+ meetingId: 'meeting id',
2153
+ autoupload: true,
2154
+ locussessionid: 'locus session id',
2155
+ });
2156
+ });
2157
+
2158
+ it('sends metrics on failure', async () => {
2159
+ webex.meetings.loggerRequest.uploadLogs.rejects(new Error('fake error'));
2160
+
2161
+ await meeting.uploadLogs();
2162
+
2163
+ await testUtils.flushPromises();
2164
+
2165
+ assert.calledOnceWithExactly(metricsSpy, 'js_sdk_upload_logs_failure', sinon.match({
2166
+ callStart: 'last active',
2167
+ correlationId: 'correlation id',
2168
+ feedbackId: 'correlation id',
2169
+ locusId: 'locus id',
2170
+ meetingId: 'meeting id',
2171
+ reason: 'fake error',
2172
+ autoupload: true,
2173
+ locussessionid: 'locus session id',
2174
+ }));
2175
+ });
2176
+ });
1189
2177
  });
1190
2178
  });