// bcnr-selftest.js — end-to-end proof that `window.bcnr` from // bcnr-preload.js reaches the main-process handlers over IPC and returns // what the resolver sees. Mirrors dev/selftest.js style: sets // THESEUS_NO_AUTOSTART=1, imports main.js, then wires the minimum bits // (session preload + resolver warm-up) itself so the harness stays fast // and hermetic. // // Usage: npx electron dev/bcnr-selftest.js // ^ optional; defaults to silentmode.bch process.env.THESEUS_NO_AUTOSTART = "1"; const path = require("path"); const { app, BrowserWindow, session } = require("electron"); // main.js exports resolveHost etc. for tests; importing it also registers // the ipcMain.handle("bcnr:...") handlers at module load. require("../main.js"); app.disableHardwareAcceleration(); app.commandLine.appendSwitch("disable-gpu"); app.commandLine.appendSwitch("no-sandbox"); const name = (process.argv[2] || "silentmode.bch").toLowerCase(); const watchdog = setTimeout(() => { console.log("WATCHDOG"); try { app.exit(3); } catch {} }, 60000); app.whenReady().then(async () => { // Install the same session-wide preload the shipped app installs. session.defaultSession.setPreloads([path.join(__dirname, "..", "bcnr-preload.js")]); // No explicit warm-up: the first resolveName() call flows into // resolveHost() which lazily runs ensureIndex() itself. Cold start can // take a while (electrum handshake + full walk); the watchdog covers it. const win = new BrowserWindow({ width: 800, height: 600, show: false, webPreferences: { offscreen: true } }); const wc = win.webContents; await wc.loadURL("about:blank"); const report = { name }; try { report.hasBridge = await wc.executeJavaScript("typeof window.bcnr === 'object'"); report.methods = await wc.executeJavaScript("Object.keys(window.bcnr || {}).sort()"); report.getBcnrTlds = await wc.executeJavaScript("window.bcnr.getBcnrTlds()"); report.isRegistered = await wc.executeJavaScript(`window.bcnr.isRegistered(${JSON.stringify(name)})`); report.getRecordVersion = await wc.executeJavaScript(`window.bcnr.getRecordVersion(${JSON.stringify(name)})`); report.resolveName = await wc.executeJavaScript(`window.bcnr.resolveName(${JSON.stringify(name)})`); // B.2b — the caller's eTLD+1 origin as Theseus sees it. From about:blank // this must be "about:blank"; a data: URL would be null; a real dApp // page would be its registrable domain. Full origin logic is unit-tested // in dev/origin-selftest.mjs; this proves the IPC wiring uses it. report.origin_aboutBlank = await wc.executeJavaScript("window.bcnr.getOrigin()"); } catch (e) { report.error = e.message; } console.log("\n===== BCNR SELFTEST ====="); console.log(JSON.stringify(report, null, 2)); // Verdict: bridge present, four methods, TLD list non-empty, and either // the name resolved OR it plausibly doesn't exist (isRegistered === false // + resolveName === null is a valid pass — resolver worked, name just // isn't on chain). const bridgeOk = report.hasBridge === true && Array.isArray(report.methods) && ["getBcnrTlds", "getOrigin", "getRecordVersion", "isRegistered", "resolveName"].every((m) => report.methods.includes(m)); const tldsOk = Array.isArray(report.getBcnrTlds) && report.getBcnrTlds.length > 0; const shapeOk = (report.isRegistered === true && report.resolveName && report.resolveName.name === name) || (report.isRegistered === false && report.resolveName === null); const originOk = report.origin_aboutBlank === "about:blank"; report.verdict = bridgeOk && tldsOk && shapeOk && originOk ? "PASS" : "FAIL"; console.log("verdict:", report.verdict); clearTimeout(watchdog); try { app.exit(report.verdict === "PASS" ? 0 : 1); } catch {} });