theseus/dev/selftest.js

83 lines
3.8 KiB
JavaScript
Raw Permalink Normal View History

// Electron render harness — loads a bns:// name through the REAL serveBns handler
// (imported from main.js), lets its JS execute, then reports what actually
// rendered: title, image load status, stylesheet/script counts, visible text
// length, and any failed resource loads. Also writes render.html + render.png.
// This is the full-fidelity version of manual test #2/#3 — it runs the same
// resolver + gateway path the shipped app uses.
//
// Usage: npx electron dev/selftest.js <name> e.g. hello.bch / coinspectrum.deviant.bch
process.env.THESEUS_NO_AUTOSTART = "1";
const { app, BrowserWindow, protocol } = require("electron");
const { serveBns, nativeTld, registryOf } = require("../main.js");
const fs = require("fs");
const path = require("path");
app.disableHardwareAcceleration();
app.commandLine.appendSwitch("disable-gpu");
app.commandLine.appendSwitch("no-sandbox");
const name = (process.argv[2] || "coinspectrum.deviant.bch").toLowerCase();
const settleMs = Number(process.env.THESEUS_SETTLE || 5000);
const outDir = path.join(__dirname, "..", "dev-out");
// hard watchdog so the harness can never hang a CI/agent run
const watchdog = setTimeout(() => { console.log("WATCHDOG: timed out"); try { app.exit(3); } catch {} }, 45000);
app.whenReady().then(async () => {
protocol.handle("bns", serveBns);
const win = new BrowserWindow({ width: 1200, height: 900, show: false, webPreferences: { offscreen: true } });
const wc = win.webContents;
const failed = [];
wc.on("did-fail-load", (_e, code, desc, url, isMainFrame) => { if (code !== -3) failed.push({ code, desc, url, isMainFrame }); });
const tld = nativeTld(name);
const report = { name, url: `bns://${name}/`, badge: tld ? `${registryOf(tld)} · .${tld}` : null };
try {
await wc.loadURL(`bns://${name}/`);
} catch (e) { report.loadError = e.message; }
await new Promise((r) => setTimeout(r, settleMs)); // let JS build the DOM + fetch data
try {
Object.assign(report, await wc.executeJavaScript(`(() => {
const imgs = [...document.images].map(i => {
const src = i.currentSrc || i.src || '';
return { src: src.slice(0, 90), ok: i.complete && i.naturalWidth > 0, local: src.startsWith('bns:') };
});
const brokenLocal = imgs.filter(i => !i.ok && i.local);
return {
title: document.title,
stylesheets: document.styleSheets.length,
scripts: document.scripts.length,
imgTotal: imgs.length,
imgBrokenLocal: brokenLocal.length, // served by us (bns://) — a real failure
imgBrokenExternal: imgs.filter(i => !i.ok && !i.local).length, // 3rd-party CDN — informational
brokenLocalImgs: brokenLocal.map(i => i.src),
textLen: (document.body ? document.body.innerText : '').trim().length,
h1: (document.querySelector('h1,h2') || {}).innerText || null,
};
})()`));
} catch (e) { report.evalError = e.message; }
report.failedLoads = failed;
fs.mkdirSync(outDir, { recursive: true });
try {
const html = await wc.executeJavaScript("document.documentElement.outerHTML");
fs.writeFileSync(path.join(outDir, "render.html"), html);
} catch {}
try {
const img = await wc.capturePage();
const png = img.toPNG();
if (png && png.length > 0) { fs.writeFileSync(path.join(outDir, "render.png"), png); report.screenshot = `dev-out/render.png (${png.length} bytes)`; }
else report.screenshot = "empty (offscreen not compositing)";
} catch (e) { report.screenshot = "error: " + e.message; }
console.log("\n===== SELFTEST REPORT =====");
console.log(JSON.stringify(report, null, 2));
// Verdict ignores external CDN images — only our own (bns://) assets + page loads count.
report.verdict = (!report.loadError && !report.imgBrokenLocal && report.textLen > 0) ? "PASS" : "FAIL";
clearTimeout(watchdog);
app.exit(report.verdict === "PASS" ? 0 : 2);
});