import { act, cleanup, render } from "@testing-library/react"; import * as React from "react"; import { afterEach, describe, expect, it, vi } from "vitest"; import { defineToolcraft } from "../../../schema/define-toolcraft"; import type { ToolcraftExternalStore } from "../../../state/toolcraft-external-store"; import { ToolcraftRoot } from "../../app-shell/toolcraft-root"; import { useToolcraftStore } from "../../app-shell/toolcraft-store-context"; import { ControlsPanel } from "../controls-panel"; const counters = vi.hoisted(() => ({ commits: new Map(), executions: new Map(), })); function increment(counter: Map, id: string): void { counter.set(id, (counter.get(id) ?? 0) + 1); } function CommitProbe({ id }: { id: string }): null { React.useLayoutEffect(() => { increment(counters.commits, id); }); return null; } vi.mock("@repo/ui", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, PanelSection: (props: React.ComponentProps) => ( <> ), }; }); vi.mock("../renderers/controls-panel-basic-renderers", async (importOriginal) => { const actual = await importOriginal< typeof import("../renderers/controls-panel-basic-renderers") >(); return { ...actual, renderBasicControl: ( args: Parameters[0], ): React.ReactNode => { increment(counters.executions, args.id); return ( <> {actual.renderBasicControl(args)} ); }, }; }); vi.mock("../renderers/controls-panel-compound-renderers", async (importOriginal) => { const actual = await importOriginal< typeof import("../renderers/controls-panel-compound-renderers") >(); return { ...actual, renderCompoundColorGroup: ( args: Parameters[0], ): React.ReactNode => { const id = args.entries.map(([controlId]) => controlId).join("+"); increment(counters.executions, id); return ( <> {actual.renderCompoundColorGroup(args)} ); }, }; }); function CaptureStore({ capture, }: { capture: (store: ToolcraftExternalStore) => void; }): null { capture(useToolcraftStore()); return null; } function resetCounters(): void { counters.commits.clear(); counters.executions.clear(); } function count(counter: Map, id: string): number { return counter.get(id) ?? 0; } function renderIsolationPanel( schema: ReturnType, initialState?: React.ComponentProps["initialState"], ): ToolcraftExternalStore { let store: ToolcraftExternalStore | undefined; render( { store = value; }} /> , ); if (!store) { throw new Error("Expected Toolcraft store to be captured."); } resetCounters(); return store; } afterEach(() => { cleanup(); resetCounters(); window.localStorage.clear(); }); describe("ControlsPanel render isolation", () => { it("commits only the slider whose target changed", () => { const schema = defineToolcraft({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { alpha: { defaultValue: 10, label: "Alpha", max: 100, min: 0, target: "shape.alpha", type: "slider", }, beta: { defaultValue: 20, label: "Beta", max: 100, min: 0, target: "shape.beta", type: "slider", }, }, title: "Transform", }, ], title: "Controls", }, }, }); const store = renderIsolationPanel(schema); act(() => { store.dispatch({ target: "shape.alpha", type: "controls.setValue", value: 30, }); }); expect(count(counters.executions, "alpha")).toBe(1); expect(count(counters.commits, "control:alpha")).toBe(1); expect(count(counters.executions, "beta")).toBe(0); expect(count(counters.commits, "control:beta")).toBe(0); expect(count(counters.commits, "section:Transform")).toBe(0); }); it("keeps control items and their section cold across transient commits", () => { const schema = defineToolcraft({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { alpha: { defaultValue: 10, label: "Alpha", max: 100, min: 0, target: "shape.alpha", type: "slider", }, beta: { defaultValue: 20, label: "Beta", max: 100, min: 0, target: "shape.beta", type: "slider", }, }, title: "Transform", }, ], title: "Controls", }, timeline: { mode: "playback" }, }, }); const store = renderIsolationPanel(schema); act(() => { store.dispatchTransient({ currentTimeSeconds: 1, type: "timeline.setCurrentTime" }); store.commitTransient("playback"); store.dispatchTransient({ offset: { x: 12, y: -8 }, type: "canvas.setViewport", zoom: 125, }); store.commitTransient("viewport"); }); expect(count(counters.executions, "alpha")).toBe(0); expect(count(counters.commits, "control:alpha")).toBe(0); expect(count(counters.executions, "beta")).toBe(0); expect(count(counters.commits, "control:beta")).toBe(0); expect(count(counters.commits, "section:Transform")).toBe(0); act(() => { store.dispatch({ target: "shape.alpha", type: "controls.setValue", value: 30 }); }); expect(count(counters.executions, "alpha")).toBe(1); expect(count(counters.commits, "control:alpha")).toBe(1); expect(count(counters.executions, "beta")).toBe(0); expect(count(counters.commits, "control:beta")).toBe(0); expect(count(counters.commits, "section:Transform")).toBe(0); }); it("updates conditional controls only for their declared targets", () => { const schema = defineToolcraft({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { disabledAmount: { defaultValue: 10, disabledWhen: { equals: true, target: "mode.disabled" }, label: "Disabled amount", max: 100, min: 0, target: "shape.disabledAmount", type: "slider", }, visibleAmount: { defaultValue: 20, label: "Visible amount", max: 100, min: 0, target: "shape.visibleAmount", type: "slider", visibleWhen: { equals: true, target: "mode.visible" }, }, }, title: "Conditional", }, ], title: "Controls", }, }, }); const store = renderIsolationPanel(schema, { values: { "mode.disabled": false, "mode.visible": false }, }); act(() => { store.dispatch({ target: "unrelated.value", type: "controls.setValue", value: 1, }); }); expect(count(counters.executions, "disabledAmount")).toBe(0); expect(count(counters.executions, "visibleAmount")).toBe(0); expect(count(counters.commits, "section:Conditional")).toBe(0); act(() => { store.dispatch({ target: "mode.disabled", type: "controls.setValue", value: true, }); }); expect(count(counters.executions, "disabledAmount")).toBe(1); expect(count(counters.commits, "control:disabledAmount")).toBe(1); expect(count(counters.executions, "visibleAmount")).toBe(0); expect(count(counters.commits, "section:Conditional")).toBe(0); resetCounters(); act(() => { store.dispatch({ target: "mode.visible", type: "controls.setValue", value: true, }); }); expect(count(counters.executions, "visibleAmount")).toBe(1); expect(count(counters.commits, "control:visibleAmount")).toBe(1); expect(count(counters.executions, "disabledAmount")).toBe(0); expect(count(counters.commits, "control:disabledAmount")).toBe(0); expect(count(counters.commits, "section:Conditional")).toBe(1); }); it("isolates keyframe group and selection metadata by target", () => { const schema = defineToolcraft({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { alpha: { defaultValue: 10, label: "Alpha", max: 100, min: 0, target: "shape.alpha", type: "slider", }, beta: { defaultValue: 20, label: "Beta", max: 100, min: 0, target: "shape.beta", type: "slider", }, }, title: "Animation", }, ], title: "Controls", }, timeline: true, }, }); const store = renderIsolationPanel(schema, { timeline: { expanded: true, keyframeGroups: [ { controlId: "shape.alpha", keyframes: [ { controlId: "shape.alpha", controlLabel: "Alpha", id: "alpha-0", timeSeconds: 0, value: 10, valueLabel: "10", }, ], label: "Alpha", }, { controlId: "shape.beta", keyframes: [ { controlId: "shape.beta", controlLabel: "Beta", id: "beta-0", timeSeconds: 0, value: 20, valueLabel: "20", }, ], label: "Beta", }, ], }, }); act(() => { store.dispatch({ keyframeId: "alpha-0", type: "timeline.selectKeyframe" }); }); expect(count(counters.executions, "alpha")).toBe(1); expect(count(counters.commits, "control:alpha")).toBe(1); expect(count(counters.executions, "beta")).toBe(0); expect(count(counters.commits, "control:beta")).toBe(0); expect(count(counters.commits, "section:Animation")).toBe(0); resetCounters(); act(() => { store.dispatch({ keyframeId: "beta-0", type: "timeline.selectKeyframe" }); }); resetCounters(); act(() => { store.dispatch({ easing: { type: "step" }, keyframeId: "alpha-0", type: "timeline.changeKeyframeEasing", }); }); expect(count(counters.executions, "alpha")).toBe(1); expect(count(counters.commits, "control:alpha")).toBe(1); expect(count(counters.executions, "beta")).toBe(0); expect(count(counters.commits, "control:beta")).toBe(0); expect(count(counters.commits, "section:Animation")).toBe(0); }); it("preserves isolation inside inline and compound render groups", () => { const schema = defineToolcraft({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { enabled: { defaultValue: true, label: "Enabled", target: "shape.enabled", type: "switch", }, locked: { defaultValue: false, label: "Locked", target: "shape.locked", type: "switch", }, fill: { defaultValue: { hex: "#000000" }, label: "Fill", semanticGroup: "shape-colors", target: "shape.fill", type: "color", }, stroke: { defaultValue: { hex: "#ffffff" }, label: "Stroke", semanticGroup: "shape-colors", target: "shape.stroke", type: "color", }, }, layoutGroups: [ { controls: ["enabled", "locked"], layout: "inline" }, ], title: "Appearance", }, ], title: "Controls", }, }, }); const store = renderIsolationPanel(schema); act(() => { store.dispatch({ target: "shape.enabled", type: "controls.setValue", value: false, }); }); expect(count(counters.executions, "enabled")).toBe(1); expect(count(counters.executions, "locked")).toBe(0); expect(count(counters.executions, "fill+stroke")).toBe(0); expect(count(counters.commits, "section:Appearance")).toBe(0); resetCounters(); act(() => { store.dispatch({ target: "shape.fill", type: "controls.setValue", value: { hex: "#ff0000" }, }); }); expect(count(counters.executions, "fill+stroke")).toBe(1); expect(count(counters.commits, "control:fill+stroke")).toBe(1); expect(count(counters.executions, "enabled")).toBe(0); expect(count(counters.executions, "locked")).toBe(0); expect(count(counters.commits, "section:Appearance")).toBe(0); }); });