@marimo-team/islands 0.25.1-dev4 → 0.25.1-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 (280) hide show
  1. package/dist/{ConnectedDataExplorerComponent-KVhjDMSe.js → ConnectedDataExplorerComponent-CwMXfDQR.js} +3 -3
  2. package/dist/{ErrorBoundary-pV36lYEK.js → ErrorBoundary-vRGgXmad.js} +1 -1
  3. package/dist/{ImageComparisonComponent-Dlm5aWnH.js → ImageComparisonComponent-Cpfz30OZ.js} +51 -52
  4. package/dist/{abnfDiagram-VCTEODGH-CpN0FRda.js → abnfDiagram-VCTEODGH-AFhOQTt8.js} +3 -3
  5. package/dist/{architectureDiagram-5GKGNRK7-DDyj5SRB.js → architectureDiagram-5GKGNRK7-BngksAAQ.js} +5 -5
  6. package/dist/{blockDiagram-I7D4REHJ-BbXEXJRu.js → blockDiagram-I7D4REHJ-CvBmppdy.js} +9 -9
  7. package/dist/{c4Diagram-7LVT6UL2-DcLsbQmR.js → c4Diagram-7LVT6UL2-EceL4_jH.js} +7 -7
  8. package/dist/{cells-B5-y5EY3.js → cells-Cv93oav_.js} +3 -3
  9. package/dist/{channel-B5XnTarr.js → channel-z7HZXHwv.js} +1 -1
  10. package/dist/{chat-ui-HJZsTl7o.js → chat-ui-DLSF8a04.js} +4 -4
  11. package/dist/{chunk-4HAMMTFA-D2qv8E0X.js → chunk-4HAMMTFA-BPTTOOC5.js} +5 -5
  12. package/dist/{chunk-75Z2AOVW-5_HsvXwr.js → chunk-75Z2AOVW-C4AOleKf.js} +1 -1
  13. package/dist/{chunk-DU6HZSFF-BUgAHvnM.js → chunk-DU6HZSFF-1TwWR6gh.js} +1 -1
  14. package/dist/{chunk-F27PBJKO-DHmYWZXr.js → chunk-F27PBJKO-DMI1PBe4.js} +1 -1
  15. package/dist/{chunk-GMAD6QVW-Czynz8aA.js → chunk-GMAD6QVW-vStrMz2P.js} +3 -3
  16. package/dist/{chunk-GVQU2GXP-yQEdulRS.js → chunk-GVQU2GXP-2HwWgs4u.js} +2 -2
  17. package/dist/{chunk-IMKFNOWR-BfwTebD0.js → chunk-IMKFNOWR-UOVZuZVn.js} +5 -5
  18. package/dist/{chunk-L3NEJ4N5-DwRWnDDK.js → chunk-L3NEJ4N5-RhC7i0I2.js} +5 -5
  19. package/dist/{chunk-OSK3NFVY-BBKU_Ign.js → chunk-OSK3NFVY-CZV09N-U.js} +6 -6
  20. package/dist/{chunk-P2QGCYS3-C0iGU29N.js → chunk-P2QGCYS3-0TAWai9C.js} +1 -1
  21. package/dist/{chunk-POPQ4Y6H-BCbS3Ozc.js → chunk-POPQ4Y6H-Cc3_56GX.js} +1 -1
  22. package/dist/{chunk-PWAF6VOD-CTFCL0jI.js → chunk-PWAF6VOD-lNxB9k8z.js} +1 -1
  23. package/dist/{chunk-SHT3W25Y-BspJEJ5H.js → chunk-SHT3W25Y-CrEPyWy1.js} +7 -7
  24. package/dist/{chunk-SVP7TREG-DX3rFNTe.js → chunk-SVP7TREG-uIyyySp6.js} +2 -2
  25. package/dist/{chunk-TICWLB2K-fVF7Uujg.js → chunk-TICWLB2K-DdXM3eg6.js} +5 -5
  26. package/dist/classDiagram-ZZMXUADV-BiATbBE4.js +30 -0
  27. package/dist/classDiagram-v2-VYDZK3BY-JnH97GYw.js +30 -0
  28. package/dist/{code-visibility-CgZS2a3W.js → code-visibility-5wuTKcAD.js} +2 -2
  29. package/dist/{common-DnMDPPaW.js → common-PL37o7BX.js} +13 -13
  30. package/dist/{cynefinDiagram-5FMLGOSQ-CFQrqzSX.js → cynefinDiagram-5FMLGOSQ-zknaAsGy.js} +3 -3
  31. package/dist/{dagre-GXQ25YYZ-xHNAUTyG.js → dagre-GXQ25YYZ-BhMOoMGJ.js} +10 -10
  32. package/dist/{data-grid-overlay-editor-hHYgD_Sm.js → data-grid-overlay-editor-CWqzAL_P.js} +1 -1
  33. package/dist/{diagram-S7CK7UJ4-Bt1rPbAx.js → diagram-S7CK7UJ4-V5-Z-EDY.js} +4 -4
  34. package/dist/{diagram-UQ7AKVKN-D1sq5FoZ.js → diagram-UQ7AKVKN-qw8AjDal.js} +3 -3
  35. package/dist/{diagram-VSXAHHWV-BKpmG23x.js → diagram-VSXAHHWV-CR7BJygZ.js} +2 -2
  36. package/dist/{diagram-VX7I27RA-BMwGFVD6.js → diagram-VX7I27RA-DfuqFb1E.js} +5 -5
  37. package/dist/{diagram-Z3DM3KII--KLDR9Pl.js → diagram-Z3DM3KII-DpWwlYZB.js} +3 -3
  38. package/dist/{dist-BaHjhkpZ.js → dist-CcyKTBTF.js} +1 -1
  39. package/dist/{ebnfDiagram-PWID7BFC-WnG4cvSQ.js → ebnfDiagram-PWID7BFC-C20OnNMZ.js} +3 -3
  40. package/dist/{erDiagram-RLTQ6QDP-DhzKiYHc.js → erDiagram-RLTQ6QDP-DBXLWO9v.js} +12 -12
  41. package/dist/{error-entries-Bkbpx0T0.js → error-entries-DLl0XqoW.js} +1 -1
  42. package/dist/{feedback-button-CvKssdG_.js → feedback-button-BwKWcLqp.js} +4 -4
  43. package/dist/flowDiagram-HODETNUW-DL52nMkt.js +16 -0
  44. package/dist/{formats-C8rLgZT9.js → formats-Cl_67ghI.js} +1 -1
  45. package/dist/{ganttDiagram-EL5Y4UJY-DbzEBLbl.js → ganttDiagram-EL5Y4UJY-cRRaDt88.js} +2 -2
  46. package/dist/{gitGraphDiagram-WWUBYQGX-BMf0iKi1.js → gitGraphDiagram-WWUBYQGX-Pox5k9-Y.js} +2 -2
  47. package/dist/{glide-data-editor-Ohetlgag.js → glide-data-editor-DdDhX9sS.js} +3 -3
  48. package/dist/{globals-CPNNcOJI.js → globals-D07l3kcu.js} +1 -1
  49. package/dist/{html-to-image-BAgJOlSW.js → html-to-image-CGVgroef.js} +2 -2
  50. package/dist/{infoDiagram-27XIBGKW-BagtCX_5.js → infoDiagram-27XIBGKW-ntpxMfrq.js} +2 -2
  51. package/dist/{ishikawaDiagram-5VMMS53U-DByDehYy.js → ishikawaDiagram-5VMMS53U-BllIlHE5.js} +3 -3
  52. package/dist/{journeyDiagram-3NMN7TZE-D2LcKDUO.js → journeyDiagram-3NMN7TZE-EPJDPlt0.js} +2 -2
  53. package/dist/{kanban-definition-UXKFOSKX-BxwkbBI_.js → kanban-definition-UXKFOSKX-GYtNMjtS.js} +9 -9
  54. package/dist/{katex-C6D4cX_N.js → katex-BNCmKUol.js} +983 -1120
  55. package/dist/{loader-D2W4oM-3.js → loader-DEZSzvma.js} +253 -248
  56. package/dist/main.js +72 -69
  57. package/dist/{mermaid-DPNuhemn.js → mermaid-Dnzoxjt1.js} +49 -49
  58. package/dist/{mhchem-DWCF06w9.js → mhchem-BEc7A1or.js} +1 -1
  59. package/dist/{mindmap-definition-YA3MSWOX-Cgvojw3y.js → mindmap-definition-YA3MSWOX-Cth76xgH.js} +11 -11
  60. package/dist/{number-overlay-editor-CHWg5gGO.js → number-overlay-editor-DerHT6Rq.js} +1 -1
  61. package/dist/{pegDiagram-XKGWAZYB-DahHhYyN.js → pegDiagram-XKGWAZYB-Cu4uOXii.js} +3 -3
  62. package/dist/{pieDiagram-E7YTZNPT-CCtX0oCK.js → pieDiagram-E7YTZNPT-Bh3eDa9s.js} +3 -3
  63. package/dist/{process-output-zDX4jbhd.js → process-output-CGfg-JmZ.js} +2 -2
  64. package/dist/{quadrantDiagram-AXDQQJYC-DftINo6g.js → quadrantDiagram-AXDQQJYC--kqzFC3w.js} +1 -1
  65. package/dist/{railroadDiagram-O6MQD6OU-Du5NsPUb.js → railroadDiagram-O6MQD6OU-DG-M6Rnc.js} +3 -3
  66. package/dist/{react-vega-5AcMW8gG.js → react-vega-ewj7q_U5.js} +1 -1
  67. package/dist/{requirementDiagram-BXWQKSXE-0pmmxL6_.js → requirementDiagram-BXWQKSXE-DCwsThh0.js} +11 -11
  68. package/dist/{reveal-component-BujcZI2B.js → reveal-component-sfZwts_E.js} +3 -3
  69. package/dist/{sankeyDiagram-P5KCCOFB-CDKR5TJH.js → sankeyDiagram-P5KCCOFB-BdzhT0BM.js} +1 -1
  70. package/dist/{sequenceDiagram-WJ2MYXX4-DB-ChWwU.js → sequenceDiagram-WJ2MYXX4-CbXB1_PU.js} +4 -4
  71. package/dist/{stateDiagram-D77RDMKH-orN6AwMx.js → stateDiagram-D77RDMKH-A-Zf3Sb2.js} +13 -13
  72. package/dist/stateDiagram-v2-MP3YSRHH-D9YMnUGx.js +30 -0
  73. package/dist/style.css +1 -1
  74. package/dist/{swimlanes-42K2YHIH-BkSDcqDT.js → swimlanes-42K2YHIH-B_pMf0J4.js} +10 -10
  75. package/dist/swimlanesDiagram-VR7AAH4N-Ctgy-yGP.js +30 -0
  76. package/dist/{timeline-definition-24CTP7MA-BuqJUIRZ.js → timeline-definition-24CTP7MA-DTXFjTTM.js} +3 -3
  77. package/dist/{vega-component-CNf5gcrm.js → vega-component-tFOzgarw.js} +4 -4
  78. package/dist/{vega-embed-container-CbnTccZi.js → vega-embed-container-sSR5hAsy.js} +2 -2
  79. package/dist/{vega-loader.browser-D95WfUcj.js → vega-loader.browser-DNST6uVf.js} +2 -2
  80. package/dist/{vennDiagram-4TSXK5OY-CTUlJ2PK.js → vennDiagram-4TSXK5OY-BPHjZo0R.js} +3 -3
  81. package/dist/{wardleyDiagram-VM6X3IG4-3evLUb0M.js → wardleyDiagram-VM6X3IG4-6fTLYBuD.js} +3 -3
  82. package/dist/{xychartDiagram-S5SC5T6Z-DL2E3K8-.js → xychartDiagram-S5SC5T6Z-BYjwjrzE.js} +5 -5
  83. package/package.json +1 -2
  84. package/src/__mocks__/common.ts +3 -3
  85. package/src/__tests__/CellStatus.test.tsx +1 -1
  86. package/src/__tests__/setup.ts +7 -7
  87. package/src/components/app-config/ai-config.tsx +2 -0
  88. package/src/components/app-config/optional-features.tsx +1 -1
  89. package/src/components/chat/chat-panel.tsx +19 -8
  90. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +286 -0
  91. package/src/components/data-table/charts/charts.tsx +26 -13
  92. package/src/components/data-table/column-summary/chart-spec-model.tsx +4 -4
  93. package/src/components/dependency-graph/elements.ts +2 -2
  94. package/src/components/editor/__tests__/package-alert.test.tsx +140 -0
  95. package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +107 -0
  96. package/src/components/editor/actions/pair-with-agent.tsx +119 -0
  97. package/src/components/editor/actions/useNotebookActions.tsx +2 -1
  98. package/src/components/editor/ai/add-cell-with-ai.tsx +2 -0
  99. package/src/components/editor/ai/staged-cell-submission.ts +2 -2
  100. package/src/components/editor/ai/transport/chat-transport.tsx +1 -1
  101. package/src/components/editor/chrome/components/contribute-snippet-button.tsx +6 -1
  102. package/src/components/editor/connections/database/as-code.ts +44 -44
  103. package/src/components/editor/connections/storage/as-code.ts +3 -3
  104. package/src/components/editor/file-tree/requesting-tree.tsx +16 -13
  105. package/src/components/editor/navigation/clipboard.ts +2 -2
  106. package/src/components/editor/notebook-cell.tsx +2 -2
  107. package/src/components/editor/output/MarimoTracebackOutput.tsx +1 -1
  108. package/src/components/editor/output/VideoOutput.tsx +1 -1
  109. package/src/components/editor/output/ansi-reduce.ts +21 -17
  110. package/src/components/editor/output/console/ConsoleOutput.tsx +3 -3
  111. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +59 -0
  112. package/src/components/editor/output/console/text-rendering.tsx +3 -1
  113. package/src/components/editor/package-alert.tsx +20 -7
  114. package/src/components/home/components.tsx +1 -0
  115. package/src/components/pages/run-page.tsx +1 -0
  116. package/src/components/slides/__tests__/minimap-actions.test.tsx +7 -7
  117. package/src/components/slides/__tests__/minimap.test.ts +12 -12
  118. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +8 -8
  119. package/src/components/static-html/__tests__/share-modal.test.tsx +154 -0
  120. package/src/components/static-html/__tests__/stage-for-publish.test.ts +111 -0
  121. package/src/components/static-html/share-modal.tsx +114 -144
  122. package/src/components/static-html/stage-for-publish.ts +56 -0
  123. package/src/components/static-html/static-banner.tsx +2 -2
  124. package/src/components/ui/links.tsx +6 -1
  125. package/src/components/ui/typography.tsx +16 -8
  126. package/src/core/ai/context/__tests__/registry.test.ts +31 -28
  127. package/src/core/ai/context/providers/cell-output.ts +8 -8
  128. package/src/core/ai/context/providers/datasource.ts +10 -7
  129. package/src/core/ai/context/providers/error.ts +7 -7
  130. package/src/core/ai/context/providers/file.ts +8 -8
  131. package/src/core/ai/context/providers/tables.ts +7 -7
  132. package/src/core/ai/context/providers/variable.ts +7 -7
  133. package/src/core/ai/context/registry.ts +18 -18
  134. package/src/core/ai/ids/ids.ts +5 -5
  135. package/src/core/ai/model-registry.ts +12 -9
  136. package/src/core/ai/staged-cells.ts +6 -6
  137. package/src/core/ai/tools/base.ts +6 -6
  138. package/src/core/ai/tools/edit-notebook-tool.ts +6 -6
  139. package/src/core/ai/tools/registry.ts +4 -4
  140. package/src/core/ai/tools/run-cells-tool.ts +7 -7
  141. package/src/core/ai/tools/sample-tool.ts +6 -6
  142. package/src/core/cells/__tests__/cells.test.ts +27 -0
  143. package/src/core/cells/cells.ts +2 -1
  144. package/src/core/codemirror/cells/debugger-decorations.ts +13 -7
  145. package/src/core/codemirror/cells/line-timing-decorations.ts +9 -9
  146. package/src/core/codemirror/cells/traceback-decorations.ts +7 -4
  147. package/src/core/codemirror/code-lens/extension.ts +13 -13
  148. package/src/core/codemirror/copilot/__tests__/language-server.test.ts +6 -6
  149. package/src/core/codemirror/copilot/__tests__/transport.test.ts +12 -12
  150. package/src/core/codemirror/copilot/language-server.ts +13 -13
  151. package/src/core/codemirror/copilot/transport.ts +1 -1
  152. package/src/core/codemirror/find-replace/search-highlight.ts +5 -5
  153. package/src/core/codemirror/go-to-definition/underline.ts +3 -3
  154. package/src/core/codemirror/keymaps/vim.ts +3 -3
  155. package/src/core/codemirror/language/languages/markdown.ts +8 -8
  156. package/src/core/codemirror/language/languages/python.ts +7 -7
  157. package/src/core/codemirror/language/languages/sql/completion-builder.ts +5 -5
  158. package/src/core/codemirror/language/languages/sql/completion-store.ts +4 -4
  159. package/src/core/codemirror/language/languages/sql/sql.ts +21 -21
  160. package/src/core/codemirror/lsp/__tests__/transports.test.ts +10 -10
  161. package/src/core/codemirror/lsp/federated-lsp.ts +29 -27
  162. package/src/core/codemirror/lsp/notebook-lsp.ts +21 -21
  163. package/src/core/codemirror/misc/__tests__/dnd.test.ts +10 -10
  164. package/src/core/codemirror/misc/__tests__/paste.test.ts +7 -4
  165. package/src/core/codemirror/reactive-references/extension.ts +3 -3
  166. package/src/core/codemirror/rtc/loro/awareness.ts +12 -12
  167. package/src/core/codemirror/rtc/loro/sync.ts +5 -5
  168. package/src/core/codemirror/vim/cursor-visibility.ts +3 -3
  169. package/src/core/dom/ui-element.ts +5 -5
  170. package/src/core/dom/uiregistry.ts +10 -10
  171. package/src/core/hotkeys/hotkeys.ts +9 -9
  172. package/src/core/islands/__tests__/bridge.test.ts +4 -4
  173. package/src/core/islands/__tests__/test-utils.tsx +4 -4
  174. package/src/core/islands/bridge.ts +85 -82
  175. package/src/core/islands/components/web-components.tsx +7 -7
  176. package/src/core/islands/worker/__tests__/controller.test.ts +1 -1
  177. package/src/core/islands/worker/controller.ts +6 -3
  178. package/src/core/islands/worker-factory.ts +2 -2
  179. package/src/core/kernel/RuntimeState.ts +4 -4
  180. package/src/core/lsp/__tests__/transport.test.ts +19 -19
  181. package/src/core/lsp/transport.ts +5 -5
  182. package/src/core/network/CachingRequestRegistry.ts +2 -2
  183. package/src/core/network/DeferredRequestRegistry.ts +4 -4
  184. package/src/core/network/__tests__/export-asset-url.test.ts +45 -0
  185. package/src/core/network/export-asset-url.ts +19 -0
  186. package/src/core/network/requests-network.ts +2 -7
  187. package/src/core/runtime/runtime.ts +25 -20
  188. package/src/core/static/virtual-file-tracker.ts +5 -5
  189. package/src/core/wasm/__tests__/bridge.test.ts +2 -2
  190. package/src/core/wasm/bridge.ts +132 -133
  191. package/src/core/wasm/router.ts +5 -5
  192. package/src/core/wasm/store.ts +4 -4
  193. package/src/core/wasm/worker/bootstrap.ts +8 -5
  194. package/src/core/wasm/worker/message-buffer.ts +3 -3
  195. package/src/core/websocket/transports/__tests__/ws.test.ts +8 -8
  196. package/src/core/websocket/transports/basic.ts +15 -8
  197. package/src/core/websocket/transports/sse.ts +7 -7
  198. package/src/core/websocket/transports/transport.ts +3 -3
  199. package/src/core/websocket/transports/ws.ts +9 -7
  200. package/src/css/globals.css +18 -21
  201. package/src/css/katex.min.css +260 -241
  202. package/src/hooks/__tests__/useOverflowDetection.test.tsx +5 -5
  203. package/src/hooks/__tests__/useResizeObserver.test.tsx +12 -12
  204. package/src/plugins/core/registerReactComponent.tsx +5 -5
  205. package/src/plugins/core/sidebar-element.tsx +2 -2
  206. package/src/plugins/impl/ButtonPlugin.tsx +3 -3
  207. package/src/plugins/impl/CheckboxPlugin.tsx +3 -3
  208. package/src/plugins/impl/CodeEditorPlugin.tsx +3 -3
  209. package/src/plugins/impl/DatePickerPlugin.tsx +3 -3
  210. package/src/plugins/impl/DateRangePlugin.tsx +3 -3
  211. package/src/plugins/impl/DateTimePickerPlugin.tsx +3 -3
  212. package/src/plugins/impl/DictPlugin.tsx +3 -3
  213. package/src/plugins/impl/DropdownPlugin.tsx +3 -3
  214. package/src/plugins/impl/FileUploadPlugin.tsx +3 -3
  215. package/src/plugins/impl/MatrixPlugin.tsx +4 -4
  216. package/src/plugins/impl/MicrophonePlugin.tsx +3 -3
  217. package/src/plugins/impl/MultiselectPlugin.tsx +3 -3
  218. package/src/plugins/impl/NumberPlugin.tsx +3 -3
  219. package/src/plugins/impl/RadioPlugin.tsx +9 -5
  220. package/src/plugins/impl/RangeSliderPlugin.tsx +3 -3
  221. package/src/plugins/impl/RefreshPlugin.tsx +3 -3
  222. package/src/plugins/impl/SliderPlugin.tsx +3 -3
  223. package/src/plugins/impl/SwitchPlugin.tsx +3 -3
  224. package/src/plugins/impl/TabsPlugin.tsx +3 -3
  225. package/src/plugins/impl/TextAreaPlugin.tsx +3 -3
  226. package/src/plugins/impl/TextInputPlugin.tsx +3 -3
  227. package/src/plugins/impl/__tests__/MatrixPlugin.test.tsx +2 -2
  228. package/src/plugins/impl/anywidget/model.ts +10 -10
  229. package/src/plugins/impl/anywidget/registry.ts +12 -9
  230. package/src/plugins/impl/anywidget/runtime.ts +11 -9
  231. package/src/plugins/impl/anywidget/widget-binding.ts +6 -6
  232. package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +7 -6
  233. package/src/plugins/impl/matplotlib/MatplotlibPlugin.tsx +3 -3
  234. package/src/plugins/impl/matplotlib/__tests__/matplotlib-renderer.test.ts +2 -2
  235. package/src/plugins/impl/matplotlib/matplotlib-renderer.ts +2 -2
  236. package/src/plugins/impl/mpl-interactive/mpl-websocket-shim.ts +10 -10
  237. package/src/plugins/impl/panel/utils.ts +5 -5
  238. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +3 -3
  239. package/src/plugins/impl/vega/VegaPlugin.tsx +3 -3
  240. package/src/plugins/impl/vega/__tests__/use-vega-container-remeasure.test.ts +7 -7
  241. package/src/plugins/impl/vega/__tests__/utils.test.ts +16 -1
  242. package/src/plugins/impl/vega/__tests__/vega.test.ts +37 -0
  243. package/src/plugins/impl/vega/loader.ts +23 -1
  244. package/src/plugins/impl/vega/utils.ts +5 -4
  245. package/src/plugins/layout/AccordionPlugin.tsx +3 -3
  246. package/src/plugins/layout/CalloutPlugin.tsx +3 -3
  247. package/src/plugins/layout/ImageComparisonPlugin.tsx +5 -3
  248. package/src/plugins/layout/JsonOutputPlugin.tsx +3 -3
  249. package/src/plugins/layout/MimeRenderPlugin.tsx +3 -3
  250. package/src/plugins/layout/NavigationMenuPlugin.tsx +3 -3
  251. package/src/plugins/layout/OutlinePlugin.tsx +3 -3
  252. package/src/plugins/layout/ProgressPlugin.tsx +3 -3
  253. package/src/plugins/layout/RoutesPlugin.tsx +6 -8
  254. package/src/plugins/layout/StatPlugin.tsx +3 -3
  255. package/src/plugins/layout/TexPlugin.tsx +3 -3
  256. package/src/plugins/layout/carousel/CarouselPlugin.tsx +4 -4
  257. package/src/plugins/layout/mermaid/MermaidPlugin.tsx +3 -3
  258. package/src/utils/Deferred.ts +6 -6
  259. package/src/utils/async-capture-tracker.ts +10 -7
  260. package/src/utils/errors.ts +5 -5
  261. package/src/utils/id-tree.tsx +83 -80
  262. package/src/utils/lru.ts +1 -1
  263. package/src/utils/multi-map.ts +14 -12
  264. package/src/utils/paths.ts +6 -6
  265. package/src/utils/pluralize.ts +3 -3
  266. package/src/utils/progress.ts +6 -6
  267. package/src/utils/python-poet/poet.ts +14 -14
  268. package/src/utils/routes.ts +4 -2
  269. package/src/utils/semaphore.ts +6 -6
  270. package/src/utils/storage/storage.ts +6 -6
  271. package/src/utils/storage/typed.ts +16 -12
  272. package/src/utils/time.ts +9 -9
  273. package/src/utils/timed-cache.ts +4 -4
  274. package/src/utils/tracer.ts +9 -6
  275. package/dist/classDiagram-ZZMXUADV-Fe-V14Sc.js +0 -30
  276. package/dist/classDiagram-v2-VYDZK3BY-xTDg7lOs.js +0 -30
  277. package/dist/flowDiagram-HODETNUW-6dMdB8pR.js +0 -16
  278. package/dist/katex-DFBiSucW.js +0 -21840
  279. package/dist/stateDiagram-v2-MP3YSRHH-o05_rJN8.js +0 -30
  280. package/dist/swimlanesDiagram-VR7AAH4N-D_nFQfRc.js +0 -30
@@ -120,6 +120,65 @@ describe("ConsoleOutput pdb history", () => {
120
120
  expect(newInput).toHaveValue("next");
121
121
  });
122
122
 
123
+ it("submits passwords without making them available to input history", () => {
124
+ const passwordPrompt: WithResponse<OutputMessage> = {
125
+ ...stdinPrompt("Password: "),
126
+ mimetype: "text/password",
127
+ };
128
+ const onSubmitDebugger = vi.fn();
129
+ const { rerender } = renderWithProvider(
130
+ <ConsoleOutput
131
+ {...defaultProps}
132
+ consoleOutputs={[stdinPrompt("Name: ")]}
133
+ onSubmitDebugger={onSubmitDebugger}
134
+ />,
135
+ );
136
+ const nameInput = screen.getByTestId("console-input");
137
+ fireEvent.change(nameInput, { target: { value: "marimo" } });
138
+ fireEvent.keyDown(nameInput, { key: "Enter" });
139
+
140
+ rerender(
141
+ <TooltipProvider>
142
+ <ConsoleOutput
143
+ {...defaultProps}
144
+ consoleOutputs={[stdinPrompt("Name: ", "marimo"), passwordPrompt]}
145
+ onSubmitDebugger={onSubmitDebugger}
146
+ />
147
+ </TooltipProvider>,
148
+ );
149
+ const input = screen.getByTestId("console-input");
150
+ expect(input).toHaveAttribute("type", "password");
151
+ fireEvent.change(input, { target: { value: "getpass-regression-secret" } });
152
+ fireEvent.keyDown(input, { key: "ArrowUp" });
153
+ expect(input).toHaveValue("getpass-regression-secret");
154
+ fireEvent.keyDown(input, { key: "ArrowDown" });
155
+ expect(input).toHaveValue("getpass-regression-secret");
156
+ fireEvent.keyDown(input, { key: "Enter" });
157
+ expect(onSubmitDebugger).toHaveBeenLastCalledWith(
158
+ "getpass-regression-secret",
159
+ 1,
160
+ );
161
+ expect(input).toHaveValue("");
162
+
163
+ rerender(
164
+ <TooltipProvider>
165
+ <ConsoleOutput
166
+ {...defaultProps}
167
+ consoleOutputs={[
168
+ stdinPrompt("Name: ", "marimo"),
169
+ { ...passwordPrompt, response: "" },
170
+ stdinPrompt("Name: "),
171
+ ]}
172
+ />
173
+ </TooltipProvider>,
174
+ );
175
+ const nextInput = screen.getByTestId("console-input");
176
+ fireEvent.keyDown(nextInput, { key: "ArrowUp" });
177
+ expect(nextInput).toHaveValue("marimo");
178
+ fireEvent.keyDown(nextInput, { key: "ArrowDown" });
179
+ expect(nextInput).toHaveValue("");
180
+ });
181
+
123
182
  it("should submit an empty string when Enter is pressed with no input", () => {
124
183
  // Many CLIs prompt "Press Enter to continue" and expect "" back.
125
184
  const onSubmitDebugger = vi.fn();
@@ -256,6 +256,7 @@ export const pipInstallReplacer: Replacer = (domNode: DOMNode) => {
256
256
  );
257
257
  }
258
258
 
259
+ // oxlint-disable-next-line react/jsx-no-useless-fragment -- html-react-parser replacers must return a React element.
259
260
  return <>{segments}</>;
260
261
  };
261
262
 
@@ -283,6 +284,7 @@ export const urlReplacer: Replacer = (domNode: DOMNode) => {
283
284
  return undefined;
284
285
  }
285
286
 
287
+ // oxlint-disable-next-line react/jsx-no-useless-fragment -- html-react-parser replacers must return a React element.
286
288
  return <>{result}</>;
287
289
  };
288
290
 
@@ -331,5 +333,5 @@ export const RenderTextWithLinks = ({ text }: { text: string }) => {
331
333
  );
332
334
  }, [text]);
333
335
 
334
- return <>{content}</>;
336
+ return content;
335
337
  };
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import { zodResolver } from "@hookform/resolvers/zod";
4
+ import { useAtomValue } from "jotai";
4
5
  import {
5
6
  BoxIcon,
6
7
  CheckIcon,
@@ -34,6 +35,7 @@ import {
34
35
  import { useResolvedMarimoConfig } from "@/core/config/config";
35
36
  import type { PackageOperationStatus } from "@/core/kernel/messages";
36
37
  import { useRequestClient } from "@/core/network/requests";
38
+ import { sandboxAtom } from "@/core/packages/sandbox-state";
37
39
  import { RESTART_REQUIRED_DESCRIPTION } from "@/core/packages/toast-components";
38
40
  import { isWasm } from "@/core/wasm/utils";
39
41
  import { usePackageMetadata } from "@/hooks/usePackageMetadata";
@@ -104,6 +106,7 @@ export const PackageAlert: React.FC = () => {
104
106
  const { packageAlert } = useAlerts();
105
107
  const { clearPackageAlert } = useAlertActions();
106
108
  const [userConfig] = useResolvedMarimoConfig();
109
+ const sandbox = useAtomValue(sandboxAtom);
107
110
  const [desiredPackageVersions, setDesiredPackageVersions] = useState<
108
111
  Record<string, string>
109
112
  >({});
@@ -132,8 +135,14 @@ export const PackageAlert: React.FC = () => {
132
135
  return null;
133
136
  }
134
137
 
138
+ const sandboxPackageManager =
139
+ packageAlert.source === "server" ? null : sandbox?.backend;
140
+ const packageManager =
141
+ sandboxPackageManager ?? userConfig.package_management.manager;
135
142
  const doesSupportVersioning =
136
- userConfig.package_management.manager !== "pixi";
143
+ packageAlert.source === "server" ||
144
+ sandbox !== null ||
145
+ packageManager !== "pixi";
137
146
 
138
147
  if (isMissingPackageAlert(packageAlert)) {
139
148
  return (
@@ -207,7 +216,7 @@ export const PackageAlert: React.FC = () => {
207
216
  {packageAlert.isolated ? (
208
217
  <>
209
218
  <InstallPackagesButton
210
- manager={userConfig.package_management.manager}
219
+ manager={packageManager}
211
220
  packages={packageAlert.packages.map((pkg) => {
212
221
  const parsed = parsePackageSpecifier(pkg);
213
222
  const currentExtras =
@@ -219,10 +228,12 @@ export const PackageAlert: React.FC = () => {
219
228
  source={packageAlert.source}
220
229
  />
221
230
 
222
- {!isWasm() && (
231
+ {!isWasm() && packageAlert.source !== "server" && (
223
232
  <>
224
233
  <span className="px-2 text-sm">with</span>{" "}
225
- <PackageManagerForm />
234
+ <PackageManagerForm
235
+ fixedManager={sandboxPackageManager ?? undefined}
236
+ />
226
237
  </>
227
238
  )}
228
239
  </>
@@ -449,7 +460,9 @@ const InstallPackagesButton = ({
449
460
  );
450
461
  };
451
462
 
452
- const PackageManagerForm: React.FC = () => {
463
+ const PackageManagerForm: React.FC<{
464
+ fixedManager?: PackageManagerName;
465
+ }> = ({ fixedManager }) => {
453
466
  const [config, setConfig] = useResolvedMarimoConfig();
454
467
  const { saveUserConfig } = useRequestClient();
455
468
 
@@ -490,8 +503,8 @@ const PackageManagerForm: React.FC = () => {
490
503
  <NativeSelect
491
504
  data-testid="install-package-manager-select"
492
505
  onChange={(e) => field.onChange(e.target.value)}
493
- value={field.value}
494
- disabled={field.disabled}
506
+ value={fixedManager ?? field.value}
507
+ disabled={fixedManager !== undefined || field.disabled}
495
508
  className="inline-flex mr-2"
496
509
  >
497
510
  {PackageManagerNames.map((option) => (
@@ -170,6 +170,7 @@ export const ResourceLinks: React.FC = () => {
170
170
  key={resource.title}
171
171
  href={resource.url}
172
172
  target="_blank"
173
+ rel="noreferrer"
173
174
  aria-label={`${resource.title}: ${resource.description}`}
174
175
  className="flex items-start gap-3 py-3 px-3 rounded-lg border hover:bg-accent/20 transition-colors shadow-xs"
175
176
  >
@@ -50,6 +50,7 @@ const Watermark = () => {
50
50
  <a
51
51
  href={Constants.githubPage}
52
52
  target="_blank"
53
+ rel="noreferrer"
53
54
  className="text-sm text-(--grass-11) font-bold tracking-wide transition-colors bg-(--grass-4) hover:bg-(--grass-5) border-t border-l border-(--grass-8) px-3 py-1 rounded-tl-md flex items-center gap-2"
54
55
  >
55
56
  <span>made with marimo</span>
@@ -46,21 +46,21 @@ beforeAll(() => {
46
46
  };
47
47
  }
48
48
  global.IntersectionObserver ??= class {
49
- observe() {
49
+ public observe() {
50
50
  /* noop */
51
51
  }
52
- unobserve() {
52
+ public unobserve() {
53
53
  /* noop */
54
54
  }
55
- disconnect() {
55
+ public disconnect() {
56
56
  /* noop */
57
57
  }
58
- takeRecords() {
58
+ public takeRecords() {
59
59
  return [];
60
60
  }
61
- root = null;
62
- rootMargin = "";
63
- thresholds = [];
61
+ public root = null;
62
+ public rootMargin = "";
63
+ public thresholds = [];
64
64
  } as unknown as typeof IntersectionObserver;
65
65
  });
66
66
 
@@ -42,28 +42,28 @@ describe("useVisibleCellIds", () => {
42
42
  mutationObserveSpy = vi.fn();
43
43
 
44
44
  global.IntersectionObserver = class MockIntersectionObserver {
45
- constructor(
45
+ public constructor(
46
46
  callback: IntersectionObserverCallback,
47
47
  _options?: IntersectionObserverInit,
48
48
  ) {
49
49
  intersectionCallback = callback;
50
50
  }
51
- observe = observeSpy;
52
- unobserve = vi.fn();
53
- disconnect = intersectionDisconnectSpy;
54
- root = null;
55
- rootMargin = "";
56
- thresholds = [0];
57
- takeRecords = vi.fn(() => []);
51
+ public observe = observeSpy;
52
+ public unobserve = vi.fn();
53
+ public disconnect = intersectionDisconnectSpy;
54
+ public root = null;
55
+ public rootMargin = "";
56
+ public thresholds = [0];
57
+ public takeRecords = vi.fn(() => []);
58
58
  } as unknown as typeof IntersectionObserver;
59
59
 
60
60
  global.MutationObserver = class MockMutationObserver {
61
- constructor(callback: MutationCallback) {
61
+ public constructor(callback: MutationCallback) {
62
62
  mutationCallback = callback;
63
63
  }
64
- observe = mutationObserveSpy;
65
- disconnect = mutationDisconnectSpy;
66
- takeRecords = vi.fn(() => []);
64
+ public observe = mutationObserveSpy;
65
+ public disconnect = mutationDisconnectSpy;
66
+ public takeRecords = vi.fn(() => []);
67
67
  } as unknown as typeof MutationObserver;
68
68
  });
69
69
 
@@ -76,12 +76,12 @@ describe("SlideScrollContainer", () => {
76
76
  vi.stubGlobal(
77
77
  "ResizeObserver",
78
78
  class MockResizeObserver {
79
- callback: ResizeObserverCallback;
80
- observe = vi.fn();
81
- unobserve = vi.fn();
82
- disconnect = vi.fn();
79
+ public callback: ResizeObserverCallback;
80
+ public observe = vi.fn();
81
+ public unobserve = vi.fn();
82
+ public disconnect = vi.fn();
83
83
 
84
- constructor(callback: ResizeObserverCallback) {
84
+ public constructor(callback: ResizeObserverCallback) {
85
85
  this.callback = callback;
86
86
  resizeObservers.push(this);
87
87
  }
@@ -90,9 +90,9 @@ describe("SlideScrollContainer", () => {
90
90
  vi.stubGlobal(
91
91
  "MutationObserver",
92
92
  class MockMutationObserver {
93
- observe = vi.fn();
94
- disconnect = vi.fn();
95
- takeRecords = vi.fn(() => []);
93
+ public observe = vi.fn();
94
+ public disconnect = vi.fn();
95
+ public takeRecords = vi.fn(() => []);
96
96
  },
97
97
  );
98
98
  });
@@ -0,0 +1,154 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
4
+ import type React from "react";
5
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
+ import { Dialog } from "@/components/ui/dialog";
7
+ import { TooltipProvider } from "@/components/ui/tooltip";
8
+ import { ShareStaticNotebookModal } from "../share-modal";
9
+ import { stageForPublish } from "../stage-for-publish";
10
+
11
+ const exportAsHTML = vi.fn();
12
+
13
+ vi.mock("@/core/network/requests", () => ({
14
+ useRequestClient: () => ({ exportAsHTML }),
15
+ }));
16
+ vi.mock("@/core/export/layout", () => ({
17
+ getExportLayout: vi.fn().mockResolvedValue(undefined),
18
+ }));
19
+ vi.mock("@/core/static/virtual-file-tracker", () => ({
20
+ VirtualFileTracker: { INSTANCE: { filenames: () => [] } },
21
+ }));
22
+ vi.mock("../stage-for-publish", () => ({
23
+ stageForPublish: vi.fn(),
24
+ }));
25
+
26
+ const stageForPublishMock = vi.mocked(stageForPublish);
27
+ const CLAIM_URL = "https://claim.example/abc";
28
+
29
+ function wrapper({ children }: { children: React.ReactNode }) {
30
+ return (
31
+ <TooltipProvider>
32
+ <Dialog open={true}>{children}</Dialog>
33
+ </TooltipProvider>
34
+ );
35
+ }
36
+
37
+ describe("ShareStaticNotebookModal", () => {
38
+ const onClose = vi.fn();
39
+ const windowOpen = vi.fn<typeof window.open>();
40
+
41
+ beforeEach(() => {
42
+ vi.clearAllMocks();
43
+ vi.stubGlobal("open", windowOpen);
44
+ exportAsHTML.mockResolvedValue({
45
+ contents: "<html></html>",
46
+ filename: "nb.html",
47
+ });
48
+ });
49
+
50
+ afterEach(() => {
51
+ vi.unstubAllGlobals();
52
+ });
53
+
54
+ function renderModal() {
55
+ return render(<ShareStaticNotebookModal onClose={onClose} />, {
56
+ wrapper,
57
+ });
58
+ }
59
+
60
+ it("exports with CDN assets, opens the claim page, and keeps the link in the dialog", async () => {
61
+ stageForPublishMock.mockResolvedValue(CLAIM_URL);
62
+ renderModal();
63
+
64
+ fireEvent.click(screen.getByTestId("share-static-notebook-button"));
65
+
66
+ const link = await screen.findByTestId("open-claim-page-link");
67
+ expect(link).toHaveAttribute("href", CLAIM_URL);
68
+ expect(link).toHaveAttribute("rel", "noopener noreferrer");
69
+ expect(link).toHaveAttribute("target", "_blank");
70
+
71
+ expect(windowOpen).toHaveBeenCalledWith(
72
+ CLAIM_URL,
73
+ "_blank",
74
+ "noopener,noreferrer",
75
+ );
76
+ expect(exportAsHTML).toHaveBeenCalledWith(
77
+ expect.objectContaining({
78
+ includeCode: true,
79
+ download: false,
80
+ assetUrl: expect.stringContaining("cdn.jsdelivr.net"),
81
+ }),
82
+ );
83
+ expect(stageForPublishMock).toHaveBeenCalledWith(
84
+ "nb.html",
85
+ "<html></html>",
86
+ );
87
+ // The dialog stays open so the link survives a blocked popup.
88
+ expect(onClose).not.toHaveBeenCalled();
89
+ expect(
90
+ screen.queryByTestId("share-static-notebook-button"),
91
+ ).not.toBeInTheDocument();
92
+ });
93
+
94
+ it("closes from the staged view via Done", async () => {
95
+ stageForPublishMock.mockResolvedValue(CLAIM_URL);
96
+ renderModal();
97
+
98
+ fireEvent.click(screen.getByTestId("share-static-notebook-button"));
99
+ fireEvent.click(
100
+ await screen.findByTestId("done-share-static-notebook-button"),
101
+ );
102
+
103
+ expect(onClose).toHaveBeenCalledTimes(1);
104
+ });
105
+
106
+ it("shows the failure in the dialog and allows retrying", async () => {
107
+ stageForPublishMock
108
+ .mockRejectedValueOnce(new Error("Too many uploads, try again later"))
109
+ .mockResolvedValueOnce(CLAIM_URL);
110
+ renderModal();
111
+
112
+ fireEvent.click(screen.getByTestId("share-static-notebook-button"));
113
+
114
+ const error = await screen.findByTestId("share-static-notebook-error");
115
+ expect(error).toHaveTextContent(
116
+ "Publish failed: Too many uploads, try again later",
117
+ );
118
+ expect(windowOpen).not.toHaveBeenCalled();
119
+ expect(onClose).not.toHaveBeenCalled();
120
+
121
+ const retry = screen.getByTestId("share-static-notebook-button");
122
+ expect(retry).toHaveTextContent("Try again");
123
+ expect(retry).toBeEnabled();
124
+ fireEvent.click(retry);
125
+
126
+ expect(await screen.findByTestId("open-claim-page-link")).toHaveAttribute(
127
+ "href",
128
+ CLAIM_URL,
129
+ );
130
+ });
131
+
132
+ it("disables both buttons while staging", async () => {
133
+ let resolveStage: (url: string) => void = () => undefined;
134
+ stageForPublishMock.mockImplementation(
135
+ () =>
136
+ new Promise<string>((resolve) => {
137
+ resolveStage = resolve;
138
+ }),
139
+ );
140
+ renderModal();
141
+
142
+ fireEvent.click(screen.getByTestId("share-static-notebook-button"));
143
+
144
+ await waitFor(() => {
145
+ expect(screen.getByTestId("share-static-notebook-button")).toBeDisabled();
146
+ });
147
+ expect(
148
+ screen.getByTestId("cancel-share-static-notebook-button"),
149
+ ).toBeDisabled();
150
+
151
+ resolveStage(CLAIM_URL);
152
+ await screen.findByTestId("open-claim-page-link");
153
+ });
154
+ });
@@ -0,0 +1,111 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { MAX_PUBLISH_BYTES, stageForPublish } from "../stage-for-publish";
5
+
6
+ // Opaque to the client; the shapes here are deliberately not molab's.
7
+ const PENDING = {
8
+ pendingId: "id-1",
9
+ presignedUrl: "https://upload.example/put?token=abc",
10
+ claimUrl: "https://claim.example/abc",
11
+ expiresAt: "2026-01-01T00:00:00Z",
12
+ };
13
+
14
+ function jsonResponse(body: unknown, status = 200): Response {
15
+ return new Response(JSON.stringify(body), {
16
+ status,
17
+ headers: { "Content-Type": "application/json" },
18
+ });
19
+ }
20
+
21
+ describe("stageForPublish", () => {
22
+ const fetchMock = vi.fn<typeof fetch>();
23
+
24
+ beforeEach(() => {
25
+ vi.stubGlobal("fetch", fetchMock);
26
+ });
27
+
28
+ afterEach(() => {
29
+ fetchMock.mockReset();
30
+ vi.unstubAllGlobals();
31
+ });
32
+
33
+ it("reserves a pending upload, PUTs the export, and returns the claim URL", async () => {
34
+ fetchMock
35
+ .mockResolvedValueOnce(jsonResponse(PENDING))
36
+ .mockResolvedValueOnce(new Response(null, { status: 200 }));
37
+
38
+ const claimUrl = await stageForPublish("nb.html", "<html>hi</html>");
39
+
40
+ expect(claimUrl).toBe(PENDING.claimUrl);
41
+ expect(fetchMock).toHaveBeenCalledTimes(2);
42
+
43
+ const [stageUrl, stageInit] = fetchMock.mock.calls[0];
44
+ expect(String(stageUrl)).toMatch(/\/api\/artifacts\/pending$/);
45
+ expect(stageInit?.method).toBe("POST");
46
+ expect(JSON.parse(String(stageInit?.body))).toEqual({
47
+ fileName: "nb.html",
48
+ fileSize: new Blob(["<html>hi</html>"]).size,
49
+ });
50
+
51
+ const [putUrl, putInit] = fetchMock.mock.calls[1];
52
+ expect(putUrl).toBe(PENDING.presignedUrl);
53
+ expect(putInit?.method).toBe("PUT");
54
+ expect(putInit?.body).toBeInstanceOf(Blob);
55
+ });
56
+
57
+ it("surfaces the server's error message when staging is rejected", async () => {
58
+ fetchMock.mockResolvedValueOnce(
59
+ jsonResponse({ error: "Only .html or .htm files are supported" }, 400),
60
+ );
61
+
62
+ await expect(stageForPublish("nb.txt", "x")).rejects.toThrow(
63
+ "Only .html or .htm files are supported",
64
+ );
65
+ expect(fetchMock).toHaveBeenCalledTimes(1);
66
+ });
67
+
68
+ it("explains a 429 when the body carries no message", async () => {
69
+ fetchMock.mockResolvedValueOnce(new Response("", { status: 429 }));
70
+
71
+ await expect(stageForPublish("nb.html", "x")).rejects.toThrow(
72
+ "Too many uploads, try again later",
73
+ );
74
+ });
75
+
76
+ it("falls back to a generic message for other bodiless failures", async () => {
77
+ fetchMock.mockResolvedValueOnce(new Response("", { status: 500 }));
78
+
79
+ await expect(stageForPublish("nb.html", "x")).rejects.toThrow(
80
+ "Failed to prepare the upload",
81
+ );
82
+ });
83
+
84
+ it("fails when the presigned PUT is rejected", async () => {
85
+ fetchMock
86
+ .mockResolvedValueOnce(jsonResponse(PENDING))
87
+ .mockResolvedValueOnce(new Response(null, { status: 403 }));
88
+
89
+ await expect(stageForPublish("nb.html", "x")).rejects.toThrow(
90
+ "Failed to upload the notebook export",
91
+ );
92
+ });
93
+
94
+ it("rejects exports over the size limit before touching the network", async () => {
95
+ // Stub Blob so the test doesn't allocate 100 MB.
96
+ const RealBlob = globalThis.Blob;
97
+ vi.stubGlobal(
98
+ "Blob",
99
+ class extends RealBlob {
100
+ override get size() {
101
+ return MAX_PUBLISH_BYTES + 1;
102
+ }
103
+ },
104
+ );
105
+
106
+ await expect(stageForPublish("nb.html", "x")).rejects.toThrow(
107
+ "File is too large. Maximum size is 100 MB.",
108
+ );
109
+ expect(fetchMock).not.toHaveBeenCalled();
110
+ });
111
+ });