"use strict"; const assert = require("assert"); const origin = process.argv[2] || "http://localhost:5173"; const cdpPort = process.env.CDP_PORT || "9222"; const genealogyId = process.env.GENEALOGY_ID || "2080557121112465409"; const wait = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)); const connect = async () => { const pages = await (await fetch(`http://127.0.0.1:${cdpPort}/json`)).json(); const page = pages.find((candidate) => candidate.type === "page" && candidate.url.startsWith(`${origin}/`)); if (!page) throw new Error(`Chrome debugging has no ${origin} project page`); const socket = new WebSocket(page.webSocketDebuggerUrl); await new Promise((resolve, reject) => { socket.addEventListener("open", resolve, { once: true }); socket.addEventListener("error", reject, { once: true }); }); let id = 0; const pending = new Map(); socket.addEventListener("message", (event) => { const message = JSON.parse(event.data); const request = pending.get(message.id); if (!request) return; pending.delete(message.id); message.error ? request.reject(new Error(message.error.message)) : request.resolve(message.result); }); const send = (method, params = {}) => new Promise((resolve, reject) => { id += 1; pending.set(id, { resolve, reject }); socket.send(JSON.stringify({ id, method, params })); }); return { socket, send }; }; const valueOf = async (send, expression) => (await send("Runtime.evaluate", { expression, returnByValue: true, awaitPromise: true })).result?.value; const waitFor = async (send, expression, message) => { for (let attempt = 0; attempt < 80; attempt += 1) { if (await valueOf(send, expression)) return; await wait(100); } throw new Error(message); }; const open = async (send, route) => { const url = `${origin}/#${route}`; await send("Page.navigate", { url }); await waitFor(send, `location.href === ${JSON.stringify(url)}`, `navigation failed: ${route}`); const previousTimeOrigin = await valueOf(send, "performance.timeOrigin"); await send("Page.reload"); await waitFor(send, `performance.timeOrigin !== ${JSON.stringify(previousTimeOrigin)}`, `reload failed: ${route}`); await waitFor(send, "document.body.innerText.length > 0", `page did not render: ${route}`); }; const run = async () => { const { socket, send } = await connect(); try { await send("Page.enable"); await send("Runtime.enable"); const readbacks = [ ["/pages/records/r03-gift-list?genealogyId=" + genealogyId, "\u63a5\u53e3\u8054\u8c03\u9a8c\u8bc1\u4eb2\u53cb"], ["/pages/records/r05-ritual-list?genealogyId=" + genealogyId, "\u63a5\u53e3\u8054\u8c03\u9a8c\u8bc1\u793c\u4eea\u6d3b\u52a8"], ["/pages/records/r08-growth-journal?genealogyId=" + genealogyId, "\u63a5\u53e3\u8054\u8c03\u9a8c\u8bc1\u6210\u957f\u8bb0\u5f55"], ["/pages/records/r10-memo-list?genealogyId=" + genealogyId, "\u63a5\u53e3\u8054\u8c03\u9a8c\u8bc1\u5907\u5fd8"], ["/pages/records/r11-merit-records?genealogyId=" + genealogyId, "\u63a5\u53e3\u8054\u8c03\u9a8c\u8bc1\u529f\u5fb7"], ]; for (const [route, text] of readbacks) { await open(send, route); await waitFor(send, `document.body.innerText.includes(${JSON.stringify(text)})`, `service readback missing: ${route}`); assert.strictEqual(await valueOf(send, "Boolean(document.querySelector('.state-card .app-loading'))"), false, `page stuck loading: ${route}`); } await open(send, "/pages/records/r08-growth-journal?genealogyId=" + genealogyId); await valueOf(send, "document.querySelector('.header-action')?.click()"); await waitFor(send, "Boolean(document.querySelector('.form-card'))", "R08 create form did not open"); assert.strictEqual(await valueOf(send, "document.querySelectorAll('.required-mark').length"), 1, "R08 required marker drifted"); await open(send, "/pages/records/r10-memo-list?genealogyId=" + genealogyId); await valueOf(send, "document.querySelector('.header-action')?.click()"); await waitFor(send, "Boolean(document.querySelector('.form-card'))", "R10 create form did not open"); assert.strictEqual(await valueOf(send, "document.querySelectorAll('.required-mark').length"), 1, "R10 required marker drifted"); await open(send, "/pages/records/r11-merit-records?genealogyId=" + genealogyId); await valueOf(send, "document.querySelector('.header-action')?.click()"); await waitFor(send, "Boolean(document.querySelector('.form-card'))", "R11 create form did not open"); assert.strictEqual(await valueOf(send, "document.querySelectorAll('.required-mark').length"), 2, "R11 required marker drifted"); process.stdout.write("R-BUSINESS-FLOW-RUNTIME-SMOKE PASS\n"); } finally { socket.close(); } }; run().catch((error) => { process.stderr.write(`${error.stack || error.message}\n`); process.exit(1); });