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( ' { 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(".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"); });