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

46 lines
3.7 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"));
test("Bevel Apply and SUBSURF Convert consume evaluated geometry", async ({ page }) => {
test.setTimeout(180_000);
await page.goto("/?engine=manual");
const result = await page.evaluate(async ({ bytes }) => {
const { WebEngineClient } = await import("/src/engine-client/WebEngineClient.ts");
const run = async (modifierType: string, parameters: Record<string, unknown>, operator: string) => {
const client = new WebEngineClient({ timeoutMs: 60_000 });
try {
const open = await client.openBlend(Uint8Array.from(bytes).buffer);
const node = open.snapshot.nodes.find((n) => n.name === "BasicCube");
if (!node?.dataId) throw new Error("BasicCube is missing");
const meshId = node.dataId;
const added = await client.applyCommand({ type: "addModifier", objectId: node.id, meshId, modifierType, baseRevision: open.snapshot.revision } as never);
const modifier = (added.snapshot.meshes.find((m) => m.id === meshId)?.modifierStack ?? []).find((m) => m.type === modifierType);
if (!modifier?.uuid) throw new Error("modifier was not published");
const configured = await client.applyCommand({ type: "setModifierParameters", meshId, modifierUuid: modifier.uuid, parameters, baseRevision: added.snapshot.revision } as never);
const depsgraph = await client.evaluateDepsgraph();
const evaluated = depsgraph.depsgraph.meshes.find((m) => m.meshId === meshId || m.objectId === node.id);
const payload = JSON.stringify({ operator, properties: operator === "object.convert" ? { target: "MESH" } : { modifier: modifier.name, single_user: true, report: true }, baseRevision: configured.snapshot.revision, sceneName: configured.snapshot.scenes?.[0]?.name ?? "Scene", areaType: "VIEW_3D", mode: "OBJECT", native: true, selectedObjects: [node.name], activeObject: node.name, meshSelection: null, nonMeshSelection: null });
const source = `import json, web_blender\nweb_blender.desktop_operator(json.loads(${JSON.stringify(payload)}))`;
const applied = await client.executeEmbeddedPython(source, "Breadth.py", false);
const afterMesh = applied.snapshot.meshes.find((m) => m.id === meshId) ?? applied.snapshot.meshes.find((m) => m.name === "Cube.001");
return { modifierType, operator, evalVerts: evaluated?.vertexCount ?? null, pythonState: applied.python.state, afterVerts: afterMesh?.vertexCount ?? null, afterStack: afterMesh?.modifierStack?.length ?? 0, output: applied.python.output?.slice(0, 200) };
} catch (error) { const e = error as { message?: string; code?: string }; return { modifierType, operator, error: e?.message, code: e?.code }; }
finally { client.terminate(); }
};
return {
bevelApply: await run("BEVEL", { width: 0.1, segments: 2 }, "object.modifier_apply"),
subsurfConvert: await run("SUBSURF", { levels: 2, render_levels: 2 }, "object.convert"),
};
}, { bytes: Array.from(fixture) });
fs.writeFileSync(path.join(root, "tests/golden/WBV2-P1425-001/verification/modifier-apply-convert-production.json"), JSON.stringify({ schemaVersion: 1, browser: "chromium", scope: "BEVEL apply and SUBSURF convert consume the evaluated mesh", ...result }, null, 2));
for (const item of [result.bevelApply, result.subsurfConvert]) {
expect(item.error).toBeUndefined();
expect(item.pythonState).toBe("DONE");
expect(item.evalVerts).toBeGreaterThan(8);
expect(item.afterVerts).toBe(item.evalVerts);
expect(item.afterStack).toBe(0);
}
});