2026-05-16 11:51:44 +07:00
|
|
|
import React from "react";
|
|
|
|
|
import { fireEvent, render, screen } from "@testing-library/react";
|
|
|
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
|
import { CanvasRenderer } from "./canvas-renderer";
|
|
|
|
|
import type { Layer } from "@pien-studio/types";
|
|
|
|
|
|
|
|
|
|
vi.mock("next/image", () => ({
|
2026-05-31 03:03:49 +07:00
|
|
|
default: ({
|
|
|
|
|
alt,
|
|
|
|
|
src,
|
|
|
|
|
unoptimized,
|
|
|
|
|
...props
|
|
|
|
|
}: React.ImgHTMLAttributes<HTMLImageElement> & { unoptimized?: boolean }) =>
|
|
|
|
|
React.createElement("img", {
|
|
|
|
|
alt,
|
|
|
|
|
src,
|
|
|
|
|
"data-unoptimized": unoptimized ? "true" : undefined,
|
|
|
|
|
...props,
|
|
|
|
|
}),
|
2026-05-16 11:51:44 +07:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("../hooks/use-translations", () => ({
|
|
|
|
|
useTranslations: () => ({ t: (key: string) => key }),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
class ResizeObserverMock {
|
|
|
|
|
observe() {}
|
|
|
|
|
disconnect() {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
describe("CanvasRenderer", () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
vi.stubGlobal("ResizeObserver", ResizeObserverMock);
|
2026-05-31 03:03:49 +07:00
|
|
|
Object.defineProperty(HTMLElement.prototype, "setPointerCapture", {
|
|
|
|
|
configurable: true,
|
|
|
|
|
value: vi.fn(),
|
|
|
|
|
});
|
2026-05-16 11:51:44 +07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("keeps the rotation handle interactive", () => {
|
|
|
|
|
const layer: Layer = {
|
|
|
|
|
id: "layer-1",
|
2026-05-21 00:02:12 +07:00
|
|
|
type: "raster",
|
2026-05-31 03:03:49 +07:00
|
|
|
asset: { kind: "inline", uri: "data:image/png;base64,test" },
|
2026-05-16 11:51:44 +07:00
|
|
|
x: 0,
|
|
|
|
|
y: 0,
|
|
|
|
|
width: 100,
|
|
|
|
|
height: 100,
|
|
|
|
|
scale: 1,
|
|
|
|
|
rotation: 0,
|
|
|
|
|
opacity: 1,
|
2026-05-21 00:02:12 +07:00
|
|
|
effects: [],
|
|
|
|
|
visible: true,
|
2026-05-16 11:51:44 +07:00
|
|
|
};
|
|
|
|
|
const onRotateLayer = vi.fn();
|
|
|
|
|
|
|
|
|
|
render(
|
|
|
|
|
<CanvasRenderer
|
|
|
|
|
layers={[layer]}
|
|
|
|
|
canvasWidth={200}
|
|
|
|
|
canvasHeight={200}
|
|
|
|
|
selectedLayerId={layer.id}
|
|
|
|
|
onSelectLayer={() => undefined}
|
|
|
|
|
onMoveLayer={() => undefined}
|
|
|
|
|
onResizeLayer={() => undefined}
|
|
|
|
|
onRotateLayer={onRotateLayer}
|
|
|
|
|
isDark={false}
|
|
|
|
|
/>,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const rotateHandle = screen.getByTitle("editor.rotate");
|
|
|
|
|
expect(rotateHandle).toHaveClass("pointer-events-auto");
|
|
|
|
|
|
2026-05-31 03:03:49 +07:00
|
|
|
fireEvent(
|
|
|
|
|
rotateHandle,
|
|
|
|
|
new MouseEvent("pointerdown", {
|
|
|
|
|
bubbles: true,
|
|
|
|
|
button: 0,
|
|
|
|
|
clientX: 50,
|
|
|
|
|
clientY: 0,
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
fireEvent(
|
|
|
|
|
rotateHandle,
|
|
|
|
|
new MouseEvent("pointermove", {
|
|
|
|
|
bubbles: true,
|
|
|
|
|
clientX: 100,
|
|
|
|
|
clientY: 50,
|
|
|
|
|
}),
|
|
|
|
|
);
|
2026-05-16 11:51:44 +07:00
|
|
|
|
|
|
|
|
expect(onRotateLayer).toHaveBeenCalledWith(layer.id, 90);
|
|
|
|
|
});
|
|
|
|
|
});
|