feat: add render graph driven renderer architecture
Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
+141
@@ -0,0 +1,141 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("right-click DOM menu searches and adds through one worker gesture", async ({ page }) => {
|
||||
await page.goto("/test/browser/index.html");
|
||||
await page.evaluate(() => window.ready);
|
||||
await page.evaluate(() => {
|
||||
const events: {
|
||||
mutations: Array<{ version: number; cause: string; mutations: readonly unknown[] }>;
|
||||
snapshots: number[];
|
||||
requests: Array<{ frozen: boolean; revision: number; position: { x: number; y: number } }>;
|
||||
} = { mutations: [], snapshots: [], requests: [] };
|
||||
(window as typeof window & { menuEvents: typeof events }).menuEvents = events;
|
||||
window.root.onMutations((event) => events.mutations.push(event));
|
||||
window.root.onSnapshots((event) => events.snapshots.push(event.version));
|
||||
window.view.onHostRequests((request) => {
|
||||
if (request.kind === "add-node-menu")
|
||||
events.requests.push({
|
||||
frozen: Object.isFrozen(request) && Object.isFrozen(request.viewPosition),
|
||||
revision: request.compositionRevision,
|
||||
position: { ...request.viewPosition },
|
||||
});
|
||||
});
|
||||
});
|
||||
const canvas = page.locator("#primary");
|
||||
await canvas.click({ button: "right", position: { x: 40, y: 50 } });
|
||||
const dialog = page.getByRole("dialog", { name: "Add node" });
|
||||
await expect(dialog).toBeVisible();
|
||||
expect(
|
||||
await dialog.getByRole("group").evaluateAll((groups) =>
|
||||
groups.map((group) => ({
|
||||
name: group.getAttribute("aria-label"),
|
||||
options: [...group.querySelectorAll('[role="option"]')].map((item) => item.textContent?.trim()),
|
||||
})),
|
||||
),
|
||||
).toEqual([
|
||||
{ name: "Common", options: ["Frame", "Reroute", "Group Input", "Group Output"] },
|
||||
{
|
||||
name: "Shader",
|
||||
options: [
|
||||
"Value",
|
||||
"Color",
|
||||
"Math",
|
||||
"Vector Math",
|
||||
"Mix",
|
||||
"Color Ramp",
|
||||
"Texture Coordinate",
|
||||
"Noise Texture",
|
||||
"Image Texture",
|
||||
"Principled BSDF",
|
||||
"Material Output",
|
||||
],
|
||||
},
|
||||
{ name: "Geometry", options: ["Position", "Mesh Cube", "Set Position", "Transform Geometry", "Join Geometry"] },
|
||||
{ name: "Compositor", options: ["Image", "Color Balance"] },
|
||||
]);
|
||||
const search = page.getByRole("combobox", { name: "Search nodes" });
|
||||
await search.fill(" ShAdEr ");
|
||||
await expect(dialog.getByRole("option")).toHaveText([
|
||||
"Value",
|
||||
"Color",
|
||||
"Math",
|
||||
"Vector Math",
|
||||
"Mix",
|
||||
"Color Ramp",
|
||||
"Texture Coordinate",
|
||||
"Noise Texture",
|
||||
"Image Texture",
|
||||
"Principled BSDF",
|
||||
"Material Output",
|
||||
]);
|
||||
await search.fill("noise-texture");
|
||||
await expect(dialog.getByRole("option")).toHaveText(["Noise Texture"]);
|
||||
await search.press("Enter");
|
||||
await expect(dialog).toHaveCount(0);
|
||||
await expect
|
||||
.poll(() => page.evaluate(() => window.root.getState().then((snapshot) => snapshot.nodes.length)))
|
||||
.toBe(1);
|
||||
const result = await page.evaluate(async () => ({
|
||||
snapshot: await window.root.getState(),
|
||||
events: (
|
||||
window as typeof window & {
|
||||
menuEvents: {
|
||||
mutations: Array<{ version: number; cause: string; mutations: readonly unknown[] }>;
|
||||
snapshots: number[];
|
||||
requests: Array<{ frozen: boolean; revision: number; position: { x: number; y: number } }>;
|
||||
};
|
||||
}
|
||||
).menuEvents,
|
||||
}));
|
||||
expect(result.snapshot.nodes[0]?.typeId).toBe("fxnode.shader.noise-texture");
|
||||
expect(result.snapshot.nodes[0]?.position).toEqual({ x: -120, y: 40 });
|
||||
expect(result.events.mutations).toHaveLength(1);
|
||||
expect(result.events.mutations[0]).toMatchObject({ version: 2, cause: "api" });
|
||||
expect(result.events.mutations[0]?.mutations).toHaveLength(1);
|
||||
expect(result.events.snapshots).toEqual([2]);
|
||||
expect(result.events.requests).toEqual([{ frozen: true, revision: 31, position: { x: 40, y: 50 } }]);
|
||||
const rootAdded = await page.evaluate(async () => {
|
||||
const beforeSelection = window.view.getHostSnapshot().selection.nodeCount;
|
||||
await window.root.dispatch({ type: "node.add", nodeType: "fxnode.shader.value", position: { x: -120, y: 40 } });
|
||||
const snapshot = await window.root.getState();
|
||||
return {
|
||||
id: snapshot.nodes.find((node) => node.typeId === "fxnode.shader.value")!.id,
|
||||
beforeSelection,
|
||||
afterSelection: window.view.getHostSnapshot().selection.nodeCount,
|
||||
};
|
||||
});
|
||||
expect(rootAdded.afterSelection).toBe(rootAdded.beforeSelection);
|
||||
await canvas.press("Delete");
|
||||
expect((await page.evaluate(() => window.root.getState())).nodes.map((node) => node.id)).toEqual([rootAdded.id]);
|
||||
await windowUndo(page);
|
||||
await windowUndo(page);
|
||||
await windowUndo(page);
|
||||
expect((await page.evaluate(() => window.root.getState())).nodes).toHaveLength(0);
|
||||
await canvas.click({ button: "right", position: { x: 80, y: 80 } });
|
||||
await expect(dialog).toBeVisible();
|
||||
await page.evaluate(async () => {
|
||||
window.fxnodeHost.destroy();
|
||||
await window.view.detach();
|
||||
window.root.destroy();
|
||||
});
|
||||
await expect(dialog).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("right-click on a node and Ctrl-RMB never open the add menu", async ({ page }) => {
|
||||
await page.goto("/examples/blender/");
|
||||
await page.evaluate(() => window.fxnodeExample.ready);
|
||||
const canvas = page.locator("#graph"),
|
||||
dialog = page.getByRole("dialog", { name: "Add node" });
|
||||
await canvas.click({ button: "right", position: { x: 320, y: 160 } });
|
||||
await expect(dialog).toHaveCount(0);
|
||||
await canvas.hover({ position: { x: 30, y: 30 } });
|
||||
await page.keyboard.down("Control");
|
||||
await page.mouse.down({ button: "right" });
|
||||
await page.mouse.up({ button: "right" });
|
||||
await page.keyboard.up("Control");
|
||||
await expect(dialog).toHaveCount(0);
|
||||
});
|
||||
|
||||
async function windowUndo(page: import("@playwright/test").Page): Promise<void> {
|
||||
await page.evaluate(() => window.root.undo());
|
||||
}
|
||||
Reference in New Issue
Block a user