// node --test web/cocore/cocore.test.mjs (after `cargo wasm`; skips without Chrome) // index.html as served, in headless Chrome: the module graph loads, signed out, with a form per action of // every module. @atproto/oauth-client-browser (esm.sh) and the stylesheet are stubbed. import assert from "node:assert/strict"; import { readdirSync, readFileSync } from "node:fs"; import { test } from "node:test"; import { browse, CHROME } from "../../../atlibs/docs/browser.mjs"; const ROOT = new URL("./", import.meta.url).pathname; const NAMES = readdirSync(new URL("modules/", import.meta.url)).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5)); const ACTIONS = NAMES.flatMap((name) => JSON.parse(readFileSync(new URL(`modules/${name}.json`, import.meta.url), "utf8")).actions.map((a) => a.label)); const STUBS = { "https://esm.sh/": ["text/javascript", "export const BrowserOAuthClient = { load: async () => ({ init: async () => undefined }) }"], "https://cdn.jsdelivr.net/": ["text/css", ""], }; test("the page boots in Chrome, signed out, with every action's form", { skip: !CHROME && "no Chrome" }, () => browse(async ({ send, on, open, evaluate }) => { const errors = []; on("Runtime.exceptionThrown", ({ exceptionDetails: e }) => errors.push(e.exception?.description ?? e.text)); on("Log.entryAdded", ({ entry }) => entry.level === "error" && !entry.url?.endsWith("/favicon.ico") && errors.push(`${entry.text} ${entry.url ?? ""}`)); on("Fetch.requestPaused", ({ requestId, request }) => { const [type, body] = Object.entries(STUBS).find(([prefix]) => request.url.startsWith(prefix))[1]; const responseHeaders = [{ name: "content-type", value: type }, { name: "access-control-allow-origin", value: "*" }]; send("Fetch.fulfillRequest", { requestId, responseCode: 200, responseHeaders, body: Buffer.from(body).toString("base64") }); }); await send("Runtime.enable"); await send("Log.enable"); await send("Fetch.enable", { patterns: Object.keys(STUBS).map((prefix) => ({ urlPattern: `${prefix}*` })) }); await open("/index.html"); const ready = `document.querySelectorAll("#actions details").length === ${NAMES.length} && document.querySelectorAll("#actions form").length === ${ACTIONS.length}`; for (const end = Date.now() + 15_000; Date.now() < end && !(await evaluate(ready)); ) await new Promise((ok) => setTimeout(ok, 100)); assert.deepEqual(errors, []); assert.ok(await evaluate(ready), "every module's actions rendered"); assert.equal(await evaluate(`document.querySelector("#login").hidden`), false); assert.equal(await evaluate(`document.querySelector("#signed-in").hidden`), true); assert.deepEqual(await evaluate(`[...document.querySelectorAll("#actions h4")].map((h) => h.textContent)`).then((l) => l.sort()), ACTIONS.sort()); }, { root: ROOT }), );