完善MECMAS21参数配置与分组交互

This commit is contained in:
ljz committed 2026-08-03 23:51:27 +08:00
1 parent 32f21f08ff
commit be54070855
28 files changed
+3418 -202

No files matched your search

+233
View File
@@ -186,6 +186,239 @@ export const componentCatalog = {
},
],
},
{
type: "choice_visibility_test",
label: "离散参数测试元件",
modelType: "choice_visibility_test",
modelVersion: "1.0.0",
symbol: "symbol-not-registered",
order: 5,
category: {
id: "generic",
label: "通用组件",
order: 1,
},
ports: [],
parameters: [
{
name: "mode",
label: "工作模式",
quantity: "dimensionless",
unit: "",
default: 1,
minimum: 1,
maximum: 3,
minimumExclusive: false,
editor: "choice",
options: [
{ value: 1, label: "基础模式" },
{ value: 2, label: "高级模式" },
{ value: 3, label: "专家模式" },
],
},
{
name: "variant",
label: "高级变体",
quantity: "dimensionless",
unit: "",
default: 10,
minimum: 10,
maximum: 20,
minimumExclusive: false,
editor: "choice",
options: [
{ value: 10, label: "变体 A" },
{ value: 20, label: "变体 B" },
],
},
{
name: "basic_value",
label: "基础参数",
quantity: "dimensionless",
unit: "",
default: 1,
minimumExclusive: false,
visibleWhen: [{ parameter: "mode", values: [1] }],
},
{
name: "advanced_value",
label: "高级参数",
quantity: "dimensionless",
unit: "",
default: 1,
minimumExclusive: false,
visibleWhen: [{ parameter: "mode", values: [2, 3] }],
},
{
name: "combined_value",
label: "组合参数",
quantity: "dimensionless",
unit: "",
default: 3,
minimumExclusive: false,
visibleWhen: [
{ parameter: "mode", values: [2, 3] },
{ parameter: "variant", values: [20] },
],
},
],
},
{
type: "amesim_mecmas21",
label: "MECMAS21 编码测试元件",
modelType: "amesim_mecmas21",
modelVersion: "1.0.0",
symbol: "symbol-not-registered",
order: 6,
category: {
id: "generic",
label: "通用组件",
order: 1,
},
ports: [],
parameterGroups: [
{
id: "friction",
label: "摩擦",
order: 10,
parameters: ["frictionType", "strib", "rvisc"],
defaultExpanded: false,
},
{
id: "endstops",
label: "限位",
order: 20,
parameters: ["discContactOption", "xmin"],
defaultExpanded: false,
},
],
parameters: [
{
name: "mass",
label: "质量",
quantity: "mass",
unit: "kg",
default: 1,
minimum: 0,
minimumExclusive: true,
},
{
name: "rvisc",
label: "黏性摩擦系数",
quantity: "translational_damping",
unit: "N/(m/s)",
default: 0,
minimum: 0,
minimumExclusive: false,
description: "用于验证折叠摩擦参数仍支持详情提示和值保留。",
visibleWhen: [{ parameter: "useFriction", values: [2] }],
},
{
name: "xmin",
label: "下位移限位",
quantity: "length",
unit: "m",
default: -1,
minimumExclusive: false,
visibleWhen: [{ parameter: "stoptype", values: [1, 2, 3] }],
},
{
name: "useFriction",
label: "启用摩擦",
quantity: "dimensionless",
unit: "",
default: 1,
minimum: 1,
maximum: 2,
minimumExclusive: false,
editor: "choice",
options: [
{ value: 1, label: "禁用" },
{ value: 2, label: "启用" },
],
},
{
name: "stoptype",
label: "限位类型",
quantity: "dimensionless",
unit: "",
default: 4,
minimum: 1,
maximum: 4,
minimumExclusive: false,
editor: "choice",
options: [
{ value: 1, label: "理想限位" },
{ value: 2, label: "弹性限位" },
{ value: 3, label: "恢复碰撞" },
{ value: 4, label: "无限位" },
],
},
{
name: "discContactOption",
label: "允许负接触力",
quantity: "dimensionless",
unit: "",
default: 1,
minimum: 1,
maximum: 2,
minimumExclusive: false,
editor: "choice",
options: [
{ value: 1, label: "允许负接触力" },
{ value: 2, label: "不允许负接触力" },
],
visibleWhen: [{ parameter: "stoptype", values: [2] }],
},
{
name: "strib",
label: "Stribeck 选项",
quantity: "dimensionless",
unit: "",
default: 1,
minimum: 1,
maximum: 2,
minimumExclusive: false,
editor: "choice",
options: [
{ value: 1, label: "禁用" },
{ value: 2, label: "启用" },
],
visibleWhen: [
{ parameter: "useFriction", values: [2] },
{ parameter: "stoptype", values: [1, 2, 4] },
{ parameter: "frictionType", values: [2] },
],
},
{
name: "frictionType",
label: "摩擦类型",
quantity: "dimensionless",
unit: "",
default: 1,
minimum: 1,
maximum: 2,
minimumExclusive: false,
editor: "choice",
options: [
{ value: 1, label: "简单" },
{ value: 2, label: "高级" },
],
visibleWhen: [
{ parameter: "useFriction", values: [2] },
{ parameter: "stoptype", values: [1, 2, 4] },
],
},
{
name: "unrelatedCode",
label: "无关编码",
quantity: "dimensionless",
unit: "",
default: 7,
minimumExclusive: false,
},
],
},
],
},
],
+501 -9
View File
@@ -7,7 +7,11 @@ test.beforeEach(async ({ page }) => {
});
function parameterRow(table: Locator, name: string) {
return table.getByRole("rowheader", { name, exact: true }).locator("..");
return parameterNameCell(table, name).locator("..");
}
function parameterNameCell(table: Locator, name: string) {
return table.getByRole("rowheader", { name, exact: true });
}
async function addPneumaticTestComponent(page: Page) {
@@ -22,6 +26,30 @@ async function addPneumaticTestComponent(page: Page) {
await node.click();
}
async function addChoiceVisibilityTestComponent(page: Page) {
const canvas = page.locator(".flow-canvas .react-flow__pane");
await page
.getByRole("button", { name: "离散参数测试元件", exact: true })
.dragTo(canvas, { targetPosition: { x: 620, y: 330 } });
const node = page.locator(
'.flow-canvas .react-flow__node[data-id="choice_visibility_test_1"]',
);
await expect(node).toBeVisible();
await node.click();
}
async function addMecmasEncodingTestComponent(page: Page) {
const canvas = page.locator(".flow-canvas .react-flow__pane");
await page
.getByRole("button", { name: "MECMAS21 编码测试元件", exact: true })
.dragTo(canvas, { targetPosition: { x: 620, y: 330 } });
const node = page.locator(
'.flow-canvas .react-flow__node[data-id="amesim_mecmas21_1"]',
);
await expect(node).toBeVisible();
await node.click();
}
test("组件参数和仿真设置使用共享的三列表格", async ({ page }) => {
await page.goto("/");
await addPneumaticTestComponent(page);
@@ -170,6 +198,456 @@ test("组件参数和仿真设置使用共享的三列表格", async ({ page })
await expect(solver).toHaveValue("Radau");
});
test("通用离散选项按多条件控制参数行且保留隐藏值和未知旧值", async ({
page,
}) => {
await page.goto("/");
await addChoiceVisibilityTestComponent(page);
const componentTable = page.getByRole("table", { name: "组件参数" });
const mode = page.getByLabel("工作模式", { exact: true });
const variant = page.getByLabel("高级变体", { exact: true });
await expect(mode).toHaveValue("1");
await expect(mode.locator("option:checked")).toHaveText("基础模式");
await expect(variant).toHaveValue("10");
await expect(parameterRow(componentTable, "基础参数")).toBeVisible();
await expect(parameterRow(componentTable, "高级参数")).toHaveCount(0);
await expect(parameterRow(componentTable, "组合参数")).toHaveCount(0);
await mode.selectOption("2");
await expect(parameterRow(componentTable, "基础参数")).toHaveCount(0);
await expect(parameterRow(componentTable, "高级参数")).toBeVisible();
await expect(parameterRow(componentTable, "组合参数")).toHaveCount(0);
const advancedValue = page.getByLabel("高级参数", { exact: true });
await advancedValue.fill("42");
await advancedValue.press("Enter");
await variant.selectOption("20");
await expect(parameterRow(componentTable, "组合参数")).toBeVisible();
await mode.selectOption("3");
await expect(parameterRow(componentTable, "高级参数")).toBeVisible();
await expect(parameterRow(componentTable, "组合参数")).toBeVisible();
await mode.selectOption("1");
await expect(parameterRow(componentTable, "高级参数")).toHaveCount(0);
await expect(parameterRow(componentTable, "组合参数")).toHaveCount(0);
await mode.selectOption("2");
await expect(page.getByLabel("高级参数", { exact: true })).toHaveValue("42");
await page.getByRole("button", { name: "保存工程", exact: true }).click();
const changedProjectCount = await page.evaluate(() => {
let changed = 0;
Object.keys(window.localStorage)
.filter((key) =>
[
"system-simulation-flow:autosave",
"system-simulation-flow:project:",
].some((prefix) => key.startsWith(prefix)),
)
.forEach((key) => {
const raw = window.localStorage.getItem(key);
if (!raw) {
return;
}
const project = JSON.parse(raw) as {
nodes?: Array<{
id?: string;
data?: { parameters?: Record<string, number | string> };
}>;
};
const node = project.nodes?.find(
(candidate) => candidate.id === "choice_visibility_test_1",
);
if (!node?.data?.parameters) {
return;
}
node.data.parameters.mode = 99;
window.localStorage.setItem(key, JSON.stringify(project));
changed += 1;
});
return changed;
});
expect(changedProjectCount).toBeGreaterThanOrEqual(2);
await page.getByRole("button", { name: "加载工程", exact: true }).click();
await page
.locator('.flow-canvas .react-flow__node[data-id="choice_visibility_test_1"]')
.click();
await expect(mode).toHaveValue("");
await expect(mode).toHaveAttribute("aria-invalid", "true");
await expect(mode.locator("option:checked")).toHaveText(
"当前选项无效,请重新选择",
);
await expect(parameterRow(componentTable, "基础参数")).toHaveCount(0);
await expect(parameterRow(componentTable, "高级参数")).toHaveCount(0);
await expect(parameterRow(componentTable, "组合参数")).toHaveCount(0);
await page.getByRole("button", { name: "保存工程", exact: true }).click();
const persistedModes = await page.evaluate(() =>
Object.keys(window.localStorage)
.filter((key) => key.startsWith("system-simulation-flow:project:"))
.flatMap((key) => {
const raw = window.localStorage.getItem(key);
if (!raw) {
return [];
}
const project = JSON.parse(raw) as {
nodes?: Array<{
id?: string;
data?: { parameters?: Record<string, number | string> };
}>;
};
const node = project.nodes?.find(
(candidate) => candidate.id === "choice_visibility_test_1",
);
return node?.data?.parameters ? [node.data.parameters.mode] : [];
}),
);
expect(persistedModes).toContain(99);
await mode.selectOption("2");
await expect(mode).toHaveValue("2");
await expect(mode).not.toHaveAttribute("aria-invalid", "true");
await expect(page.getByLabel("高级参数", { exact: true })).toHaveValue("42");
});
test("MECMAS21 可配置参数前置并按条件显示可折叠参数组", async ({
page,
}) => {
await page.goto("/");
await addMecmasEncodingTestComponent(page);
const componentTable = page.getByRole("table", { name: "组件参数" });
const useFriction = page.getByLabel("启用摩擦", { exact: true });
const stoptype = page.getByLabel("限位类型", { exact: true });
const frictionGroup = componentTable.getByRole("button", { name: /摩擦/ });
const endstopsGroup = componentTable.getByRole("button", { name: /限位/ });
const parameterOrder = (
await componentTable.getByRole("rowheader").allTextContents()
).map((text) => text.trim());
expect(parameterOrder.indexOf("启用摩擦")).toBeGreaterThanOrEqual(0);
expect(parameterOrder.indexOf("限位类型")).toBeGreaterThanOrEqual(0);
expect(parameterOrder.indexOf("质量")).toBeGreaterThanOrEqual(0);
expect(parameterOrder.indexOf("启用摩擦")).toBeLessThan(
parameterOrder.indexOf("质量"),
);
expect(parameterOrder.indexOf("限位类型")).toBeLessThan(
parameterOrder.indexOf("质量"),
);
await expect(useFriction).toHaveValue("1");
await expect(stoptype).toHaveValue("4");
await expect(frictionGroup).toHaveCount(0);
await expect(endstopsGroup).toHaveCount(0);
await useFriction.selectOption("2");
await expect(frictionGroup).toBeVisible();
await expect(frictionGroup).toHaveAttribute("aria-expanded", "false");
await expect(frictionGroup.locator("xpath=ancestor::th")).toHaveAttribute(
"colspan",
"3",
);
await expect(page.getByLabel("摩擦类型", { exact: true })).toBeHidden();
const frictionGroupBox = await frictionGroup.boundingBox();
const unrelatedRowBox = await parameterRow(
componentTable,
"无关编码",
).boundingBox();
expect(frictionGroupBox).not.toBeNull();
expect(unrelatedRowBox).not.toBeNull();
expect(frictionGroupBox!.y).toBeGreaterThan(unrelatedRowBox!.y);
await frictionGroup.focus();
await expect(frictionGroup).toBeFocused();
await page.keyboard.press("Enter");
await expect(frictionGroup).toHaveAttribute("aria-expanded", "true");
const frictionType = page.getByLabel("摩擦类型", { exact: true });
const strib = page.getByLabel("Stribeck 选项", { exact: true });
const viscousFriction = page.getByLabel("黏性摩擦系数", { exact: true });
await expect(frictionType).toBeVisible();
await expect(viscousFriction).toBeVisible();
await expect(strib).toHaveCount(0);
await frictionType.selectOption("2");
await expect(strib).toBeVisible();
const expandedOrder = (
await componentTable.getByRole("rowheader").allTextContents()
).map((text) => text.trim());
expect(expandedOrder.indexOf("摩擦类型")).toBeLessThan(
expandedOrder.indexOf("Stribeck 选项"),
);
expect(expandedOrder.indexOf("Stribeck 选项")).toBeLessThan(
expandedOrder.indexOf("黏性摩擦系数"),
);
await frictionGroup.focus();
await expect(frictionGroup).toBeFocused();
await page.keyboard.press("Space");
await expect(frictionGroup).toHaveAttribute("aria-expanded", "false");
await expect(frictionType).toBeHidden();
await expect(strib).toBeHidden();
await expect(viscousFriction).toBeHidden();
await page.keyboard.press("Space");
await expect(frictionGroup).toHaveAttribute("aria-expanded", "true");
await expect(frictionType).toHaveValue("2");
await stoptype.selectOption("2");
await expect(endstopsGroup).toBeVisible();
await expect(endstopsGroup).toHaveAttribute("aria-expanded", "false");
await expect(endstopsGroup.locator("xpath=ancestor::th")).toHaveAttribute(
"colspan",
"3",
);
await endstopsGroup.focus();
await page.keyboard.press("Enter");
await expect(endstopsGroup).toHaveAttribute("aria-expanded", "true");
await expect(page.getByLabel("允许负接触力", { exact: true })).toBeVisible();
await expect(page.getByLabel("下位移限位", { exact: true })).toBeVisible();
const endstopOrder = (
await componentTable.getByRole("rowheader").allTextContents()
).map((text) => text.trim());
expect(endstopOrder.indexOf("允许负接触力")).toBeLessThan(
endstopOrder.indexOf("下位移限位"),
);
const endstopsGroupBox = await endstopsGroup.boundingBox();
expect(endstopsGroupBox).not.toBeNull();
expect(frictionGroupBox!.y).toBeLessThan(endstopsGroupBox!.y);
await stoptype.selectOption("3");
await expect(frictionGroup).toBeVisible();
await expect(endstopsGroup).toBeVisible();
await expect(frictionType).toHaveCount(0);
await expect(strib).toHaveCount(0);
await expect(viscousFriction).toBeVisible();
await expect(page.getByLabel("允许负接触力", { exact: true })).toHaveCount(0);
await expect(page.getByLabel("下位移限位", { exact: true })).toBeVisible();
await stoptype.selectOption("4");
await expect(endstopsGroup).toHaveCount(0);
await expect(frictionType).toBeVisible();
});
test("MECMAS21 参数组折叠和条件切换保留值并清理详情浮层", async ({
page,
}) => {
await page.goto("/");
await addMecmasEncodingTestComponent(page);
const componentTable = page.getByRole("table", { name: "组件参数" });
const useFriction = page.getByLabel("启用摩擦", { exact: true });
const frictionGroup = componentTable.getByRole("button", { name: /摩擦/ });
await useFriction.selectOption("2");
await frictionGroup.click();
const frictionType = page.getByLabel("摩擦类型", { exact: true });
await frictionType.selectOption("2");
const strib = page.getByLabel("Stribeck 选项", { exact: true });
const viscousFriction = page.getByLabel("黏性摩擦系数", { exact: true });
await strib.selectOption("2");
await viscousFriction.fill("12.5");
await viscousFriction.press("Enter");
await expect(viscousFriction).toHaveValue("12.5");
await frictionGroup.focus();
await parameterNameCell(componentTable, "黏性摩擦系数").hover();
await page.waitForTimeout(600);
const preview = page.locator("body > #parameter-help-preview");
await expect(preview.locator(".parameter-help-preview-title")).toHaveText(
"黏性摩擦系数",
);
await page.keyboard.press("Enter");
await expect(frictionGroup).toHaveAttribute("aria-expanded", "false");
await expect(preview).toHaveCount(0);
await frictionGroup.click();
await expect(frictionType).toHaveValue("2");
await expect(strib).toHaveValue("2");
await expect(viscousFriction).toHaveValue("12.5");
await useFriction.selectOption("1");
await expect(frictionGroup).toHaveCount(0);
await useFriction.selectOption("2");
await expect(frictionGroup).toBeVisible();
if ((await frictionGroup.getAttribute("aria-expanded")) !== "true") {
await frictionGroup.click();
}
await expect(frictionType).toHaveValue("2");
await expect(strib).toHaveValue("2");
await expect(viscousFriction).toHaveValue("12.5");
await viscousFriction.fill("-1");
await viscousFriction.press("Enter");
await expect(componentTable.getByText("不能小于 0", { exact: true })).toBeVisible();
await frictionGroup.click();
await expect(frictionGroup).toHaveAttribute("aria-expanded", "false");
await expect(frictionGroup).toContainText("1 个错误");
await useFriction.selectOption("1");
await expect(frictionGroup).toBeVisible();
await expect(frictionGroup).toContainText("1 个错误");
await expect(frictionGroup).toHaveAttribute("aria-describedby");
await frictionGroup.click();
await expect(componentTable).toContainText(
"1 个错误参数被当前配置选项隐藏,请调整上方配置后修改",
);
});
test("MECMAS21 旧参数编码只迁移一次且新工程和 XML 写入版本", async ({
page,
}) => {
await page.goto("/");
await addMecmasEncodingTestComponent(page);
const useFriction = page.getByLabel("启用摩擦", { exact: true });
const frictionGroup = page
.getByRole("table", { name: "组件参数" })
.getByRole("button", { name: /摩擦/ });
await expect(useFriction).toHaveValue("1");
await expect(frictionGroup).toHaveCount(0);
await page.getByRole("button", { name: "保存工程", exact: true }).click();
const savedEncodingVersions = await page.evaluate(() =>
Object.keys(window.localStorage)
.filter((key) => key.startsWith("system-simulation-flow:project:"))
.flatMap((key) => {
const raw = window.localStorage.getItem(key);
if (!raw) {
return [];
}
const project = JSON.parse(raw) as {
amesimParameterEncodingVersion?: number | null;
nodes?: Array<{ id?: string }>;
};
return project.nodes?.some(
(node) => node.id === "amesim_mecmas21_1",
)
? [project.amesimParameterEncodingVersion]
: [];
}),
);
expect(savedEncodingVersions).toContain(1);
await page.getByRole("button", { name: "生成系统 XML", exact: true }).click();
await expect(page.getByLabel("生成的系统 XML")).toContainText(
'amesimParameterEncodingVersion="1"',
);
const migratedProjectCount = await page.evaluate(() => {
let changed = 0;
Object.keys(window.localStorage)
.filter((key) =>
[
"system-simulation-flow:autosave",
"system-simulation-flow:project:",
].some((prefix) => key.startsWith(prefix)),
)
.forEach((key) => {
const raw = window.localStorage.getItem(key);
if (!raw) {
return;
}
const project = JSON.parse(raw) as {
mediumReferenceVersion?: number | null;
amesimParameterEncodingVersion?: number | null;
nodes?: Array<{
id?: string;
data?: {
modelType?: string;
parameters?: Record<string, number | string>;
};
}>;
};
const node = project.nodes?.find(
(candidate) => candidate.id === "amesim_mecmas21_1",
);
if (!node?.data?.parameters) {
return;
}
project.amesimParameterEncodingVersion = null;
project.mediumReferenceVersion = null;
delete node.data.modelType;
node.data.parameters.useFriction = 0;
delete node.data.parameters.strib;
node.data.parameters.unrelatedCode = 9;
window.localStorage.setItem(key, JSON.stringify(project));
changed += 1;
});
return changed;
});
expect(migratedProjectCount).toBeGreaterThanOrEqual(2);
await page.getByRole("button", { name: "加载工程", exact: true }).click();
await page
.locator('.flow-canvas .react-flow__node[data-id="amesim_mecmas21_1"]')
.click();
await expect(useFriction).toHaveValue("1");
await expect(useFriction.locator("option:checked")).toHaveText("禁用");
await useFriction.selectOption("2");
await expect(frictionGroup).toHaveAttribute("aria-expanded", "false");
await frictionGroup.click();
const frictionType = page.getByLabel("摩擦类型", { exact: true });
await frictionType.selectOption("2");
const strib = page.getByLabel("Stribeck 选项", { exact: true });
await expect(strib).toHaveValue("2");
await expect(strib.locator("option:checked")).toHaveText("启用");
await expect(page.getByLabel("无关编码", { exact: true })).toHaveValue("9");
await useFriction.selectOption("1");
await expect(frictionGroup).toHaveCount(0);
await page.getByRole("button", { name: "保存工程", exact: true }).click();
await page.getByRole("button", { name: "加载工程", exact: true }).click();
await page
.locator('.flow-canvas .react-flow__node[data-id="amesim_mecmas21_1"]')
.click();
await expect(useFriction).toHaveValue("1");
await expect(page.getByLabel("无关编码", { exact: true })).toHaveValue("9");
await useFriction.selectOption("2");
await expect(frictionGroup).toBeVisible();
if ((await frictionGroup.getAttribute("aria-expanded")) !== "true") {
await frictionGroup.click();
}
await expect(frictionType).toHaveValue("2");
await expect(strib).toHaveValue("2");
});
test("详情浮层只在参数列悬停且下拉选择期间不触发", async ({ page }) => {
await page.goto("/");
await addMecmasEncodingTestComponent(page);
const componentTable = page.getByRole("table", { name: "组件参数" });
const choice = page.getByLabel("启用摩擦", { exact: true });
const otherNameCell = parameterNameCell(componentTable, "无关编码");
const preview = page.locator("body > #parameter-help-preview");
await otherNameCell.hover();
await page.waitForTimeout(600);
await expect(preview).toBeVisible();
await expect(preview.locator(".parameter-help-preview-title")).toHaveText(
"无关编码",
);
await choice.hover();
await expect(preview).toHaveCount(0);
await choice.focus();
await expect(choice).toBeFocused();
await otherNameCell.hover();
await page.waitForTimeout(600);
await expect(preview).toHaveCount(0);
await choice.selectOption("2");
await choice.focus();
await otherNameCell.hover();
await page.waitForTimeout(600);
await expect(preview).toHaveCount(0);
await choice.evaluate((element) => element.blur());
await page.locator(".panel-title").filter({ hasText: "组件参数" }).hover();
await otherNameCell.hover();
await page.waitForTimeout(600);
await expect(preview.locator(".parameter-help-preview-title")).toHaveText(
"无关编码",
);
});
test("最窄参数面板滚动时表头固定且值列保持可用宽度", async ({ page }) => {
await page.goto("/");
await addPneumaticTestComponent(page);
@@ -234,19 +712,31 @@ test("最窄参数面板滚动时表头固定且值列保持可用宽度", async
expect(narrowLayout.horizontalOverflow).toBeLessThanOrEqual(1);
});
test("参数说明延迟显示,单位切换不改变 XML 基础值", async ({ page }) => {
test("参数说明只在参数列悬停显示,单位切换不改变 XML 基础值", async ({
page,
}) => {
await page.goto("/");
await addPneumaticTestComponent(page);
const componentTable = page.getByRole("table", { name: "组件参数" });
const pressureRow = parameterRow(componentTable, "参考压力");
const pressureNameCell = parameterNameCell(componentTable, "参考压力");
const pressureValueCell = pressureRow.locator(".parameter-table-value-cell");
const pressureUnitCell = pressureRow.locator(".parameter-table-unit-cell");
const preview = page.locator("body > #parameter-help-preview");
const pressureRowBox = await pressureRow.boundingBox();
expect(pressureRowBox).not.toBeNull();
await pressureValueCell.hover();
await page.waitForTimeout(600);
await expect(preview).toHaveCount(0);
await pressureUnitCell.hover();
await page.waitForTimeout(600);
await expect(preview).toHaveCount(0);
const pressureNameCellBox = await pressureNameCell.boundingBox();
expect(pressureNameCellBox).not.toBeNull();
const pointer = {
x: pressureRowBox!.x + pressureRowBox!.width / 2,
y: pressureRowBox!.y + pressureRowBox!.height / 2,
x: pressureNameCellBox!.x + pressureNameCellBox!.width / 2,
y: pressureNameCellBox!.y + pressureNameCellBox!.height / 2,
};
await page.mouse.move(pointer.x, pointer.y);
await page.waitForTimeout(600);
@@ -283,13 +773,15 @@ test("参数说明延迟显示,单位切换不改变 XML 基础值", async ({
expect(Math.abs(stationaryPreviewBox!.x - previewBox!.x)).toBeLessThanOrEqual(1);
expect(Math.abs(stationaryPreviewBox!.y - previewBox!.y)).toBeLessThanOrEqual(1);
await pressureValueCell.hover();
await expect(preview).toHaveCount(0);
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 pressureNameCell.hover();
await page.waitForTimeout(600);
await expect(preview.locator(".parameter-help-preview-meta")).toContainText(
"默认值:100",
@@ -527,7 +1019,7 @@ test("组件参数公式保留原式,并在说明中显示计算值且 XML 只
await expect(pressureInput).toHaveValue(expression);
await expect(pressureRow).not.toContainText("78.5");
await pressureRow.hover();
await parameterNameCell(componentTable, "参考压力").hover();
await page.waitForTimeout(600);
const preview = page.locator("body > #parameter-help-preview");
await expect(preview).toBeVisible();
@@ -602,7 +1094,7 @@ test("仿真数值设置同样保留公式,并在执行协议中使用计算
await expect(stopInput).toHaveValue(expression);
await expect(stopRow).not.toContainText("7");
await stopRow.hover();
await parameterNameCell(simulationTable, "结束时间").hover();
await page.waitForTimeout(600);
await expect(
page.getByTestId("parameter-calculated-value"),