testWebUiStopsWithTheServer
the web UI stops with the tcm serve that started it, however that ended: killed, its exit handlers never run
import { codebase, env, LIB, uiPage } from "#codebase/tcmts/cli/test/e2e/contributions"; import { strip, tcmBin, tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness"; import assert from "node:assert/strict"; import { execFileSync, spawn } from "node:child_process"; export const testWebUiStopsWithTheServer = async () => { const server = codebase(tempDir("contributions stop"), "served"); server.write(LIB); server.tcm("add"); await withChildren(async (keep) => { const child = keep( spawn(process.execPath, [tcmBin(), "serve", "--port", "0", "--token", "tok", "--public"], { cwd: server.dir, env: env(), }), ); let out = ""; child.stdout.setEncoding("utf8").on("data", (d: string) => (out += d)); child.stderr.setEncoding("utf8").on("data", (d: string) => (out += d)); const url = await new Promise<string>((resolve) => { const look = setInterval(() => { const m = /url\s+(https?:\/\/[\d.]+:\d+)/.exec(out); if (m) (clearInterval(look), resolve(m[1]!)); }, 50); }); assert.equal((await uiPage(`${url}/forge/people`)).status, 200); const ui = /ui\s+url\s+(https?:\/\/[\d.]+:(\d+))/.exec(strip(out)); assert.ok(ui, out); child.kill("SIGKILL"); const until = Date.now() + 15_000; let answers = true; while (answers && Date.now() < until) { await new Promise((r) => setTimeout(r, 250)); answers = await fetch(`${ui[1]}/forge/people`).then( () => true, () => false, ); } if (answers) // (left running: stop it, so the failure doesn't outlive the test) try { execFileSync("pkill", ["-f", `start app --port ${ui[2]}`]); } catch {} assert.ok(!answers, "the web UI stopped when its server was killed"); }); }