// @vitest-environment happy-dom import { afterEach, describe, expect, it, vi } from "vitest"; import { createSpawnForm, type SpawnFormHandle } from "./spawnForm.js"; function stubApi(): RequestInit[] { const sessionRequests: RequestInit[] = []; vi.stubGlobal( "fetch", vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => { const url = String(input); if (url.includes("/api/sessions") && init?.method === "POST") { sessionRequests.push(init); return new Response(JSON.stringify({ id: "s1", command: "claude", cwd: "/srv/work" }), { status: 200, }); } if (url.includes("/api/info")) { return new Response( JSON.stringify({ hostname: "h", version: "0", home_dir: "/home/user" }), { status: 200 }, ); } if (url.includes("/api/names")) { return new Response(JSON.stringify({ names: ["amber-fox"] }), { status: 200 }); } return new Response(JSON.stringify([]), { status: 200 }); }), ); return sessionRequests; } describe("spawn form structured view", () => { let handle: SpawnFormHandle | null = null; async function drain(): Promise { for (let i = 0; i < 20; i++) await Promise.resolve(); } afterEach(async () => { handle?.destroy(); handle = null; await drain(); vi.unstubAllGlobals(); }); it("is default-on and shown for resolved Claude Code and Codex commands", async () => { stubApi(); handle = createSpawnForm({ onSuccess() {} }); document.body.appendChild(handle.el); await drain(); const wrap = handle.el.querySelector(".structured-view")!; const checkbox = wrap.querySelector("input")!; const disclosure = handle.el.querySelector(".wt-collapsible")!; expect(disclosure.hidden).toBe(true); handle.el.querySelector(".wt-toggle")!.click(); expect(disclosure.hidden).toBe(false); expect(wrap.hidden).toBe(false); expect(checkbox.checked).toBe(true); const custom = handle.el.querySelector('[data-id="custom"]')!; custom.click(); const command = handle.el.querySelector(".cmd-raw")!; command.value = "FOO=1 /usr/local/bin/codex"; command.dispatchEvent(new Event("input")); expect(wrap.hidden).toBe(false); expect(checkbox.checked).toBe(true); command.value = "opencode"; command.dispatchEvent(new Event("input")); expect(wrap.hidden).toBe(true); expect(checkbox.checked).toBe(false); }); it("keeps an unchecked box unchecked across a command change", async () => { stubApi(); handle = createSpawnForm({ onSuccess() {} }); document.body.appendChild(handle.el); await drain(); const checkbox = handle.el.querySelector("input[name=structured_view]")!; expect(checkbox.checked).toBe(true); checkbox.click(); expect(checkbox.checked).toBe(false); handle.el.querySelector('[data-id="custom"]')!.click(); const command = handle.el.querySelector(".cmd-raw")!; command.value = "codex"; command.dispatchEvent(new Event("input")); expect(checkbox.checked).toBe(false); }); it("clears the checked default when Codex changes to an unsupported command", async () => { stubApi(); handle = createSpawnForm({ onSuccess() {} }); document.body.appendChild(handle.el); await drain(); handle.el.querySelector('[data-id="custom"]')!.click(); const command = handle.el.querySelector(".cmd-raw")!; command.value = "env -i codex"; command.dispatchEvent(new Event("input")); const checkbox = handle.el.querySelector("input[name=structured_view]")!; expect(checkbox.checked).toBe(true); command.value = "opencode"; command.dispatchEvent(new Event("input")); expect(checkbox.closest(".structured-view")!.hidden).toBe(true); expect(checkbox.checked).toBe(false); }); it.each(["claude", "codex"])("emits Structured for a %s command by default", async (tool) => { const requests = stubApi(); handle = createSpawnForm({ seed: { cwd: "/srv/work", cwdRawVisible: true, worktreeEnabled: false }, onSuccess() {}, }); document.body.appendChild(handle.el); await drain(); if (tool === "codex") { handle.el.querySelector('[data-id="custom"]')!.click(); const command = handle.el.querySelector(".cmd-raw")!; command.value = "codex"; command.dispatchEvent(new Event("input")); } handle.el.requestSubmit(); await drain(); expect(requests).toHaveLength(1); expect(JSON.parse(String(requests[0].body))).toMatchObject({ command: tool, view: "Structured", }); }); it("emits no view once the operator unticks the box", async () => { const requests = stubApi(); handle = createSpawnForm({ seed: { cwd: "/srv/work", cwdRawVisible: true, worktreeEnabled: false }, onSuccess() {}, }); document.body.appendChild(handle.el); await drain(); handle.el.querySelector("input[name=structured_view]")!.click(); handle.el.requestSubmit(); await drain(); expect(requests).toHaveLength(1); expect(JSON.parse(String(requests[0].body)).view).toBeUndefined(); }); });