Advance M8-M11 parity workflows
This commit is contained in:
63
web/tests/e2e/compositor-unsupported-gate.spec.ts
Normal file
63
web/tests/e2e/compositor-unsupported-gate.spec.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user