@webex/plugin-meetings 2.59.3-next.1 → 2.59.4

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 (420) hide show
  1. package/.eslintrc.js +6 -6
  2. package/LICENSE +1 -1
  3. package/README.md +1204 -1204
  4. package/UPGRADING.md +287 -287
  5. package/babel.config.js +3 -3
  6. package/browsers.js +108 -108
  7. package/dist/common/browser-detection.d.ts +9 -9
  8. package/dist/common/browser-detection.js.map +1 -1
  9. package/dist/common/collection.d.ts +48 -48
  10. package/dist/common/collection.js +43 -43
  11. package/dist/common/collection.js.map +1 -1
  12. package/dist/common/config.d.ts +2 -2
  13. package/dist/common/config.js.map +1 -1
  14. package/dist/common/errors/captcha-error.d.ts +15 -15
  15. package/dist/common/errors/captcha-error.js +7 -7
  16. package/dist/common/errors/captcha-error.js.map +1 -1
  17. package/dist/common/errors/intent-to-join.d.ts +16 -16
  18. package/dist/common/errors/intent-to-join.js +7 -7
  19. package/dist/common/errors/intent-to-join.js.map +1 -1
  20. package/dist/common/errors/join-meeting.d.ts +17 -17
  21. package/dist/common/errors/join-meeting.js +8 -8
  22. package/dist/common/errors/join-meeting.js.map +1 -1
  23. package/dist/common/errors/media.d.ts +15 -15
  24. package/dist/common/errors/media.js +7 -7
  25. package/dist/common/errors/media.js.map +1 -1
  26. package/dist/common/errors/parameter.d.ts +15 -15
  27. package/dist/common/errors/parameter.js +7 -7
  28. package/dist/common/errors/parameter.js.map +1 -1
  29. package/dist/common/errors/password-error.d.ts +15 -15
  30. package/dist/common/errors/password-error.js +7 -7
  31. package/dist/common/errors/password-error.js.map +1 -1
  32. package/dist/common/errors/permission.d.ts +14 -14
  33. package/dist/common/errors/permission.js +6 -6
  34. package/dist/common/errors/permission.js.map +1 -1
  35. package/dist/common/errors/reconnection-in-progress.d.ts +9 -9
  36. package/dist/common/errors/reconnection-in-progress.js +6 -6
  37. package/dist/common/errors/reconnection-in-progress.js.map +1 -1
  38. package/dist/common/errors/reconnection.d.ts +15 -15
  39. package/dist/common/errors/reconnection.js +7 -7
  40. package/dist/common/errors/reconnection.js.map +1 -1
  41. package/dist/common/errors/stats.d.ts +15 -15
  42. package/dist/common/errors/stats.js +7 -7
  43. package/dist/common/errors/stats.js.map +1 -1
  44. package/dist/common/errors/webex-errors.d.ts +81 -81
  45. package/dist/common/errors/webex-errors.js +42 -42
  46. package/dist/common/errors/webex-errors.js.map +1 -1
  47. package/dist/common/errors/webex-meetings-error.d.ts +20 -20
  48. package/dist/common/errors/webex-meetings-error.js +12 -12
  49. package/dist/common/errors/webex-meetings-error.js.map +1 -1
  50. package/dist/common/events/events-scope.d.ts +17 -17
  51. package/dist/common/events/events-scope.js +10 -10
  52. package/dist/common/events/events-scope.js.map +1 -1
  53. package/dist/common/events/events.d.ts +12 -12
  54. package/dist/common/events/events.js +4 -4
  55. package/dist/common/events/events.js.map +1 -1
  56. package/dist/common/events/trigger-proxy.d.ts +2 -2
  57. package/dist/common/events/trigger-proxy.js.map +1 -1
  58. package/dist/common/events/util.d.ts +2 -2
  59. package/dist/common/events/util.js.map +1 -1
  60. package/dist/common/logs/logger-config.d.ts +2 -2
  61. package/dist/common/logs/logger-config.js.map +1 -1
  62. package/dist/common/logs/logger-proxy.d.ts +2 -2
  63. package/dist/common/logs/logger-proxy.js.map +1 -1
  64. package/dist/common/logs/request.d.ts +34 -34
  65. package/dist/common/logs/request.js +18 -18
  66. package/dist/common/logs/request.js.map +1 -1
  67. package/dist/common/queue.d.ts +32 -32
  68. package/dist/common/queue.js +18 -18
  69. package/dist/common/queue.js.map +1 -1
  70. package/dist/config.d.ts +73 -73
  71. package/dist/config.js +2 -2
  72. package/dist/config.js.map +1 -1
  73. package/dist/constants.d.ts +926 -924
  74. package/dist/constants.js +11 -9
  75. package/dist/constants.js.map +1 -1
  76. package/dist/controls-options-manager/constants.d.ts +4 -4
  77. package/dist/controls-options-manager/constants.js.map +1 -1
  78. package/dist/controls-options-manager/enums.d.ts +5 -5
  79. package/dist/controls-options-manager/enums.js.map +1 -1
  80. package/dist/controls-options-manager/index.d.ts +120 -120
  81. package/dist/controls-options-manager/index.js +81 -81
  82. package/dist/controls-options-manager/index.js.map +1 -1
  83. package/dist/controls-options-manager/util.d.ts +7 -7
  84. package/dist/controls-options-manager/util.js.map +1 -1
  85. package/dist/index.d.ts +4 -4
  86. package/dist/index.js.map +1 -1
  87. package/dist/locus-info/controlsUtils.d.ts +2 -2
  88. package/dist/locus-info/controlsUtils.js +21 -21
  89. package/dist/locus-info/controlsUtils.js.map +1 -1
  90. package/dist/locus-info/embeddedAppsUtils.d.ts +2 -2
  91. package/dist/locus-info/embeddedAppsUtils.js +14 -14
  92. package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
  93. package/dist/locus-info/fullState.d.ts +2 -2
  94. package/dist/locus-info/fullState.js.map +1 -1
  95. package/dist/locus-info/hostUtils.d.ts +2 -2
  96. package/dist/locus-info/hostUtils.js +19 -19
  97. package/dist/locus-info/hostUtils.js.map +1 -1
  98. package/dist/locus-info/index.d.ts +269 -269
  99. package/dist/locus-info/index.js +180 -180
  100. package/dist/locus-info/index.js.map +1 -1
  101. package/dist/locus-info/infoUtils.d.ts +2 -2
  102. package/dist/locus-info/infoUtils.js.map +1 -1
  103. package/dist/locus-info/mediaSharesUtils.d.ts +2 -2
  104. package/dist/locus-info/mediaSharesUtils.js +50 -50
  105. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  106. package/dist/locus-info/parser.d.ts +212 -212
  107. package/dist/locus-info/parser.js +136 -136
  108. package/dist/locus-info/parser.js.map +1 -1
  109. package/dist/locus-info/selfUtils.d.ts +2 -2
  110. package/dist/locus-info/selfUtils.js +52 -52
  111. package/dist/locus-info/selfUtils.js.map +1 -1
  112. package/dist/media/index.d.ts +32 -32
  113. package/dist/media/index.js +145 -145
  114. package/dist/media/index.js.map +1 -1
  115. package/dist/media/properties.d.ts +108 -108
  116. package/dist/media/properties.js +49 -49
  117. package/dist/media/properties.js.map +1 -1
  118. package/dist/media/util.d.ts +2 -2
  119. package/dist/media/util.js.map +1 -1
  120. package/dist/mediaQualityMetrics/config.d.ts +233 -233
  121. package/dist/mediaQualityMetrics/config.js.map +1 -1
  122. package/dist/meeting/effectsState.d.ts +42 -42
  123. package/dist/meeting/effectsState.js +24 -24
  124. package/dist/meeting/effectsState.js.map +1 -1
  125. package/dist/meeting/in-meeting-actions.d.ts +79 -79
  126. package/dist/meeting/in-meeting-actions.js +11 -11
  127. package/dist/meeting/in-meeting-actions.js.map +1 -1
  128. package/dist/meeting/index.d.ts +1621 -1621
  129. package/dist/meeting/index.js +1538 -1518
  130. package/dist/meeting/index.js.map +1 -1
  131. package/dist/meeting/muteState.d.ts +116 -116
  132. package/dist/meeting/muteState.js +85 -85
  133. package/dist/meeting/muteState.js.map +1 -1
  134. package/dist/meeting/request.d.ts +255 -255
  135. package/dist/meeting/request.js +141 -141
  136. package/dist/meeting/request.js.map +1 -1
  137. package/dist/meeting/state.d.ts +9 -9
  138. package/dist/meeting/state.js +30 -30
  139. package/dist/meeting/state.js.map +1 -1
  140. package/dist/meeting/util.d.ts +2 -2
  141. package/dist/meeting/util.js.map +1 -1
  142. package/dist/meeting-info/collection.d.ts +20 -20
  143. package/dist/meeting-info/collection.js +11 -11
  144. package/dist/meeting-info/collection.js.map +1 -1
  145. package/dist/meeting-info/index.d.ts +57 -57
  146. package/dist/meeting-info/index.js +50 -50
  147. package/dist/meeting-info/index.js.map +1 -1
  148. package/dist/meeting-info/meeting-info-v2.d.ts +93 -93
  149. package/dist/meeting-info/meeting-info-v2.js +52 -52
  150. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  151. package/dist/meeting-info/request.d.ts +22 -22
  152. package/dist/meeting-info/request.js +14 -14
  153. package/dist/meeting-info/request.js.map +1 -1
  154. package/dist/meeting-info/util.d.ts +2 -2
  155. package/dist/meeting-info/util.js +9 -9
  156. package/dist/meeting-info/util.js.map +1 -1
  157. package/dist/meeting-info/utilv2.d.ts +2 -2
  158. package/dist/meeting-info/utilv2.js +20 -20
  159. package/dist/meeting-info/utilv2.js.map +1 -1
  160. package/dist/meetings/collection.d.ts +23 -23
  161. package/dist/meetings/collection.js +14 -14
  162. package/dist/meetings/collection.js.map +1 -1
  163. package/dist/meetings/index.d.ts +296 -296
  164. package/dist/meetings/index.js +259 -259
  165. package/dist/meetings/index.js.map +1 -1
  166. package/dist/meetings/request.d.ts +27 -27
  167. package/dist/meetings/request.js +15 -15
  168. package/dist/meetings/request.js.map +1 -1
  169. package/dist/meetings/util.d.ts +18 -18
  170. package/dist/meetings/util.js +29 -29
  171. package/dist/meetings/util.js.map +1 -1
  172. package/dist/member/index.d.ts +147 -147
  173. package/dist/member/index.js +214 -214
  174. package/dist/member/index.js.map +1 -1
  175. package/dist/member/member.types.d.ts +11 -11
  176. package/dist/member/member.types.js.map +1 -1
  177. package/dist/member/util.d.ts +2 -2
  178. package/dist/member/util.js +60 -60
  179. package/dist/member/util.js.map +1 -1
  180. package/dist/members/collection.d.ts +24 -24
  181. package/dist/members/collection.js +11 -11
  182. package/dist/members/collection.js.map +1 -1
  183. package/dist/members/index.d.ts +298 -298
  184. package/dist/members/index.js +275 -275
  185. package/dist/members/index.js.map +1 -1
  186. package/dist/members/request.d.ts +50 -50
  187. package/dist/members/request.js +27 -27
  188. package/dist/members/request.js.map +1 -1
  189. package/dist/members/util.d.ts +2 -2
  190. package/dist/members/util.js +21 -21
  191. package/dist/members/util.js.map +1 -1
  192. package/dist/metrics/config.d.ts +169 -169
  193. package/dist/metrics/config.js.map +1 -1
  194. package/dist/metrics/constants.d.ts +59 -57
  195. package/dist/metrics/constants.js +2 -0
  196. package/dist/metrics/constants.js.map +1 -1
  197. package/dist/metrics/index.d.ts +152 -152
  198. package/dist/metrics/index.js +90 -90
  199. package/dist/metrics/index.js.map +1 -1
  200. package/dist/networkQualityMonitor/index.d.ts +70 -70
  201. package/dist/networkQualityMonitor/index.js +65 -65
  202. package/dist/networkQualityMonitor/index.js.map +1 -1
  203. package/dist/peer-connection-manager/index.d.ts +6 -6
  204. package/dist/peer-connection-manager/index.js +87 -87
  205. package/dist/peer-connection-manager/index.js.map +1 -1
  206. package/dist/peer-connection-manager/util.d.ts +6 -6
  207. package/dist/peer-connection-manager/util.js +9 -9
  208. package/dist/peer-connection-manager/util.js.map +1 -1
  209. package/dist/personal-meeting-room/index.d.ts +47 -47
  210. package/dist/personal-meeting-room/index.js +67 -67
  211. package/dist/personal-meeting-room/index.js.map +1 -1
  212. package/dist/personal-meeting-room/request.d.ts +14 -14
  213. package/dist/personal-meeting-room/request.js +7 -7
  214. package/dist/personal-meeting-room/request.js.map +1 -1
  215. package/dist/personal-meeting-room/util.d.ts +2 -2
  216. package/dist/personal-meeting-room/util.js.map +1 -1
  217. package/dist/reachability/index.d.ts +139 -139
  218. package/dist/reachability/index.js +110 -110
  219. package/dist/reachability/index.js.map +1 -1
  220. package/dist/reachability/request.d.ts +35 -35
  221. package/dist/reachability/request.js +15 -15
  222. package/dist/reachability/request.js.map +1 -1
  223. package/dist/reactions/reactions.d.ts +4 -4
  224. package/dist/reactions/reactions.js.map +1 -1
  225. package/dist/reactions/reactions.type.d.ts +32 -32
  226. package/dist/reactions/reactions.type.js.map +1 -1
  227. package/dist/reconnection-manager/index.d.ts +112 -112
  228. package/dist/reconnection-manager/index.js +112 -112
  229. package/dist/reconnection-manager/index.js.map +1 -1
  230. package/dist/recording-controller/enums.d.ts +7 -7
  231. package/dist/recording-controller/enums.js.map +1 -1
  232. package/dist/recording-controller/index.d.ts +193 -193
  233. package/dist/recording-controller/index.js +127 -127
  234. package/dist/recording-controller/index.js.map +1 -1
  235. package/dist/recording-controller/util.d.ts +13 -13
  236. package/dist/recording-controller/util.js.map +1 -1
  237. package/dist/roap/collection.d.ts +10 -10
  238. package/dist/roap/collection.js.map +1 -1
  239. package/dist/roap/handler.d.ts +47 -47
  240. package/dist/roap/handler.js +27 -27
  241. package/dist/roap/handler.js.map +1 -1
  242. package/dist/roap/index.d.ts +116 -116
  243. package/dist/roap/index.js +111 -111
  244. package/dist/roap/index.js.map +1 -1
  245. package/dist/roap/request.d.ts +35 -35
  246. package/dist/roap/request.js +17 -17
  247. package/dist/roap/request.js.map +1 -1
  248. package/dist/roap/state.d.ts +9 -9
  249. package/dist/roap/state.js +14 -14
  250. package/dist/roap/state.js.map +1 -1
  251. package/dist/roap/turnDiscovery.d.ts +67 -67
  252. package/dist/roap/turnDiscovery.js +46 -46
  253. package/dist/roap/turnDiscovery.js.map +1 -1
  254. package/dist/roap/util.d.ts +2 -2
  255. package/dist/roap/util.js.map +1 -1
  256. package/dist/statsAnalyzer/global.d.ts +118 -126
  257. package/dist/statsAnalyzer/global.js +4 -12
  258. package/dist/statsAnalyzer/global.js.map +1 -1
  259. package/dist/statsAnalyzer/index.d.ts +193 -190
  260. package/dist/statsAnalyzer/index.js +182 -140
  261. package/dist/statsAnalyzer/index.js.map +1 -1
  262. package/dist/statsAnalyzer/mqaUtil.d.ts +22 -22
  263. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  264. package/dist/transcription/index.d.ts +64 -64
  265. package/dist/transcription/index.js +42 -42
  266. package/dist/transcription/index.js.map +1 -1
  267. package/internal-README.md +172 -172
  268. package/jest.config.js +3 -3
  269. package/package.json +21 -22
  270. package/process +1 -1
  271. package/src/common/browser-detection.ts +39 -39
  272. package/src/common/collection.ts +94 -94
  273. package/src/common/config.ts +9 -9
  274. package/src/common/errors/captcha-error.ts +25 -25
  275. package/src/common/errors/intent-to-join.ts +27 -27
  276. package/src/common/errors/join-meeting.ts +32 -32
  277. package/src/common/errors/media.ts +25 -25
  278. package/src/common/errors/parameter.ts +33 -33
  279. package/src/common/errors/password-error.ts +25 -25
  280. package/src/common/errors/permission.ts +24 -24
  281. package/src/common/errors/reconnection-in-progress.ts +8 -8
  282. package/src/common/errors/reconnection.ts +25 -25
  283. package/src/common/errors/stats.ts +25 -25
  284. package/src/common/errors/webex-errors.ts +140 -140
  285. package/src/common/errors/webex-meetings-error.ts +35 -35
  286. package/src/common/events/events-scope.ts +30 -30
  287. package/src/common/events/events.ts +25 -25
  288. package/src/common/events/trigger-proxy.ts +25 -25
  289. package/src/common/events/util.ts +39 -39
  290. package/src/common/logs/logger-config.ts +8 -8
  291. package/src/common/logs/logger-proxy.ts +44 -44
  292. package/src/common/logs/request.ts +65 -65
  293. package/src/common/queue.ts +50 -50
  294. package/src/config.ts +96 -96
  295. package/src/constants.ts +1123 -1121
  296. package/src/controls-options-manager/constants.ts +5 -5
  297. package/src/controls-options-manager/enums.ts +6 -6
  298. package/src/controls-options-manager/index.ts +183 -183
  299. package/src/controls-options-manager/util.ts +20 -20
  300. package/src/index.js +15 -15
  301. package/src/locus-info/controlsUtils.ts +112 -112
  302. package/src/locus-info/embeddedAppsUtils.ts +57 -57
  303. package/src/locus-info/fullState.ts +69 -69
  304. package/src/locus-info/hostUtils.ts +60 -60
  305. package/src/locus-info/index.ts +1303 -1303
  306. package/src/locus-info/infoUtils.ts +101 -101
  307. package/src/locus-info/mediaSharesUtils.ts +173 -173
  308. package/src/locus-info/parser.ts +680 -680
  309. package/src/locus-info/selfUtils.ts +428 -428
  310. package/src/media/index.ts +675 -675
  311. package/src/media/properties.ts +313 -313
  312. package/src/media/util.ts +37 -37
  313. package/src/mediaQualityMetrics/config.ts +382 -382
  314. package/src/meeting/effectsState.ts +209 -209
  315. package/src/meeting/in-meeting-actions.ts +153 -153
  316. package/src/meeting/index.ts +6572 -6537
  317. package/src/meeting/muteState.ts +365 -365
  318. package/src/meeting/request.ts +810 -810
  319. package/src/meeting/state.ts +194 -194
  320. package/src/meeting/util.ts +530 -530
  321. package/src/meeting-info/collection.ts +41 -41
  322. package/src/meeting-info/index.ts +137 -137
  323. package/src/meeting-info/meeting-info-v2.ts +273 -273
  324. package/src/meeting-info/request.ts +46 -46
  325. package/src/meeting-info/util.ts +314 -314
  326. package/src/meeting-info/utilv2.ts +324 -324
  327. package/src/meetings/collection.ts +43 -43
  328. package/src/meetings/index.ts +1128 -1128
  329. package/src/meetings/request.ts +81 -81
  330. package/src/meetings/util.ts +181 -181
  331. package/src/member/index.ts +446 -446
  332. package/src/member/member.types.ts +13 -13
  333. package/src/member/util.ts +286 -286
  334. package/src/members/collection.ts +40 -40
  335. package/src/members/index.ts +900 -900
  336. package/src/members/request.ts +175 -175
  337. package/src/members/util.ts +260 -260
  338. package/src/metrics/config.ts +485 -485
  339. package/src/metrics/constants.ts +63 -61
  340. package/src/metrics/index.ts +543 -543
  341. package/src/networkQualityMonitor/index.ts +211 -211
  342. package/src/peer-connection-manager/index.ts +847 -847
  343. package/src/peer-connection-manager/util.ts +119 -119
  344. package/src/personal-meeting-room/index.ts +157 -157
  345. package/src/personal-meeting-room/request.ts +48 -48
  346. package/src/personal-meeting-room/util.ts +49 -49
  347. package/src/reachability/index.ts +478 -478
  348. package/src/reachability/request.ts +81 -81
  349. package/src/reactions/reactions.ts +104 -104
  350. package/src/reactions/reactions.type.ts +36 -36
  351. package/src/reconnection-manager/index.ts +622 -622
  352. package/src/recording-controller/enums.ts +8 -8
  353. package/src/recording-controller/index.ts +315 -315
  354. package/src/recording-controller/util.ts +58 -58
  355. package/src/roap/collection.ts +62 -62
  356. package/src/roap/handler.ts +294 -294
  357. package/src/roap/index.ts +413 -413
  358. package/src/roap/request.ts +229 -229
  359. package/src/roap/state.ts +156 -156
  360. package/src/roap/turnDiscovery.ts +283 -283
  361. package/src/roap/util.ts +100 -100
  362. package/src/statsAnalyzer/global.ts +120 -128
  363. package/src/statsAnalyzer/index.ts +1329 -1266
  364. package/src/statsAnalyzer/mqaUtil.ts +290 -290
  365. package/src/transcription/index.ts +154 -154
  366. package/test/integration/spec/journey.js +941 -941
  367. package/test/integration/spec/space-meeting.js +457 -457
  368. package/test/integration/spec/transcription.js +55 -55
  369. package/test/unit/spec/common/browser-detection.js +119 -119
  370. package/test/unit/spec/common/queue.js +69 -69
  371. package/test/unit/spec/controls-options-manager/index.js +123 -123
  372. package/test/unit/spec/controls-options-manager/util.js +65 -65
  373. package/test/unit/spec/fixture/locus.js +406 -406
  374. package/test/unit/spec/locus-info/controlsUtils.js +82 -82
  375. package/test/unit/spec/locus-info/embeddedAppsUtils.js +104 -104
  376. package/test/unit/spec/locus-info/index.js +1272 -1272
  377. package/test/unit/spec/locus-info/infoUtils.js +138 -138
  378. package/test/unit/spec/locus-info/lib/BasicSeqCmp.json +975 -975
  379. package/test/unit/spec/locus-info/lib/SeqCmp.json +522 -522
  380. package/test/unit/spec/locus-info/lib/selfConstant.js +286 -286
  381. package/test/unit/spec/locus-info/parser.js +298 -298
  382. package/test/unit/spec/locus-info/selfUtils.js +185 -185
  383. package/test/unit/spec/media/properties.ts +305 -305
  384. package/test/unit/spec/meeting/effectsState.js +281 -281
  385. package/test/unit/spec/meeting/in-meeting-actions.ts +90 -90
  386. package/test/unit/spec/meeting/index.js +5298 -5227
  387. package/test/unit/spec/meeting/muteState.js +430 -430
  388. package/test/unit/spec/meeting/request.js +317 -317
  389. package/test/unit/spec/meeting/utils.js +319 -319
  390. package/test/unit/spec/meeting-info/meetinginfov2.js +376 -376
  391. package/test/unit/spec/meeting-info/request.js +64 -64
  392. package/test/unit/spec/meeting-info/util.js +37 -37
  393. package/test/unit/spec/meeting-info/utilv2.js +330 -330
  394. package/test/unit/spec/meetings/collection.js +52 -52
  395. package/test/unit/spec/meetings/index.js +1375 -1375
  396. package/test/unit/spec/meetings/utils.js +66 -66
  397. package/test/unit/spec/member/index.js +47 -47
  398. package/test/unit/spec/member/util.js +80 -80
  399. package/test/unit/spec/members/index.js +364 -364
  400. package/test/unit/spec/members/request.js +200 -200
  401. package/test/unit/spec/members/utils.js +42 -42
  402. package/test/unit/spec/metrics/index.js +111 -111
  403. package/test/unit/spec/networkQualityMonitor/index.js +99 -99
  404. package/test/unit/spec/peerconnection-manager/index.js +218 -218
  405. package/test/unit/spec/peerconnection-manager/utils.js +49 -49
  406. package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +388 -388
  407. package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +29 -29
  408. package/test/unit/spec/reachability/index.ts +50 -50
  409. package/test/unit/spec/reconnection-manager/index.js +206 -206
  410. package/test/unit/spec/recording-controller/index.js +230 -230
  411. package/test/unit/spec/recording-controller/util.js +101 -101
  412. package/test/unit/spec/roap/index.ts +128 -128
  413. package/test/unit/spec/roap/turnDiscovery.ts +372 -372
  414. package/test/unit/spec/roap/util.js +30 -30
  415. package/test/unit/spec/stats-analyzer/index.js +438 -287
  416. package/test/utils/cmr.js +104 -104
  417. package/test/utils/testUtils.js +287 -287
  418. package/test/utils/webex-config.js +77 -77
  419. package/test/utils/webex-test-users.js +82 -82
  420. package/tsconfig.json +5 -5
@@ -1,941 +1,941 @@
1
- /* globals navigator */
2
- /* eslint prefer-arrow-callback: 0 */
3
-
4
- import {assert} from '@webex/test-helper-chai';
5
- import {skipInNode} from '@webex/test-helper-mocha';
6
- import sinon from 'sinon';
7
-
8
- import BrowserDetection from '@webex/plugin-meetings/dist/common/browser-detection';
9
-
10
- import DEFAULT_RESOLUTIONS from '../../../src/config';
11
- import testUtils from '../../utils/testUtils';
12
-
13
- require('dotenv').config();
14
-
15
- const webexTestUsers = require('../../utils/webex-test-users');
16
-
17
- const {isBrowser} = BrowserDetection();
18
-
19
- let userSet, alice, bob, chris, enumerateSpy, channelUrlA, channelUrlB;
20
-
21
- skipInNode(describe)('plugin-meetings', () => {
22
- describe('journey', () => {
23
- before(() =>
24
- webexTestUsers
25
- .generateTestUsers({
26
- count: 3,
27
- whistler: process.env.WHISTLER || process.env.JENKINS,
28
- })
29
- .then((users) => {
30
- userSet = users;
31
- alice = userSet[0];
32
- bob = userSet[1];
33
- chris = userSet[2];
34
- alice.name = 'alice';
35
- bob.name = 'bob';
36
- chris.name = 'chris';
37
- alice.webex.meetings.name = 'alice';
38
- bob.webex.meetings.name = 'bob';
39
- chris.webex.meetings.name = 'chris';
40
- channelUrlA =
41
- 'https://board-a.wbx2.com/board/api/v1/channels/49cfb550-5517-11eb-a2af-1b9e4bc3da13';
42
- channelUrlB =
43
- 'https://board-a.wbx2.com/board/api/v1/channels/977a7330-54f4-11eb-b1ef-91f5eefc7bf3';
44
- })
45
- .then(() =>
46
- Promise.all([testUtils.syncAndEndMeeting(alice), testUtils.syncAndEndMeeting(bob)])
47
- )
48
- .catch((error) => {
49
- throw error;
50
- })
51
- );
52
-
53
- before(() => {
54
- enumerateSpy = sinon.spy(navigator.mediaDevices, 'enumerateDevices');
55
- });
56
-
57
- beforeEach(() => {
58
- enumerateSpy.resetHistory();
59
- });
60
-
61
- describe('Check configuration values', () => {
62
- it('properly sets the Media Quality Analyzer `metrics` config', () => {
63
- assert.equal(alice.webex.meetings.config.metrics.autoSendMQA, true);
64
- assert.equal(alice.webex.meetings.config.metrics.mqaMetricsInterval, 60000);
65
- assert.equal(alice.webex.meetings.config.metrics.clientType, 'WEBEX_SDK');
66
- assert.equal(alice.webex.meetings.config.metrics.clientName, 'WEBEX_JS_SDK');
67
- });
68
- });
69
-
70
- // Alice calls bob and bob rejects it
71
- xdescribe('End outgoing Call', () => {
72
- after(() => {
73
- alice.meeting = null;
74
- bob.meeting = null;
75
- });
76
-
77
- it('Alice Ends a outgoing meeting', () =>
78
- Promise.all([
79
- testUtils.delayedPromise(alice.webex.meetings.create(bob.emailAddress)),
80
- testUtils.waitForEvents([
81
- {scope: alice.webex.meetings, event: 'meeting:added', user: alice},
82
- ]),
83
- ])
84
- .then(() =>
85
- Promise.all([
86
- testUtils.delayedPromise(alice.meeting.join()),
87
- testUtils.waitForEvents([
88
- {scope: bob.webex.meetings, event: 'meeting:added', user: bob},
89
- ]),
90
- ])
91
- )
92
- .then(() => {
93
- // bob and alice have meeting object
94
- bob.meeting.acknowledge('INCOMING');
95
- assert.equal(bob.meeting.sipUri, alice.emailAddress);
96
- assert.equal(alice.meeting.sipUri, bob.emailAddress);
97
- assert.equal(bob.meeting.state, 'IDLE');
98
- assert.equal(alice.meeting.state, 'JOINED');
99
- })
100
- .then(function aliceLeavesMeetingAndBobGetsMeetingRemoved() {
101
- return Promise.all([
102
- testUtils.delayedPromise(alice.meeting.leave()),
103
- testUtils.waitForEvents([
104
- {scope: bob.webex.meetings, event: 'meeting:removed', user: bob},
105
- ]),
106
- ]);
107
- })
108
- .then(() => testUtils.waitForStateChange(alice.meeting, 'LEFT'))
109
- .then(() =>
110
- Promise.all([
111
- testUtils.waitForCallEnded(alice, bob.emailAddress),
112
- testUtils.waitForCallEnded(bob, alice.emailAddress),
113
- ])
114
- )
115
- .then(() => {
116
- assert.equal(alice.webex.meetings.getMeetingByType('sipUri', bob.emailAddress), null);
117
- assert.equal(bob.webex.meetings.getMeetingByType('sipUri', alice.emailAddress), null);
118
- })
119
- .catch((err) => {
120
- throw err;
121
- }));
122
- });
123
-
124
- // The event was coming but incomplete
125
- // 1) Test user doesnt have locus tag information
126
-
127
- // Alice calls bob and bob rejects it
128
- xdescribe('reject Incoming Call', () => {
129
- it('alice dials bob and bob receives meeting added', () =>
130
- Promise.all([
131
- testUtils.delayedPromise(alice.webex.meetings.create(bob.emailAddress)),
132
- testUtils.waitForEvents([
133
- {scope: alice.webex.meetings, event: 'meeting:added', user: alice},
134
- ]),
135
- ])
136
- .then(() =>
137
- Promise.all([
138
- testUtils.delayedPromise(alice.meeting.join()),
139
- testUtils.waitForEvents([
140
- {scope: bob.webex.meetings, event: 'meeting:added', user: bob},
141
- ]),
142
- ])
143
- )
144
- .then(function alicebobJoined() {
145
- assert.exists(bob.meeting);
146
- assert.exists(alice.meeting);
147
- assert.equal(bob.meeting.sipUri, alice.emailAddress);
148
- assert.equal(alice.meeting.sipUri, bob.emailAddress);
149
- assert.exists(bob.meeting.partner);
150
- assert.exists(alice.meeting.partner);
151
- })
152
- .then(function bobState() {
153
- testUtils.waitForStateChange(bob.meeting, 'IDLE');
154
- })
155
- .then(function aliceState() {
156
- testUtils.waitForStateChange(alice.meeting, 'JOINED');
157
- })
158
- .then(function bobDeclinedCall() {
159
- return bob.meeting
160
- .acknowledge('INCOMING')
161
- .then(() => bob.meeting.decline('BUSY'))
162
- .then(() => testUtils.waitForStateChange(bob.meeting, 'DECLINED'))
163
- .catch((e) => {
164
- console.error('Bob decline call not successful', e);
165
- throw e;
166
- });
167
- })
168
- .then(function aliceLeaveMeeting() {
169
- assert.equal(alice.meeting.state, 'JOINED');
170
-
171
- return alice.meeting
172
- .leave()
173
- .then(() => testUtils.waitForStateChange(alice.meeting, 'LEFT'))
174
- .then(() => testUtils.waitForStateChange(bob.meeting, 'DECLINED'))
175
- .catch((e) => {
176
- console.error('alice was not able to leave the meeting', e);
177
- throw e;
178
- });
179
- })
180
- .then(function WaitForMeetingEnd() {
181
- return Promise.all([
182
- testUtils.waitForCallEnded(alice, bob.emailAddress),
183
- testUtils.waitForCallEnded(bob, alice.emailAddress),
184
- ])
185
- .then(() => {
186
- assert.equal(
187
- alice.webex.meetings.getMeetingByType('sipUri', bob.emailAddress),
188
- null
189
- );
190
- assert.equal(
191
- bob.webex.meetings.getMeetingByType('sipUri', alice.emailAddress),
192
- null
193
- );
194
- })
195
- .catch((e) => {
196
- console.error('Alice bob meeting is deleted', e);
197
- throw e;
198
- });
199
- }));
200
- });
201
-
202
- // Enabled when config.enableUnifiedMeetings = true
203
- xdescribe('Conversation URL', () => {
204
- describe('Successful 1:1 meeting', () => {
205
- it('Fetch meeting information with a conversation URL for a 1:1 space', async () => {
206
- assert.equal(Object.keys(bob.webex.meetings.getAllMeetings()), 0);
207
- assert.equal(Object.keys(chris.webex.meetings.getAllMeetings()), 0);
208
-
209
- const conversation = await chris.webex.internal.conversation.create({
210
- participants: [bob],
211
- });
212
-
213
- await chris.webex.internal.conversation.post(conversation, {
214
- displayName: 'hello world how are you ',
215
- });
216
-
217
- await Promise.all([
218
- testUtils.delayedPromise(
219
- chris.webex.meetings.create(conversation.url, 'CONVERSATION_URL')
220
- ),
221
- testUtils.waitForEvents([
222
- {scope: chris.webex.meetings, event: 'meeting:added', user: chris},
223
- ]),
224
- ]).then(function chrisJoinsMeeting() {
225
- return Promise.all([
226
- testUtils.delayedPromise(chris.meeting.join()),
227
- testUtils
228
- .waitForEvents([
229
- {scope: bob.webex.meetings, event: 'meeting:added', user: bob},
230
- {scope: chris.meeting, event: 'meeting:stateChange', user: chris},
231
- ])
232
- .then((response) => {
233
- assert.equal(response[0].result.payload.currentState, 'ACTIVE');
234
- }),
235
- ]);
236
- });
237
- });
238
-
239
- it('Fetch meeting information with invalid conversation URL and throws error', () => {
240
- chris.webex.meetings.meetingInfo
241
- .fetchMeetingInfo('http://some-invalid.com', 'CONVERSATION_URL')
242
- .then((response) => {
243
- assert(response.result === '404');
244
- });
245
- });
246
- });
247
- });
248
-
249
- describe('Successful 1:1 meeting (including Guest)', function () {
250
- before(() => {
251
- // Workaround since getDisplayMedia requires a user gesture to be activated, and this is a integration tests
252
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1580944
253
- if (isBrowser('firefox') || isBrowser('safari')) {
254
- sinon.replace(
255
- navigator.mediaDevices,
256
- 'getDisplayMedia',
257
- navigator.mediaDevices.getUserMedia
258
- );
259
- }
260
-
261
- this.timeout(80000);
262
- });
263
-
264
- it('No previous Call', () => {
265
- assert.equal(Object.keys(bob.webex.meetings.getAllMeetings()), 0);
266
- assert.equal(Object.keys(alice.webex.meetings.getAllMeetings()), 0);
267
-
268
- return alice.webex.internal.conversation
269
- .create({participants: [bob]})
270
- .then((conversation) =>
271
- alice.webex.internal.conversation.post(conversation, {
272
- displayName: 'hello world how are you ',
273
- })
274
- );
275
- });
276
-
277
- it('alice dials bob and adds media', () =>
278
- Promise.all([
279
- testUtils.delayedPromise(alice.webex.meetings.create(bob.emailAddress)),
280
- testUtils.waitForEvents([
281
- {scope: alice.webex.meetings, event: 'meeting:added', user: alice},
282
- ]),
283
- ])
284
- .then(function aliceJoinsMeeting() {
285
- return Promise.all([
286
- testUtils.delayedPromise(alice.meeting.join()),
287
- testUtils
288
- .waitForEvents([
289
- {scope: bob.webex.meetings, event: 'meeting:added', user: bob},
290
- {scope: alice.meeting, event: 'meeting:stateChange', user: alice},
291
- ])
292
- .then((response) => {
293
- assert.equal(response[0].result.payload.currentState, 'ACTIVE');
294
- }),
295
- ]);
296
- })
297
- .then(() => {
298
- assert.equal(bob.meeting.partner.state, 'JOINED');
299
- // Wait for openH264 to finsish downloading and peerConnection to be stable
300
- testUtils.waitUntil(4000);
301
- })
302
- .then(() =>
303
- Promise.all([
304
- testUtils.addMedia(alice),
305
- testUtils.waitForEvents([
306
- {scope: alice.meeting, event: 'meeting:media:local:start', user: alice},
307
- ]),
308
- ])
309
- )
310
- .then(() => assert(enumerateSpy.called)));
311
-
312
- it('bob joins the meeting', () => {
313
- const checkBobIsInMeeting = (event) =>
314
- !!event.delta.updated.find(
315
- (member) => bob.meeting.members.selfId === member.id && member.status === 'IN_MEETING'
316
- );
317
-
318
- return Promise.all([
319
- bob.meeting.acknowledge('INCOMING').then(() => bob.meeting.join()),
320
- testUtils.waitForEvents([
321
- {
322
- scope: alice.meeting.members,
323
- event: 'members:update',
324
- user: alice,
325
- match: checkBobIsInMeeting,
326
- },
327
- ]),
328
- ]);
329
- });
330
-
331
- it('bob adds media to the meeting', () =>
332
- Promise.all([
333
- testUtils.addMedia(bob),
334
- testUtils
335
- .waitForEvents([
336
- {scope: bob.meeting, event: 'meeting:media:local:start', user: bob},
337
- {scope: alice.meeting, event: 'meeting:media:remote:start', user: alice},
338
- ])
339
- .catch((e) => {
340
- console.error('Error on remote and local start event', e);
341
- throw e;
342
- }),
343
- ])
344
- .then(() => {
345
- assert.equal(bob.meeting.sipUri, alice.id);
346
- assert.equal(alice.meeting.sipUri, bob.id);
347
- assert.exists(alice.meeting.members.locusUrl);
348
- assert.equal(alice.meeting.type, 'CALL');
349
- assert.equal(bob.meeting.type, 'CALL');
350
- assert(enumerateSpy.called);
351
- })
352
- .then(function bobState() {
353
- testUtils.waitForStateChange(bob.meeting, 'JOINED');
354
- })
355
- .then(function aliceState() {
356
- testUtils.waitForStateChange(alice.meeting, 'JOINED');
357
- })
358
- .catch((e) => {
359
- console.error('Error bob joins the meeting ', e);
360
- throw e;
361
- }));
362
-
363
- it('check for meeting properties', () => {
364
- assert.exists(alice.meeting.userId, 'userId not present');
365
- assert.exists(alice.meeting.deviceUrl, 'deviceUrl not present');
366
- assert.exists(alice.meeting.partner, 'partner not present');
367
- assert.exists(alice.meeting.type, 'type not present');
368
- assert.exists(alice.meeting.state, 'state not present');
369
- assert.exists(alice.meeting.guest, 'guest not present');
370
- assert.exists(alice.meeting.mediaProperties, 'mediaProperties not Present');
371
- assert.exists(alice.meeting.mediaProperties.mediaDirection, 'mediaDirection not present');
372
- assert.exists(alice.meeting.members.selfId, 'selfId not present');
373
- });
374
-
375
- it('alice Audio Mute ', () => {
376
- const checkEvent = (event) =>
377
- !!event.delta.updated.find(
378
- (member) => alice.meeting.members.selfId === member.id && member.isAudioMuted === true
379
- );
380
-
381
- return Promise.all([
382
- testUtils.delayedPromise(alice.meeting.muteAudio()),
383
- testUtils.waitForEvents([
384
- {scope: bob.meeting.members, event: 'members:update', match: checkEvent},
385
- ]),
386
- ]).then(() => {
387
- assert.equal(alice.meeting.audio.muted, true);
388
- assert.equal(alice.meeting.isAudioMuted(), true);
389
- });
390
- });
391
-
392
- it('alice Audio unMute ', () => {
393
- const checkEvent = (event) =>
394
- !!event.delta.updated.find(
395
- (member) => alice.meeting.members.selfId === member.id && member.isAudioMuted === false
396
- );
397
-
398
- return Promise.all([
399
- testUtils.delayedPromise(alice.meeting.unmuteAudio()),
400
- testUtils.waitForEvents([
401
- {scope: bob.meeting.members, event: 'members:update', match: checkEvent},
402
- ]),
403
- ]).then(() => {
404
- assert.equal(alice.meeting.audio.muted, false);
405
- assert.equal(alice.meeting.isAudioMuted(), false);
406
- });
407
- });
408
-
409
- it('alice Video Mute', () => {
410
- const checkEvent = (event) =>
411
- !!event.delta.updated.find(
412
- (member) => alice.meeting.members.selfId === member.id && member.isVideoMuted === true
413
- );
414
-
415
- return Promise.all([
416
- testUtils.delayedPromise(alice.meeting.muteVideo()),
417
- testUtils.waitForEvents([
418
- {scope: alice.meeting.members, event: 'members:update', match: checkEvent},
419
- ]),
420
- ]).then(() => {
421
- assert.equal(alice.meeting.video.muted, true);
422
- assert.equal(alice.meeting.isVideoMuted(), true);
423
- });
424
- });
425
-
426
- it('alice video unMute', () => {
427
- const checkEvent = (event) =>
428
- !!event.delta.updated.find(
429
- (member) => alice.meeting.members.selfId === member.id && member.isVideoMuted === false
430
- );
431
-
432
- return Promise.all([
433
- testUtils.delayedPromise(alice.meeting.unmuteVideo()),
434
- testUtils.waitForEvents([
435
- {scope: bob.meeting.members, event: 'members:update', match: checkEvent},
436
- ]),
437
- ]).then(() => {
438
- assert.equal(alice.meeting.video.muted, false);
439
- assert.equal(alice.meeting.isVideoMuted(), false);
440
- });
441
- });
442
-
443
- it('alice update Audio', () => {
444
- const oldVideoTrackId = alice.meeting.mediaProperties.videoTrack.id;
445
-
446
- return alice.meeting.getMediaStreams({sendAudio: true}).then((response) =>
447
- Promise.all([
448
- testUtils.delayedPromise(
449
- alice.meeting
450
- .updateAudio({
451
- sendAudio: true,
452
- receiveAudio: true,
453
- stream: response[0],
454
- })
455
- .then(() => {
456
- console.log(
457
- 'AUDIO ',
458
- alice.meeting.mediaProperties.peerConnection.audioTransceiver.sender.track
459
- );
460
- assert.equal(
461
- alice.meeting.mediaProperties.audioTrack.id,
462
- response[0].getAudioTracks()[0].id
463
- );
464
- assert.equal(alice.meeting.mediaProperties.videoTrack.id, oldVideoTrackId);
465
- })
466
- ),
467
- testUtils
468
- .waitForEvents([{scope: alice.meeting, event: 'media:ready'}])
469
- .then((response) => {
470
- console.log('MEDIA:READY event ', response[0].result);
471
- assert.equal(response[0].result.type === 'local', true);
472
- }),
473
- ])
474
- );
475
- });
476
-
477
- it('alice update video', () => {
478
- const oldAudioTrackId = alice.meeting.mediaProperties.audioTrack.id;
479
-
480
- return alice.meeting.getMediaStreams({sendVideo: true}).then((response) =>
481
- Promise.all([
482
- testUtils.delayedPromise(
483
- alice.meeting
484
- .updateVideo({
485
- sendVideo: true,
486
- receiveVideo: true,
487
- stream: response[0],
488
- })
489
- .then(() => {
490
- assert.equal(
491
- alice.meeting.mediaProperties.videoTrack.id,
492
- response[0].getVideoTracks()[0].id
493
- );
494
- assert.equal(alice.meeting.mediaProperties.audioTrack.id, oldAudioTrackId);
495
- })
496
- ),
497
- testUtils
498
- .waitForEvents([{scope: alice.meeting, event: 'media:ready'}])
499
- .then((response) => {
500
- console.log('MEDIA:READY event ', response[0].result);
501
- assert.equal(response[0].result.type === 'local', true);
502
- }),
503
- ])
504
- );
505
- });
506
-
507
- it('alice mutes bob', () =>
508
- Promise.all([
509
- testUtils.delayedPromise(alice.meeting.mute(bob.meeting.members.selfId, true)),
510
- testUtils
511
- .waitForEvents([{scope: bob.meeting, event: 'meeting:self:mutedByOthers'}])
512
- .then((response) => {
513
- console.log('meeting:self:mutedByOthers event ', response[0].result);
514
- assert.equal(response[0].result.payload.unmuteAllowed, true);
515
- }),
516
- ]));
517
-
518
- it('alice unmutes bob', () =>
519
- Promise.all([
520
- testUtils.delayedPromise(alice.meeting.mute(bob.meeting.members.selfId, false)),
521
- testUtils
522
- .waitForEvents([{scope: bob.meeting, event: 'meeting:self:unmutedByOthers'}])
523
- .then((response) => {
524
- console.log('meeting:self:unmutedByOthers event ', response[0].result);
525
- }),
526
- ]));
527
-
528
- it('bob audio mute, so alice cannot unmute bob', (done) => {
529
- const checkEvent = (event) =>
530
- !!event.delta.updated.find(
531
- (member) => bob.meeting.members.selfId === member.id && member.isAudioMuted === true
532
- );
533
-
534
- // first bob mutes himself
535
- Promise.all([
536
- testUtils.delayedPromise(bob.meeting.muteAudio()),
537
- testUtils.waitForEvents([
538
- {scope: bob.meeting.members, event: 'members:update', match: checkEvent},
539
- ]),
540
- ])
541
- .then(() => {
542
- assert.equal(bob.meeting.audio.muted, true);
543
- assert.equal(bob.meeting.isAudioMuted(), true);
544
- })
545
- // now alice tries to unmmut bob
546
- .then(() =>
547
- testUtils.delayedPromise(alice.meeting.mute(bob.meeting.members.selfId, false))
548
- )
549
- // expect the waitForEvents to timeout
550
- .then(() =>
551
- testUtils.waitForEvents(
552
- [{scope: bob.meeting, event: 'meeting:self:unmutedByOthers'}],
553
- 2000
554
- )
555
- )
556
- .then(() => {
557
- assert.fail('bob received unexpected meeting:self:unmutedByOthers event');
558
- })
559
- .catch(() => {
560
- assert.equal(bob.meeting.audio.muted, true);
561
- assert.equal(bob.meeting.isAudioMuted(), true);
562
- done();
563
- });
564
- });
565
-
566
- it('bob audio unmute ', () => {
567
- const checkEvent = (event) =>
568
- !!event.delta.updated.find(
569
- (member) => bob.meeting.members.selfId === member.id && member.isAudioMuted === false
570
- );
571
-
572
- return Promise.all([
573
- testUtils.delayedPromise(bob.meeting.unmuteAudio()),
574
- testUtils.waitForEvents([
575
- {scope: alice.meeting.members, event: 'members:update', match: checkEvent},
576
- ]),
577
- ]).then(() => {
578
- assert.equal(bob.meeting.audio.muted, false);
579
- assert.equal(bob.meeting.isAudioMuted(), false);
580
- });
581
- });
582
-
583
- it('alice shares the screen with highFrameRate', () =>
584
- Promise.all([
585
- testUtils.delayedPromise(
586
- alice.meeting.shareScreen({sharePreferences: {highFrameRate: true}})
587
- ),
588
- testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingLocal'}]),
589
- testUtils
590
- .waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingRemote'}])
591
- .then((response) => {
592
- assert.equal(response[0].result.memberId, alice.meeting.selfId);
593
- }),
594
- testUtils
595
- .waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
596
- .then((response) => {
597
- console.log(
598
- 'SCREEN SHARE RESPONSE ',
599
- JSON.stringify(response, testUtils.getCircularReplacer())
600
- );
601
- }),
602
- testUtils
603
- .waitForEvents([{scope: alice.meeting, event: 'media:ready'}])
604
- .then((response) => {
605
- console.log('MEDIA:READY event ', response[0].result);
606
- assert.equal(response[0].result.type === 'localShare', true);
607
- }),
608
- ]).then(() => {
609
- // TODO: Re-eanable Safari when screensharing issues have been resolved
610
- if (!isBrowser('safari')) {
611
- assert.equal(alice.meeting.mediaProperties.shareTrack.getConstraints().height, 720);
612
- }
613
- assert.equal(alice.meeting.isSharing, true);
614
- assert.equal(alice.meeting.shareStatus, 'local_share_active');
615
- assert.equal(bob.meeting.shareStatus, 'remote_share_active');
616
- console.log(
617
- 'SCREEN SHARE PARTICIPANTS ',
618
- JSON.stringify(alice.meeting.locusInfo.participants)
619
- );
620
-
621
- return testUtils.waitUntil(10000);
622
- }));
623
-
624
- it('bob steals the screen share from alice', () =>
625
- Promise.all([
626
- testUtils.delayedPromise(bob.meeting.shareScreen()),
627
- testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:stoppedSharingLocal'}]),
628
- testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingLocal'}]),
629
- testUtils
630
- .waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingRemote'}])
631
- .then((response) => {
632
- assert.equal(response[0].result.memberId, bob.meeting.selfId);
633
- }),
634
- testUtils
635
- .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
636
- .then((response) => {
637
- console.log(
638
- 'SCREEN SHARE RESPONSE ',
639
- JSON.stringify(response, testUtils.getCircularReplacer())
640
- );
641
- }),
642
- testUtils.waitForEvents([{scope: bob.meeting, event: 'media:ready'}]).then((response) => {
643
- console.log('MEDIA:READY event ', response[0].result);
644
- assert.equal(response[0].result.type === 'localShare', true);
645
- }),
646
- ]).then(() => {
647
- const heightResolution = DEFAULT_RESOLUTIONS.meetings.screenResolution.idealHeight;
648
-
649
- // TODO: Re-eanable Safari when screensharing issues have been resolved
650
- if (!isBrowser('safari')) {
651
- assert.equal(
652
- bob.meeting.mediaProperties.shareTrack.getConstraints().height,
653
- heightResolution
654
- );
655
- }
656
- assert.equal(bob.meeting.isSharing, true);
657
- assert.equal(bob.meeting.shareStatus, 'local_share_active');
658
- assert.equal(alice.meeting.shareStatus, 'remote_share_active');
659
-
660
- return testUtils.waitUntil(10000);
661
- }));
662
-
663
- it('bob stops sharing ', () =>
664
- Promise.all([
665
- // Wait for peerConnection to stabalize
666
- testUtils.waitUntil(20000),
667
- testUtils.delayedPromise(
668
- bob.meeting.updateShare({
669
- sendShare: false,
670
- receiveShare: true,
671
- })
672
- ),
673
- testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:stoppedSharingLocal'}]),
674
- testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:stoppedSharingRemote'}]),
675
- ]).then(() => {
676
- assert.equal(bob.meeting.isSharing, false);
677
- assert.equal(bob.meeting.shareStatus, 'no_share');
678
- assert.equal(alice.meeting.shareStatus, 'no_share');
679
- }));
680
-
681
- it('alice shares whiteboard A', () =>
682
- Promise.all([
683
- testUtils.delayedPromise(alice.meeting.startWhiteboardShare(channelUrlA)),
684
- testUtils.waitForEvents([
685
- {scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'},
686
- ]),
687
- testUtils
688
- .waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'}])
689
- .then((response) => {
690
- const {memberId, resourceUrl} = response[0].result;
691
-
692
- assert.equal(memberId, alice.meeting.selfId);
693
- assert.equal(resourceUrl, channelUrlA);
694
- }),
695
- testUtils
696
- .waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
697
- .then((response) => {
698
- console.log(
699
- 'WHITEBOARD SHARE RESPONSE ',
700
- JSON.stringify(response, testUtils.getCircularReplacer())
701
- );
702
- }),
703
- ]).then(() => {
704
- assert.equal(alice.meeting.isSharing, false);
705
- assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
706
- assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
707
- }));
708
-
709
- it('bob steals share from alice with whiteboard B', () =>
710
- Promise.all([
711
- testUtils.delayedPromise(bob.meeting.startWhiteboardShare(channelUrlB)),
712
- testUtils.waitForEvents([
713
- {scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'},
714
- ]),
715
- testUtils
716
- .waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'}])
717
- .then((response) => {
718
- const {memberId, resourceUrl} = response[0].result;
719
-
720
- assert.equal(memberId, bob.meeting.selfId);
721
- assert.equal(resourceUrl, channelUrlB);
722
- }),
723
- testUtils
724
- .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
725
- .then((response) => {
726
- console.log(
727
- 'WHITEBOARD SHARE RESPONSE ',
728
- JSON.stringify(response, testUtils.getCircularReplacer())
729
- );
730
- }),
731
- ]).then(() => {
732
- assert.equal(bob.meeting.isSharing, false);
733
- assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
734
- assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
735
- }));
736
-
737
- it('bob stops sharing ', () =>
738
- Promise.all([
739
- // Wait for peerConnection to stabalize
740
- testUtils.waitUntil(20000),
741
- testUtils.delayedPromise(bob.meeting.stopWhiteboardShare(channelUrlB)),
742
- testUtils.waitForEvents([
743
- {scope: bob.meeting, event: 'meeting:stoppedSharingWhiteboard'},
744
- ]),
745
- testUtils.waitForEvents([
746
- {scope: alice.meeting, event: 'meeting:stoppedSharingWhiteboard'},
747
- ]),
748
- ]).then(() => {
749
- assert.equal(bob.meeting.isSharing, false);
750
- assert.equal(bob.meeting.shareStatus, 'no_share');
751
- assert.equal(alice.meeting.shareStatus, 'no_share');
752
- }));
753
-
754
- it('alice shares whiteboard B', () =>
755
- Promise.all([
756
- testUtils.delayedPromise(alice.meeting.startWhiteboardShare(channelUrlB)),
757
- testUtils.waitForEvents([
758
- {scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'},
759
- ]),
760
- testUtils
761
- .waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'}])
762
- .then((response) => {
763
- const {memberId, resourceUrl} = response[0].result;
764
-
765
- assert.equal(memberId, alice.meeting.selfId);
766
- assert.equal(resourceUrl, channelUrlB);
767
- }),
768
- testUtils
769
- .waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
770
- .then((response) => {
771
- console.log(
772
- 'WHITEBOARD SHARE RESPONSE ',
773
- JSON.stringify(response, testUtils.getCircularReplacer())
774
- );
775
- }),
776
- ]).then(() => {
777
- assert.equal(alice.meeting.isSharing, false);
778
- assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
779
- assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
780
- }));
781
-
782
- it('bob steals the share from alice with desktop share', () =>
783
- Promise.all([
784
- testUtils.delayedPromise(bob.meeting.shareScreen()),
785
- testUtils.waitForEvents([
786
- {scope: alice.meeting, event: 'meeting:stoppedSharingWhiteboard'},
787
- ]),
788
- testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingLocal'}]),
789
- testUtils
790
- .waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingRemote'}])
791
- .then((response) => {
792
- assert.equal(response[0].result.memberId, bob.meeting.selfId);
793
- }),
794
- testUtils
795
- .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
796
- .then((response) => {
797
- console.log(
798
- 'SCREEN SHARE RESPONSE ',
799
- JSON.stringify(response, testUtils.getCircularReplacer())
800
- );
801
- }),
802
- testUtils.waitForEvents([{scope: bob.meeting, event: 'media:ready'}]).then((response) => {
803
- console.log('MEDIA:READY event ', response[0].result);
804
- assert.equal(response[0].result.type === 'localShare', true);
805
- }),
806
- ]).then(() => {
807
- const heightResolution = DEFAULT_RESOLUTIONS.meetings.screenResolution.idealHeight;
808
-
809
- // TODO: Re-eanable Safari when screensharing issues have been resolved
810
- if (!isBrowser('safari')) {
811
- assert.equal(
812
- bob.meeting.mediaProperties.shareTrack.getConstraints().height,
813
- heightResolution
814
- );
815
- }
816
- assert.equal(bob.meeting.isSharing, true);
817
- assert.equal(bob.meeting.shareStatus, 'local_share_active');
818
- assert.equal(alice.meeting.shareStatus, 'remote_share_active');
819
-
820
- return testUtils.waitUntil(10000);
821
- }));
822
-
823
- it('bob shares whiteboard B', () =>
824
- Promise.all([
825
- testUtils.delayedPromise(bob.meeting.startWhiteboardShare(channelUrlB)),
826
- testUtils.waitForEvents([
827
- {scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'},
828
- ]),
829
- testUtils
830
- .waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'}])
831
- .then((response) => {
832
- const {memberId, resourceUrl} = response[0].result;
833
-
834
- assert.equal(memberId, bob.meeting.selfId);
835
- assert.equal(resourceUrl, channelUrlB);
836
- }),
837
- testUtils
838
- .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
839
- .then((response) => {
840
- console.log(
841
- 'WHITEBOARD SHARE RESPONSE ',
842
- JSON.stringify(response, testUtils.getCircularReplacer())
843
- );
844
- }),
845
- ]).then(() => {
846
- assert.equal(bob.meeting.isSharing, false);
847
- assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
848
- assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
849
- }));
850
-
851
- it('alice adds chris as guest to 1:1 meeting', () =>
852
- Promise.all([
853
- testUtils.delayedPromise(alice.meeting.invite({emailAddress: chris.emailAddress})),
854
- testUtils.waitForEvents([
855
- {scope: chris.webex.meetings, event: 'meeting:added', user: chris},
856
- ]),
857
- testUtils
858
- .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
859
- .then((response) => {
860
- const chrisParticipant = response[0].result.delta.added.find(
861
- (member) => member.participant.identity === chris.id
862
- );
863
-
864
- assert.equal(chrisParticipant.status, 'NOT_IN_MEETING');
865
- }),
866
- ])
867
- .catch((e) => {
868
- console.error('Error adding chris as guest ', e);
869
- throw e;
870
- })
871
- .then(function memberUpdated() {
872
- assert.exists(chris.meeting);
873
-
874
- return Promise.all([
875
- testUtils.delayedPromise(chris.meeting.join()),
876
- testUtils.waitForEvents([
877
- {
878
- scope: alice.meeting.members,
879
- event: 'members:update',
880
- match: testUtils.checkParticipantUpdatedStatus(chris, 'IN_MEETING'),
881
- },
882
- ]),
883
- ])
884
- .then(() => {
885
- assert.equal(
886
- alice.meeting.members.membersCollection.get(chris.meeting.members.selfId)
887
- .participant.state,
888
- 'JOINED'
889
- );
890
- })
891
- .then(() => testUtils.waitForStateChange(chris.meeting, 'JOINED'))
892
- .then(() => testUtils.addMedia(chris))
893
- .then(() => assert(enumerateSpy.called));
894
- })
895
- .then(() =>
896
- Promise.all([
897
- testUtils.delayedPromise(chris.meeting.leave()),
898
- testUtils.waitForEvents([
899
- {
900
- scope: alice.meeting.members,
901
- event: 'members:update',
902
- match: testUtils.checkParticipantUpdatedStatus(chris, 'NOT_IN_MEETING'),
903
- },
904
- ]),
905
- ])
906
- )
907
- .catch((e) => {
908
- console.error('Error chris joining the meeting ', e);
909
- throw e;
910
- }));
911
-
912
- it('leave on the meeting object', () => {
913
- const checkInactive = (result) => result.reason === 'CALL_INACTIVE';
914
-
915
- Promise.all([
916
- testUtils.delayedPromise(bob.meeting.leave()),
917
- testUtils.waitForEvents([
918
- {scope: alice.meeting.members, event: 'members:update', user: alice},
919
- {
920
- scope: bob.webex.meetings,
921
- event: 'meeting:removed',
922
- user: bob,
923
- match: checkInactive,
924
- },
925
- {scope: alice.webex.meetings, event: 'meeting:removed', user: alice},
926
- ]),
927
- ])
928
- .then(() => {
929
- assert.equal(bob.meeting, null);
930
- assert.equal(alice.meeting, null);
931
- })
932
- .then(() => testUtils.waitForCallEnded(bob, alice.emailAddress))
933
- .then(() => testUtils.waitForCallEnded(alice, bob.emailAddress))
934
- .then(() => {
935
- assert.equal(alice.webex.meetings.getMeetingByType('sipUri', bob.emailAddress), null);
936
- assert.equal(bob.webex.meetings.getMeetingByType('sipUri', alice.emailAddress), null);
937
- });
938
- });
939
- });
940
- });
941
- });
1
+ /* globals navigator */
2
+ /* eslint prefer-arrow-callback: 0 */
3
+
4
+ import {assert} from '@webex/test-helper-chai';
5
+ import {skipInNode} from '@webex/test-helper-mocha';
6
+ import sinon from 'sinon';
7
+
8
+ import BrowserDetection from '@webex/plugin-meetings/dist/common/browser-detection';
9
+
10
+ import DEFAULT_RESOLUTIONS from '../../../src/config';
11
+ import testUtils from '../../utils/testUtils';
12
+
13
+ require('dotenv').config();
14
+
15
+ const webexTestUsers = require('../../utils/webex-test-users');
16
+
17
+ const {isBrowser} = BrowserDetection();
18
+
19
+ let userSet, alice, bob, chris, enumerateSpy, channelUrlA, channelUrlB;
20
+
21
+ skipInNode(describe)('plugin-meetings', () => {
22
+ describe('journey', () => {
23
+ before(() =>
24
+ webexTestUsers
25
+ .generateTestUsers({
26
+ count: 3,
27
+ whistler: process.env.WHISTLER || process.env.JENKINS,
28
+ })
29
+ .then((users) => {
30
+ userSet = users;
31
+ alice = userSet[0];
32
+ bob = userSet[1];
33
+ chris = userSet[2];
34
+ alice.name = 'alice';
35
+ bob.name = 'bob';
36
+ chris.name = 'chris';
37
+ alice.webex.meetings.name = 'alice';
38
+ bob.webex.meetings.name = 'bob';
39
+ chris.webex.meetings.name = 'chris';
40
+ channelUrlA =
41
+ 'https://board-a.wbx2.com/board/api/v1/channels/49cfb550-5517-11eb-a2af-1b9e4bc3da13';
42
+ channelUrlB =
43
+ 'https://board-a.wbx2.com/board/api/v1/channels/977a7330-54f4-11eb-b1ef-91f5eefc7bf3';
44
+ })
45
+ .then(() =>
46
+ Promise.all([testUtils.syncAndEndMeeting(alice), testUtils.syncAndEndMeeting(bob)])
47
+ )
48
+ .catch((error) => {
49
+ throw error;
50
+ })
51
+ );
52
+
53
+ before(() => {
54
+ enumerateSpy = sinon.spy(navigator.mediaDevices, 'enumerateDevices');
55
+ });
56
+
57
+ beforeEach(() => {
58
+ enumerateSpy.resetHistory();
59
+ });
60
+
61
+ describe('Check configuration values', () => {
62
+ it('properly sets the Media Quality Analyzer `metrics` config', () => {
63
+ assert.equal(alice.webex.meetings.config.metrics.autoSendMQA, true);
64
+ assert.equal(alice.webex.meetings.config.metrics.mqaMetricsInterval, 60000);
65
+ assert.equal(alice.webex.meetings.config.metrics.clientType, 'WEBEX_SDK');
66
+ assert.equal(alice.webex.meetings.config.metrics.clientName, 'WEBEX_JS_SDK');
67
+ });
68
+ });
69
+
70
+ // Alice calls bob and bob rejects it
71
+ xdescribe('End outgoing Call', () => {
72
+ after(() => {
73
+ alice.meeting = null;
74
+ bob.meeting = null;
75
+ });
76
+
77
+ it('Alice Ends a outgoing meeting', () =>
78
+ Promise.all([
79
+ testUtils.delayedPromise(alice.webex.meetings.create(bob.emailAddress)),
80
+ testUtils.waitForEvents([
81
+ {scope: alice.webex.meetings, event: 'meeting:added', user: alice},
82
+ ]),
83
+ ])
84
+ .then(() =>
85
+ Promise.all([
86
+ testUtils.delayedPromise(alice.meeting.join()),
87
+ testUtils.waitForEvents([
88
+ {scope: bob.webex.meetings, event: 'meeting:added', user: bob},
89
+ ]),
90
+ ])
91
+ )
92
+ .then(() => {
93
+ // bob and alice have meeting object
94
+ bob.meeting.acknowledge('INCOMING');
95
+ assert.equal(bob.meeting.sipUri, alice.emailAddress);
96
+ assert.equal(alice.meeting.sipUri, bob.emailAddress);
97
+ assert.equal(bob.meeting.state, 'IDLE');
98
+ assert.equal(alice.meeting.state, 'JOINED');
99
+ })
100
+ .then(function aliceLeavesMeetingAndBobGetsMeetingRemoved() {
101
+ return Promise.all([
102
+ testUtils.delayedPromise(alice.meeting.leave()),
103
+ testUtils.waitForEvents([
104
+ {scope: bob.webex.meetings, event: 'meeting:removed', user: bob},
105
+ ]),
106
+ ]);
107
+ })
108
+ .then(() => testUtils.waitForStateChange(alice.meeting, 'LEFT'))
109
+ .then(() =>
110
+ Promise.all([
111
+ testUtils.waitForCallEnded(alice, bob.emailAddress),
112
+ testUtils.waitForCallEnded(bob, alice.emailAddress),
113
+ ])
114
+ )
115
+ .then(() => {
116
+ assert.equal(alice.webex.meetings.getMeetingByType('sipUri', bob.emailAddress), null);
117
+ assert.equal(bob.webex.meetings.getMeetingByType('sipUri', alice.emailAddress), null);
118
+ })
119
+ .catch((err) => {
120
+ throw err;
121
+ }));
122
+ });
123
+
124
+ // The event was coming but incomplete
125
+ // 1) Test user doesnt have locus tag information
126
+
127
+ // Alice calls bob and bob rejects it
128
+ xdescribe('reject Incoming Call', () => {
129
+ it('alice dials bob and bob receives meeting added', () =>
130
+ Promise.all([
131
+ testUtils.delayedPromise(alice.webex.meetings.create(bob.emailAddress)),
132
+ testUtils.waitForEvents([
133
+ {scope: alice.webex.meetings, event: 'meeting:added', user: alice},
134
+ ]),
135
+ ])
136
+ .then(() =>
137
+ Promise.all([
138
+ testUtils.delayedPromise(alice.meeting.join()),
139
+ testUtils.waitForEvents([
140
+ {scope: bob.webex.meetings, event: 'meeting:added', user: bob},
141
+ ]),
142
+ ])
143
+ )
144
+ .then(function alicebobJoined() {
145
+ assert.exists(bob.meeting);
146
+ assert.exists(alice.meeting);
147
+ assert.equal(bob.meeting.sipUri, alice.emailAddress);
148
+ assert.equal(alice.meeting.sipUri, bob.emailAddress);
149
+ assert.exists(bob.meeting.partner);
150
+ assert.exists(alice.meeting.partner);
151
+ })
152
+ .then(function bobState() {
153
+ testUtils.waitForStateChange(bob.meeting, 'IDLE');
154
+ })
155
+ .then(function aliceState() {
156
+ testUtils.waitForStateChange(alice.meeting, 'JOINED');
157
+ })
158
+ .then(function bobDeclinedCall() {
159
+ return bob.meeting
160
+ .acknowledge('INCOMING')
161
+ .then(() => bob.meeting.decline('BUSY'))
162
+ .then(() => testUtils.waitForStateChange(bob.meeting, 'DECLINED'))
163
+ .catch((e) => {
164
+ console.error('Bob decline call not successful', e);
165
+ throw e;
166
+ });
167
+ })
168
+ .then(function aliceLeaveMeeting() {
169
+ assert.equal(alice.meeting.state, 'JOINED');
170
+
171
+ return alice.meeting
172
+ .leave()
173
+ .then(() => testUtils.waitForStateChange(alice.meeting, 'LEFT'))
174
+ .then(() => testUtils.waitForStateChange(bob.meeting, 'DECLINED'))
175
+ .catch((e) => {
176
+ console.error('alice was not able to leave the meeting', e);
177
+ throw e;
178
+ });
179
+ })
180
+ .then(function WaitForMeetingEnd() {
181
+ return Promise.all([
182
+ testUtils.waitForCallEnded(alice, bob.emailAddress),
183
+ testUtils.waitForCallEnded(bob, alice.emailAddress),
184
+ ])
185
+ .then(() => {
186
+ assert.equal(
187
+ alice.webex.meetings.getMeetingByType('sipUri', bob.emailAddress),
188
+ null
189
+ );
190
+ assert.equal(
191
+ bob.webex.meetings.getMeetingByType('sipUri', alice.emailAddress),
192
+ null
193
+ );
194
+ })
195
+ .catch((e) => {
196
+ console.error('Alice bob meeting is deleted', e);
197
+ throw e;
198
+ });
199
+ }));
200
+ });
201
+
202
+ // Enabled when config.enableUnifiedMeetings = true
203
+ xdescribe('Conversation URL', () => {
204
+ describe('Successful 1:1 meeting', () => {
205
+ it('Fetch meeting information with a conversation URL for a 1:1 space', async () => {
206
+ assert.equal(Object.keys(bob.webex.meetings.getAllMeetings()), 0);
207
+ assert.equal(Object.keys(chris.webex.meetings.getAllMeetings()), 0);
208
+
209
+ const conversation = await chris.webex.internal.conversation.create({
210
+ participants: [bob],
211
+ });
212
+
213
+ await chris.webex.internal.conversation.post(conversation, {
214
+ displayName: 'hello world how are you ',
215
+ });
216
+
217
+ await Promise.all([
218
+ testUtils.delayedPromise(
219
+ chris.webex.meetings.create(conversation.url, 'CONVERSATION_URL')
220
+ ),
221
+ testUtils.waitForEvents([
222
+ {scope: chris.webex.meetings, event: 'meeting:added', user: chris},
223
+ ]),
224
+ ]).then(function chrisJoinsMeeting() {
225
+ return Promise.all([
226
+ testUtils.delayedPromise(chris.meeting.join()),
227
+ testUtils
228
+ .waitForEvents([
229
+ {scope: bob.webex.meetings, event: 'meeting:added', user: bob},
230
+ {scope: chris.meeting, event: 'meeting:stateChange', user: chris},
231
+ ])
232
+ .then((response) => {
233
+ assert.equal(response[0].result.payload.currentState, 'ACTIVE');
234
+ }),
235
+ ]);
236
+ });
237
+ });
238
+
239
+ it('Fetch meeting information with invalid conversation URL and throws error', () => {
240
+ chris.webex.meetings.meetingInfo
241
+ .fetchMeetingInfo('http://some-invalid.com', 'CONVERSATION_URL')
242
+ .then((response) => {
243
+ assert(response.result === '404');
244
+ });
245
+ });
246
+ });
247
+ });
248
+
249
+ describe('Successful 1:1 meeting (including Guest)', function () {
250
+ before(() => {
251
+ // Workaround since getDisplayMedia requires a user gesture to be activated, and this is a integration tests
252
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1580944
253
+ if (isBrowser('firefox') || isBrowser('safari')) {
254
+ sinon.replace(
255
+ navigator.mediaDevices,
256
+ 'getDisplayMedia',
257
+ navigator.mediaDevices.getUserMedia
258
+ );
259
+ }
260
+
261
+ this.timeout(80000);
262
+ });
263
+
264
+ it('No previous Call', () => {
265
+ assert.equal(Object.keys(bob.webex.meetings.getAllMeetings()), 0);
266
+ assert.equal(Object.keys(alice.webex.meetings.getAllMeetings()), 0);
267
+
268
+ return alice.webex.internal.conversation
269
+ .create({participants: [bob]})
270
+ .then((conversation) =>
271
+ alice.webex.internal.conversation.post(conversation, {
272
+ displayName: 'hello world how are you ',
273
+ })
274
+ );
275
+ });
276
+
277
+ it('alice dials bob and adds media', () =>
278
+ Promise.all([
279
+ testUtils.delayedPromise(alice.webex.meetings.create(bob.emailAddress)),
280
+ testUtils.waitForEvents([
281
+ {scope: alice.webex.meetings, event: 'meeting:added', user: alice},
282
+ ]),
283
+ ])
284
+ .then(function aliceJoinsMeeting() {
285
+ return Promise.all([
286
+ testUtils.delayedPromise(alice.meeting.join()),
287
+ testUtils
288
+ .waitForEvents([
289
+ {scope: bob.webex.meetings, event: 'meeting:added', user: bob},
290
+ {scope: alice.meeting, event: 'meeting:stateChange', user: alice},
291
+ ])
292
+ .then((response) => {
293
+ assert.equal(response[0].result.payload.currentState, 'ACTIVE');
294
+ }),
295
+ ]);
296
+ })
297
+ .then(() => {
298
+ assert.equal(bob.meeting.partner.state, 'JOINED');
299
+ // Wait for openH264 to finsish downloading and peerConnection to be stable
300
+ testUtils.waitUntil(4000);
301
+ })
302
+ .then(() =>
303
+ Promise.all([
304
+ testUtils.addMedia(alice),
305
+ testUtils.waitForEvents([
306
+ {scope: alice.meeting, event: 'meeting:media:local:start', user: alice},
307
+ ]),
308
+ ])
309
+ )
310
+ .then(() => assert(enumerateSpy.called)));
311
+
312
+ it('bob joins the meeting', () => {
313
+ const checkBobIsInMeeting = (event) =>
314
+ !!event.delta.updated.find(
315
+ (member) => bob.meeting.members.selfId === member.id && member.status === 'IN_MEETING'
316
+ );
317
+
318
+ return Promise.all([
319
+ bob.meeting.acknowledge('INCOMING').then(() => bob.meeting.join()),
320
+ testUtils.waitForEvents([
321
+ {
322
+ scope: alice.meeting.members,
323
+ event: 'members:update',
324
+ user: alice,
325
+ match: checkBobIsInMeeting,
326
+ },
327
+ ]),
328
+ ]);
329
+ });
330
+
331
+ it('bob adds media to the meeting', () =>
332
+ Promise.all([
333
+ testUtils.addMedia(bob),
334
+ testUtils
335
+ .waitForEvents([
336
+ {scope: bob.meeting, event: 'meeting:media:local:start', user: bob},
337
+ {scope: alice.meeting, event: 'meeting:media:remote:start', user: alice},
338
+ ])
339
+ .catch((e) => {
340
+ console.error('Error on remote and local start event', e);
341
+ throw e;
342
+ }),
343
+ ])
344
+ .then(() => {
345
+ assert.equal(bob.meeting.sipUri, alice.id);
346
+ assert.equal(alice.meeting.sipUri, bob.id);
347
+ assert.exists(alice.meeting.members.locusUrl);
348
+ assert.equal(alice.meeting.type, 'CALL');
349
+ assert.equal(bob.meeting.type, 'CALL');
350
+ assert(enumerateSpy.called);
351
+ })
352
+ .then(function bobState() {
353
+ testUtils.waitForStateChange(bob.meeting, 'JOINED');
354
+ })
355
+ .then(function aliceState() {
356
+ testUtils.waitForStateChange(alice.meeting, 'JOINED');
357
+ })
358
+ .catch((e) => {
359
+ console.error('Error bob joins the meeting ', e);
360
+ throw e;
361
+ }));
362
+
363
+ it('check for meeting properties', () => {
364
+ assert.exists(alice.meeting.userId, 'userId not present');
365
+ assert.exists(alice.meeting.deviceUrl, 'deviceUrl not present');
366
+ assert.exists(alice.meeting.partner, 'partner not present');
367
+ assert.exists(alice.meeting.type, 'type not present');
368
+ assert.exists(alice.meeting.state, 'state not present');
369
+ assert.exists(alice.meeting.guest, 'guest not present');
370
+ assert.exists(alice.meeting.mediaProperties, 'mediaProperties not Present');
371
+ assert.exists(alice.meeting.mediaProperties.mediaDirection, 'mediaDirection not present');
372
+ assert.exists(alice.meeting.members.selfId, 'selfId not present');
373
+ });
374
+
375
+ it('alice Audio Mute ', () => {
376
+ const checkEvent = (event) =>
377
+ !!event.delta.updated.find(
378
+ (member) => alice.meeting.members.selfId === member.id && member.isAudioMuted === true
379
+ );
380
+
381
+ return Promise.all([
382
+ testUtils.delayedPromise(alice.meeting.muteAudio()),
383
+ testUtils.waitForEvents([
384
+ {scope: bob.meeting.members, event: 'members:update', match: checkEvent},
385
+ ]),
386
+ ]).then(() => {
387
+ assert.equal(alice.meeting.audio.muted, true);
388
+ assert.equal(alice.meeting.isAudioMuted(), true);
389
+ });
390
+ });
391
+
392
+ it('alice Audio unMute ', () => {
393
+ const checkEvent = (event) =>
394
+ !!event.delta.updated.find(
395
+ (member) => alice.meeting.members.selfId === member.id && member.isAudioMuted === false
396
+ );
397
+
398
+ return Promise.all([
399
+ testUtils.delayedPromise(alice.meeting.unmuteAudio()),
400
+ testUtils.waitForEvents([
401
+ {scope: bob.meeting.members, event: 'members:update', match: checkEvent},
402
+ ]),
403
+ ]).then(() => {
404
+ assert.equal(alice.meeting.audio.muted, false);
405
+ assert.equal(alice.meeting.isAudioMuted(), false);
406
+ });
407
+ });
408
+
409
+ it('alice Video Mute', () => {
410
+ const checkEvent = (event) =>
411
+ !!event.delta.updated.find(
412
+ (member) => alice.meeting.members.selfId === member.id && member.isVideoMuted === true
413
+ );
414
+
415
+ return Promise.all([
416
+ testUtils.delayedPromise(alice.meeting.muteVideo()),
417
+ testUtils.waitForEvents([
418
+ {scope: alice.meeting.members, event: 'members:update', match: checkEvent},
419
+ ]),
420
+ ]).then(() => {
421
+ assert.equal(alice.meeting.video.muted, true);
422
+ assert.equal(alice.meeting.isVideoMuted(), true);
423
+ });
424
+ });
425
+
426
+ it('alice video unMute', () => {
427
+ const checkEvent = (event) =>
428
+ !!event.delta.updated.find(
429
+ (member) => alice.meeting.members.selfId === member.id && member.isVideoMuted === false
430
+ );
431
+
432
+ return Promise.all([
433
+ testUtils.delayedPromise(alice.meeting.unmuteVideo()),
434
+ testUtils.waitForEvents([
435
+ {scope: bob.meeting.members, event: 'members:update', match: checkEvent},
436
+ ]),
437
+ ]).then(() => {
438
+ assert.equal(alice.meeting.video.muted, false);
439
+ assert.equal(alice.meeting.isVideoMuted(), false);
440
+ });
441
+ });
442
+
443
+ it('alice update Audio', () => {
444
+ const oldVideoTrackId = alice.meeting.mediaProperties.videoTrack.id;
445
+
446
+ return alice.meeting.getMediaStreams({sendAudio: true}).then((response) =>
447
+ Promise.all([
448
+ testUtils.delayedPromise(
449
+ alice.meeting
450
+ .updateAudio({
451
+ sendAudio: true,
452
+ receiveAudio: true,
453
+ stream: response[0],
454
+ })
455
+ .then(() => {
456
+ console.log(
457
+ 'AUDIO ',
458
+ alice.meeting.mediaProperties.peerConnection.audioTransceiver.sender.track
459
+ );
460
+ assert.equal(
461
+ alice.meeting.mediaProperties.audioTrack.id,
462
+ response[0].getAudioTracks()[0].id
463
+ );
464
+ assert.equal(alice.meeting.mediaProperties.videoTrack.id, oldVideoTrackId);
465
+ })
466
+ ),
467
+ testUtils
468
+ .waitForEvents([{scope: alice.meeting, event: 'media:ready'}])
469
+ .then((response) => {
470
+ console.log('MEDIA:READY event ', response[0].result);
471
+ assert.equal(response[0].result.type === 'local', true);
472
+ }),
473
+ ])
474
+ );
475
+ });
476
+
477
+ it('alice update video', () => {
478
+ const oldAudioTrackId = alice.meeting.mediaProperties.audioTrack.id;
479
+
480
+ return alice.meeting.getMediaStreams({sendVideo: true}).then((response) =>
481
+ Promise.all([
482
+ testUtils.delayedPromise(
483
+ alice.meeting
484
+ .updateVideo({
485
+ sendVideo: true,
486
+ receiveVideo: true,
487
+ stream: response[0],
488
+ })
489
+ .then(() => {
490
+ assert.equal(
491
+ alice.meeting.mediaProperties.videoTrack.id,
492
+ response[0].getVideoTracks()[0].id
493
+ );
494
+ assert.equal(alice.meeting.mediaProperties.audioTrack.id, oldAudioTrackId);
495
+ })
496
+ ),
497
+ testUtils
498
+ .waitForEvents([{scope: alice.meeting, event: 'media:ready'}])
499
+ .then((response) => {
500
+ console.log('MEDIA:READY event ', response[0].result);
501
+ assert.equal(response[0].result.type === 'local', true);
502
+ }),
503
+ ])
504
+ );
505
+ });
506
+
507
+ it('alice mutes bob', () =>
508
+ Promise.all([
509
+ testUtils.delayedPromise(alice.meeting.mute(bob.meeting.members.selfId, true)),
510
+ testUtils
511
+ .waitForEvents([{scope: bob.meeting, event: 'meeting:self:mutedByOthers'}])
512
+ .then((response) => {
513
+ console.log('meeting:self:mutedByOthers event ', response[0].result);
514
+ assert.equal(response[0].result.payload.unmuteAllowed, true);
515
+ }),
516
+ ]));
517
+
518
+ it('alice unmutes bob', () =>
519
+ Promise.all([
520
+ testUtils.delayedPromise(alice.meeting.mute(bob.meeting.members.selfId, false)),
521
+ testUtils
522
+ .waitForEvents([{scope: bob.meeting, event: 'meeting:self:unmutedByOthers'}])
523
+ .then((response) => {
524
+ console.log('meeting:self:unmutedByOthers event ', response[0].result);
525
+ }),
526
+ ]));
527
+
528
+ it('bob audio mute, so alice cannot unmute bob', (done) => {
529
+ const checkEvent = (event) =>
530
+ !!event.delta.updated.find(
531
+ (member) => bob.meeting.members.selfId === member.id && member.isAudioMuted === true
532
+ );
533
+
534
+ // first bob mutes himself
535
+ Promise.all([
536
+ testUtils.delayedPromise(bob.meeting.muteAudio()),
537
+ testUtils.waitForEvents([
538
+ {scope: bob.meeting.members, event: 'members:update', match: checkEvent},
539
+ ]),
540
+ ])
541
+ .then(() => {
542
+ assert.equal(bob.meeting.audio.muted, true);
543
+ assert.equal(bob.meeting.isAudioMuted(), true);
544
+ })
545
+ // now alice tries to unmmut bob
546
+ .then(() =>
547
+ testUtils.delayedPromise(alice.meeting.mute(bob.meeting.members.selfId, false))
548
+ )
549
+ // expect the waitForEvents to timeout
550
+ .then(() =>
551
+ testUtils.waitForEvents(
552
+ [{scope: bob.meeting, event: 'meeting:self:unmutedByOthers'}],
553
+ 2000
554
+ )
555
+ )
556
+ .then(() => {
557
+ assert.fail('bob received unexpected meeting:self:unmutedByOthers event');
558
+ })
559
+ .catch(() => {
560
+ assert.equal(bob.meeting.audio.muted, true);
561
+ assert.equal(bob.meeting.isAudioMuted(), true);
562
+ done();
563
+ });
564
+ });
565
+
566
+ it('bob audio unmute ', () => {
567
+ const checkEvent = (event) =>
568
+ !!event.delta.updated.find(
569
+ (member) => bob.meeting.members.selfId === member.id && member.isAudioMuted === false
570
+ );
571
+
572
+ return Promise.all([
573
+ testUtils.delayedPromise(bob.meeting.unmuteAudio()),
574
+ testUtils.waitForEvents([
575
+ {scope: alice.meeting.members, event: 'members:update', match: checkEvent},
576
+ ]),
577
+ ]).then(() => {
578
+ assert.equal(bob.meeting.audio.muted, false);
579
+ assert.equal(bob.meeting.isAudioMuted(), false);
580
+ });
581
+ });
582
+
583
+ it('alice shares the screen with highFrameRate', () =>
584
+ Promise.all([
585
+ testUtils.delayedPromise(
586
+ alice.meeting.shareScreen({sharePreferences: {highFrameRate: true}})
587
+ ),
588
+ testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingLocal'}]),
589
+ testUtils
590
+ .waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingRemote'}])
591
+ .then((response) => {
592
+ assert.equal(response[0].result.memberId, alice.meeting.selfId);
593
+ }),
594
+ testUtils
595
+ .waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
596
+ .then((response) => {
597
+ console.log(
598
+ 'SCREEN SHARE RESPONSE ',
599
+ JSON.stringify(response, testUtils.getCircularReplacer())
600
+ );
601
+ }),
602
+ testUtils
603
+ .waitForEvents([{scope: alice.meeting, event: 'media:ready'}])
604
+ .then((response) => {
605
+ console.log('MEDIA:READY event ', response[0].result);
606
+ assert.equal(response[0].result.type === 'localShare', true);
607
+ }),
608
+ ]).then(() => {
609
+ // TODO: Re-eanable Safari when screensharing issues have been resolved
610
+ if (!isBrowser('safari')) {
611
+ assert.equal(alice.meeting.mediaProperties.shareTrack.getConstraints().height, 720);
612
+ }
613
+ assert.equal(alice.meeting.isSharing, true);
614
+ assert.equal(alice.meeting.shareStatus, 'local_share_active');
615
+ assert.equal(bob.meeting.shareStatus, 'remote_share_active');
616
+ console.log(
617
+ 'SCREEN SHARE PARTICIPANTS ',
618
+ JSON.stringify(alice.meeting.locusInfo.participants)
619
+ );
620
+
621
+ return testUtils.waitUntil(10000);
622
+ }));
623
+
624
+ it('bob steals the screen share from alice', () =>
625
+ Promise.all([
626
+ testUtils.delayedPromise(bob.meeting.shareScreen()),
627
+ testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:stoppedSharingLocal'}]),
628
+ testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingLocal'}]),
629
+ testUtils
630
+ .waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingRemote'}])
631
+ .then((response) => {
632
+ assert.equal(response[0].result.memberId, bob.meeting.selfId);
633
+ }),
634
+ testUtils
635
+ .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
636
+ .then((response) => {
637
+ console.log(
638
+ 'SCREEN SHARE RESPONSE ',
639
+ JSON.stringify(response, testUtils.getCircularReplacer())
640
+ );
641
+ }),
642
+ testUtils.waitForEvents([{scope: bob.meeting, event: 'media:ready'}]).then((response) => {
643
+ console.log('MEDIA:READY event ', response[0].result);
644
+ assert.equal(response[0].result.type === 'localShare', true);
645
+ }),
646
+ ]).then(() => {
647
+ const heightResolution = DEFAULT_RESOLUTIONS.meetings.screenResolution.idealHeight;
648
+
649
+ // TODO: Re-eanable Safari when screensharing issues have been resolved
650
+ if (!isBrowser('safari')) {
651
+ assert.equal(
652
+ bob.meeting.mediaProperties.shareTrack.getConstraints().height,
653
+ heightResolution
654
+ );
655
+ }
656
+ assert.equal(bob.meeting.isSharing, true);
657
+ assert.equal(bob.meeting.shareStatus, 'local_share_active');
658
+ assert.equal(alice.meeting.shareStatus, 'remote_share_active');
659
+
660
+ return testUtils.waitUntil(10000);
661
+ }));
662
+
663
+ it('bob stops sharing ', () =>
664
+ Promise.all([
665
+ // Wait for peerConnection to stabalize
666
+ testUtils.waitUntil(20000),
667
+ testUtils.delayedPromise(
668
+ bob.meeting.updateShare({
669
+ sendShare: false,
670
+ receiveShare: true,
671
+ })
672
+ ),
673
+ testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:stoppedSharingLocal'}]),
674
+ testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:stoppedSharingRemote'}]),
675
+ ]).then(() => {
676
+ assert.equal(bob.meeting.isSharing, false);
677
+ assert.equal(bob.meeting.shareStatus, 'no_share');
678
+ assert.equal(alice.meeting.shareStatus, 'no_share');
679
+ }));
680
+
681
+ it('alice shares whiteboard A', () =>
682
+ Promise.all([
683
+ testUtils.delayedPromise(alice.meeting.startWhiteboardShare(channelUrlA)),
684
+ testUtils.waitForEvents([
685
+ {scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'},
686
+ ]),
687
+ testUtils
688
+ .waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'}])
689
+ .then((response) => {
690
+ const {memberId, resourceUrl} = response[0].result;
691
+
692
+ assert.equal(memberId, alice.meeting.selfId);
693
+ assert.equal(resourceUrl, channelUrlA);
694
+ }),
695
+ testUtils
696
+ .waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
697
+ .then((response) => {
698
+ console.log(
699
+ 'WHITEBOARD SHARE RESPONSE ',
700
+ JSON.stringify(response, testUtils.getCircularReplacer())
701
+ );
702
+ }),
703
+ ]).then(() => {
704
+ assert.equal(alice.meeting.isSharing, false);
705
+ assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
706
+ assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
707
+ }));
708
+
709
+ it('bob steals share from alice with whiteboard B', () =>
710
+ Promise.all([
711
+ testUtils.delayedPromise(bob.meeting.startWhiteboardShare(channelUrlB)),
712
+ testUtils.waitForEvents([
713
+ {scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'},
714
+ ]),
715
+ testUtils
716
+ .waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'}])
717
+ .then((response) => {
718
+ const {memberId, resourceUrl} = response[0].result;
719
+
720
+ assert.equal(memberId, bob.meeting.selfId);
721
+ assert.equal(resourceUrl, channelUrlB);
722
+ }),
723
+ testUtils
724
+ .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
725
+ .then((response) => {
726
+ console.log(
727
+ 'WHITEBOARD SHARE RESPONSE ',
728
+ JSON.stringify(response, testUtils.getCircularReplacer())
729
+ );
730
+ }),
731
+ ]).then(() => {
732
+ assert.equal(bob.meeting.isSharing, false);
733
+ assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
734
+ assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
735
+ }));
736
+
737
+ it('bob stops sharing ', () =>
738
+ Promise.all([
739
+ // Wait for peerConnection to stabalize
740
+ testUtils.waitUntil(20000),
741
+ testUtils.delayedPromise(bob.meeting.stopWhiteboardShare(channelUrlB)),
742
+ testUtils.waitForEvents([
743
+ {scope: bob.meeting, event: 'meeting:stoppedSharingWhiteboard'},
744
+ ]),
745
+ testUtils.waitForEvents([
746
+ {scope: alice.meeting, event: 'meeting:stoppedSharingWhiteboard'},
747
+ ]),
748
+ ]).then(() => {
749
+ assert.equal(bob.meeting.isSharing, false);
750
+ assert.equal(bob.meeting.shareStatus, 'no_share');
751
+ assert.equal(alice.meeting.shareStatus, 'no_share');
752
+ }));
753
+
754
+ it('alice shares whiteboard B', () =>
755
+ Promise.all([
756
+ testUtils.delayedPromise(alice.meeting.startWhiteboardShare(channelUrlB)),
757
+ testUtils.waitForEvents([
758
+ {scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'},
759
+ ]),
760
+ testUtils
761
+ .waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'}])
762
+ .then((response) => {
763
+ const {memberId, resourceUrl} = response[0].result;
764
+
765
+ assert.equal(memberId, alice.meeting.selfId);
766
+ assert.equal(resourceUrl, channelUrlB);
767
+ }),
768
+ testUtils
769
+ .waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
770
+ .then((response) => {
771
+ console.log(
772
+ 'WHITEBOARD SHARE RESPONSE ',
773
+ JSON.stringify(response, testUtils.getCircularReplacer())
774
+ );
775
+ }),
776
+ ]).then(() => {
777
+ assert.equal(alice.meeting.isSharing, false);
778
+ assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
779
+ assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
780
+ }));
781
+
782
+ it('bob steals the share from alice with desktop share', () =>
783
+ Promise.all([
784
+ testUtils.delayedPromise(bob.meeting.shareScreen()),
785
+ testUtils.waitForEvents([
786
+ {scope: alice.meeting, event: 'meeting:stoppedSharingWhiteboard'},
787
+ ]),
788
+ testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingLocal'}]),
789
+ testUtils
790
+ .waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingRemote'}])
791
+ .then((response) => {
792
+ assert.equal(response[0].result.memberId, bob.meeting.selfId);
793
+ }),
794
+ testUtils
795
+ .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
796
+ .then((response) => {
797
+ console.log(
798
+ 'SCREEN SHARE RESPONSE ',
799
+ JSON.stringify(response, testUtils.getCircularReplacer())
800
+ );
801
+ }),
802
+ testUtils.waitForEvents([{scope: bob.meeting, event: 'media:ready'}]).then((response) => {
803
+ console.log('MEDIA:READY event ', response[0].result);
804
+ assert.equal(response[0].result.type === 'localShare', true);
805
+ }),
806
+ ]).then(() => {
807
+ const heightResolution = DEFAULT_RESOLUTIONS.meetings.screenResolution.idealHeight;
808
+
809
+ // TODO: Re-eanable Safari when screensharing issues have been resolved
810
+ if (!isBrowser('safari')) {
811
+ assert.equal(
812
+ bob.meeting.mediaProperties.shareTrack.getConstraints().height,
813
+ heightResolution
814
+ );
815
+ }
816
+ assert.equal(bob.meeting.isSharing, true);
817
+ assert.equal(bob.meeting.shareStatus, 'local_share_active');
818
+ assert.equal(alice.meeting.shareStatus, 'remote_share_active');
819
+
820
+ return testUtils.waitUntil(10000);
821
+ }));
822
+
823
+ it('bob shares whiteboard B', () =>
824
+ Promise.all([
825
+ testUtils.delayedPromise(bob.meeting.startWhiteboardShare(channelUrlB)),
826
+ testUtils.waitForEvents([
827
+ {scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'},
828
+ ]),
829
+ testUtils
830
+ .waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'}])
831
+ .then((response) => {
832
+ const {memberId, resourceUrl} = response[0].result;
833
+
834
+ assert.equal(memberId, bob.meeting.selfId);
835
+ assert.equal(resourceUrl, channelUrlB);
836
+ }),
837
+ testUtils
838
+ .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
839
+ .then((response) => {
840
+ console.log(
841
+ 'WHITEBOARD SHARE RESPONSE ',
842
+ JSON.stringify(response, testUtils.getCircularReplacer())
843
+ );
844
+ }),
845
+ ]).then(() => {
846
+ assert.equal(bob.meeting.isSharing, false);
847
+ assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
848
+ assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
849
+ }));
850
+
851
+ it('alice adds chris as guest to 1:1 meeting', () =>
852
+ Promise.all([
853
+ testUtils.delayedPromise(alice.meeting.invite({emailAddress: chris.emailAddress})),
854
+ testUtils.waitForEvents([
855
+ {scope: chris.webex.meetings, event: 'meeting:added', user: chris},
856
+ ]),
857
+ testUtils
858
+ .waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
859
+ .then((response) => {
860
+ const chrisParticipant = response[0].result.delta.added.find(
861
+ (member) => member.participant.identity === chris.id
862
+ );
863
+
864
+ assert.equal(chrisParticipant.status, 'NOT_IN_MEETING');
865
+ }),
866
+ ])
867
+ .catch((e) => {
868
+ console.error('Error adding chris as guest ', e);
869
+ throw e;
870
+ })
871
+ .then(function memberUpdated() {
872
+ assert.exists(chris.meeting);
873
+
874
+ return Promise.all([
875
+ testUtils.delayedPromise(chris.meeting.join()),
876
+ testUtils.waitForEvents([
877
+ {
878
+ scope: alice.meeting.members,
879
+ event: 'members:update',
880
+ match: testUtils.checkParticipantUpdatedStatus(chris, 'IN_MEETING'),
881
+ },
882
+ ]),
883
+ ])
884
+ .then(() => {
885
+ assert.equal(
886
+ alice.meeting.members.membersCollection.get(chris.meeting.members.selfId)
887
+ .participant.state,
888
+ 'JOINED'
889
+ );
890
+ })
891
+ .then(() => testUtils.waitForStateChange(chris.meeting, 'JOINED'))
892
+ .then(() => testUtils.addMedia(chris))
893
+ .then(() => assert(enumerateSpy.called));
894
+ })
895
+ .then(() =>
896
+ Promise.all([
897
+ testUtils.delayedPromise(chris.meeting.leave()),
898
+ testUtils.waitForEvents([
899
+ {
900
+ scope: alice.meeting.members,
901
+ event: 'members:update',
902
+ match: testUtils.checkParticipantUpdatedStatus(chris, 'NOT_IN_MEETING'),
903
+ },
904
+ ]),
905
+ ])
906
+ )
907
+ .catch((e) => {
908
+ console.error('Error chris joining the meeting ', e);
909
+ throw e;
910
+ }));
911
+
912
+ it('leave on the meeting object', () => {
913
+ const checkInactive = (result) => result.reason === 'CALL_INACTIVE';
914
+
915
+ Promise.all([
916
+ testUtils.delayedPromise(bob.meeting.leave()),
917
+ testUtils.waitForEvents([
918
+ {scope: alice.meeting.members, event: 'members:update', user: alice},
919
+ {
920
+ scope: bob.webex.meetings,
921
+ event: 'meeting:removed',
922
+ user: bob,
923
+ match: checkInactive,
924
+ },
925
+ {scope: alice.webex.meetings, event: 'meeting:removed', user: alice},
926
+ ]),
927
+ ])
928
+ .then(() => {
929
+ assert.equal(bob.meeting, null);
930
+ assert.equal(alice.meeting, null);
931
+ })
932
+ .then(() => testUtils.waitForCallEnded(bob, alice.emailAddress))
933
+ .then(() => testUtils.waitForCallEnded(alice, bob.emailAddress))
934
+ .then(() => {
935
+ assert.equal(alice.webex.meetings.getMeetingByType('sipUri', bob.emailAddress), null);
936
+ assert.equal(bob.webex.meetings.getMeetingByType('sipUri', alice.emailAddress), null);
937
+ });
938
+ });
939
+ });
940
+ });
941
+ });