fix: 财务本人报销由总经理独立审批(09-04-reimbursement-state-gap-finance-view)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-09-12 20:03:29 +08:00
父节点 31ab9fbb2b
当前提交 229867f5fd
共修改 18 个文件,包含 629 行新增和 20 行删除
+225 -7
查看文件
@@ -13,6 +13,9 @@ const docker = (args, input) => execFileSync("docker", args, { input, encoding:
async function main() {
assert.equal(process.env.RUN_ISOLATED_DB_TEST, "1", "Explicit disposable database opt-in required");
const managerIsCeo = process.env.RUN_MANAGER_IS_CEO_TEST === "1";
const ownerApprovalTest = process.env.RUN_OWNER_APPROVAL_TEST === "1";
assert.ok(!ownerApprovalTest || managerIsCeo, "Owner approval checks require the small-team fixture");
const password = randomUUID();
let container;
let prisma;
@@ -22,6 +25,7 @@ async function main() {
let browser;
let preview;
const passed = [];
const businessBlockers = [];
try {
container = docker(["run", "-d", "--rm", "--pull=never", "--tmpfs", "/var/lib/postgresql/data", "-p", "127.0.0.1::5432", "-e", `POSTGRES_PASSWORD=${password}`, "postgres:16-alpine"]);
let ready = false;
@@ -45,13 +49,12 @@ async function main() {
bank_account_encrypted: "synthetic-not-account", bank_name: "synthetic", password_hash: "not-a-login-hash",
} });
const expenseType = await prisma.expenseType.create({ data: { code: "synthetic_http", name: "synthetic", category: "office", sort_order: 1 } });
const manager = await prisma.employee.create({ data: {
let manager = managerIsCeo ? null : await prisma.employee.create({ data: {
name: "synthetic-manager", email: "[email protected]", employee_no: "synthetic-manager",
department_id: department.id, title: "synthetic", hire_date: new Date("2026-09-09"),
bank_account_encrypted: "synthetic-not-account", bank_name: "synthetic", password_hash: "not-a-login-hash",
} });
await prisma.employee.update({ where: { id: employee.id }, data: { direct_manager_id: manager.id } });
const approvers = { manager };
const approvers = manager ? { manager } : {};
for (const role of ["ceo", "finance"]) {
approvers[role] = await prisma.employee.create({ data: {
name: `synthetic-${role}`, email: `invoice-${role}@example.invalid`, employee_no: `synthetic-${role}`,
@@ -62,12 +65,24 @@ async function main() {
for (const [role, actor] of Object.entries(approvers)) {
await prisma.employeeRole.create({ data: { employee_id: actor.id, role_code: role } });
}
if (managerIsCeo) {
manager = approvers.ceo;
approvers.manager = manager;
for (const actor of [approvers.ceo, approvers.finance]) {
await prisma.employeeRole.create({ data: { employee_id: actor.id, role_code: "employee" } });
}
await prisma.employee.update({ where: { id: approvers.finance.id }, data: { direct_manager_id: manager.id } });
assert.equal(await prisma.employeeRole.count({ where: { role_code: "manager" } }), 0);
assert.equal(await prisma.employee.count(), 3);
passed.push("small team: employee and finance report to the same CEO; no manager role or separate manager account");
}
await prisma.employee.update({ where: { id: employee.id }, data: { direct_manager_id: manager.id } });
await prisma.employeeRole.create({ data: { employee_id: employee.id, role_code: "employee" } });
const loginPassword = `Synthetic!${randomUUID()}`;
const passwordHash = await serverRequire("./src/utils/crypto").hashPassword(loginPassword);
await prisma.employee.updateMany({ data: { password_hash: passwordHash, must_change_password: false } });
await prisma.workflowDefinition.create({ data: { name: "synthetic-reimbursement", entity_type: "reimbursement", definition_json: { steps: [] }, version: 1 } });
await prisma.approvalRule.create({ data: { name: "synthetic-three-step", min_amount: 0, level1_role: "manager", level2_role: "ceo", level3_role: "finance", priority: 1 } });
const approvalRule = await prisma.approvalRule.create({ data: { name: "synthetic-three-step", min_amount: 0, level1_role: "manager", level2_role: "ceo", level3_role: "finance", priority: 1 } });
await prisma.featureFlag.create({ data: { flag_key: "reimbursement_invoice_guard_v1", override_mode: "force_on", rollout_type: "global", department_ids: [] } });
const makeForm = () => prisma.reimbursementForm.create({ data: { form_number: `SYN-${randomUUID()}`, owner_id: employee.id, submitter_id: employee.id, department_id: department.id, reimbursement_date: new Date("2026-09-09") } });
const makeInvoice = (overrides = {}) => prisma.invoicePool.create({ data: {
@@ -110,7 +125,7 @@ async function main() {
}
const origin = await app.listen({ host: "127.0.0.1", port: 0 });
const tokens = new Map();
for (const actor of [employee, ...Object.values(approvers)]) {
for (const actor of new Map([employee, ...Object.values(approvers)].map((actor) => [actor.id, actor])).values()) {
const login = await fetch(`${origin}/api/auth/login`, { method: "POST", headers: { "content-type": "application/json", "x-device-fingerprint": `synthetic-${actor.id}` }, body: JSON.stringify({ identifier: actor.email, password: loginPassword }) });
assert.equal(login.status, 200, "password login");
tokens.set(actor.id, (await login.json()).data.accessToken);
@@ -371,6 +386,7 @@ async function main() {
assert.equal(resubmit.status, 200);
const newWorkflowId = resubmit.body.data.workflowInstanceId;
assert.notEqual(newWorkflowId, workflow.id);
const approvalActors = [];
for (const role of ["manager", "ceo", "finance"]) {
const task = await prisma.workflowTask.findFirst({ where: { instance_id: newWorkflowId, status: "pending" } });
assert.ok(task, `pending task for ${role}`);
@@ -410,12 +426,17 @@ async function main() {
}
const approval = await post(`/workflow/tasks/${task.id}/approve`, {}, approvers[role].id);
assert.equal(approval.status, 200, `${role} approval: ${approval.status} ${approval.body.error?.code ?? ""}`);
approvalActors.push(approvers[role].id);
assert.equal((await post(`/workflow/tasks/${task.id}/approve`, {}, approvers[role].id)).status, 409);
}
assert.equal((await prisma.reimbursementForm.findUnique({ where: { id: form.id } })).status, "approved");
assert.equal(await prisma.workflowTask.count({ where: { instance_id: newWorkflowId, status: "pending" } }), 0);
assert.equal((await prisma.workflowInstance.findUnique({ where: { id: newWorkflowId } })).current_status, "approved");
passed.push("owner cannot self-approve; return/edit/resubmit and manager/ceo/finance approval complete without payment");
if (managerIsCeo) {
assert.deepEqual(approvalActors, [approvers.ceo.id, approvers.ceo.id, approvers.finance.id]);
passed.push("small team: same CEO completes separate manager and CEO steps; no automatic person-level deduplication");
}
if (process.env.RUN_PAYMENT_EXPERIENCE_TEST === "1") {
await require("./test-payment-experience.cjs")({ app, prisma, employee, approvers, form, post, origin, tokens, serverRequire, passed, browser, preview, loginPassword, handoffCheck });
}
@@ -496,10 +517,207 @@ async function main() {
root, browser, preview, loginPassword,
});
}
if (ownerApprovalTest) {
await prisma.approvalRule.update({ where: { id: approvalRule.id }, data: { owner_self_fallback_role: "finance" } });
const prepareOwnerForm = async (owner) => {
const ownedForm = await makeForm();
const ownedInvoice = await makeInvoice();
assert.equal((await bind(ownedInvoice, ownedForm)).status, 200);
const item = await prisma.reimbursementItem.findFirst({ where: { reimbursement_id: ownedForm.id } });
await prisma.reimbursementItem.update({ where: { id: item.id }, data: { expense_type_id: expenseType.id, description: "synthetic owner approval" } });
await prisma.invoicePool.update({ where: { id: ownedInvoice.id }, data: { owner_employee_id: owner.id, uploaded_by_employee_id: owner.id } });
await prisma.reimbursementForm.update({ where: { id: ownedForm.id }, data: { owner_id: owner.id, submitter_id: owner.id } });
return ownedForm;
};
const ceoForm = await prepareOwnerForm(approvers.ceo);
const ceoSubmitted = await post(`/reimbursements/${ceoForm.id}/submit`, {}, approvers.ceo.id);
assert.equal(ceoSubmitted.status, 200, "CEO owner submits with explicit finance fallback");
const instanceId = ceoSubmitted.body.data.workflowInstanceId;
const tasks = await prisma.workflowTask.findMany({ where: { instance_id: instanceId } });
assert.equal(tasks.length, 1, "CEO own chain collapses to one finance step");
assert.equal(tasks[0].assignee_role, "finance");
assert.equal((await post(`/workflow/tasks/${tasks[0].id}/approve`, {}, approvers.ceo.id)).status, 403);
assert.equal((await post(`/workflow/tasks/${tasks[0].id}/approve`, {}, approvers.finance.id)).status, 200);
assert.equal((await prisma.reimbursementForm.findUnique({ where: { id: ceoForm.id } })).status, "approved");
passed.push("CEO owner with finance fallback: exactly one finance task, owner rejected, finance approves");
const financeForm = await prepareOwnerForm(approvers.finance);
const financeSubmitted = await post(`/reimbursements/${financeForm.id}/submit`, {}, approvers.finance.id);
assert.equal(financeSubmitted.status, 200, "finance owner submits for one CEO approval");
const originalFinanceInstanceId = financeSubmitted.body.data.workflowInstanceId;
const returnedTask = await prisma.workflowTask.findFirst({ where: { instance_id: originalFinanceInstanceId, status: "pending" } });
assert.equal(returnedTask.assignee_role, "ceo");
assert.equal((await post(`/workflow/tasks/${returnedTask.id}/return`, { comment: "synthetic finance correction" }, approvers.ceo.id)).status, 200);
const financeResubmitted = await post(`/reimbursements/${financeForm.id}/submit`, {}, approvers.finance.id);
assert.equal(financeResubmitted.status, 200);
const financeInstanceId = financeResubmitted.body.data.workflowInstanceId;
assert.notEqual(financeInstanceId, originalFinanceInstanceId);
assert.equal(await prisma.workflowTask.count({ where: { instance_id: originalFinanceInstanceId } }), 1);
const selfTask = await prisma.workflowTask.findFirst({ where: { instance_id: financeInstanceId, status: "pending" } });
assert.ok(selfTask);
assert.equal(selfTask.assignee_role, "ceo");
assert.equal(await prisma.workflowTask.count({ where: { instance_id: financeInstanceId } }), 1);
const selfApproval = await post(`/workflow/tasks/${selfTask.id}/approve`, {}, approvers.finance.id);
assert.equal(selfApproval.status, 403);
assert.equal((await post(`/workflow/tasks/${selfTask.id}/approve`, {}, approvers.ceo.id)).status, 200);
assert.equal((await post(`/workflow/tasks/${selfTask.id}/approve`, {}, approvers.ceo.id)).status, 409);
assert.equal(await prisma.workflowTask.count({ where: { instance_id: financeInstanceId, status: "pending" } }), 0);
assert.equal((await prisma.reimbursementForm.findUnique({ where: { id: financeForm.id } })).status, "approved");
passed.push("finance owner: return/resubmit preserves history; one CEO approval completes reimbursement, owner denied, replay denied, no finance task");
if (process.env.RUN_PAYMENT_EXPERIENCE_TEST === "1") {
await require("./test-payment-experience.cjs")({
app, prisma, employee, approvers, form: financeForm, payee: approvers.finance,
fixtureCode: "SYN-PAY-FINANCE", post, origin, tokens, serverRequire, passed,
browser, preview, loginPassword, handoffCheck,
});
passed.push("finance owner payment: finance creates own batch, cannot review, CEO separately reviews, synthetic export/receipt only");
}
for (const unavailable of ["inactive", "archived", "submitter", "missing_role"]) {
const blockedForm = await prepareOwnerForm(approvers.finance);
try {
if (unavailable === "inactive") await prisma.employee.update({ where: { id: approvers.ceo.id }, data: { status: "archived" } });
if (unavailable === "archived") await prisma.employee.update({ where: { id: approvers.ceo.id }, data: { archived_at: new Date() } });
if (unavailable === "submitter") await prisma.reimbursementForm.update({ where: { id: blockedForm.id }, data: { submitter_id: approvers.ceo.id } });
if (unavailable === "missing_role") await prisma.employeeRole.deleteMany({ where: { employee_id: approvers.ceo.id, role_code: "ceo" } });
for (const budgetEnabled of [false, true]) {
await prisma.featureFlag.upsert({
where: { flag_key: "budget_precheck_v1" },
create: { flag_key: "budget_precheck_v1", override_mode: budgetEnabled ? "force_on" : "force_off", rollout_type: "global", department_ids: [] },
update: { override_mode: budgetEnabled ? "force_on" : "force_off" },
});
const precheck = await post(`/reimbursements/${blockedForm.id}/precheck`, {}, approvers.finance.id);
assert.equal(precheck.status, 200);
assert.equal(precheck.body.data.decision, "block");
assert.ok(precheck.body.data.blockingReasons.some((reason) => reason.code === "finance_owner_ceo_unavailable"));
assert.equal((await post(`/reimbursements/${blockedForm.id}/submit`, {}, approvers.finance.id)).status, 409);
assert.equal(await prisma.workflowInstance.count({ where: { reimbursement_id: blockedForm.id } }), 0);
assert.equal((await prisma.reimbursementForm.findUnique({ where: { id: blockedForm.id } })).status, "draft");
}
} finally {
await prisma.employee.update({ where: { id: approvers.ceo.id }, data: { status: "active", archived_at: null } });
if (unavailable === "missing_role") await prisma.employeeRole.create({ data: { employee_id: approvers.ceo.id, role_code: "ceo" } });
await prisma.featureFlag.update({ where: { flag_key: "budget_precheck_v1" }, data: { override_mode: "force_off" } });
}
}
passed.push("finance owner: inactive/archived/submitter/missing-role CEO blocks precheck and submission without pending workflow");
for (const additionalRole of ["second_finance", "owner_ceo"]) {
const actorId = additionalRole === "second_finance" ? employee.id : approvers.finance.id;
const roleCode = additionalRole === "second_finance" ? "finance" : "ceo";
await prisma.employeeRole.create({ data: { employee_id: actorId, role_code: roleCode } });
try {
const extraForm = await prepareOwnerForm(approvers.finance);
const submitted = await post(`/reimbursements/${extraForm.id}/submit`, {}, approvers.finance.id);
assert.equal(submitted.status, 200);
const extraTasks = await prisma.workflowTask.findMany({ where: { instance_id: submitted.body.data.workflowInstanceId } });
assert.equal(extraTasks.length, 1);
assert.equal(extraTasks[0].assignee_role, "ceo");
if (additionalRole === "owner_ceo") {
const denied = await post(`/workflow/tasks/${extraTasks[0].id}/approve`, {}, approvers.finance.id);
assert.equal(denied.status, 409);
assert.equal(denied.body.error.details.workflow, "self_approval_not_allowed");
} else {
assert.equal((await post(`/workflow/tasks/${extraTasks[0].id}/approve`, {}, employee.id)).status, 403);
}
assert.equal((await post(`/workflow/tasks/${extraTasks[0].id}/approve`, {}, approvers.ceo.id)).status, 200);
assert.equal((await prisma.reimbursementForm.findUnique({ where: { id: extraForm.id } })).status, "approved");
} finally {
await prisma.employeeRole.deleteMany({ where: { employee_id: actorId, role_code: roleCode } });
}
}
passed.push("finance owner: second finance does not change CEO-only rule; finance+CEO applicant still denied self-approval");
if (browser && preview) {
const { expect } = createRequire(path.join(root, "client/package.json"))("@playwright/test");
const uiOrigin = `http://127.0.0.1:${preview.httpServer.address().port}`;
for (const mobile of [false, true]) {
const browserForm = await prepareOwnerForm(approvers.finance);
for (const actor of [approvers.finance, approvers.ceo]) {
const context = await browser.newContext({ serviceWorkers: "block", viewport: mobile ? { width: 390, height: 844 } : { width: 1440, height: 960 } });
try {
const fingerprint = `synthetic-owner-${mobile}-${actor.id}`;
await context.addCookies([{ name: "hyb_oa_device_fingerprint", value: fingerprint, url: uiOrigin }]);
const login = await context.request.post(`${uiOrigin}/api/auth/login`, {
headers: { "x-device-fingerprint": fingerprint },
data: { identifier: actor.email, password: loginPassword },
});
assert.equal(login.status(), 200);
const page = await context.newPage();
if (actor.id === approvers.finance.id) {
await page.goto(`${uiOrigin}${mobile ? "/mobile" : ""}/reimbursements/${browserForm.id}`);
const response = page.waitForResponse((result) => result.url().endsWith(`/reimbursements/${browserForm.id}/submit`) && result.request().method() === "POST");
const precheckResponse = page.waitForResponse((result) => result.url().endsWith(`/reimbursements/${browserForm.id}/precheck`) && result.request().method() === "POST");
await page.getByTestId("reimbursement-submit").click();
const precheck = await (await precheckResponse).json();
assert.notEqual(precheck.data.decision, "block");
if (precheck.data.decision !== "pass") {
const confirm = page.getByRole("button", { name: "确认提交", exact: true });
await expect(confirm).toBeVisible();
await confirm.click();
}
assert.equal((await response).status(), 200);
} else {
const workflow = await prisma.workflowInstance.findFirst({ where: { reimbursement_id: browserForm.id, current_status: "pending" } });
const task = await prisma.workflowTask.findFirst({ where: { instance_id: workflow.id, status: "pending" } });
assert.equal(task.assignee_role, "ceo");
await page.goto(`${uiOrigin}${mobile ? "/mobile/approvals" : "/workflow/tasks"}/${task.id}`);
await page.getByTestId(mobile ? "mobile-approvals-approve" : "workflow-task-approve").click();
await expect(page.getByTestId("workflow-action-confirm-dialog")).toBeVisible();
const response = page.waitForResponse((result) => result.url().endsWith(`/workflow/tasks/${task.id}/approve`) && result.request().method() === "POST");
await page.getByTestId("workflow-action-confirm-submit").click();
assert.equal((await response).status(), 200);
assert.equal((await prisma.reimbursementForm.findUnique({ where: { id: browserForm.id } })).status, "approved");
assert.equal(await prisma.workflowTask.count({ where: { instance_id: workflow.id } }), 1);
}
} finally { await context.close(); }
}
}
passed.push("finance owner: real desktop/mobile finance submits after precheck, CEO approves once via UI and no further task is created");
}
const transferForm = await prepareOwnerForm(approvers.finance);
const transferSubmitted = await post(`/reimbursements/${transferForm.id}/submit`, {}, approvers.finance.id);
assert.equal(transferSubmitted.status, 200);
const transferTask = await prisma.workflowTask.findFirst({ where: { instance_id: transferSubmitted.body.data.workflowInstanceId, status: "pending" } });
const assertNoPendingActions = async (actor) => {
const response = await fetch(`${origin}/api/reimbursements?scope=all&pageSize=100`, {
headers: { authorization: `Bearer ${tokens.get(actor.id)}` }, signal: AbortSignal.timeout(15000),
});
assert.equal(response.status, 200);
const source = (await response.json()).data.items.find((item) => item.id === transferForm.id);
assert.ok(source);
assert.equal(source.pendingWorkflow, null, "non-CEO has no reimbursement list approval prompt");
};
await prisma.employeeRole.create({ data: { employee_id: employee.id, role_code: "finance" } });
const transferBody = { toApproverId: employee.id, reason: "synthetic transfer safety validation" };
const deniedTransfer = await post(`/workflow/tasks/${transferTask.id}/transfer`, transferBody, approvers.ceo.id);
assert.equal(deniedTransfer.status, 403);
assert.equal(deniedTransfer.body.error.details.reasonCode, "reimbursement.finance_owner_ceo_required");
assert.equal((await prisma.workflowTask.findUnique({ where: { id: transferTask.id } })).assignee_role, "ceo");
await prisma.employeeRole.create({ data: { employee_id: employee.id, role_code: "ceo" } });
assert.equal((await post(`/workflow/tasks/${transferTask.id}/transfer`, transferBody, approvers.ceo.id)).status, 200);
await prisma.employeeRole.deleteMany({ where: { employee_id: employee.id, role_code: "ceo" } });
await assertNoPendingActions(employee);
assert.equal((await post(`/workflow/tasks/${transferTask.id}/approve`, {}, employee.id)).status, 403);
const delegatedGrant = await prisma.delegationGrant.create({ data: {
principal_employee_id: employee.id, delegate_employee_id: approvers.ceo.id, scope: "all",
valid_from: new Date(Date.now() - 60000),
} });
assert.equal((await post(`/workflow/tasks/${transferTask.id}/approve`, {}, approvers.ceo.id)).status, 403);
await prisma.employeeRole.create({ data: { employee_id: employee.id, role_code: "ceo" } });
await prisma.employeeRole.create({ data: { employee_id: approvers.ceo.id, role_code: "finance" } });
await prisma.employeeRole.deleteMany({ where: { employee_id: approvers.ceo.id, role_code: "ceo" } });
await assertNoPendingActions(approvers.ceo);
assert.equal((await post(`/workflow/tasks/${transferTask.id}/approve`, {}, approvers.ceo.id)).status, 403);
await prisma.employeeRole.create({ data: { employee_id: approvers.ceo.id, role_code: "ceo" } });
await prisma.employeeRole.deleteMany({ where: { employee_id: approvers.ceo.id, role_code: "finance" } });
assert.equal((await post(`/workflow/tasks/${transferTask.id}/approve`, {}, approvers.ceo.id)).status, 200);
assert.equal((await prisma.reimbursementForm.findUnique({ where: { id: transferForm.id } })).status, "approved");
await prisma.delegationGrant.delete({ where: { id: delegatedGrant.id } });
await prisma.employeeRole.deleteMany({ where: { employee_id: employee.id, role_code: { in: ["finance", "ceo"] } } });
passed.push("finance owner: transfer only to CEO, stale assignee or principal and non-CEO delegate rejected; eligible CEO delegation approves");
}
await prisma.employee.update({ where: { id: employee.id }, data: { token_version: { increment: 1 } } });
assert.equal((await fetch(`${origin}/api/me`, { headers: { authorization: `Bearer ${tokens.get(employee.id)}` } })).status, 401);
passed.push("revoked token version rejected by real auth plugin");
console.log(JSON.stringify({ status: "PASS_REAL_DB_HTTP", passed, authentication: "REAL_PASSWORD_LOGIN_JWT_SYNTHETIC_ACCOUNTS", liveOcr: "NOT_TESTED", ocrWorker: process.env.RUN_JOB_QUEUE === "1" ? "REAL_PGBOSS_MOCK_PROVIDER" : process.env.RUN_BROWSER_TEST === "1" ? "REAL_WORKER_MOCK_PROVIDER_MANUAL_DISPATCH" : "NOT_TESTED", approvalFlow: "RETURN_RESUBMIT_THREE_STEP_APPROVAL", payment: process.env.RUN_HANDOFF_PROJECTION_TEST === "1" ? "SYNTHETIC_RECEIPT_RECORDED_PAID_NO_BANK_CONNECTION" : process.env.RUN_PAYMENT_EXPERIENCE_TEST === "1" ? "CREATE_REVIEW_DOWNLOAD_STILL_UNPAID" : "NOT_TESTED" }, null, 2));
console.log(JSON.stringify({ status: businessBlockers.length ? "BLOCKED_OWNER_APPROVAL" : "PASS_REAL_DB_HTTP", passed, businessBlockers, authentication: "REAL_PASSWORD_LOGIN_JWT_SYNTHETIC_ACCOUNTS", liveOcr: "NOT_TESTED", ocrWorker: process.env.RUN_JOB_QUEUE === "1" ? "REAL_PGBOSS_MOCK_PROVIDER" : process.env.RUN_BROWSER_TEST === "1" ? "REAL_WORKER_MOCK_PROVIDER_MANUAL_DISPATCH" : "NOT_TESTED", approvalFlow: "RETURN_RESUBMIT_THREE_STEP_APPROVAL", payment: process.env.RUN_HANDOFF_PROJECTION_TEST === "1" ? "SYNTHETIC_RECEIPT_RECORDED_PAID_NO_BANK_CONNECTION" : process.env.RUN_PAYMENT_EXPERIENCE_TEST === "1" ? "CREATE_REVIEW_DOWNLOAD_STILL_UNPAID" : "NOT_TESTED" }, null, 2));
if (businessBlockers.length) process.exitCode = 1;
} finally {
if (browser) await browser.close().catch(() => { process.exitCode = 1; console.error("Browser cleanup failed"); });
if (preview) await new Promise((resolve, reject) => preview.httpServer.close((error) => error ? reject(error) : resolve())).catch(() => { process.exitCode = 1; console.error("Preview cleanup failed"); });
@@ -517,4 +735,4 @@ async function main() {
}
}
main().catch((error) => { console.error("Isolated HTTP verification failed:", error.code ?? error.name, error.code === "ERR_ASSERTION" ? error.message : "", error.stack?.match(/test-(?:invoice-first-http|reimbursement-retained-delete)\.cjs:\d+:\d+/)?.[0] ?? ""); process.exitCode = 1; });
main().catch((error) => { console.error("Isolated HTTP verification failed:", error.code ?? error.name, error.code === "ERR_ASSERTION" ? error.message : "", error.stack?.match(/test-(?:invoice-first-http|reimbursement-retained-delete|payment-experience)\.cjs:\d+:\d+/)?.[0] ?? ""); process.exitCode = 1; });