- 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>
56 lines
4.2 KiB
TypeScript
56 lines
4.2 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("scene create, switch and delete publish active-scene objects", 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 client = new WebEngineClient({ timeoutMs: 30_000 });
|
|
try {
|
|
const open = await client.openBlend(Uint8Array.from(bytes).buffer);
|
|
const mesh = open.snapshot.nodes.find((n) => n.type === "MESH");
|
|
let revision = open.snapshot.revision;
|
|
let sceneName = open.snapshot.scenes?.[0]?.name ?? "Scene";
|
|
const invoke = async (operator: string, properties: Record<string, unknown>, activeName: string | null = mesh?.name ?? null) => {
|
|
const payload = JSON.stringify({ operator, properties, baseRevision: revision, sceneName, areaType: "VIEW_3D", mode: "OBJECT", native: true, selectedObjects: activeName ? [activeName] : [], activeObject: activeName, meshSelection: null, nonMeshSelection: null });
|
|
const res = await client.executeEmbeddedPython(`import json, web_blender\nweb_blender.desktop_operator(json.loads(${JSON.stringify(payload)}))`, "SceneFlow.py", false);
|
|
revision = res.snapshot.revision;
|
|
if (res.python.state !== "DONE") throw new Error(res.python.error ?? res.python.output ?? res.python.state);
|
|
return res.snapshot;
|
|
};
|
|
const baseScenes = open.snapshot.scenes.map((scene) => scene.name);
|
|
const created = await invoke("scene.new", { type: "NEW" });
|
|
const afterNew = { scenes: created.scenes.map((scene) => scene.name), sceneId: created.sceneId, nodes: created.nodes.length };
|
|
const target = created.scenes.find((scene) => scene.name === baseScenes[0]);
|
|
if (!target) throw new Error("original scene is missing");
|
|
const switched = await client.applyCommand({ type: "setScene", sceneId: target.id } as never);
|
|
revision = switched.snapshot.revision;
|
|
const afterSwitch = { scenes: switched.snapshot.scenes.map((scene) => scene.name), sceneId: switched.snapshot.sceneId, nodes: switched.snapshot.nodes.length };
|
|
const currentNew = switched.snapshot.scenes.find((scene) => scene.name !== baseScenes[0]);
|
|
if (!currentNew) throw new Error("new scene is missing");
|
|
const switchNew = await client.applyCommand({ type: "setScene", sceneId: currentNew.id } as never);
|
|
revision = switchNew.snapshot.revision;
|
|
sceneName = currentNew.name;
|
|
const activeInNew = switchNew.snapshot.nodes.find((node) => node.type === "MESH")?.name ?? null;
|
|
const newSceneNodes = switchNew.snapshot.nodes.map((node) => node.name);
|
|
let afterDelete: unknown;
|
|
try {
|
|
const deleted = await invoke("scene.delete", {}, activeInNew);
|
|
afterDelete = { scenes: deleted.scenes.map((scene) => scene.name), sceneId: deleted.sceneId, nodes: deleted.nodes.length };
|
|
} catch (error) { afterDelete = { error: (error as Error)?.message }; }
|
|
return { baseScenes, afterNew, afterSwitch, newSceneNodes, beforeDeleteSceneId: switchNew.snapshot.sceneId, afterDelete };
|
|
} catch (error) { const e = error as { message?: string; code?: string }; return { error: e?.message, code: e?.code }; }
|
|
finally { client.terminate(); }
|
|
}, { bytes: Array.from(fixture) });
|
|
fs.writeFileSync(path.join(root, "tests/golden/WBV2-P1425-001/verification/scene-flow-production.json"), JSON.stringify({ schemaVersion: 1, browser: "chromium", scope: "scene.new -> setScene original/new -> scene.delete with active-scene nodes", ...result }, null, 2));
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.baseScenes).toEqual(["Scene"]);
|
|
expect(result.afterNew).toMatchObject({ scenes: ["Scene", "Scene.001"], nodes: 0 });
|
|
expect(result.afterSwitch).toMatchObject({ sceneId: "scene:Scene", nodes: 3 });
|
|
expect(result.newSceneNodes).toEqual([]);
|
|
expect(result.afterDelete).toMatchObject({ scenes: ["Scene"], sceneId: "scene:Scene", nodes: 3 });
|
|
});
|