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); } } }); });