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({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { prompt: { defaultValue: "Short prompt", label: "Prompt", target: "generation.prompt", type: "text", }, instructions: { defaultValue: "Long prompt instructions", label: "Instructions", target: "generation.instructions", type: "code", }, }, title: "Text", }, ], title: "Controls", }, }, }); 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({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { instructions: { defaultValue: initialInstructions, label: "Instructions", target: "generation.instructions", type: "code", }, }, title: "Text", }, ], title: "Controls", }, }, }); 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({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { prompt: { defaultValue: "Initial prompt", label: "Prompt", target: "generation.prompt", type: "text", }, }, title: "Text", }, ], title: "Controls", }, }, }); 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({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { fontSize: { commitMode: "setting", defaultValue: "16", label: "Font size", target: "typography.fontSize", type: "text", }, }, title: "Typography", }, ], title: "Controls", }, }, }); 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"); }); });