fix: R27-5 R27-6 收口本地回归基线与E2E适配

这个提交包含在:
2026-03-22 21:13:03 +08:00
父节点 312200ec1b
当前提交 15d0473c0b
共修改 8 个文件,包含 148 行新增和 18 行删除
+3 -1
查看文件
@@ -1,5 +1,7 @@
import { expect, test, type Locator, type Page } from "@playwright/test";
import { openNavLink } from "./helpers/navigation";
const FINANCE_MGR = { identifier: "[email protected]", password: "FinanceMgrPassword1234", name: "Finance Manager" };
const ADMINISTRATION = { identifier: "[email protected]", password: "AdministrationPassword1234", name: "Administration" };
@@ -125,7 +127,7 @@ test("E2E 资产流转主链路:建卡→领用归还→调拨→盘点", asyn
await logout(page, ADMINISTRATION.name);
await login(page, FINANCE_MGR);
await page.getByRole("link", { name: "资产盘点" }).click();
await (await openNavLink(page, "资产盘点")).click();
await page.getByTestId("inventory-create").click();
const inventoryRow = page.getByTestId("inventory-row").first();
+24
查看文件
@@ -0,0 +1,24 @@
import { expect, type Locator, type Page } from "@playwright/test";
export async function openBackupModulesIfNeeded(page: Page) {
const summary = page.locator("summary").filter({ hasText: "备用模块" }).first();
if (await summary.count()) {
const details = summary.locator("xpath=ancestor::details[1]");
const isOpen = await details.evaluate((node) => (node as HTMLDetailsElement).open);
if (!isOpen) {
await summary.click();
await expect(details).toHaveAttribute("open", "");
}
}
}
export async function openNavLink(page: Page, name: string | RegExp): Promise<Locator> {
const link = page.getByRole("link", { name }).first();
if (await link.isVisible().catch(() => false)) {
return link;
}
await openBackupModulesIfNeeded(page);
await expect(link).toBeVisible();
return link;
}
+2
查看文件
@@ -204,6 +204,8 @@ test("Portal 管理视角重排正确,备用模块默认折叠", async ({ page
await login(page, ADMIN);
await expect(page.locator('[aria-label^="portal-card-"]').first()).toBeVisible();
const labels = await page.locator('[aria-label^="portal-card-"]').evaluateAll((nodes) =>
nodes.map((node) => node.getAttribute("aria-label")),
);
+6 -4
查看文件
@@ -1,5 +1,7 @@
import { expect, test, type Page } from "@playwright/test";
import { openNavLink } from "./helpers/navigation";
const EMPLOYEE = { identifier: "[email protected]", password: "EmployeePassword1234", name: "Employee" };
const MANAGER = { identifier: "[email protected]", password: "ManagerPassword1234", name: "Manager" };
const FINANCE = { identifier: "[email protected]", password: "FinancePassword1234", name: "Finance" };
@@ -30,7 +32,7 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
// 1) employee: create reimbursement
await login(page, EMPLOYEE);
await page.getByRole("link", { name: "我的报销" }).click();
await page.locator("nav").getByRole("link", { name: "我的报销", exact: true }).click();
const createResponsePromise = page.waitForResponse((response) => {
const url = new URL(response.url());
return response.request().method() === "POST" && url.pathname === "/api/reimbursements" && response.ok();
@@ -47,7 +49,7 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
const reimbursementSummaryText = await page.getByTestId("reimbursement-summary").innerText();
// 2) employee: upload invoice and wait OCR
await page.getByRole("link", { name: "票据中心" }).click();
await (await openNavLink(page, "票据中心")).click();
const marker = `MOCK_E2E_${Date.now()}_${Math.random().toString(16).slice(2)}`;
await page.getByTestId("invoice-upload-file").setInputFiles({
name: `e2e-${Date.now()}.png`,
@@ -87,7 +89,7 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
await logout(page, EMPLOYEE.name);
await login(page, MANAGER);
await page.getByRole("link", { name: "待我处理" }).click();
await (await openNavLink(page, "待我处理")).click();
await expect(page.getByTestId("workflow-tasks-table")).toBeVisible();
const managerTaskRow = page.getByTestId("workflow-task-row").filter({ hasText: reimbursementId }).first();
await expect(managerTaskRow).toBeVisible();
@@ -99,7 +101,7 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
// 6) finance approve + pay
await login(page, FINANCE);
await page.getByRole("link", { name: "待我处理" }).click();
await (await openNavLink(page, "待我处理")).click();
const financeTaskRow = page.getByTestId("workflow-task-row").filter({ hasText: reimbursementId }).first();
await expect(financeTaskRow).toBeVisible();
await financeTaskRow.getByTestId("workflow-task-detail-link").click();
+5 -3
查看文件
@@ -1,5 +1,7 @@
import { expect, test, type Locator, type Page } from "@playwright/test";
import { openNavLink } from "./helpers/navigation";
const EMPLOYEE = { identifier: "[email protected]", password: "EmployeePassword1234", name: "Employee" };
const MANAGER = { identifier: "[email protected]", password: "ManagerPassword1234", name: "Manager" };
const FINANCE_MGR = { identifier: "[email protected]", password: "FinanceMgrPassword1234", name: "Finance Manager" };
@@ -45,7 +47,7 @@ test("E2E 采购主链路:员工提单→经理审批→财务归档", async (
const title = `Playwright 采购 ${Date.now()}`;
await login(page, EMPLOYEE);
await page.getByRole("link", { name: "采购申请", exact: true }).first().click();
await (await openNavLink(page, "采购申请")).click();
await page.getByTestId("purchase-requests-create").click();
await expect(page.getByTestId("purchase-title")).toBeVisible();
@@ -74,7 +76,7 @@ test("E2E 采购主链路:员工提单→经理审批→财务归档", async (
await logout(page, EMPLOYEE.name);
await login(page, MANAGER);
await page.getByRole("link", { name: "待我处理" }).click();
await (await openNavLink(page, "待我处理")).click();
const managerTaskRow = page.getByTestId("workflow-task-row").filter({ hasText: currentTaskId }).first();
await expect(managerTaskRow).toBeVisible({ timeout: 30_000 });
await managerTaskRow.getByTestId("workflow-task-detail-link").click();
@@ -85,7 +87,7 @@ test("E2E 采购主链路:员工提单→经理审批→财务归档", async (
await logout(page, MANAGER.name);
await login(page, FINANCE_MGR);
await page.getByRole("link", { name: "采购申请", exact: true }).first().click();
await (await openNavLink(page, "采购申请")).click();
await page.getByRole("button", { name: "全范围" }).click();
await page.getByRole("combobox").first().selectOption("approved");
const purchaseRow = page.getByRole("row").filter({ hasText: title }).first();
+2 -2
查看文件
@@ -99,8 +99,8 @@ test("E2E 项目工作台:沟通回填 + 收口面板 + Portal 摘要", async
await expect(page.getByTestId("project-closure-panel")).toContainText("确认交付/验收记录齐全");
await page.goto("/portal");
await expect(page.getByText(/项目摘要:/)).toContainText("今日待跟进");
await expect(page.getByText(/项目摘要:/)).toContainText("待收口项目");
await expect(page.getByRole("heading", { name: "今日管理重点" })).toBeVisible();
await expect(page.getByRole("link", { name: /待跟进 \/ 待收口项目/ })).toBeVisible();
await adminClient.dispose();
});