import { describe, expect, it } from "vitest"; import { defineToolcraft, fireEvent, renderControlsPanelWithSchema, screen, } from "../testing/controls-panel-test-utils"; describe("ControlsPanel gradient control", () => { it.each([ ["linear", "Linear"], ["radial", "Radial"], ["angular", "Angular"], ["diamond", "Diamond"], ] as const)( "preserves %s gradient type in the gradient select", (gradientType, label) => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: { controls: { sections: [ { id: "test-section-1", controls: { gradient: { applicability: { mode: "always" as const }, defaultValue: { angle: 138, gradientType, stops: [ { color: "#111111", position: "0%" }, { color: "#14B8FF", position: "45%" }, { color: "#F472B6", position: "76%" }, ], }, label: "Gradient", target: "style.gradient", type: "gradient", }, }, title: "Gradient", }, ], title: "Generation Controls", }, }, }, modules: [], }); const { container } = renderControlsPanelWithSchema(schema); const gradientSelect = container.querySelector( '[data-slot="select-trigger"]', ); expect(gradientSelect?.textContent).toContain(label); }, ); it("commits gradient stop position inputs on blur or Enter with a separated percent suffix", () => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: { controls: { sections: [ { id: "test-section-2", controls: { gradient: { applicability: { mode: "always" as const }, defaultValue: { angle: 90, gradientType: "linear", stops: [ { color: "#111111", position: "0%" }, { color: "#FFFFFF", position: "100%" }, ], }, label: "Gradient", target: "style.gradient", type: "gradient", }, }, title: "Gradient", }, ], title: "Generation Controls", }, }, }, modules: [], }); renderControlsPanelWithSchema(schema); const firstPositionInput = screen.getByLabelText( "Stop 1 position", ) as HTMLInputElement; const secondPositionInput = screen.getByLabelText( "Stop 2 position", ) as HTMLInputElement; const firstPositionGroup = firstPositionInput.closest( '[data-slot="input-group"]', ); const firstOpacityInput = screen.getByLabelText("Stop 1 opacity"); const stopsList = firstPositionInput.closest( '[data-slot="gradient-stops-list"]', ); const gradientControlItem = stopsList?.closest( "[data-control-item-compound-context]", ); const firstStopGrid = firstPositionInput .closest('[data-slot="field"]') ?.querySelector('[data-slot="gradient-stop-row-grid"]'); expect(firstPositionInput.value).toBe("0"); expect(firstPositionGroup?.textContent).toContain("%"); expect(stopsList?.className).not.toContain("border-y"); expect(gradientControlItem).toBeNull(); expect(firstPositionInput.className.split(/\s+/)).toContain("pl-[5px]"); expect(firstOpacityInput.className.split(/\s+/)).toContain("pl-[5px]"); expect(firstStopGrid?.className).toContain( "grid-cols-[3.5rem_minmax(0,1fr)_1.5rem]", ); fireEvent.change(firstPositionInput, { target: { value: "25" } }); expect( JSON.parse(screen.getByTestId("gradient-value").textContent ?? "{}"), ).toMatchObject({ stops: [{ position: "0%" }, { position: "100%" }], }); fireEvent.blur(firstPositionInput); expect( JSON.parse(screen.getByTestId("gradient-value").textContent ?? "{}"), ).toMatchObject({ stops: [{ position: "25%" }, { position: "100%" }], }); fireEvent.change(secondPositionInput, { target: { value: "75" } }); expect( JSON.parse(screen.getByTestId("gradient-value").textContent ?? "{}"), ).toMatchObject({ stops: [{ position: "25%" }, { position: "100%" }], }); fireEvent.keyDown(secondPositionInput, { code: "Enter", key: "Enter" }); expect( JSON.parse(screen.getByTestId("gradient-value").textContent ?? "{}"), ).toMatchObject({ stops: [{ position: "25%" }, { position: "75%" }], }); }); });