testPollsExample

tcmts.cli.test.e2e.examples.testPollsExample · #bnw7a5ab · term

the polls example builds, passes its tests, and runs in a browser

import { CHROME, pageText } from "#codebase/tcmts/cli/test/browser";
import { env, exampleDir, hashOf } from "#codebase/tcmts/cli/test/e2e/examples";
import { tcmBin, tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness";
import { POLLS } from "#codebase/tcmts/fixtures";
import assert from "node:assert/strict";
import { spawn, spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { stripVTControlCharacters } from "node:util";

export const testPollsExample = async () => {
  if (!CHROME) return console.log("skipped: no Chrome");
  const dir = path.join(tempDir("examples"), "polls");
  const setup = spawnSync(path.join(exampleDir(POLLS), "setup.sh"), [dir], {
    env: env(),
    encoding: "utf8",
  });
  const out = stripVTControlCharacters(setup.stdout + setup.stderr);
  assert.equal(setup.status, 0, out);
  assert.match(out, /9 passed, 0 failed/);
  assert.ok(
    fs.existsSync(path.join(dir, "scratch.ts")) && !fs.existsSync(path.join(dir, "server.ts")),
    "only the playground is left as a file",
  );

  await withChildren(async (keep) => {
    const child = keep(
      spawn(process.execPath, [tcmBin(), "start", "polls.main", "--port", "0"], {
        cwd: dir,
        env: env(),
      }),
    );
    let log = "";
    child.stdout.setEncoding("utf8").on("data", (d: string) => (log += d));
    child.stderr.setEncoding("utf8").on("data", (d: string) => (log += d));
    for (const end = Date.now() + 60000; !/url\s+http/.test(log) && Date.now() < end;)
      await new Promise((r) => setTimeout(r, 100));
    const url = /url\s+(http:\/\/\S+)/.exec(log)?.[1];
    assert.ok(url, log);

    const call = async (name: string, args: unknown[]) => {
      const r = await fetch(new URL(`/__tcm/rpc/${hashOf(name, dir)}`, url), {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify(args),
      });
      assert.equal(r.status, 200, await r.clone().text());
      return r.json();
    };
    const id = await call("polls.createPoll", ["Tabs or spaces?", ["tabs", "spaces"], 5]);
    await call("polls.vote", [id, 0]);

    // the page lists the poll and streams its tally from the server
    const text = await pageText(url!, "main", (t) => /tabs is ahead/.test(t));
    assert.match(text, /Tabs or spaces\?/);
    assert.match(text, /tabs\s+█+\s+100% \(1\)/);
  });
}

uses