@marimo-team/frontend 0.23.16-dev4 → 0.23.16-dev41

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 (254) hide show
  1. package/dist/assets/{CellStatus-BalYv0pK.js → CellStatus-C6Cj3oJc.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-DI7mV-Gw.js → ConnectedDataExplorerComponent-CMaZapRd.js} +1 -1
  3. package/dist/assets/{ErrorBoundary-C7_5jjWi.js → ErrorBoundary-DzTD8LVq.js} +1 -1
  4. package/dist/assets/{ImperativeModal-BIavOiUv.js → ImperativeModal-fY-ZfT0b.js} +1 -1
  5. package/dist/assets/{JsonOutput-CkCD-FgM.js → JsonOutput-CyzvjIjx.js} +12 -12
  6. package/dist/assets/{LazyAnyLanguageCodeMirror-sVm_hz8A.js → LazyAnyLanguageCodeMirror-B2JvSXP-.js} +2 -2
  7. package/dist/assets/{MarimoErrorOutput-DO2k2fA5.js → MarimoErrorOutput-CIuzXFFo.js} +4 -4
  8. package/dist/assets/{RSPContexts-CgC81f0I.js → RSPContexts-WiCgGm__.js} +1 -1
  9. package/dist/assets/RenderHTML-Cd-PP5ZR.js +1 -0
  10. package/dist/assets/{RunButton-BKRupqr7.js → RunButton-CnYWedW4.js} +1 -1
  11. package/dist/assets/{add-cell-with-ai-CEZtaZCK.js → add-cell-with-ai-ByOBQT99.js} +8 -8
  12. package/dist/assets/add-connection-dialog-C97ylgk0.js +170 -0
  13. package/dist/assets/{agent-panel-CHB6t7Zy.js → agent-panel-Dxo9WUKV.js} +5 -5
  14. package/dist/assets/ai-model-dropdown-Bvqy98cI.js +5 -0
  15. package/dist/assets/{alert-dialog-BXegNC0I.js → alert-dialog-Bb8Lz8ko.js} +1 -1
  16. package/dist/assets/{any-language-editor-DCpZRrpx.js → any-language-editor--tRHs8C_.js} +1 -1
  17. package/dist/assets/{app-config-button-NrM9ywXA.js → app-config-button-v1lG63C2.js} +1 -1
  18. package/dist/assets/{button-eIihcbUw.js → button-DDGiD1NW.js} +1 -1
  19. package/dist/assets/{cache-panel-wllSTlbM.js → cache-panel-DcQUeUpg.js} +1 -1
  20. package/dist/assets/{capabilities-B09j1Eor.js → capabilities-DoEg0XwL.js} +1 -1
  21. package/dist/assets/{cell-editor-B5JVq7_q.js → cell-editor-BKrHbyX_.js} +16 -16
  22. package/dist/assets/cell-link-w5IbCQV4.js +1 -0
  23. package/dist/assets/cells-DzyDERZy.js +235 -0
  24. package/dist/assets/{chat-display-BG08ltQ3.js → chat-display-Ccgk4vbE.js} +1 -1
  25. package/dist/assets/{chat-panel-P2CzCtXJ.js → chat-panel--53TIc3t.js} +4 -4
  26. package/dist/assets/{chat-ui-fAJZAoTD.js → chat-ui-B5rBxgsw.js} +4 -4
  27. package/dist/assets/{column-preview-Dne1dIt0.js → column-preview-Cb8R9kfl.js} +1 -1
  28. package/dist/assets/{command-CAJLPEBq.js → command-Dqxie4gq.js} +1 -1
  29. package/dist/assets/{command-palette-iOCqUIs1.js → command-palette-B1S9PjZi.js} +1 -1
  30. package/dist/assets/{common-CD6Mj8n6.js → common-CJ3baa6D.js} +1 -1
  31. package/dist/assets/components-DpUIWGaj.js +1 -0
  32. package/dist/assets/config-B-Q7J_6d.js +1 -0
  33. package/dist/assets/{config-COUOIPEq.js → config-BJVx3eBW.js} +1 -1
  34. package/dist/assets/{copy-BtTOqPTS.js → copy-Bxb1_Gtw.js} +1 -1
  35. package/dist/assets/{copy-icon-C2pG0ZNK.js → copy-icon-neDQUo4Q.js} +1 -1
  36. package/dist/assets/{createReducer-C7kZ8zEe.js → createReducer-DGx5Af-C.js} +1 -1
  37. package/dist/assets/{datasource-ySAiC9gr.js → datasource-D_VcQMEn.js} +2 -2
  38. package/dist/assets/{dates-D-kIKDYA.js → dates-C2LWzsCZ.js} +1 -1
  39. package/dist/assets/{dependency-graph-panel-BF23EwcD.js → dependency-graph-panel-DY5lvPDx.js} +3 -3
  40. package/dist/assets/{dialog-D1DEsRZ2.js → dialog-BCVepWLJ.js} +1 -1
  41. package/dist/assets/{dist-ByVeMWkr.js → dist-BLN8PNJV.js} +1 -1
  42. package/dist/assets/dist-CiVShZKM.js +2 -0
  43. package/dist/assets/{documentation-panel-e9Fi9R7e.js → documentation-panel-CGhwxsXK.js} +1 -1
  44. package/dist/assets/download-DpS57jyt.js +9 -0
  45. package/dist/assets/{dropdown-menu-BFZLnWeO.js → dropdown-menu-dHmZR8bI.js} +1 -1
  46. package/dist/assets/{edit-page-7X3HYey7.js → edit-page-DA765yQV.js} +6 -6
  47. package/dist/assets/{error-banner-B6eIlxzg.js → error-banner-BSxEOIn2.js} +1 -1
  48. package/dist/assets/error-entries-CTYMwfsh.js +8 -0
  49. package/dist/assets/{error-panel-DdsUL6b7.js → error-panel-DGAkG5kW.js} +1 -1
  50. package/dist/assets/{es-1D83cgiu.js → es-gYgfF8y5.js} +1 -1
  51. package/dist/assets/{esm-BL7jQmzn.js → esm-B30N1GS0.js} +1 -1
  52. package/dist/assets/{field-BeZbVzXA.js → field-BsxD35VE.js} +1 -1
  53. package/dist/assets/{file-explorer-panel-Ntq1-VbF.js → file-explorer-panel-BKUo-MDh.js} +3 -3
  54. package/dist/assets/{file-icons-Cb54mIL8.js → file-icons-DfWENcb8.js} +1 -1
  55. package/dist/assets/{file-name-input-BWFcK1ey.js → file-name-input-CNVZtm5K.js} +1 -1
  56. package/dist/assets/floating-outline-LitP0wCD.js +1 -0
  57. package/dist/assets/focus-CNKbm-Xz.js +1 -0
  58. package/dist/assets/{form-B6BkSCJb.js → form-nHzLTU1m.js} +2 -2
  59. package/dist/assets/{formats-ClEFGPy-.js → formats-DzmLpc9A.js} +1 -1
  60. package/dist/assets/{formatting-B_41gSF5.js → formatting-CDf6w1Kt.js} +1 -1
  61. package/dist/assets/{fullscreen-dUjPYOmm.js → fullscreen-CTDqNQr6.js} +1 -1
  62. package/dist/assets/{gallery-page-CWQQAYpa.js → gallery-page-CJ3ms1Hn.js} +1 -1
  63. package/dist/assets/{glide-data-editor-lMARFWHS.js → glide-data-editor-j2igs9Y_.js} +1 -1
  64. package/dist/assets/home-page-DM9Z_IJ7.js +4 -0
  65. package/dist/assets/{html-to-image-CwmX28T9.js → html-to-image-JaxFFZcr.js} +2 -2
  66. package/dist/assets/index-C7_REKh1.js +38 -0
  67. package/dist/assets/index-D6Dp_PFj.css +2 -0
  68. package/dist/assets/{input-CqrUjynb.js → input-JxFwu-3G.js} +1 -1
  69. package/dist/assets/kiosk-mode-BumOFEtY.js +1 -0
  70. package/dist/assets/{label-BElwWzf0.js → label-CqjrpwRC.js} +1 -1
  71. package/dist/assets/{layout-CUlZijwG.js → layout-B29hqiiK.js} +5 -5
  72. package/dist/assets/{links-CToBjIIj.js → links-CZr5bjvo.js} +1 -1
  73. package/dist/assets/logs-panel-CQRPYS8j.js +1 -0
  74. package/dist/assets/{markdown-renderer-QvXG0CRk.js → markdown-renderer-sEayY9-m.js} +2 -2
  75. package/dist/assets/{menu-items-DbSLBfXR.js → menu-items-CCi6aOPm.js} +1 -1
  76. package/dist/assets/{mermaid-Bh0flEIb.js → mermaid-CYN0wOyG.js} +1 -1
  77. package/dist/assets/{name-cell-input-C6cukQ9k.js → name-cell-input-B-aj1KH3.js} +1 -1
  78. package/dist/assets/node-sql-parser-Si4oZ2P-.js +68 -0
  79. package/dist/assets/{numbers-CeeaFKqu.js → numbers-rmawRqQP.js} +1 -1
  80. package/dist/assets/{outline-panel-BPlg9_CE.js → outline-panel-BOryk60D.js} +1 -1
  81. package/dist/assets/{packages-panel-BzQF60rG.js → packages-panel-DoYDLty3.js} +1 -1
  82. package/dist/assets/pair-with-agent-modal-BCRSACei.js +4 -0
  83. package/dist/assets/panels-Bb4fIHgH.js +4 -0
  84. package/dist/assets/{popover-DrHQ3KEt.js → popover-Bcz1Zikb.js} +1 -1
  85. package/dist/assets/process-output-d-LEMtGI.js +1 -0
  86. package/dist/assets/{radio-group-CLBjGkt5.js → radio-group-DfioQthW.js} +1 -1
  87. package/dist/assets/{readonly-code-display-D63oRtBP.js → readonly-code-display-C9fu8tvK.js} +1 -1
  88. package/dist/assets/{readonly-python-code-CW_G5e4E.js → readonly-python-code-DHxOnQGj.js} +1 -1
  89. package/dist/assets/{renderShortcut-BZLr8D7H.js → renderShortcut-Bl8_FVn8.js} +1 -1
  90. package/dist/assets/{reveal-component-BLMTmd8T.js → reveal-component-5jf0W625.js} +60 -60
  91. package/dist/assets/{run-page-B6pgDYEJ.js → run-page-BMKx9ld_.js} +1 -1
  92. package/dist/assets/{runs-D51Xwrsk.js → runs-DBTXqJHS.js} +1 -1
  93. package/dist/assets/scratchpad-panel-C8z8vzBX.js +1 -0
  94. package/dist/assets/{scroll-to-bottom-button-Cgr10kaJ.js → scroll-to-bottom-button-C8yfT4wq.js} +1 -1
  95. package/dist/assets/{secrets-panel-Cc5KDBk6.js → secrets-panel-6J6wcuVR.js} +1 -1
  96. package/dist/assets/{select-B5TFNjmU.js → select-BP75_5jJ.js} +1 -1
  97. package/dist/assets/{session-CEFnN9Cq.js → session-BmukRjSi.js} +1 -1
  98. package/dist/assets/{session-panel-Y0Oon0sD.js → session-panel-BVVk-02h.js} +1 -1
  99. package/dist/assets/{share-CYpcX4N4.js → share-852X_cqy.js} +1 -1
  100. package/dist/assets/{skeleton-D3QPxqWC.js → skeleton-Bubr9pIj.js} +1 -1
  101. package/dist/assets/slides-DkEgzTJB.css +1 -0
  102. package/dist/assets/{snippets-panel-CXpGflMO.js → snippets-panel-U2-iok-c.js} +1 -1
  103. package/dist/assets/{spec-CzqcmYQk.js → spec-C7opZZRp.js} +1 -1
  104. package/dist/assets/{state-BvdK8eiw.js → state-D10U2MwA.js} +1 -1
  105. package/dist/assets/{state-WBgc7MiA.js → state-DDag0B_B.js} +1 -1
  106. package/dist/assets/state-DtziTd1T.js +3 -0
  107. package/dist/assets/{state-DBzEQtWz.js → state-DxQhUsG9.js} +1 -1
  108. package/dist/assets/{strings-Djnbwmfl.js → strings--BknHX9C.js} +1 -1
  109. package/dist/assets/{swiper-component-DInvCxhI.js → swiper-component-g8EXE911.js} +1 -1
  110. package/dist/assets/switch-OVajJBPR.js +1 -0
  111. package/dist/assets/{terminal-D3IQBBYo.js → terminal-217O8hlZ.js} +1 -1
  112. package/dist/assets/{textarea-CpFfEUet.js → textarea-Bmzmbbpo.js} +1 -1
  113. package/dist/assets/{tooltip-CFX4fYHU.js → tooltip-4bZlU7jl.js} +1 -1
  114. package/dist/assets/{tooltip-HLb6RxVp.js → tooltip-B7U4xkIN.js} +1 -1
  115. package/dist/assets/{tracing-CKn3gWHw.js → tracing-B5XFvMmV.js} +1 -1
  116. package/dist/assets/{tracing-panel-BU-o_LCd.js → tracing-panel-DnR2bYDe.js} +2 -2
  117. package/dist/assets/{tree-actions-CsC2XmGo.js → tree-actions-Dx9CDaxV.js} +1 -1
  118. package/dist/assets/{useBoolean-D89u30n-.js → useBoolean-CFj86iac.js} +1 -1
  119. package/dist/assets/useCellActionButton-DypR3yDt.js +1 -0
  120. package/dist/assets/{useDeleteCell-EPH4kcG7.js → useDeleteCell-vMXAr3rY.js} +1 -1
  121. package/dist/assets/{useDependencyPanelTab-CZnK7N2L.js → useDependencyPanelTab-CwdwKf7A.js} +1 -1
  122. package/dist/assets/useEventListener-C0195JsF.js +1 -0
  123. package/dist/assets/{useHotkey-DIuRH8Wu.js → useHotkey-DLZvrRZT.js} +1 -1
  124. package/dist/assets/{useIframeCapabilities-Ccb4fvKc.js → useIframeCapabilities-j6fR_dBA.js} +1 -1
  125. package/dist/assets/{useInstallPackage-BRbUAUFn.js → useInstallPackage-WiYBwhUO.js} +1 -1
  126. package/dist/assets/{useInterval-CC0vKpWm.js → useInterval-CWBTUy5W.js} +1 -1
  127. package/dist/assets/useNotebookActions-jWIcmpv0.js +12 -0
  128. package/dist/assets/{useRunCells-CSSF_mJ0.js → useRunCells-C2dvU2jA.js} +1 -1
  129. package/dist/assets/{useSplitCell-9Qz93yPZ.js → useSplitCell-C1tubdNi.js} +1 -1
  130. package/dist/assets/{useTheme-KXqAyDPC.js → useTheme-Bxv9B31g.js} +1 -1
  131. package/dist/assets/{utils-Z80SV4_d.js → utils-BWBBpCkT.js} +1 -1
  132. package/dist/assets/{vega-component-Cie3ag_T.js → vega-component-Db8KjZJG.js} +1 -1
  133. package/dist/assets/{write-secret-modal-DEEn7sZV.js → write-secret-modal-3-v-dHVj.js} +1 -1
  134. package/dist/index.html +68 -68
  135. package/package.json +3 -4
  136. package/src/__mocks__/requests.ts +45 -4
  137. package/src/components/data-table/__tests__/__snapshots__/chart-spec-model.test.ts.snap +174 -21
  138. package/src/components/data-table/__tests__/chart-spec-model.test.ts +102 -1
  139. package/src/components/data-table/column-summary/chart-spec-model.tsx +163 -103
  140. package/src/components/data-table/column-summary/legacy-chart-spec.ts +15 -7
  141. package/src/components/data-table/column-summary/utils.ts +26 -7
  142. package/src/components/data-table/types.ts +1 -1
  143. package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +99 -18
  144. package/src/components/editor/actions/__tests__/pdf-export.test.ts +0 -4
  145. package/src/components/editor/actions/pair-with-agent-commands.ts +21 -10
  146. package/src/components/editor/actions/pair-with-agent-modal.tsx +2 -2
  147. package/src/components/editor/actions/pdf-export.ts +1 -4
  148. package/src/components/editor/actions/useNotebookActions.tsx +7 -13
  149. package/src/components/editor/cell/code/__tests__/cell-editor-activity-lifecycle.test.ts +250 -0
  150. package/src/components/editor/cell/code/cell-editor.tsx +13 -7
  151. package/src/components/editor/chrome/panels/__tests__/logs-panel.test.tsx +25 -0
  152. package/src/components/editor/chrome/panels/logs-panel.tsx +12 -2
  153. package/src/components/editor/connections/storage/__tests__/__snapshots__/as-code.test.ts.snap +50 -0
  154. package/src/components/editor/connections/storage/__tests__/as-code.test.ts +87 -8
  155. package/src/components/editor/connections/storage/as-code.ts +40 -21
  156. package/src/components/editor/connections/storage/schemas.ts +83 -42
  157. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
  158. package/src/components/slides/__tests__/cell-output-block.test.tsx +40 -0
  159. package/src/components/slides/__tests__/slide-cell-view.test.tsx +33 -0
  160. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +198 -0
  161. package/src/components/slides/reveal-component.tsx +25 -19
  162. package/src/components/slides/slide-cell-view.tsx +1 -1
  163. package/src/components/slides/slide-scroll-hint.tsx +161 -0
  164. package/src/components/slides/slides.css +4 -2
  165. package/src/components/static-html/share-modal.tsx +1 -1
  166. package/src/components/ui/input.tsx +1 -1
  167. package/src/core/cells/__tests__/cells.test.ts +12 -2
  168. package/src/core/cells/__tests__/logs.test.ts +5 -5
  169. package/src/core/cells/cells.ts +17 -4
  170. package/src/core/cells/document-changes.ts +1 -0
  171. package/src/core/cells/logs.ts +14 -4
  172. package/src/core/codemirror/copilot/__tests__/language-server.test.ts +396 -100
  173. package/src/core/codemirror/copilot/__tests__/transport.test.ts +128 -540
  174. package/src/core/codemirror/copilot/language-server.ts +182 -70
  175. package/src/core/codemirror/copilot/transport.ts +15 -207
  176. package/src/core/codemirror/copilot/types.ts +9 -2
  177. package/src/core/codemirror/find-replace/__tests__/navigate.test.ts +42 -30
  178. package/src/core/codemirror/find-replace/navigate.ts +2 -0
  179. package/src/core/codemirror/go-to-definition/__tests__/commands.test.ts +24 -3
  180. package/src/core/codemirror/go-to-definition/commands.ts +3 -0
  181. package/src/core/codemirror/keymaps/__tests__/keymaps.test.ts +31 -2
  182. package/src/core/codemirror/keymaps/keymaps.ts +12 -0
  183. package/src/core/codemirror/language/__tests__/sql.test.ts +443 -61
  184. package/src/core/codemirror/language/languages/python.ts +23 -11
  185. package/src/core/codemirror/language/languages/sql/completion-store.ts +5 -1
  186. package/src/core/codemirror/language/languages/sql/sql.ts +210 -3
  187. package/src/core/codemirror/lsp/__tests__/federated-lsp.test.ts +161 -0
  188. package/src/core/codemirror/lsp/__tests__/log-messages.test.ts +53 -0
  189. package/src/core/codemirror/lsp/__tests__/normalize-markdown-math.test.ts +25 -0
  190. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +598 -156
  191. package/src/core/codemirror/lsp/__tests__/transports.test.ts +112 -0
  192. package/src/core/codemirror/lsp/federated-lsp.ts +76 -23
  193. package/src/core/codemirror/lsp/log-messages.ts +37 -0
  194. package/src/core/codemirror/lsp/normalize-markdown-math.ts +8 -4
  195. package/src/core/codemirror/lsp/notebook-lsp.ts +220 -56
  196. package/src/core/codemirror/lsp/transports.ts +8 -1
  197. package/src/core/codemirror/lsp/types.ts +68 -8
  198. package/src/core/codemirror/lsp/utils.ts +14 -0
  199. package/src/core/codemirror/utils.ts +28 -0
  200. package/src/core/hotkeys/hotkeys.ts +0 -2
  201. package/src/core/islands/__tests__/bridge.test.ts +107 -0
  202. package/src/core/islands/bridge.ts +16 -0
  203. package/src/core/lsp/__tests__/transport.test.ts +509 -337
  204. package/src/core/lsp/transport.ts +304 -132
  205. package/src/core/mode.ts +10 -0
  206. package/src/core/network/__tests__/api.test.ts +42 -0
  207. package/src/core/network/__tests__/connection.test.ts +45 -0
  208. package/src/core/network/__tests__/requests-lazy.test.ts +32 -1
  209. package/src/core/network/__tests__/requests-network.test.ts +21 -0
  210. package/src/core/network/api.ts +27 -0
  211. package/src/core/network/connection.ts +15 -0
  212. package/src/core/network/requests-lazy.ts +1 -0
  213. package/src/core/network/requests-network.ts +14 -8
  214. package/src/core/network/requests-static.ts +1 -0
  215. package/src/core/network/requests-toasting.tsx +1 -0
  216. package/src/core/network/types.ts +22 -6
  217. package/src/core/rtc/state.ts +9 -0
  218. package/src/core/static/download-html.ts +5 -14
  219. package/src/core/wasm/bridge.ts +4 -2
  220. package/src/core/wasm/worker/types.ts +5 -2
  221. package/src/css/app/codemirror.css +16 -2
  222. package/src/plugins/impl/FormPlugin.tsx +1 -1
  223. package/src/plugins/impl/__tests__/FormPlugin.test.tsx +162 -0
  224. package/src/stories/log-viewer.stories.tsx +12 -6
  225. package/src/utils/__tests__/download.test.tsx +24 -1
  226. package/src/utils/download.ts +11 -6
  227. package/dist/assets/RenderHTML-BCvU9dYz.js +0 -1
  228. package/dist/assets/add-connection-dialog-B-jCRNTN.js +0 -170
  229. package/dist/assets/ai-model-dropdown-DXgLphFa.js +0 -5
  230. package/dist/assets/cell-link-DqBkyAFe.js +0 -1
  231. package/dist/assets/cells-Cf7bHHq3.js +0 -229
  232. package/dist/assets/components-BH6gDVv6.js +0 -1
  233. package/dist/assets/config-BbOTTCYY.js +0 -1
  234. package/dist/assets/dist-BCMBu0rO.js +0 -2
  235. package/dist/assets/download-BomYt3nl.js +0 -9
  236. package/dist/assets/error-entries-Birw-8VX.js +0 -8
  237. package/dist/assets/floating-outline-wz-WSRgP.js +0 -1
  238. package/dist/assets/focus-DiEyfiAG.js +0 -1
  239. package/dist/assets/home-page-DJ4jJsZj.js +0 -4
  240. package/dist/assets/index-A71LAt6h.css +0 -2
  241. package/dist/assets/index-CMZzy-dF.js +0 -38
  242. package/dist/assets/kiosk-mode-ABm3oYgq.js +0 -1
  243. package/dist/assets/logs-panel-iFV4ZJ9b.js +0 -1
  244. package/dist/assets/node-sql-parser-BWgUjcfV.js +0 -68
  245. package/dist/assets/pair-with-agent-modal-CKOYwOYw.js +0 -4
  246. package/dist/assets/panels-Dj45fW-v.js +0 -4
  247. package/dist/assets/process-output-BEhIGfkO.js +0 -1
  248. package/dist/assets/scratchpad-panel-B0mEqBNk.js +0 -1
  249. package/dist/assets/slides-MCbMDtlY.css +0 -1
  250. package/dist/assets/state-BZQc7xxL.js +0 -3
  251. package/dist/assets/switch-CvweaCXq.js +0 -1
  252. package/dist/assets/useCellActionButton-CRfIEVB5.js +0 -1
  253. package/dist/assets/useEventListener-B_w3A283.js +0 -1
  254. package/dist/assets/useNotebookActions-DTXAoukG.js +0 -12
@@ -1,565 +1,153 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* oxlint-disable typescript/no-explicit-any */
3
-
4
- import { WebSocketTransport } from "@open-rpc/client-js";
5
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
3
  import { Mocks } from "@/__mocks__/common";
7
4
  import { LazyWebsocketTransport } from "../transport";
8
5
 
9
- // Mock the Logger
10
6
  vi.mock("@/utils/Logger", () => ({
11
7
  Logger: Mocks.logger(),
12
8
  }));
13
9
 
14
- // Mock the WebSocketTransport
15
- vi.mock("@open-rpc/client-js", () => {
16
- const mockWebSocketTransport = vi.fn();
17
- mockWebSocketTransport.prototype.connect = vi.fn();
18
- mockWebSocketTransport.prototype.close = vi.fn();
19
- mockWebSocketTransport.prototype.sendData = vi.fn();
20
- mockWebSocketTransport.prototype.subscribe = vi.fn();
21
- mockWebSocketTransport.prototype.unsubscribe = vi.fn();
22
-
23
- return {
24
- WebSocketTransport: mockWebSocketTransport,
25
- };
26
- });
10
+ class FakeWebSocket {
11
+ static readonly OPEN = 1;
12
+ static readonly CLOSED = 3;
13
+ static readonly instances: FakeWebSocket[] = [];
14
+
15
+ readonly sent: string[] = [];
16
+ readyState = 0;
17
+ readonly url: string;
18
+ private readonly listeners = new Map<
19
+ string,
20
+ Set<(event: Record<string, never>) => void>
21
+ >();
22
+
23
+ constructor(url: string) {
24
+ this.url = url;
25
+ FakeWebSocket.instances.push(this);
26
+ }
27
+
28
+ addEventListener(
29
+ type: string,
30
+ listener: (event: Record<string, never>) => void,
31
+ ) {
32
+ const listeners = this.listeners.get(type) ?? new Set();
33
+ listeners.add(listener);
34
+ this.listeners.set(type, listeners);
35
+ }
36
+
37
+ send(frame: string) {
38
+ this.sent.push(frame);
39
+ }
40
+
41
+ close() {
42
+ this.readyState = FakeWebSocket.CLOSED;
43
+ this.emit("close");
44
+ }
45
+
46
+ open() {
47
+ this.readyState = FakeWebSocket.OPEN;
48
+ this.emit("open");
49
+ }
50
+
51
+ fail() {
52
+ this.emit("error");
53
+ }
54
+
55
+ private emit(type: string) {
56
+ for (const listener of this.listeners.get(type) ?? []) {
57
+ listener({});
58
+ }
59
+ }
60
+ }
61
+
62
+ async function getSocket(index: number): Promise<FakeWebSocket> {
63
+ await vi.waitFor(() => {
64
+ expect(FakeWebSocket.instances.length).toBeGreaterThan(index);
65
+ });
66
+ return FakeWebSocket.instances[index];
67
+ }
27
68
 
28
69
  describe("LazyWebsocketTransport", () => {
29
70
  const mockWsUrl = "ws://localhost:8080/copilot";
30
- let mockGetWsUrl: ReturnType<typeof vi.fn>;
31
- let mockWaitForReady: ReturnType<typeof vi.fn>;
32
- let mockShowError: ReturnType<typeof vi.fn>;
33
71
 
34
72
  beforeEach(() => {
35
- vi.clearAllMocks();
36
-
37
- mockGetWsUrl = vi.fn(() => mockWsUrl);
38
- mockWaitForReady = vi.fn().mockResolvedValue(undefined);
39
- mockShowError = vi.fn();
40
-
41
- // Mock the WebSocketTransport constructor
42
- (WebSocketTransport as any).mockImplementation(function (this: any) {
43
- this.connect = vi.fn().mockResolvedValue(undefined);
44
- this.close = vi.fn();
45
- this.sendData = vi.fn().mockResolvedValue({ result: "success" });
46
- this.subscribe = vi.fn();
47
- this.unsubscribe = vi.fn();
48
- });
73
+ FakeWebSocket.instances.length = 0;
74
+ vi.stubGlobal("WebSocket", FakeWebSocket);
49
75
  });
50
76
 
51
- describe("constructor", () => {
52
- it("should create a transport with default options", () => {
53
- const transport = new LazyWebsocketTransport({
54
- getWsUrl: mockGetWsUrl,
55
- waitForReady: mockWaitForReady,
56
- showError: mockShowError,
57
- });
58
-
59
- expect(transport).toBeDefined();
60
- expect(mockGetWsUrl).not.toHaveBeenCalled();
61
- });
62
-
63
- it("should accept custom retry options", () => {
64
- const transport = new LazyWebsocketTransport({
65
- getWsUrl: mockGetWsUrl,
66
- waitForReady: mockWaitForReady,
67
- showError: mockShowError,
68
- retries: 5,
69
- retryDelayMs: 2000,
70
- maxTimeoutMs: 10_000,
71
- });
72
-
73
- expect(transport).toBeDefined();
74
- });
77
+ afterEach(() => {
78
+ vi.unstubAllGlobals();
75
79
  });
76
80
 
77
- describe("connect", () => {
78
- it("should wait for prerequisites before connecting", async () => {
79
- const transport = new LazyWebsocketTransport({
80
- getWsUrl: mockGetWsUrl,
81
- waitForReady: mockWaitForReady,
82
- showError: mockShowError,
83
- });
84
-
85
- await transport.connect();
86
-
87
- expect(mockWaitForReady).toHaveBeenCalledTimes(1);
88
- expect(mockGetWsUrl).toHaveBeenCalledTimes(1);
89
- expect(WebSocketTransport).toHaveBeenCalledWith(mockWsUrl);
90
- });
91
-
92
- it("should create delegate and connect", async () => {
93
- const transport = new LazyWebsocketTransport({
94
- getWsUrl: mockGetWsUrl,
95
- waitForReady: mockWaitForReady,
96
- showError: mockShowError,
97
- });
98
-
99
- await transport.connect();
100
-
101
- const delegate = (transport as any).delegate;
102
- expect(delegate).toBeDefined();
103
- expect(delegate.connect).toHaveBeenCalledTimes(1);
104
- });
105
-
106
- it("should retry on connection failure", async () => {
107
- let attemptCount = 0;
108
- (WebSocketTransport as any).mockImplementation(function (this: any) {
109
- this.connect = vi.fn().mockImplementation(() => {
110
- attemptCount++;
111
- if (attemptCount < 2) {
112
- return Promise.reject(new Error("Connection failed"));
113
- }
114
- return Promise.resolve(undefined);
115
- });
116
- this.close = vi.fn();
117
- this.sendData = vi.fn();
118
- this.subscribe = vi.fn();
119
- this.unsubscribe = vi.fn();
120
- });
121
-
122
- const transport = new LazyWebsocketTransport({
123
- getWsUrl: mockGetWsUrl,
124
- waitForReady: mockWaitForReady,
125
- showError: mockShowError,
126
- retries: 3,
127
- retryDelayMs: 10,
128
- });
129
-
130
- await transport.connect();
131
-
132
- expect(attemptCount).toBe(2);
133
- });
134
-
135
- it("should show error toast on final retry failure", async () => {
136
- const connectionError = new Error("Connection failed");
137
- (WebSocketTransport as any).mockImplementation(function (this: any) {
138
- this.connect = vi.fn().mockRejectedValue(connectionError);
139
- this.close = vi.fn();
140
- this.sendData = vi.fn();
141
- this.subscribe = vi.fn();
142
- this.unsubscribe = vi.fn();
143
- });
144
-
145
- const transport = new LazyWebsocketTransport({
146
- getWsUrl: mockGetWsUrl,
147
- waitForReady: mockWaitForReady,
148
- showError: mockShowError,
149
- retries: 2,
150
- retryDelayMs: 10,
151
- });
152
-
153
- await expect(transport.connect()).rejects.toThrow("Connection failed");
154
-
155
- expect(mockShowError).toHaveBeenCalledTimes(1);
156
- expect(mockShowError).toHaveBeenCalledWith(
157
- "GitHub Copilot Connection Error",
158
- "Failed to connect to GitHub Copilot. Please check your settings and try again.\n\nConnection failed",
159
- );
160
- expect((transport as any).delegate).toBeUndefined();
161
- });
162
-
163
- it("should handle waitForReady failure", async () => {
164
- const waitError = new Error("Prerequisites not ready");
165
- mockWaitForReady.mockRejectedValue(waitError);
166
-
167
- const transport = new LazyWebsocketTransport({
168
- getWsUrl: mockGetWsUrl,
169
- waitForReady: mockWaitForReady,
170
- showError: mockShowError,
171
- });
172
-
173
- await expect(transport.connect()).rejects.toThrow(
174
- "Prerequisites not ready",
175
- );
176
- expect(WebSocketTransport).not.toHaveBeenCalled();
177
- });
81
+ it("waits for Copilot prerequisites before connecting", async () => {
82
+ let ready: (() => void) | undefined;
83
+ const waitForReady = vi.fn(
84
+ () =>
85
+ new Promise<void>((resolve) => {
86
+ ready = resolve;
87
+ }),
88
+ );
89
+ const transport = new LazyWebsocketTransport({
90
+ getWsUrl: () => mockWsUrl,
91
+ waitForReady,
92
+ showError: vi.fn(),
93
+ retryDelayMs: 0,
94
+ });
95
+
96
+ const connection = transport.connect();
97
+ expect(waitForReady).toHaveBeenCalledTimes(1);
98
+ expect(FakeWebSocket.instances).toHaveLength(0);
99
+
100
+ ready?.();
101
+ const socket = await getSocket(0);
102
+ socket.open();
103
+ await connection;
104
+
105
+ expect(socket.url).toBe(mockWsUrl);
178
106
  });
179
107
 
180
- describe("subscribe", () => {
181
- it("should register handler on parent and track subscription", () => {
182
- const transport = new LazyWebsocketTransport({
183
- getWsUrl: mockGetWsUrl,
184
- waitForReady: mockWaitForReady,
185
- showError: mockShowError,
186
- });
187
-
188
- const handler = vi.fn();
189
- transport.subscribe("notification", handler);
190
-
191
- expect((transport as any).pendingSubscriptions).toHaveLength(1);
192
- expect((transport as any).pendingSubscriptions[0]).toEqual({
193
- event: "notification",
194
- handler,
195
- });
196
- });
197
-
198
- it("should register handler on delegate if it exists", async () => {
199
- const transport = new LazyWebsocketTransport({
200
- getWsUrl: mockGetWsUrl,
201
- waitForReady: mockWaitForReady,
202
- showError: mockShowError,
203
- });
204
-
205
- await transport.connect();
206
-
207
- const handler = vi.fn();
208
- transport.subscribe("notification", handler);
209
-
210
- const delegate = (transport as any).delegate;
211
- expect(delegate.subscribe).toHaveBeenCalledWith("notification", handler);
212
- });
213
-
214
- it("should register pending subscriptions when delegate is created", async () => {
215
- const transport = new LazyWebsocketTransport({
216
- getWsUrl: mockGetWsUrl,
217
- waitForReady: mockWaitForReady,
218
- showError: mockShowError,
219
- });
220
-
221
- const handler1 = vi.fn();
222
- const handler2 = vi.fn();
223
- transport.subscribe("notification", handler1);
224
- transport.subscribe("response", handler2);
225
-
226
- await transport.connect();
227
-
228
- const delegate = (transport as any).delegate;
229
- expect(delegate.subscribe).toHaveBeenCalledWith("notification", handler1);
230
- expect(delegate.subscribe).toHaveBeenCalledWith("response", handler2);
231
- });
108
+ it("shows a user-facing error after the final retry", async () => {
109
+ const showError = vi.fn();
110
+ const transport = new LazyWebsocketTransport({
111
+ getWsUrl: () => mockWsUrl,
112
+ waitForReady: vi.fn().mockResolvedValue(undefined),
113
+ showError,
114
+ retries: 2,
115
+ retryDelayMs: 0,
116
+ });
117
+
118
+ const connection = transport.connect();
119
+ (await getSocket(0)).fail();
120
+ (await getSocket(1)).fail();
121
+
122
+ await expect(connection).rejects.toThrow(
123
+ "WebSocket connection to ws://localhost:8080/copilot failed",
124
+ );
125
+ expect(showError).toHaveBeenCalledWith(
126
+ "GitHub Copilot Connection Error",
127
+ "Failed to connect to GitHub Copilot. Please check your settings and try again.\n\nWebSocket connection to ws://localhost:8080/copilot failed",
128
+ );
232
129
  });
233
130
 
234
- describe("unsubscribe", () => {
235
- it("should remove specific handler for specific event", () => {
236
- const transport = new LazyWebsocketTransport({
237
- getWsUrl: mockGetWsUrl,
238
- waitForReady: mockWaitForReady,
239
- showError: mockShowError,
240
- });
241
-
242
- const handler1 = vi.fn();
243
- const handler2 = vi.fn();
244
- transport.subscribe("notification", handler1);
245
- transport.subscribe("notification", handler2);
246
-
247
- expect((transport as any).pendingSubscriptions).toHaveLength(2);
248
-
249
- transport.unsubscribe("notification", handler1);
250
-
251
- expect((transport as any).pendingSubscriptions).toHaveLength(1);
252
- expect((transport as any).pendingSubscriptions[0].handler).toBe(handler2);
253
- });
254
-
255
- it("should remove handler from all events when event not specified", () => {
256
- const transport = new LazyWebsocketTransport({
257
- getWsUrl: mockGetWsUrl,
258
- waitForReady: mockWaitForReady,
259
- showError: mockShowError,
260
- });
261
-
262
- const handler = vi.fn();
263
- transport.subscribe("notification", handler);
264
- transport.subscribe("response", handler);
265
-
266
- expect((transport as any).pendingSubscriptions).toHaveLength(2);
267
-
268
- transport.unsubscribe(undefined, handler);
269
-
270
- expect((transport as any).pendingSubscriptions).toHaveLength(0);
271
- });
272
-
273
- it("should remove all handlers for event when handler not specified", () => {
274
- const transport = new LazyWebsocketTransport({
275
- getWsUrl: mockGetWsUrl,
276
- waitForReady: mockWaitForReady,
277
- showError: mockShowError,
278
- });
279
-
280
- const handler1 = vi.fn();
281
- const handler2 = vi.fn();
282
- transport.subscribe("notification", handler1);
283
- transport.subscribe("notification", handler2);
284
- transport.subscribe("response", handler1);
285
-
286
- expect((transport as any).pendingSubscriptions).toHaveLength(3);
287
-
288
- transport.unsubscribe("notification");
289
-
290
- expect((transport as any).pendingSubscriptions).toHaveLength(1);
291
- expect((transport as any).pendingSubscriptions[0].event).toBe("response");
292
- });
293
-
294
- it("should remove all subscriptions when neither event nor handler specified", () => {
295
- const transport = new LazyWebsocketTransport({
296
- getWsUrl: mockGetWsUrl,
297
- waitForReady: mockWaitForReady,
298
- showError: mockShowError,
299
- });
300
-
301
- transport.subscribe("notification", vi.fn());
302
- transport.subscribe("response", vi.fn());
303
-
304
- expect((transport as any).pendingSubscriptions).toHaveLength(2);
305
-
306
- transport.unsubscribe();
307
-
308
- expect((transport as any).pendingSubscriptions).toHaveLength(0);
309
- });
310
-
311
- it("should unsubscribe from delegate if it exists", async () => {
312
- const transport = new LazyWebsocketTransport({
313
- getWsUrl: mockGetWsUrl,
314
- waitForReady: mockWaitForReady,
315
- showError: mockShowError,
316
- });
317
-
318
- await transport.connect();
319
-
320
- const handler = vi.fn();
321
- transport.subscribe("notification", handler);
322
- transport.unsubscribe("notification", handler);
323
-
324
- const delegate = (transport as any).delegate;
325
- expect(delegate.unsubscribe).toHaveBeenCalledWith(
326
- "notification",
327
- handler,
328
- );
329
- });
330
- });
331
-
332
- describe("sendData", () => {
333
- it("should send data through delegate when connected", async () => {
334
- const transport = new LazyWebsocketTransport({
335
- getWsUrl: mockGetWsUrl,
336
- waitForReady: mockWaitForReady,
337
- showError: mockShowError,
338
- });
339
-
340
- await transport.connect();
341
-
342
- const data: any = { method: "test", params: [] };
343
- const result = await transport.sendData(data, 5000);
344
-
345
- const delegate = (transport as any).delegate;
346
- expect(delegate.sendData).toHaveBeenCalledWith(data, 5000);
347
- expect(result).toEqual({ result: "success" });
348
- });
349
-
350
- it("should reconnect if delegate is undefined", async () => {
351
- const transport = new LazyWebsocketTransport({
352
- getWsUrl: mockGetWsUrl,
353
- waitForReady: mockWaitForReady,
354
- showError: mockShowError,
355
- });
356
-
357
- const data: any = { method: "test", params: [] };
358
- await transport.sendData(data, 5000);
359
-
360
- // sendData calls tryConnect directly, not connect, so wait functions aren't called
361
- // But it should still create and connect the delegate
362
- expect(WebSocketTransport).toHaveBeenCalled();
363
- const delegate = (transport as any).delegate;
364
- expect(delegate).toBeDefined();
365
- expect(delegate.connect).toHaveBeenCalled();
366
- });
367
-
368
- it("should use maxTimeoutMs as default when no timeout is provided", async () => {
369
- const transport = new LazyWebsocketTransport({
370
- getWsUrl: mockGetWsUrl,
371
- waitForReady: mockWaitForReady,
372
- showError: mockShowError,
373
- maxTimeoutMs: 5000,
374
- });
375
-
376
- await transport.connect();
377
-
378
- const data: any = { method: "test", params: [] };
379
- await transport.sendData(data, undefined);
380
-
381
- const delegate = (transport as any).delegate;
382
- expect(delegate.sendData).toHaveBeenCalledWith(data, 5000);
383
- });
384
-
385
- it("should respect caller-provided timeout without clamping", async () => {
386
- const transport = new LazyWebsocketTransport({
387
- getWsUrl: mockGetWsUrl,
388
- waitForReady: mockWaitForReady,
389
- showError: mockShowError,
390
- maxTimeoutMs: 5000,
391
- });
392
-
393
- await transport.connect();
394
-
395
- const data: any = { method: "test", params: [] };
396
- await transport.sendData(data, 30_000);
397
-
398
- const delegate = (transport as any).delegate;
399
- expect(delegate.sendData).toHaveBeenCalledWith(data, 30_000);
400
- });
401
-
402
- it("should throw error if reconnection fails", async () => {
403
- const connectionError = new Error("Connection failed");
404
- (WebSocketTransport as any).mockImplementation(function (this: any) {
405
- this.connect = vi.fn().mockRejectedValue(connectionError);
406
- this.close = vi.fn();
407
- this.sendData = vi.fn();
408
- this.subscribe = vi.fn();
409
- this.unsubscribe = vi.fn();
410
- });
411
-
412
- const transport = new LazyWebsocketTransport({
413
- getWsUrl: mockGetWsUrl,
414
- waitForReady: mockWaitForReady,
415
- showError: mockShowError,
416
- retries: 1,
417
- retryDelayMs: 10,
418
- });
419
-
420
- const data: any = { method: "test", params: [] };
421
- await expect(transport.sendData(data, 5000)).rejects.toThrow(
422
- "Unable to connect to GitHub Copilot",
423
- );
424
- });
425
- });
426
-
427
- describe("onReconnect", () => {
428
- it("should call onReconnect after close + sendData reconnection", async () => {
429
- const transport = new LazyWebsocketTransport({
430
- getWsUrl: mockGetWsUrl,
431
- waitForReady: mockWaitForReady,
432
- showError: mockShowError,
433
- });
434
-
435
- const onReconnect = vi.fn().mockResolvedValue(undefined);
436
- transport.onReconnect = onReconnect;
437
-
438
- // Initial connect
439
- await transport.connect();
440
- expect(onReconnect).not.toHaveBeenCalled();
441
-
442
- // Close the transport (simulates failure handling)
443
- transport.close();
444
-
445
- // sendData should reconnect and call onReconnect
446
- const data: any = { method: "test", params: [] };
447
- await transport.sendData(data, 5000);
448
-
131
+ it("inherits reconnect callbacks for Copilot re-initialization", async () => {
132
+ const transport = new LazyWebsocketTransport({
133
+ getWsUrl: () => mockWsUrl,
134
+ waitForReady: vi.fn().mockResolvedValue(undefined),
135
+ showError: vi.fn(),
136
+ retryDelayMs: 0,
137
+ });
138
+ const onReconnect = vi.fn().mockResolvedValue(undefined);
139
+ transport.onReconnect = onReconnect;
140
+
141
+ const initialConnection = transport.connect();
142
+ const firstSocket = await getSocket(0);
143
+ firstSocket.open();
144
+ await initialConnection;
145
+ firstSocket.close();
146
+
147
+ const secondSocket = await getSocket(1);
148
+ secondSocket.open();
149
+ await vi.waitFor(() => {
449
150
  expect(onReconnect).toHaveBeenCalledTimes(1);
450
151
  });
451
-
452
- it("should NOT call onReconnect on initial sendData connection", async () => {
453
- const transport = new LazyWebsocketTransport({
454
- getWsUrl: mockGetWsUrl,
455
- waitForReady: mockWaitForReady,
456
- showError: mockShowError,
457
- });
458
-
459
- const onReconnect = vi.fn().mockResolvedValue(undefined);
460
- transport.onReconnect = onReconnect;
461
-
462
- // sendData without prior connect — this is the initial connection
463
- const data: any = { method: "test", params: [] };
464
- await transport.sendData(data, 5000);
465
-
466
- expect(onReconnect).not.toHaveBeenCalled();
467
- });
468
-
469
- it("should call onReconnect after tryConnect failure + retry via sendData", async () => {
470
- let connectAttempt = 0;
471
- (WebSocketTransport as any).mockImplementation(function (this: any) {
472
- this.connect = vi.fn().mockImplementation(() => {
473
- connectAttempt++;
474
- // First 2 attempts fail (retries=2 exhausted), then succeed on next sendData
475
- if (connectAttempt <= 2) {
476
- return Promise.reject(new Error("Connection failed"));
477
- }
478
- return Promise.resolve(undefined);
479
- });
480
- this.close = vi.fn();
481
- this.sendData = vi.fn().mockResolvedValue({ result: "success" });
482
- this.subscribe = vi.fn();
483
- this.unsubscribe = vi.fn();
484
- });
485
-
486
- const transport = new LazyWebsocketTransport({
487
- getWsUrl: mockGetWsUrl,
488
- waitForReady: mockWaitForReady,
489
- showError: mockShowError,
490
- retries: 2,
491
- retryDelayMs: 10,
492
- });
493
-
494
- const onReconnect = vi.fn().mockResolvedValue(undefined);
495
- transport.onReconnect = onReconnect;
496
-
497
- // Initial connect fails (all retries exhausted)
498
- await expect(transport.connect()).rejects.toThrow("Connection failed");
499
- expect(onReconnect).not.toHaveBeenCalled();
500
-
501
- // Now sendData reconnects successfully
502
- const data: any = { method: "test", params: [] };
503
- await transport.sendData(data, 5000);
504
-
505
- expect(onReconnect).toHaveBeenCalledTimes(1);
506
- });
507
-
508
- it("should propagate onReconnect rejection and allow retry", async () => {
509
- const transport = new LazyWebsocketTransport({
510
- getWsUrl: mockGetWsUrl,
511
- waitForReady: mockWaitForReady,
512
- showError: mockShowError,
513
- });
514
-
515
- const reconnectError = new Error("Re-initialization failed");
516
- const onReconnect = vi.fn().mockRejectedValueOnce(reconnectError);
517
- transport.onReconnect = onReconnect;
518
-
519
- await transport.connect();
520
- transport.close();
521
-
522
- const data: any = { method: "test", params: [] };
523
- await expect(transport.sendData(data, 5000)).rejects.toThrow(
524
- "Re-initialization failed",
525
- );
526
- expect(onReconnect).toHaveBeenCalledTimes(1);
527
-
528
- // needsReInitialization should still be true, so a subsequent retry
529
- // will attempt onReconnect again
530
- onReconnect.mockResolvedValueOnce(undefined);
531
- await transport.sendData(data, 5000);
532
- expect(onReconnect).toHaveBeenCalledTimes(2);
533
- });
534
- });
535
-
536
- describe("close", () => {
537
- it("should close delegate and clear it", async () => {
538
- const transport = new LazyWebsocketTransport({
539
- getWsUrl: mockGetWsUrl,
540
- waitForReady: mockWaitForReady,
541
- showError: mockShowError,
542
- });
543
-
544
- await transport.connect();
545
-
546
- const delegate = (transport as any).delegate;
547
- expect(delegate).toBeDefined();
548
-
549
- transport.close();
550
-
551
- expect(delegate.close).toHaveBeenCalledTimes(1);
552
- expect((transport as any).delegate).toBeUndefined();
553
- });
554
-
555
- it("should handle close when delegate is undefined", () => {
556
- const transport = new LazyWebsocketTransport({
557
- getWsUrl: mockGetWsUrl,
558
- waitForReady: mockWaitForReady,
559
- showError: mockShowError,
560
- });
561
-
562
- expect(() => transport.close()).not.toThrow();
563
- });
564
152
  });
565
153
  });