You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mail-yubao/tests/e2e/sample-mails-detail-smoke.s...

187 lines
5.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { test, expect, type Page, type ConsoleMessage } from "@playwright/test";
import * as fs from "node:fs";
import * as path from "node:path";
import { execSync } from "node:child_process";
type MailItem = {
key: string;
id: string;
status: string;
mail_type: string;
container_no: string | null;
shipments: number;
table_rows: number;
url: string;
};
type DetailResult = {
key: string;
id: string;
url: string;
open_ms: number;
ok: boolean;
antd_warnings: string[];
page_errors: string[];
visible_checks: string[];
note?: string;
};
function btn(page: Page, label: string) {
const re = new RegExp(`^${label.split("").map(escapeRe).join("\\s*")}$`);
return page.getByRole("button", { name: re });
}
function escapeRe(s: string) {
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
async function login(page: Page) {
await page.goto("/login");
const user = page.getByLabel("用户名");
await user.click();
await user.fill("");
await user.fill("admin");
const pwd = page.getByLabel("密码");
await pwd.click();
await pwd.fill("");
await pwd.fill("admin123");
await btn(page, "登录").click();
await expect(page).toHaveURL(/\/mails/, { timeout: 20_000 });
}
function loadSampleItems(): MailItem[] {
execSync("pnpm exec tsx scripts/ingest-sample-mails.ts", {
cwd: process.cwd(),
encoding: "utf8",
env: process.env,
stdio: ["ignore", "pipe", "pipe"],
});
const report = path.join(process.cwd(), "data", "logs", "sample-mails-ingest.json");
const json = JSON.parse(fs.readFileSync(report, "utf8")) as { items: MailItem[] };
return json.items;
}
test.describe("sample mails M1-M4 detail console", () => {
test("open four details + catch antd warnings", async ({ page }) => {
test.setTimeout(240_000);
const items = loadSampleItems();
expect(items.length).toBe(4);
await login(page);
const results: DetailResult[] = [];
for (const item of items) {
const antd_warnings: string[] = [];
const page_errors: string[] = [];
const onConsole = (msg: ConsoleMessage) => {
const text = msg.text();
if (
msg.type() === "error" ||
msg.type() === "warning" ||
text.includes("[antd:")
) {
if (text.includes("[antd:")) antd_warnings.push(text.slice(0, 300));
else if (msg.type() === "error") page_errors.push(text.slice(0, 300));
}
};
const onPageError = (err: Error) => {
page_errors.push(err.message.slice(0, 300));
};
page.on("console", onConsole);
page.on("pageerror", onPageError);
const t0 = Date.now();
let ok = true;
const visible_checks: string[] = [];
let note: string | undefined;
try {
await page.goto(`/mails/${item.id}`, { waitUntil: "domcontentloaded" });
await expect(page.getByRole("button", { name: /回列表/ })).toBeVisible({
timeout: 30_000,
});
visible_checks.push("回列表");
await expect(page.locator(".mail-biz-units")).toBeVisible({
timeout: 15_000,
});
visible_checks.push("指令区");
// 若有标准化表,确认 Table 渲染且无 rowKey/span 告警
const tableTitle = page.getByText(/工单标准化列表|货件标准表/);
if (await tableTitle.first().isVisible().catch(() => false)) {
visible_checks.push("标准表");
await expect(page.locator(".ant-table-tbody").first()).toBeVisible();
}
// 等一拍收集异步 warning
await page.waitForTimeout(800);
} catch (e) {
ok = false;
note = e instanceof Error ? e.message.slice(0, 240) : String(e);
} finally {
page.off("console", onConsole);
page.off("pageerror", onPageError);
}
// 过滤已知无关噪声,只关心 antd Descriptions/Table
const critical = antd_warnings.filter(
(w) =>
w.includes("[antd: Descriptions]") ||
w.includes("[antd: Table]") ||
w.includes("rowKey") ||
w.includes("span"),
);
results.push({
key: item.key,
id: item.id,
url: item.url,
open_ms: Date.now() - t0,
ok: ok && critical.length === 0 && page_errors.length === 0,
antd_warnings: critical,
page_errors,
visible_checks,
note:
note ||
`type=${item.mail_type} status=${item.status} cn=${item.container_no} rows=${item.table_rows}`,
});
}
const outDir = path.join(process.cwd(), "data", "logs");
fs.mkdirSync(outDir, { recursive: true });
const summary = {
at: new Date().toISOString(),
fail: results.filter((r) => !r.ok).length,
results,
};
fs.writeFileSync(
path.join(outDir, "sample-mails-detail-smoke.json"),
JSON.stringify(summary, null, 2),
"utf8",
);
const md = [
"# Sample Mails Detail Smoke (M1–M4)",
"",
`| mail | id | open_ms | ok | antd | checks | note |`,
`|---|---|---:|:---:|---|---|---|`,
...results.map(
(r) =>
`| M${r.key} | ${r.id} | ${r.open_ms} | ${r.ok ? "Y" : "N"} | ${r.antd_warnings.length} | ${r.visible_checks.join("/") || "-"} | ${(r.note ?? "").replace(/\|/g, "/")} |`,
),
"",
...results
.filter((r) => r.antd_warnings.length || r.page_errors.length)
.flatMap((r) => [
`## M${r.key} issues`,
...r.antd_warnings.map((w) => `- antd: ${w}`),
...r.page_errors.map((w) => `- error: ${w}`),
"",
]),
].join("\n");
fs.writeFileSync(path.join(outDir, "sample-mails-detail-smoke.md"), md, "utf8");
expect(results.every((r) => r.ok)).toBeTruthy();
});
});