68 行
2.4 KiB
TypeScript
68 行
2.4 KiB
TypeScript
import { expect, type Page } from "@playwright/test";
|
||
|
||
export type LiveInvoiceOcrStatus = "available" | "ocr_failed";
|
||
|
||
export type LiveInvoiceOcrResult = {
|
||
status: LiveInvoiceOcrStatus;
|
||
detailText: string;
|
||
bannerText: string;
|
||
durationMs: number;
|
||
invoiceId: string | null;
|
||
invoiceCode: string | null;
|
||
invoiceNumber: string | null;
|
||
sellerName: string | null;
|
||
totalAmount: string | null;
|
||
invoiceDate: string | null;
|
||
};
|
||
|
||
function extractField(detailText: string, label: string) {
|
||
const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||
const match = detailText.match(new RegExp(`${escaped}([^\\n]+)`));
|
||
return match?.[1]?.trim() || null;
|
||
}
|
||
|
||
export async function openInvoicePool(page: Page) {
|
||
await page.goto("/invoice-pool");
|
||
await expect(page.getByTestId("invoice-pool-table")).toBeVisible();
|
||
}
|
||
|
||
export async function uploadLiveInvoiceAndWait(page: Page, invoiceFilePath: string, timeout = 180_000): Promise<LiveInvoiceOcrResult> {
|
||
const startedAt = Date.now();
|
||
|
||
await page.getByTestId("invoice-upload-file").setInputFiles(invoiceFilePath);
|
||
await page.getByTestId("invoice-upload-submit").click();
|
||
|
||
const detailPanel = page.getByTestId("invoice-detail-panel");
|
||
await expect(detailPanel).toBeVisible({ timeout: 30_000 });
|
||
|
||
await expect
|
||
.poll(async () => {
|
||
const text = await detailPanel.innerText().catch(() => "");
|
||
if (text.includes("状态:available")) return "available";
|
||
if (text.includes("状态:ocr_failed")) return "ocr_failed";
|
||
return "pending_ocr";
|
||
}, { timeout })
|
||
.not.toBe("pending_ocr");
|
||
|
||
const detailText = await detailPanel.innerText();
|
||
const bannerText = await page.getByTestId("invoice-ocr-status-banner").innerText().catch(() => "");
|
||
const status = detailText.includes("状态:ocr_failed") ? "ocr_failed" : "available";
|
||
const invoiceNo = extractField(detailText, "发票号:");
|
||
const [invoiceCode, invoiceNumber] = invoiceNo && invoiceNo.includes("-")
|
||
? invoiceNo.split("-", 2).map((item) => item.trim() || null)
|
||
: [invoiceNo, null];
|
||
|
||
return {
|
||
status,
|
||
detailText,
|
||
bannerText,
|
||
durationMs: Date.now() - startedAt,
|
||
invoiceId: extractField(detailText, "票据ID:"),
|
||
invoiceCode,
|
||
invoiceNumber,
|
||
sellerName: extractField(detailText, "销售方:"),
|
||
totalAmount: extractField(detailText, "总金额:"),
|
||
invoiceDate: extractField(detailText, "开票日期:"),
|
||
};
|
||
}
|