import { expect, test } from "@playwright/test"; 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/M10-11/nla-evaluation.json"), "utf8")); const blendBytes = fs.readFileSync(path.join(root, golden.fixture)); test("M10-11 evaluates NLA track, strip and time mapping through the production Worker", async ({ page }) => { test.setTimeout(120_000); await page.goto("/"); const result = await page.evaluate(async ({ bytes, expected }) => { const { WebEngineClient } = await import("/src/engine-client/WebEngineClient.ts"); const client = new WebEngineClient({ timeoutMs: 60_000 }); await client.init(); const source = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer; const opened = await client.openBlend(source); const initial = JSON.stringify({ nlaTracks: opened.snapshot.nlaTracks, animations: opened.snapshot.animations }); const samples = []; for (const frame of expected.frames) { await client.applyCommand({ type: "setFrame", frame: frame.frame }); const report = await client.evaluateDepsgraph(); const mesh = report.depsgraph.meshes.find((candidate) => candidate.objectId === `object:${expected.object}`); samples.push({ frame: frame.frame, status: report.depsgraph.status, worldMatrix: mesh?.worldMatrix ?? null }); } const after = await client.snapshot(); client.terminate(); return { snapshot: opened.snapshot, initial, after: JSON.stringify({ nlaTracks: after.snapshot.nlaTracks, animations: after.snapshot.animations }), samples }; }, { bytes: new Uint8Array(blendBytes), expected: golden }); expect(result.snapshot.nlaTracks).toHaveLength(golden.tracks.length); expect(result.snapshot.nlaTracks[0].strips).toHaveLength(golden.tracks[0].strips.length); expect(result.after).toBe(result.initial); expect(result.samples).toHaveLength(golden.frames.length); for (const [index, sample] of result.samples.entries()) { expect(sample.status, `frame ${sample.frame}`).toBe("EVALUATED"); expect(sample.worldMatrix, `frame ${sample.frame}`).not.toBeNull(); const maximumError = Math.max(...sample.worldMatrix.map((value: number, matrixIndex: number) => Math.abs(value - golden.frames[index].worldMatrix[matrixIndex]))); expect(maximumError, `frame ${sample.frame} matrix error`).toBeLessThanOrEqual(golden.tolerance.maxMatrixError); } });