R31-1 R31-4: 收口详情页工作台化与 E2E 契约

这个提交包含在:
2026-03-24 08:58:36 +08:00
父节点 994d98e74c
当前提交 279be83931
共修改 17 个文件,包含 906 行新增和 455 行删除
+33 -32
查看文件
@@ -1,8 +1,8 @@
import { expect, test, type Locator, type Page } from "@playwright/test";
import { test, expect } from "./helpers/fixtures";
import { EMPLOYEE, MANAGER, apiPostData, createAuthenticatedApiClient, login, logout } from "./helpers/auth";
import { openNavLink } from "./helpers/navigation";
import { TEST_IDS } from "./helpers/testIds";
import type { Locator, Page } from "@playwright/test";
function formatDate(offsetDays: number) {
const value = new Date();
@@ -69,7 +69,7 @@ async function withdrawLeave(api: Awaited<ReturnType<typeof createAuthenticatedA
return apiPostData<{ leaveRequestId: string; leaveStatus: string }>(api, `/api/leave-requests/${leaveRequestId}/withdraw`, {});
}
test("E2E 请假主链路:草稿 → 提交 → 撤回 + 提交 → 审批", async ({ page }) => {
test("E2E 请假主链路:草稿 → 提交 → 撤回 + 提交 → 审批", async ({ page, workflowDetail }) => {
const employeeClient = await createAuthenticatedApiClient(EMPLOYEE);
const baseOffset = 30 + Number(String(Date.now()).slice(-2));
const firstDate = formatDate(baseOffset);
@@ -77,42 +77,43 @@ test("E2E 请假主链路:草稿 → 提交 → 撤回 + 提交 → 审批", a
try {
await login(page, EMPLOYEE);
await (await openNavLink(page, "请假")).click();
await expect(page.getByRole("heading", { name: "请假申请" })).toBeVisible();
await (await openNavLink(page, "请假")).click();
await expect(page.getByRole("heading", { name: "请假申请" })).toBeVisible();
const firstLeaveId = await createLeaveDraft(page, firstDate, firstDate, `Playwright 撤回请假 ${Date.now()}`);
await submitLeave(employeeClient.api, firstLeaveId);
await page.goto("/leave-requests");
const firstRow = page.getByRole("row").filter({ hasText: firstDate }).first();
await expect(firstRow).toContainText("审批中", { timeout: 30_000 });
const firstLeaveId = await createLeaveDraft(page, firstDate, firstDate, `Playwright 撤回请假 ${Date.now()}`);
await submitLeave(employeeClient.api, firstLeaveId);
await page.goto("/leave-requests");
const firstRow = page.getByRole("row").filter({ hasText: firstDate }).first();
await expect(firstRow).toContainText("审批中", { timeout: 30_000 });
await withdrawLeave(employeeClient.api, firstLeaveId);
await page.goto("/leave-requests");
await expect(firstRow).toContainText("草稿", { timeout: 30_000 });
await withdrawLeave(employeeClient.api, firstLeaveId);
await page.goto("/leave-requests");
await expect(firstRow).toContainText("草稿", { timeout: 30_000 });
const secondLeaveId = await createLeaveDraft(page, secondDate, secondDate, `Playwright 审批请假 ${Date.now()}`);
const secondSubmit = await submitLeave(employeeClient.api, secondLeaveId);
await page.goto("/leave-requests");
const secondRow = page.getByRole("row").filter({ hasText: secondDate }).first();
await expect(secondRow).toContainText("审批中", { timeout: 30_000 });
const secondLeaveId = await createLeaveDraft(page, secondDate, secondDate, `Playwright 审批请假 ${Date.now()}`);
const secondSubmit = await submitLeave(employeeClient.api, secondLeaveId);
await page.goto("/leave-requests");
const secondRow = page.getByRole("row").filter({ hasText: secondDate }).first();
await expect(secondRow).toContainText("审批中", { timeout: 30_000 });
await logout(page, EMPLOYEE.name);
await logout(page, EMPLOYEE.name);
await login(page, MANAGER);
await (await openNavLink(page, "待我处理")).click();
await expect(page.getByTestId(TEST_IDS.workflow.tasksTable)).toBeVisible();
const taskRow = page.getByTestId(TEST_IDS.workflow.taskRow).filter({ hasText: secondSubmit.currentTaskId }).first();
await expect(taskRow).toBeVisible({ timeout: 30_000 });
await taskRow.getByTestId(TEST_IDS.workflow.detailLink).click();
await page.getByTestId(TEST_IDS.workflow.approve).click();
await expect(page.getByTestId(TEST_IDS.workflow.summary)).toContainText(/状态:(completed|已完成)/);
await login(page, MANAGER);
await (await openNavLink(page, "待我处理")).click();
await expect(page.getByTestId(TEST_IDS.workflow.tasksTable)).toBeVisible();
const taskRow = page.getByTestId(TEST_IDS.workflow.taskRow).filter({ hasText: secondSubmit.currentTaskId }).first();
await expect(taskRow).toBeVisible({ timeout: 30_000 });
await taskRow.getByTestId(TEST_IDS.workflow.detailLink).click();
await workflowDetail.assertLoaded();
await workflowDetail.approve();
await expect(workflowDetail.summary).toContainText(/状态:(completed|已完成)/);
await logout(page, MANAGER.name);
await logout(page, MANAGER.name);
await login(page, EMPLOYEE);
await page.goto("/leave-requests");
await expect(page.getByRole("row").filter({ hasText: secondDate }).first()).toContainText("已通过", { timeout: 30_000 });
await expect(page.getByRole("row").filter({ hasText: firstDate }).first()).toContainText("草稿", { timeout: 30_000 });
await login(page, EMPLOYEE);
await page.goto("/leave-requests");
await expect(page.getByRole("row").filter({ hasText: secondDate }).first()).toContainText("已通过", { timeout: 30_000 });
await expect(page.getByRole("row").filter({ hasText: firstDate }).first()).toContainText("草稿", { timeout: 30_000 });
} finally {
await employeeClient.dispose();
}