runTestsWithVitest

tcmts.cli.vitest.runTestsWithVitest · #tfn4sg5y · term · runs on the server

uses node:child_process

Run test definitions with Vitest: in Node, or in a browser for tests that need one.

import type { Codebase } from "#codebase/tcmts/cli/codebase";
import { prepareTestRun } from "#codebase/tcmts/cli/vitest";
import type { DefSource, TestRun } from "#codebase/tcmts/loader";
import { spawnSync } from "node:child_process";
import fs from "node:fs";

export function runTestsWithVitest(
  cb: Codebase,
  tests: { hash: string; componentHash: string }[],
  src: DefSource,
): TestRun[] {
  if (!tests.length) return [];
  const { requestFile, results } = prepareTestRun(cb, tests, src);
  const r = spawnSync(process.execPath, [process.argv[1]!, "internal-vitest", requestFile], {
    cwd: cb.lay.root,
    encoding: "utf8",
    timeout: 10 * 60_000,
    env: { ...process.env, NO_COLOR: "1" },
    // (fd 3: where it says it's waiting for a slot, `vitestChild`: this one's stderr, not stdout, which an MCP server
    // running this speaks on)
    stdio: ["ignore", "pipe", "pipe", 2],
  });
  // TCM_KEEP_TEST_RUN=1 leaves the request in .tcm/test, to run the child by hand (`tcm internal-vitest <it>`)
  if (!process.env.TCM_KEEP_TEST_RUN) fs.rmSync(requestFile, { force: true });
  let done: TestRun[] = [];
  try {
    done = JSON.parse(fs.readFileSync(results, "utf8")) as TestRun[];
  } catch {
    // no results: the runner itself failed
  }
  fs.rmSync(results, { force: true });
  const why = (r.stderr || r.stdout || "").trim().split("\n").slice(-8).join("\n");
  return tests.map(
    (t) =>
      done.find((d) => d.hash === t.hash) ?? {
        hash: t.hash,
        ok: false,
        message: `no result: the test runner failed${why ? `\n${why}` : ""}`,
        output: "",
        ms: 0,
        infrastructure: true,
      },
  );
}

uses

used by