159 lines
5.7 KiB
TypeScript
159 lines
5.7 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { prepareApp } from "./fixtures";
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
await prepareApp(page);
|
|
});
|
|
|
|
test("未知图形元件使用带端口和名称的默认节点,并将动作结果写入控制台", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
const paletteItem = page.getByRole("button", { name: /通用测试元件/ });
|
|
await expect(paletteItem).toBeVisible();
|
|
|
|
await paletteItem.dragTo(page.locator(".flow-canvas .react-flow__pane"));
|
|
|
|
const node = page.locator('.flow-canvas .react-flow__node[data-id="generic_sensor_1"]');
|
|
await expect(node).toBeVisible();
|
|
await expect(node.locator(".sim-node")).toHaveClass(/generic-component/);
|
|
await expect(node.locator(".node-symbol-anchor")).toHaveCount(0);
|
|
await expect(node.locator(".node-label")).toHaveText("generic_sensor_1");
|
|
await expect(node.locator(".port-handle")).toHaveCount(2);
|
|
|
|
const consolePanel = page.getByRole("complementary", {
|
|
name: "仿真控制台",
|
|
exact: true,
|
|
});
|
|
await expect(consolePanel).not.toHaveClass(/has-unread/);
|
|
await expect(consolePanel.locator(".simulation-console-unread")).toHaveCount(0);
|
|
await expect(consolePanel).not.toContainText("已添加组件");
|
|
|
|
await page.getByRole("button", { name: "生成系统 XML" }).click();
|
|
await expect(consolePanel).toContainText("XML 已生成");
|
|
const xmlBlock = consolePanel.getByLabel("生成的系统 XML");
|
|
await expect(xmlBlock).toBeVisible();
|
|
await expect(xmlBlock).toContainText('<?xml version="1.0" encoding="UTF-8"?>');
|
|
await expect(xmlBlock).toContainText('<Component id="generic_sensor_1"');
|
|
await expect(page.locator(".properties .xml-output")).toHaveCount(0);
|
|
await expect(page.locator(".properties")).not.toContainText("系统 XML");
|
|
|
|
await page.getByRole("button", { name: "检查模型" }).click();
|
|
await expect(consolePanel).toContainText(/模型检查/);
|
|
await expect(page.locator(".status-strip")).toHaveCount(0);
|
|
await expect(page.locator(".validation-section")).toHaveCount(0);
|
|
await expect(page.locator(".properties")).not.toContainText("仿真结果");
|
|
});
|
|
|
|
test("拖入组件后仅选择新组件,变换操作不会继续作用于旧选择", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
const paletteItem = page.getByRole("button", { name: /通用测试元件/ });
|
|
const pane = page.locator(".flow-canvas .react-flow__pane");
|
|
|
|
await paletteItem.dragTo(pane, { targetPosition: { x: 220, y: 220 } });
|
|
const firstNode = page.locator(
|
|
'.flow-canvas .react-flow__node[data-id="generic_sensor_1"]',
|
|
);
|
|
await expect(firstNode).toHaveClass(/selected/);
|
|
await expect(firstNode.locator(".sim-node")).toHaveCSS(
|
|
"outline-style",
|
|
"dashed",
|
|
);
|
|
|
|
await paletteItem.dragTo(pane, { targetPosition: { x: 480, y: 340 } });
|
|
const secondNode = page.locator(
|
|
'.flow-canvas .react-flow__node[data-id="generic_sensor_2"]',
|
|
);
|
|
await expect(firstNode).not.toHaveClass(/selected/);
|
|
await expect(secondNode).toHaveClass(/selected/);
|
|
await expect(firstNode.locator(".sim-node")).toHaveCSS("outline-style", "none");
|
|
await expect(secondNode.locator(".sim-node")).toHaveCSS(
|
|
"outline-style",
|
|
"dashed",
|
|
);
|
|
|
|
await page
|
|
.getByRole("button", { name: "顺时针旋转 90° (Ctrl+R)", exact: true })
|
|
.click();
|
|
await expect(firstNode.locator(".sim-node")).not.toHaveClass(
|
|
/orientation-vertical/,
|
|
);
|
|
await expect(secondNode.locator(".sim-node")).toHaveClass(
|
|
/orientation-vertical/,
|
|
);
|
|
});
|
|
|
|
test("框选结束后隐藏整体包围框并保留每个组件的虚线选中框", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
const paletteItem = page.getByRole("button", { name: /通用测试元件/ });
|
|
const pane = page.locator(".flow-canvas .react-flow__pane");
|
|
|
|
await paletteItem.dragTo(pane, { targetPosition: { x: 220, y: 220 } });
|
|
await paletteItem.dragTo(pane, { targetPosition: { x: 480, y: 340 } });
|
|
const firstNode = page.locator(
|
|
'.flow-canvas .react-flow__node[data-id="generic_sensor_1"]',
|
|
);
|
|
const secondNode = page.locator(
|
|
'.flow-canvas .react-flow__node[data-id="generic_sensor_2"]',
|
|
);
|
|
const [paneBounds, firstBounds, secondBounds] = await Promise.all([
|
|
pane.boundingBox(),
|
|
firstNode.boundingBox(),
|
|
secondNode.boundingBox(),
|
|
]);
|
|
expect(paneBounds).not.toBeNull();
|
|
expect(firstBounds).not.toBeNull();
|
|
expect(secondBounds).not.toBeNull();
|
|
|
|
const startX = Math.max(
|
|
paneBounds!.x + 4,
|
|
Math.min(firstBounds!.x, secondBounds!.x) - 14,
|
|
);
|
|
const startY = Math.max(
|
|
paneBounds!.y + 4,
|
|
Math.min(firstBounds!.y, secondBounds!.y) - 14,
|
|
);
|
|
const endX = Math.min(
|
|
paneBounds!.x + paneBounds!.width - 4,
|
|
Math.max(
|
|
firstBounds!.x + firstBounds!.width,
|
|
secondBounds!.x + secondBounds!.width,
|
|
) + 14,
|
|
);
|
|
const endY = Math.min(
|
|
paneBounds!.y + paneBounds!.height - 4,
|
|
Math.max(
|
|
firstBounds!.y + firstBounds!.height,
|
|
secondBounds!.y + secondBounds!.height,
|
|
) + 14,
|
|
);
|
|
|
|
await page.mouse.move(startX, startY);
|
|
await page.mouse.down();
|
|
await page.mouse.move(endX, endY, { steps: 12 });
|
|
await page.mouse.up();
|
|
|
|
await expect(firstNode).toHaveClass(/selected/);
|
|
await expect(secondNode).toHaveClass(/selected/);
|
|
await expect(firstNode.locator(".sim-node")).toHaveCSS(
|
|
"outline-style",
|
|
"dashed",
|
|
);
|
|
await expect(secondNode.locator(".sim-node")).toHaveCSS(
|
|
"outline-style",
|
|
"dashed",
|
|
);
|
|
await expect(page.locator(".flow-canvas .react-flow__selection")).toHaveCount(0);
|
|
|
|
const aggregateSelection = page.locator(
|
|
".flow-canvas .react-flow__nodesselection-rect",
|
|
);
|
|
await expect(aggregateSelection).toHaveCount(1);
|
|
await expect(aggregateSelection).toHaveCSS("border-top-width", "0px");
|
|
await expect(aggregateSelection).toHaveCSS("pointer-events", "none");
|
|
});
|