runTestInScratch

tcmts.studio.runTestInScratch · #ixt5ah57 · term · runs on the server

uses node:util

Run one test a scratch file holds (path, text being what the file holds), as tcm test runs it, again: its outcome, as the notebook shows it under the test.

import { classify } from "#codebase/tcmts/cli/main";
import { isTestPath, runCached } from "#codebase/tcmts/cli/testing";
import { HttpError } from "#codebase/tcmts/server";
import { analyzedScratch, editableCodebase, scratchPath } from "#codebase/tcmts/studio";
import type { ScratchValue } from "#codebase/tcmts/studio";
import { stripVTControlCharacters } from "node:util";

export async function runTestInScratch(
  file: string,
  text: string,
  path: string,
): Promise<ScratchValue> {
  const cb = editableCodebase();
  const abs = scratchPath(cb, file, text);
  const a = analyzedScratch(cb, abs, text);
  if (a.diagnostics.length || a.errors.length)
    throw new HttpError(409, `${file} has problems: fix them first.`);
  const row = classify(cb, a.defs, a.namespace ?? "").find(
    (r) => r.path === path && isTestPath(r.path),
  );
  if (!row) throw new HttpError(404, `${file} has no test ${path}.`);
  const src = cb.source([...a.defs, ...a.watches]);
  const o = runCached(cb, [{ path: row.path, rec: row.def }], src, true)[0];
  if (!o) throw new HttpError(500, `${path} didn't run.`);
  const def = row.def as typeof row.def & { range?: { start: number; nameStart?: number } };
  return {
    line: text.slice(0, def.range?.nameStart ?? def.range?.start ?? 0).split("\n").length,
    ok: o.result.ok,
    value: o.result.ok
      ? `passes (${Math.round(o.result.ms)}ms)`
      : stripVTControlCharacters(o.result.message),
    test: path,
  };
}

uses

used by