import { cleanup, render, screen } from "@testing-library/react";
import { afterEach, describe, expect, it } from "vitest";
import { ToolcraftRoot } from "../app-shell/toolcraft-root";
import { CanvasStateProbe, createSchema, renderCanvasShell } from "./canvas-shell-test-utils";
afterEach(() => { cleanup(); window.localStorage.clear(); });
function browserZoomEvent(type: string): Event {
return type === "wheel"
? new WheelEvent(type, { bubbles: true, cancelable: true, ctrlKey: true, deltaY: -100 })
: new Event(type, { bubbles: true, cancelable: true });
}
describe("Toolcraft browser zoom boundary", () => {
it("blocks page zoom over portaled UI without changing canvas or blocking ordinary scroll", () => {
const { container } = renderCanvasShell({ afterCanvas: });
const portalRoot = container.querySelector("[data-toolcraft-portal-root]")!;
const option = document.createElement("div");
portalRoot.append(option);
for (const type of ["wheel", "gesturestart", "gesturechange", "gestureend"]) {
const event = browserZoomEvent(type);
expect(option.dispatchEvent(event)).toBe(false);
expect(event.defaultPrevented).toBe(true);
}
expect(option.dispatchEvent(new WheelEvent("wheel", { bubbles: true, cancelable: true, deltaY: 40 }))).toBe(true);
expect(screen.getByTestId("canvas-offset").textContent).toBe("0,0");
expect(screen.getByTestId("canvas-zoom").textContent).toBe("100");
// The host page outside Toolcraft retains its normal accessibility zoom.
expect(document.body.dispatchEvent(browserZoomEvent("wheel"))).toBe(true);
});
it("protects panels even without a mounted canvas", () => {
render();
expect(screen.getByRole("button", { name: "Panel" }).dispatchEvent(browserZoomEvent("wheel"))).toBe(false);
});
it("removes capture-phase native gesture listeners when the canvas unmounts", () => {
const { unmount } = renderCanvasShell({ frameProps: { "data-slot": "toolcraft-runtime-app" } as React.HTMLAttributes });
const canvas = screen.getByRole("application", { name: "Canvas viewport" });
const workspace = canvas.parentElement!;
unmount();
for (const target of [canvas, workspace]) {
for (const type of ["wheel", "gesturestart", "gesturechange", "gestureend"]) {
expect(target.dispatchEvent(browserZoomEvent(type))).toBe(true);
}
}
});
});