Files
workinf_Blender_Wasm/web/tests/e2e/nonmesh-main-reader-production.spec.ts
mes123456 d1e6b63d54
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
chore: checkpoint web Blender feature-gap work, docs and tests
- update native web_engine sources and rebuilt wasm artifacts
- add task cards, status notes and tooling scripts
- add web e2e specs, tutorial UI sources and tutorial assets
- sync golden task manifests and audit records

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-11-11 10:46:55 +08:00

86 lines
4.5 KiB
TypeScript

import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { expect, test } from "@playwright/test";
const root = path.resolve(import.meta.dirname, "../../..");
const fixturePath = path.join(root, "tests/files/web/nonmesh_scene.blend");
const fixture = fs.readFileSync(fixturePath);
const fixtureSha256 = crypto.createHash("sha256").update(fixture).digest("hex");
test("WBV2 reads non-mesh geometry and attributes from Blender Main without JS simulation", async ({ page }) => {
test.setTimeout(120_000);
await page.goto("/?engine=manual");
const result = await page.evaluate(async (bytes) => {
const { WebEngineClient } = await import("/src/engine-client/WebEngineClient.ts");
const summarize = (snapshot: any) => (snapshot.nonMeshData ?? []).map((data: any) => ({
id: data.id,
name: data.name,
type: data.type,
geometryStatus: data.geometryStatus,
pointCount: data.pointCount,
splineCount: data.splineCount,
controlPointsLength: data.controlPoints?.length ?? 0,
splineOffsetsLength: data.splineOffsets?.length ?? 0,
pointWeightsLength: data.pointWeights?.length ?? 0,
handlePointsLength: data.handlePoints?.length ?? 0,
splineTypes: data.splineTypes ?? [],
attributes: (data.attributes ?? []).map((attribute: any) => ({ name: attribute.name, domain: attribute.domain, dataType: attribute.dataType })).sort((a: any, b: any) => JSON.stringify(a).localeCompare(JSON.stringify(b))),
attributeValueNames: (data.attributeValues ?? []).map((attribute: any) => attribute.name).sort(),
textLength: typeof data.text === "string" ? data.text.length : 0,
fontCharacterCount: data.fontCharacters?.length ?? 0,
fontTextBoxCount: data.fontTextBoxes?.length ?? 0,
volumeGridCount: data.volumeGrids?.length ?? 0,
})).sort((a: any, b: any) => `${a.type}:${a.name}`.localeCompare(`${b.type}:${b.name}`));
const client = new WebEngineClient({ timeoutMs: 60_000 });
const reopenedClient = new WebEngineClient({ timeoutMs: 60_000 });
try {
const opened = await client.openBlend(Uint8Array.from(bytes).buffer);
const data = summarize(opened.snapshot);
if (data.length === 0) throw new Error("Blender Main returned no non-mesh data");
const saved = await client.saveBlend();
client.terminate();
const reopened = await reopenedClient.openBlend(saved.slice(0));
return {
browser: "chromium",
fixtureSha256: await crypto.subtle.digest("SHA-256", Uint8Array.from(bytes)).then((hash) => Array.from(new Uint8Array(hash), (value) => value.toString(16).padStart(2, "0")).join("")),
data,
reopenedData: summarize(reopened.snapshot),
openedRevision: opened.snapshot.revision,
reopenedRevision: reopened.snapshot.revision,
};
}
finally {
client.terminate();
reopenedClient.terminate();
}
}, Array.from(fixture));
fs.mkdirSync(path.join(root, "tests/golden/WBV2-P1101-000"), { recursive: true });
fs.writeFileSync(path.join(root, "tests/golden/WBV2-P1101-000/nonmesh-main-reader-production.json"), `${JSON.stringify({
schemaVersion: 1,
task: "WBV2-P1101-000",
operation: "NONMESH_MAIN_READER_CHROMIUM",
browser: "chromium",
queueMutation: false,
sourceRnaStructs: {
"rna-struct:CurvePoint": "nonMeshData[type=CURVES].pointCount + attributes[name=position]",
"rna-struct:SplinePoint": "nonMeshData[type=CURVE].pointWeights",
"rna-struct:SplinePoints": "nonMeshData[type=CURVE].pointCount",
"rna-struct:AttributeGroupCurves": "nonMeshData[type=CURVES].attributes",
"rna-struct:AttributeGroupPointCloud": "nonMeshData[type=POINT_CLOUD].attributes",
},
...result,
}, null, 2)}\n`);
expect(result.browser).toBe("chromium");
expect(result.fixtureSha256).toBe(fixtureSha256);
expect(result.openedRevision).toBe(1);
expect(result.reopenedRevision).toBe(1);
expect(result.data).toEqual(result.reopenedData);
expect(result.data.some((data: any) => ["CURVE", "SURFACE"].includes(data.type) && data.pointCount > 0)).toBe(true);
expect(result.data.some((data: any) => data.type === "FONT" && data.textLength > 0)).toBe(true);
expect(result.data.some((data: any) => data.type === "POINT_CLOUD" && data.attributes.length > 0)).toBe(true);
expect(result.data.some((data: any) => data.type === "CURVES" && data.pointCount > 0 && data.attributes.some((attribute: any) => attribute.name === "position"))).toBe(true);
expect(result.data.some((data: any) => data.type === "VOLUME")).toBe(true);
});