import { cleanup, fireEvent, render, screen } from "@testing-library/react";
import * as React from "react";
import { afterEach, describe, expect, it } from "vitest";
import { defineToolcraft } from "../../schema/define-toolcraft";
import { CanvasShell } from "../canvas/canvas-shell";
import { ToolcraftRoot } from "./toolcraft-root";
import { TOOLCRAFT_THEME_PREFERENCE_STORAGE_KEY } from "./theme-runtime";
import { ToolbarPanel } from "./toolbar-panel";
import { useToolcraft } from "./use-toolcraft";
afterEach(() => {
cleanup();
document.documentElement.classList.remove("dark");
document.documentElement.style.colorScheme = "";
window.localStorage.clear();
});
function createSchema() {
return defineToolcraft({
canvas: { enabled: true },
panels: {
controls: {
sections: [
{
controls: {
opacity: {
defaultValue: 75,
target: "selectedLayer.opacity",
type: "slider",
},
},
},
],
title: "Controls",
},
},
});
}
function StateProbe() {
const { dispatch, state } = useToolcraft();
return (
<>
{state.canvas.offset.x},{state.canvas.offset.y}
{String(state.values["selectedLayer.opacity"])}
>
);
}
function renderToolbar() {
return render(
,
);
}
describe("ToolbarPanel", () => {
it("dispatches zoom commands", () => {
renderToolbar();
expect(screen.getByText("100%")).toBeTruthy();
fireEvent.click(screen.getByRole("button", { name: "Zoom out" }));
expect(screen.getByText("90%")).toBeTruthy();
fireEvent.click(screen.getByRole("button", { name: "Zoom in" }));
fireEvent.click(screen.getByRole("button", { name: "Zoom in" }));
expect(screen.getByText("110%")).toBeTruthy();
});
it("resets zoom from the zoom label double click", () => {
renderToolbar();
fireEvent.click(screen.getByRole("button", { name: "Zoom in" }));
expect(screen.getByText("110%")).toBeTruthy();
fireEvent.doubleClick(screen.getByText("110%"));
expect(screen.getByText("100%")).toBeTruthy();
});
it("centers the canvas through the radar command", () => {
renderToolbar();
fireEvent.click(screen.getByRole("button", { name: "Move canvas" }));
expect(screen.getByTestId("canvas-offset").textContent).toBe("24,48");
fireEvent.click(screen.getByRole("button", { name: "Center canvas" }));
expect(screen.getByTestId("canvas-offset").textContent).toBe("0,0");
});
it("binds undo and redo to runtime history", () => {
renderToolbar();
const undoButton = screen.getByRole("button", { name: "Undo" });
const redoButton = screen.getByRole("button", { name: "Redo" });
expect((undoButton as HTMLButtonElement).disabled).toBe(true);
expect((redoButton as HTMLButtonElement).disabled).toBe(true);
fireEvent.click(screen.getByRole("button", { name: "Change value" }));
expect(screen.getByTestId("opacity-value").textContent).toBe("25");
expect((undoButton as HTMLButtonElement).disabled).toBe(false);
fireEvent.click(undoButton);
expect(screen.getByTestId("opacity-value").textContent).toBe("75");
expect((redoButton as HTMLButtonElement).disabled).toBe(false);
fireEvent.click(redoButton);
expect(screen.getByTestId("opacity-value").textContent).toBe("25");
});
it("toggles the scoped editor theme through the shared runtime", () => {
const { container } = renderToolbar();
const lightButton = screen.getByRole("button", { name: "Light theme" });
const themeScope = container.querySelector(
"[data-toolcraft-theme-scope]",
);
expect(lightButton.querySelector('[data-icon="theme-light"]')).toBeTruthy();
expect(themeScope?.dataset.toolcraftTheme).toBe("dark");
expect(themeScope?.style.colorScheme).toBe("dark");
expect(document.documentElement.classList.contains("dark")).toBe(false);
expect(document.documentElement.style.colorScheme).toBe("");
fireEvent.click(lightButton);
expect(themeScope?.dataset.toolcraftTheme).toBe("light");
expect(themeScope?.style.colorScheme).toBe("light");
expect(document.documentElement.classList.contains("dark")).toBe(false);
expect(document.documentElement.style.colorScheme).toBe("");
expect(
window.localStorage.getItem(TOOLCRAFT_THEME_PREFERENCE_STORAGE_KEY),
).toBe("light");
expect(screen.getByRole("button", { name: "Dark theme" })).toBeTruthy();
expect(
screen
.getByRole("button", { name: "Dark theme" })
.querySelector('[data-icon="theme-dark"]'),
).toBeTruthy();
fireEvent.click(screen.getByRole("button", { name: "Dark theme" }));
expect(themeScope?.dataset.toolcraftTheme).toBe("dark");
expect(themeScope?.style.colorScheme).toBe("dark");
expect(document.documentElement.classList.contains("dark")).toBe(false);
expect(document.documentElement.style.colorScheme).toBe("");
expect(
window.localStorage.getItem(TOOLCRAFT_THEME_PREFERENCE_STORAGE_KEY),
).toBe("dark");
});
it("uses toolbar feature defaults from the app schema", () => {
render(
,
);
expect(screen.queryByRole("button", { name: "Undo" })).toBeNull();
expect(screen.queryByRole("button", { name: "Center canvas" })).toBeNull();
expect(screen.queryByRole("button", { name: "Light theme" })).toBeNull();
expect(screen.queryByRole("button", { name: "Zoom in" })).toBeNull();
});
});