testPushDeploys

tcmts.cli.test.e2e.prod.testPushDeploys · #zu4xmrvx · term

tcm push deploys: a running tcm start on the other side builds and switches

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

export const testPushDeploys = () =>
  withChildren(async (keep) => {
    const server = tempDir("deploy-server");
    const laptop = tempDir("deploy-laptop");
    const at = (cwd: string, ...args: string[]) => {
      const r = spawnSync(process.execPath, [tcmBin(), ...args], { cwd, encoding: "utf8", env: plainEnv() });
      if (r.status !== 0) throw new Error(`tcm ${args.join(" ")} in ${cwd}: ${r.stdout}${r.stderr}`);
      return r.stdout;
    };
    at(server, "init");
    at(laptop, "init");
    const app = (version: string) =>
      fs.writeFileSync(
        path.join(laptop, "scratch.ts"),
        `// tcm: namespace web
import { hostname } from "node:os";
export async function hello(): Promise<string> { return "${version} " + hostname(); }
export async function main() { document.body.textContent = await hello(); }
`,
      );
    app("v1");
    at(laptop, "add");
    at(laptop, "remote", "add", "prod", server);
    assert.match(at(laptop, "push", "prod"), /pushed prod\/main/, "a fresh server's empty branch can be pushed to");

    const child: ChildProcess = keep(spawn(process.execPath, [tcmBin(), "start", "web.main", "--port", "0"], { cwd: server, 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]!;
    const v1 = await loadTab(url);
    assert.match((await call(url, v1.endpoint, [])).body, /^"v1 /);

    app("v2");
    at(laptop, "update");
    assert.match(at(laptop, "push", "prod"), /sent \d+ definition/);
    await waitFor(() => /deployed web\.main/.test(out));
    const v2 = await loadTab(url);
    assert.match((await call(url, v2.endpoint, [])).body, /^"v2 /);
    assert.match((await call(url, v1.endpoint, [])).body, /^"v1 /, "tabs opened before the push keep working");
  })

uses