import { cleanup, fireEvent, screen } from "@testing-library/react"; import * as React from "react"; import { afterEach, describe, expect, it } from "vitest"; import { useToolcraftDispatch } from "../app-shell/use-toolcraft"; import { createSchema, renderCanvasShell } from "./canvas-shell-test-utils"; afterEach(() => { cleanup(); }); describe("CanvasShell media rendering", () => { function InfinityToggle(): React.JSX.Element { const dispatch = useToolcraftDispatch(); return ( ); } it("hides media when a parent layer group is hidden", () => { renderCanvasShell({ initialState: { layers: [ { collapsed: false, displayName: "Scene Group", id: "group-1", kind: "group", name: "scene-group", visible: false, }, { displayName: "Layer 1", id: "layer-1", kind: "layer", name: "layer-1", parentGroupId: "group-1", visible: true, }, ], mediaAssets: [ { sourceSize: { height: 200, unit: "px", width: 300 }, assetKind: "image", lifecycle: "ready", resourceRef: "data:image/png;base64,test", fileName: "material.png", id: "media-1", layerId: "layer-1", mimeType: "image/png", position: { x: 0, y: 0 }, size: { height: 200, unit: "px", width: 300 }, }, ], selectedLayerId: "layer-1", }, schema: createSchema(), }); expect( screen.queryByRole("button", { name: "Select material.png" }), ).toBeNull(); }); it("hides unavailable image resources", () => { renderCanvasShell({ initialState: { layers: [ { displayName: "Unavailable", id: "unavailable-layer", kind: "layer", name: "unavailable", visible: true, }, ], mediaAssets: [ { assetKind: "image", error: { code: "binary-resource-unavailable", message: "The image resource is unavailable.", }, fileName: "unavailable.png", id: "unavailable-image", layerId: "unavailable-layer", lifecycle: "unavailable", mimeType: "image/png", position: { x: 0, y: 0 }, resourceRef: `media:image:sha256:${"b".repeat(64)}`, size: { height: 200, unit: "px", width: 300 }, sourceSize: { height: 200, unit: "px", width: 300 }, }, ], }, schema: createSchema(), }); expect( screen.queryByRole("button", { name: "Select unavailable.png" }), ).toBeNull(); }); it("keeps one canonical image layer across finite and infinite modes", () => { renderCanvasShell({ afterCanvas: , initialState: { layers: [ { displayName: "Layer 1", id: "layer-1", kind: "layer", name: "layer-1", visible: true, }, ], mediaAssets: [ { assetKind: "image", fileName: "material.png", id: "media-1", layerId: "layer-1", lifecycle: "ready", mimeType: "image/png", position: { x: 48, y: -24 }, resourceRef: `media:image:sha256:${"a".repeat(64)}`, size: { height: 200, unit: "px", width: 300 }, sourceSize: { height: 100, unit: "px", width: 400 }, transform: { flipHorizontal: true, rotationDeg: 90 }, }, ], selectedLayerId: "layer-1", }, schema: createSchema(), }); const finiteLayer = screen.getByRole("button", { name: "Select material.png", }); expect(finiteLayer.style.cssText).toContain("height: 200px"); expect(finiteLayer.style.cssText).toContain("left: -102px"); expect(finiteLayer.style.cssText).toContain("top: -124px"); expect(finiteLayer.style.cssText).toContain("width: 300px"); expect(finiteLayer.style.transform).toBe("rotate(90deg) scale(-1, 1)"); expect(finiteLayer.dataset.selected).toBe("true"); const finiteStyle = finiteLayer.style.cssText; expect( document.querySelector("[data-toolcraft-canvas-surface]") ?.dataset.toolcraftCanvasMode, ).toBe("finite"); fireEvent.click(screen.getByRole("button", { name: "Enable Infinity" })); const infiniteLayer = screen.getByRole("button", { name: "Select material.png", }); expect(infiniteLayer).toBe(finiteLayer); expect(infiniteLayer.style.cssText).toBe(finiteStyle); expect(infiniteLayer.dataset.selected).toBe("true"); expect( document.querySelector("[data-toolcraft-canvas-surface]") ?.dataset.toolcraftCanvasMode, ).toBe("infinite"); }); it("positions uploaded images by their own frame in infinite mode", () => { renderCanvasShell({ initialState: { canvas: { mode: "infinite", offset: { x: 0, y: 0 }, size: { height: 200, unit: "px", width: 300 }, zoom: 100, }, layers: [ { displayName: "Layer 1", id: "layer-1", kind: "layer", name: "layer-1", visible: true, }, ], mediaAssets: [ { sourceSize: { height: 120, unit: "px", width: 240 }, assetKind: "image", lifecycle: "ready", resourceRef: "data:image/png;base64,test", fileName: "material.png", id: "media-1", layerId: "layer-1", mimeType: "image/png", position: { x: 48, y: -24 }, size: { height: 120, unit: "px", width: 240 }, transform: { flipHorizontal: true, rotationDeg: 90 }, }, ], }, schema: createSchema(), }); const mediaButton = screen.getByRole("button", { name: "Select material.png", }); const mediaImage = screen.getByRole("img", { name: "material.png" }); expect(mediaButton.style.left).toBe("-72px"); expect(mediaButton.style.top).toBe("-84px"); expect(mediaButton.style.width).toBe("240px"); expect(mediaButton.style.height).toBe("120px"); expect(mediaButton.style.transform).toContain("rotate(90deg) scale(-1, 1)"); expect(mediaImage.getAttribute("style")).toBeNull(); }); });