registryOn
uses node:child_process
tcm registry run on the fake network, reading Jetstream every 2 seconds, until the test ends: its address (at
127.0.0.1, where a loopback OAuth client comes back to), until (waiting for something, saying what the registry said if
it doesn't happen), and page (a page's HTML, without the markers server rendering puts between adjacent text).
With base, it runs under that path, behind tcm serve --proxy (as tcm's own does, at tcm.codes/registry), listening
on IPv6 (as on Railway's private network): url is the registry's under the server, and own the registry's own address.
import { uiPage } from "#codebase/tcmts/cli/test/e2e/contributions"; import type { Keep } from "#codebase/tcmts/cli/test/e2e/contributions"; import type { FakeAtproto } from "#codebase/tcmts/cli/test/e2e/examples"; import { plainEnv, strip, tcmBin, tempDir } from "#codebase/tcmts/cli/test/e2e/harness"; import { codebase, startServerInfo } from "#codebase/tcmts/cli/test/e2e/sync"; import assert from "node:assert/strict"; import { spawn } from "node:child_process"; export async function registryOn(keep: Keep, net: FakeAtproto, { base }: { base?: string } = {}) { const dir = tempDir("registry run"); const child = keep( spawn( process.execPath, [ tcmBin(), "registry", "--port", "0", "--dir", "here", ...(base ? ["--base", base, "--host", "::1"] : []), ], { cwd: dir, env: { ...plainEnv(), TCM_ATPROTO_DIRECTORY: net.url, TCM_ATPROTO_LOCAL: "1", TCM_JETSTREAM: net.url, TCM_RELAY: net.url, TCM_REGISTRY_EVERY: "2s", }, }, ), ); let out = ""; child.stdout!.setEncoding("utf8").on("data", (d: string) => (out += d)); child.stderr!.setEncoding("utf8").on("data", (d: string) => (out += d)); const until = async (what: string, cond: () => boolean | Promise<boolean>, ms = 180_000) => { for ( const end = Date.now() + ms; Date.now() < end; await new Promise((r) => setTimeout(r, 500)) ) if (await cond()) return; throw new Error(`timed out waiting for ${what}:\n${strip(out)}`); }; await until("the registry to start", () => /url\s+http:\/\/\S+/.test(out)); const own = /url\s+(http:\/\/\S+)/ .exec(out)![1]! .replace(/\/$/, "") .replace("//localhost", "//127.0.0.1"); // (its jobs, which the packed app keeps: said a moment after the url, once the worker is up) await until("its jobs", () => /jobs\s+(recurring|no recurring)/.test(out)); const front = base ? ( await startServerInfo( keep, codebase(tempDir("registry front"), "front").dir, "tok", "--proxy", `${base}=${own.slice(0, -base.length)}`, ) ).url : undefined; const url = front ? `${front}${base}` : own; const page = async (p: string, cookie?: string) => { console.log(`reading ${p}`); const got = cookie ? await fetch(`${url}${p}`, { headers: { cookie } }).then(async (r) => ({ status: r.status, html: await r.text(), })) : await uiPage(`${url}${p}`, 30_000); assert.equal(got.status, 200, `${p}: ${got.status}\n${strip(out)}`); return got.html.replaceAll("<!-- -->", ""); }; return { url, own, until, page, out: () => strip(out) }; }
uses
- tcmts.cli.test.e2e.contributions.Keep
- tcmts.cli.test.e2e.contributions.uiPage
- tcmts.cli.test.e2e.examples.FakeAtproto
- tcmts.cli.test.e2e.harness.plainEnv
- tcmts.cli.test.e2e.harness.strip
- tcmts.cli.test.e2e.harness.tcmBin
- tcmts.cli.test.e2e.harness.tempDir
- tcmts.cli.test.e2e.sync.codebase
- tcmts.cli.test.e2e.sync.startServerInfo