Files
lemonspace_app/tests/use-pipeline-preview.test.ts

123 lines
3.1 KiB
TypeScript

// @vitest-environment jsdom
import { act, createElement } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { emptyHistogram } from "@/lib/image-pipeline/histogram";
import type { PipelineStep } from "@/lib/image-pipeline/contracts";
const workerClientMocks = vi.hoisted(() => ({
renderPreviewWithWorkerFallback: vi.fn(),
}));
vi.mock("@/lib/image-pipeline/worker-client", () => ({
isPipelineAbortError: () => false,
renderPreviewWithWorkerFallback: workerClientMocks.renderPreviewWithWorkerFallback,
}));
import { usePipelinePreview } from "@/hooks/use-pipeline-preview";
function PreviewHarness({
sourceUrl,
steps,
}: {
sourceUrl: string | null;
steps: PipelineStep[];
}) {
const { canvasRef } = usePipelinePreview({
sourceUrl,
steps,
nodeWidth: 320,
});
return createElement("canvas", { ref: canvasRef });
}
(globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
describe("usePipelinePreview", () => {
let container: HTMLDivElement | null = null;
let root: Root | null = null;
beforeEach(() => {
vi.useFakeTimers();
workerClientMocks.renderPreviewWithWorkerFallback.mockReset();
workerClientMocks.renderPreviewWithWorkerFallback.mockResolvedValue({
width: 120,
height: 80,
imageData: { data: new Uint8ClampedArray(120 * 80 * 4) },
histogram: emptyHistogram(),
});
vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockReturnValue({
putImageData: vi.fn(),
} as unknown as CanvasRenderingContext2D);
container = document.createElement("div");
document.body.appendChild(container);
root = createRoot(container);
});
afterEach(async () => {
vi.restoreAllMocks();
if (root) {
await act(async () => {
root?.unmount();
});
}
container?.remove();
root = null;
container = null;
vi.useRealTimers();
});
it("does not restart preview rendering when only step references change", async () => {
const stepsA: PipelineStep[] = [
{
nodeId: "light-1",
type: "light-adjust",
params: { brightness: 10 },
},
];
await act(async () => {
root?.render(
createElement(PreviewHarness, {
sourceUrl: "https://cdn.example.com/source.png",
steps: stepsA,
}),
);
});
await act(async () => {
vi.advanceTimersByTime(16);
await Promise.resolve();
});
const stepsB: PipelineStep[] = [
{
nodeId: "light-1",
type: "light-adjust",
params: { brightness: 10 },
},
];
await act(async () => {
root?.render(
createElement(PreviewHarness, {
sourceUrl: "https://cdn.example.com/source.png",
steps: stepsB,
}),
);
});
await act(async () => {
vi.advanceTimersByTime(16);
await Promise.resolve();
});
expect(workerClientMocks.renderPreviewWithWorkerFallback).toHaveBeenCalledTimes(1);
});
});