1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// node --test examples/web/hello/hello.test.mjs (after `cargo wasm`; skips without Chrome)
// index.html as served, in headless Chrome: the module graph loads, both components render signed out,
// and Count runs the real hello module in the page. The PLC directory and the PDS are stubbed, and so is
// @atproto/oauth-client-browser (esm.sh) unless ATLIBS_DOCS_NETWORK=1, which loads the real one.
import assert from "node:assert/strict";
import { test } from "node:test";
import { browse, CHROME } from "../../../docs/browser.mjs";
const ROOT = new URL("../../../", import.meta.url).pathname;
const NETWORK = process.env.ATLIBS_DOCS_NETWORK === "1";
const did = "did:plc:lpfuqerea3deuoyrn7ojser4";
// url prefix -> [content type, body]
const STUBS = {
[`https://plc.directory/${did}`]: ["application/json", JSON.stringify({ service: [{ id: "#atproto_pds", serviceEndpoint: "https://pds.example" }] })],
"https://pds.example/xrpc/com.atproto.repo.listRecords?": ["application/json", JSON.stringify({ records: [{ uri: `at://${did}/xyz.statusphere.status/a`, value: { status: "🙂" } }] })],
...(!NETWORK && { "https://esm.sh/": ["text/javascript", "export const BrowserOAuthClient = { load: async () => ({ init: async () => undefined }) }"] }),
};
test("hello boots in Chrome, signed out, and counts records", { 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 stub = Object.entries(STUBS).find(([prefix]) => request.url.startsWith(prefix))?.[1];
const [type, body] = stub ?? ["text/plain", "not stubbed"];
const responseHeaders = [{ name: "content-type", value: type }, { name: "access-control-allow-origin", value: "*" }, { name: "access-control-allow-headers", value: "*" }];
send("Fetch.fulfillRequest", { requestId, responseCode: stub ? 200 : 404, 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("/examples/web/hello/index.html");
// until main.js's cubit.init() has rendered: the sign-in form shown, the status form hidden
const signedOut = `!!customElements.get("hello-count") && document.querySelector("hello-status .status")?.hidden === true && !document.querySelector("hello-status .login").hidden`;
const until = async (expression) => {
for (const end = Date.now() + 15_000; Date.now() < end; await new Promise((ok) => setTimeout(ok, 100))) if (await evaluate(expression)) return;
assert.fail(`timed out: ${expression}\n${errors.join("\n")}`);
};
await until(signedOut);
await evaluate(`(() => { const form = document.querySelector("hello-count form"); form.did.value = ${JSON.stringify(did)}; form.requestSubmit() })()`);
await until(`document.querySelector("hello-count .out").textContent !== ""`);
assert.equal(await evaluate(`document.querySelector("hello-count .out").textContent`), "1 records in xyz.statusphere.status");
assert.deepEqual(errors, []);
}, { root: ROOT }));