旧版前端工程文件导入时版本对比查验、审阅与仿真时部分阻挡功能实现;前端参数输入格式统一规范
This commit is contained in:
1 parent
22579e51c9
commit
44b6ea74ab
32 files changed
+2087
-322
No files matched your search
@@ -2864,7 +2864,7 @@ test("缺失或错误工程版本、字符串端口和缺失 Handle 均拒绝恢
|
||||
if (invalidVariant === "missing-version") {
|
||||
delete project.projectSchemaVersion;
|
||||
} else if (invalidVariant === "wrong-version") {
|
||||
project.projectSchemaVersion = 2;
|
||||
project.projectSchemaVersion = 3;
|
||||
} else if (invalidVariant === "string-port") {
|
||||
project.nodes[0].data.ports = ["port_1"];
|
||||
} else {
|
||||
|
||||
@@ -883,7 +883,7 @@ test("MECMAS21 旧的 0/1 编码不转换并阻止执行", async ({
|
||||
await expect(consolePanel).toContainText("模型检查发现");
|
||||
});
|
||||
|
||||
test("缺失模型版本的工程可查看但不补默认参数且不能执行", async ({
|
||||
test("缺失模型版本保留来源并补当前默认值,生成 XML 只警告", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/");
|
||||
@@ -923,8 +923,8 @@ test("缺失模型版本的工程可查看但不补默认参数且不能执行",
|
||||
const node = page.locator(
|
||||
'.flow-canvas .react-flow__node[data-id="amesim_mecmas21_1"]',
|
||||
);
|
||||
await expect(node.locator('[data-model-contract-compatible="false"]')).toBeVisible();
|
||||
await expect(node.getByLabel(/模型合同不兼容/)).toBeVisible();
|
||||
await expect(node.locator('[data-model-contract-compatible="true"]')).toBeVisible();
|
||||
await expect(node.getByLabel(/模型合同不兼容/)).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "保存工程", exact: true }).click();
|
||||
const persistedWithoutDefaults = await page.evaluate(() => {
|
||||
const key = Object.keys(window.localStorage).find((candidate) =>
|
||||
@@ -950,7 +950,7 @@ test("缺失模型版本的工程可查看但不补默认参数且不能执行",
|
||||
data &&
|
||||
data.modelVersion === undefined &&
|
||||
data.parameters &&
|
||||
!("strib" in data.parameters),
|
||||
("strib" in data.parameters),
|
||||
);
|
||||
});
|
||||
expect(persistedWithoutDefaults).toBe(true);
|
||||
@@ -959,20 +959,13 @@ test("缺失模型版本的工程可查看但不补默认参数且不能执行",
|
||||
name: "仿真控制台",
|
||||
exact: true,
|
||||
});
|
||||
await page.getByRole("button", { name: "检查模型", exact: true }).click();
|
||||
await expect(consolePanel).toHaveClass(/minimized/);
|
||||
await expect(
|
||||
consolePanel.locator(".simulation-console-dock-summary"),
|
||||
).toContainText("模型检查发现");
|
||||
await expandSimulationConsole(page);
|
||||
await expect(consolePanel.locator(".simulation-console-dock-log")).toContainText(
|
||||
"缺少 modelVersion",
|
||||
);
|
||||
await expect(consolePanel).toContainText("工程包含旧版或版本未知的组件");
|
||||
await page.getByRole("button", { name: "生成系统 XML", exact: true }).click();
|
||||
await expandSimulationConsole(page);
|
||||
await expect(consolePanel).toContainText("不能生成执行 XML");
|
||||
await page.getByRole("button", { name: "运行仿真", exact: true }).click();
|
||||
await expect(consolePanel).toContainText("模型检查发现");
|
||||
await expect(consolePanel).toContainText("XML 已生成");
|
||||
await expect(consolePanel).toContainText("可能出现仿真失败或仿真结果与实际不符");
|
||||
await expect(consolePanel).not.toContainText("不能生成执行 XML");
|
||||
});
|
||||
|
||||
test("详情浮层只在参数列悬停且下拉选择期间不触发", async ({ page }) => {
|
||||
|
||||
@@ -103,7 +103,7 @@ test("压力默认显示 Pa,bar 与 Pa 换算保持绝压且无大气压偏移
|
||||
await expectPressureXml(page, 250000);
|
||||
}
|
||||
const exported = await exportProject(page);
|
||||
expect(exported.project.nodes[0].data.parameters.reference_pressure).toBe(250000);
|
||||
expect(exported.project.nodes[0].data.parameters.reference_pressure).toBe(2.5);
|
||||
expect(exported.project.nodes[0].data.parameterUnits.reference_pressure).toBe("bar");
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import cases from "../../../tests/fixtures/parameter-expressions.json" with { type: "json" };
|
||||
import { evaluateParameterExpression } from "../../src/parameterExpression";
|
||||
import { componentVersionNotices, decodeProjectParameters, encodeProjectParameters } from "../../src/projectCompatibility";
|
||||
const definitions = [{ type: "chamber", modelType: "chamber", modelVersion: "2", parameters: {
|
||||
p0: { unit: "Pa", quantity: "pressure" }, T0: { unit: "K", quantity: "temperature" },
|
||||
} }];
|
||||
function project(value: number | string, version: 1 | 2 = 2) {
|
||||
return { projectSchemaVersion: version, nodes: [{ id: "c", data: { label: "c", componentType: "chamber",
|
||||
modelType: "chamber", modelVersion: "1", parameters: { p0: value, T0: 20 }, parameterUnits: { p0: "bar", T0: "degC" } } }] };
|
||||
}
|
||||
test("shared expression grammar and resource limits", () => {
|
||||
for (const [source, expected] of cases.valid) {
|
||||
const actual = evaluateParameterExpression(String(source));
|
||||
expect(actual.ok, String(source)).toBe(true);
|
||||
if (actual.ok) expect(actual.value).toBeCloseTo(Number(expected), 12);
|
||||
}
|
||||
for (const source of [...cases.invalid, "(".repeat(34) + "1" + ")".repeat(34), "1+".repeat(256) + "1", "1".repeat(513), `min(${Array(17).fill("1").join(",")})`]) {
|
||||
expect(evaluateParameterExpression(source).ok, source).toBe(false);
|
||||
}
|
||||
});
|
||||
test("v2 selected-unit numbers and expression values agree; legacy numbers retain SI", () => {
|
||||
for (const value of [2.5, "2.5", "=2.5", "2+0.5"]) {
|
||||
const input = project(value);
|
||||
const original = structuredClone(input);
|
||||
const internal = decodeProjectParameters(input, definitions);
|
||||
const parameter = internal.nodes[0].data.parameters.p0;
|
||||
const actual = typeof parameter === "number" ? parameter :
|
||||
(() => { const e = evaluateParameterExpression(parameter); return e.ok ? e.value * 1e5 : NaN; })();
|
||||
expect(actual).toBe(250000);
|
||||
expect(internal.nodes[0].data.parameters.T0).toBe(293.15);
|
||||
const exported = encodeProjectParameters(internal, definitions);
|
||||
expect(exported.projectSchemaVersion).toBe(2);
|
||||
expect(decodeProjectParameters(exported, definitions)).toEqual(internal);
|
||||
expect(input).toEqual(original);
|
||||
}
|
||||
expect(decodeProjectParameters(project(250000, 1), definitions).nodes[0].data.parameters.p0).toBe(250000);
|
||||
expect(() => encodeProjectParameters(project(2.5), definitions)).toThrow(/重复换算/);
|
||||
});
|
||||
test("version index finds stale and missing versions without mutating or per-node fetch", () => {
|
||||
const input = project(2.5);
|
||||
const original = structuredClone(input);
|
||||
expect(componentVersionNotices(input.nodes, definitions)).toEqual([
|
||||
{ componentId: "c", label: "c", storedVersion: "1", currentVersion: "2" },
|
||||
]);
|
||||
expect(input).toEqual(original);
|
||||
input.nodes[0].data.modelVersion = "2";
|
||||
expect(componentVersionNotices(input.nodes, definitions)).toEqual([]);
|
||||
});
|
||||
|
||||
test("export preserves exact SI doubles when display-unit round trip loses a bit", () => {
|
||||
const input = project(15299999.999999998, 1);
|
||||
input.nodes[0].data.parameterUnits.p0 = "bar";
|
||||
input.nodes[0].data.parameters.T0 = 293.15;
|
||||
const encoded = encodeProjectParameters(input, definitions);
|
||||
expect(encoded.nodes[0].data.parameterUnits.p0).toBe("Pa");
|
||||
expect(encoded.nodes[0].data.parameters.p0).toBe(15299999.999999998);
|
||||
expect(decodeProjectParameters(encoded, definitions).nodes[0].data.parameters).toEqual(input.nodes[0].data.parameters);
|
||||
});
|
||||
Reference in new issue
Block a user