startTests
uses node:child_process
Run tests as tcm test <names> does (all of them, without names; the tests under a namespace, or one): it's run, on
the branch the studio serves, what it says kept as it comes (testRuns). One at a time. The run's id.
import { HttpError } from "#codebase/tcmts/server"; import { editableCodebase, runsOfTests, tcmEnv } from "#codebase/tcmts/studio"; import type { TestRun } from "#codebase/tcmts/studio"; import { spawn } from "node:child_process"; import { stripVTControlCharacters } from "node:util"; export async function startTests(names: string[]): Promise<string> { const cb = editableCodebase(); if (runsOfTests.some((r) => r.ended === undefined)) throw new HttpError(409, "Tests are running already: one run at a time."); for (const n of names) if (!/^[\w$.-]+$/.test(n)) throw new HttpError(400, `${n} isn't a name.`); const env: NodeJS.ProcessEnv = { ...tcmEnv(), NO_COLOR: "1" }; const run: TestRun = { id: Math.random().toString(36).slice(2, 10), names, started: Date.now(), lines: [], }; runsOfTests.push(run); while (runsOfTests.length > 5) runsOfTests.shift(); const child = spawn(process.execPath, [process.argv[1]!, "test", ...names], { cwd: cb.lay.root, env, }); let rest = ""; const said = (chunk: Buffer) => { rest += stripVTControlCharacters(chunk.toString("utf8")); const lines = rest.split("\n"); rest = lines.pop()!; run.lines.push(...lines); if (run.lines.length > 2000) run.lines.splice(0, run.lines.length - 2000); }; child.stdout.on("data", said); child.stderr.on("data", said); child.on("close", (code) => { if (rest) run.lines.push(rest); run.code = code ?? 1; run.ended = Date.now(); }); return run.id; }
uses
- tcmts.server.HttpError
- tcmts.studio.TestRun
- tcmts.studio.editableCodebase
- tcmts.studio.runsOfTests
- tcmts.studio.tcmEnv