testBuildDuringStart
A build of the app tcm start serves, while it serves it (two at once, each replacing it), doesn't break
serving: it reads the build before or the one after, whole; and pruning leaves the build it serves
import { plainEnv, tcmBin, tcmInBackground, withChildren } from "#codebase/tcmts/cli/test/e2e/harness"; import { get, loadTab, setUp, waitFor } from "#codebase/tcmts/cli/test/e2e/prod"; import assert from "node:assert/strict"; import { spawn } from "node:child_process"; export const testBuildDuringStart = () => withChildren(async (keep) => { const { dir, tcm, scratch } = setUp(); scratch(`// tcm: namespace app export async function greeting(name: string): Promise<string> { return "hello " + name + " from " + process.pid; } export async function main() { document.querySelector("#app")!.textContent = await greeting("ada"); } `); tcm("add"); tcm("build", "app.main"); const child = keep( spawn(process.execPath, [tcmBin(), "start", "app.main", "--port", "0"], { cwd: dir, env: plainEnv(), }), ); let out = ""; child.stdout!.setEncoding("utf8").on("data", (d: string) => (out += d)); child.stderr!.setEncoding("utf8").on("data", (d: string) => (out += d)); await waitFor(() => /url\s+http:\/\/\S+/.test(out)); const url = /url\s+(http:\/\/\S+)/.exec(out)![1]!; let building = true; const pages: number[] = []; const reading = (async () => { while (building) pages.push((await get(url)).status); })(); const made = await Promise.all( [1, 2].map(() => tcmInBackground(keep, dir, "build", "app.main", "--force")), ); building = false; await reading; for (const m of made) assert.equal(m.status, 0, m.out); assert.ok(pages.length > 0); assert.deepEqual([...new Set(pages)], [200], `pages: ${pages.join(" ")}\n${out}`); const tab = await loadTab(url); assert.equal((await get(new URL(tab.asset, url))).status, 200); tcm("apps", "prune", "--keep", "0"); assert.equal((await get(url)).status, 200, "the build it serves stays"); assert.equal((await get(new URL(tab.asset, url))).status, 200, "and its assets"); })