import { describe, expect, it } from "vitest"; import { defineToolcraft, fireEvent, renderControlsPanel, renderControlsPanelWithSchema, screen, } from "../testing/controls-panel-test-utils"; describe("ControlsPanel text input controls", () => { it("renders editable text inputs and textareas with caret cursor affordance", () => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: { controls: { sections: [ { id: "test-section-1", controls: { prompt: { applicability: { mode: "always" as const }, defaultValue: "Short prompt", label: "Prompt", target: "generation.prompt", type: "text", }, instructions: { applicability: { mode: "always" as const }, defaultValue: "Long prompt instructions", label: "Instructions", target: "generation.instructions", type: "code", }, }, title: "Text", }, ], title: "Controls", }, }, }, modules: [], }); renderControlsPanelWithSchema(schema); expect(screen.getByDisplayValue("Short prompt").className).toContain( "cursor-text", ); expect( screen.getByDisplayValue("Long prompt instructions").className, ).toContain("cursor-text"); expect( screen.getByDisplayValue("Long prompt instructions").className, ).toContain("max-h-[calc(12lh+12px)]"); expect( screen.getByDisplayValue("Long prompt instructions").className, ).toContain("overflow-y-auto"); }); it("preserves newline characters in code textarea values by default", () => { const initialInstructions = "First line\nSecond line"; const editedInstructions = "Alpha\nBeta\nGamma"; const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: { controls: { sections: [ { id: "test-section-2", controls: { instructions: { applicability: { mode: "always" as const }, defaultValue: initialInstructions, label: "Instructions", target: "generation.instructions", type: "code", }, }, title: "Text", }, ], title: "Controls", }, }, }, modules: [], }); renderControlsPanelWithSchema(schema); const textarea = screen.getByLabelText( "Instructions", ) as HTMLTextAreaElement; expect(textarea.tagName).toBe("TEXTAREA"); expect(textarea.value).toBe(initialInstructions); fireEvent.change(textarea, { target: { value: editedInstructions } }); expect(textarea.value).toBe(editedInstructions); expect(screen.getByTestId("values-json").textContent).toContain( `"generation.instructions":${JSON.stringify(editedInstructions)}`, ); }); it("applies text input values while typing", () => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: { controls: { sections: [ { id: "test-section-3", controls: { prompt: { applicability: { mode: "always" as const }, defaultValue: "Initial prompt", label: "Prompt", target: "generation.prompt", type: "text", }, }, title: "Text", }, ], title: "Controls", }, }, }, modules: [], }); renderControlsPanelWithSchema(schema); const input = screen.getByDisplayValue( "Initial prompt", ) as HTMLInputElement; fireEvent.change(input, { target: { value: "Live prompt" } }); expect(input.value).toBe("Live prompt"); expect(screen.getByTestId("values-json").textContent).toContain( '"generation.prompt":"Live prompt"', ); }); it("commits setting text inputs on blur or Enter", () => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: { controls: { sections: [ { id: "test-section-4", controls: { fontSize: { applicability: { mode: "always" as const }, commitMode: "setting", defaultValue: "16", label: "Font size", target: "typography.fontSize", type: "text", }, }, title: "Typography", }, ], title: "Controls", }, }, }, modules: [], }); renderControlsPanelWithSchema(schema); const input = screen.getByDisplayValue("16") as HTMLInputElement; fireEvent.change(input, { target: { value: "24" } }); expect(input.value).toBe("24"); expect(screen.getByTestId("values-json").textContent).toContain( '"typography.fontSize":"16"', ); fireEvent.blur(input); expect(screen.getByTestId("values-json").textContent).toContain( '"typography.fontSize":"24"', ); fireEvent.change(input, { target: { value: "32" } }); expect(screen.getByTestId("values-json").textContent).toContain( '"typography.fontSize":"24"', ); fireEvent.keyDown(input, { code: "Enter", key: "Enter" }); expect(screen.getByTestId("values-json").textContent).toContain( '"typography.fontSize":"32"', ); fireEvent.change(input, { target: { value: "" } }); expect(input.value).toBe(""); fireEvent.blur(input); expect(screen.getByDisplayValue("16")).toBeTruthy(); expect(screen.getByTestId("values-json").textContent).toContain( '"typography.fontSize":"16"', ); }); it("applies empty text input values while typing and reset restores defaults", () => { renderControlsPanel(); const promptInput = screen.getByDisplayValue( "Initial prompt", ) as HTMLInputElement; fireEvent.change(promptInput, { target: { value: "" } }); expect(promptInput.value).toBe(""); expect(screen.getByTestId("prompt-value").textContent).toBe(""); fireEvent.change(promptInput, { target: { value: "Draft prompt" } }); expect(screen.getByTestId("prompt-value").textContent).toBe("Draft prompt"); fireEvent.click(screen.getByRole("button", { name: "Reset controls" })); expect(screen.getByDisplayValue("Initial prompt")).toBeTruthy(); expect(screen.getByTestId("prompt-value").textContent).toBe( "Initial prompt", ); }); });