@webex/calling 3.11.0 → 3.12.0-llmrefactor.2

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 (372) hide show
  1. package/dist/CallHistory/CallHistory.js +596 -0
  2. package/dist/CallHistory/CallHistory.js.map +1 -0
  3. package/dist/CallHistory/CallHistory.test.js +916 -0
  4. package/dist/CallHistory/CallHistory.test.js.map +1 -0
  5. package/dist/CallHistory/callHistoryFixtures.js +650 -0
  6. package/dist/CallHistory/callHistoryFixtures.js.map +1 -0
  7. package/dist/CallHistory/constants.js +38 -0
  8. package/dist/CallHistory/constants.js.map +1 -0
  9. package/dist/CallHistory/types.js +7 -0
  10. package/dist/CallHistory/types.js.map +1 -0
  11. package/dist/CallRecording/CallRecording.js +160 -0
  12. package/dist/CallRecording/CallRecording.js.map +1 -0
  13. package/dist/CallRecording/CallRecording.test.js +257 -0
  14. package/dist/CallRecording/CallRecording.test.js.map +1 -0
  15. package/dist/CallRecording/WxcCallRecordingConnector.js +577 -0
  16. package/dist/CallRecording/WxcCallRecordingConnector.js.map +1 -0
  17. package/dist/CallRecording/WxcCallRecordingConnector.test.js +652 -0
  18. package/dist/CallRecording/WxcCallRecordingConnector.test.js.map +1 -0
  19. package/dist/CallRecording/callRecordingFixtures.js +235 -0
  20. package/dist/CallRecording/callRecordingFixtures.js.map +1 -0
  21. package/dist/CallRecording/constants.js +50 -0
  22. package/dist/CallRecording/constants.js.map +1 -0
  23. package/dist/CallRecording/types.js +137 -0
  24. package/dist/CallRecording/types.js.map +1 -0
  25. package/dist/CallRecording/utils.js +42 -0
  26. package/dist/CallRecording/utils.js.map +1 -0
  27. package/dist/CallRecording/utils.test.js +97 -0
  28. package/dist/CallRecording/utils.test.js.map +1 -0
  29. package/dist/CallSettings/CallSettings.js +311 -0
  30. package/dist/CallSettings/CallSettings.js.map +1 -0
  31. package/dist/CallSettings/CallSettings.test.js +122 -0
  32. package/dist/CallSettings/CallSettings.test.js.map +1 -0
  33. package/dist/CallSettings/UcmBackendConnector.js +308 -0
  34. package/dist/CallSettings/UcmBackendConnector.js.map +1 -0
  35. package/dist/CallSettings/UcmBackendConnector.test.js +411 -0
  36. package/dist/CallSettings/UcmBackendConnector.test.js.map +1 -0
  37. package/dist/CallSettings/WxCallBackendConnector.js +597 -0
  38. package/dist/CallSettings/WxCallBackendConnector.js.map +1 -0
  39. package/dist/CallSettings/WxCallBackendConnector.test.js +904 -0
  40. package/dist/CallSettings/WxCallBackendConnector.test.js.map +1 -0
  41. package/dist/CallSettings/constants.js +31 -0
  42. package/dist/CallSettings/constants.js.map +1 -0
  43. package/dist/CallSettings/testFixtures.js +68 -0
  44. package/dist/CallSettings/testFixtures.js.map +1 -0
  45. package/dist/CallSettings/types.js +7 -0
  46. package/dist/CallSettings/types.js.map +1 -0
  47. package/dist/CallingClient/CallingClient.js +1349 -0
  48. package/dist/CallingClient/CallingClient.js.map +1 -0
  49. package/dist/CallingClient/CallingClient.test.js +1625 -0
  50. package/dist/CallingClient/CallingClient.test.js.map +1 -0
  51. package/dist/CallingClient/callRecordFixtures.js +101 -0
  52. package/dist/CallingClient/callRecordFixtures.js.map +1 -0
  53. package/dist/CallingClient/calling/CallerId/index.js +275 -0
  54. package/dist/CallingClient/calling/CallerId/index.js.map +1 -0
  55. package/dist/CallingClient/calling/CallerId/index.test.js +275 -0
  56. package/dist/CallingClient/calling/CallerId/index.test.js.map +1 -0
  57. package/dist/CallingClient/calling/CallerId/types.js +7 -0
  58. package/dist/CallingClient/calling/CallerId/types.js.map +1 -0
  59. package/dist/CallingClient/calling/call.js +3666 -0
  60. package/dist/CallingClient/calling/call.js.map +1 -0
  61. package/dist/CallingClient/calling/call.test.js +3970 -0
  62. package/dist/CallingClient/calling/call.test.js.map +1 -0
  63. package/dist/CallingClient/calling/callManager.js +531 -0
  64. package/dist/CallingClient/calling/callManager.js.map +1 -0
  65. package/dist/CallingClient/calling/callManager.test.js +881 -0
  66. package/dist/CallingClient/calling/callManager.test.js.map +1 -0
  67. package/dist/CallingClient/calling/index.js +30 -0
  68. package/dist/CallingClient/calling/index.js.map +1 -0
  69. package/dist/CallingClient/calling/types.js +79 -0
  70. package/dist/CallingClient/calling/types.js.map +1 -0
  71. package/dist/CallingClient/callingClientFixtures.js +143 -0
  72. package/dist/CallingClient/callingClientFixtures.js.map +1 -0
  73. package/dist/CallingClient/constants.js +272 -0
  74. package/dist/CallingClient/constants.js.map +1 -0
  75. package/dist/CallingClient/line/index.js +339 -0
  76. package/dist/CallingClient/line/index.js.map +1 -0
  77. package/dist/CallingClient/line/line.test.js +379 -0
  78. package/dist/CallingClient/line/line.test.js.map +1 -0
  79. package/dist/CallingClient/line/types.js +21 -0
  80. package/dist/CallingClient/line/types.js.map +1 -0
  81. package/dist/CallingClient/registration/index.js +19 -0
  82. package/dist/CallingClient/registration/index.js.map +1 -0
  83. package/dist/CallingClient/registration/register.js +2079 -0
  84. package/dist/CallingClient/registration/register.js.map +1 -0
  85. package/dist/CallingClient/registration/register.test.js +2476 -0
  86. package/dist/CallingClient/registration/register.test.js.map +1 -0
  87. package/dist/CallingClient/registration/registerFixtures.js +36 -0
  88. package/dist/CallingClient/registration/registerFixtures.js.map +1 -0
  89. package/dist/CallingClient/registration/types.js +33 -0
  90. package/dist/CallingClient/registration/types.js.map +1 -0
  91. package/dist/CallingClient/registration/webWorker.js +67 -0
  92. package/dist/CallingClient/registration/webWorker.js.map +1 -0
  93. package/dist/CallingClient/registration/webWorker.test.js +189 -0
  94. package/dist/CallingClient/registration/webWorker.test.js.map +1 -0
  95. package/dist/CallingClient/registration/webWorkerStr.js +15 -0
  96. package/dist/CallingClient/registration/webWorkerStr.js.map +1 -0
  97. package/dist/CallingClient/types.js +14 -0
  98. package/dist/CallingClient/types.js.map +1 -0
  99. package/dist/CallingClient/utils/constants.js +58 -0
  100. package/dist/CallingClient/utils/constants.js.map +1 -0
  101. package/dist/CallingClient/utils/index.js +63 -0
  102. package/dist/CallingClient/utils/index.js.map +1 -0
  103. package/dist/CallingClient/utils/mobiusSocketMapper.js +122 -0
  104. package/dist/CallingClient/utils/mobiusSocketMapper.js.map +1 -0
  105. package/dist/CallingClient/utils/mobiusSocketMapper.test.js +221 -0
  106. package/dist/CallingClient/utils/mobiusSocketMapper.test.js.map +1 -0
  107. package/dist/CallingClient/utils/request.js +435 -0
  108. package/dist/CallingClient/utils/request.js.map +1 -0
  109. package/dist/CallingClient/utils/request.test.js +999 -0
  110. package/dist/CallingClient/utils/request.test.js.map +1 -0
  111. package/dist/CallingClient/utils/types.js +7 -0
  112. package/dist/CallingClient/utils/types.js.map +1 -0
  113. package/dist/CallingClient/utils/wsFeatureFlag.js +70 -0
  114. package/dist/CallingClient/utils/wsFeatureFlag.js.map +1 -0
  115. package/dist/CallingClient/utils/wsFeatureFlag.test.js +139 -0
  116. package/dist/CallingClient/utils/wsFeatureFlag.test.js.map +1 -0
  117. package/dist/CallingClient/windowsChromiumIceWarmupUtils.js +142 -0
  118. package/dist/CallingClient/windowsChromiumIceWarmupUtils.js.map +1 -0
  119. package/dist/Contacts/ContactsClient.js +1208 -0
  120. package/dist/Contacts/ContactsClient.js.map +1 -0
  121. package/dist/Contacts/ContactsClient.test.js +999 -0
  122. package/dist/Contacts/ContactsClient.test.js.map +1 -0
  123. package/dist/Contacts/constants.js +40 -0
  124. package/dist/Contacts/constants.js.map +1 -0
  125. package/dist/Contacts/contactFixtures.js +430 -0
  126. package/dist/Contacts/contactFixtures.js.map +1 -0
  127. package/dist/Contacts/types.js +43 -0
  128. package/dist/Contacts/types.js.map +1 -0
  129. package/dist/Errors/catalog/CallError.js +89 -0
  130. package/dist/Errors/catalog/CallError.js.map +1 -0
  131. package/dist/Errors/catalog/CallingDeviceError.js +83 -0
  132. package/dist/Errors/catalog/CallingDeviceError.js.map +1 -0
  133. package/dist/Errors/catalog/ExtendedError.js +42 -0
  134. package/dist/Errors/catalog/ExtendedError.js.map +1 -0
  135. package/dist/Errors/catalog/LineError.js +85 -0
  136. package/dist/Errors/catalog/LineError.js.map +1 -0
  137. package/dist/Errors/index.js +28 -0
  138. package/dist/Errors/index.js.map +1 -0
  139. package/dist/Errors/types.js +61 -0
  140. package/dist/Errors/types.js.map +1 -0
  141. package/dist/Events/impl/index.js +79 -0
  142. package/dist/Events/impl/index.js.map +1 -0
  143. package/dist/Events/types.js +134 -0
  144. package/dist/Events/types.js.map +1 -0
  145. package/dist/Logger/index.js +228 -0
  146. package/dist/Logger/index.js.map +1 -0
  147. package/dist/Logger/index.test.js +87 -0
  148. package/dist/Logger/index.test.js.map +1 -0
  149. package/dist/Logger/types.js +34 -0
  150. package/dist/Logger/types.js.map +1 -0
  151. package/dist/Metrics/index.js +595 -0
  152. package/dist/Metrics/index.js.map +1 -0
  153. package/dist/Metrics/index.test.js +819 -0
  154. package/dist/Metrics/index.test.js.map +1 -0
  155. package/dist/Metrics/types.js +82 -0
  156. package/dist/Metrics/types.js.map +1 -0
  157. package/dist/SDKConnector/index.js +102 -0
  158. package/dist/SDKConnector/index.js.map +1 -0
  159. package/dist/SDKConnector/index.test.js +9 -0
  160. package/dist/SDKConnector/index.test.js.map +1 -0
  161. package/dist/SDKConnector/types.js +7 -0
  162. package/dist/SDKConnector/types.js.map +1 -0
  163. package/dist/SDKConnector/utils.js +39 -0
  164. package/dist/SDKConnector/utils.js.map +1 -0
  165. package/dist/SDKConnector/utils.test.js +9 -0
  166. package/dist/SDKConnector/utils.test.js.map +1 -0
  167. package/dist/Voicemail/BroadworksBackendConnector.js +699 -0
  168. package/dist/Voicemail/BroadworksBackendConnector.js.map +1 -0
  169. package/dist/Voicemail/BroadworksBackendConnector.test.js +820 -0
  170. package/dist/Voicemail/BroadworksBackendConnector.test.js.map +1 -0
  171. package/dist/Voicemail/UcmBackendConnector.js +628 -0
  172. package/dist/Voicemail/UcmBackendConnector.js.map +1 -0
  173. package/dist/Voicemail/UcmBackendConnector.test.js +738 -0
  174. package/dist/Voicemail/UcmBackendConnector.test.js.map +1 -0
  175. package/dist/Voicemail/Voicemail.js +472 -0
  176. package/dist/Voicemail/Voicemail.js.map +1 -0
  177. package/dist/Voicemail/Voicemail.test.js +391 -0
  178. package/dist/Voicemail/Voicemail.test.js.map +1 -0
  179. package/dist/Voicemail/WxCallBackendConnector.js +657 -0
  180. package/dist/Voicemail/WxCallBackendConnector.js.map +1 -0
  181. package/dist/Voicemail/WxCallBackendConnector.test.js +1225 -0
  182. package/dist/Voicemail/WxCallBackendConnector.test.js.map +1 -0
  183. package/dist/Voicemail/constants.js +61 -0
  184. package/dist/Voicemail/constants.js.map +1 -0
  185. package/dist/Voicemail/types.js +7 -0
  186. package/dist/Voicemail/types.js.map +1 -0
  187. package/dist/Voicemail/voicemailFixture.js +524 -0
  188. package/dist/Voicemail/voicemailFixture.js.map +1 -0
  189. package/dist/api.js +213 -0
  190. package/dist/api.js.map +1 -0
  191. package/dist/common/Utils.js +1624 -0
  192. package/dist/common/Utils.js.map +1 -0
  193. package/dist/common/Utils.test.js +2225 -0
  194. package/dist/common/Utils.test.js.map +1 -0
  195. package/dist/common/constants.js +62 -0
  196. package/dist/common/constants.js.map +1 -0
  197. package/dist/common/index.js +19 -0
  198. package/dist/common/index.js.map +1 -0
  199. package/dist/common/testUtil.js +988 -0
  200. package/dist/common/testUtil.js.map +1 -0
  201. package/dist/common/types.js +78 -0
  202. package/dist/common/types.js.map +1 -0
  203. package/dist/index.js +452 -0
  204. package/dist/index.js.map +1 -0
  205. package/dist/mobius-socket/config.js +24 -0
  206. package/dist/mobius-socket/config.js.map +1 -0
  207. package/dist/mobius-socket/errors.js +143 -0
  208. package/dist/mobius-socket/errors.js.map +1 -0
  209. package/dist/mobius-socket/errors.test.js +20 -0
  210. package/dist/mobius-socket/errors.test.js.map +1 -0
  211. package/dist/mobius-socket/index.js +57 -0
  212. package/dist/mobius-socket/index.js.map +1 -0
  213. package/dist/mobius-socket/mobius-socket-events.test.js +492 -0
  214. package/dist/mobius-socket/mobius-socket-events.test.js.map +1 -0
  215. package/dist/mobius-socket/mobius-socket.js +849 -0
  216. package/dist/mobius-socket/mobius-socket.js.map +1 -0
  217. package/dist/mobius-socket/mobius-socket.test.js +1898 -0
  218. package/dist/mobius-socket/mobius-socket.test.js.map +1 -0
  219. package/dist/mobius-socket/socket/constants.js +55 -0
  220. package/dist/mobius-socket/socket/constants.js.map +1 -0
  221. package/dist/mobius-socket/socket/index.js +15 -0
  222. package/dist/mobius-socket/socket/index.js.map +1 -0
  223. package/dist/mobius-socket/socket/socket-base.js +604 -0
  224. package/dist/mobius-socket/socket/socket-base.js.map +1 -0
  225. package/dist/mobius-socket/socket/socket.js +19 -0
  226. package/dist/mobius-socket/socket/socket.js.map +1 -0
  227. package/dist/mobius-socket/socket/socket.shim.js +26 -0
  228. package/dist/mobius-socket/socket/socket.shim.js.map +1 -0
  229. package/dist/mobius-socket/socket/types.js +7 -0
  230. package/dist/mobius-socket/socket/types.js.map +1 -0
  231. package/dist/mobius-socket/socket.test.js +727 -0
  232. package/dist/mobius-socket/socket.test.js.map +1 -0
  233. package/dist/mobius-socket/test/mocha-helpers.js +23 -0
  234. package/dist/mobius-socket/test/mocha-helpers.js.map +1 -0
  235. package/dist/mobius-socket/test/promise-tick.js +28 -0
  236. package/dist/mobius-socket/test/promise-tick.js.map +1 -0
  237. package/dist/mobius-socket/types.js +7 -0
  238. package/dist/mobius-socket/types.js.map +1 -0
  239. package/dist/module/CallHistory/CallHistory.js +28 -17
  240. package/dist/module/CallRecording/CallRecording.js +56 -0
  241. package/dist/module/CallRecording/WxcCallRecordingConnector.js +257 -0
  242. package/dist/module/CallRecording/callRecordingFixtures.js +201 -0
  243. package/dist/module/CallRecording/constants.js +28 -0
  244. package/dist/module/CallRecording/types.js +19 -0
  245. package/dist/module/CallRecording/utils.js +14 -0
  246. package/dist/module/CallingClient/CallingClient.js +166 -8
  247. package/dist/module/CallingClient/calling/call.js +201 -68
  248. package/dist/module/CallingClient/calling/callManager.js +51 -11
  249. package/dist/module/CallingClient/calling/types.js +2 -0
  250. package/dist/module/CallingClient/constants.js +29 -0
  251. package/dist/module/CallingClient/line/index.js +4 -2
  252. package/dist/module/CallingClient/registration/register.js +274 -64
  253. package/dist/module/CallingClient/registration/types.js +5 -1
  254. package/dist/module/CallingClient/registration/webWorker.js +42 -61
  255. package/dist/module/CallingClient/registration/webWorkerStr.js +47 -82
  256. package/dist/module/CallingClient/utils/constants.js +36 -0
  257. package/dist/module/CallingClient/utils/index.js +5 -0
  258. package/dist/module/CallingClient/utils/mobiusSocketMapper.js +72 -0
  259. package/dist/module/CallingClient/utils/request.js +211 -0
  260. package/dist/module/CallingClient/utils/types.js +1 -0
  261. package/dist/module/CallingClient/utils/wsFeatureFlag.js +41 -0
  262. package/dist/module/Contacts/ContactsClient.js +1 -1
  263. package/dist/module/Errors/types.js +2 -0
  264. package/dist/module/Events/types.js +23 -10
  265. package/dist/module/Metrics/index.js +48 -1
  266. package/dist/module/Metrics/types.js +18 -0
  267. package/dist/module/api.js +3 -2
  268. package/dist/module/common/Utils.js +85 -22
  269. package/dist/module/common/testUtil.js +6 -1
  270. package/dist/module/common/types.js +3 -0
  271. package/dist/module/index.js +7 -3
  272. package/dist/module/mobius-socket/config.js +15 -0
  273. package/dist/module/mobius-socket/errors.js +58 -0
  274. package/dist/module/mobius-socket/index.js +24 -0
  275. package/dist/module/mobius-socket/mobius-socket.js +593 -0
  276. package/dist/module/mobius-socket/socket/constants.js +26 -0
  277. package/dist/module/mobius-socket/socket/index.js +4 -0
  278. package/dist/module/mobius-socket/socket/socket-base.js +368 -0
  279. package/dist/module/mobius-socket/socket/socket.js +9 -0
  280. package/dist/module/mobius-socket/socket/socket.shim.js +12 -0
  281. package/dist/module/mobius-socket/socket/types.js +1 -0
  282. package/dist/module/mobius-socket/types.js +1 -0
  283. package/dist/types/CallHistory/CallHistory.d.ts.map +1 -1
  284. package/dist/types/CallRecording/CallRecording.d.ts +18 -0
  285. package/dist/types/CallRecording/CallRecording.d.ts.map +1 -0
  286. package/dist/types/CallRecording/WxcCallRecordingConnector.d.ts +23 -0
  287. package/dist/types/CallRecording/WxcCallRecordingConnector.d.ts.map +1 -0
  288. package/dist/types/CallRecording/callRecordingFixtures.d.ts +61 -0
  289. package/dist/types/CallRecording/callRecordingFixtures.d.ts.map +1 -0
  290. package/dist/types/CallRecording/constants.d.ts +29 -0
  291. package/dist/types/CallRecording/constants.d.ts.map +1 -0
  292. package/dist/types/CallRecording/types.d.ts +176 -0
  293. package/dist/types/CallRecording/types.d.ts.map +1 -0
  294. package/dist/types/CallRecording/utils.d.ts +3 -0
  295. package/dist/types/CallRecording/utils.d.ts.map +1 -0
  296. package/dist/types/CallingClient/CallingClient.d.ts +10 -1
  297. package/dist/types/CallingClient/CallingClient.d.ts.map +1 -1
  298. package/dist/types/CallingClient/calling/call.d.ts +17 -3
  299. package/dist/types/CallingClient/calling/call.d.ts.map +1 -1
  300. package/dist/types/CallingClient/calling/callManager.d.ts +8 -4
  301. package/dist/types/CallingClient/calling/callManager.d.ts.map +1 -1
  302. package/dist/types/CallingClient/calling/types.d.ts +38 -9
  303. package/dist/types/CallingClient/calling/types.d.ts.map +1 -1
  304. package/dist/types/CallingClient/constants.d.ts +29 -0
  305. package/dist/types/CallingClient/constants.d.ts.map +1 -1
  306. package/dist/types/CallingClient/line/index.d.ts +1 -1
  307. package/dist/types/CallingClient/line/index.d.ts.map +1 -1
  308. package/dist/types/CallingClient/registration/register.d.ts +10 -2
  309. package/dist/types/CallingClient/registration/register.d.ts.map +1 -1
  310. package/dist/types/CallingClient/registration/types.d.ts +29 -3
  311. package/dist/types/CallingClient/registration/types.d.ts.map +1 -1
  312. package/dist/types/CallingClient/registration/webWorker.d.ts.map +1 -1
  313. package/dist/types/CallingClient/registration/webWorkerStr.d.ts +1 -1
  314. package/dist/types/CallingClient/registration/webWorkerStr.d.ts.map +1 -1
  315. package/dist/types/CallingClient/types.d.ts +6 -3
  316. package/dist/types/CallingClient/types.d.ts.map +1 -1
  317. package/dist/types/CallingClient/utils/constants.d.ts +35 -0
  318. package/dist/types/CallingClient/utils/constants.d.ts.map +1 -0
  319. package/dist/types/CallingClient/utils/index.d.ts +6 -0
  320. package/dist/types/CallingClient/utils/index.d.ts.map +1 -0
  321. package/dist/types/CallingClient/utils/mobiusSocketMapper.d.ts +5 -0
  322. package/dist/types/CallingClient/utils/mobiusSocketMapper.d.ts.map +1 -0
  323. package/dist/types/CallingClient/utils/request.d.ts +28 -0
  324. package/dist/types/CallingClient/utils/request.d.ts.map +1 -0
  325. package/dist/types/CallingClient/utils/types.d.ts +34 -0
  326. package/dist/types/CallingClient/utils/types.d.ts.map +1 -0
  327. package/dist/types/CallingClient/utils/wsFeatureFlag.d.ts +4 -0
  328. package/dist/types/CallingClient/utils/wsFeatureFlag.d.ts.map +1 -0
  329. package/dist/types/Errors/types.d.ts +2 -0
  330. package/dist/types/Errors/types.d.ts.map +1 -1
  331. package/dist/types/Events/types.d.ts +80 -16
  332. package/dist/types/Events/types.d.ts.map +1 -1
  333. package/dist/types/Metrics/index.d.ts.map +1 -1
  334. package/dist/types/Metrics/types.d.ts +19 -2
  335. package/dist/types/Metrics/types.d.ts.map +1 -1
  336. package/dist/types/SDKConnector/types.d.ts +39 -12
  337. package/dist/types/SDKConnector/types.d.ts.map +1 -1
  338. package/dist/types/api.d.ts +6 -4
  339. package/dist/types/api.d.ts.map +1 -1
  340. package/dist/types/common/Utils.d.ts +9 -4
  341. package/dist/types/common/Utils.d.ts.map +1 -1
  342. package/dist/types/common/testUtil.d.ts +5 -1
  343. package/dist/types/common/testUtil.d.ts.map +1 -1
  344. package/dist/types/common/types.d.ts +9 -1
  345. package/dist/types/common/types.d.ts.map +1 -1
  346. package/dist/types/index.d.ts +9 -4
  347. package/dist/types/index.d.ts.map +1 -1
  348. package/dist/types/mobius-socket/config.d.ts +17 -0
  349. package/dist/types/mobius-socket/config.d.ts.map +1 -0
  350. package/dist/types/mobius-socket/errors.d.ts +32 -0
  351. package/dist/types/mobius-socket/errors.d.ts.map +1 -0
  352. package/dist/types/mobius-socket/index.d.ts +14 -0
  353. package/dist/types/mobius-socket/index.d.ts.map +1 -0
  354. package/dist/types/mobius-socket/mobius-socket.d.ts +48 -0
  355. package/dist/types/mobius-socket/mobius-socket.d.ts.map +1 -0
  356. package/dist/types/mobius-socket/socket/constants.d.ts +27 -0
  357. package/dist/types/mobius-socket/socket/constants.d.ts.map +1 -0
  358. package/dist/types/mobius-socket/socket/index.d.ts +5 -0
  359. package/dist/types/mobius-socket/socket/index.d.ts.map +1 -0
  360. package/dist/types/mobius-socket/socket/socket-base.d.ts +43 -0
  361. package/dist/types/mobius-socket/socket/socket-base.d.ts.map +1 -0
  362. package/dist/types/mobius-socket/socket/socket.d.ts +6 -0
  363. package/dist/types/mobius-socket/socket/socket.d.ts.map +1 -0
  364. package/dist/types/mobius-socket/socket/socket.shim.d.ts +6 -0
  365. package/dist/types/mobius-socket/socket/socket.shim.d.ts.map +1 -0
  366. package/dist/types/mobius-socket/socket/types.d.ts +61 -0
  367. package/dist/types/mobius-socket/socket/types.d.ts.map +1 -0
  368. package/dist/types/mobius-socket/types.d.ts +21 -0
  369. package/dist/types/mobius-socket/types.d.ts.map +1 -0
  370. package/package.json +21 -5
  371. package/src/mobius-socket/socket/socket.shim.ts +22 -0
  372. package/src/mobius-socket/socket/socket.ts +14 -0
@@ -0,0 +1,3970 @@
1
+ "use strict";
2
+
3
+ var _typeof = require("@babel/runtime-corejs2/helpers/typeof");
4
+ var _Object$keys2 = require("@babel/runtime-corejs2/core-js/object/keys");
5
+ var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
6
+ var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
7
+ var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
8
+ var _Object$defineProperties = require("@babel/runtime-corejs2/core-js/object/define-properties");
9
+ var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
10
+ var _WeakMap = require("@babel/runtime-corejs2/core-js/weak-map");
11
+ var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
12
+ var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
13
+ var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
14
+ var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
15
+ var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
16
+ var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
17
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
18
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
19
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
20
+ var InternalMediaCoreModule = _interopRequireWildcard(require("@webex/internal-media-core"));
21
+ var _mediaHelpers = require("@webex/media-helpers");
22
+ var _types = require("../../Errors/types");
23
+ var _Utils = _interopRequireWildcard(require("../../common/Utils"));
24
+ var Utils = _Utils;
25
+ var _types2 = require("../../Events/types");
26
+ var _constants = require("../constants");
27
+ var _types3 = require("../../common/types");
28
+ var _types4 = require("../../Metrics/types");
29
+ var _call = require("./call");
30
+ var _types5 = require("./types");
31
+ var _testUtil = require("../../common/testUtil");
32
+ var _callManager = require("./callManager");
33
+ var _Logger = _interopRequireDefault(require("../../Logger"));
34
+ var _Errors = require("../../Errors");
35
+ var _constants2 = require("../../common/constants");
36
+ var _request = require("../utils/request");
37
+ function _interopRequireWildcard(e, t) { if ("function" == typeof _WeakMap) var r = new _WeakMap(), n = new _WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t2 in e) "default" !== _t2 && {}.hasOwnProperty.call(e, _t2) && ((i = (o = _Object$defineProperty) && _Object$getOwnPropertyDescriptor(e, _t2)) && (i.get || i.set) ? o(f, _t2, i) : f[_t2] = e[_t2]); return f; })(e, t); }
38
+ function ownKeys(e, r) { var t = _Object$keys2(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
39
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; } /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable dot-notation */ /* eslint-disable @typescript-eslint/no-shadow */
40
+ jest.mock('../../mobius-socket', function () {
41
+ return {
42
+ getMobiusSocketInstance: jest.fn().mockReturnValue({
43
+ sendWssRequest: jest.fn()
44
+ })
45
+ };
46
+ });
47
+ jest.mock('@webex/internal-media-core');
48
+ var uploadLogsSpy = jest.spyOn(Utils, 'uploadLogs').mockResolvedValue(undefined);
49
+ var webex = (0, _testUtil.getTestUtilsWebex)();
50
+ var mockInternalMediaCoreModule = InternalMediaCoreModule;
51
+ var defaultServiceIndicator = _types3.ServiceIndicator.CALLING;
52
+ var activeUrl = 'FakeActiveUrl';
53
+ var mockLineId = 'e4e8ee2a-a154-4e52-8f11-ef4cde2dce72';
54
+ describe('Call Tests', function () {
55
+ var deviceId = '55dfb53f-bed2-36da-8e85-cee7f02aa68e';
56
+ var dest = {
57
+ type: _types3.CallType.URI,
58
+ address: 'tel:5003'
59
+ };
60
+ var dummyMidCallEvent = {
61
+ eventType: 'callInfo',
62
+ eventData: {
63
+ callerId: {
64
+ from: '"Bob Marley" <sip:5010@207.182.171.130;user=phone>;tag=888068389-1654853820619-'
65
+ }
66
+ }
67
+ };
68
+ var callManager;
69
+ var deleteCallFromCollection = jest.fn();
70
+ var disconnectStats = {
71
+ 'rtp-rxstat': {
72
+ Dur: 53.77999999999787,
73
+ LostPkt: 11,
74
+ LatePkt: 0,
75
+ Oct: 41156,
76
+ Pkt: 2379,
77
+ AvgJit: 0.041720656289440466,
78
+ VQMetrics: {
79
+ maxJitter: 0,
80
+ VoPktSizeMs: 20,
81
+ VoOneWayDelayMs: 0.26116666666666666,
82
+ hwType: 'OS X 10.15.7 64-bit/Chrome-105.0.0.0',
83
+ networkType: 'wifi',
84
+ VoRxCodec: 'opus'
85
+ }
86
+ },
87
+ 'rtp-txstat': {
88
+ Dur: 53.77999999999787,
89
+ Pkt: 2410,
90
+ Oct: 41156,
91
+ VQMetrics: {
92
+ VoTxCodec: 'opus',
93
+ rtpBitRate: 32000
94
+ }
95
+ }
96
+ };
97
+ var parseMediaQualityStatisticsMock = jest.spyOn(Utils, 'parseMediaQualityStatistics').mockReturnValue(disconnectStats);
98
+ var mockTrack = {
99
+ enabled: false
100
+ };
101
+ var mockEffect = {
102
+ isEnabled: true,
103
+ effectTrack: mockTrack,
104
+ on: jest.fn(),
105
+ off: jest.fn()
106
+ };
107
+ var roapMediaConnectionConfig = {
108
+ skipInactiveTransceivers: true,
109
+ iceServers: [],
110
+ iceCandidatesTimeout: _constants.ICE_CANDIDATES_TIMEOUT,
111
+ sdpMunging: {
112
+ convertPort9to0: true,
113
+ addContentSlides: false,
114
+ copyClineToSessionLevel: true
115
+ }
116
+ };
117
+ var roapMediaConnectionOptions = {
118
+ localTracks: {
119
+ audio: mockTrack
120
+ },
121
+ direction: {
122
+ audio: 'sendrecv',
123
+ video: 'inactive',
124
+ screenShareVideo: 'inactive'
125
+ }
126
+ };
127
+ afterEach(function () {
128
+ webex.request = jest.fn();
129
+ });
130
+ beforeEach(function () {
131
+ _request.APIRequest.resetInstance();
132
+ _request.APIRequest.getInstance({
133
+ webex: webex,
134
+ isMobiusSocketEnabled: false
135
+ });
136
+ callManager = (0, _callManager.getCallManager)(webex, defaultServiceIndicator);
137
+ });
138
+ it('create call object', function () {
139
+ webex.request.mockReturnValueOnce({
140
+ statusCode: 200,
141
+ body: {
142
+ device: {
143
+ deviceId: '8a67806f-fc4d-446b-a131-31e71ea5b010',
144
+ correlationId: '8a67806f-fc4d-446b-a131-31e71ea5b011'
145
+ },
146
+ callId: '8a67806f-fc4d-446b-a131-31e71ea5b020',
147
+ callData: {
148
+ callState: _types5.MobiusCallState.PROCEEDING
149
+ }
150
+ }
151
+ });
152
+ var call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
153
+ expect(call).toBeTruthy();
154
+ });
155
+ it('should log a warning when sending a digit fails', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee() {
156
+ var tone, errorMessage, mockMediaConnection, callManager, call, realMediaConnection, warnSpy, infoSpy;
157
+ return _regenerator.default.wrap(function (_context) {
158
+ while (1) switch (_context.prev = _context.next) {
159
+ case 0:
160
+ tone = '1';
161
+ errorMessage = 'Failed to send digit'; // Mock the mediaConnection object
162
+ mockMediaConnection = {
163
+ insertDTMF: jest.fn(function () {
164
+ throw new Error(errorMessage);
165
+ })
166
+ };
167
+ callManager = (0, _callManager.getCallManager)(webex, defaultServiceIndicator);
168
+ call = callManager.createCall(_types3.CallDirection.OUTBOUND, deviceId, mockLineId, dest);
169
+ realMediaConnection = call.mediaConnection; // Set the mock mediaConnection object
170
+ call.mediaConnection = mockMediaConnection;
171
+
172
+ // Spy on the log methods
173
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
174
+ infoSpy = jest.spyOn(_Logger.default, 'info'); // Call the sendDigit method
175
+ call.sendDigit(tone);
176
+
177
+ // Expect log.info to be called with the digit being sent
178
+ expect(infoSpy).toHaveBeenCalledWith("".concat(_constants2.METHOD_START_MESSAGE, " with: ").concat(tone), {
179
+ file: 'call',
180
+ method: 'sendDigit'
181
+ });
182
+
183
+ // Expect the log.warn method to be called with the error message
184
+ expect(warnSpy).toHaveBeenCalledWith("Unable to send digit on call: ".concat(errorMessage), {
185
+ file: 'call',
186
+ method: 'sendDigit'
187
+ });
188
+
189
+ // Restore the real mediaConnection object
190
+ call.mediaConnection = realMediaConnection;
191
+ call.end();
192
+ _context.next = 1;
193
+ return (0, _Utils.waitForMsecs)(50);
194
+ case 1:
195
+ // Need to add a small delay for Promise and callback to finish.
196
+
197
+ /* After call ends, call manager should have 0 record */
198
+ expect((0, _keys.default)(callManager.getActiveCalls()).length).toBe(0);
199
+ case 2:
200
+ case "end":
201
+ return _context.stop();
202
+ }
203
+ }, _callee);
204
+ })));
205
+ it('delete call object when ending the call', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee2() {
206
+ var callManager, mockStream, localAudioStream, call, infoSpy;
207
+ return _regenerator.default.wrap(function (_context2) {
208
+ while (1) switch (_context2.prev = _context2.next) {
209
+ case 0:
210
+ webex.request.mockReturnValue({
211
+ statusCode: 200,
212
+ body: {
213
+ device: {
214
+ deviceId: '8a67806f-fc4d-446b-a131-31e71ea5b010',
215
+ correlationId: '8a67806f-fc4d-446b-a131-31e71ea5b011'
216
+ },
217
+ callId: '8a67806f-fc4d-446b-a131-31e71ea5b020'
218
+ }
219
+ });
220
+ callManager = (0, _callManager.getCallManager)(webex, defaultServiceIndicator);
221
+ mockStream = {
222
+ on: jest.fn(),
223
+ setUserMuted: jest.fn()
224
+ };
225
+ localAudioStream = mockStream;
226
+ call = callManager.createCall(_types3.CallDirection.OUTBOUND, deviceId, mockLineId, dest);
227
+ infoSpy = jest.spyOn(_Logger.default, 'info');
228
+ expect(call).toBeTruthy();
229
+ /* After creation , call manager should have 1 record */
230
+ expect((0, _keys.default)(callManager.getActiveCalls()).length).toBe(1);
231
+ call.mute(localAudioStream);
232
+ expect(call.isMuted()).toEqual(true);
233
+ expect(mockStream.setUserMuted).toBeCalledOnceWith(true);
234
+ expect(infoSpy).toHaveBeenCalledWith('invoking with: user mute', {
235
+ file: 'call',
236
+ method: 'mute'
237
+ });
238
+ call.mute(localAudioStream);
239
+ expect(mockStream.setUserMuted).toBeCalledWith(false);
240
+ expect(call.isMuted()).toEqual(false);
241
+ call.end();
242
+ expect(infoSpy).toHaveBeenCalledWith(_constants2.METHOD_START_MESSAGE, {
243
+ file: 'call',
244
+ method: 'end'
245
+ });
246
+ _context2.next = 1;
247
+ return (0, _Utils.waitForMsecs)(50);
248
+ case 1:
249
+ // Need to add a small delay for Promise and callback to finish.
250
+ expect(parseMediaQualityStatisticsMock).toHaveBeenCalledTimes(1);
251
+ expect(webex.request.mock.calls[0][0].body.metrics).toStrictEqual(disconnectStats);
252
+ expect(call.getDisconnectReason().code).toBe(_types5.DisconnectCode.NORMAL);
253
+ expect(call.getDisconnectReason().cause).toBe(_types5.DisconnectCause.NORMAL);
254
+
255
+ /* After call ends, call manager should have 0 record */
256
+ expect((0, _keys.default)(callManager.getActiveCalls()).length).toBe(0);
257
+ case 2:
258
+ case "end":
259
+ return _context2.stop();
260
+ }
261
+ }, _callee2);
262
+ })));
263
+ it('Check whether media requests succeed or not', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee3() {
264
+ var mediaResponse, call, response;
265
+ return _regenerator.default.wrap(function (_context3) {
266
+ while (1) switch (_context3.prev = _context3.next) {
267
+ case 0:
268
+ webex.request.mockReturnValue({
269
+ statusCode: 200,
270
+ body: {
271
+ device: {
272
+ deviceId: '8a67806f-fc4d-446b-a131-31e71ea5b010',
273
+ correlationId: '8a67806f-fc4d-446b-a131-31e71ea5b011'
274
+ },
275
+ callId: '8a67806f-fc4d-446b-a131-31e71ea5b020'
276
+ }
277
+ });
278
+ mediaResponse = {
279
+ statusCode: 200,
280
+ body: {
281
+ device: {
282
+ deviceId: '8a67806f-fc4d-446b-a131-31e71ea5b010',
283
+ correlationId: '8a67806f-fc4d-446b-a131-31e71ea5b011'
284
+ },
285
+ callId: '8a67806f-fc4d-446b-a131-31e71ea5b020'
286
+ }
287
+ };
288
+ call = callManager.createCall(_types3.CallDirection.INBOUND, deviceId, mockLineId, dest);
289
+ _context3.next = 1;
290
+ return call['postMedia']({});
291
+ case 1:
292
+ response = _context3.sent;
293
+ expect(response.body).toStrictEqual(mediaResponse.body);
294
+ case 2:
295
+ case "end":
296
+ return _context3.stop();
297
+ }
298
+ }, _callee3);
299
+ })));
300
+ it('check whether callerId midcall event is serviced or not', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee4() {
301
+ var call;
302
+ return _regenerator.default.wrap(function (_context4) {
303
+ while (1) switch (_context4.prev = _context4.next) {
304
+ case 0:
305
+ call = callManager.createCall(_types3.CallDirection.OUTBOUND, deviceId, mockLineId, dest);
306
+ call.handleMidCallEvent(dummyMidCallEvent);
307
+ _context4.next = 1;
308
+ return (0, _Utils.waitForMsecs)(50);
309
+ case 1:
310
+ expect(call.getCallerInfo().name).toStrictEqual('Bob Marley');
311
+ expect(call.getCallerInfo().num).toStrictEqual('5010');
312
+ expect(call.getCallerInfo().avatarSrc).toBeFalsy();
313
+ case 2:
314
+ case "end":
315
+ return _context4.stop();
316
+ }
317
+ }, _callee4);
318
+ })));
319
+ it('check whether call midcall event is serviced or not', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee5() {
320
+ var call, logSpy, corelationId;
321
+ return _regenerator.default.wrap(function (_context5) {
322
+ while (1) switch (_context5.prev = _context5.next) {
323
+ case 0:
324
+ call = callManager.createCall(_types3.CallDirection.OUTBOUND, deviceId, mockLineId, dest);
325
+ dummyMidCallEvent.eventType = 'callState';
326
+ logSpy = jest.spyOn(_Logger.default, 'log');
327
+ call.handleMidCallEvent(dummyMidCallEvent);
328
+ _context5.next = 1;
329
+ return (0, _Utils.waitForMsecs)(50);
330
+ case 1:
331
+ corelationId = call.getCorrelationId();
332
+ expect(logSpy).toHaveBeenLastCalledWith("Received Midcall call event for correlationId : ".concat(corelationId), {
333
+ file: 'call',
334
+ method: 'handleMidCallEvent'
335
+ });
336
+ case 2:
337
+ case "end":
338
+ return _context5.stop();
339
+ }
340
+ }, _callee5);
341
+ })));
342
+ it('check call stats for active call', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee6() {
343
+ var call, callRtpStats, _t;
344
+ return _regenerator.default.wrap(function (_context6) {
345
+ while (1) switch (_context6.prev = _context6.next) {
346
+ case 0:
347
+ call = callManager.createCall(_types3.CallDirection.OUTBOUND, deviceId, mockLineId, dest);
348
+ _context6.prev = 1;
349
+ _context6.next = 2;
350
+ return call.getCallRtpStats();
351
+ case 2:
352
+ callRtpStats = _context6.sent;
353
+ _context6.next = 4;
354
+ break;
355
+ case 3:
356
+ _context6.prev = 3;
357
+ _t = _context6["catch"](1);
358
+ console.error(_t);
359
+ case 4:
360
+ expect(callRtpStats).toStrictEqual(disconnectStats);
361
+ case 5:
362
+ case "end":
363
+ return _context6.stop();
364
+ }
365
+ }, _callee6, null, [[1, 3]]);
366
+ })));
367
+ it('dial functionality tests for coverage', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee7() {
368
+ var mockStream, localAudioStream, warnSpy, call, bnrMetricSpy, logSpy;
369
+ return _regenerator.default.wrap(function (_context7) {
370
+ while (1) switch (_context7.prev = _context7.next) {
371
+ case 0:
372
+ mockStream = {
373
+ outputStream: {
374
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
375
+ },
376
+ on: jest.fn(),
377
+ getEffectByKind: jest.fn().mockImplementation(function () {
378
+ return mockEffect;
379
+ })
380
+ };
381
+ localAudioStream = mockStream;
382
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
383
+ call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
384
+ bnrMetricSpy = jest.spyOn(call['metricManager'], 'submitBNRMetric');
385
+ logSpy = jest.spyOn(_Logger.default, 'log');
386
+ call.dial(localAudioStream);
387
+ expect(mockTrack.enabled).toEqual(true);
388
+ expect(mockInternalMediaCoreModule.RoapMediaConnection).toBeCalledOnceWith(roapMediaConnectionConfig, roapMediaConnectionOptions, expect.any(String), expect.any(Function), expect.any(Function), expect.any(Function));
389
+ expect(call['mediaStateMachine'].state.value).toBe('S_SEND_ROAP_OFFER');
390
+ expect(logSpy).toHaveBeenCalled();
391
+ expect(bnrMetricSpy).toBeCalledOnceWith(_types4.METRIC_EVENT.BNR_ENABLED, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId());
392
+
393
+ /* Now change the state and recall to check for error */
394
+ call['mediaStateMachine'].state.value = 'S_SEND_ROAP_OFFER';
395
+ call.dial(localAudioStream);
396
+ expect(call['mediaStateMachine'].state.value).toBe('S_SEND_ROAP_OFFER');
397
+ expect(warnSpy).toBeCalledOnceWith("Call cannot be dialed because the state is already : S_SEND_ROAP_OFFER", {
398
+ file: 'call',
399
+ method: 'dial'
400
+ });
401
+ case 1:
402
+ case "end":
403
+ return _context7.stop();
404
+ }
405
+ }, _callee7);
406
+ })));
407
+ it('answer functionality tests for coverage', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee8() {
408
+ var mockStream, localAudioStream, warnSpy, call, bnrMetricSpy, infoSpy;
409
+ return _regenerator.default.wrap(function (_context8) {
410
+ while (1) switch (_context8.prev = _context8.next) {
411
+ case 0:
412
+ mockStream = {
413
+ outputStream: {
414
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
415
+ },
416
+ on: jest.fn(),
417
+ getEffectByKind: jest.fn().mockImplementation(function () {
418
+ return mockEffect;
419
+ })
420
+ };
421
+ localAudioStream = mockStream;
422
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
423
+ call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
424
+ /** Cannot answer in idle state */
425
+ bnrMetricSpy = jest.spyOn(call['metricManager'], 'submitBNRMetric');
426
+ infoSpy = jest.spyOn(_Logger.default, 'info');
427
+ call.answer(localAudioStream);
428
+ expect(mockTrack.enabled).toEqual(true);
429
+ expect(mockInternalMediaCoreModule.RoapMediaConnection).toBeCalledOnceWith(roapMediaConnectionConfig, roapMediaConnectionOptions, expect.any(String), expect.any(Function), expect.any(Function), expect.any(Function));
430
+ expect(call['callStateMachine'].state.value).toBe('S_IDLE');
431
+ expect(warnSpy).toBeCalledOnceWith("Call cannot be answered because the state is : S_IDLE", {
432
+ file: 'call',
433
+ method: 'answer'
434
+ });
435
+ expect(infoSpy).toHaveBeenCalled();
436
+
437
+ /* Now change the state and recall to check for correct flow */
438
+ call['callStateMachine'].state.value = 'S_SEND_CALL_PROGRESS';
439
+ call.answer(localAudioStream);
440
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_CONNECT');
441
+ expect(bnrMetricSpy).toBeCalledOnceWith(_types4.METRIC_EVENT.BNR_ENABLED, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId());
442
+ case 1:
443
+ case "end":
444
+ return _context8.stop();
445
+ }
446
+ }, _callee8);
447
+ })));
448
+ it('registers and unregisters media connection listeners with stable handlers', function () {
449
+ var mockStream = {
450
+ outputStream: {
451
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
452
+ },
453
+ on: jest.fn(),
454
+ getEffectByKind: jest.fn().mockReturnValue(undefined)
455
+ };
456
+ var localAudioStream = mockStream;
457
+ var call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
458
+ call.dial(localAudioStream);
459
+ var mediaOnMock = call['mediaConnection'].on;
460
+ var mediaOffSpy = jest.spyOn(call['mediaConnection'], 'off');
461
+ expect(mediaOnMock).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ROAP_MESSAGE_TO_SEND, expect.any(Function));
462
+ expect(mediaOnMock).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ROAP_FAILURE, expect.any(Function));
463
+ expect(mediaOnMock).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.REMOTE_TRACK_ADDED, expect.any(Function));
464
+ expect(mediaOnMock).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ICE_GATHERING_STATE_CHANGED, expect.any(Function));
465
+ expect(mediaOnMock).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.PEER_CONNECTION_STATE_CHANGED, expect.any(Function));
466
+ expect(mediaOnMock).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ICE_CONNECTION_STATE_CHANGED, expect.any(Function));
467
+ expect(mediaOnMock).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ICE_CANDIDATE_ERROR, expect.any(Function));
468
+ call['unregisterMediaConnectionListeners']();
469
+ expect(mediaOffSpy).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ROAP_MESSAGE_TO_SEND, expect.any(Function));
470
+ expect(mediaOffSpy).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ROAP_FAILURE, expect.any(Function));
471
+ expect(mediaOffSpy).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.REMOTE_TRACK_ADDED, expect.any(Function));
472
+ expect(mediaOffSpy).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ICE_GATHERING_STATE_CHANGED, expect.any(Function));
473
+ expect(mediaOffSpy).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.PEER_CONNECTION_STATE_CHANGED, expect.any(Function));
474
+ expect(mediaOffSpy).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ICE_CONNECTION_STATE_CHANGED, expect.any(Function));
475
+ expect(mediaOffSpy).toBeCalledWith(InternalMediaCoreModule.MediaConnectionEventNames.ICE_CANDIDATE_ERROR, expect.any(Function));
476
+ });
477
+ it('handles ICE listener payloads and submits metrics with event names', function () {
478
+ var mockStream = {
479
+ outputStream: {
480
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
481
+ },
482
+ on: jest.fn(),
483
+ getEffectByKind: jest.fn().mockReturnValue(undefined)
484
+ };
485
+ var localAudioStream = mockStream;
486
+ var call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
487
+ call.dial(localAudioStream);
488
+ var metricSpy = jest.spyOn(call['metricManager'], 'submitMediaMetric');
489
+ var warnSpy = jest.spyOn(_Logger.default, 'warn');
490
+ var getHandlerForEvent = function getHandlerForEvent(eventName) {
491
+ var _mock$calls$find;
492
+ return (_mock$calls$find = call['mediaConnection'].on.mock.calls.find(function (_ref9) {
493
+ var _ref0 = (0, _slicedToArray2.default)(_ref9, 1),
494
+ name = _ref0[0];
495
+ return name === eventName;
496
+ })) === null || _mock$calls$find === void 0 ? void 0 : _mock$calls$find[1];
497
+ };
498
+ var iceGatheringHandler = getHandlerForEvent(InternalMediaCoreModule.MediaConnectionEventNames.ICE_GATHERING_STATE_CHANGED);
499
+ var peerConnectionHandler = getHandlerForEvent(InternalMediaCoreModule.MediaConnectionEventNames.PEER_CONNECTION_STATE_CHANGED);
500
+ var iceConnectionHandler = getHandlerForEvent(InternalMediaCoreModule.MediaConnectionEventNames.ICE_CONNECTION_STATE_CHANGED);
501
+ var iceCandidateErrorHandler = getHandlerForEvent(InternalMediaCoreModule.MediaConnectionEventNames.ICE_CANDIDATE_ERROR);
502
+ iceGatheringHandler({
503
+ iceGatheringState: 'gathering'
504
+ });
505
+ peerConnectionHandler({
506
+ connectionState: 'connected'
507
+ });
508
+ iceConnectionHandler({
509
+ iceConnectionState: 'completed'
510
+ });
511
+ iceCandidateErrorHandler({
512
+ errorCode: 701,
513
+ errorText: 'STUN host lookup failed',
514
+ url: 'stun:example.org:3478'
515
+ });
516
+ expect(metricSpy).toHaveBeenNthCalledWith(1, _types4.METRIC_EVENT.MEDIA, _types4.MEDIA_CONNECTION_ACTION.ICE_GATHERING_STATE_CHANGED, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId(), undefined, undefined, 'gathering');
517
+ expect(metricSpy).toHaveBeenNthCalledWith(2, _types4.METRIC_EVENT.MEDIA, _types4.MEDIA_CONNECTION_ACTION.PEER_CONNECTION_STATE_CHANGED, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId(), undefined, undefined, 'connected');
518
+ expect(metricSpy).toHaveBeenNthCalledWith(3, _types4.METRIC_EVENT.MEDIA, _types4.MEDIA_CONNECTION_ACTION.ICE_CONNECTION_STATE_CHANGED, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId(), undefined, undefined, 'completed');
519
+ expect(metricSpy).toHaveBeenNthCalledWith(4, _types4.METRIC_EVENT.MEDIA_ERROR, _types4.MEDIA_CONNECTION_ACTION.ICE_CANDIDATE_ERROR, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId(), undefined, undefined, undefined, expect.any(_Errors.CallError));
520
+ var mediaErrorCall = metricSpy.mock.calls[3];
521
+ expect(mediaErrorCall[mediaErrorCall.length - 1].getCallError().message).toBe('ICE candidate error occurred: {"address":null,"errorCode":701,"errorText":"STUN host lookup failed","port":null,"url":"stun:example.org:3478"}');
522
+ expect(warnSpy).toHaveBeenCalledWith('ICE candidate error occurred: {"address":null,"errorCode":701,"errorText":"STUN host lookup failed","port":null,"url":"stun:example.org:3478"}', {
523
+ file: 'call',
524
+ method: 'mediaIceEventsListener'
525
+ });
526
+ });
527
+ it('handles ROAP failure listener and submits media error metric', function () {
528
+ var _mock$calls$find2;
529
+ var mockStream = {
530
+ outputStream: {
531
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
532
+ },
533
+ on: jest.fn(),
534
+ getEffectByKind: jest.fn().mockReturnValue(undefined)
535
+ };
536
+ var localAudioStream = mockStream;
537
+ var call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
538
+ call.dial(localAudioStream);
539
+ var metricSpy = jest.spyOn(call['metricManager'], 'submitMediaMetric');
540
+ var warnSpy = jest.spyOn(_Logger.default, 'warn');
541
+ var roapFailureHandler = (_mock$calls$find2 = call['mediaConnection'].on.mock.calls.find(function (_ref1) {
542
+ var _ref10 = (0, _slicedToArray2.default)(_ref1, 1),
543
+ name = _ref10[0];
544
+ return name === InternalMediaCoreModule.MediaConnectionEventNames.ROAP_FAILURE;
545
+ })) === null || _mock$calls$find2 === void 0 ? void 0 : _mock$calls$find2[1];
546
+ var roapFailure = new Error('Failed to process remote SDP');
547
+ roapFailureHandler(roapFailure);
548
+ expect(metricSpy).toHaveBeenCalledWith(_types4.METRIC_EVENT.MEDIA_ERROR, _types4.MEDIA_CONNECTION_ACTION.ROAP_FAILURE, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId(), undefined, undefined, undefined, expect.any(_Errors.CallError));
549
+ var roapFailureMetricCall = metricSpy.mock.calls.find(function (_ref11) {
550
+ var _ref12 = (0, _slicedToArray2.default)(_ref11, 2),
551
+ name = _ref12[0],
552
+ metricAction = _ref12[1];
553
+ return name === _types4.METRIC_EVENT.MEDIA_ERROR && metricAction === _types4.MEDIA_CONNECTION_ACTION.ROAP_FAILURE;
554
+ });
555
+ expect(roapFailureMetricCall).toBeDefined();
556
+ expect((roapFailureMetricCall === null || roapFailureMetricCall === void 0 ? void 0 : roapFailureMetricCall[roapFailureMetricCall.length - 1]).getCallError().message).toBe('ROAP failure occurred: Failed to process remote SDP');
557
+ expect(warnSpy).toHaveBeenCalledWith('ROAP failure occurred: Failed to process remote SDP', {
558
+ file: 'call',
559
+ method: 'mediaRoapEventsListener'
560
+ });
561
+ });
562
+ it('sends connect before ROAP answer when inbound offer is delayed', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee9() {
563
+ var _mock$calls$find3;
564
+ var mockStream, localAudioStream, call, handleOutgoingCallConnectSpy, delayedOffer, sendCallStateMachineEvtSpy, sendMediaStateMachineEvtSpy, roapListener;
565
+ return _regenerator.default.wrap(function (_context9) {
566
+ while (1) switch (_context9.prev = _context9.next) {
567
+ case 0:
568
+ mockStream = {
569
+ outputStream: {
570
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
571
+ },
572
+ on: jest.fn(),
573
+ getEffectByKind: jest.fn().mockImplementation(function () {
574
+ return mockEffect;
575
+ })
576
+ };
577
+ localAudioStream = mockStream;
578
+ call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.INBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
579
+ webex.request.mockReturnValue({
580
+ statusCode: 200,
581
+ body: {
582
+ callId: 'mock-call-id'
583
+ }
584
+ });
585
+ call.sendCallStateMachineEvt({
586
+ type: 'E_RECV_CALL_SETUP',
587
+ data: {
588
+ seq: 1,
589
+ messageType: 'OFFER'
590
+ }
591
+ });
592
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_PROGRESS');
593
+ _context9.next = 1;
594
+ return call.answer(localAudioStream);
595
+ case 1:
596
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_CONNECT');
597
+
598
+ // Connect is attempted by answer(), but is deferred because offer is not buffered yet.
599
+ handleOutgoingCallConnectSpy = jest.spyOn(call, 'handleOutgoingCallConnect');
600
+ expect(call['connectPending']).toBe(true);
601
+ expect(call['mediaConnection'].roapMessageReceived).not.toHaveBeenCalled();
602
+ delayedOffer = {
603
+ seq: 1,
604
+ messageType: 'OFFER',
605
+ sdp: 'v=0',
606
+ version: 1
607
+ };
608
+ call.sendMediaStateMachineEvt({
609
+ type: 'E_RECV_ROAP_OFFER',
610
+ data: delayedOffer
611
+ });
612
+ _context9.next = 2;
613
+ return (0, _testUtil.flushPromises)(2);
614
+ case 2:
615
+ expect(call['mediaConnection'].roapMessageReceived).toHaveBeenCalledWith(delayedOffer);
616
+ sendCallStateMachineEvtSpy = jest.spyOn(call, 'sendCallStateMachineEvt');
617
+ sendMediaStateMachineEvtSpy = jest.spyOn(call, 'sendMediaStateMachineEvt');
618
+ roapListener = (_mock$calls$find3 = call['mediaConnection'].on.mock.calls.find(function (_ref14) {
619
+ var _ref15 = (0, _slicedToArray2.default)(_ref14, 1),
620
+ eventName = _ref15[0];
621
+ return eventName === InternalMediaCoreModule.MediaConnectionEventNames.ROAP_MESSAGE_TO_SEND;
622
+ })) === null || _mock$calls$find3 === void 0 ? void 0 : _mock$calls$find3[1];
623
+ expect(roapListener).toBeDefined();
624
+ _context9.next = 3;
625
+ return roapListener({
626
+ roapMessage: {
627
+ messageType: 'ANSWER',
628
+ sdp: 'v=0',
629
+ seq: 1,
630
+ version: 2
631
+ }
632
+ });
633
+ case 3:
634
+ _context9.next = 4;
635
+ return (0, _testUtil.flushPromises)(2);
636
+ case 4:
637
+ // On ANSWER from media layer, connect is retried first, then ROAP answer is posted.
638
+ expect(sendCallStateMachineEvtSpy).toHaveBeenNthCalledWith(1, {
639
+ type: 'E_SEND_CALL_CONNECT'
640
+ });
641
+ expect(sendMediaStateMachineEvtSpy).toHaveBeenNthCalledWith(1, {
642
+ type: 'E_SEND_ROAP_ANSWER',
643
+ data: expect.objectContaining({
644
+ messageType: 'ANSWER'
645
+ })
646
+ });
647
+ expect(handleOutgoingCallConnectSpy).toHaveBeenCalled();
648
+ expect(call['mediaConnection'].roapMessageReceived).toHaveBeenLastCalledWith(delayedOffer);
649
+ expect(call['connectPending']).toBe(false);
650
+ case 5:
651
+ case "end":
652
+ return _context9.stop();
653
+ }
654
+ }, _callee9);
655
+ })));
656
+ var iceLiteOfferSdp = 'v=0\r\no=- 0 0 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n' + 'a=ice-lite\r\nm=audio 19564 UDP/TLS/RTP/SAVPF 0\r\na=sendrecv\r\n';
657
+ var fullIceOfferSdp = 'v=0\r\no=- 0 0 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n' + 'm=audio 19564 UDP/TLS/RTP/SAVPF 0\r\na=sendrecv\r\na=ice-ufrag:mLbW\r\n';
658
+ describe.each([{
659
+ name: 'reduced timeout when the offer is ice-lite and reduceTimeoutForIceLite is enabled',
660
+ sdp: iceLiteOfferSdp,
661
+ iceGatheringConfig: {
662
+ reduceTimeoutForIceLite: true
663
+ },
664
+ expectedTimeout: _constants.ICE_LITE_CANDIDATES_TIMEOUT
665
+ }, {
666
+ name: 'custom reduced timeout when the offer is ice-lite and iceLiteTimeout is overridden',
667
+ sdp: iceLiteOfferSdp,
668
+ iceGatheringConfig: {
669
+ reduceTimeoutForIceLite: true,
670
+ iceLiteTimeout: 750
671
+ },
672
+ expectedTimeout: 750
673
+ }, {
674
+ name: 'default timeout when the offer is ice-lite but reduceTimeoutForIceLite is disabled',
675
+ sdp: iceLiteOfferSdp,
676
+ iceGatheringConfig: {
677
+ reduceTimeoutForIceLite: false
678
+ },
679
+ expectedTimeout: _constants.ICE_CANDIDATES_TIMEOUT
680
+ }, {
681
+ name: 'default timeout when the offer is ice-lite but no iceGathering config is provided',
682
+ sdp: iceLiteOfferSdp,
683
+ iceGatheringConfig: undefined,
684
+ expectedTimeout: _constants.ICE_CANDIDATES_TIMEOUT
685
+ }, {
686
+ name: 'default timeout when reduceTimeoutForIceLite is enabled but the offer is not ice-lite',
687
+ sdp: fullIceOfferSdp,
688
+ iceGatheringConfig: {
689
+ reduceTimeoutForIceLite: true
690
+ },
691
+ expectedTimeout: _constants.ICE_CANDIDATES_TIMEOUT
692
+ }])('ICE candidates timeout selection', function (_ref16) {
693
+ var name = _ref16.name,
694
+ sdp = _ref16.sdp,
695
+ iceGatheringConfig = _ref16.iceGatheringConfig,
696
+ expectedTimeout = _ref16.expectedTimeout;
697
+ it("uses ".concat(name), /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee0() {
698
+ var mockStream, localAudioStream, call;
699
+ return _regenerator.default.wrap(function (_context0) {
700
+ while (1) switch (_context0.prev = _context0.next) {
701
+ case 0:
702
+ mockStream = {
703
+ outputStream: {
704
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
705
+ },
706
+ on: jest.fn(),
707
+ getEffectByKind: jest.fn().mockImplementation(function () {
708
+ return mockEffect;
709
+ })
710
+ };
711
+ localAudioStream = mockStream;
712
+ call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.INBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest, iceGatheringConfig);
713
+ webex.request.mockReturnValue({
714
+ statusCode: 200,
715
+ body: {
716
+ callId: 'mock-call-id'
717
+ }
718
+ });
719
+
720
+ /* Buffer the remote offer before answering so it is available at media connection init. */
721
+ call.sendMediaStateMachineEvt({
722
+ type: 'E_RECV_ROAP_OFFER',
723
+ data: {
724
+ seq: 1,
725
+ messageType: 'OFFER',
726
+ version: 1,
727
+ sdp: sdp
728
+ }
729
+ });
730
+ _context0.next = 1;
731
+ return call.answer(localAudioStream);
732
+ case 1:
733
+ expect(mockInternalMediaCoreModule.RoapMediaConnection).toBeCalledOnceWith(_objectSpread(_objectSpread({}, roapMediaConnectionConfig), {}, {
734
+ iceCandidatesTimeout: expectedTimeout
735
+ }), roapMediaConnectionOptions, expect.any(String), expect.any(Function), expect.any(Function), expect.any(Function));
736
+ case 2:
737
+ case "end":
738
+ return _context0.stop();
739
+ }
740
+ }, _callee0);
741
+ })));
742
+ });
743
+ it('testing enabling/disabling the BNR on an active call', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee1() {
744
+ var mockStream, localAudioStream, onStreamSpy, onEffectSpy, offStreamSpy, offEffectSpy, call, updateLocalTracksSpy, bnrMetricSpy;
745
+ return _regenerator.default.wrap(function (_context1) {
746
+ while (1) switch (_context1.prev = _context1.next) {
747
+ case 0:
748
+ mockStream = {
749
+ outputStream: {
750
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
751
+ },
752
+ on: jest.fn(),
753
+ off: jest.fn(),
754
+ getEffectByKind: jest.fn()
755
+ };
756
+ localAudioStream = mockStream;
757
+ onStreamSpy = jest.spyOn(localAudioStream, 'on');
758
+ onEffectSpy = jest.spyOn(mockEffect, 'on');
759
+ offStreamSpy = jest.spyOn(localAudioStream, 'off');
760
+ offEffectSpy = jest.spyOn(mockEffect, 'off');
761
+ call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
762
+ call.dial(localAudioStream);
763
+ expect(mockTrack.enabled).toEqual(true);
764
+ expect(mockInternalMediaCoreModule.RoapMediaConnection).toBeCalledOnceWith(roapMediaConnectionConfig, roapMediaConnectionOptions, expect.any(String), expect.any(Function), expect.any(Function), expect.any(Function));
765
+ expect(call['mediaStateMachine'].state.value).toBe('S_SEND_ROAP_OFFER');
766
+ updateLocalTracksSpy = jest.spyOn(call['mediaConnection'], 'updateLocalTracks');
767
+ bnrMetricSpy = jest.spyOn(call['metricManager'], 'submitBNRMetric');
768
+ /* Update the stream with the effect */
769
+ jest.spyOn(localAudioStream, 'getEffectByKind').mockReturnValue(mockEffect);
770
+
771
+ /* Checking if listeners on the localAudioStream have been registered */
772
+ expect(onStreamSpy).toBeCalledTimes(2);
773
+ expect(onStreamSpy).toBeCalledWith(InternalMediaCoreModule.LocalStreamEventNames.OutputTrackChange, expect.any(Function));
774
+ expect(onStreamSpy).toBeCalledWith(InternalMediaCoreModule.LocalStreamEventNames.EffectAdded, expect.any(Function));
775
+ bnrMetricSpy.mockClear();
776
+ /* Invoking the callback function to trigger EffectAdded event to simulate adding effect to the stream */
777
+ onStreamSpy.mock.calls[1][1](mockEffect);
778
+ expect(onEffectSpy).toBeCalledWith(_mediaHelpers.EffectEvent.Enabled, expect.any(Function));
779
+ expect(onEffectSpy).toBeCalledWith(_mediaHelpers.EffectEvent.Disabled, expect.any(Function));
780
+
781
+ /* Send Enabled event on the effect, update track and send metrics for BNR disabled */
782
+ onStreamSpy.mock.calls[0][1](mockTrack);
783
+ onEffectSpy.mock.calls[0][1]();
784
+ expect(updateLocalTracksSpy).toBeCalledOnceWith({
785
+ audio: mockTrack
786
+ });
787
+ expect(bnrMetricSpy).toBeCalledOnceWith(_types4.METRIC_EVENT.BNR_ENABLED, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId());
788
+
789
+ /* Clear the mocks */
790
+ updateLocalTracksSpy.mockClear();
791
+ bnrMetricSpy.mockClear();
792
+
793
+ /* Send Disabled event on the effect, update track and send metrics for BNR disabled */
794
+ mockEffect.isEnabled = false;
795
+ onStreamSpy.mock.calls[0][1](mockTrack);
796
+ onEffectSpy.mock.calls[1][1]();
797
+ expect(updateLocalTracksSpy).toBeCalledOnceWith({
798
+ audio: mockTrack
799
+ });
800
+ expect(bnrMetricSpy).toBeCalledOnceWith(_types4.METRIC_EVENT.BNR_DISABLED, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId());
801
+ call.end();
802
+ _context1.next = 1;
803
+ return (0, _Utils.waitForMsecs)(50);
804
+ case 1:
805
+ /* Checks for switching off the listeners on call disconnect */
806
+ expect(offStreamSpy).toBeCalledTimes(2);
807
+ expect(offStreamSpy).toBeCalledWith(InternalMediaCoreModule.LocalStreamEventNames.OutputTrackChange, expect.any(Function));
808
+ expect(offStreamSpy).toBeCalledWith(InternalMediaCoreModule.LocalStreamEventNames.EffectAdded, expect.any(Function));
809
+ expect(offEffectSpy).toBeCalledWith(_mediaHelpers.EffectEvent.Enabled, expect.any(Function));
810
+ expect(offEffectSpy).toBeCalledWith(_mediaHelpers.EffectEvent.Disabled, expect.any(Function));
811
+ case 2:
812
+ case "end":
813
+ return _context1.stop();
814
+ }
815
+ }, _callee1);
816
+ })));
817
+ it('does not register effect listeners when the added effect cannot be resolved', function () {
818
+ var mockStream = {
819
+ outputStream: {
820
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
821
+ },
822
+ on: jest.fn(),
823
+ getEffectByKind: jest.fn().mockReturnValue(undefined)
824
+ };
825
+ var localAudioStream = mockStream;
826
+ var onStreamSpy = jest.spyOn(localAudioStream, 'on');
827
+ var onEffectSpy = jest.spyOn(mockEffect, 'on');
828
+ var call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
829
+ call.dial(localAudioStream);
830
+ expect(function () {
831
+ return onStreamSpy.mock.calls[1][1](undefined);
832
+ }).not.toThrow();
833
+ expect(onEffectSpy).not.toHaveBeenCalled();
834
+ });
835
+ it('answer fails if localAudioTrack is empty', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee10() {
836
+ var mockStream, localAudioStream, warnSpy, call;
837
+ return _regenerator.default.wrap(function (_context10) {
838
+ while (1) switch (_context10.prev = _context10.next) {
839
+ case 0:
840
+ mockStream = {
841
+ outputStream: {
842
+ getAudioTracks: jest.fn().mockReturnValue([])
843
+ },
844
+ on: jest.fn(),
845
+ off: jest.fn(),
846
+ getEffectByKind: jest.fn()
847
+ };
848
+ localAudioStream = mockStream;
849
+ webex.request.mockReturnValue({
850
+ statusCode: 200,
851
+ body: {
852
+ device: {
853
+ deviceId: '8a67806f-fc4d-446b-a131-31e71ea5b010',
854
+ correlationId: '8a67806f-fc4d-446b-a131-31e71ea5b011'
855
+ },
856
+ callId: '8a67806f-fc4d-446b-a131-31e71ea5b020'
857
+ }
858
+ });
859
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
860
+ call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
861
+ call.answer(localAudioStream);
862
+ _context10.next = 1;
863
+ return (0, _Utils.waitForMsecs)(50);
864
+ case 1:
865
+ expect(warnSpy).toBeCalledTimes(2);
866
+ expect(warnSpy).toBeCalledWith("Did not find a local track while answering the call ".concat(call.getCorrelationId()), {
867
+ file: 'call',
868
+ method: 'answer'
869
+ });
870
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_CLEARED');
871
+ expect(call['mediaStateMachine'].state.value).toBe('S_ROAP_IDLE');
872
+ expect(call.getDisconnectReason().code).toBe(_types5.DisconnectCode.MEDIA_INACTIVITY);
873
+ expect(call.getDisconnectReason().cause).toBe(_types5.DisconnectCause.MEDIA_INACTIVITY);
874
+ expect(webex.request.mock.calls[0][0].body.metrics).toStrictEqual(disconnectStats);
875
+ case 2:
876
+ case "end":
877
+ return _context10.stop();
878
+ }
879
+ }, _callee10);
880
+ })));
881
+ it('dial fails if localAudioTrack is empty', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee11() {
882
+ var mockStream, localAudioStream, warnSpy, call;
883
+ return _regenerator.default.wrap(function (_context11) {
884
+ while (1) switch (_context11.prev = _context11.next) {
885
+ case 0:
886
+ mockStream = {
887
+ outputStream: {
888
+ getAudioTracks: jest.fn().mockReturnValue([])
889
+ },
890
+ on: jest.fn()
891
+ };
892
+ localAudioStream = mockStream;
893
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
894
+ call = (0, _call.createCall)(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, deleteCallFromCollection, defaultServiceIndicator, dest);
895
+ call.dial(localAudioStream);
896
+ _context11.next = 1;
897
+ return (0, _Utils.waitForMsecs)(50);
898
+ case 1:
899
+ expect(warnSpy).toBeCalledTimes(1);
900
+ expect(warnSpy).toBeCalledWith("Did not find a local track while dialing the call ".concat(call.getCorrelationId()), {
901
+ file: 'call',
902
+ method: 'dial'
903
+ });
904
+ expect(call['callStateMachine'].state.value).toBe('S_IDLE');
905
+ expect(call['mediaStateMachine'].state.value).toBe('S_ROAP_IDLE');
906
+ expect(webex.request).not.toBeCalledOnceWith();
907
+ case 2:
908
+ case "end":
909
+ return _context11.stop();
910
+ }
911
+ }, _callee11);
912
+ })));
913
+ it('update media after call creation with valid stream', function () {
914
+ var callManager = (0, _callManager.getCallManager)(webex, defaultServiceIndicator);
915
+ var mockStream = {
916
+ outputStream: {
917
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
918
+ },
919
+ on: jest.fn(),
920
+ off: jest.fn(),
921
+ getEffectByKind: jest.fn()
922
+ };
923
+ var localAudioStream = mockStream;
924
+ var onStream1Spy = jest.spyOn(localAudioStream, 'on');
925
+ var offStream1Spy = jest.spyOn(localAudioStream, 'off');
926
+ var call = callManager.createCall(_types3.CallDirection.OUTBOUND, deviceId, mockLineId, dest);
927
+ call.dial(localAudioStream);
928
+ expect(mockTrack.enabled).toEqual(true);
929
+ expect(onStream1Spy).toBeCalledTimes(2);
930
+ expect(onStream1Spy).toBeCalledWith(InternalMediaCoreModule.LocalStreamEventNames.OutputTrackChange, expect.any(Function));
931
+ expect(onStream1Spy).toBeCalledWith(InternalMediaCoreModule.LocalStreamEventNames.EffectAdded, expect.any(Function));
932
+ var mockTrack2 = {
933
+ enabled: true
934
+ };
935
+ var mockStream2 = {
936
+ outputStream: {
937
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack2])
938
+ },
939
+ on: jest.fn(),
940
+ getEffectByKind: jest.fn()
941
+ };
942
+ var localAudioStream2 = mockStream2;
943
+ var onStream2Spy = jest.spyOn(localAudioStream2, 'on');
944
+ call.updateMedia(localAudioStream2);
945
+ expect(call['mediaConnection'].updateLocalTracks).toBeCalledOnceWith({
946
+ audio: mockTrack2
947
+ });
948
+ expect(call['localAudioStream']).toEqual(localAudioStream2);
949
+ expect(offStream1Spy).toBeCalledWith(InternalMediaCoreModule.LocalStreamEventNames.EffectAdded, expect.any(Function));
950
+ expect(onStream2Spy).toBeCalledWith(InternalMediaCoreModule.LocalStreamEventNames.OutputTrackChange, expect.any(Function));
951
+ expect(onStream2Spy).toBeCalledWith(InternalMediaCoreModule.LocalStreamEventNames.EffectAdded, expect.any(Function));
952
+ });
953
+ it('update media with invalid stream', function () {
954
+ var callManager = (0, _callManager.getCallManager)(webex, defaultServiceIndicator);
955
+ var warnSpy = jest.spyOn(_Logger.default, 'warn');
956
+ var infoSpy = jest.spyOn(_Logger.default, 'info');
957
+ var mockStream = {
958
+ outputStream: {
959
+ getAudioTracks: jest.fn().mockReturnValue([mockTrack])
960
+ },
961
+ on: jest.fn(),
962
+ getEffectByKind: jest.fn()
963
+ };
964
+ var localAudioStream = mockStream;
965
+ var call = callManager.createCall(_types3.CallDirection.OUTBOUND, deviceId, mockLineId, dest);
966
+ call.dial(localAudioStream);
967
+ expect(mockTrack.enabled).toEqual(true);
968
+ var errorStream = {
969
+ outputStream: {
970
+ getAudioTracks: jest.fn().mockReturnValue([])
971
+ }
972
+ };
973
+ var localAudioStream2 = errorStream;
974
+ call.updateMedia(localAudioStream2);
975
+ expect(call['mediaConnection'].updateLocalTracks).not.toBeCalled();
976
+ expect(warnSpy).toHaveBeenCalledWith("Did not find a local track while updating media for call ".concat(call.getCorrelationId(), ". Will not update media"), {
977
+ file: 'call',
978
+ method: 'updateMedia'
979
+ });
980
+ expect(infoSpy).toHaveBeenCalledWith('invoking with stream', {
981
+ file: 'call',
982
+ method: 'dial'
983
+ });
984
+ });
985
+ it('test system mute and user mute different scnearios', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee12() {
986
+ var logSpy, callManager, mockStream, localAudioStream, call;
987
+ return _regenerator.default.wrap(function (_context12) {
988
+ while (1) switch (_context12.prev = _context12.next) {
989
+ case 0:
990
+ logSpy = jest.spyOn(_Logger.default, 'info');
991
+ webex.request.mockReturnValue({
992
+ statusCode: 200,
993
+ body: {
994
+ device: {
995
+ deviceId: '8a67806f-fc4d-446b-a131-31e71ea5b010',
996
+ correlationId: '8a67806f-fc4d-446b-a131-31e71ea5b011'
997
+ },
998
+ callId: '8a67806f-fc4d-446b-a131-31e71ea5b020'
999
+ }
1000
+ });
1001
+ callManager = (0, _callManager.getCallManager)(webex, defaultServiceIndicator);
1002
+ mockStream = {
1003
+ on: jest.fn(),
1004
+ setUserMuted: jest.fn(),
1005
+ systemMuted: false,
1006
+ userMuted: false
1007
+ };
1008
+ localAudioStream = mockStream;
1009
+ call = callManager.createCall(dest, _types3.CallDirection.OUTBOUND, deviceId, mockLineId);
1010
+ expect(call).toBeTruthy();
1011
+ /* System mute is being triggered, mute state within call object should update to true */
1012
+ mockStream.systemMuted = true;
1013
+ call.mute(localAudioStream, _types5.MUTE_TYPE.SYSTEM);
1014
+ expect(call.isMuted()).toEqual(true);
1015
+
1016
+ /* User mute is triggered, but no change will happen to the call object mute state since it is system muted */
1017
+ logSpy.mockClear();
1018
+ call.mute(localAudioStream, _types5.MUTE_TYPE.USER);
1019
+ expect(call.isMuted()).toEqual(true);
1020
+ expect(mockStream.setUserMuted).not.toBeCalledOnceWith(true);
1021
+ expect(logSpy).toHaveBeenCalledWith("Call is muted on the system - ".concat(call.getCorrelationId(), "."), {
1022
+ file: 'call',
1023
+ method: 'mute'
1024
+ });
1025
+
1026
+ /* System mute is being triggered, mute state within call object should update to false */
1027
+ mockStream.systemMuted = false;
1028
+ call.mute(localAudioStream, _types5.MUTE_TYPE.SYSTEM);
1029
+ expect(call.isMuted()).toEqual(false);
1030
+
1031
+ /* User mute can be triggered now updating call object mute state as well */
1032
+ call.mute(localAudioStream, _types5.MUTE_TYPE.USER);
1033
+ expect(call.isMuted()).toEqual(true);
1034
+ expect(mockStream.setUserMuted).toBeCalledOnceWith(true);
1035
+ mockStream.userMuted = true;
1036
+
1037
+ /* System mute being triggered now won't update the mute state within call object but will block the user unmute */
1038
+ logSpy.mockClear();
1039
+ mockStream.systemMuted = true;
1040
+ call.mute(localAudioStream, _types5.MUTE_TYPE.SYSTEM);
1041
+ expect(call.isMuted()).toEqual(true);
1042
+ expect(logSpy).toHaveBeenCalledWith("Call is muted by the user already - ".concat(call.getCorrelationId(), "."), {
1043
+ file: 'call',
1044
+ method: 'mute'
1045
+ });
1046
+
1047
+ /* User mute now won't be able to update mute state back to false as system mute is also set */
1048
+ call.mute(localAudioStream, _types5.MUTE_TYPE.USER);
1049
+ expect(call.isMuted()).toEqual(true);
1050
+ expect(mockStream.setUserMuted).not.toBeCalledOnceWith(false);
1051
+
1052
+ /* Revert the system mute but call mute state remains same */
1053
+ mockStream.systemMuted = false;
1054
+ call.mute(localAudioStream, _types5.MUTE_TYPE.SYSTEM);
1055
+ expect(call.isMuted()).toEqual(true);
1056
+
1057
+ /* User mute will be able update the mute state now */
1058
+ mockStream.setUserMuted.mockClear();
1059
+ call.mute(localAudioStream, _types5.MUTE_TYPE.USER);
1060
+ expect(call.isMuted()).toEqual(false);
1061
+ expect(mockStream.setUserMuted).toBeCalledOnceWith(false);
1062
+ case 1:
1063
+ case "end":
1064
+ return _context12.stop();
1065
+ }
1066
+ }, _callee12);
1067
+ })));
1068
+ describe('Guest Calling Flow Tests', function () {
1069
+ var dummyEvent = {
1070
+ type: 'E_SEND_CALL_SETUP',
1071
+ data: undefined
1072
+ };
1073
+ var call;
1074
+ it('outgoing call without guest calling must have callee', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee13() {
1075
+ var requestSpy, requestArgs;
1076
+ return _regenerator.default.wrap(function (_context13) {
1077
+ while (1) switch (_context13.prev = _context13.next) {
1078
+ case 0:
1079
+ call = new _call.Call(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, function () {
1080
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1081
+ var dummy = 10;
1082
+ }, defaultServiceIndicator, dest);
1083
+ call['callStateMachine'].state.value = 'S_IDLE';
1084
+ requestSpy = jest.spyOn(webex, 'request');
1085
+ call.sendCallStateMachineEvt(dummyEvent);
1086
+ requestArgs = requestSpy.mock.calls[0][0];
1087
+ expect('callee' in requestArgs.body).toBe(true);
1088
+ case 1:
1089
+ case "end":
1090
+ return _context13.stop();
1091
+ }
1092
+ }, _callee13);
1093
+ })));
1094
+ it('outgoing call for guest calling must not have callee', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee14() {
1095
+ var requestSpy, requestArgs;
1096
+ return _regenerator.default.wrap(function (_context14) {
1097
+ while (1) switch (_context14.prev = _context14.next) {
1098
+ case 0:
1099
+ call = new _call.Call(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, function () {
1100
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1101
+ var dummy = 10;
1102
+ }, defaultServiceIndicator);
1103
+ call['callStateMachine'].state.value = 'S_IDLE';
1104
+ requestSpy = jest.spyOn(webex, 'request');
1105
+ call.sendCallStateMachineEvt(dummyEvent);
1106
+ requestArgs = requestSpy.mock.calls[0][0];
1107
+ expect('callee' in requestArgs.body).toBe(false);
1108
+ case 1:
1109
+ case "end":
1110
+ return _context14.stop();
1111
+ }
1112
+ }, _callee14);
1113
+ })));
1114
+ });
1115
+ });
1116
+ describe('State Machine handler tests', function () {
1117
+ var deviceId = '55dfb53f-bed2-36da-8e85-cee7f02aa68e';
1118
+ var dest = {
1119
+ type: _types3.CallType.URI,
1120
+ address: 'tel:5003'
1121
+ };
1122
+ var mockStatusBody = {
1123
+ device: {
1124
+ deviceId: '123e4567-e89b-12d3-a456-426614174000',
1125
+ correlationId: 'b5476d4c-f48b-475e-b4e2-994e24d14ca2'
1126
+ },
1127
+ callId: 'fcf86aa5-5539-4c9f-8b72-667786ae9b6c'
1128
+ };
1129
+ var call;
1130
+ var dtmfMock;
1131
+ beforeEach(function () {
1132
+ _request.APIRequest.resetInstance();
1133
+ _request.APIRequest.getInstance({
1134
+ webex: webex,
1135
+ isMobiusSocketEnabled: false
1136
+ });
1137
+ call = new _call.Call(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, function () {
1138
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1139
+ var dummy = 10;
1140
+ }, defaultServiceIndicator, dest);
1141
+ jest.clearAllTimers();
1142
+ jest.useFakeTimers();
1143
+ call['callStateMachine'].state.value = 'S_IDLE';
1144
+ call.mediaConnection = _testUtil.mediaConnection;
1145
+ dtmfMock = jest.spyOn(call['mediaConnection'], 'insertDTMF');
1146
+ });
1147
+
1148
+ // afterEach(() => call.removeAllListeners());
1149
+
1150
+ it('successful session refresh', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee15() {
1151
+ var statusPayload, dummyEvent, funcSpy, logSpy;
1152
+ return _regenerator.default.wrap(function (_context15) {
1153
+ while (1) switch (_context15.prev = _context15.next) {
1154
+ case 0:
1155
+ statusPayload = {
1156
+ statusCode: 200,
1157
+ body: mockStatusBody
1158
+ };
1159
+ dummyEvent = {
1160
+ type: 'E_CALL_ESTABLISHED'
1161
+ };
1162
+ call['callStateMachine'].state.value = 'S_SEND_CALL_CONNECT';
1163
+ webex.request.mockReturnValue(statusPayload);
1164
+ jest.spyOn(global, 'setInterval');
1165
+ funcSpy = jest.spyOn(call, 'postStatus').mockResolvedValue(statusPayload);
1166
+ logSpy = jest.spyOn(_Logger.default, 'info');
1167
+ call.sendCallStateMachineEvt(dummyEvent);
1168
+ jest.advanceTimersByTime(_constants.DEFAULT_SESSION_TIMER);
1169
+
1170
+ /* This is to flush all the promises from the Promise queue so that
1171
+ * Jest.fakeTimers can advance time and also clear the promise Queue
1172
+ */
1173
+ _context15.next = 1;
1174
+ return (0, _testUtil.flushPromises)(3);
1175
+ case 1:
1176
+ expect(setInterval).toHaveBeenCalledTimes(1);
1177
+ expect(setInterval).toHaveBeenCalledWith(expect.any(Function), _constants.DEFAULT_SESSION_TIMER);
1178
+ expect(funcSpy).toBeCalledTimes(1);
1179
+ expect(logSpy).toBeCalledWith('Session refresh successful', {
1180
+ file: 'call',
1181
+ method: 'scheduleCallKeepaliveInterval'
1182
+ });
1183
+ expect(logSpy).toHaveBeenCalledWith("".concat(_constants2.METHOD_START_MESSAGE, " with: ").concat(call.getCorrelationId()), {
1184
+ file: 'call',
1185
+ method: 'handleCallEstablished'
1186
+ });
1187
+ case 2:
1188
+ case "end":
1189
+ return _context15.stop();
1190
+ }
1191
+ }, _callee15);
1192
+ })));
1193
+ it('session refresh 401 emits token error and ends the call', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee16() {
1194
+ var statusPayload, emitSpy, funcSpy;
1195
+ return _regenerator.default.wrap(function (_context16) {
1196
+ while (1) switch (_context16.prev = _context16.next) {
1197
+ case 0:
1198
+ expect.assertions(4);
1199
+ statusPayload = {
1200
+ statusCode: 401
1201
+ };
1202
+ webex.request.mockReturnValue(statusPayload);
1203
+ jest.spyOn(global, 'clearInterval');
1204
+ emitSpy = jest.spyOn(call, 'emit');
1205
+ call.on(_types2.CALL_EVENT_KEYS.CALL_ERROR, function (errObj) {
1206
+ expect(errObj.type).toStrictEqual(_types.ERROR_TYPE.TOKEN_ERROR);
1207
+ });
1208
+ funcSpy = jest.spyOn(call, 'postStatus').mockRejectedValue(statusPayload);
1209
+ call['handleCallEstablished']({});
1210
+ jest.advanceTimersByTime(_constants.DEFAULT_SESSION_TIMER);
1211
+ _context16.next = 1;
1212
+ return _promise.default.resolve();
1213
+ case 1:
1214
+ _context16.next = 2;
1215
+ return _promise.default.resolve();
1216
+ case 2:
1217
+ // clearInterval is called twice: once in scheduleCallKeepaliveInterval (at start)
1218
+ // and once in handleCallKeepaliveError when clearing timer due to error
1219
+ expect(clearInterval).toHaveBeenCalledTimes(2);
1220
+ expect(funcSpy).toBeCalledTimes(1);
1221
+ expect(emitSpy).toHaveBeenCalledWith(_types2.CALL_EVENT_KEYS.DISCONNECT, call.getCorrelationId());
1222
+ case 3:
1223
+ case "end":
1224
+ return _context16.stop();
1225
+ }
1226
+ }, _callee16);
1227
+ })));
1228
+ it('session refresh failure', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee17() {
1229
+ var statusPayload, funcSpy;
1230
+ return _regenerator.default.wrap(function (_context17) {
1231
+ while (1) switch (_context17.prev = _context17.next) {
1232
+ case 0:
1233
+ expect.assertions(4);
1234
+ statusPayload = {
1235
+ statusCode: 403
1236
+ };
1237
+ webex.request.mockReturnValue(statusPayload);
1238
+ jest.spyOn(global, 'clearInterval');
1239
+ call.on(_types2.CALL_EVENT_KEYS.CALL_ERROR, function (errObj) {
1240
+ expect(errObj.type).toStrictEqual(_types.ERROR_TYPE.FORBIDDEN_ERROR);
1241
+ expect(errObj.message).toStrictEqual('An unauthorized action has been received. This action has been blocked. Please contact the administrator if this persists.');
1242
+ });
1243
+ funcSpy = jest.spyOn(call, 'postStatus').mockRejectedValue(statusPayload);
1244
+ call['handleCallEstablished']({});
1245
+ jest.advanceTimersByTime(_constants.DEFAULT_SESSION_TIMER);
1246
+
1247
+ /* This is to flush all the promises from the Promise queue so that
1248
+ * Jest.fakeTimers can advance time and also clear the promise Queue
1249
+ */
1250
+ _context17.next = 1;
1251
+ return (0, _testUtil.flushPromises)(2);
1252
+ case 1:
1253
+ // clearInterval is called twice: once in scheduleCallKeepaliveInterval (at start)
1254
+ // and once in handleCallKeepaliveError when clearing timer due to error
1255
+ expect(clearInterval).toHaveBeenCalledTimes(2);
1256
+ expect(funcSpy).toBeCalledTimes(1);
1257
+ case 2:
1258
+ case "end":
1259
+ return _context17.stop();
1260
+ }
1261
+ }, _callee17);
1262
+ })));
1263
+ it('session refresh 500 schedules retry via retry-after or default interval', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee18() {
1264
+ var errorPayload, okPayload, scheduleKeepaliveSpy, postStatusSpy;
1265
+ return _regenerator.default.wrap(function (_context18) {
1266
+ while (1) switch (_context18.prev = _context18.next) {
1267
+ case 0:
1268
+ errorPayload = {
1269
+ statusCode: 500,
1270
+ headers: {
1271
+ 'retry-after': 1
1272
+ }
1273
+ };
1274
+ okPayload = {
1275
+ statusCode: 200,
1276
+ body: {}
1277
+ };
1278
+ scheduleKeepaliveSpy = jest.spyOn(call, 'scheduleCallKeepaliveInterval');
1279
+ postStatusSpy = jest.spyOn(call, 'postStatus').mockRejectedValueOnce(errorPayload).mockResolvedValueOnce(okPayload);
1280
+ if (call['sessionTimer'] === undefined) {
1281
+ call['handleCallEstablished']({});
1282
+ }
1283
+ jest.advanceTimersByTime(_constants.DEFAULT_SESSION_TIMER);
1284
+ _context18.next = 1;
1285
+ return (0, _testUtil.flushPromises)(2);
1286
+ case 1:
1287
+ expect(postStatusSpy).toHaveBeenCalledTimes(1);
1288
+
1289
+ // Now advance by 1 second for the retry-after interval
1290
+ jest.advanceTimersByTime(1000);
1291
+ _context18.next = 2;
1292
+ return (0, _testUtil.flushPromises)(2);
1293
+ case 2:
1294
+ expect(postStatusSpy).toHaveBeenCalledTimes(2);
1295
+ expect(scheduleKeepaliveSpy).toHaveBeenCalledTimes(2);
1296
+ case 3:
1297
+ case "end":
1298
+ return _context18.stop();
1299
+ }
1300
+ }, _callee18);
1301
+ })));
1302
+ it('scheduleCallKeepaliveInterval clears existing interval before creating new one', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee19() {
1303
+ var firstTimer, secondTimer;
1304
+ return _regenerator.default.wrap(function (_context19) {
1305
+ while (1) switch (_context19.prev = _context19.next) {
1306
+ case 0:
1307
+ jest.spyOn(global, 'setInterval');
1308
+ jest.spyOn(global, 'clearInterval');
1309
+
1310
+ // Setup the first keepalive interval
1311
+ call['handleCallEstablished']({});
1312
+
1313
+ // At this point, scheduleCallKeepaliveInterval was called once
1314
+ // It should have called clearInterval once (at the start) and setInterval once
1315
+ expect(clearInterval).toHaveBeenCalledTimes(1);
1316
+ expect(setInterval).toHaveBeenCalledTimes(1);
1317
+ firstTimer = call['sessionTimer'];
1318
+ expect(firstTimer).toBeDefined();
1319
+
1320
+ // Manually call scheduleCallKeepaliveInterval again to simulate a retry scenario
1321
+ call['scheduleCallKeepaliveInterval']();
1322
+
1323
+ // clearInterval should have been called again to clear the previous timer
1324
+ expect(clearInterval).toHaveBeenCalledTimes(2);
1325
+ // A new interval should have been created
1326
+ expect(setInterval).toHaveBeenCalledTimes(2);
1327
+
1328
+ // The sessionTimer should be different (new timer)
1329
+ secondTimer = call['sessionTimer'];
1330
+ expect(secondTimer).toBeDefined();
1331
+ case 1:
1332
+ case "end":
1333
+ return _context19.stop();
1334
+ }
1335
+ }, _callee19);
1336
+ })));
1337
+ it('keepalive ends after reaching max retry count', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee20() {
1338
+ var errorPayload, warnSpy, postStatusSpy;
1339
+ return _regenerator.default.wrap(function (_context20) {
1340
+ while (1) switch (_context20.prev = _context20.next) {
1341
+ case 0:
1342
+ errorPayload = {
1343
+ statusCode: 500,
1344
+ headers: {
1345
+ 'retry-after': 1
1346
+ }
1347
+ };
1348
+ jest.spyOn(global, 'clearInterval');
1349
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
1350
+ postStatusSpy = jest.spyOn(call, 'postStatus').mockRejectedValue(errorPayload); // Put the call in the S_CALL_ESTABLISHED state and set it as connected
1351
+ call['callStateMachine'].state.value = 'S_CALL_ESTABLISHED';
1352
+ call['connected'] = true;
1353
+
1354
+ // Call handleCallEstablished which will setup interval
1355
+ call['handleCallEstablished']({});
1356
+
1357
+ // Advance timer to trigger the first failure (uses DEFAULT_SESSION_TIMER)
1358
+ jest.advanceTimersByTime(_constants.DEFAULT_SESSION_TIMER);
1359
+ _context20.next = 1;
1360
+ return (0, _testUtil.flushPromises)(2);
1361
+ case 1:
1362
+ // Now advance by 1 second for each of the 4 retry attempts (retry-after: 1 second each)
1363
+ // Need to do this separately to allow state machine to process and create new intervals
1364
+ jest.advanceTimersByTime(1000);
1365
+ _context20.next = 2;
1366
+ return (0, _testUtil.flushPromises)(2);
1367
+ case 2:
1368
+ jest.advanceTimersByTime(1000);
1369
+ _context20.next = 3;
1370
+ return (0, _testUtil.flushPromises)(2);
1371
+ case 3:
1372
+ jest.advanceTimersByTime(1000);
1373
+ _context20.next = 4;
1374
+ return (0, _testUtil.flushPromises)(2);
1375
+ case 4:
1376
+ jest.advanceTimersByTime(1000);
1377
+ _context20.next = 5;
1378
+ return (0, _testUtil.flushPromises)(2);
1379
+ case 5:
1380
+ // The error handler should detect we're at max retry count and stop
1381
+ expect(warnSpy).toHaveBeenCalledWith("Max keepalive retry attempts reached. Aborting call keepalive for callId: ".concat(call.getCallId()), {
1382
+ file: 'call',
1383
+ method: 'keepaliveRetryCallback'
1384
+ });
1385
+ expect(postStatusSpy).toHaveBeenCalledTimes(5);
1386
+ expect(call['callKeepaliveRetryCount']).toBe(4);
1387
+ case 6:
1388
+ case "end":
1389
+ return _context20.stop();
1390
+ }
1391
+ }, _callee20);
1392
+ })));
1393
+ it('state changes during successful incoming call', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee21() {
1394
+ var statusPayload, dummyEvent, postMediaSpy, deleteSpy, dummyOkEvent;
1395
+ return _regenerator.default.wrap(function (_context21) {
1396
+ while (1) switch (_context21.prev = _context21.next) {
1397
+ case 0:
1398
+ statusPayload = {
1399
+ statusCode: 200,
1400
+ body: mockStatusBody
1401
+ };
1402
+ dummyEvent = {
1403
+ type: 'E_RECV_CALL_SETUP',
1404
+ data: {
1405
+ seq: 1,
1406
+ messageType: 'OFFER'
1407
+ }
1408
+ };
1409
+ postMediaSpy = jest.spyOn(call, 'postMedia');
1410
+ deleteSpy = jest.spyOn(call, 'delete');
1411
+ webex.request.mockReturnValue(statusPayload);
1412
+ call['direction'] = _types3.CallDirection.INBOUND;
1413
+ call.sendCallStateMachineEvt(dummyEvent);
1414
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_PROGRESS');
1415
+ dummyEvent.type = 'E_SEND_CALL_CONNECT';
1416
+ call.sendCallStateMachineEvt(dummyEvent);
1417
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_CONNECT');
1418
+
1419
+ /* we should expect to forward the roap offer message to mediaSdk for further processing */
1420
+ dummyEvent.type = 'E_RECV_ROAP_OFFER';
1421
+ call.sendMediaStateMachineEvt(dummyEvent);
1422
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
1423
+
1424
+ /* expect sending roap answer to mobius */
1425
+ dummyEvent.type = 'E_SEND_ROAP_ANSWER';
1426
+ call.sendMediaStateMachineEvt(dummyEvent);
1427
+ expect(postMediaSpy).toBeCalledOnceWith(dummyEvent.data);
1428
+ dummyOkEvent = {
1429
+ type: 'E_ROAP_OK',
1430
+ data: {
1431
+ received: true,
1432
+ message: {
1433
+ seq: 1,
1434
+ messageType: 'OFFER'
1435
+ }
1436
+ }
1437
+ };
1438
+ /* we receive roap Ok from mobius and expect mediaSdk to process it */
1439
+ call.sendMediaStateMachineEvt(dummyOkEvent);
1440
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyOkEvent.data.message);
1441
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_ESTABLISHED');
1442
+ expect(call.isConnected()).toBe(true);
1443
+ call.sendDigit('1');
1444
+ expect(dtmfMock).toBeCalledOnceWith('1');
1445
+ call.sendCallStateMachineEvt({
1446
+ type: 'E_RECV_CALL_DISCONNECT'
1447
+ });
1448
+ expect(deleteSpy).toBeCalledOnceWith();
1449
+ expect(call['callStateMachine'].state.value).toBe('S_RECV_CALL_DISCONNECT');
1450
+ case 1:
1451
+ case "end":
1452
+ return _context21.stop();
1453
+ }
1454
+ }, _callee21);
1455
+ })));
1456
+ it('state changes during unsuccessful incoming call due to no offer', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee22() {
1457
+ var statusPayload, dummyEvent;
1458
+ return _regenerator.default.wrap(function (_context22) {
1459
+ while (1) switch (_context22.prev = _context22.next) {
1460
+ case 0:
1461
+ call['direction'] = _types3.CallDirection.INBOUND;
1462
+ statusPayload = {
1463
+ statusCode: 200,
1464
+ body: mockStatusBody
1465
+ };
1466
+ dummyEvent = {
1467
+ type: 'E_RECV_CALL_SETUP',
1468
+ data: {
1469
+ seq: 1,
1470
+ message: {},
1471
+ type: 'OFFER'
1472
+ }
1473
+ };
1474
+ webex.request.mockReturnValue(statusPayload);
1475
+ call.sendCallStateMachineEvt(dummyEvent);
1476
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_PROGRESS');
1477
+ _context22.next = 1;
1478
+ return call['handleOutgoingCallConnect']({
1479
+ type: 'E_SEND_CALL_CONNECT'
1480
+ });
1481
+ case 1:
1482
+ /* state should not change since there is no offer received. */
1483
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_PROGRESS');
1484
+ expect(call.isConnected()).toBeFalsy();
1485
+ call.sendCallStateMachineEvt({
1486
+ type: 'E_RECV_CALL_DISCONNECT'
1487
+ });
1488
+ expect(call['callStateMachine'].state.value).toBe('S_RECV_CALL_DISCONNECT');
1489
+ case 2:
1490
+ case "end":
1491
+ return _context22.stop();
1492
+ }
1493
+ }, _callee22);
1494
+ })));
1495
+ it('processes callerId on received progress event in established state without emitting PROGRESS', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee23() {
1496
+ var callManager, statusPayload, call, dummyEvent, dummyOkEvent, emitSpy, startCallerIdSpy, mobiusProgressEvent;
1497
+ return _regenerator.default.wrap(function (_context23) {
1498
+ while (1) switch (_context23.prev = _context23.next) {
1499
+ case 0:
1500
+ callManager = (0, _callManager.getCallManager)(webex, defaultServiceIndicator);
1501
+ statusPayload = {
1502
+ statusCode: 200,
1503
+ body: mockStatusBody
1504
+ };
1505
+ call = callManager.createCall(_types3.CallDirection.OUTBOUND, deviceId, mockLineId, dest);
1506
+ webex.request.mockReturnValue(statusPayload);
1507
+
1508
+ // Move to S_SEND_CALL_SETUP
1509
+ dummyEvent = {
1510
+ type: 'E_SEND_CALL_SETUP',
1511
+ data: {
1512
+ seq: 1,
1513
+ message: {},
1514
+ type: 'OFFER'
1515
+ }
1516
+ };
1517
+ call.sendCallStateMachineEvt(dummyEvent);
1518
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_SETUP');
1519
+
1520
+ // Complete media negotiation to allow connect -> established
1521
+ // Ask media SDK to initiate offer
1522
+ dummyEvent.type = 'E_SEND_ROAP_OFFER';
1523
+ dummyEvent.data = {
1524
+ seq: 1,
1525
+ messageType: 'OFFER',
1526
+ sdp: 'sdp'
1527
+ };
1528
+ call.sendMediaStateMachineEvt(dummyEvent);
1529
+ expect(call['mediaStateMachine'].state.value).toBe('S_SEND_ROAP_OFFER');
1530
+ dummyEvent.type = 'E_RECV_ROAP_ANSWER';
1531
+ dummyEvent.data = {
1532
+ seq: 1,
1533
+ messageType: 'ANSWER',
1534
+ sdp: 'sdp'
1535
+ };
1536
+ call.sendMediaStateMachineEvt(dummyEvent);
1537
+ expect(call['mediaStateMachine'].state.value).toBe('S_RECV_ROAP_ANSWER');
1538
+ // Send OK
1539
+ dummyOkEvent = {
1540
+ type: 'E_ROAP_OK',
1541
+ data: {
1542
+ received: false,
1543
+ message: {
1544
+ seq: 1,
1545
+ messageType: 'OK'
1546
+ }
1547
+ }
1548
+ };
1549
+ call.sendMediaStateMachineEvt(dummyOkEvent);
1550
+ expect(call['mediaStateMachine'].state.value).toBe('S_ROAP_OK');
1551
+ expect(call['mediaNegotiationCompleted']).toBe(true);
1552
+
1553
+ // Move call to established
1554
+ dummyEvent.type = 'E_RECV_CALL_CONNECT';
1555
+ dummyEvent.data = undefined;
1556
+ call.sendCallStateMachineEvt(dummyEvent);
1557
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_ESTABLISHED');
1558
+ emitSpy = jest.spyOn(call, 'emit');
1559
+ startCallerIdSpy = jest.spyOn(call, 'startCallerIdResolution'); // Now send progress with callerId while established via CallManager (Mobius event)
1560
+ mobiusProgressEvent = {
1561
+ id: 'evt1',
1562
+ timestamp: (0, _now.default)(),
1563
+ trackingId: 'track-1',
1564
+ data: {
1565
+ eventType: _types5.MobiusEventType.CALL_PROGRESS,
1566
+ callerId: {
1567
+ from: '"Bob Marley" <sip:5010@207.182.171.130;user=phone>;tag=888068389-1654853820619-'
1568
+ },
1569
+ callProgressData: {
1570
+ inbandMedia: true,
1571
+ alerting: false
1572
+ },
1573
+ callId: call.getCallId(),
1574
+ callUrl: 'https://mobius.example/call',
1575
+ deviceId: deviceId,
1576
+ correlationId: call.getCorrelationId()
1577
+ }
1578
+ };
1579
+ callManager['dequeueWsEvents'](mobiusProgressEvent);
1580
+
1581
+ // CallerId resolution should be triggered exactly once (handled by CallManager)
1582
+ expect(startCallerIdSpy).toBeCalledOnceWith(mobiusProgressEvent.data.callerId);
1583
+ // Since it returns early in established state, PROGRESS event should not be emitted here
1584
+ expect(emitSpy.mock.calls.find(function (args) {
1585
+ return args && args[0] === _types2.CALL_EVENT_KEYS.PROGRESS;
1586
+ })).toBeUndefined();
1587
+ expect(call['callStateMachine'].state.value).not.toBe('S_RECV_CALL_PROGRESS');
1588
+ // Early media flag should not be set due to early return
1589
+ expect(call.earlyMedia).not.toBe(true);
1590
+ case 1:
1591
+ case "end":
1592
+ return _context23.stop();
1593
+ }
1594
+ }, _callee23);
1595
+ })));
1596
+ it('state changes during unsuccessful incoming call due error in call connect', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee24() {
1597
+ var warnSpy, errorSpy, stateMachineSpy, statusPayload, roapMessage;
1598
+ return _regenerator.default.wrap(function (_context24) {
1599
+ while (1) switch (_context24.prev = _context24.next) {
1600
+ case 0:
1601
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
1602
+ errorSpy = jest.spyOn(_Logger.default, 'error');
1603
+ stateMachineSpy = jest.spyOn(call, 'sendCallStateMachineEvt');
1604
+ statusPayload = {
1605
+ statusCode: 200,
1606
+ body: mockStatusBody
1607
+ };
1608
+ roapMessage = {
1609
+ seq: 1,
1610
+ message: {},
1611
+ type: 'OFFER'
1612
+ };
1613
+ call['direction'] = _types3.CallDirection.INBOUND;
1614
+ webex.request.mockReturnValue(statusPayload);
1615
+ call.sendCallStateMachineEvt({
1616
+ type: 'E_RECV_CALL_SETUP'
1617
+ });
1618
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_PROGRESS');
1619
+ call.sendMediaStateMachineEvt({
1620
+ type: 'E_RECV_ROAP_OFFER',
1621
+ data: roapMessage
1622
+ });
1623
+ webex.request.mockRejectedValueOnce({
1624
+ statusCode: 403
1625
+ }).mockResolvedValue(statusPayload);
1626
+ _context24.next = 1;
1627
+ return call['handleOutgoingCallConnect']({
1628
+ type: 'E_SEND_CALL_CONNECT'
1629
+ });
1630
+ case 1:
1631
+ expect(call['callStateMachine'].state.value).toBe('S_UNKNOWN');
1632
+ expect(stateMachineSpy).toBeCalledTimes(3);
1633
+ expect(warnSpy).toBeCalledTimes(3);
1634
+ expect(errorSpy).toBeCalledTimes(1);
1635
+ case 2:
1636
+ case "end":
1637
+ return _context24.stop();
1638
+ }
1639
+ }, _callee24);
1640
+ })));
1641
+ it('state changes during successful outgoing call', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee25() {
1642
+ var statusPayload, dummyEvent, postMediaSpy, logSpy, dummyOkEvent;
1643
+ return _regenerator.default.wrap(function (_context25) {
1644
+ while (1) switch (_context25.prev = _context25.next) {
1645
+ case 0:
1646
+ statusPayload = {
1647
+ statusCode: 200,
1648
+ body: mockStatusBody
1649
+ };
1650
+ dummyEvent = {
1651
+ type: 'E_SEND_CALL_SETUP',
1652
+ data: undefined
1653
+ };
1654
+ postMediaSpy = jest.spyOn(call, 'postMedia');
1655
+ logSpy = jest.spyOn(_Logger.default, 'log');
1656
+ webex.request.mockReturnValue(statusPayload);
1657
+ call.sendCallStateMachineEvt(dummyEvent);
1658
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_SETUP');
1659
+ expect(logSpy).toHaveBeenCalled();
1660
+ dummyEvent.type = 'E_RECV_CALL_PROGRESS';
1661
+ call.sendCallStateMachineEvt(dummyEvent);
1662
+ expect(call['callStateMachine'].state.value).toBe('S_RECV_CALL_PROGRESS');
1663
+ dummyEvent.type = 'E_SEND_ROAP_OFFER';
1664
+ call.sendMediaStateMachineEvt(dummyEvent);
1665
+
1666
+ /**
1667
+ * Since the event doesn't have any data above, we should request media sdk for an offer here.
1668
+ * The below event is expected to be called again my mediaSdk.
1669
+ */
1670
+ dummyEvent.data = {
1671
+ seq: 1,
1672
+ messageType: 'OFFER',
1673
+ sdp: 'sdp'
1674
+ };
1675
+ call.sendMediaStateMachineEvt(dummyEvent);
1676
+ expect(_testUtil.mediaConnection.initiateOffer).toHaveBeenCalledTimes(1);
1677
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyEvent.data);
1678
+ dummyEvent.type = 'E_RECV_ROAP_ANSWER';
1679
+ call.sendMediaStateMachineEvt(dummyEvent);
1680
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
1681
+ dummyOkEvent = {
1682
+ type: 'E_ROAP_OK',
1683
+ data: {
1684
+ received: false,
1685
+ message: {
1686
+ seq: 1,
1687
+ messageType: 'OK'
1688
+ }
1689
+ }
1690
+ };
1691
+ call.sendMediaStateMachineEvt(dummyOkEvent);
1692
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyOkEvent.data.message);
1693
+ dummyEvent.type = 'E_RECV_ROAP_OFFER_REQUEST';
1694
+ call.sendMediaStateMachineEvt(dummyEvent);
1695
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
1696
+ dummyEvent.type = 'E_SEND_ROAP_OFFER';
1697
+ call.sendMediaStateMachineEvt(dummyEvent);
1698
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyEvent.data);
1699
+ dummyEvent.type = 'E_RECV_ROAP_ANSWER';
1700
+ call.sendMediaStateMachineEvt(dummyEvent);
1701
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
1702
+ call.sendMediaStateMachineEvt(dummyOkEvent);
1703
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyOkEvent.data.message);
1704
+
1705
+ /* With the two roap offer/answer transactions that we simulated earlier
1706
+ we get a total 4 outgoing and 3 incoming roap messages.
1707
+ */
1708
+ expect(postMediaSpy).toBeCalledTimes(4);
1709
+ expect(_testUtil.mediaConnection.roapMessageReceived).toBeCalledTimes(3);
1710
+ dummyEvent.type = 'E_RECV_CALL_CONNECT';
1711
+ call.sendCallStateMachineEvt(dummyEvent);
1712
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_ESTABLISHED');
1713
+ expect(call.isConnected()).toBe(true);
1714
+ call.sendCallStateMachineEvt({
1715
+ type: 'E_SEND_CALL_DISCONNECT'
1716
+ });
1717
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_DISCONNECT');
1718
+ case 1:
1719
+ case "end":
1720
+ return _context25.stop();
1721
+ }
1722
+ }, _callee25);
1723
+ })));
1724
+ it('outgoing call where we receive connect directly after setup. Media established before connect. test call and media state changes', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee26() {
1725
+ var statusPayload, dummySetupEvent, dummyConnectEvent, dummyOfferEvent, dummyAnswerEvent, dummyOkEvent, postMediaSpy;
1726
+ return _regenerator.default.wrap(function (_context26) {
1727
+ while (1) switch (_context26.prev = _context26.next) {
1728
+ case 0:
1729
+ statusPayload = {
1730
+ statusCode: 200,
1731
+ body: mockStatusBody
1732
+ };
1733
+ dummySetupEvent = {
1734
+ type: 'E_SEND_CALL_SETUP',
1735
+ data: undefined
1736
+ };
1737
+ dummyConnectEvent = {
1738
+ type: 'E_RECV_CALL_CONNECT',
1739
+ data: undefined
1740
+ };
1741
+ dummyOfferEvent = {
1742
+ type: 'E_SEND_ROAP_OFFER',
1743
+ data: undefined
1744
+ };
1745
+ dummyAnswerEvent = {
1746
+ type: 'E_RECV_ROAP_ANSWER',
1747
+ data: {
1748
+ seq: 1,
1749
+ messageType: 'ANSWER',
1750
+ sdp: 'sdp'
1751
+ }
1752
+ };
1753
+ dummyOkEvent = {
1754
+ type: 'E_ROAP_OK',
1755
+ data: {
1756
+ received: false,
1757
+ message: {
1758
+ seq: 1,
1759
+ messageType: 'OK'
1760
+ }
1761
+ }
1762
+ };
1763
+ postMediaSpy = jest.spyOn(call, 'postMedia');
1764
+ webex.request.mockReturnValue(statusPayload);
1765
+ call.sendCallStateMachineEvt(dummySetupEvent);
1766
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_SETUP');
1767
+ call.sendMediaStateMachineEvt(dummyOfferEvent);
1768
+
1769
+ /**
1770
+ * Since the event doesn't have any data above, we should request media sdk for an offer here.
1771
+ * The below event is expected to be called again my mediaSdk.
1772
+ */
1773
+ dummyOfferEvent.data = {
1774
+ seq: 1,
1775
+ messageType: 'OFFER',
1776
+ sdp: 'sdp'
1777
+ };
1778
+ call.sendMediaStateMachineEvt(dummyOfferEvent);
1779
+ expect(_testUtil.mediaConnection.initiateOffer).toHaveBeenCalledTimes(1);
1780
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyOfferEvent.data);
1781
+ call.sendMediaStateMachineEvt(dummyAnswerEvent);
1782
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyAnswerEvent.data);
1783
+ call.sendMediaStateMachineEvt(dummyOkEvent);
1784
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyOkEvent.data.message);
1785
+ expect(call['mediaStateMachine'].state.value).toBe('S_ROAP_OK');
1786
+ call.sendCallStateMachineEvt(dummyConnectEvent);
1787
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_ESTABLISHED');
1788
+ expect(call.isConnected()).toBe(true);
1789
+ call.sendCallStateMachineEvt({
1790
+ type: 'E_SEND_CALL_DISCONNECT'
1791
+ });
1792
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_DISCONNECT');
1793
+ case 1:
1794
+ case "end":
1795
+ return _context26.stop();
1796
+ }
1797
+ }, _callee26);
1798
+ })));
1799
+ it('state changes during successful outgoing call with early media', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee27() {
1800
+ var statusPayload, dummyEvent;
1801
+ return _regenerator.default.wrap(function (_context27) {
1802
+ while (1) switch (_context27.prev = _context27.next) {
1803
+ case 0:
1804
+ statusPayload = {
1805
+ statusCode: 200,
1806
+ body: mockStatusBody
1807
+ };
1808
+ dummyEvent = {
1809
+ type: 'E_SEND_CALL_SETUP',
1810
+ data: {
1811
+ seq: 1,
1812
+ message: {},
1813
+ type: 'OFFER'
1814
+ }
1815
+ };
1816
+ webex.request.mockReturnValue(statusPayload);
1817
+ call.sendCallStateMachineEvt(dummyEvent);
1818
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_SETUP');
1819
+ dummyEvent.type = 'E_RECV_CALL_PROGRESS';
1820
+ call.sendCallStateMachineEvt(dummyEvent);
1821
+ expect(call['callStateMachine'].state.value).toBe('S_RECV_CALL_PROGRESS');
1822
+
1823
+ /* Send a second callProgress event with inband media and it should handle */
1824
+ dummyEvent.data['callProgressData'] = {
1825
+ inbandMedia: true
1826
+ };
1827
+ dummyEvent.data['callerId'] = {
1828
+ from: '"Bob Marley" <sip:5010@207.182.171.130;user=phone>;tag=888068389-1654853820619-'
1829
+ };
1830
+ call.sendCallStateMachineEvt(dummyEvent);
1831
+ expect(call['callStateMachine'].state.value).toBe('S_RECV_CALL_PROGRESS');
1832
+ dummyEvent.type = 'E_RECV_CALL_CONNECT';
1833
+ call.sendCallStateMachineEvt(dummyEvent);
1834
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_ESTABLISHED');
1835
+ call.sendCallStateMachineEvt({
1836
+ type: 'E_RECV_CALL_DISCONNECT'
1837
+ });
1838
+ expect(call['callStateMachine'].state.value).toBe('S_RECV_CALL_DISCONNECT');
1839
+ case 1:
1840
+ case "end":
1841
+ return _context27.stop();
1842
+ }
1843
+ }, _callee27);
1844
+ })));
1845
+ it('state changes during unsuccessful outgoing call due to error in call setup', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee28() {
1846
+ var statusPayload, dummyEvent, errorSpy;
1847
+ return _regenerator.default.wrap(function (_context28) {
1848
+ while (1) switch (_context28.prev = _context28.next) {
1849
+ case 0:
1850
+ statusPayload = {
1851
+ statusCode: 403,
1852
+ body: mockStatusBody
1853
+ };
1854
+ dummyEvent = {
1855
+ type: 'E_SEND_CALL_SETUP',
1856
+ data: {
1857
+ seq: 1,
1858
+ message: {},
1859
+ type: 'OFFER'
1860
+ }
1861
+ };
1862
+ webex.request.mockRejectedValueOnce(statusPayload);
1863
+ errorSpy = jest.spyOn(_Logger.default, 'error');
1864
+ call.sendCallStateMachineEvt(dummyEvent);
1865
+ _context28.next = 1;
1866
+ return (0, _testUtil.flushPromises)(3);
1867
+ case 1:
1868
+ _context28.next = 2;
1869
+ return _promise.default.resolve();
1870
+ case 2:
1871
+ _context28.next = 3;
1872
+ return _promise.default.resolve();
1873
+ case 3:
1874
+ expect(call['callStateMachine'].state.value).toBe('S_UNKNOWN');
1875
+ expect(errorSpy).toHaveBeenCalled();
1876
+ expect(uploadLogsSpy).toHaveBeenCalledWith({
1877
+ correlationId: call.getCorrelationId(),
1878
+ callId: call.getCallId()
1879
+ });
1880
+ case 4:
1881
+ case "end":
1882
+ return _context28.stop();
1883
+ }
1884
+ }, _callee28);
1885
+ })));
1886
+ it('state changes during unsuccessful outgoing call due to error in media ok', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee29() {
1887
+ var statusPayload, dummyEvent, warnSpy;
1888
+ return _regenerator.default.wrap(function (_context29) {
1889
+ while (1) switch (_context29.prev = _context29.next) {
1890
+ case 0:
1891
+ statusPayload = {
1892
+ statusCode: 403,
1893
+ body: mockStatusBody
1894
+ };
1895
+ dummyEvent = {
1896
+ type: 'E_ROAP_OK',
1897
+ data: {
1898
+ received: false,
1899
+ message: {}
1900
+ }
1901
+ };
1902
+ call['callStateMachine'].state.value = 'S_RECV_CALL_PROGRESS';
1903
+ call['earlyMedia'] = true;
1904
+ call['mediaStateMachine'].state.value = 'S_RECV_ROAP_ANSWER';
1905
+ webex.request.mockRejectedValue(statusPayload);
1906
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
1907
+ jest.spyOn(Utils, 'uploadLogs').mockResolvedValue(undefined);
1908
+ _context29.next = 1;
1909
+ return call['handleRoapEstablished']({}, dummyEvent);
1910
+ case 1:
1911
+ _context29.next = 2;
1912
+ return (0, _testUtil.flushPromises)(2);
1913
+ case 2:
1914
+ _context29.next = 3;
1915
+ return _promise.default.resolve();
1916
+ case 3:
1917
+ _context29.next = 4;
1918
+ return _promise.default.resolve();
1919
+ case 4:
1920
+ expect(call.isConnected()).toBe(false);
1921
+ expect(call['mediaStateMachine'].state.value).toBe('S_ROAP_TEARDOWN');
1922
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_CLEARED');
1923
+ expect(warnSpy).toHaveBeenCalledWith('Failed to process MediaOk request', {
1924
+ file: 'call',
1925
+ method: 'handleRoapEstablished'
1926
+ });
1927
+ expect(warnSpy).toHaveBeenCalledWith('Call failed due to media issue', {
1928
+ file: 'call',
1929
+ method: 'handleRoapError'
1930
+ });
1931
+ case 5:
1932
+ case "end":
1933
+ return _context29.stop();
1934
+ }
1935
+ }, _callee29);
1936
+ })));
1937
+ it('state changes during unsuccessful outgoing call since no sdp in offer', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee30() {
1938
+ var statusPayload, dummyEvent;
1939
+ return _regenerator.default.wrap(function (_context30) {
1940
+ while (1) switch (_context30.prev = _context30.next) {
1941
+ case 0:
1942
+ statusPayload = {
1943
+ statusCode: 403,
1944
+ body: mockStatusBody
1945
+ };
1946
+ dummyEvent = {
1947
+ type: 'E_SEND_ROAP_OFFER',
1948
+ data: {
1949
+ seq: 1,
1950
+ type: 'OFFER'
1951
+ }
1952
+ };
1953
+ webex.request.mockReturnValue(statusPayload);
1954
+ call['callStateMachine'].state.value = 'S_RECV_CALL_PROGRESS';
1955
+ call['mediaStateMachine'].state.value = 'S_ROAP_IDLE';
1956
+ call.sendMediaStateMachineEvt(dummyEvent);
1957
+ /* since there is no sdp, mediaMachine should remain in same state
1958
+ and an initiateOffer request to be sent to SDK only once */
1959
+ expect(call['mediaStateMachine'].state.value).toBe('S_SEND_ROAP_OFFER');
1960
+ expect(_testUtil.mediaConnection.initiateOffer).toBeCalledOnceWith();
1961
+ case 1:
1962
+ case "end":
1963
+ return _context30.stop();
1964
+ }
1965
+ }, _callee30);
1966
+ })));
1967
+ it('Outgoing Roap offer retry-after error case during midcall', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee31() {
1968
+ var statusPayload, funcSpy, stateMachineSpy, dummyEvent;
1969
+ return _regenerator.default.wrap(function (_context31) {
1970
+ while (1) switch (_context31.prev = _context31.next) {
1971
+ case 0:
1972
+ statusPayload = {
1973
+ statusCode: 503,
1974
+ headers: {
1975
+ 'retry-after': 1
1976
+ },
1977
+ body: mockStatusBody
1978
+ };
1979
+ jest.spyOn(global, 'setTimeout');
1980
+ funcSpy = jest.spyOn(call, 'postMedia').mockRejectedValueOnce(statusPayload);
1981
+ stateMachineSpy = jest.spyOn(call, 'sendMediaStateMachineEvt');
1982
+ dummyEvent = {
1983
+ type: 'E_SEND_ROAP_OFFER',
1984
+ data: {
1985
+ seq: 1,
1986
+ message: {},
1987
+ type: 'OFFER',
1988
+ sdp: 'sdp'
1989
+ }
1990
+ };
1991
+ call['connected'] = true;
1992
+ _context31.next = 1;
1993
+ return call['handleOutgoingRoapOffer']({}, dummyEvent);
1994
+ case 1:
1995
+ jest.advanceTimersByTime(1005);
1996
+ expect(setTimeout).toHaveBeenCalledTimes(1);
1997
+ expect(funcSpy).toHaveBeenCalledWith(dummyEvent.data);
1998
+
1999
+ /* first failure , and second because of retry-after */
2000
+ expect(funcSpy).toHaveBeenCalledTimes(2);
2001
+ expect(stateMachineSpy).toBeCalledOnceWith(dummyEvent);
2002
+ case 2:
2003
+ case "end":
2004
+ return _context31.stop();
2005
+ }
2006
+ }, _callee31);
2007
+ })));
2008
+ it('Outgoing Roap offer retry-after error case during call establishment', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee32() {
2009
+ var statusPayload, funcSpy, stateMachineSpy, dummyEvent;
2010
+ return _regenerator.default.wrap(function (_context32) {
2011
+ while (1) switch (_context32.prev = _context32.next) {
2012
+ case 0:
2013
+ statusPayload = {
2014
+ statusCode: 503,
2015
+ headers: {
2016
+ 'retry-after': 1
2017
+ },
2018
+ body: mockStatusBody
2019
+ };
2020
+ jest.spyOn(global, 'setTimeout');
2021
+ funcSpy = jest.spyOn(call, 'postMedia').mockRejectedValueOnce(statusPayload);
2022
+ stateMachineSpy = jest.spyOn(call, 'sendMediaStateMachineEvt');
2023
+ dummyEvent = {
2024
+ type: 'E_SEND_ROAP_OFFER',
2025
+ data: {
2026
+ seq: 1,
2027
+ message: {},
2028
+ type: 'OFFER',
2029
+ sdp: 'sdp'
2030
+ }
2031
+ };
2032
+ call['connected'] = false;
2033
+ _context32.next = 1;
2034
+ return call['handleOutgoingRoapOffer']({}, dummyEvent);
2035
+ case 1:
2036
+ jest.advanceTimersByTime(1005);
2037
+ expect(funcSpy).toBeCalledOnceWith(dummyEvent.data);
2038
+
2039
+ /* These shouldn't be called as call is not connected yet */
2040
+ expect(setTimeout).not.toHaveBeenCalled();
2041
+ expect(stateMachineSpy).not.toBeCalled();
2042
+ case 2:
2043
+ case "end":
2044
+ return _context32.stop();
2045
+ }
2046
+ }, _callee32);
2047
+ })));
2048
+ it('Outgoing Roap Answer retry-after error case during midcall', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee33() {
2049
+ var statusPayload, funcSpy, stateMachineSpy, dummyEvent;
2050
+ return _regenerator.default.wrap(function (_context33) {
2051
+ while (1) switch (_context33.prev = _context33.next) {
2052
+ case 0:
2053
+ statusPayload = {
2054
+ statusCode: 503,
2055
+ headers: {
2056
+ 'retry-after': 1
2057
+ },
2058
+ body: mockStatusBody
2059
+ };
2060
+ jest.spyOn(global, 'setTimeout');
2061
+ funcSpy = jest.spyOn(call, 'postMedia').mockRejectedValueOnce(statusPayload);
2062
+ stateMachineSpy = jest.spyOn(call, 'sendMediaStateMachineEvt');
2063
+ dummyEvent = {
2064
+ type: 'E_SEND_ROAP_ANSWER',
2065
+ data: {
2066
+ seq: 1,
2067
+ message: {},
2068
+ type: 'OFFER'
2069
+ }
2070
+ };
2071
+ call['connected'] = true;
2072
+ call['mediaStateMachine'].state.value = 'S_RECV_ROAP_OFFER';
2073
+ _context33.next = 1;
2074
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
2075
+ case 1:
2076
+ jest.advanceTimersByTime(1005);
2077
+ expect(setTimeout).toHaveBeenCalledTimes(1);
2078
+ expect(funcSpy).toHaveBeenCalledWith(dummyEvent.data);
2079
+
2080
+ /* first failure , and second because of retry-after */
2081
+ expect(funcSpy).toHaveBeenCalledTimes(2);
2082
+ expect(stateMachineSpy).toBeCalledOnceWith(dummyEvent);
2083
+ case 2:
2084
+ case "end":
2085
+ return _context33.stop();
2086
+ }
2087
+ }, _callee33);
2088
+ })));
2089
+ it('Outgoing Roap answer retry-after error case during call establishment', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee34() {
2090
+ var statusPayload, funcSpy, stateMachineSpy, dummyEvent;
2091
+ return _regenerator.default.wrap(function (_context34) {
2092
+ while (1) switch (_context34.prev = _context34.next) {
2093
+ case 0:
2094
+ statusPayload = {
2095
+ statusCode: 503,
2096
+ headers: {
2097
+ 'retry-after': 1
2098
+ },
2099
+ body: mockStatusBody
2100
+ };
2101
+ jest.spyOn(global, 'setTimeout');
2102
+ funcSpy = jest.spyOn(call, 'postMedia').mockRejectedValueOnce(statusPayload);
2103
+ stateMachineSpy = jest.spyOn(call, 'sendMediaStateMachineEvt');
2104
+ dummyEvent = {
2105
+ type: 'E_SEND_ROAP_ANSWER',
2106
+ data: {
2107
+ seq: 1,
2108
+ message: {},
2109
+ type: 'OFFER'
2110
+ }
2111
+ };
2112
+ call['connected'] = false;
2113
+ _context34.next = 1;
2114
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
2115
+ case 1:
2116
+ jest.advanceTimersByTime(1005);
2117
+ expect(funcSpy).toBeCalledOnceWith(dummyEvent.data);
2118
+ expect(funcSpy).toHaveBeenCalledTimes(1);
2119
+
2120
+ /* These shouldn't be called as call is not connected yet */
2121
+ expect(setTimeout).not.toHaveBeenCalled();
2122
+ expect(stateMachineSpy).not.toBeCalled();
2123
+ case 2:
2124
+ case "end":
2125
+ return _context34.stop();
2126
+ }
2127
+ }, _callee34);
2128
+ })));
2129
+ it('ROAP error during mid call', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee35() {
2130
+ var statusPayload, warnSpy, stateMachineSpy, funcSpy, errorEvent;
2131
+ return _regenerator.default.wrap(function (_context35) {
2132
+ while (1) switch (_context35.prev = _context35.next) {
2133
+ case 0:
2134
+ statusPayload = {
2135
+ statusCode: 200,
2136
+ body: mockStatusBody
2137
+ };
2138
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
2139
+ stateMachineSpy = jest.spyOn(call, 'sendCallStateMachineEvt');
2140
+ funcSpy = jest.spyOn(call, 'postMedia').mockResolvedValue(statusPayload);
2141
+ errorEvent = {
2142
+ type: 'E_ROAP_ERROR',
2143
+ data: {
2144
+ seq: 2,
2145
+ messageType: 'ERROR',
2146
+ errorType: 'OUT_OF_ORDER'
2147
+ }
2148
+ };
2149
+ call['mediaStateMachine'].state.value = 'S_SEND_ROAP_ANSWER';
2150
+ call['connected'] = true;
2151
+ call.sendMediaStateMachineEvt(errorEvent);
2152
+ expect(funcSpy).toBeCalledOnceWith(errorEvent.data);
2153
+ expect(warnSpy).not.toHaveBeenCalled();
2154
+ expect(stateMachineSpy).not.toHaveBeenCalled();
2155
+ case 1:
2156
+ case "end":
2157
+ return _context35.stop();
2158
+ }
2159
+ }, _callee35);
2160
+ })));
2161
+ it('ROAP ok retry-after during mid call', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee36() {
2162
+ var statusPayload, funcSpy, stateMachineSpy, dummyEvent;
2163
+ return _regenerator.default.wrap(function (_context36) {
2164
+ while (1) switch (_context36.prev = _context36.next) {
2165
+ case 0:
2166
+ statusPayload = {
2167
+ statusCode: 503,
2168
+ headers: {
2169
+ 'retry-after': 1
2170
+ },
2171
+ body: mockStatusBody
2172
+ };
2173
+ jest.spyOn(global, 'setTimeout');
2174
+ funcSpy = jest.spyOn(call, 'postMedia').mockRejectedValueOnce(statusPayload);
2175
+ stateMachineSpy = jest.spyOn(call, 'sendMediaStateMachineEvt');
2176
+ dummyEvent = {
2177
+ type: 'E_ROAP_OK',
2178
+ data: {
2179
+ seq: 1,
2180
+ message: {},
2181
+ type: 'OK'
2182
+ }
2183
+ };
2184
+ call['connected'] = true;
2185
+ call['mediaStateMachine'].state.value = 'S_RECV_ROAP_ANSWER';
2186
+ _context36.next = 1;
2187
+ return call['handleRoapEstablished']({}, dummyEvent);
2188
+ case 1:
2189
+ jest.advanceTimersByTime(1005);
2190
+ expect(setTimeout).toHaveBeenCalledTimes(1);
2191
+ expect(funcSpy).toHaveBeenCalled();
2192
+
2193
+ /* first failure , and second because of retry-after */
2194
+ expect(funcSpy).toHaveBeenCalledTimes(2);
2195
+ expect(stateMachineSpy).toBeCalledOnceWith(dummyEvent);
2196
+ case 2:
2197
+ case "end":
2198
+ return _context36.stop();
2199
+ }
2200
+ }, _callee36);
2201
+ })));
2202
+ it('Unable to communicate roap error with mobius', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee37() {
2203
+ var statusPayload, stateMachineSpy, funcSpy, errorEvent;
2204
+ return _regenerator.default.wrap(function (_context37) {
2205
+ while (1) switch (_context37.prev = _context37.next) {
2206
+ case 0:
2207
+ statusPayload = {
2208
+ statusCode: 403,
2209
+ body: mockStatusBody
2210
+ };
2211
+ stateMachineSpy = jest.spyOn(call, 'sendCallStateMachineEvt');
2212
+ funcSpy = jest.spyOn(call, 'postMedia').mockRejectedValue(statusPayload);
2213
+ errorEvent = {
2214
+ type: 'E_ROAP_ERROR',
2215
+ data: {
2216
+ seq: 2,
2217
+ messageType: 'ERROR',
2218
+ errorType: 'OUT_OF_ORDER'
2219
+ }
2220
+ };
2221
+ call['mediaStateMachine'].state.value = 'S_SEND_ROAP_ANSWER';
2222
+ call['connected'] = true;
2223
+ call.sendMediaStateMachineEvt(errorEvent);
2224
+ expect(funcSpy).toBeCalledOnceWith(errorEvent.data);
2225
+ expect(stateMachineSpy).not.toHaveBeenCalled();
2226
+ case 1:
2227
+ case "end":
2228
+ return _context37.stop();
2229
+ }
2230
+ }, _callee37);
2231
+ })));
2232
+ it('ROAP error during call establishment', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee38() {
2233
+ var statusPayload, warnSpy, stateMachineSpy, funcSpy, errorEvent;
2234
+ return _regenerator.default.wrap(function (_context38) {
2235
+ while (1) switch (_context38.prev = _context38.next) {
2236
+ case 0:
2237
+ statusPayload = {
2238
+ statusCode: 200,
2239
+ body: mockStatusBody
2240
+ };
2241
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
2242
+ stateMachineSpy = jest.spyOn(call, 'sendCallStateMachineEvt');
2243
+ funcSpy = jest.spyOn(call, 'postMedia').mockResolvedValue(statusPayload);
2244
+ errorEvent = {
2245
+ type: 'E_ROAP_ERROR',
2246
+ data: {
2247
+ seq: 2,
2248
+ messageType: 'ERROR',
2249
+ errorType: 'OUT_OF_ORDER'
2250
+ }
2251
+ };
2252
+ call['connected'] = false;
2253
+ _context38.next = 1;
2254
+ return call['handleRoapError']({}, errorEvent);
2255
+ case 1:
2256
+ expect(funcSpy).toBeCalledOnceWith(errorEvent.data);
2257
+ expect(warnSpy).toBeCalledOnceWith('Call failed due to media issue', {
2258
+ file: 'call',
2259
+ method: 'handleRoapError'
2260
+ });
2261
+ expect(stateMachineSpy).toBeCalledOnceWith({
2262
+ data: {
2263
+ media: true
2264
+ },
2265
+ type: 'E_UNKNOWN'
2266
+ });
2267
+ case 2:
2268
+ case "end":
2269
+ return _context38.stop();
2270
+ }
2271
+ }, _callee38);
2272
+ })));
2273
+ it('incoming call: failing ROAP_ANSWER posts error path and tears down', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee39() {
2274
+ var statusPayload, warnSpy, postMediaSpy, setupEvent, connectEvent, offerEvent, answerEvent;
2275
+ return _regenerator.default.wrap(function (_context39) {
2276
+ while (1) switch (_context39.prev = _context39.next) {
2277
+ case 0:
2278
+ statusPayload = {
2279
+ statusCode: 403,
2280
+ body: mockStatusBody
2281
+ };
2282
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
2283
+ postMediaSpy = jest.spyOn(call, 'postMedia').mockRejectedValueOnce(statusPayload); // Simulate inbound call flow
2284
+ call['direction'] = _types3.CallDirection.INBOUND;
2285
+ setupEvent = {
2286
+ type: 'E_RECV_CALL_SETUP',
2287
+ data: {
2288
+ seq: 1,
2289
+ messageType: 'OFFER'
2290
+ }
2291
+ };
2292
+ call.sendCallStateMachineEvt(setupEvent);
2293
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_PROGRESS');
2294
+ connectEvent = {
2295
+ type: 'E_SEND_CALL_CONNECT'
2296
+ };
2297
+ call.sendCallStateMachineEvt(connectEvent);
2298
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_CONNECT');
2299
+ offerEvent = {
2300
+ type: 'E_RECV_ROAP_OFFER',
2301
+ data: {
2302
+ seq: 1,
2303
+ messageType: 'OFFER'
2304
+ }
2305
+ };
2306
+ call.sendMediaStateMachineEvt(offerEvent);
2307
+ answerEvent = {
2308
+ type: 'E_SEND_ROAP_ANSWER',
2309
+ data: {
2310
+ seq: 1,
2311
+ messageType: 'ANSWER'
2312
+ }
2313
+ };
2314
+ _context39.next = 1;
2315
+ return call.sendMediaStateMachineEvt(answerEvent);
2316
+ case 1:
2317
+ _context39.next = 2;
2318
+ return (0, _testUtil.flushPromises)(2);
2319
+ case 2:
2320
+ _context39.next = 3;
2321
+ return _promise.default.resolve();
2322
+ case 3:
2323
+ _context39.next = 4;
2324
+ return _promise.default.resolve();
2325
+ case 4:
2326
+ expect(postMediaSpy).toBeCalledOnceWith(answerEvent.data);
2327
+ expect(warnSpy).toHaveBeenCalledWith('Failed to send MediaAnswer request', {
2328
+ file: 'call',
2329
+ method: 'handleOutgoingRoapAnswer'
2330
+ });
2331
+ expect(warnSpy).toHaveBeenCalledWith('Call failed due to media issue', {
2332
+ file: 'call',
2333
+ method: 'handleRoapError'
2334
+ });
2335
+
2336
+ // Final state should be torn down and cleared for unconnected call
2337
+ expect(call['mediaStateMachine'].state.value).toBe('S_ROAP_TEARDOWN');
2338
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_CLEARED');
2339
+ case 5:
2340
+ case "end":
2341
+ return _context39.stop();
2342
+ }
2343
+ }, _callee39);
2344
+ })));
2345
+ it('state changes during successful incoming call with out of order events', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee40() {
2346
+ var statusPayload, dummyEvent, postMediaSpy, dummyOkEvent, dummyOfferEvent;
2347
+ return _regenerator.default.wrap(function (_context40) {
2348
+ while (1) switch (_context40.prev = _context40.next) {
2349
+ case 0:
2350
+ statusPayload = {
2351
+ statusCode: 200,
2352
+ body: mockStatusBody
2353
+ };
2354
+ dummyEvent = {
2355
+ type: 'E_RECV_CALL_SETUP',
2356
+ data: {
2357
+ seq: 1,
2358
+ messageType: 'OFFER'
2359
+ }
2360
+ };
2361
+ postMediaSpy = jest.spyOn(call, 'postMedia');
2362
+ webex.request.mockReturnValue(statusPayload);
2363
+ call['direction'] = _types3.CallDirection.INBOUND;
2364
+ call.sendCallStateMachineEvt(dummyEvent);
2365
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_PROGRESS');
2366
+ dummyEvent.type = 'E_SEND_CALL_CONNECT';
2367
+ call.sendCallStateMachineEvt(dummyEvent);
2368
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_CONNECT');
2369
+
2370
+ /* we should expect to forward the roap offer message to mediaSdk for further processing */
2371
+ dummyEvent.type = 'E_RECV_ROAP_OFFER';
2372
+ call.sendMediaStateMachineEvt(dummyEvent);
2373
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2374
+
2375
+ /* expect sending roap answer to mobius */
2376
+ dummyEvent.type = 'E_SEND_ROAP_ANSWER';
2377
+ dummyEvent.data = {
2378
+ seq: 1,
2379
+ messageType: 'ANSWER'
2380
+ };
2381
+ _context40.next = 1;
2382
+ return call.sendMediaStateMachineEvt(dummyEvent);
2383
+ case 1:
2384
+ expect(postMediaSpy).toBeCalledOnceWith(dummyEvent.data);
2385
+
2386
+ /* we receive roap Offer Request followed by roap Ok from mobius and handle
2387
+ out of order events by buffering and processing them in sequence */
2388
+ dummyOkEvent = {
2389
+ type: 'E_ROAP_OK',
2390
+ data: {
2391
+ received: true,
2392
+ message: {
2393
+ seq: 1,
2394
+ messageType: 'OK'
2395
+ }
2396
+ }
2397
+ };
2398
+ dummyEvent.type = 'E_RECV_ROAP_OFFER_REQUEST';
2399
+ dummyEvent.data = {
2400
+ seq: 2,
2401
+ messageType: 'OFFER_REQUEST'
2402
+ };
2403
+ _context40.next = 2;
2404
+ return call.sendMediaStateMachineEvt(dummyEvent);
2405
+ case 2:
2406
+ expect(call['receivedRoapOKSeq']).toBe(0);
2407
+ expect(_testUtil.mediaConnection.roapMessageReceived).not.toHaveBeenLastCalledWith(dummyEvent.data);
2408
+ call.sendMediaStateMachineEvt(dummyOkEvent);
2409
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenNthCalledWith(2, dummyOkEvent.data.message);
2410
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2411
+ dummyOfferEvent = {
2412
+ type: 'E_SEND_ROAP_OFFER',
2413
+ data: {
2414
+ seq: 2,
2415
+ messageType: 'OFFER',
2416
+ sdp: 'sdp'
2417
+ }
2418
+ };
2419
+ expect(call['mediaStateMachine'].state.value).toBe('S_RECV_ROAP_OFFER_REQUEST');
2420
+ call.sendMediaStateMachineEvt(dummyOfferEvent);
2421
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyOfferEvent.data);
2422
+ dummyEvent.type = 'E_RECV_ROAP_ANSWER';
2423
+ dummyEvent.data = {
2424
+ seq: 2,
2425
+ messageType: 'ANSWER'
2426
+ };
2427
+ call.sendMediaStateMachineEvt(dummyEvent);
2428
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2429
+ dummyOkEvent.data = {
2430
+ received: false,
2431
+ message: {
2432
+ seq: 2,
2433
+ messageType: 'OK'
2434
+ }
2435
+ };
2436
+ call.sendMediaStateMachineEvt(dummyOkEvent);
2437
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyOkEvent.data.message);
2438
+
2439
+ /* With the two roap offer/answer transactions that we simulated earlier
2440
+ we get a total 4 outgoing and 3 incoming roap messages.
2441
+ */
2442
+ expect(postMediaSpy).toBeCalledTimes(3);
2443
+ expect(_testUtil.mediaConnection.roapMessageReceived).toBeCalledTimes(4);
2444
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_ESTABLISHED');
2445
+ expect(call.isConnected()).toBe(true);
2446
+ dummyEvent.type = 'E_CALL_HOLD';
2447
+ dummyEvent.data = {
2448
+ seq: 3,
2449
+ messageType: 'OFFER'
2450
+ };
2451
+ call.sendCallStateMachineEvt(dummyEvent);
2452
+ dummyEvent.type = 'E_RECV_ROAP_OFFER';
2453
+ _context40.next = 3;
2454
+ return call.sendMediaStateMachineEvt(dummyEvent);
2455
+ case 3:
2456
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2457
+ dummyEvent.type = 'E_SEND_ROAP_ANSWER';
2458
+ dummyEvent.data = {
2459
+ seq: 3,
2460
+ messageType: 'ANSWER'
2461
+ };
2462
+ _context40.next = 4;
2463
+ return call.sendMediaStateMachineEvt(dummyEvent);
2464
+ case 4:
2465
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyEvent.data);
2466
+ dummyEvent.type = 'E_RECV_ROAP_OFFER';
2467
+ dummyEvent.data = {
2468
+ seq: 4,
2469
+ messageType: 'OFFER'
2470
+ };
2471
+ call.sendMediaStateMachineEvt(dummyEvent);
2472
+ expect(call['receivedRoapOKSeq']).toBe(2);
2473
+ expect(_testUtil.mediaConnection.roapMessageReceived).not.toHaveBeenLastCalledWith(dummyEvent.data);
2474
+ dummyOkEvent.data = {
2475
+ received: true,
2476
+ message: {
2477
+ seq: 3,
2478
+ messageType: 'OK'
2479
+ }
2480
+ };
2481
+ _context40.next = 5;
2482
+ return call.sendMediaStateMachineEvt(dummyOkEvent);
2483
+ case 5:
2484
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenNthCalledWith(6, dummyOkEvent.data.message);
2485
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2486
+ dummyEvent.type = 'E_SEND_ROAP_ANSWER';
2487
+ dummyEvent.data = {
2488
+ seq: 4,
2489
+ messageType: 'ANSWER'
2490
+ };
2491
+ expect(call['mediaStateMachine'].state.value).toBe('S_RECV_ROAP_OFFER');
2492
+ call.sendMediaStateMachineEvt(dummyEvent);
2493
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyEvent.data);
2494
+ case 6:
2495
+ case "end":
2496
+ return _context40.stop();
2497
+ }
2498
+ }, _callee40);
2499
+ })));
2500
+ it('successfully handles out of order events when ROAP OK is received while executing outgoingRoapAnswer', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee41() {
2501
+ var mockStatusBody, statusPayload, dummyEvent, postMediaSpy, dummyOkEvent, dummyOfferEvent;
2502
+ return _regenerator.default.wrap(function (_context41) {
2503
+ while (1) switch (_context41.prev = _context41.next) {
2504
+ case 0:
2505
+ mockStatusBody = {
2506
+ device: {
2507
+ deviceId: '123e4567-e89b-12d3-a456-426614174000',
2508
+ correlationId: 'b5476d4c-f48b-475e-b4e2-994e24d14ca2'
2509
+ },
2510
+ callId: 'fcf86aa5-5539-4c9f-8b72-667786ae9b6c'
2511
+ };
2512
+ statusPayload = {
2513
+ statusCode: 200,
2514
+ body: mockStatusBody
2515
+ };
2516
+ dummyEvent = {
2517
+ type: 'E_RECV_CALL_SETUP',
2518
+ data: {
2519
+ seq: 1,
2520
+ messageType: 'OFFER'
2521
+ }
2522
+ };
2523
+ postMediaSpy = jest.spyOn(call, 'postMedia');
2524
+ webex.request.mockReturnValue(statusPayload);
2525
+ call['direction'] = _types3.CallDirection.INBOUND;
2526
+ call.sendCallStateMachineEvt(dummyEvent);
2527
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_PROGRESS');
2528
+ dummyEvent.type = 'E_SEND_CALL_CONNECT';
2529
+ call.sendCallStateMachineEvt(dummyEvent);
2530
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_CONNECT');
2531
+
2532
+ /* we should expect to forward the roap offer message to mediaSdk for further processing */
2533
+ dummyEvent.type = 'E_RECV_ROAP_OFFER';
2534
+ call.sendMediaStateMachineEvt(dummyEvent);
2535
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2536
+
2537
+ /* expect sending roap answer to mobius */
2538
+ dummyEvent.type = 'E_SEND_ROAP_ANSWER';
2539
+ dummyEvent.data = {
2540
+ seq: 1,
2541
+ messageType: 'ANSWER'
2542
+ };
2543
+ _context41.next = 1;
2544
+ return call.sendMediaStateMachineEvt(dummyEvent);
2545
+ case 1:
2546
+ expect(postMediaSpy).toBeCalledOnceWith(dummyEvent.data);
2547
+
2548
+ /* we receive roap Offer Request followed by roap Ok from mobius and handle
2549
+ out of order events by buffering and processing them in sequence */
2550
+ dummyOkEvent = {
2551
+ type: 'E_ROAP_OK',
2552
+ data: {
2553
+ received: true,
2554
+ message: {
2555
+ seq: 1,
2556
+ messageType: 'OK'
2557
+ }
2558
+ }
2559
+ };
2560
+ dummyEvent.type = 'E_RECV_ROAP_OFFER_REQUEST';
2561
+ dummyEvent.data = {
2562
+ seq: 2,
2563
+ messageType: 'OFFER_REQUEST'
2564
+ };
2565
+ _context41.next = 2;
2566
+ return call.sendMediaStateMachineEvt(dummyEvent);
2567
+ case 2:
2568
+ expect(call['receivedRoapOKSeq']).toBe(0);
2569
+ expect(_testUtil.mediaConnection.roapMessageReceived).not.toHaveBeenLastCalledWith(dummyEvent.data);
2570
+ call.sendMediaStateMachineEvt(dummyOkEvent);
2571
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenNthCalledWith(2, dummyOkEvent.data.message);
2572
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2573
+ dummyOfferEvent = {
2574
+ type: 'E_SEND_ROAP_OFFER',
2575
+ data: {
2576
+ seq: 2,
2577
+ messageType: 'OFFER',
2578
+ sdp: 'sdp'
2579
+ }
2580
+ };
2581
+ expect(call['mediaStateMachine'].state.value).toBe('S_RECV_ROAP_OFFER_REQUEST');
2582
+ call.sendMediaStateMachineEvt(dummyOfferEvent);
2583
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyOfferEvent.data);
2584
+ dummyEvent.type = 'E_RECV_ROAP_ANSWER';
2585
+ dummyEvent.data = {
2586
+ seq: 2,
2587
+ messageType: 'ANSWER'
2588
+ };
2589
+ call.sendMediaStateMachineEvt(dummyEvent);
2590
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2591
+ dummyOkEvent.data = {
2592
+ received: false,
2593
+ message: {
2594
+ seq: 2,
2595
+ messageType: 'OK'
2596
+ }
2597
+ };
2598
+ call.sendMediaStateMachineEvt(dummyOkEvent);
2599
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyOkEvent.data.message);
2600
+
2601
+ /* With the two roap offer/answer transactions that we simulated earlier
2602
+ we get a total 4 outgoing and 3 incoming roap messages.
2603
+ */
2604
+ expect(postMediaSpy).toBeCalledTimes(3);
2605
+ expect(_testUtil.mediaConnection.roapMessageReceived).toBeCalledTimes(4);
2606
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_ESTABLISHED');
2607
+ expect(call.isConnected()).toBe(true);
2608
+ dummyEvent.type = 'E_CALL_HOLD';
2609
+ dummyEvent.data = {
2610
+ seq: 3,
2611
+ messageType: 'OFFER'
2612
+ };
2613
+ call.sendCallStateMachineEvt(dummyEvent);
2614
+ dummyEvent.type = 'E_RECV_ROAP_OFFER';
2615
+ _context41.next = 3;
2616
+ return call.sendMediaStateMachineEvt(dummyEvent);
2617
+ case 3:
2618
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2619
+ dummyEvent.type = 'E_SEND_ROAP_ANSWER';
2620
+ dummyEvent.data = {
2621
+ seq: 3,
2622
+ messageType: 'ANSWER'
2623
+ };
2624
+ _context41.next = 4;
2625
+ return call.sendMediaStateMachineEvt(dummyEvent);
2626
+ case 4:
2627
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyEvent.data);
2628
+ dummyEvent.type = 'E_RECV_ROAP_OFFER';
2629
+ dummyEvent.data = {
2630
+ seq: 4,
2631
+ messageType: 'OFFER'
2632
+ };
2633
+ dummyOkEvent.data = {
2634
+ received: true,
2635
+ message: {
2636
+ seq: 3,
2637
+ messageType: 'OK'
2638
+ }
2639
+ };
2640
+ call.sendMediaStateMachineEvt(dummyEvent);
2641
+ _context41.next = 5;
2642
+ return call.sendMediaStateMachineEvt(dummyOkEvent);
2643
+ case 5:
2644
+ expect(call['receivedRoapOKSeq']).toBe(3);
2645
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenNthCalledWith(6, dummyOkEvent.data.message);
2646
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2647
+ dummyEvent.type = 'E_SEND_ROAP_ANSWER';
2648
+ dummyEvent.data = {
2649
+ seq: 4,
2650
+ messageType: 'ANSWER'
2651
+ };
2652
+ expect(call['mediaStateMachine'].state.value).toBe('S_RECV_ROAP_OFFER');
2653
+ call.sendMediaStateMachineEvt(dummyEvent);
2654
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyEvent.data);
2655
+ case 6:
2656
+ case "end":
2657
+ return _context41.stop();
2658
+ }
2659
+ }, _callee41);
2660
+ })));
2661
+ it('handle hold event successfully when media received after progress but before connect', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee42() {
2662
+ var statusPayload, dummyEvent, postMediaSpy, infoSpy, dummyOkEvent;
2663
+ return _regenerator.default.wrap(function (_context42) {
2664
+ while (1) switch (_context42.prev = _context42.next) {
2665
+ case 0:
2666
+ statusPayload = {
2667
+ statusCode: 200,
2668
+ body: mockStatusBody
2669
+ };
2670
+ dummyEvent = {
2671
+ type: 'E_SEND_CALL_SETUP',
2672
+ data: {
2673
+ seq: 1,
2674
+ messageType: 'OFFER',
2675
+ sdp: 'sdp'
2676
+ }
2677
+ };
2678
+ postMediaSpy = jest.spyOn(call, 'postMedia');
2679
+ infoSpy = jest.spyOn(_Logger.default, 'info');
2680
+ webex.request.mockReturnValue(statusPayload);
2681
+ call.sendCallStateMachineEvt(dummyEvent);
2682
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_SETUP');
2683
+ dummyEvent.type = 'E_SEND_ROAP_OFFER';
2684
+ call.sendMediaStateMachineEvt(dummyEvent);
2685
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyEvent.data);
2686
+ dummyEvent.type = 'E_RECV_CALL_PROGRESS';
2687
+ dummyEvent.data = undefined;
2688
+ call.sendCallStateMachineEvt(dummyEvent);
2689
+ expect(call['callStateMachine'].state.value).toBe('S_RECV_CALL_PROGRESS');
2690
+ dummyEvent.type = 'E_RECV_ROAP_ANSWER';
2691
+ dummyEvent.data = {
2692
+ seq: 1,
2693
+ messageType: 'ANSWER',
2694
+ sdp: 'sdp'
2695
+ };
2696
+ call.sendMediaStateMachineEvt(dummyEvent);
2697
+ expect(_testUtil.mediaConnection.roapMessageReceived).toHaveBeenLastCalledWith(dummyEvent.data);
2698
+ expect(call['mediaNegotiationCompleted']).toBe(false);
2699
+ dummyOkEvent = {
2700
+ type: 'E_ROAP_OK',
2701
+ data: {
2702
+ received: false,
2703
+ message: {
2704
+ seq: 1,
2705
+ messageType: 'OK'
2706
+ }
2707
+ }
2708
+ };
2709
+ call.sendMediaStateMachineEvt(dummyOkEvent);
2710
+ expect(call['mediaNegotiationCompleted']).toBe(true);
2711
+ expect(postMediaSpy).toHaveBeenLastCalledWith(dummyOkEvent.data.message);
2712
+ dummyEvent.type = 'E_RECV_CALL_CONNECT';
2713
+ dummyEvent.data = undefined;
2714
+ call.sendCallStateMachineEvt(dummyEvent);
2715
+
2716
+ /* Call will move to connect state then immediately move to established state as
2717
+ media negotiation is already completed before connect was received
2718
+ */
2719
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_ESTABLISHED');
2720
+ expect(call.isConnected()).toBe(true);
2721
+ dummyEvent.type = 'E_CALL_HOLD';
2722
+ dummyEvent.data = undefined;
2723
+ call.sendCallStateMachineEvt(dummyEvent);
2724
+ expect(call['callStateMachine'].state.value).toBe('S_CALL_HOLD');
2725
+ expect(infoSpy).toHaveBeenCalledWith("".concat(_constants2.METHOD_START_MESSAGE, " with: ").concat(call.getCorrelationId()), {
2726
+ file: 'call',
2727
+ method: 'handleCallHold'
2728
+ });
2729
+ case 1:
2730
+ case "end":
2731
+ return _context42.stop();
2732
+ }
2733
+ }, _callee42);
2734
+ })));
2735
+ it('emits DISCONNECT before mobius delete request is invoked', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee43() {
2736
+ var emitSpy, deleteSpy;
2737
+ return _regenerator.default.wrap(function (_context43) {
2738
+ while (1) switch (_context43.prev = _context43.next) {
2739
+ case 0:
2740
+ emitSpy = jest.spyOn(call, 'emit');
2741
+ deleteSpy = jest.spyOn(call, 'delete').mockResolvedValue({
2742
+ statusCode: 200
2743
+ });
2744
+ call.sendCallStateMachineEvt({
2745
+ type: 'E_RECV_CALL_DISCONNECT'
2746
+ });
2747
+ _context43.next = 1;
2748
+ return (0, _testUtil.flushPromises)(1);
2749
+ case 1:
2750
+ expect(emitSpy).toHaveBeenCalledWith(_types2.CALL_EVENT_KEYS.DISCONNECT, call.getCorrelationId());
2751
+ expect(deleteSpy).toHaveBeenCalled();
2752
+ expect(emitSpy.mock.invocationCallOrder[0]).toBeLessThan(deleteSpy.mock.invocationCallOrder[0]);
2753
+ case 2:
2754
+ case "end":
2755
+ return _context43.stop();
2756
+ }
2757
+ }, _callee43);
2758
+ })));
2759
+ describe('Call event timers tests', function () {
2760
+ var callManager;
2761
+ beforeEach(function () {
2762
+ jest.useFakeTimers();
2763
+ callManager = (0, _callManager.getCallManager)(webex, defaultServiceIndicator);
2764
+ });
2765
+ afterEach(function () {
2766
+ jest.clearAllTimers();
2767
+ });
2768
+ it('times out if the next event is not received - 60 seconds timeout', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee44() {
2769
+ var statusPayload, dummyEvent, logSpy, emitSpy, deleteSpy, dummyOkEvent;
2770
+ return _regenerator.default.wrap(function (_context44) {
2771
+ while (1) switch (_context44.prev = _context44.next) {
2772
+ case 0:
2773
+ statusPayload = {
2774
+ statusCode: 200,
2775
+ body: mockStatusBody
2776
+ };
2777
+ dummyEvent = {
2778
+ type: 'E_SEND_CALL_SETUP',
2779
+ data: undefined
2780
+ };
2781
+ logSpy = jest.spyOn(_Logger.default, 'warn');
2782
+ emitSpy = jest.spyOn(call, 'emit');
2783
+ deleteSpy = jest.spyOn(call, 'delete');
2784
+ callManager.callCollection = {};
2785
+ webex.request.mockReturnValue(statusPayload);
2786
+
2787
+ // handleOutgoingCallSetup is asynchronous
2788
+ _context44.next = 1;
2789
+ return call.sendCallStateMachineEvt(dummyEvent);
2790
+ case 1:
2791
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_SETUP');
2792
+ dummyEvent.type = 'E_RECV_CALL_PROGRESS';
2793
+ call.sendCallStateMachineEvt(dummyEvent);
2794
+ expect(call['callStateMachine'].state.value).toBe('S_RECV_CALL_PROGRESS');
2795
+
2796
+ // Media setup for the call
2797
+ dummyEvent.type = 'E_SEND_ROAP_OFFER';
2798
+ call.sendMediaStateMachineEvt(dummyEvent);
2799
+ dummyEvent.data = {
2800
+ seq: 1,
2801
+ messageType: 'OFFER',
2802
+ sdp: 'sdp'
2803
+ };
2804
+ call.sendMediaStateMachineEvt(dummyEvent);
2805
+ dummyEvent.type = 'E_RECV_ROAP_ANSWER';
2806
+ call.sendMediaStateMachineEvt(dummyEvent);
2807
+ dummyOkEvent = {
2808
+ type: 'E_ROAP_OK',
2809
+ data: {
2810
+ received: false,
2811
+ message: {
2812
+ seq: 1,
2813
+ messageType: 'OK'
2814
+ }
2815
+ }
2816
+ };
2817
+ call.sendMediaStateMachineEvt(dummyOkEvent);
2818
+ dummyEvent.type = 'E_RECV_ROAP_OFFER_REQUEST';
2819
+ call.sendMediaStateMachineEvt(dummyEvent);
2820
+ dummyEvent.type = 'E_SEND_ROAP_OFFER';
2821
+ call.sendMediaStateMachineEvt(dummyEvent);
2822
+ dummyEvent.type = 'E_RECV_ROAP_ANSWER';
2823
+ logSpy.mockClear();
2824
+ jest.advanceTimersByTime(60000);
2825
+ expect(logSpy.mock.calls[0][0]).toBe('Call timed out');
2826
+ expect(emitSpy).toHaveBeenCalledWith(_types2.CALL_EVENT_KEYS.DISCONNECT, call.getCorrelationId());
2827
+ expect(deleteSpy).toHaveBeenCalledTimes(1);
2828
+ expect(callManager.callCollection).toStrictEqual({});
2829
+ case 2:
2830
+ case "end":
2831
+ return _context44.stop();
2832
+ }
2833
+ }, _callee44);
2834
+ })));
2835
+ it('times out if the next event is not received - 10 seconds timeout', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee45() {
2836
+ var statusPayload, dummyEvent, call, emitSpy, deleteSpy, logSpy;
2837
+ return _regenerator.default.wrap(function (_context45) {
2838
+ while (1) switch (_context45.prev = _context45.next) {
2839
+ case 0:
2840
+ statusPayload = {
2841
+ statusCode: 200,
2842
+ body: mockStatusBody
2843
+ };
2844
+ dummyEvent = {
2845
+ type: 'E_SEND_CALL_SETUP',
2846
+ data: undefined
2847
+ };
2848
+ callManager.callCollection = {};
2849
+ call = callManager.createCall(dest, _types3.CallDirection.OUTBOUND, deviceId, mockLineId);
2850
+ emitSpy = jest.spyOn(call, 'emit');
2851
+ deleteSpy = jest.spyOn(call, 'delete');
2852
+ logSpy = jest.spyOn(_Logger.default, 'warn');
2853
+ webex.request.mockReturnValue(statusPayload);
2854
+ expect((0, _keys.default)(callManager.callCollection)[0]).toBe(call.getCorrelationId());
2855
+
2856
+ // handleOutgoingCallSetup is asynchronous
2857
+ _context45.next = 1;
2858
+ return call.sendCallStateMachineEvt(dummyEvent);
2859
+ case 1:
2860
+ expect(call['callStateMachine'].state.value).toBe('S_SEND_CALL_SETUP');
2861
+ logSpy.mockClear();
2862
+ jest.advanceTimersByTime(10000);
2863
+ expect(logSpy.mock.calls[0][0]).toBe('Call timed out');
2864
+ expect(emitSpy).toHaveBeenCalledWith(_types2.CALL_EVENT_KEYS.DISCONNECT, call.getCorrelationId());
2865
+ expect(deleteSpy).toHaveBeenCalledTimes(1);
2866
+ expect(callManager.callCollection).toStrictEqual({});
2867
+ case 2:
2868
+ case "end":
2869
+ return _context45.stop();
2870
+ }
2871
+ }, _callee45);
2872
+ })));
2873
+ });
2874
+ });
2875
+ describe('Supplementary Services tests', function () {
2876
+ var deviceId = '55dfb53f-bed2-36da-8e85-cee7f02aa68e';
2877
+ var dest = {
2878
+ type: _types3.CallType.URI,
2879
+ address: 'tel:5003'
2880
+ };
2881
+ var mockResponseBody = {
2882
+ device: {
2883
+ deviceId: '123e4567-e89b-12d3-a456-426614174000',
2884
+ correlationId: 'b5476d4c-f48b-475e-b4e2-994e24d14ca2'
2885
+ },
2886
+ callId: 'fcf86aa5-5539-4c9f-8b72-667786ae9b6c'
2887
+ };
2888
+ var call;
2889
+ beforeEach(function () {
2890
+ _request.APIRequest.resetInstance();
2891
+ _request.APIRequest.getInstance({
2892
+ webex: webex,
2893
+ isMobiusSocketEnabled: false
2894
+ });
2895
+ /* Since we are not actually testing from the start of a call , so it's good to set the below
2896
+ * parameters manually
2897
+ */
2898
+
2899
+ call = new _call.Call(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, function () {
2900
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2901
+ var dummy = 10;
2902
+ }, defaultServiceIndicator, dest);
2903
+ call['connected'] = true;
2904
+ call['earlyMedia'] = false;
2905
+
2906
+ /* Also supplementary services will start always from Call_Established state */
2907
+ call['callStateMachine'].state.value = 'S_CALL_ESTABLISHED';
2908
+ call.removeAllListeners(_types2.CALL_EVENT_KEYS.CALL_ERROR);
2909
+ jest.clearAllTimers();
2910
+ jest.useFakeTimers();
2911
+ });
2912
+ describe('Call hold-resume tests', function () {
2913
+ var mockHeldEvent = {
2914
+ eventType: 'callState',
2915
+ eventData: {
2916
+ callState: 'HELD'
2917
+ }
2918
+ };
2919
+ var mockResumeEvent = {
2920
+ eventType: 'callState',
2921
+ eventData: {
2922
+ callState: 'CONNECTED'
2923
+ }
2924
+ };
2925
+ var dummyEvent = {
2926
+ type: 'E_SEND_ROAP_OFFER',
2927
+ data: {
2928
+ seq: 1,
2929
+ message: {},
2930
+ type: 'OFFER'
2931
+ }
2932
+ };
2933
+ beforeEach(function () {
2934
+ call.removeAllListeners();
2935
+ });
2936
+ it('Handle successful Call hold case without delayed http response', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee47() {
2937
+ var responsePayload, warnSpy, roapEvent;
2938
+ return _regenerator.default.wrap(function (_context47) {
2939
+ while (1) switch (_context47.prev = _context47.next) {
2940
+ case 0:
2941
+ expect.assertions(7);
2942
+ responsePayload = {
2943
+ statusCode: 200,
2944
+ body: mockResponseBody
2945
+ };
2946
+ jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
2947
+ jest.spyOn(global, 'setTimeout');
2948
+ jest.spyOn(global, 'clearTimeout');
2949
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
2950
+ call['held'] = false;
2951
+ call.on(_types2.CALL_EVENT_KEYS.HELD, /*#__PURE__*/function () {
2952
+ var _ref56 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee46(correlationId) {
2953
+ return _regenerator.default.wrap(function (_context46) {
2954
+ while (1) switch (_context46.prev = _context46.next) {
2955
+ case 0:
2956
+ expect(correlationId).toStrictEqual(call.getCorrelationId());
2957
+ case 1:
2958
+ case "end":
2959
+ return _context46.stop();
2960
+ }
2961
+ }, _callee46);
2962
+ }));
2963
+ return function (_x) {
2964
+ return _ref56.apply(this, arguments);
2965
+ };
2966
+ }());
2967
+ _context47.next = 1;
2968
+ return call.doHoldResume();
2969
+ case 1:
2970
+ _context47.next = 2;
2971
+ return (0, _testUtil.flushPromises)(2);
2972
+ case 2:
2973
+ expect(setTimeout).toHaveBeenCalledTimes(1);
2974
+ call.handleMidCallEvent(mockHeldEvent);
2975
+
2976
+ /* At this point, the Call State should be S_CALL_HOLD
2977
+ */
2978
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_HOLD');
2979
+
2980
+ /* We simulate the media Connection events manually here as we are not really testing with actual
2981
+ * media.
2982
+ */
2983
+ call['handleIncomingRoapOffer']({}, dummyEvent);
2984
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
2985
+ roapEvent.data.type = 'ANSWER';
2986
+ _context47.next = 3;
2987
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
2988
+ case 3:
2989
+ roapEvent.data.type = 'OK';
2990
+ _context47.next = 4;
2991
+ return call['handleRoapEstablished']({}, dummyEvent);
2992
+ case 4:
2993
+ expect(clearTimeout).toHaveBeenCalledTimes(1);
2994
+ /* isHeld flag should be set and an Hold event should be emitted */
2995
+ expect(call.isHeld()).toStrictEqual(true);
2996
+ /* We should return back to call established state */
2997
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
2998
+ jest.advanceTimersByTime(12000);
2999
+ expect(warnSpy).not.toHaveBeenCalledWith('Hold response timed out', {
3000
+ file: 'call',
3001
+ method: 'handleCallHold'
3002
+ });
3003
+ case 5:
3004
+ case "end":
3005
+ return _context47.stop();
3006
+ }
3007
+ }, _callee47);
3008
+ })));
3009
+ it('Handle successful Call hold case with delayed http response', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee49() {
3010
+ var responsePayload, warnSpy, roapEvent;
3011
+ return _regenerator.default.wrap(function (_context49) {
3012
+ while (1) switch (_context49.prev = _context49.next) {
3013
+ case 0:
3014
+ expect.assertions(8);
3015
+ responsePayload = {
3016
+ statusCode: 200,
3017
+ body: mockResponseBody
3018
+ };
3019
+ jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
3020
+ jest.spyOn(global, 'setTimeout');
3021
+ jest.spyOn(global, 'clearTimeout');
3022
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3023
+ call['held'] = false;
3024
+ call.on(_types2.CALL_EVENT_KEYS.HELD, /*#__PURE__*/function () {
3025
+ var _ref58 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee48(correlationId) {
3026
+ return _regenerator.default.wrap(function (_context48) {
3027
+ while (1) switch (_context48.prev = _context48.next) {
3028
+ case 0:
3029
+ expect(correlationId).toStrictEqual(call.getCorrelationId());
3030
+ case 1:
3031
+ case "end":
3032
+ return _context48.stop();
3033
+ }
3034
+ }, _callee48);
3035
+ }));
3036
+ return function (_x2) {
3037
+ return _ref58.apply(this, arguments);
3038
+ };
3039
+ }());
3040
+ call.doHoldResume();
3041
+ _context49.next = 1;
3042
+ return _promise.default.resolve();
3043
+ case 1:
3044
+ _context49.next = 2;
3045
+ return _promise.default.resolve();
3046
+ case 2:
3047
+ expect(setTimeout).not.toHaveBeenCalled();
3048
+ call.handleMidCallEvent(mockHeldEvent);
3049
+
3050
+ /* At this point, the Call State should be S_CALL_HOLD
3051
+ */
3052
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_HOLD');
3053
+ expect(call.isHeld()).toBe(true);
3054
+ /* We simulate the media Connection events manually here as we are not really testing with actual
3055
+ * media.
3056
+ */
3057
+ call['handleIncomingRoapOffer']({}, dummyEvent);
3058
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
3059
+ roapEvent.data.type = 'ANSWER';
3060
+ _context49.next = 3;
3061
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
3062
+ case 3:
3063
+ roapEvent.data.type = 'OK';
3064
+ _context49.next = 4;
3065
+ return call['handleRoapEstablished']({}, dummyEvent);
3066
+ case 4:
3067
+ expect(clearTimeout).not.toHaveBeenCalled();
3068
+ /* isHeld flag should be set and an Hold event should be emitted */
3069
+ expect(call.isHeld()).toStrictEqual(true);
3070
+ /* We should return back to call established state */
3071
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3072
+ jest.advanceTimersByTime(12000);
3073
+ expect(warnSpy).not.toHaveBeenCalledWith('Hold response timed out', {
3074
+ file: 'call',
3075
+ method: 'handleCallHold'
3076
+ });
3077
+ case 5:
3078
+ case "end":
3079
+ return _context49.stop();
3080
+ }
3081
+ }, _callee49);
3082
+ })));
3083
+ it('Handle failure Call Hold case during signalling', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee51() {
3084
+ var responsePayload;
3085
+ return _regenerator.default.wrap(function (_context51) {
3086
+ while (1) switch (_context51.prev = _context51.next) {
3087
+ case 0:
3088
+ expect.assertions(4);
3089
+ responsePayload = {
3090
+ statusCode: 503,
3091
+ body: mockResponseBody
3092
+ };
3093
+ jest.spyOn(webex, 'request').mockRejectedValue(responsePayload);
3094
+ call['held'] = false;
3095
+ call.on(_types2.CALL_EVENT_KEYS.HOLD_ERROR, /*#__PURE__*/function () {
3096
+ var _ref60 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee50(errObj) {
3097
+ return _regenerator.default.wrap(function (_context50) {
3098
+ while (1) switch (_context50.prev = _context50.next) {
3099
+ case 0:
3100
+ expect(errObj.type).toStrictEqual(_types.ERROR_TYPE.SERVICE_UNAVAILABLE);
3101
+ expect(errObj.message).toStrictEqual('An unknown error occurred. Wait a moment and try again.');
3102
+ case 1:
3103
+ case "end":
3104
+ return _context50.stop();
3105
+ }
3106
+ }, _callee50);
3107
+ }));
3108
+ return function (_x3) {
3109
+ return _ref60.apply(this, arguments);
3110
+ };
3111
+ }());
3112
+ _context51.next = 1;
3113
+ return call.doHoldResume();
3114
+ case 1:
3115
+ _context51.next = 2;
3116
+ return (0, _testUtil.flushPromises)(2);
3117
+ case 2:
3118
+ expect(call.isHeld()).toStrictEqual(false);
3119
+
3120
+ /* At this point , the Call State should transition to S_CALL_ESTABLISHED
3121
+ */
3122
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3123
+ case 3:
3124
+ case "end":
3125
+ return _context51.stop();
3126
+ }
3127
+ }, _callee51);
3128
+ })));
3129
+ it('Handle failure Call Hold case during offer/answer exchange', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee53() {
3130
+ var responsePayload, rejectPayload, roapEvent;
3131
+ return _regenerator.default.wrap(function (_context53) {
3132
+ while (1) switch (_context53.prev = _context53.next) {
3133
+ case 0:
3134
+ expect.assertions(5);
3135
+ responsePayload = {
3136
+ statusCode: 200,
3137
+ body: mockResponseBody
3138
+ };
3139
+ rejectPayload = {
3140
+ statusCode: 503,
3141
+ body: mockResponseBody
3142
+ };
3143
+ jest.spyOn(webex, 'request').mockResolvedValueOnce(responsePayload).mockRejectedValueOnce(rejectPayload);
3144
+ call['held'] = false;
3145
+ call.on(_types2.CALL_EVENT_KEYS.HOLD_ERROR, /*#__PURE__*/function () {
3146
+ var _ref62 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee52(errObj) {
3147
+ return _regenerator.default.wrap(function (_context52) {
3148
+ while (1) switch (_context52.prev = _context52.next) {
3149
+ case 0:
3150
+ expect(errObj.type).toStrictEqual(_types.ERROR_TYPE.SERVICE_UNAVAILABLE);
3151
+ expect(errObj.message).toStrictEqual('An unknown error occurred. Wait a moment and try again.');
3152
+ case 1:
3153
+ case "end":
3154
+ return _context52.stop();
3155
+ }
3156
+ }, _callee52);
3157
+ }));
3158
+ return function (_x4) {
3159
+ return _ref62.apply(this, arguments);
3160
+ };
3161
+ }());
3162
+ call.doHoldResume();
3163
+ _context53.next = 1;
3164
+ return (0, _testUtil.flushPromises)(2);
3165
+ case 1:
3166
+ /* the Call State should transition to S_CALL_ESTABLISHED
3167
+ */
3168
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_HOLD');
3169
+ call['handleIncomingRoapOffer']({}, dummyEvent);
3170
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
3171
+ /* We are intentionally failing the ROAP ANSWER */
3172
+ roapEvent.data.type = 'ANSWER';
3173
+ _context53.next = 2;
3174
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
3175
+ case 2:
3176
+ expect(call.isHeld()).toStrictEqual(false);
3177
+ /* We should return back to call established state */
3178
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3179
+ case 3:
3180
+ case "end":
3181
+ return _context53.stop();
3182
+ }
3183
+ }, _callee53);
3184
+ })));
3185
+ it('Handle failure Call Hold case during roap ok out', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee54() {
3186
+ var responsePayload, warnSpy, roapEvent;
3187
+ return _regenerator.default.wrap(function (_context54) {
3188
+ while (1) switch (_context54.prev = _context54.next) {
3189
+ case 0:
3190
+ responsePayload = {
3191
+ statusCode: 200,
3192
+ body: mockResponseBody
3193
+ };
3194
+ jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
3195
+ jest.spyOn(global, 'setTimeout');
3196
+ jest.spyOn(global, 'clearTimeout');
3197
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3198
+ call['held'] = false;
3199
+ _context54.next = 1;
3200
+ return call.doHoldResume();
3201
+ case 1:
3202
+ _context54.next = 2;
3203
+ return (0, _testUtil.flushPromises)(2);
3204
+ case 2:
3205
+ expect(setTimeout).toHaveBeenCalledTimes(1);
3206
+
3207
+ /* At this point, the Call State should be S_CALL_HOLD
3208
+ */
3209
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_HOLD');
3210
+
3211
+ /* We simulate the media Connection events manually here as we are not really testing with actual
3212
+ * media.
3213
+ */
3214
+ call['handleIncomingRoapOffer']({}, dummyEvent);
3215
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
3216
+ roapEvent.data.type = 'ANSWER';
3217
+ _context54.next = 3;
3218
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
3219
+ case 3:
3220
+ jest.spyOn(webex, 'request').mockRejectedValue({
3221
+ statusCode: 403
3222
+ });
3223
+ roapEvent.data.type = 'OK';
3224
+ _context54.next = 4;
3225
+ return call['handleRoapEstablished']({}, dummyEvent);
3226
+ case 4:
3227
+ /* this is for coverage */
3228
+ call['callStateMachine'].state.value = 'S_CALL_HOLD';
3229
+ _context54.next = 5;
3230
+ return call['handleRoapEstablished']({}, dummyEvent);
3231
+ case 5:
3232
+ expect(call.isHeld()).toStrictEqual(false);
3233
+ /* We should return back to call established state */
3234
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3235
+ expect(warnSpy).toHaveBeenCalledWith('Failed to process MediaOk request', {
3236
+ file: 'call',
3237
+ method: 'handleRoapEstablished'
3238
+ });
3239
+ case 6:
3240
+ case "end":
3241
+ return _context54.stop();
3242
+ }
3243
+ }, _callee54);
3244
+ })));
3245
+ it('Handle failure Call resume case during roap ok out', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee55() {
3246
+ var responsePayload, warnSpy, roapEvent;
3247
+ return _regenerator.default.wrap(function (_context55) {
3248
+ while (1) switch (_context55.prev = _context55.next) {
3249
+ case 0:
3250
+ responsePayload = {
3251
+ statusCode: 200,
3252
+ body: mockResponseBody
3253
+ };
3254
+ jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
3255
+ jest.spyOn(global, 'setTimeout');
3256
+ jest.spyOn(global, 'clearTimeout');
3257
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3258
+ call['held'] = true;
3259
+ _context55.next = 1;
3260
+ return call.doHoldResume();
3261
+ case 1:
3262
+ _context55.next = 2;
3263
+ return (0, _testUtil.flushPromises)(2);
3264
+ case 2:
3265
+ expect(setTimeout).toHaveBeenCalledTimes(1);
3266
+
3267
+ /* At this point, the Call State should be S_CALL_RESUME
3268
+ */
3269
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_RESUME');
3270
+
3271
+ /* We simulate the media Connection events manually here as we are not really testing with actual
3272
+ * media.
3273
+ */
3274
+ call['handleIncomingRoapOffer']({}, dummyEvent);
3275
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
3276
+ roapEvent.data.type = 'ANSWER';
3277
+ _context55.next = 3;
3278
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
3279
+ case 3:
3280
+ jest.spyOn(webex, 'request').mockRejectedValue({
3281
+ statusCode: 403
3282
+ });
3283
+ roapEvent.data.type = 'OK';
3284
+ _context55.next = 4;
3285
+ return call['handleRoapEstablished']({}, dummyEvent);
3286
+ case 4:
3287
+ expect(call.isHeld()).toStrictEqual(true);
3288
+ /* We should return back to call established state */
3289
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3290
+ expect(warnSpy).toHaveBeenCalledWith('Failed to process MediaOk request', {
3291
+ file: 'call',
3292
+ method: 'handleRoapEstablished'
3293
+ });
3294
+ case 5:
3295
+ case "end":
3296
+ return _context55.stop();
3297
+ }
3298
+ }, _callee55);
3299
+ })));
3300
+ it('Handle Call hold case where successful Held response does not come', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee57() {
3301
+ var responsePayload, roapEvent;
3302
+ return _regenerator.default.wrap(function (_context57) {
3303
+ while (1) switch (_context57.prev = _context57.next) {
3304
+ case 0:
3305
+ expect.assertions(5);
3306
+ responsePayload = {
3307
+ statusCode: 200,
3308
+ body: mockResponseBody
3309
+ };
3310
+ jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
3311
+ call['held'] = false;
3312
+ call.on(_types2.CALL_EVENT_KEYS.HOLD_ERROR, /*#__PURE__*/function () {
3313
+ var _ref66 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee56(errObj) {
3314
+ return _regenerator.default.wrap(function (_context56) {
3315
+ while (1) switch (_context56.prev = _context56.next) {
3316
+ case 0:
3317
+ expect(errObj.type).toStrictEqual(_types.ERROR_TYPE.TIMEOUT);
3318
+ expect(errObj.message).toStrictEqual('An error occurred while placing the call on hold. Wait a moment and try again.');
3319
+ case 1:
3320
+ case "end":
3321
+ return _context56.stop();
3322
+ }
3323
+ }, _callee56);
3324
+ }));
3325
+ return function (_x5) {
3326
+ return _ref66.apply(this, arguments);
3327
+ };
3328
+ }());
3329
+ jest.runAllTimers();
3330
+ call.doHoldResume();
3331
+ _context57.next = 1;
3332
+ return (0, _testUtil.flushPromises)(2);
3333
+ case 1:
3334
+ /* At this point, the Call State should be S_CALL_HOLD
3335
+ */
3336
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_HOLD');
3337
+
3338
+ /* We simulate the media Connection events manually here as we are not really testing with actual
3339
+ * media.
3340
+ */
3341
+ call['handleIncomingRoapOffer']({}, dummyEvent);
3342
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
3343
+ roapEvent.data.type = 'ANSWER';
3344
+ _context57.next = 2;
3345
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
3346
+ case 2:
3347
+ roapEvent.data.type = 'OK';
3348
+ _context57.next = 3;
3349
+ return call['handleRoapEstablished']({}, dummyEvent);
3350
+ case 3:
3351
+ /* Advancing timer by 12 seconds so that it gets timed out */
3352
+ jest.advanceTimersByTime(12000);
3353
+
3354
+ /* isHeld flag should be unset */
3355
+ expect(call.isHeld()).toStrictEqual(false);
3356
+ /* We should return back to call established state */
3357
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3358
+ case 4:
3359
+ case "end":
3360
+ return _context57.stop();
3361
+ }
3362
+ }, _callee57);
3363
+ })));
3364
+ it('Handle successful Call Resume case without delayed http response', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee59() {
3365
+ var responsePayload, warnSpy, roapEvent;
3366
+ return _regenerator.default.wrap(function (_context59) {
3367
+ while (1) switch (_context59.prev = _context59.next) {
3368
+ case 0:
3369
+ expect.assertions(7);
3370
+ responsePayload = {
3371
+ statusCode: 200,
3372
+ body: mockResponseBody
3373
+ };
3374
+ jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
3375
+ jest.spyOn(global, 'setTimeout');
3376
+ jest.spyOn(global, 'clearTimeout');
3377
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3378
+ call['held'] = true;
3379
+ call.on(_types2.CALL_EVENT_KEYS.RESUMED, /*#__PURE__*/function () {
3380
+ var _ref68 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee58(correlationId) {
3381
+ return _regenerator.default.wrap(function (_context58) {
3382
+ while (1) switch (_context58.prev = _context58.next) {
3383
+ case 0:
3384
+ expect(correlationId).toStrictEqual(call.getCorrelationId());
3385
+ case 1:
3386
+ case "end":
3387
+ return _context58.stop();
3388
+ }
3389
+ }, _callee58);
3390
+ }));
3391
+ return function (_x6) {
3392
+ return _ref68.apply(this, arguments);
3393
+ };
3394
+ }());
3395
+ _context59.next = 1;
3396
+ return call.doHoldResume();
3397
+ case 1:
3398
+ _context59.next = 2;
3399
+ return (0, _testUtil.flushPromises)(2);
3400
+ case 2:
3401
+ expect(setTimeout).toHaveBeenCalledTimes(1);
3402
+ call.handleMidCallEvent(mockResumeEvent);
3403
+
3404
+ /* At this point ,the Call State should be S_CALL_RESUME
3405
+ */
3406
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_RESUME');
3407
+
3408
+ /* We simulate the media Connection events manually here as we are not really testing with actual
3409
+ * media.
3410
+ */
3411
+ call['handleIncomingRoapOffer']({}, dummyEvent);
3412
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
3413
+ roapEvent.data.type = 'ANSWER';
3414
+ _context59.next = 3;
3415
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
3416
+ case 3:
3417
+ roapEvent.data.type = 'OK';
3418
+ _context59.next = 4;
3419
+ return call['handleRoapEstablished']({}, dummyEvent);
3420
+ case 4:
3421
+ expect(clearTimeout).toHaveBeenCalledTimes(1);
3422
+ /* isHeld flag should not be set and an Resume event should be emitted */
3423
+ expect(call.isHeld()).toStrictEqual(false);
3424
+ /* We should return back to call established state */
3425
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3426
+ jest.advanceTimersByTime(12000);
3427
+ expect(warnSpy).not.toHaveBeenCalledWith('Resume response timed out', {
3428
+ file: 'call',
3429
+ method: 'handleCallResume'
3430
+ });
3431
+ case 5:
3432
+ case "end":
3433
+ return _context59.stop();
3434
+ }
3435
+ }, _callee59);
3436
+ })));
3437
+ it('Handle successful Call Resume case with delayed http response', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee61() {
3438
+ var responsePayload, warnSpy, roapEvent;
3439
+ return _regenerator.default.wrap(function (_context61) {
3440
+ while (1) switch (_context61.prev = _context61.next) {
3441
+ case 0:
3442
+ expect.assertions(7);
3443
+ responsePayload = {
3444
+ statusCode: 200,
3445
+ body: mockResponseBody
3446
+ };
3447
+ jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
3448
+ jest.spyOn(global, 'setTimeout');
3449
+ jest.spyOn(global, 'clearTimeout');
3450
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3451
+ call['held'] = true;
3452
+ call.on(_types2.CALL_EVENT_KEYS.RESUMED, /*#__PURE__*/function () {
3453
+ var _ref70 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee60(correlationId) {
3454
+ return _regenerator.default.wrap(function (_context60) {
3455
+ while (1) switch (_context60.prev = _context60.next) {
3456
+ case 0:
3457
+ expect(correlationId).toStrictEqual(call.getCorrelationId());
3458
+ case 1:
3459
+ case "end":
3460
+ return _context60.stop();
3461
+ }
3462
+ }, _callee60);
3463
+ }));
3464
+ return function (_x7) {
3465
+ return _ref70.apply(this, arguments);
3466
+ };
3467
+ }());
3468
+ call.doHoldResume();
3469
+ _context61.next = 1;
3470
+ return _promise.default.resolve();
3471
+ case 1:
3472
+ _context61.next = 2;
3473
+ return _promise.default.resolve();
3474
+ case 2:
3475
+ expect(setTimeout).not.toHaveBeenCalled();
3476
+ call.handleMidCallEvent(mockResumeEvent);
3477
+
3478
+ /* At this point ,the Call State should be S_CALL_RESUME
3479
+ */
3480
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_RESUME');
3481
+
3482
+ /* We simulate the media Connection events manually here as we are not really testing with actual
3483
+ * media.
3484
+ */
3485
+ call['handleIncomingRoapOffer']({}, dummyEvent);
3486
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
3487
+ roapEvent.data.type = 'ANSWER';
3488
+ _context61.next = 3;
3489
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
3490
+ case 3:
3491
+ roapEvent.data.type = 'OK';
3492
+ _context61.next = 4;
3493
+ return call['handleRoapEstablished']({}, dummyEvent);
3494
+ case 4:
3495
+ expect(clearTimeout).not.toHaveBeenCalled();
3496
+ /* isHeld flag should not be set and an Resume event should be emitted */
3497
+ expect(call.isHeld()).toStrictEqual(false);
3498
+ /* We should return back to call established state */
3499
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3500
+ jest.advanceTimersByTime(12000);
3501
+ expect(warnSpy).not.toHaveBeenCalledWith('Resume response timed out', {
3502
+ file: 'call',
3503
+ method: 'handleCallResume'
3504
+ });
3505
+ case 5:
3506
+ case "end":
3507
+ return _context61.stop();
3508
+ }
3509
+ }, _callee61);
3510
+ })));
3511
+ it('Handle failure Call Resume case during signalling', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee63() {
3512
+ var responsePayload;
3513
+ return _regenerator.default.wrap(function (_context63) {
3514
+ while (1) switch (_context63.prev = _context63.next) {
3515
+ case 0:
3516
+ expect.assertions(4);
3517
+ responsePayload = {
3518
+ statusCode: 503,
3519
+ body: mockResponseBody
3520
+ };
3521
+ jest.spyOn(webex, 'request').mockRejectedValue(responsePayload);
3522
+ call['held'] = true;
3523
+ call.on(_types2.CALL_EVENT_KEYS.RESUME_ERROR, /*#__PURE__*/function () {
3524
+ var _ref72 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee62(errObj) {
3525
+ return _regenerator.default.wrap(function (_context62) {
3526
+ while (1) switch (_context62.prev = _context62.next) {
3527
+ case 0:
3528
+ expect(errObj.type).toStrictEqual(_types.ERROR_TYPE.SERVICE_UNAVAILABLE);
3529
+ expect(errObj.message).toStrictEqual('An unknown error occurred. Wait a moment and try again.');
3530
+ case 1:
3531
+ case "end":
3532
+ return _context62.stop();
3533
+ }
3534
+ }, _callee62);
3535
+ }));
3536
+ return function (_x8) {
3537
+ return _ref72.apply(this, arguments);
3538
+ };
3539
+ }());
3540
+ _context63.next = 1;
3541
+ return call.doHoldResume();
3542
+ case 1:
3543
+ _context63.next = 2;
3544
+ return (0, _testUtil.flushPromises)(2);
3545
+ case 2:
3546
+ expect(call.isHeld()).toStrictEqual(true);
3547
+
3548
+ /* At this point , the Call State should transition to S_CALL_ESTABLISHED
3549
+ */
3550
+
3551
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3552
+ case 3:
3553
+ case "end":
3554
+ return _context63.stop();
3555
+ }
3556
+ }, _callee63);
3557
+ })));
3558
+ it('Handle failure Call Resume case during offer/answer exchange', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee65() {
3559
+ var responsePayload, rejectPayload, roapEvent;
3560
+ return _regenerator.default.wrap(function (_context65) {
3561
+ while (1) switch (_context65.prev = _context65.next) {
3562
+ case 0:
3563
+ expect.assertions(5);
3564
+ responsePayload = {
3565
+ statusCode: 200,
3566
+ body: mockResponseBody
3567
+ };
3568
+ rejectPayload = {
3569
+ statusCode: 503,
3570
+ body: mockResponseBody
3571
+ };
3572
+ jest.spyOn(webex, 'request').mockResolvedValueOnce(responsePayload).mockRejectedValueOnce(rejectPayload);
3573
+ call['held'] = true;
3574
+ call.on(_types2.CALL_EVENT_KEYS.RESUME_ERROR, /*#__PURE__*/function () {
3575
+ var _ref74 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee64(errObj) {
3576
+ return _regenerator.default.wrap(function (_context64) {
3577
+ while (1) switch (_context64.prev = _context64.next) {
3578
+ case 0:
3579
+ expect(errObj.type).toStrictEqual(_types.ERROR_TYPE.SERVICE_UNAVAILABLE);
3580
+ expect(errObj.message).toStrictEqual('An unknown error occurred. Wait a moment and try again.');
3581
+ case 1:
3582
+ case "end":
3583
+ return _context64.stop();
3584
+ }
3585
+ }, _callee64);
3586
+ }));
3587
+ return function (_x9) {
3588
+ return _ref74.apply(this, arguments);
3589
+ };
3590
+ }());
3591
+ call.doHoldResume();
3592
+ _context65.next = 1;
3593
+ return (0, _testUtil.flushPromises)(2);
3594
+ case 1:
3595
+ /* At this point , the Call State should transition to S_CALL_ESTABLISHED
3596
+ */
3597
+
3598
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_RESUME');
3599
+ call['handleIncomingRoapOffer']({}, dummyEvent);
3600
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
3601
+ /* We are intentionally failing the ROAP ANSWER */
3602
+ roapEvent.data.type = 'ANSWER';
3603
+ _context65.next = 2;
3604
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
3605
+ case 2:
3606
+ expect(call.isHeld()).toStrictEqual(true);
3607
+ /* We should return back to call established state */
3608
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3609
+ case 3:
3610
+ case "end":
3611
+ return _context65.stop();
3612
+ }
3613
+ }, _callee65);
3614
+ })));
3615
+ it('Handle Call resume case where successful response does not come', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee67() {
3616
+ var responsePayload, roapEvent;
3617
+ return _regenerator.default.wrap(function (_context67) {
3618
+ while (1) switch (_context67.prev = _context67.next) {
3619
+ case 0:
3620
+ expect.assertions(5);
3621
+ responsePayload = {
3622
+ statusCode: 200,
3623
+ body: mockResponseBody
3624
+ };
3625
+ jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
3626
+ call['held'] = true;
3627
+ call.on(_types2.CALL_EVENT_KEYS.RESUME_ERROR, /*#__PURE__*/function () {
3628
+ var _ref76 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee66(errObj) {
3629
+ return _regenerator.default.wrap(function (_context66) {
3630
+ while (1) switch (_context66.prev = _context66.next) {
3631
+ case 0:
3632
+ expect(errObj.type).toStrictEqual(_types.ERROR_TYPE.TIMEOUT);
3633
+ expect(errObj.message).toStrictEqual('An error occurred while resuming the call. Wait a moment and try again.');
3634
+ case 1:
3635
+ case "end":
3636
+ return _context66.stop();
3637
+ }
3638
+ }, _callee66);
3639
+ }));
3640
+ return function (_x0) {
3641
+ return _ref76.apply(this, arguments);
3642
+ };
3643
+ }());
3644
+ call.doHoldResume();
3645
+ _context67.next = 1;
3646
+ return (0, _testUtil.flushPromises)(2);
3647
+ case 1:
3648
+ /* At this point ,the Call State should be S_CALL_RESUME
3649
+ */
3650
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_RESUME');
3651
+
3652
+ /* We simulate the media Connection events manually here as we are not really testing with actual
3653
+ * media.
3654
+ */
3655
+ call['handleIncomingRoapOffer']({}, dummyEvent);
3656
+ roapEvent = JSON.parse((0, _stringify.default)(dummyEvent));
3657
+ roapEvent.data.type = 'ANSWER';
3658
+ _context67.next = 2;
3659
+ return call['handleOutgoingRoapAnswer']({}, dummyEvent);
3660
+ case 2:
3661
+ roapEvent.data.type = 'OK';
3662
+ _context67.next = 3;
3663
+ return call['handleRoapEstablished']({}, dummyEvent);
3664
+ case 3:
3665
+ /* Advancing timer by 12 seconds so that it gets timed out */
3666
+ jest.advanceTimersByTime(12000);
3667
+ expect(call.isHeld()).toStrictEqual(true);
3668
+ /* We should return back to call established state */
3669
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3670
+ case 4:
3671
+ case "end":
3672
+ return _context67.stop();
3673
+ }
3674
+ }, _callee67);
3675
+ })));
3676
+ });
3677
+ describe('Call transfer tests', function () {
3678
+ var transfereeNumber = '5004';
3679
+ var transfereeDest = {
3680
+ type: _types3.CallType.URI,
3681
+ address: "tel:".concat(transfereeNumber)
3682
+ };
3683
+ var secondCall;
3684
+
3685
+ /* A spy on handleCallErrors to check whether it is being invoked or not depending on tests */
3686
+ var handleErrorSpy = jest.spyOn(Utils, 'handleCallErrors');
3687
+ var uploadLogsSpy = jest.spyOn(Utils, 'uploadLogs');
3688
+ var transferLoggingContext = {
3689
+ file: 'call',
3690
+ method: 'completeTransfer'
3691
+ };
3692
+ beforeEach(function () {
3693
+ /* We will put the first call on hold to perform the transfer */
3694
+ call['held'] = true;
3695
+
3696
+ /* We will create a second call just like the first call, but call is active, i.e, not held */
3697
+ secondCall = new _call.Call(activeUrl, webex, _types3.CallDirection.OUTBOUND, deviceId, mockLineId, function () {
3698
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3699
+ var dummy = 10;
3700
+ }, defaultServiceIndicator, transfereeDest);
3701
+ secondCall['connected'] = true;
3702
+ secondCall['earlyMedia'] = false;
3703
+ secondCall['callStateMachine'].state.value = 'S_CALL_ESTABLISHED';
3704
+ secondCall.removeAllListeners(_types2.CALL_EVENT_KEYS.CALL_ERROR);
3705
+ secondCall['held'] = false;
3706
+ });
3707
+ it('Handle successful consult transfer case ', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee70() {
3708
+ var responsePayload, requestSpy, warnSpy, infoSpy, metricSpy;
3709
+ return _regenerator.default.wrap(function (_context70) {
3710
+ while (1) switch (_context70.prev = _context70.next) {
3711
+ case 0:
3712
+ expect.assertions(12); // Updated to match actual assertion count
3713
+ responsePayload = {
3714
+ statusCode: 200,
3715
+ body: mockResponseBody
3716
+ };
3717
+ requestSpy = jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
3718
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3719
+ infoSpy = jest.spyOn(_Logger.default, 'info');
3720
+ metricSpy = jest.spyOn(call['metricManager'], 'submitCallMetric');
3721
+ call.on(_types2.CALL_EVENT_KEYS.DISCONNECT, /*#__PURE__*/function () {
3722
+ var _ref78 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee68(correlationId) {
3723
+ return _regenerator.default.wrap(function (_context68) {
3724
+ while (1) switch (_context68.prev = _context68.next) {
3725
+ case 0:
3726
+ expect(correlationId).toStrictEqual(call.getCorrelationId());
3727
+ case 1:
3728
+ case "end":
3729
+ return _context68.stop();
3730
+ }
3731
+ }, _callee68);
3732
+ }));
3733
+ return function (_x1) {
3734
+ return _ref78.apply(this, arguments);
3735
+ };
3736
+ }());
3737
+ secondCall.on(_types2.CALL_EVENT_KEYS.DISCONNECT, /*#__PURE__*/function () {
3738
+ var _ref79 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee69(correlationId) {
3739
+ return _regenerator.default.wrap(function (_context69) {
3740
+ while (1) switch (_context69.prev = _context69.next) {
3741
+ case 0:
3742
+ expect(correlationId).toStrictEqual(secondCall.getCorrelationId());
3743
+ case 1:
3744
+ case "end":
3745
+ return _context69.stop();
3746
+ }
3747
+ }, _callee69);
3748
+ }));
3749
+ return function (_x10) {
3750
+ return _ref79.apply(this, arguments);
3751
+ };
3752
+ }());
3753
+ _context70.next = 1;
3754
+ return call.completeTransfer(_types5.TransferType.CONSULT, secondCall.getCallId(), undefined);
3755
+ case 1:
3756
+ _context70.next = 2;
3757
+ return (0, _testUtil.flushPromises)(2);
3758
+ case 2:
3759
+ expect(requestSpy).toBeCalled();
3760
+ expect(metricSpy).toHaveBeenCalledWith(_types4.METRIC_EVENT.CALL, _types4.TRANSFER_ACTION.CONSULT, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId(), undefined);
3761
+ call.sendCallStateMachineEvt({
3762
+ type: 'E_RECV_CALL_DISCONNECT'
3763
+ });
3764
+ secondCall.sendCallStateMachineEvt({
3765
+ type: 'E_RECV_CALL_DISCONNECT'
3766
+ });
3767
+
3768
+ /* We should return back to S_RECV_CALL_DISCONNECT state for both the calls */
3769
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_RECV_CALL_DISCONNECT');
3770
+ expect(secondCall['callStateMachine'].state.value).toStrictEqual('S_RECV_CALL_DISCONNECT');
3771
+ expect(handleErrorSpy).not.toBeCalled();
3772
+ expect(uploadLogsSpy).not.toBeCalled();
3773
+ expect(infoSpy).toHaveBeenCalledWith("Initiating Consult transfer between : ".concat(call.getCallId(), " and ").concat(secondCall.getCallId()), transferLoggingContext);
3774
+ expect(warnSpy).not.toHaveBeenCalledWith("Consult Transfer failed for correlationId ".concat(call.getCorrelationId()), transferLoggingContext);
3775
+ expect(infoSpy).toHaveBeenCalledWith("Initiating Consult transfer between : ".concat(call.getCallId(), " and ").concat(secondCall.getCallId()), transferLoggingContext);
3776
+ expect(warnSpy).not.toHaveBeenCalledWith("Consult Transfer failed for correlationId ".concat(call.getCorrelationId()), transferLoggingContext);
3777
+ case 3:
3778
+ case "end":
3779
+ return _context70.stop();
3780
+ }
3781
+ }, _callee70);
3782
+ })));
3783
+ it('Handle successful blind transfer case ', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee72() {
3784
+ var responsePayload, requestSpy, warnSpy, infoSpy, metricSpy;
3785
+ return _regenerator.default.wrap(function (_context72) {
3786
+ while (1) switch (_context72.prev = _context72.next) {
3787
+ case 0:
3788
+ expect.assertions(10); // Updated to match actual assertion count
3789
+ responsePayload = {
3790
+ statusCode: 200,
3791
+ body: mockResponseBody
3792
+ };
3793
+ requestSpy = jest.spyOn(webex, 'request').mockResolvedValue(responsePayload);
3794
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3795
+ infoSpy = jest.spyOn(_Logger.default, 'info');
3796
+ metricSpy = jest.spyOn(call['metricManager'], 'submitCallMetric');
3797
+ call.on(_types2.CALL_EVENT_KEYS.DISCONNECT, /*#__PURE__*/function () {
3798
+ var _ref81 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee71(correlationId) {
3799
+ return _regenerator.default.wrap(function (_context71) {
3800
+ while (1) switch (_context71.prev = _context71.next) {
3801
+ case 0:
3802
+ expect(correlationId).toStrictEqual(call.getCorrelationId());
3803
+ case 1:
3804
+ case "end":
3805
+ return _context71.stop();
3806
+ }
3807
+ }, _callee71);
3808
+ }));
3809
+ return function (_x11) {
3810
+ return _ref81.apply(this, arguments);
3811
+ };
3812
+ }());
3813
+ _context72.next = 1;
3814
+ return call.completeTransfer(_types5.TransferType.BLIND, undefined, transfereeNumber);
3815
+ case 1:
3816
+ _context72.next = 2;
3817
+ return (0, _testUtil.flushPromises)(2);
3818
+ case 2:
3819
+ expect(requestSpy).toBeCalled();
3820
+ expect(metricSpy).toHaveBeenCalledWith(_types4.METRIC_EVENT.CALL, _types4.TRANSFER_ACTION.BLIND, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId(), undefined);
3821
+ call.sendCallStateMachineEvt({
3822
+ type: 'E_RECV_CALL_DISCONNECT'
3823
+ });
3824
+
3825
+ /* We should return back to S_RECV_CALL_DISCONNECT state */
3826
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_RECV_CALL_DISCONNECT');
3827
+ expect(handleErrorSpy).not.toBeCalled();
3828
+ expect(uploadLogsSpy).not.toBeCalled();
3829
+ expect(infoSpy).toHaveBeenCalledWith("Initiating Blind transfer with : ".concat(transfereeNumber), transferLoggingContext);
3830
+ expect(warnSpy).not.toHaveBeenCalledWith("Blind Transfer failed for correlationId ".concat(call.getCorrelationId()), transferLoggingContext);
3831
+ expect(infoSpy).toHaveBeenCalledWith("Initiating Blind transfer with : ".concat(transfereeNumber), transferLoggingContext);
3832
+ expect(warnSpy).not.toHaveBeenCalledWith("Blind Transfer failed for correlationId ".concat(call.getCorrelationId()), transferLoggingContext);
3833
+ case 3:
3834
+ case "end":
3835
+ return _context72.stop();
3836
+ }
3837
+ }, _callee72);
3838
+ })));
3839
+ it('Handle unsuccessful blind transfer case', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee73() {
3840
+ var responsePayload, emitSpy, requestSpy, warnSpy, metricSpy;
3841
+ return _regenerator.default.wrap(function (_context73) {
3842
+ while (1) switch (_context73.prev = _context73.next) {
3843
+ case 0:
3844
+ responsePayload = {
3845
+ statusCode: 403,
3846
+ body: mockResponseBody
3847
+ };
3848
+ emitSpy = jest.spyOn(call, 'emit');
3849
+ requestSpy = jest.spyOn(webex, 'request').mockRejectedValue(responsePayload);
3850
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3851
+ metricSpy = jest.spyOn(call['metricManager'], 'submitCallMetric');
3852
+ call['broadworksCorrelationInfo'] = 'dummy-broadworks-correlation-info';
3853
+ _context73.next = 1;
3854
+ return call.completeTransfer(_types5.TransferType.BLIND, undefined, transfereeNumber);
3855
+ case 1:
3856
+ _context73.next = 2;
3857
+ return (0, _testUtil.flushPromises)(1);
3858
+ case 2:
3859
+ expect(requestSpy).toBeCalled();
3860
+ /* We should be in CALL_ESTABLISHED state */
3861
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3862
+ expect(call['held']).toBe(true);
3863
+ expect(handleErrorSpy).toHaveBeenCalledWith(expect.anything(), _types.ERROR_LAYER.CALL_CONTROL,
3864
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3865
+ expect.anything(), call.getCorrelationId(), responsePayload, 'completeTransfer', 'call');
3866
+ expect(uploadLogsSpy).toHaveBeenCalledWith({
3867
+ correlationId: call.getCorrelationId(),
3868
+ callId: call.getCallId(),
3869
+ broadworksCorrelationInfo: 'dummy-broadworks-correlation-info'
3870
+ });
3871
+ /* check whether error event is being emitted by sdk */
3872
+ expect(emitSpy).toBeCalledOnceWith(_types2.CALL_EVENT_KEYS.TRANSFER_ERROR, expect.any(_Errors.CallError));
3873
+ expect(warnSpy).toHaveBeenCalledWith("Blind Transfer failed for correlationId ".concat(call.getCorrelationId()), transferLoggingContext);
3874
+ expect(metricSpy).toHaveBeenCalledWith(_types4.METRIC_EVENT.CALL_ERROR, _types4.TRANSFER_ACTION.BLIND, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId(), expect.any(_Errors.CallError));
3875
+ case 3:
3876
+ case "end":
3877
+ return _context73.stop();
3878
+ }
3879
+ }, _callee73);
3880
+ })));
3881
+ it('Handle unsuccessful consult transfer case', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee74() {
3882
+ var responsePayload, emitSpy, requestSpy, warnSpy, metricSpy;
3883
+ return _regenerator.default.wrap(function (_context74) {
3884
+ while (1) switch (_context74.prev = _context74.next) {
3885
+ case 0:
3886
+ responsePayload = {
3887
+ statusCode: 403,
3888
+ body: mockResponseBody
3889
+ };
3890
+ emitSpy = jest.spyOn(call, 'emit');
3891
+ requestSpy = jest.spyOn(webex, 'request').mockRejectedValue(responsePayload);
3892
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3893
+ metricSpy = jest.spyOn(call['metricManager'], 'submitCallMetric');
3894
+ _context74.next = 1;
3895
+ return call.completeTransfer(_types5.TransferType.CONSULT, secondCall.getCallId(), undefined);
3896
+ case 1:
3897
+ _context74.next = 2;
3898
+ return (0, _testUtil.flushPromises)(2);
3899
+ case 2:
3900
+ expect(requestSpy).toBeCalled();
3901
+ /* We should be in CALL_ESTABLISHED state */
3902
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3903
+ expect(call['held']).toBe(true);
3904
+ expect(secondCall['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3905
+ expect(handleErrorSpy).toHaveBeenCalledWith(expect.anything(), _types.ERROR_LAYER.CALL_CONTROL,
3906
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3907
+ expect.anything(), call.getCorrelationId(), responsePayload, 'completeTransfer', 'call');
3908
+ expect(uploadLogsSpy).toHaveBeenCalledWith({
3909
+ correlationId: call.getCorrelationId(),
3910
+ callId: call.getCallId()
3911
+ });
3912
+ /* check whether error event is being emitted by sdk */
3913
+ expect(emitSpy).toHaveBeenCalledWith(_types2.CALL_EVENT_KEYS.TRANSFER_ERROR, expect.any(_Errors.CallError));
3914
+ expect(warnSpy).toHaveBeenCalledWith("Consult Transfer failed for correlationId ".concat(call.getCorrelationId()), transferLoggingContext);
3915
+ expect(metricSpy).toHaveBeenCalledWith(_types4.METRIC_EVENT.CALL_ERROR, _types4.TRANSFER_ACTION.CONSULT, _types4.METRIC_TYPE.BEHAVIORAL, call.getCallId(), call.getCorrelationId(), expect.any(_Errors.CallError));
3916
+ case 3:
3917
+ case "end":
3918
+ return _context74.stop();
3919
+ }
3920
+ }, _callee74);
3921
+ })));
3922
+ it('Handle blind transfer with undefined transferTarget', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee75() {
3923
+ var requestSpy, warnSpy;
3924
+ return _regenerator.default.wrap(function (_context75) {
3925
+ while (1) switch (_context75.prev = _context75.next) {
3926
+ case 0:
3927
+ requestSpy = jest.spyOn(webex, 'request');
3928
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3929
+ _context75.next = 1;
3930
+ return call.completeTransfer(_types5.TransferType.BLIND, undefined, undefined);
3931
+ case 1:
3932
+ /* We should be in CALL_ESTABLISHED state */
3933
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3934
+ expect(secondCall['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3935
+ expect(handleErrorSpy).not.toBeCalled();
3936
+ expect(uploadLogsSpy).not.toBeCalled();
3937
+ expect(requestSpy).not.toBeCalled();
3938
+ expect(warnSpy).toBeCalledOnceWith("Invalid information received, transfer failed for correlationId: ".concat(call.getCorrelationId()), transferLoggingContext);
3939
+ case 2:
3940
+ case "end":
3941
+ return _context75.stop();
3942
+ }
3943
+ }, _callee75);
3944
+ })));
3945
+ it('Handle consult transfer with undefined transferCallId', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee76() {
3946
+ var requestSpy, warnSpy;
3947
+ return _regenerator.default.wrap(function (_context76) {
3948
+ while (1) switch (_context76.prev = _context76.next) {
3949
+ case 0:
3950
+ requestSpy = jest.spyOn(webex, 'request');
3951
+ warnSpy = jest.spyOn(_Logger.default, 'warn');
3952
+ _context76.next = 1;
3953
+ return call.completeTransfer(_types5.TransferType.CONSULT, undefined, undefined);
3954
+ case 1:
3955
+ /* We should be in CALL_ESTABLISHED state */
3956
+ expect(call['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3957
+ expect(secondCall['callStateMachine'].state.value).toStrictEqual('S_CALL_ESTABLISHED');
3958
+ expect(handleErrorSpy).not.toBeCalled();
3959
+ expect(uploadLogsSpy).not.toBeCalled();
3960
+ expect(requestSpy).not.toBeCalled();
3961
+ expect(warnSpy).toBeCalledOnceWith("Invalid information received, transfer failed for correlationId: ".concat(call.getCorrelationId()), transferLoggingContext);
3962
+ case 2:
3963
+ case "end":
3964
+ return _context76.stop();
3965
+ }
3966
+ }, _callee76);
3967
+ })));
3968
+ });
3969
+ });
3970
+ //# sourceMappingURL=call.test.js.map