Files
workinf_Blender_Wasm/web/tests/e2e/wbv2-modifier-matrix-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

62 lines
3.5 KiB
TypeScript

import { test, expect } from "@playwright/test";
import fs from "node:fs";
import path from "node:path";
const root = path.resolve(import.meta.dirname, "../../..");
const fixture = fs.readFileSync(path.join(root, "tests/files/web/basic_scene.blend"));
const receiptDir = path.join(root, "tests/golden/WBV2-P1425-001/verification");
fs.mkdirSync(receiptDir, { recursive: true });
const types = [
"WEIGHTED_NORMAL", "CORRECTIVE_SMOOTH", "LAPLACIANSMOOTH", "MASK", "NORMAL_EDIT",
"SKIN", "UV_PROJECT", "UV_WARP", "WARP", "DATA_TRANSFER", "VERTEX_WEIGHT_EDIT",
"VERTEX_WEIGHT_MIX", "VERTEX_WEIGHT_PROXIMITY", "LAPLACIANDEFORM", "PARTICLE_INSTANCE",
"SURFACE", "MESH_CACHE", "MESH_SEQUENCE_CACHE", "MULTIRES", "EXPLODE",
];
test("expanded modifier whitelist adds, evaluates and removes in native Main", async ({ page }) => {
test.setTimeout(180_000);
await page.goto("/?engine=manual");
const result = await page.evaluate(async ({ bytes, types }) => {
const { WebEngineClient } = await import("/src/engine-client/WebEngineClient.ts");
const client = new WebEngineClient({ timeoutMs: 60_000 });
const reopened = new WebEngineClient({ timeoutMs: 60_000 });
const cases: Record<string, unknown>[] = [];
try {
const open = await client.openBlend(Uint8Array.from(bytes).buffer);
const node = open.snapshot.nodes.find((n) => n.type === "MESH");
if (!node?.dataId) throw new Error("mesh fixture is missing");
const meshId = node.dataId;
let revision = open.snapshot.revision;
for (const modifierType of types) {
try {
const added = await client.applyCommand({ type: "addModifier", objectId: node.id, meshId, modifierType, baseRevision: revision } as never);
revision = added.snapshot.revision;
const stack = added.snapshot.meshes.find((m) => m.id === meshId)?.modifierStack ?? [];
const modifier = stack.at(-1);
if (!modifier?.uuid) throw new Error("modifier was not published");
const removed = await client.applyCommand({ type: "removeModifier", objectId: node.id, meshId, modifierUuid: modifier.uuid, baseRevision: revision } as never);
revision = removed.snapshot.revision;
const remaining = removed.snapshot.meshes.find((m) => m.id === meshId)?.modifierStack ?? [];
cases.push({ modifierType, status: remaining.some((m) => m.uuid === modifier.uuid) ? "REMOVE_FAILED" : "FINISHED", publishedType: modifier.type, revision });
} catch (error) {
const e = error as { message?: string; code?: string };
cases.push({ modifierType, status: "ERROR", message: e?.message, code: e?.code });
}
}
const saved = await client.saveBlend();
client.terminate();
const reopen = await reopened.openBlend(saved);
return { ok: true, cases, reopenRevision: reopen.snapshot.revision };
} catch (error) {
const e = error as { message?: string; code?: string };
return { ok: false, cases, message: e?.message, code: e?.code };
} finally { client.terminate(); reopened.terminate(); }
}, { bytes: Array.from(fixture), types });
fs.writeFileSync(path.join(receiptDir, "modifier-matrix-production.json"), JSON.stringify({ schemaVersion: 1, browser: "chromium", scope: "20 expanded modifiers add/publication/remove/save/reopen", ...result }, null, 2));
expect(result.ok).toBe(true);
expect(result.reopenRevision).toBe(1);
const failed = (result.cases as Record<string, unknown>[]).filter((item) => item.status !== "FINISHED");
expect(failed).toEqual([]);
});