309 lines
11 KiB
TypeScript
309 lines
11 KiB
TypeScript
import { expect, test, type Locator, type Page } from "@playwright/test";
|
|
|
|
import { prepareApp } from "./fixtures";
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
await prepareApp(page);
|
|
});
|
|
|
|
function parameterRow(table: Locator, name: string) {
|
|
return table.getByRole("rowheader", { name, exact: true }).locator("..");
|
|
}
|
|
|
|
async function addPneumaticTestComponent(page: Page) {
|
|
const canvas = page.locator(".flow-canvas .react-flow__pane");
|
|
await page
|
|
.getByRole("button", { name: "AMESim 气动测试元件", exact: true })
|
|
.dragTo(canvas, { targetPosition: { x: 620, y: 330 } });
|
|
const node = page.locator(
|
|
'.flow-canvas .react-flow__node[data-id="amesim_pneumatic_test_1"]',
|
|
);
|
|
await expect(node).toBeVisible();
|
|
await node.click();
|
|
}
|
|
|
|
test("组件参数和仿真设置使用共享的三列表格", async ({ page }) => {
|
|
await page.goto("/");
|
|
await addPneumaticTestComponent(page);
|
|
|
|
const componentTable = page.getByRole("table", { name: "组件参数" });
|
|
const simulationTable = page.getByRole("table", { name: "仿真设置" });
|
|
await expect(componentTable).toBeVisible();
|
|
await expect(simulationTable).toBeVisible();
|
|
|
|
await expect(componentTable.getByRole("columnheader")).toHaveText([
|
|
"参数",
|
|
"值",
|
|
"单位",
|
|
]);
|
|
await expect(componentTable.getByRole("rowheader")).toHaveText([
|
|
"组件名称",
|
|
"节点 ID",
|
|
"介质物性索引",
|
|
"参考压力",
|
|
]);
|
|
await expect(simulationTable.getByRole("rowheader")).toHaveText([
|
|
"起始时间",
|
|
"结束时间",
|
|
"采样步长",
|
|
"最大积分步长",
|
|
"求解器",
|
|
]);
|
|
|
|
await expect(parameterRow(simulationTable, "起始时间").locator("td").last()).toHaveText(
|
|
"s",
|
|
);
|
|
await expect(parameterRow(simulationTable, "求解器").locator("td").last()).toHaveText(
|
|
"—",
|
|
);
|
|
|
|
const componentNameWidth = await componentTable
|
|
.locator("thead .parameter-table-name-cell")
|
|
.evaluate((element) => element.getBoundingClientRect().width);
|
|
const simulationNameWidth = await simulationTable
|
|
.locator("thead .parameter-table-name-cell")
|
|
.evaluate((element) => element.getBoundingClientRect().width);
|
|
expect(Math.abs(componentNameWidth - simulationNameWidth)).toBeLessThanOrEqual(1);
|
|
});
|
|
|
|
test("参数说明延迟显示,单位切换不改变 XML 基础值", async ({ page }) => {
|
|
await page.goto("/");
|
|
await addPneumaticTestComponent(page);
|
|
|
|
const componentTable = page.getByRole("table", { name: "组件参数" });
|
|
const pressureRow = parameterRow(componentTable, "参考压力");
|
|
const preview = page.locator("body > #parameter-help-preview");
|
|
|
|
const pressureRowBox = await pressureRow.boundingBox();
|
|
expect(pressureRowBox).not.toBeNull();
|
|
const pointer = {
|
|
x: pressureRowBox!.x + pressureRowBox!.width / 2,
|
|
y: pressureRowBox!.y + pressureRowBox!.height / 2,
|
|
};
|
|
await page.mouse.move(pointer.x, pointer.y);
|
|
await page.waitForTimeout(600);
|
|
await expect(preview).toBeVisible();
|
|
await expect(preview.locator(".parameter-help-preview-title")).toHaveText("参考压力");
|
|
await expect(preview.locator(".parameter-help-preview-description")).toContainText(
|
|
"单位换算和 XML 基础单位输出",
|
|
);
|
|
await expect(preview.locator(".parameter-help-preview-meta")).toContainText(
|
|
"默认值:100000",
|
|
);
|
|
await expect(preview.locator(".parameter-help-preview-meta")).toContainText(
|
|
"当前单位:Pa",
|
|
);
|
|
const previewBox = await preview.boundingBox();
|
|
expect(previewBox).not.toBeNull();
|
|
const horizontalGap =
|
|
pointer.x < previewBox!.x
|
|
? previewBox!.x - pointer.x
|
|
: pointer.x > previewBox!.x + previewBox!.width
|
|
? pointer.x - (previewBox!.x + previewBox!.width)
|
|
: 0;
|
|
const verticalGap =
|
|
pointer.y < previewBox!.y
|
|
? previewBox!.y - pointer.y
|
|
: pointer.y > previewBox!.y + previewBox!.height
|
|
? pointer.y - (previewBox!.y + previewBox!.height)
|
|
: 0;
|
|
expect(Math.hypot(horizontalGap, verticalGap)).toBeLessThanOrEqual(24);
|
|
await page.mouse.move(pointer.x + 24, pointer.y);
|
|
await page.waitForTimeout(100);
|
|
const stationaryPreviewBox = await preview.boundingBox();
|
|
expect(stationaryPreviewBox).not.toBeNull();
|
|
expect(Math.abs(stationaryPreviewBox!.x - previewBox!.x)).toBeLessThanOrEqual(1);
|
|
expect(Math.abs(stationaryPreviewBox!.y - previewBox!.y)).toBeLessThanOrEqual(1);
|
|
|
|
await page.locator(".panel-title").filter({ hasText: "组件参数" }).hover();
|
|
await expect(preview).toHaveCount(0);
|
|
|
|
await page.getByLabel("参考压力单位").selectOption("kPa");
|
|
await expect(page.getByLabel("参考压力", { exact: true })).toHaveValue("100");
|
|
|
|
await pressureRow.hover();
|
|
await page.waitForTimeout(600);
|
|
await expect(preview.locator(".parameter-help-preview-meta")).toContainText(
|
|
"默认值:100",
|
|
);
|
|
await expect(preview.locator(".parameter-help-preview-meta")).toContainText(
|
|
"当前单位:kPa",
|
|
);
|
|
|
|
await page.getByRole("button", { name: "生成系统 XML", exact: true }).click();
|
|
const consolePanel = page.getByRole("complementary", {
|
|
name: "仿真控制台",
|
|
exact: true,
|
|
});
|
|
await expect(consolePanel.getByLabel("生成的系统 XML")).toContainText(
|
|
'<Parameter name="reference_pressure" value="100000"',
|
|
);
|
|
});
|
|
|
|
test("参数表列宽可调整并在刷新后保留", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
const simulationTable = page.getByRole("table", { name: "仿真设置" });
|
|
const nameHeader = simulationTable.locator("thead .parameter-table-name-cell");
|
|
const separator = simulationTable.getByRole("separator", {
|
|
name: "调整参数名列宽",
|
|
exact: true,
|
|
});
|
|
const initialWidth = await nameHeader.evaluate(
|
|
(element) => element.getBoundingClientRect().width,
|
|
);
|
|
const initialValue = Number(await separator.getAttribute("aria-valuenow"));
|
|
const separatorBox = await separator.boundingBox();
|
|
expect(separatorBox).not.toBeNull();
|
|
await page.mouse.move(
|
|
separatorBox!.x + separatorBox!.width / 2,
|
|
separatorBox!.y + separatorBox!.height / 2,
|
|
);
|
|
await page.mouse.down();
|
|
await page.mouse.move(
|
|
separatorBox!.x + separatorBox!.width / 2 + 16,
|
|
separatorBox!.y + separatorBox!.height / 2,
|
|
{ steps: 3 },
|
|
);
|
|
await page.mouse.up();
|
|
|
|
await expect(separator).toHaveAttribute(
|
|
"aria-valuenow",
|
|
String(initialValue + 16),
|
|
);
|
|
const resizedWidth = await nameHeader.evaluate(
|
|
(element) => element.getBoundingClientRect().width,
|
|
);
|
|
expect(resizedWidth).toBeGreaterThan(initialWidth + 14);
|
|
|
|
await page.reload();
|
|
const reloadedTable = page.getByRole("table", { name: "仿真设置" });
|
|
await expect(
|
|
reloadedTable.getByRole("separator", {
|
|
name: "调整参数名列宽",
|
|
exact: true,
|
|
}),
|
|
).toHaveAttribute("aria-valuenow", String(initialValue + 16));
|
|
|
|
const wrapOverflow = await reloadedTable.evaluate((table) => {
|
|
const wrap = table.closest<HTMLElement>(".parameter-table-wrap");
|
|
return wrap ? wrap.scrollWidth - wrap.clientWidth : Number.POSITIVE_INFINITY;
|
|
});
|
|
expect(wrapOverflow).toBeLessThanOrEqual(1);
|
|
|
|
const reloadedSeparator = reloadedTable.getByRole("separator", {
|
|
name: "调整参数名列宽",
|
|
exact: true,
|
|
});
|
|
await reloadedSeparator.dblclick();
|
|
await expect(reloadedSeparator).toHaveAttribute("aria-valuenow", "112");
|
|
await reloadedSeparator.focus();
|
|
await page.keyboard.press("ArrowRight");
|
|
await expect(reloadedSeparator).toHaveAttribute("aria-valuenow", "120");
|
|
});
|
|
|
|
test("组件参数公式保留原式,并在说明中显示计算值且 XML 只写数值", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
await addPneumaticTestComponent(page);
|
|
|
|
const expression = "3.14*10^2/4";
|
|
const componentTable = page.getByRole("table", { name: "组件参数" });
|
|
const pressureRow = parameterRow(componentTable, "参考压力");
|
|
const pressureInput = page.getByLabel("参考压力", { exact: true });
|
|
|
|
await page.getByLabel("参考压力单位").selectOption("kPa");
|
|
await pressureInput.fill(expression);
|
|
await pressureInput.press("Enter");
|
|
|
|
await expect(pressureInput).toHaveValue(expression);
|
|
await expect(pressureRow).not.toContainText("78.5");
|
|
|
|
await pressureRow.hover();
|
|
await page.waitForTimeout(600);
|
|
const preview = page.locator("body > #parameter-help-preview");
|
|
await expect(preview).toBeVisible();
|
|
await expect(preview.getByTestId("parameter-calculated-value")).toContainText(
|
|
"78.5",
|
|
);
|
|
await expect(preview.getByTestId("parameter-calculated-value")).toContainText(
|
|
"kPa",
|
|
);
|
|
|
|
await page.getByRole("button", { name: "生成系统 XML", exact: true }).click();
|
|
const consolePanel = page.getByRole("complementary", {
|
|
name: "仿真控制台",
|
|
exact: true,
|
|
});
|
|
const xmlBlock = consolePanel.getByLabel("生成的系统 XML");
|
|
await expect(xmlBlock).toContainText(
|
|
'<Parameter name="reference_pressure" value="78500"',
|
|
);
|
|
await expect(xmlBlock).not.toContainText(expression);
|
|
|
|
await page.getByRole("button", { name: "保存工程", exact: true }).click();
|
|
await pressureInput.fill("120");
|
|
await pressureInput.press("Enter");
|
|
await page.getByRole("button", { name: "加载工程", exact: true }).click();
|
|
await page
|
|
.locator('.flow-canvas .react-flow__node[data-id="amesim_pneumatic_test_1"]')
|
|
.click();
|
|
await expect(page.getByLabel("参考压力", { exact: true })).toHaveValue(
|
|
expression,
|
|
);
|
|
});
|
|
|
|
test("非法组件参数公式显示错误并阻止 XML 生成", async ({ page }) => {
|
|
await page.goto("/");
|
|
await addPneumaticTestComponent(page);
|
|
|
|
const invalidExpression = "3.14*/4";
|
|
const componentTable = page.getByRole("table", { name: "组件参数" });
|
|
const pressureInput = page.getByLabel("参考压力", { exact: true });
|
|
|
|
await pressureInput.fill(invalidExpression);
|
|
await pressureInput.press("Enter");
|
|
|
|
await expect(pressureInput).toHaveValue(invalidExpression);
|
|
await expect(pressureInput).toHaveAttribute("aria-invalid", "true");
|
|
await expect(
|
|
componentTable.locator(".parameter-table-message-row .field-error"),
|
|
).toBeVisible();
|
|
|
|
await page.getByRole("button", { name: "生成系统 XML", exact: true }).click();
|
|
const consolePanel = page.getByRole("complementary", {
|
|
name: "仿真控制台",
|
|
exact: true,
|
|
});
|
|
await expect(consolePanel).toContainText("XML 生成失败");
|
|
await expect(consolePanel).toContainText("参考压力");
|
|
await expect(consolePanel.getByLabel("生成的系统 XML")).toHaveCount(0);
|
|
});
|
|
|
|
test("仿真数值设置同样保留公式,并在执行协议中使用计算值", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
const expression = "1+2*3";
|
|
const simulationTable = page.getByRole("table", { name: "仿真设置" });
|
|
const stopRow = parameterRow(simulationTable, "结束时间");
|
|
const stopInput = page.getByLabel("结束时间", { exact: true });
|
|
await stopInput.fill(expression);
|
|
await stopInput.press("Enter");
|
|
|
|
await expect(stopInput).toHaveValue(expression);
|
|
await expect(stopRow).not.toContainText("7");
|
|
await stopRow.hover();
|
|
await page.waitForTimeout(600);
|
|
await expect(
|
|
page.getByTestId("parameter-calculated-value"),
|
|
).toContainText("7 s");
|
|
|
|
await page.getByRole("button", { name: "生成系统 XML", exact: true }).click();
|
|
const xmlBlock = page.getByLabel("生成的系统 XML");
|
|
await expect(xmlBlock).toContainText('tStop="7"');
|
|
await expect(xmlBlock).not.toContainText(expression);
|
|
});
|