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>
This commit is contained in:
@@ -20,14 +20,14 @@ test("modifier stack panel commits only changed native fields", async ({ page },
|
||||
const workflow = new NativeUIWorkflow(page, testInfo.outputPath("panel"));
|
||||
await page.goto("/");
|
||||
await workflow.load(path.join(root, fixturePath), "StackTarget");
|
||||
const section = page.locator(".modifier-stack-authoring");
|
||||
const bevel = section.locator(".modifier-row").filter({ hasText: "Stack Bevel" });
|
||||
const section = page.locator("fieldset").filter({ hasText: "StackTarget: Modifiers" }).first();
|
||||
const bevel = section.locator('[data-modifier-row][data-modifier-name="Stack Bevel"]');
|
||||
const count = await page.evaluate(() => (window as unknown as { __nativeWorkflowRequests: unknown[] }).__nativeWorkflowRequests.length);
|
||||
await bevel.getByLabel("width", { exact: true }).fill("0.35");
|
||||
await bevel.getByLabel("Amount", { exact: true }).fill("0.35");
|
||||
expect(await page.evaluate(() => (window as unknown as { __nativeWorkflowRequests: unknown[] }).__nativeWorkflowRequests.length)).toBe(count);
|
||||
await workflow.command(() => bevel.getByLabel("width", { exact: true }).press("Enter"));
|
||||
await workflow.command(() => bevel.getByLabel("Amount", { exact: true }).press("Enter"));
|
||||
await expect(page.getByRole("treeitem").filter({ hasText: "StackTarget" })).toHaveAttribute("aria-selected", "true");
|
||||
await workflow.command(async () => { await bevel.getByLabel("segments", { exact: true }).fill("4"); await bevel.getByLabel("segments", { exact: true }).press("Enter"); });
|
||||
await workflow.command(async () => { await bevel.getByLabel("Segments", { exact: true }).fill("4"); await bevel.getByLabel("Segments", { exact: true }).press("Enter"); });
|
||||
await bevel.screenshot({ path: testInfo.outputPath("modifier-fields-desktop.png") });
|
||||
await page.setViewportSize({ width: 960, height: 844 });
|
||||
await bevel.screenshot({ path: testInfo.outputPath("modifier-fields-compact.png") });
|
||||
@@ -38,10 +38,10 @@ test("modifier stack panel commits only changed native fields", async ({ page },
|
||||
expect(geometry.every((item) => item.fits && item.width >= 60)).toBe(true);
|
||||
await page.setViewportSize({ width: 1280, height: 720 });
|
||||
await workflow.click(page.getByRole("button", { name: "Move Stack Bevel up", exact: true }));
|
||||
await page.getByLabel("Modifier type", { exact: true }).fill("SOLIDIFY");
|
||||
await workflow.click(section.getByRole("button", { name: "Add", exact: true }));
|
||||
await workflow.measured("remove-array", () => workflow.click(page.getByRole("button", { name: "Remove Stack Array", exact: true })));
|
||||
await expect(section.locator(".modifier-row").filter({ hasText: "Stack Array" })).toHaveCount(0);
|
||||
await page.getByLabel("Properties modifier type", { exact: true }).selectOption("Solidify");
|
||||
await workflow.click(section.getByRole("button", { name: "Add Modifier", exact: true }));
|
||||
await workflow.measured("remove-array", () => workflow.click(section.locator('[data-modifier-row][data-modifier-name="Stack Array"]').getByRole("button", { name: "Remove", exact: true })));
|
||||
await expect(section.locator('[data-modifier-row][data-modifier-name="Stack Array"]')).toHaveCount(0);
|
||||
await workflow.save("after");
|
||||
const output = path.join(workflow.directory, "main.json");
|
||||
const request = path.join(workflow.directory, "request.json");
|
||||
@@ -63,7 +63,9 @@ for (const { route, modifierType } of scenarios) {
|
||||
const directory = process.env.WBV2_RECEIPT_DIR ?? testInfo.outputPath("receipts");
|
||||
const scenario = route === "parameters" ? `parameters-${modifierType.toLowerCase()}` : route;
|
||||
fs.mkdirSync(directory, { recursive: true });
|
||||
await page.goto("/");
|
||||
// These scenarios own the only engine client; the app page would already
|
||||
// hold the single-writer lock. The blank manual host keeps the contract.
|
||||
await page.goto("/?engine=manual");
|
||||
const result = await page.evaluate(async (input) => {
|
||||
const { WebEngineClient } = await import("/src/engine-client/WebEngineClient.ts");
|
||||
const clients: InstanceType<typeof WebEngineClient>[] = [];
|
||||
@@ -145,7 +147,7 @@ for (const { route, modifierType } of scenarios) {
|
||||
BEVEL: [{ segments: 0 }, { width: -0.1 }, { segments: 2.5 }],
|
||||
ARRAY: [{ count: 0 }, { relative_offset_displace: [1, 2] }, { use_relative_offset: 1 }],
|
||||
MIRROR: [{ use_axis: [1, 1, 0] }, { use_clip: "true" }],
|
||||
SOLIDIFY: [{ offset: 2 }], SUBSURF: [{ levels: 12 }],
|
||||
SOLIDIFY: [{ offset: 200000 }], SUBSURF: [{ levels: 12 }],
|
||||
}[input.modifierType];
|
||||
const badCommands: WebEngineEditCommand[] = input.route === "add"
|
||||
? [{ type: "addModifier", meshId: "missing:99999", modifierType: "PARTICLE_SYSTEM", name: "Invalid target" }]
|
||||
@@ -159,9 +161,11 @@ for (const { route, modifierType } of scenarios) {
|
||||
await save(client, "undo");
|
||||
await measured("redo", () => client.applyCommand({ type: "redo" }));
|
||||
const saved = await save(client, "redo");
|
||||
client.terminate();
|
||||
const reopened = create();
|
||||
await measured("reopen", () => reopened.openBlend(saved.slice(0)));
|
||||
await save(reopened, "reopened");
|
||||
reopened.terminate();
|
||||
const replay = create();
|
||||
await measured("replay-open", () => replay.openBlend(Uint8Array.from(atob(files.before), (char) => char.charCodeAt(0)).buffer));
|
||||
await measured("replay-write", () => replay.applyCommand(commands[input.route]));
|
||||
|
||||
Reference in New Issue
Block a user