// company-api-test/index.html 自动化验收测试
const { chromium } = require("playwright");
const path = require("path");
const OUT = (n) => path.join(require("os").tmpdir(), n);
(async () => {
const errors = [];
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
page.on("pageerror", (e) => errors.push(String(e)));
page.on("console", (m) => {
// 故意触发的 405/404 网络日志不算页面错误
if (m.type() === "error" && !/Failed to load resource/.test(m.text())) errors.push(m.text());
});
await page.goto("http://localhost:9527");
await page.waitForLoadState("networkidle");
// 1) 主链路:公网 api-cx 实名查询(真实网络请求)
const idv = await page.inputValue("#idPlain");
if (idv !== "430703198610010059") throw new Error("默认身份证明文不对: " + idv);
const preview = await page.textContent("#cxPreview");
if (!preview.includes("sign=") || !preview.includes("zjhm=J4jfHM")) throw new Error("签名 URL 预览异常: " + preview);
await page.click("#btnSendCx");
await page.waitForTimeout(4000);
const chipCode = await page.textContent("#chipCode");
if (!chipCode.includes("0")) throw new Error("respCode 应为 0: " + chipCode);
const meta = await page.textContent("#metaLine");
if (!meta.includes("430703198610010059")) throw new Error("台账 meta 应含身份证明文");
const emptyMsg = await page.textContent("#ledgerBody");
if (!emptyMsg.includes("暂无企业数据")) throw new Error("应显示空数据提示: " + emptyMsg);
await page.screenshot({ path: OUT("v2_1_cx_query.png"), fullPage: true });
// 2) 校验密文解密(后端解密回显 → 证明 AES 正确)
await page.click("#btnVerifyZjhm");
await page.waitForTimeout(3000);
const ledger = await page.textContent("#ledgerBody");
if (!ledger.includes("430703198610010059")) throw new Error("校验台账应含明文");
if (!ledger.includes("一致")) throw new Error("校验结论应为一致");
await page.screenshot({ path: OUT("v2_2_verify.png"), fullPage: true });
// 3) JSON 标签页
await page.click('.tab[data-tab="json"]');
const j = await page.textContent("#jsonScreen");
if (!j.includes("respCode")) throw new Error("JSON 视图应含 respCode");
// 4) 次链路:tax-appoint 离线示例
await page.check("#mockToggle");
await page.click("#btnSend");
await page.waitForTimeout(400);
const rows = await page.locator("#ledgerBody tr").count();
if (rows !== 2) throw new Error("示例模式应渲染 2 行, 实际 " + rows);
if (!(await page.textContent("#ledgerBody")).includes("义乌市万竹贤口腔诊所")) throw new Error("示例台账缺少企业");
const t2 = await page.textContent("#ledgerBody");
if (t2.includes("330725198202084328")) throw new Error("脱敏开启时不应显示完整证件号");
// 5) 关闭脱敏 → 完整证件号
await page.uncheck("#maskToggle");
await page.waitForTimeout(200);
if (!(await page.textContent("#ledgerBody")).includes("330725198202084328")) throw new Error("关闭脱敏后应显示完整证件号");
await page.check("#maskToggle");
// 6) tax-appoint 真实请求(经代理 → 405)→ 友好错误面板
await page.uncheck("#mockToggle");
await page.click("#btnSameOrigin");
await page.click("#btnSend");
await page.waitForTimeout(2500);
if (!(await page.locator("#stageError").isVisible())) throw new Error("后端不可用时应展示错误面板");
const chipHttp = await page.textContent("#chipHttp");
if (!/405|502/.test(chipHttp)) throw new Error("状态条应显示 405/502: " + chipHttp);
await page.screenshot({ path: OUT("v2_3_ta_error.png"), fullPage: true });
// 7) 历史
if ((await page.locator(".h-item").count()) < 2) throw new Error("应有 ≥2 条历史记录");
// 8) AES 工具
await page.fill("#aesPlain", "330725198202084328");
await page.click("#btnAesEnc");
const enc = await page.inputValue("#aesCipherOut");
if (enc !== "MoV2Ra2USY/6tc6b9xQXZkuEA+I6X3u90CSNgvFqzlE=") throw new Error("AES 加密与文档示例不一致: " + enc);
await page.fill("#aesCipherIn", enc);
await page.click("#btnAesDec");
if ((await page.inputValue("#aesPlainOut")) !== "330725198202084328") throw new Error("AES 解密不一致");
await page.fill("#aesKey", "shortkey");
await page.click("#btnAesEnc");
if (!/错误/.test(await page.inputValue("#aesCipherOut"))) throw new Error("非法密钥应提示错误");
await page.fill("#aesKey", "Gi4swf3llyafmsuK");
// 9) 密文一键填入 zjhm
await page.click("#btnAesEnc");
await page.click("#btnFillZjhm");
if ((await page.inputValue("#zjhm")) !== "MoV2Ra2USY/6tc6b9xQXZkuEA+I6X3u90CSNgvFqzlE=") throw new Error("填入 zjhm 失败");
await page.screenshot({ path: OUT("v2_4_final.png"), fullPage: true });
await browser.close();
if (errors.length) {
console.log("CONSOLE/PAGE ERRORS:");
errors.forEach((e) => console.log(" -", e.slice(0, 300)));
process.exit(1);
}
console.log("ALL CHECKS PASSED");
})().catch((e) => { console.error("FAIL:", e.message); process.exit(1); });