/** * Failure modes recorded before the fixes: * - Certification HTML must keep its QR-refresh script, without reading or writing the console parent. * - Receiving a QR URL is not evidence that an image loaded; pending/broken images must not start login polling. * - A broken image needs an accessible error and a retry, and a fresh loaded image must still permit normal login. * All scenarios enter the actual built pages and replace only the external HTTP service or browser clock. */ import assert from "node:assert/strict"; import { test } from "node:test"; import { appOrigin, backendOrigin, eventually, login, scenario, } from "./helpers/console-browser.mjs"; const qrImage = "R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="; function reply(route, data) { return route.fulfill({ json: { status: 200, msg: "", data }, headers: { "Access-Control-Allow-Origin": "*" }, }); } test( "certification QR refresh scripts run without console-parent privileges", { timeout: 30000 }, (t) => scenario(t, {}, async (page) => { await page.addInitScript(() => { document.addEventListener( "DOMContentLoaded", () => { document.documentElement.dataset.auditIsolationSeed = "synthetic-local-marker"; }, { once: true }, ); }); await page .context() .route(`${backendOrigin}/console/v1/certification/**`, (route) => { const path = new URL(route.request().url()).pathname; if (path.endsWith("/info")) return reply(route, { certification_open: 1, certification_company_open: 0, certification_upload: 0, is_certification: 0, person: { status: 4 }, }); if (path.endsWith("/auth")) return reply(route, { html: `
`, }); if (path.endsWith("/status")) return reply(route, { code: 2, refresh: 0 }); return route.fallback(); }); await login(page, "/account/realname"); await page .getByRole("button", { name: "继续扫码核验", exact: true }) .click(); const element = await page.locator("iframe.auth-frame").elementHandle(); const frame = await element.contentFrame(); await frame .locator('[data-certification-qr][data-audit-dynamic-qr="updated"]') .waitFor(); const observed = { refreshedQrVisible: await frame .locator("[data-certification-qr]") .isVisible(), pluginScriptRan: await frame.evaluate( () => document.documentElement.dataset.auditPluginScript === "ran", ), parentAccessBlocked: await frame.evaluate( () => document.documentElement.dataset.auditParentAccess === "blocked", ), parentMarkerUntouched: await page.evaluate( () => document.documentElement.dataset.auditFromCertification === undefined, ), }; assert.equal(observed.refreshedQrVisible, true); assert.equal(observed.pluginScriptRan, true); assert.equal(observed.parentAccessBlocked, true); assert.equal(observed.parentMarkerUntouched, true); return observed; }), ); test( "a broken WeChat image stops its scan and a fresh image recovers login", { timeout: 35000 }, (t) => scenario(t, {}, async (page) => { await page.clock.install(); let acquisitions = 0; let firstScanPolls = 0; let secondScanPolls = 0; let releaseImage; const imageRelease = new Promise((resolve) => { releaseImage = resolve; }); let imageRequested; const imageStarted = new Promise((resolve) => { imageRequested = resolve; }); await page.context().route(`${backendOrigin}/**`, async (route) => { const url = new URL(route.request().url()); if (url.pathname === "/audit-qr/1.gif") { imageRequested(); await imageRelease; return route.fulfill({ contentType: "image/gif", body: "invalid-image", }); } if (url.pathname === "/audit-qr/2.gif") return route.fulfill({ contentType: "image/gif", body: Buffer.from(qrImage, "base64"), }); if (url.pathname === "/console/v1/common") return reply(route, { website_name: "本地扫码验收", login_phone_password: 1, login_email_password: 1, plugin_configuration: { mp_weixin_notice: { scan_login: 1 } }, }); if (url.pathname === "/console/v1/mp_weixin_notice/qrcode") { acquisitions++; return reply(route, { img_url: `${backendOrigin}/audit-qr/${acquisitions}.gif`, ticket: `local-qr-ticket-${acquisitions}`, token: "local-qr-token", }); } if (url.pathname === "/console/v1/mp_weixin_notice/qrcode/status") { if (url.searchParams.get("ticket") === "local-qr-ticket-1") { firstScanPolls++; return reply(route, { status: "Wait" }); } secondScanPolls++; return reply(route, { status: "Success", jwt: "e2e-session-token" }); } return route.fallback(); }); try { await page.goto(`${appOrigin}/login?redirect=/security/ssh-keys`); await page .getByRole("button", { name: "获取二维码", exact: true }) .click(); await imageStarted; await page.clock.runFor(5000); const pollsBeforeImage = firstScanPolls; releaseImage(); await eventually( () => page.evaluate(() => { const image = document.querySelector(".qr-img"); return !image || image.complete; }), Boolean, "The invalid image must finish decoding", ); await page.clock.runFor(5000); const failureState = { accessibleError: await page .locator(".qr-status") .getByRole("alert") .isVisible(), brokenImageRemoved: (await page.locator(".qr-img").count()) === 0, pollsBeforeImage, pollsAfterImageFailure: firstScanPolls, }; await page .getByRole("button", { name: "刷新二维码", exact: true }) .click(); await eventually( () => page.evaluate(() => { const image = document.querySelector(".qr-img"); return Boolean(image?.complete && image.naturalWidth > 0); }), Boolean, "Retry must display a real decoded QR image", ); await page.clock.runFor(2100); await page.waitForURL((url) => url.pathname === "/security/ssh-keys"); await page.getByText("audit-01", { exact: true }).waitFor(); assert.equal(failureState.accessibleError, true); assert.equal(failureState.brokenImageRemoved, true); assert.equal(failureState.pollsBeforeImage, 0); assert.equal(failureState.pollsAfterImageFailure, 0); assert.equal(secondScanPolls, 1); return { ...failureState, retryCompletedNormalLogin: true }; } finally { releaseImage(); } }), );