/* Copyright 2026 Marimo. All rights reserved. */ import { renderHook } from "@testing-library/react"; import { createStore, Provider } from "jotai"; import type { ReactNode } from "react"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { showCodeInRunModeAtom } from "@/core/meta/state"; import { type AppMode, kioskModeAtom, viewStateAtom } from "@/core/mode"; import { useNotebookCodeAvailable } from "../code-visibility"; interface StoreOpts { mode?: AppMode; kiosk?: boolean; showInRunMode?: boolean; } function makeStore({ mode = "read", kiosk = false, showInRunMode = true, }: StoreOpts = {}) { const store = createStore(); store.set(viewStateAtom, { mode, cellAnchor: null }); store.set(kioskModeAtom, kiosk); store.set(showCodeInRunModeAtom, showInRunMode); return store; } function wrap(store: ReturnType) { return ({ children }: { children: ReactNode }) => ( {children} ); } const cellsWithCode = [{ code: "x = 1" }, { code: "" }]; const cellsWithoutCode = [{ code: "" }, { code: "" }]; const originalHref = window.location.href; function setSearch(search: string) { window.history.replaceState(null, "", `/${search}`); } describe("useNotebookCodeAvailable", () => { beforeEach(() => { setSearch(""); }); afterEach(() => { window.history.replaceState(null, "", originalHref); }); it("returns true in edit mode regardless of cells", () => { const store = makeStore({ mode: "edit" }); const { result } = renderHook( () => useNotebookCodeAvailable(cellsWithoutCode), { wrapper: wrap(store) }, ); expect(result.current).toBe(true); }); it("returns true in present mode (only reachable from edit)", () => { const store = makeStore({ mode: "present" }); const { result } = renderHook( () => useNotebookCodeAvailable(cellsWithoutCode), { wrapper: wrap(store) }, ); expect(result.current).toBe(true); }); it("returns true in kiosk mode even when read mode and no code", () => { const store = makeStore({ mode: "read", kiosk: true, showInRunMode: false, }); const { result } = renderHook( () => useNotebookCodeAvailable(cellsWithoutCode), { wrapper: wrap(store) }, ); expect(result.current).toBe(true); }); it("returns true in read mode when at least one cell has code", () => { const store = makeStore({ mode: "read" }); const { result } = renderHook( () => useNotebookCodeAvailable(cellsWithCode), { wrapper: wrap(store) }, ); expect(result.current).toBe(true); }); it("returns false in read mode when every cell.code is empty (server stripped)", () => { const store = makeStore({ mode: "read" }); const { result } = renderHook( () => useNotebookCodeAvailable(cellsWithoutCode), { wrapper: wrap(store) }, ); expect(result.current).toBe(false); }); it("returns false in read mode when host opts out via showAppCode", () => { const store = makeStore({ mode: "read", showInRunMode: false }); const { result } = renderHook( () => useNotebookCodeAvailable(cellsWithCode), { wrapper: wrap(store) }, ); expect(result.current).toBe(false); }); it("returns false in read mode when ?include-code=false", () => { setSearch("?include-code=false"); const store = makeStore({ mode: "read" }); const { result } = renderHook( () => useNotebookCodeAvailable(cellsWithCode), { wrapper: wrap(store) }, ); expect(result.current).toBe(false); }); it("ignores ?include-code=false in kiosk mode", () => { setSearch("?include-code=false"); const store = makeStore({ mode: "read", kiosk: true }); const { result } = renderHook( () => useNotebookCodeAvailable(cellsWithoutCode), { wrapper: wrap(store) }, ); expect(result.current).toBe(true); }); it("returns false for non-edit/non-read modes (home, gallery)", () => { for (const mode of ["home", "gallery"] as const) { const store = makeStore({ mode }); const { result } = renderHook( () => useNotebookCodeAvailable(cellsWithCode), { wrapper: wrap(store) }, ); expect(result.current).toBe(false); } }); });