统一菜单命名并移除剩余台账工具(05-31-unified-menu-remove-ledger-tools-wave2)
这个提交包含在:
@@ -83,7 +83,7 @@ test("E2E 资产流转主链路:建卡→领用归还→调拨→盘点", asyn
|
||||
|
||||
await login(page, FINANCE_MGR);
|
||||
await (await openNavLink(page, "资产")).click();
|
||||
await expect(page.getByRole("heading", { name: "资产台账" })).toBeVisible({ timeout: 30_000 });
|
||||
await expect(page.getByRole("heading", { name: "资产" })).toBeVisible({ timeout: 30_000 });
|
||||
await expect(page.getByTestId("asset-category-code")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "资产分类" }).click();
|
||||
await expect(page.getByTestId("asset-category-manager")).toBeVisible();
|
||||
|
||||
@@ -304,7 +304,7 @@ export async function uploadLiveInvoiceAndWait(page: Page, invoiceFilePath: stri
|
||||
const url = new URL(response.url());
|
||||
return response.request().method() === "POST" && url.pathname === "/api/invoice-pool/upload" && response.ok();
|
||||
});
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "上传票据" }).click();
|
||||
await page.getByTestId("invoice-upload-file").setInputFiles(invoiceFilePath);
|
||||
await page.getByTestId("invoice-upload-submit").click();
|
||||
const uploadPayload = (await (await uploadResponsePromise).json()) as UploadInvoiceResponse;
|
||||
|
||||
@@ -53,7 +53,7 @@ test("E2E 轻交互 OCR:报销详情上传后自动添加并提交", async ({
|
||||
await logout(page, EMPLOYEE.name);
|
||||
});
|
||||
|
||||
test("E2E 轻交互 OCR:票据中心缺关键字段后可在当前页修正并标记可用", async ({ page }) => {
|
||||
test("E2E 轻交互 OCR:票据缺关键字段后可在当前页修正并标记可用", async ({ page }) => {
|
||||
test.skip(process.env.PLAYWRIGHT_OCR_MOCK !== "1", "需要 mock OCR 环境和 OCR 作业开启");
|
||||
|
||||
await login(page, EMPLOYEE);
|
||||
@@ -61,7 +61,7 @@ test("E2E 轻交互 OCR:票据中心缺关键字段后可在当前页修正并
|
||||
await (await openNavLink(page, "票据")).click();
|
||||
await expect(page.getByTestId("invoice-pool-table")).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "上传票据" }).click();
|
||||
await page.getByTestId("invoice-upload-file").setInputFiles({
|
||||
name: `r73-missing-${Date.now()}.pdf`,
|
||||
mimeType: "application/pdf",
|
||||
|
||||
@@ -191,8 +191,8 @@ function mockNavigation(page: import("@playwright/test").Page, mode: "employee"
|
||||
{ key: "portal", href: "/portal", label: "工作台", icon: "home_app_logo", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "workflow", href: "/workflow/tasks", label: "待我处理", icon: "fact_check", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "expense", href: "/reimbursements", label: "报销", icon: "request_quote", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "purchase", href: "/purchase-requests", label: "采购申请", icon: "shopping_cart", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "contracts", href: "/contracts-registry", label: "合同台账", icon: "description", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "purchase", href: "/purchase-requests", label: "采购", icon: "shopping_cart", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "contracts", href: "/contracts-registry", label: "合同", icon: "description", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "projects", href: "/projects", label: "项目", icon: "workspaces", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "assets", href: "/assets", label: "资产", icon: "inventory_2", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "team", href: "/team", label: "团队", icon: "groups", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
@@ -211,7 +211,7 @@ function mockNavigation(page: import("@playwright/test").Page, mode: "employee"
|
||||
main: [
|
||||
{ key: "portal", href: "/portal", label: "工作台", icon: "home_app_logo", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "expense", href: "/reimbursements", label: "报销", icon: "request_quote", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "purchase", href: "/purchase-requests", label: "采购申请", icon: "shopping_cart", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "purchase", href: "/purchase-requests", label: "采购", icon: "shopping_cart", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "projects", href: "/projects", label: "项目", icon: "workspaces", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "assets", href: "/assets", label: "资产", icon: "inventory_2", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
{ key: "leave", href: "/leave-requests", label: "请假记录", icon: "event_available", placement: "main", permissionCodes: [], featureFlagKey: null },
|
||||
|
||||
@@ -40,7 +40,7 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
|
||||
const url = new URL(response.url());
|
||||
return response.request().method() === "POST" && url.pathname === "/api/invoice-pool/upload" && response.ok();
|
||||
});
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "上传票据" }).click();
|
||||
await page.getByTestId("invoice-upload-file").setInputFiles({
|
||||
name: invoiceFileName,
|
||||
mimeType: "application/pdf",
|
||||
@@ -66,7 +66,7 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
|
||||
// 3) bind invoice to reimbursement
|
||||
await page.goto("/invoice-pool");
|
||||
await expect(page.getByTestId("invoice-pool-table")).toBeVisible();
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "绑定" }).click();
|
||||
await page.getByTestId("invoice-bind-invoice").selectOption(invoiceId);
|
||||
await page.getByTestId("invoice-bind-reimbursement").selectOption(reimbursementId);
|
||||
await page.getByTestId("invoice-bind-submit").click();
|
||||
@@ -111,7 +111,7 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
|
||||
const batchName = `E2E-报销付款批次-${Date.now()}`;
|
||||
await page.goto("/payment-batches");
|
||||
await expect(page.getByTestId("payment-batch-create-panel")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "新建批次" }).click();
|
||||
const createCard = page.getByTestId("payment-batch-create-panel");
|
||||
await expect(createCard).toBeVisible();
|
||||
const createBatchResponsePromise = page.waitForResponse((response) => {
|
||||
|
||||
@@ -153,7 +153,7 @@ async function createAsset(page: Page, categoryName: string, suffix: string, ind
|
||||
};
|
||||
}
|
||||
|
||||
test("ASSET1D 公网资产台账试录:FA/EA-SYS/EA-REPO/EA-BKP", async ({ page }) => {
|
||||
test("ASSET1D 公网资产试录:FA/EA-SYS/EA-REPO/EA-BKP", async ({ page }) => {
|
||||
test.skip(process.env.ASSET1D_PUBLIC_TRIAL !== "1", "ASSET1D public trial requires explicit ASSET1D_PUBLIC_TRIAL=1");
|
||||
const admin = requireAdminUser();
|
||||
const suffix = String(Date.now()).slice(-8);
|
||||
|
||||
@@ -997,7 +997,7 @@ test(`${trialrunIssueId} 浏览器业务先行试运行:报销、审批、请
|
||||
const employee = await loginRole(page, "employee");
|
||||
try {
|
||||
await page.setViewportSize({ width: 1440, height: 960 });
|
||||
await (await openNavLink(page, "采购申请")).click();
|
||||
await (await openNavLink(page, "采购")).click();
|
||||
const createResponsePromise = page.waitForResponse(
|
||||
(response) => response.request().method() === "POST" && new URL(response.url()).pathname === "/api/purchase-requests",
|
||||
);
|
||||
@@ -1168,7 +1168,7 @@ test(`${trialrunIssueId} 浏览器业务先行试运行:报销、审批、请
|
||||
detail: "报销审批已完成;/payment-batches 返回当前功能未启用,未创建付款批次或执行付款。",
|
||||
};
|
||||
}
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "新建批次" }).click();
|
||||
const createCard = page.getByTestId("payment-batch-create-panel");
|
||||
await expect(createCard.getByRole("button", { name: "创建批次" })).toBeEnabled();
|
||||
const createBatchResponsePromise = page.waitForResponse((response) => {
|
||||
|
||||
@@ -80,18 +80,18 @@ const ROLE_ENVS: Record<RoleKey, { identifier: string; password: string }> = {
|
||||
const ROUTE_PLANS: RoutePlan[] = [
|
||||
{ role: "employee", route: "/portal", label: "员工工作台", layer: "A", expectation: "accessible" },
|
||||
{ role: "employee", route: "/reimbursements", label: "员工报销列表", layer: "A", expectation: "accessible" },
|
||||
{ role: "employee", route: "/invoice-pool", label: "员工票据中心", layer: "B", expectation: "accessible" },
|
||||
{ role: "employee", route: "/purchase-requests", label: "员工采购申请", layer: "B", expectation: "accessible" },
|
||||
{ role: "employee", route: "/assets", label: "员工资产台账", layer: "B", expectation: "accessible" },
|
||||
{ role: "employee", route: "/invoice-pool", label: "员工票据", layer: "B", expectation: "accessible" },
|
||||
{ role: "employee", route: "/purchase-requests", label: "员工采购", layer: "B", expectation: "accessible" },
|
||||
{ role: "employee", route: "/assets", label: "员工资产", layer: "B", expectation: "accessible" },
|
||||
{ role: "employee", route: "/payment-batches", label: "员工付款权限负例", layer: "B", expectation: "forbidden_ok" },
|
||||
|
||||
{ role: "manager", route: "/portal", label: "主管工作台", layer: "A", expectation: "accessible" },
|
||||
{ role: "manager", route: "/workflow/tasks", label: "主管审批待办", layer: "A", expectation: "accessible" },
|
||||
{ role: "manager", route: "/purchase-requests", label: "主管采购申请", layer: "B", expectation: "accessible" },
|
||||
{ role: "manager", route: "/purchase-requests", label: "主管采购", layer: "B", expectation: "accessible" },
|
||||
{ role: "manager", route: "/projects", label: "主管项目列表", layer: "B", expectation: "optional" },
|
||||
|
||||
{ role: "finance", route: "/portal", label: "财务工作台", layer: "A", expectation: "accessible" },
|
||||
{ role: "finance", route: "/invoice-pool", label: "财务票据中心", layer: "B", expectation: "accessible" },
|
||||
{ role: "finance", route: "/invoice-pool", label: "财务票据", layer: "B", expectation: "accessible" },
|
||||
{ role: "finance", route: "/payment-batches", label: "财务付款批次", layer: "B", expectation: "accessible" },
|
||||
{ role: "finance", route: "/ap-operations", label: "财务应付账款", layer: "B", expectation: "accessible" },
|
||||
{ role: "finance", route: "/reimbursements", label: "财务报销列表", layer: "A", expectation: "accessible" },
|
||||
@@ -103,8 +103,8 @@ const ROUTE_PLANS: RoutePlan[] = [
|
||||
{ role: "finance_mgr", route: "/audit-logs", label: "财务负责人审计日志", layer: "C", expectation: "accessible" },
|
||||
|
||||
{ role: "admin", route: "/portal", label: "管理员工作台", layer: "A", expectation: "accessible" },
|
||||
{ role: "admin", route: "/assets", label: "管理员资产台账", layer: "B", expectation: "accessible" },
|
||||
{ role: "admin", route: "/contracts-registry", label: "管理员合同台账", layer: "B", expectation: "accessible" },
|
||||
{ role: "admin", route: "/assets", label: "管理员资产", layer: "B", expectation: "accessible" },
|
||||
{ role: "admin", route: "/contracts-registry", label: "管理员合同", layer: "B", expectation: "accessible" },
|
||||
{ role: "admin", route: "/system/workspace", label: "管理员工作区设置", layer: "C", expectation: "accessible" },
|
||||
{ role: "admin", route: "/system/approval-rules", label: "管理员审批规则", layer: "C", expectation: "accessible" },
|
||||
{ role: "admin", route: "/system/feature-flags", label: "管理员功能开关", layer: "C", expectation: "accessible" },
|
||||
|
||||
@@ -276,7 +276,7 @@ const projectDetail = {
|
||||
startsAt: "2026-05-20",
|
||||
targetEndAt: "2026-06-03",
|
||||
actualEndAt: null,
|
||||
summary: "真实试运行阶段,重点验证审批、报销、合同台账和移动入口。",
|
||||
summary: "真实试运行阶段,重点验证审批、报销、合同和移动入口。",
|
||||
isConfidential: true,
|
||||
createdAt: "2026-05-20T09:00:00.000Z",
|
||||
updatedAt: "2026-05-27T09:30:00.000Z",
|
||||
@@ -324,7 +324,7 @@ const projectDetail = {
|
||||
{
|
||||
id: "project-task-wave3",
|
||||
title: "整理试运行反馈",
|
||||
description: "跟进移动端和合同台账反馈",
|
||||
description: "跟进移动端和合同反馈",
|
||||
status: "doing",
|
||||
priority: "high",
|
||||
assigneeEmployeeId: visualMe.id,
|
||||
@@ -1087,7 +1087,7 @@ test("Wave3 PC 详情和通知中心视觉截图", async ({ page }) => {
|
||||
await expect(page.getByRole("heading", { name: "项目", exact: true })).toBeVisible();
|
||||
await expect(page.getByPlaceholder("搜索项目编号、项目名、客户名")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "创建项目" })).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "新建项目" }).click();
|
||||
await expect(page.getByRole("button", { name: "创建项目" })).toBeVisible();
|
||||
|
||||
await page.goto("/projects/project-wave3");
|
||||
@@ -1098,12 +1098,11 @@ test("Wave3 PC 详情和通知中心视觉截图", async ({ page }) => {
|
||||
await page.screenshot({ path: screenshotPath("03-pc-project-detail.png"), fullPage: true });
|
||||
|
||||
await page.goto("/contracts-registry?projectId=project-wave3");
|
||||
await expect(page.getByRole("heading", { name: "合同台账", exact: true })).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "合同", exact: true })).toBeVisible();
|
||||
await expect(page.getByTestId("contracts-registry-table").getByTestId("contracts-registry-row")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "导出 CSV" })).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await expect(page.getByTestId("contracts-ledger-tools")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "导出 CSV" })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "导出" })).toBeVisible();
|
||||
await page.getByRole("button", { name: "筛选" }).click();
|
||||
await expect(page.getByTestId("contracts-advanced-filters")).toBeVisible();
|
||||
await page.getByRole("button", { name: "新增合同" }).click();
|
||||
await expect(page.getByTestId("contracts-editor-panel")).toBeVisible();
|
||||
await page.getByRole("button", { name: "关闭" }).click();
|
||||
|
||||
@@ -1034,32 +1034,31 @@ test("PC 财务与管理页 Wave4-5 视觉冒烟", async ({ page }) => {
|
||||
}
|
||||
});
|
||||
|
||||
test("PC 财务台账工具默认收起并可按需打开", async ({ page }) => {
|
||||
test("PC 财务列表使用明确动作入口", async ({ page }) => {
|
||||
await mockWave4Apis(page);
|
||||
await page.setViewportSize({ width: 1440, height: 960 });
|
||||
await login(page);
|
||||
|
||||
await page.goto("/payment-batches");
|
||||
await expect(page.getByTestId("payment-batch-create-panel")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "新建批次" }).click();
|
||||
await expect(page.getByTestId("payment-batch-create-panel")).toBeVisible();
|
||||
await expect(page.getByTestId("payment-batch-create-panel")).toContainText("新建批次");
|
||||
|
||||
await page.goto("/ap-operations");
|
||||
await expect(page.getByRole("button", { name: "导出 CSV" })).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await expect(page.getByTestId("ap-ledger-tools")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "导出 CSV" })).toBeVisible();
|
||||
await expect(page.getByTestId("ap-export")).toBeVisible();
|
||||
await page.getByTestId("ap-export").click();
|
||||
await expect(page.getByTestId("ap-export-csv")).toBeVisible();
|
||||
|
||||
await page.goto("/invoice-pool");
|
||||
await expect(page.getByTestId("invoice-export")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await expect(page.getByTestId("invoice-ledger-tools")).toBeVisible();
|
||||
await expect(page.getByTestId("invoice-actions-panel")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "绑定" }).click();
|
||||
await expect(page.getByTestId("invoice-actions-panel")).toBeVisible();
|
||||
await page.getByTestId("invoice-export").click();
|
||||
await expect(page.getByTestId("invoice-export-csv")).toBeVisible();
|
||||
});
|
||||
|
||||
test("PC 票据中心辅助核验动作可提交并重试", async ({ page }) => {
|
||||
test("PC 票据辅助核验动作可提交并重试", async ({ page }) => {
|
||||
const failedVerification: MockVerificationRecord = {
|
||||
...(invoiceListItem.verification as MockVerificationRecord),
|
||||
id: "verify-wave4-failed",
|
||||
@@ -1097,7 +1096,7 @@ test("PC 票据中心辅助核验动作可提交并重试", async ({ page }) =>
|
||||
expect(triggerRequests).toEqual(["POST"]);
|
||||
});
|
||||
|
||||
test("PC 票据中心辅助核验错误提示可理解", async ({ page }) => {
|
||||
test("PC 票据辅助核验错误提示可理解", async ({ page }) => {
|
||||
const failedVerification: MockVerificationRecord = {
|
||||
...(invoiceListItem.verification as MockVerificationRecord),
|
||||
id: "verify-wave4-attempts",
|
||||
|
||||
@@ -522,7 +522,7 @@ test.describe("R3 权限直连审计", () => {
|
||||
await expectApiStatus({ role: "employee", api: employee.api, path: "/api/audit-logs", statuses: [403], note: "员工不得查看审计日志" });
|
||||
await expectApiStatus({ role: "employee", api: employee.api, path: "/api/notifications/deliveries", statuses: [403], note: "员工不得查看通知投递审计" });
|
||||
await expectApiMutationStatus({ role: "employee", api: employee.api, path: "/api/exports/ap-operations", method: "post", data: { format: "csv" }, statuses: [403, 409], note: "员工不得导出应付账款数据;409 表示功能门禁关闭且未泄露数据" });
|
||||
await expectApiStatus({ role: "employee", api: employee.api, path: "/api/contracts-registry", statuses: [200, 409], note: "员工合同台账只能走范围过滤或功能门禁" });
|
||||
await expectApiStatus({ role: "employee", api: employee.api, path: "/api/contracts-registry", statuses: [200, 409], note: "员工合同只能走范围过滤或功能门禁" });
|
||||
await expectApiStatus({ role: "employee", api: employee.api, path: "/api/travel-requests?mine=0&pageSize=50", statuses: [403], note: "差旅冻结期员工不得直连差旅列表" });
|
||||
|
||||
const employeeInvoices = await expectApiStatus({
|
||||
|
||||
@@ -32,7 +32,7 @@ test("E2E 采购主链路:员工提单→经理审批→财务归档", async (
|
||||
|
||||
await page.setViewportSize({ width: 1440, height: 960 });
|
||||
await login(page, EMPLOYEE);
|
||||
await (await openNavLink(page, "采购申请")).click();
|
||||
await (await openNavLink(page, "采购")).click();
|
||||
const createResponsePromise = page.waitForResponse(
|
||||
(response) => response.request().method() === "POST" && new URL(response.url()).pathname === "/api/purchase-requests",
|
||||
);
|
||||
@@ -101,7 +101,7 @@ test("E2E 采购主链路:员工提单→经理审批→财务归档", async (
|
||||
await logout(page, MANAGER.name);
|
||||
|
||||
await login(page, FINANCE_MGR);
|
||||
await (await openNavLink(page, "采购申请")).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: requestNo }).first();
|
||||
|
||||
@@ -321,7 +321,6 @@ test.describe("R102 reimbursement main flow", () => {
|
||||
await page.goto("/reimbursements?status=draft");
|
||||
|
||||
await expect(page.getByTestId("reimbursements-tab-draft")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "台账工具" })).toHaveCount(0);
|
||||
await expect(page.getByTestId("reimbursement-row").getByText(formNumber)).toBeVisible();
|
||||
await expect(page.getByText(reimbursementId)).toHaveCount(0);
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ async function mockApis(page: Page) {
|
||||
sections: {
|
||||
main: [
|
||||
navigationItem("portal", "/portal", "工作台", "home_app_logo"),
|
||||
navigationItem("purchase", "/purchase-requests", "采购申请", "shopping_cart"),
|
||||
navigationItem("purchase", "/purchase-requests", "采购", "shopping_cart"),
|
||||
navigationItem("invoice", "/invoice-pool", "票据", "receipt_long"),
|
||||
],
|
||||
admin: [],
|
||||
@@ -346,10 +346,10 @@ test.describe("R103 cross page UI consistency", () => {
|
||||
await page.setViewportSize({ width: 1440, height: 960 });
|
||||
await page.goto("/purchase-requests");
|
||||
|
||||
await expect(page.locator("header").filter({ hasText: "业务" }).getByText("采购申请")).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "采购申请" })).toBeVisible();
|
||||
await expect(page.locator("header").filter({ hasText: "业务" }).getByText("采购")).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "采购" })).toBeVisible();
|
||||
await expect(page.getByTestId("purchase-requests-table")).toBeVisible();
|
||||
await expect(page.getByTestId("purchase-ledger-tools")).toBeVisible();
|
||||
await expect(page.getByTestId("purchase-advanced-filters")).toBeVisible();
|
||||
await expect(page.getByTestId("purchase-attachment-upload")).toHaveCount(0);
|
||||
await expect(page.getByTestId("purchase-row-next-step")).toHaveCount(0);
|
||||
await expect(page.getByText("付款处理")).toHaveCount(0);
|
||||
@@ -357,7 +357,7 @@ test.describe("R103 cross page UI consistency", () => {
|
||||
|
||||
await page.goto(`/purchase-requests?id=${purchaseId}`);
|
||||
await expect(page.getByTestId("purchase-requests-table")).toHaveCount(0);
|
||||
await expect(page.getByTestId("purchase-ledger-tools")).toHaveCount(0);
|
||||
await expect(page.getByTestId("purchase-advanced-filters")).toHaveCount(0);
|
||||
await expect(page.getByTestId("purchase-attachment-upload")).toHaveText("上传附件");
|
||||
await expect(page.getByText("Choose File")).toHaveCount(0);
|
||||
|
||||
@@ -370,13 +370,13 @@ test.describe("R103 cross page UI consistency", () => {
|
||||
await page.screenshot({ path: screenshotPath("purchase-desktop.png"), fullPage: true });
|
||||
});
|
||||
|
||||
test("票据中心绑定报销单不展示 UUID 兜底", async ({ page }) => {
|
||||
test("票据绑定报销单不展示 UUID 兜底", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 1440, height: 960 });
|
||||
await page.goto("/invoice-pool");
|
||||
|
||||
await expect(page.getByRole("heading", { name: "票据中心" })).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "票据" })).toBeVisible();
|
||||
await expect(page.getByTestId("invoice-detail-panel")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "绑定" }).click();
|
||||
await expect(page.getByTestId("invoice-bind-reimbursement")).toContainText("草稿单 · 2026-05-06");
|
||||
await expect(page.getByTestId("invoice-bind-reimbursement")).not.toContainText(reimbursementId);
|
||||
await expect(page.getByText("/invoice-pool")).toHaveCount(0);
|
||||
@@ -387,7 +387,7 @@ test.describe("R103 cross page UI consistency", () => {
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.goto("/invoice-pool");
|
||||
|
||||
await expect(page.getByRole("heading", { name: "票据中心" })).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "票据" })).toBeVisible();
|
||||
await expect(page.getByTestId("invoice-pool-mobile-list")).toBeVisible();
|
||||
await expect(page.getByText("Choose File")).toHaveCount(0);
|
||||
await page.screenshot({ path: screenshotPath("invoice-pool-mobile.png"), fullPage: true });
|
||||
|
||||
@@ -98,7 +98,7 @@ test.describe("R104 public visual acceptance", () => {
|
||||
await page.screenshot({ path: screenshotPath("desktop-reimbursements.png"), fullPage: true });
|
||||
|
||||
await page.goto("/invoice-pool");
|
||||
await expect(page.getByRole("heading", { name: "票据中心", exact: true })).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "票据", exact: true })).toBeVisible();
|
||||
await expectNoDesignRegressionCopy(page);
|
||||
await page.screenshot({ path: screenshotPath("desktop-invoice-pool.png"), fullPage: true });
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ test.describe("R105 pretrial visual acceptance", () => {
|
||||
await page.screenshot({ path: screenshotPath("admin-mobile-approvals.png"), fullPage: true });
|
||||
});
|
||||
|
||||
test("PC Portal、报销和票据中心保持试运行首页一致性", async ({ page }) => {
|
||||
test("PC Portal、报销和票据保持试运行首页一致性", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 1440, height: 960 });
|
||||
await loginLiveUser(page, "employee");
|
||||
|
||||
@@ -130,7 +130,7 @@ test.describe("R105 pretrial visual acceptance", () => {
|
||||
await page.screenshot({ path: screenshotPath("desktop-reimbursements.png"), fullPage: true });
|
||||
|
||||
await page.goto("/invoice-pool");
|
||||
await expect(page.getByRole("heading", { name: "票据中心", exact: true })).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "票据", exact: true })).toBeVisible();
|
||||
await expectNoLegacyDesignCopy(page);
|
||||
await page.screenshot({ path: screenshotPath("desktop-invoice-pool.png"), fullPage: true });
|
||||
});
|
||||
|
||||
@@ -517,18 +517,18 @@ test.describe.serial("R106 自动视觉巡检", () => {
|
||||
await auditPage(desktopPage, { label: "PC 报销详情", route: `/reimbursements/${seedData.reimbursementId}`, screenshotName: "pc-reimbursement-detail" });
|
||||
await compareButtons(desktopPage, "PC 报销详情", "reimbursement-item-edit", "明细编辑", "reimbursement-item-delete", "明细删除");
|
||||
await compareButtons(desktopPage, "PC 报销详情", "reimbursement-back", "返回列表", "reimbursement-delete-draft", "删除草稿");
|
||||
const invoiceMetrics = await auditPage(desktopPage, { label: "PC 票据中心", route: "/invoice-pool", screenshotName: "pc-invoice-pool" });
|
||||
const invoiceMetrics = await auditPage(desktopPage, { label: "PC 票据", route: "/invoice-pool", screenshotName: "pc-invoice-pool" });
|
||||
if (/票据\s*ID/.test(invoiceMetrics.text)) {
|
||||
addFinding({
|
||||
severity: "P2",
|
||||
page: "PC 票据中心",
|
||||
page: "PC 票据",
|
||||
category: "业务展示",
|
||||
title: "票据详情仍把内部票据 ID 放在主信息区",
|
||||
detail: "票据详情存在“票据 ID”字段,应改为票据号码/销售方/金额等业务信息。",
|
||||
evidence: screenshotPath("pc-invoice-pool"),
|
||||
});
|
||||
}
|
||||
await detectDangerButtonStyle(desktopPage, "PC 票据中心", screenshotPath("pc-invoice-pool"));
|
||||
await detectDangerButtonStyle(desktopPage, "PC 票据", screenshotPath("pc-invoice-pool"));
|
||||
await auditPage(desktopPage, { label: "PC 请假", route: "/leave", screenshotName: "pc-leave" });
|
||||
await auditPage(desktopPage, { label: "PC 采购", route: "/purchase-requests", screenshotName: "pc-purchase" });
|
||||
await auditPage(desktopPage, { label: "PC 差旅", route: "/travel-requests", screenshotName: "pc-travel" });
|
||||
|
||||
@@ -313,7 +313,7 @@ test.describe("R92 手机端票据与报销可用性", () => {
|
||||
await attachScreenshot(page, testInfo, "r97-reimbursements-mobile-draft.png");
|
||||
});
|
||||
|
||||
test("票据中心手机视口可批量选择并顺序上传", async ({ page }, testInfo) => {
|
||||
test("票据手机视口可批量选择并顺序上传", async ({ page }, testInfo) => {
|
||||
const uploadCounter = { value: 0 };
|
||||
await mockInvoicePool(page, uploadCounter);
|
||||
await loginThenUseMobileViewport(page);
|
||||
@@ -328,7 +328,7 @@ test.describe("R92 手机端票据与报销可用性", () => {
|
||||
|
||||
await page.goto("/invoice-pool");
|
||||
await expect(page.getByTestId("invoice-mobile-row")).toBeVisible();
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "上传票据" }).click();
|
||||
await page.getByTestId("invoice-upload-file").setInputFiles([
|
||||
{ name: "invoice-a.pdf", mimeType: "application/pdf", buffer: Buffer.from("%PDF-a") },
|
||||
{ name: "invoice-b.pdf", mimeType: "application/pdf", buffer: Buffer.from("%PDF-b") },
|
||||
|
||||
@@ -105,7 +105,7 @@ test("E2E 报销付款批次主链路:提交 -> 审批 -> 创建批次 -> 复
|
||||
await expect(page).toHaveURL(/\/payment-batches/);
|
||||
|
||||
await expect(page.getByTestId("payment-batch-create-panel")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "新建批次" }).click();
|
||||
const createCard = page.getByTestId("payment-batch-create-panel");
|
||||
await expect(createCard).toBeVisible();
|
||||
const createBatchResponsePromise = page.waitForResponse((response) => {
|
||||
|
||||
@@ -59,7 +59,7 @@ test("E2E 差旅支付主链路:申请→审批→支付→绑票", async ({ p
|
||||
const url = new URL(response.url());
|
||||
return response.request().method() === "POST" && url.pathname === "/api/invoice-pool/upload" && response.ok();
|
||||
});
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "上传票据" }).click();
|
||||
await page.getByTestId("invoice-upload-file").setInputFiles({
|
||||
name: invoiceFileName,
|
||||
mimeType: "application/pdf",
|
||||
@@ -79,7 +79,7 @@ test("E2E 差旅支付主链路:申请→审批→支付→绑票", async ({ p
|
||||
|
||||
await page.goto("/invoice-pool");
|
||||
await expect(page.getByTestId("invoice-pool-table")).toBeVisible();
|
||||
await page.getByRole("button", { name: "台账工具" }).click();
|
||||
await page.getByRole("button", { name: "绑定" }).click();
|
||||
const bindCard = page.locator(".card-std").filter({ hasText: "绑定业务单据" }).first();
|
||||
await bindCard.getByRole("combobox").first().selectOption("travelOrder");
|
||||
await page.getByTestId("invoice-bind-invoice").selectOption(invoiceId);
|
||||
|
||||
@@ -119,8 +119,8 @@ async function mockVisualApis(page: Page) {
|
||||
navigationItem("portal", "/portal", "工作台", "home_app_logo"),
|
||||
navigationItem("approvals", "/workflow/tasks", "待我处理", "fact_check"),
|
||||
navigationItem("reimbursements", "/reimbursements", "报销", "request_quote"),
|
||||
navigationItem("purchase", "/purchase-requests", "采购申请", "shopping_cart"),
|
||||
navigationItem("contracts", "/contracts-registry", "合同台账", "description"),
|
||||
navigationItem("purchase", "/purchase-requests", "采购", "shopping_cart"),
|
||||
navigationItem("contracts", "/contracts-registry", "合同", "description"),
|
||||
navigationItem("projects", "/projects", "项目", "workspaces"),
|
||||
navigationItem("assets", "/assets", "资产", "inventory_2"),
|
||||
],
|
||||
@@ -367,8 +367,8 @@ test.describe("visual shell", () => {
|
||||
await expect(page.locator("aside")).toBeVisible();
|
||||
await expect(page.getByTestId("topbar-profile-trigger")).toBeVisible();
|
||||
await expect(page.locator("aside").getByRole("link", { name: "工作台", exact: true })).toBeVisible();
|
||||
await expect(page.locator("aside").getByRole("link", { name: "采购申请" })).toBeVisible();
|
||||
await expect(page.locator("aside").getByRole("link", { name: "合同台账" })).toBeVisible();
|
||||
await expect(page.locator("aside").getByRole("link", { name: "采购" })).toBeVisible();
|
||||
await expect(page.locator("aside").getByRole("link", { name: "合同" })).toBeVisible();
|
||||
await expect(page.locator("aside").getByRole("link", { name: "项目" })).toBeVisible();
|
||||
await expect(page.locator("aside").getByRole("link", { name: "资产" })).toBeVisible();
|
||||
await expect(page.locator("summary").filter({ hasText: "更多" })).toBeVisible();
|
||||
@@ -390,7 +390,6 @@ test.describe("visual shell", () => {
|
||||
await page.goto("/reimbursements");
|
||||
await expect(page.getByRole("heading", { name: "我的报销" })).toBeVisible();
|
||||
await expect(page.getByTestId("reimbursements-create")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "台账工具" })).toHaveCount(0);
|
||||
await expect(page.getByTestId("reimbursements-export")).toBeVisible();
|
||||
await expect(page.getByTestId("reimbursements-status-tabs")).toBeVisible();
|
||||
await expect(page.getByTestId("reimbursements-table")).toBeVisible();
|
||||
|
||||
在新工单中引用
屏蔽一个用户