Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
142 lines
5.7 KiB
TypeScript
142 lines
5.7 KiB
TypeScript
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());
|
|
}
|