文件
hyb-oa/client/tests/e2e/travel-payment-flow.spec.ts
T

101 行
5.0 KiB
TypeScript
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
import { expect, test } from "@playwright/test";
import { createAuthenticatedApiClient, EMPLOYEE, FINANCE_MGR, login, logout, MANAGER } from "./helpers/auth";
import { createAndSubmitTravelRequestViaUi, importTravelPaymentSeed } from "./helpers/travel";
function extractId(text: string, label: string) {
const match = text.match(new RegExp(`${label}:([0-9a-f-]{36})`));
if (!match?.[1]) {
throw new Error(`Failed to parse ${label} from text: ${text}`);
}
return match[1];
}
function extractInvoiceCode(text: string) {
const match = text.match(/发票号:([A-Z0-9]+)-/);
if (!match?.[1]) {
throw new Error(`Failed to parse invoice code from text: ${text}`);
}
return match[1];
}
test("E2E 差旅支付主链路:申请→审批→支付→绑票", async ({ page }) => {
const employeeApi = await createAuthenticatedApiClient(EMPLOYEE);
const financeMgrApi = await createAuthenticatedApiClient(FINANCE_MGR);
try {
await login(page, EMPLOYEE);
const draft = await createAndSubmitTravelRequestViaUi(page, {
purposePrefix: "Playwright差旅支付",
amount: "1888.00",
});
await logout(page, EMPLOYEE.name);
await login(page, MANAGER);
await page.goto("/workflow/tasks?status=pending&page=1");
const taskRow = page.getByTestId("workflow-task-row").filter({ hasText: draft.requestId }).first();
await expect(taskRow).toBeVisible({ timeout: 30_000 });
await taskRow.getByTestId("workflow-task-detail-link").click();
await page.getByTestId("workflow-task-approve").click();
await expect(page.getByTestId("workflow-task-summary")).toContainText("状态:");
await expect(page.getByTestId("workflow-task-summary")).toContainText("已完成");
await logout(page, MANAGER.name);
const paymentSeed = await importTravelPaymentSeed(financeMgrApi.api, {
requestId: draft.requestId,
employeeId: employeeApi.me.id,
amount: "1888.00",
occurredAtDate: draft.startDate,
});
await login(page, FINANCE_MGR);
await page.goto(`/travel-requests?tab=requests&id=${draft.requestId}`);
const orderCard = page.locator(".rounded-xl.border.border-zinc-200").filter({ hasText: paymentSeed.orderNo }).last();
await expect(orderCard).toBeVisible({ timeout: 30_000 });
await expect(orderCard).toContainText("已匹配交易");
await orderCard.getByRole("button", { name: "标记已支付" }).click();
await page.locator("#travel-order-payment-voucher").fill(`BANK-${Date.now()}`);
await page.locator("#travel-order-payment-date").fill(draft.startDate);
await page.getByRole("button", { name: "确认已支付" }).click();
await expect(orderCard).toContainText("已支付", { timeout: 30_000 });
await expect(orderCard).not.toContainText("标记已支付");
await page.goto("/invoice-pool");
const invoiceFileName = `travel-payment-${Date.now()}.png`;
await page.getByTestId("invoice-upload-file").setInputFiles({
name: invoiceFileName,
mimeType: "image/png",
buffer: Buffer.from(`TRAVEL_PAYMENT_${Date.now()}`, "utf8"),
});
await page.getByTestId("invoice-upload-submit").click();
await expect(page.getByTestId("invoice-detail-panel")).toBeVisible();
await expect(page.getByTestId("invoice-detail-panel")).toContainText("状态:available", { timeout: 90_000 });
const invoiceDetailText = await page.getByTestId("invoice-detail-panel").innerText();
const invoiceId = extractId(invoiceDetailText, "票据ID");
const invoiceCode = extractInvoiceCode(invoiceDetailText);
await page.reload();
await expect(page.getByTestId("invoice-pool-table")).toBeVisible();
const bindCard = page.locator(".card-std").filter({ hasText: "绑定业务单据" }).first();
await bindCard.getByRole("combobox").first().selectOption("travelOrder");
await page.getByTestId("invoice-bind-invoice").selectOption(invoiceId);
await page.getByTestId("invoice-bind-travel-request").selectOption(draft.requestId);
await page.getByTestId("invoice-bind-travel-order").selectOption(paymentSeed.orderId);
const bindResponsePromise = page.waitForResponse((response) => response.url().includes(`/api/invoice-pool/${invoiceId}/bind`) && response.request().method() === "POST");
await page.getByTestId("invoice-bind-submit").click();
const bindResponse = await bindResponsePromise;
expect(bindResponse.ok()).toBeTruthy();
await expect(page.getByText("绑定成功")).toBeVisible({ timeout: 30_000 });
await page.goto(`/travel-requests?tab=requests&id=${draft.requestId}`);
const paidOrderCard = page.locator(".rounded-xl.border.border-zinc-200").filter({ hasText: paymentSeed.orderNo }).last();
await expect(paidOrderCard).toContainText("已支付");
await expect(paidOrderCard).not.toContainText("当前没有已绑定发票。", { timeout: 30_000 });
await expect(paidOrderCard).toContainText(invoiceCode);
await expect(paidOrderCard).toContainText("ERP 状态:");
await logout(page, FINANCE_MGR.name);
} finally {
await Promise.all([employeeApi.dispose(), financeMgrApi.dispose()]);
}
});