import { describe, expect, it } from "vitest"; import { timelineModule } from "../../../modules/built-ins/timeline/timeline-module"; import { defineToolcraft, fireEvent, renderControlsPanel, renderControlsPanelWithSchema, screen, } from "../testing/controls-panel-test-utils"; describe("ControlsPanel runtime setup controls", () => { it("commits canvas size controls to runtime state on blur or Enter", () => { renderControlsPanel(); const canvasSizeGroup = screen .getByText("Canvas width") .closest( '[data-control-layout="inline"][data-control-layout-columns="2"]', ); expect(canvasSizeGroup).toBeTruthy(); expect(canvasSizeGroup?.textContent).toContain("Canvas width"); expect(canvasSizeGroup?.textContent).toContain("Canvas height"); const widthInput = screen.getByDisplayValue("320") as HTMLInputElement; fireEvent.change(widthInput, { target: { value: "640" } }); expect(screen.getByTestId("canvas-size").textContent).toBe("320,180"); expect(widthInput.value).toBe("640"); fireEvent.blur(widthInput); expect(screen.getByTestId("canvas-size").textContent).toBe("640,360"); const heightInput = screen.getByDisplayValue("360") as HTMLInputElement; fireEvent.change(heightInput, { target: { value: "720" } }); expect(screen.getByTestId("canvas-size").textContent).toBe("640,360"); fireEvent.keyDown(heightInput, { code: "Enter", key: "Enter" }); expect(screen.getByTestId("canvas-size").textContent).toBe("1280,720"); fireEvent.click(screen.getByRole("button", { name: "Reset controls" })); expect(screen.getByTestId("canvas-size").textContent).toBe("320,180"); }); it("renders editable-output aspect ratio controls with the current canvas preset", () => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, size: { height: 1080, unit: "px", width: 1440 }, sizing: { mode: "editable-output" }, }, panels: { controls: { sections: [], title: "Controls", }, }, }, modules: [], }); const { container } = renderControlsPanelWithSchema(schema); expect(screen.getByTestId("canvas-size").textContent).toBe("1440,1080"); const aspectRatioControl = container.querySelector( '[data-slot="canvas-aspect-ratio-control"]', ); expect(screen.getByText("Aspect ratio")).toBeTruthy(); expect(aspectRatioControl?.textContent).toContain("4:3"); const values = JSON.parse( screen.getByTestId("values-json").textContent ?? "{}", ); expect(values["canvas.aspectRatio"]).toEqual({ height: 3, mode: "preset", value: "4:3", width: 4, }); expect(values["canvas.size.width"]).toBe(1440); expect(values["canvas.size.height"]).toBe(1080); }); it("preserves editable-output aspect ratio after manual size edits", () => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, size: { height: 1080, unit: "px", width: 1920 }, sizing: { mode: "editable-output" }, }, panels: { controls: { sections: [], title: "Controls", }, }, }, modules: [], }); renderControlsPanelWithSchema(schema); const widthInput = screen.getByDisplayValue("1920") as HTMLInputElement; fireEvent.change(widthInput, { target: { value: "1600" } }); fireEvent.blur(widthInput); expect(screen.getByTestId("canvas-size").textContent).toBe("1600,900"); expect(screen.queryByRole("textbox", { name: "Ratio width" })).toBeNull(); expect(screen.queryByDisplayValue("40")).toBeNull(); expect(screen.queryByDisplayValue("27")).toBeNull(); expect( JSON.parse(screen.getByTestId("values-json").textContent ?? "{}"), ).toMatchObject({ "canvas.aspectRatio": { height: 9, mode: "preset", value: "16:9", width: 16, }, "canvas.size.height": 900, "canvas.size.width": 1600, }); }); it("renders raster render scale as the last technical setup control", () => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, renderScale: true, size: { height: 1080, unit: "px", width: 1920 }, sizing: { mode: "editable-output" }, }, panels: { controls: { sections: [], title: "Controls", }, }, }, modules: [], }); renderControlsPanelWithSchema(schema); const values = JSON.parse( screen.getByTestId("values-json").textContent ?? "{}", ); expect(screen.getByText("Resolution scale")).toBeTruthy(); expect(screen.getByText("2")).toBeTruthy(); expect(values["canvas.renderScale"]).toBe(2); }); it("renders timeline extended mode as runtime panel state instead of product values", () => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, renderScale: true, size: { height: 1080, unit: "px", width: 1920 }, sizing: { mode: "editable-output" }, }, panels: { controls: { sections: [], title: "Controls", }, }, }, modules: [ timelineModule({ mode: "playback", }), ], }); renderControlsPanelWithSchema(schema, undefined, { timeline: { currentTimeSeconds: 2, expanded: true, isPlaying: true }, }); const timelineField = screen .getByText("Timeline") .closest('[role="group"]'); const setupSection = timelineField?.closest("section"); const timelineSwitch = timelineField?.querySelector('[role="switch"]'); expect( (setupSection?.textContent ?? "").indexOf("Resolution scale"), ).toBeLessThan((setupSection?.textContent ?? "").indexOf("Timeline")); expect(screen.queryByRole("button", { name: "Timeline help" })).toBeNull(); expect( screen.queryByRole("button", { name: "Infinity canvas help" }), ).toBeNull(); expect(timelineSwitch?.getAttribute("aria-checked")).toBe("false"); expect(screen.getByTestId("timeline-panel-extended").textContent).toBe( "undefined", ); expect(screen.getByTestId("timeline-panel-hidden").textContent).toBe( "undefined", ); expect(screen.getByTestId("timeline-expanded").textContent).toBe("true"); fireEvent.click(timelineSwitch as HTMLElement); expect(timelineSwitch?.getAttribute("aria-checked")).toBe("true"); expect(screen.getByTestId("timeline-panel-extended").textContent).toBe( "true", ); expect(screen.getByTestId("timeline-panel-hidden").textContent).toBe( "undefined", ); expect(screen.getByTestId("timeline-expanded").textContent).toBe("true"); expect( JSON.parse(screen.getByTestId("values-json").textContent ?? "{}"), ).not.toHaveProperty("panels.timeline.extended"); fireEvent.click(screen.getByRole("button", { name: "Reset controls" })); expect(timelineSwitch?.getAttribute("aria-checked")).toBe("true"); expect(screen.getByTestId("timeline-panel-extended").textContent).toBe( "true", ); }); });