@webex/plugin-meetings 3.0.0-beta.13 → 3.0.0-beta.130

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