219 lines
7.9 KiB
TypeScript
219 lines
7.9 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
const storageKey = "canvas.image-toolbar.v1";
|
|
|
|
test("image toolbar customization preserves actions, saves preferences and respects enabled tools", async ({
|
|
page,
|
|
context,
|
|
}) => {
|
|
const errors: string[] = [];
|
|
page.on("pageerror", (error) => errors.push(error.message));
|
|
await context.addInitScript(() => localStorage.setItem("theme", "light"));
|
|
const settings = {
|
|
canvasEnabled: true,
|
|
agentEnabled: true,
|
|
layerSplitEnabled: true,
|
|
angleEditEnabled: true,
|
|
membershipEnabled: false,
|
|
canvasToolbarConfig: {} as Record<string, unknown>,
|
|
};
|
|
await context.route("**/api/**", async (route) => {
|
|
const path = new URL(route.request().url()).pathname;
|
|
let data: unknown = {};
|
|
if (path.includes("validate-session"))
|
|
data = { valid: true, success: true };
|
|
else if (path === "/api/auth/session")
|
|
data = {
|
|
user: { id: "toolbar-test-user", name: "设计师", type: "admin" },
|
|
expires: "2099-01-01",
|
|
};
|
|
else if (path === "/api/site-settings") data = settings;
|
|
else if (path === "/api/models")
|
|
data = {
|
|
models: [
|
|
{
|
|
id: "image-test",
|
|
modelId: "gpt-image-2",
|
|
providerType: "openai",
|
|
name: "GPT Image",
|
|
type: "image",
|
|
enabled: true,
|
|
supportsImageGen: true,
|
|
imageGenConfig: { creditCostPerImage: 15 },
|
|
},
|
|
],
|
|
};
|
|
else if (
|
|
path === "/api/canvas/toolbar-test" &&
|
|
route.request().method() === "GET"
|
|
)
|
|
data = {
|
|
success: true,
|
|
data: {
|
|
id: "toolbar-test",
|
|
title: "工具栏测试",
|
|
canvasData: {
|
|
nodes: [
|
|
{
|
|
id: "toolbar-image",
|
|
type: "image",
|
|
position: { x: 220, y: 160 },
|
|
size: { width: 640, height: 420 },
|
|
data: {
|
|
status: "completed",
|
|
src: new URL("/toolbar-test.svg", page.url()).href,
|
|
title: "工具栏测试图",
|
|
originalWidth: 640,
|
|
originalHeight: 420,
|
|
},
|
|
},
|
|
],
|
|
edges: [],
|
|
viewport: { x: 0, y: 0, zoom: 1 },
|
|
},
|
|
},
|
|
};
|
|
else if (path.startsWith("/api/canvas/")) data = { success: true };
|
|
else if (path.includes("sessions")) data = { sessions: [] };
|
|
else if (path.includes("messages")) data = { messages: [] };
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify(data),
|
|
});
|
|
});
|
|
await context.route("**/toolbar-test.svg", (route) =>
|
|
route.fulfill({
|
|
contentType: "image/svg+xml",
|
|
body: '<svg xmlns="http://www.w3.org/2000/svg" width="640" height="420"><rect width="640" height="420" fill="#43b9bd"/></svg>',
|
|
})
|
|
);
|
|
const node = page.locator('[data-canvas-node-id="toolbar-image"]');
|
|
const bar = page.locator('[data-selected-image-toolbar="true"]');
|
|
const dialog = page.getByRole("dialog");
|
|
const keys = () =>
|
|
bar
|
|
.locator("button[data-tool-key]")
|
|
.evaluateAll((buttons) =>
|
|
buttons.map((button) => button.getAttribute("data-tool-key"))
|
|
);
|
|
const selectImage = async () => {
|
|
await node.waitFor();
|
|
await node.click({ position: { x: 80, y: 80 } });
|
|
await expect(bar).toBeVisible();
|
|
};
|
|
const customize = async () => {
|
|
await bar.getByRole("button", { name: "更多操作", exact: true }).click();
|
|
await page
|
|
.getByRole("menuitem", { name: "自定义工具栏", exact: true })
|
|
.click();
|
|
await expect(dialog).toBeVisible();
|
|
};
|
|
await page.goto("/canvas/toolbar-test", { waitUntil: "commit" });
|
|
await selectImage();
|
|
const initial = await keys();
|
|
await expect(bar).toHaveAttribute("data-show-tool-names", "false");
|
|
await bar.getByRole("button", { name: "高清", exact: true }).hover();
|
|
await expect(page.getByRole("tooltip")).toContainText("高清");
|
|
await page.mouse.move(1000, 100);
|
|
await customize();
|
|
await dialog.getByRole("button", { name: "固定裁剪", exact: true }).click();
|
|
await dialog.getByRole("button", { name: "取消", exact: true }).click();
|
|
expect(await keys()).toEqual(initial);
|
|
await customize();
|
|
await dialog
|
|
.getByRole("button", { name: "取消固定高清", exact: true })
|
|
.click();
|
|
await dialog.getByRole("button", { name: "固定裁剪", exact: true }).click();
|
|
await dialog.getByRole("switch", { name: "显示工具名称" }).click();
|
|
await dialog
|
|
.getByRole("button", { name: "裁剪,按左右方向键调整顺序", exact: true })
|
|
.focus();
|
|
await page.keyboard.press("ArrowLeft");
|
|
await dialog.getByRole("button", { name: "保存", exact: true }).click();
|
|
const changed = await keys();
|
|
expect(changed).toContain("crop");
|
|
expect(changed).not.toContain("enhance");
|
|
expect(changed.at(-3)).toBe("crop");
|
|
await expect(bar).toHaveAttribute("data-show-tool-names", "true");
|
|
await bar.getByRole("button", { name: "更多操作", exact: true }).click();
|
|
await expect(
|
|
page.getByRole("menuitem", { name: "高清", exact: true })
|
|
).toBeVisible();
|
|
await page.keyboard.press("Escape");
|
|
await page.reload({ waitUntil: "commit" });
|
|
await selectImage();
|
|
expect(await keys()).toEqual(changed);
|
|
await bar.getByRole("button", { name: "裁剪", exact: true }).click();
|
|
await expect(
|
|
page.getByRole("heading", { name: "裁剪", exact: true })
|
|
).toBeVisible();
|
|
await page.getByRole("button", { name: "取消", exact: true }).click();
|
|
await expect(bar).toBeVisible();
|
|
await bar.getByRole("button", { name: "添加对话", exact: true }).click();
|
|
await expect(page.getByText("已添加到对话框", { exact: true })).toBeVisible();
|
|
await customize();
|
|
await dialog
|
|
.getByRole("button", { name: "恢复默认工具栏", exact: true })
|
|
.click();
|
|
await dialog.getByRole("button", { name: "保存", exact: true }).click();
|
|
expect(await keys()).toEqual(initial);
|
|
await page.evaluate((key) => {
|
|
localStorage.setItem(key, "invalid-json{");
|
|
window.dispatchEvent(
|
|
new StorageEvent("storage", { key, newValue: "invalid-json{" })
|
|
);
|
|
}, storageKey);
|
|
expect(await keys()).toEqual(initial);
|
|
await customize();
|
|
const firstHandle = dialog.getByRole("button", {
|
|
name: "识物,按左右方向键调整顺序",
|
|
exact: true,
|
|
});
|
|
const secondHandle = dialog.getByRole("button", {
|
|
name: "高清,按左右方向键调整顺序",
|
|
exact: true,
|
|
});
|
|
await firstHandle.dragTo(secondHandle);
|
|
await dialog.getByRole("button", { name: "保存", exact: true }).click();
|
|
const draggedOrder = await keys();
|
|
expect(draggedOrder.slice(1, 3)).toEqual(["enhance", "pickObject"]);
|
|
await customize();
|
|
await page.setViewportSize({ width: 390, height: 700 });
|
|
await expect
|
|
.poll(async () => (await dialog.boundingBox())?.width)
|
|
.toBeLessThanOrEqual(358);
|
|
await expect
|
|
.poll(async () => (await dialog.boundingBox())?.height)
|
|
.toBeLessThanOrEqual(652);
|
|
await expect(
|
|
dialog.getByRole("button", { name: "保存", exact: true })
|
|
).toBeInViewport();
|
|
await dialog.getByRole("button", { name: "取消", exact: true }).click();
|
|
await page.setViewportSize({ width: 1512, height: 793 });
|
|
settings.canvasToolbarConfig = {
|
|
selectedImageInlineActionCount: 3,
|
|
items: {
|
|
imageEnhance: {
|
|
label: "自定义高清",
|
|
iconUrl: "/icons/lovart/model-gpt.svg",
|
|
enabled: true,
|
|
},
|
|
imageRemoveBackground: { enabled: false },
|
|
},
|
|
};
|
|
await page.reload({ waitUntil: "commit" });
|
|
await selectImage();
|
|
const customIcon = bar
|
|
.getByRole("button", { name: "自定义高清", exact: true })
|
|
.locator('span[aria-hidden="true"]');
|
|
expect(
|
|
await customIcon.evaluate(
|
|
(element) => (element as HTMLElement).style.maskImage
|
|
)
|
|
).toContain("model-gpt.svg");
|
|
await customize();
|
|
await expect(dialog.getByRole("button", { name: /固定抠图/ })).toHaveCount(0);
|
|
expect(errors).toEqual([]);
|
|
});
|