import { afterEach, describe, expect, test } from "bun:test" import { For } from "solid-js" import { testRender, type JSX } from "@opentui/solid" import { InlineToolRow } from "../../../src/cli/cmd/tui/routes/session/index" let testSetup: Awaited> | undefined afterEach(() => { testSetup?.renderer.destroy() testSetup = undefined }) type ToolFixture = { icon: string; label: string; error?: string } const tools: readonly ToolFixture[] = [ { icon: "✱", label: 'Grep "OPENCODE.*DB|database|sqlite|drizzle|dev.*db|data.*dir|xdg|APPDATA" in packages/opencode/src (151 matches)', }, { icon: "✱", label: 'Glob "**/*db*" in packages/opencode (6 matches)', }, { icon: "→", label: "Read packages/opencode/src/storage/db.ts [offset=1, limit=130]", }, { icon: "→", label: "Read packages/opencode/src/index.ts [offset=1, limit=100]", error: "No LSP server available for this file type.", }, { icon: "✱", label: 'Grep "export const OPENCODE_DB|OPENCODE_DB|OPENCODE_DEV|Global\\.Path\\.data|data =" in packages/opencode/src (115 matches)', }, ] as const function ShellOutput() { return ( # List files $ ls file.ts ) } function UserMessage() { return ( Check whether the next tool remains separated. ) } function Fixture(props: { errorExpanded?: boolean; before?: "shell" | "user" }) { return ( {props.before === "shell" && } {props.before === "user" && } {(item) => ( id === "message-user"} > {item.label} )} ) } async function renderFrame(component: () => JSX.Element, options: { width: number; height: number }) { testSetup = await testRender(component, options) await testSetup.renderOnce() await Bun.sleep(25) await testSetup.renderOnce() return testSetup .captureCharFrame() .split("\n") .map((line) => line.trimEnd()) .join("\n") .trimEnd() } describe("TUI inline tool wrapping", () => { test("snapshots consecutive grep, glob, and read rows at a narrow width", async () => { expect(await renderFrame(() => , { width: 72, height: 12 })).toMatchSnapshot() }) test("snapshots expanded tool errors under the tool text", async () => { expect(await renderFrame(() => , { width: 72, height: 12 })).toMatchSnapshot() }) test("keeps separation after a shell output block", async () => { expect(await renderFrame(() => , { width: 72, height: 16 })).toMatchSnapshot() }) test("keeps separation after a padded user message", async () => { expect(await renderFrame(() => , { width: 72, height: 14 })).toMatchSnapshot() }) })