64 lines
3.3 KiB
TypeScript
64 lines
3.3 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import crypto from "node:crypto";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const root = path.resolve(import.meta.dirname, "../../..");
|
|
const golden = JSON.parse(fs.readFileSync(path.join(root, "tests/golden/M11-08/compositor-unsupported-gate.json"), "utf8")) as {
|
|
fixture: { path: string; sha256: string };
|
|
scene: string;
|
|
unsupportedNode: { name: string; type: string; blenderType: string };
|
|
expectedErrorCode: string;
|
|
expectedRevisionDelta: number;
|
|
};
|
|
const fixture = fs.readFileSync(path.join(root, golden.fixture.path));
|
|
|
|
test("M11-08 keeps the Blender graph intact while blocking unsupported compositor execution", async ({ page }) => {
|
|
expect(crypto.createHash("sha256").update(fixture).digest("hex")).toBe(golden.fixture.sha256);
|
|
await page.goto("/");
|
|
const result = await page.evaluate(async (input) => {
|
|
const [{ WebEngineClient }, compositor] = await Promise.all([
|
|
import("/src/engine-client/WebEngineClient.ts"),
|
|
import("/src/compositor/CompositorExecutor.ts"),
|
|
]);
|
|
const client = new WebEngineClient({ timeoutMs: 30_000 });
|
|
await client.init();
|
|
const opened = await client.openBlend(input.bytes.buffer);
|
|
const scene = opened.snapshot.scenes.find((candidate) => candidate.name === input.scene);
|
|
if (!scene?.compositorGraph) throw new Error(`Missing compositor graph ${input.scene}`);
|
|
const beforeGraph = JSON.stringify(scene.compositorGraph);
|
|
const beforeRevision = opened.snapshot.revision;
|
|
const unsupported = scene.compositorGraph.nodes.find((node) => node.type === input.unsupportedNode.type);
|
|
let gateCode = "";
|
|
let executeCode = "";
|
|
let cachedCode = "";
|
|
try { gateCode = compositor.gateCompositorGraph(scene.compositorGraph, new Set()).issues[0]?.code ?? ""; } catch (error) { gateCode = String(error); }
|
|
try { compositor.executeCompositorGraph(scene.compositorGraph, new Map(), { width: 2, height: 2 }); }
|
|
catch (error) { executeCode = error instanceof compositor.CompositorValidationError ? error.code : String(error); }
|
|
try {
|
|
await compositor.executeCompositorGraphCached(scene.compositorGraph, new Map(), new compositor.CompositorFrameCache(512), { frame: 1, width: 2, height: 2 });
|
|
}
|
|
catch (error) { cachedCode = error instanceof compositor.CompositorValidationError ? error.code : String(error); }
|
|
const after = await client.snapshot();
|
|
client.terminate();
|
|
const afterScene = after.snapshot.scenes.find((candidate) => candidate.name === input.scene);
|
|
return {
|
|
beforeGraph,
|
|
afterGraph: JSON.stringify(afterScene?.compositorGraph),
|
|
beforeRevision,
|
|
afterRevision: after.snapshot.revision,
|
|
gateCode,
|
|
executeCode,
|
|
cachedCode,
|
|
unsupported: unsupported && { name: unsupported.name, type: unsupported.type, blenderType: unsupported.blenderType },
|
|
};
|
|
}, { bytes: new Uint8Array(fixture), scene: golden.scene, unsupportedNode: golden.unsupportedNode });
|
|
|
|
expect(result.gateCode).toBe(golden.expectedErrorCode);
|
|
expect(result.executeCode).toBe(golden.expectedErrorCode);
|
|
expect(result.cachedCode).toBe(golden.expectedErrorCode);
|
|
expect(result.unsupported).toEqual(golden.unsupportedNode);
|
|
expect(result.afterGraph).toBe(result.beforeGraph);
|
|
expect(result.afterRevision - result.beforeRevision).toBe(golden.expectedRevisionDelta);
|
|
});
|