testKeptBuildWithoutItsCode

tcmts.cli.test.e2e.prod.testKeptBuildWithoutItsCode · #pgsl7usj · term

a kept build whose code the codebase no longer has (the web UI's, its codebase copied in again when tcm changes): its tabs are told to reload (410), and the server keeps answering

import { plainEnv, tcmBin, withChildren } from "#codebase/tcmts/cli/test/e2e/harness";
import { call, setUp, waitFor } from "#codebase/tcmts/cli/test/e2e/prod";
import { hashOf } from "#codebase/tcmts/cli/test/e2e/web";
import assert from "node:assert/strict";
import { spawn } from "node:child_process";
import type { ChildProcess } from "node:child_process";
import fs from "node:fs";
import path from "node:path";

export const testKeptBuildWithoutItsCode = () =>
  withChildren(async (keep) => {
    const app = (greeting: string) => `// tcm: namespace app
import { hostname } from "node:os";
export async function greeting(name: string): Promise<string> { return "${greeting} " + name + " from " + hostname(); }
export async function main() { document.querySelector("#app")!.textContent = await greeting("ada"); }
`;
    // the old codebase's build, kept beside a new codebase that never had its code
    const old = setUp();
    old.scratch(app("hello"));
    old.tcm("add");
    old.tcm("build", "app.main");
    const stale = hashOf(old.dir, "app.greeting");
    const { dir, tcm, scratch } = setUp();
    scratch(app("hi"));
    tcm("add");
    tcm("build", "app.main");
    const apps = (d: string) => path.join(d, ".tcm", "apps");
    for (const b of fs.readdirSync(apps(old.dir)))
      if (fs.existsSync(path.join(apps(old.dir), b, "tcm-app.json")))
        fs.cpSync(path.join(apps(old.dir), b), path.join(apps(dir), b), { recursive: true });

    const child: ChildProcess = 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]!;

    assert.equal((await call(url, stale, ["ada"])).status, 410, "the old build's tab reloads");
    assert.equal(child.exitCode, null, "the server is still running");
    assert.match((await call(url, hashOf(dir, "app.greeting"), ["ada"])).body, /^"hi ada from /);
  })

uses