testSuitesFollowMethodsAndConstantsTheyRead

tcmts.cli.test.e2e.suites.testSuitesFollowMethodsAndConstantsTheyRead · #xibxyf4r · term

What a suite ran, finer than definitions where a definition is big: a class by the methods it used (a change to another of its methods keeps the result), and a written-out constant only when code that ran reads it (one that was only loaded keeps it).

import { okIn, tcmIn, tempDir } from "#codebase/tcmts/cli/test/e2e/harness";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";

export const testSuitesFollowMethodsAndConstantsTheyRead = () => {
  const dir = tempDir("suites finer");
  const ok = (...args: string[]) => okIn(dir, ...args);
  const scratch = (ns: string, text: string) =>
    fs.writeFileSync(path.join(dir, "scratch.ts"), `// tcm: namespace ${ns}\n${text}`);
  ok("init");
  scratch(
    "greeter",
    `export const SUFFIX = "";
export const BANNER = "== greeter ==";
export const banner = () => BANNER;
export class Greeter {
  hello(name: string) { return \`hello, \${name}\${SUFFIX}\`; }
  shout(s: string) { return s.toUpperCase(); }
}
export const main = (...args: string[]) =>
  console.log(args[0] === "--banner" ? banner() : new Greeter().hello(args[0] ?? "world"));
export const manifest = { name: "greeter", bin: { greet: "main" }, suites: { greet: ["e2e"] } };
`,
  );
  ok("add");
  scratch(
    "greeter.e2e",
    `import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
export const testGreets = () => {
  const r = spawnSync(process.execPath, [process.env.GREET_BIN!, "tcm"], { encoding: "utf8" });
  assert.equal(r.stdout, "hello, tcm\\n");
};
`,
  );
  ok("add");
  assert.match(ok("test"), /suites: 1 passed, 0 failed\n/);
  const cached = /suites: 1 passed, 0 failed \(1 cached\)/;
  const ranAgain = /suites: 1 passed, 0 failed\n/;

  // a method of the class it didn't call
  scratch(
    "greeter",
    `export class Greeter {
  hello(name: string) { return \`hello, \${name}\${SUFFIX}\`; }
  shout(s: string) { return s.toUpperCase() + "!"; }
}
`,
  );
  ok("update");
  assert.match(ok("test"), cached, "shout didn't run");
  // a constant loaded (banner's module imports it) but read by nothing that ran
  scratch("greeter", `export const BANNER = "~~ greeter ~~";\n`);
  ok("update");
  assert.match(ok("test"), cached, "BANNER was only loaded");

  // the method it called, the same output written another way
  scratch(
    "greeter",
    `export class Greeter {
  hello(name: string) { return "hello, " + name + SUFFIX; }
  shout(s: string) { return s.toUpperCase() + "!"; }
}
`,
  );
  ok("update");
  assert.match(ok("test"), ranAgain, "hello ran");
  // a constant that method reads: run again, so it fails
  scratch("greeter", `export const SUFFIX = "!";\n`);
  ok("update");
  const failed = tcmIn(dir, "test");
  assert.match(
    failed.out,
    /✗ greeter\.e2e\.testGreets[\s\S]*suites: 0 passed, 1 failed\n/,
    "hello reads SUFFIX",
  );
}

uses