文件
hyb-oa/client/tests/e2e/travel-freeze-protection.spec.ts
T
wangsli 1f8d5b658a 完善借款、编号、付款与预算并发及验收(09-06-release-gate-integrity)
汇总已落盘的借款本金与还款、兼容历史编号的周期化编号、付款责任与回单核验、报销进度和排序、PWA/采购事务、错误原因与日期校验及ERP退役。
统一共享预算池锁序和锁后判断,恢复差旅原预算选择,补原因码固定夹具及反向完整性检查。
纳入配套迁移、测试、受管QA、分层验收合同、规约及任务记录;原始证据留在ignored artifacts。

关联任务:09-17-company-loan-principal-repayment、09-17-erp-exclusive-retirement、09-18-reimbursement-periodic-numbering、09-08-reimbursement-payment-closeout、09-18-local-concurrency-product-fixes、09-19-budget-pool-concurrency、09-05-error-explainability-payment-readiness。
预算补审由Claude定向验证2文件928项通过,原4446/28及r6结果仍仅对应各自历史输入;本轮未重跑测试。
完整新候选门禁、R1真实入口接入与12项公网义务仍开放。生产编号未启用、差旅仍冻结;不推送、不部署,不宣称发布资格。
2026-09-19 13:11:04 +08:00

46 行
2.2 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { createAuthenticatedApiClient, EMPLOYEE, FINANCE, FINANCE_MGR, login } from "./helpers/auth";
// Original travel chains remain byte-for-byte in their specs, owned by G19's
// frozen obligations. These assertions exercise the current retained boundary.
test("冻结差旅:员工入口与共享付款边界", async ({ page }) => {
const employee = await createAuthenticatedApiClient(EMPLOYEE);
const finance = await createAuthenticatedApiClient(FINANCE_MGR);
try {
expect(employee.me.roleCodes).toContain("employee");
const denied = await employee.api.post("/api/travel-requests", { data: {} });
expect(denied.status()).toBe(403);
await login(page, EMPLOYEE);
await page.goto("/portal");
await expect(page.getByTestId("portal-work-summary")).toBeVisible();
await expect(page.getByRole("link", { name: "差旅申请", exact: true })).toHaveCount(0);
const readiness = await finance.api.post("/api/payment-batches/readiness", {
data: { entityType: "travel_order", entityIds: ["ffffffff-ffff-4fff-8fff-ffffffffffff"], defaultPaymentChannel: "bank" },
});
expect(readiness.status()).toBe(200);
const payload = await readiness.json();
expect(payload.data.ready).toBe(false);
expect(payload.data.blockers).toContainEqual(expect.objectContaining({ reasonCode: "payment_batch.travel_payment_frozen" }));
} finally {
await employee.dispose();
await finance.dispose();
}
});
test("冻结差旅:财务对账权限与入站导入权限边界", async ({ page }) => {
const finance = await createAuthenticatedApiClient(FINANCE);
try {
expect(finance.me.roleCodes).toContain("finance");
for (const endpoint of ["/api/travel/reconciliation/batches", "/api/travel/orders/import", "/api/travel/transactions/import", "/api/travel/authorizations/import"]) {
const denied = await finance.api.post(endpoint, { data: {} });
expect(denied.status(), endpoint).toBe(403);
}
await login(page, FINANCE);
await page.goto("/portal");
await expect(page.getByTestId("portal-work-summary")).toBeVisible();
await expect(page.getByRole("link", { name: "差旅申请", exact: true })).toHaveCount(0);
} finally {
await finance.dispose();
}
});