prepareTestRun
uses node:path
Prepare a Vitest run of these tests: the request a child tcm process runs (tcm internal-vitest <file>), and
where its results will be. The debugger runs it too, under its own control.
import type { Codebase } from "#codebase/tcmts/cli/codebase"; import { provideTool, toolModule } from "#codebase/tcmts/cli/lint"; import { Placement } from "#codebase/tcmts/cli/placement"; import type { Request, TestEntry } from "#codebase/tcmts/cli/vitest"; import { exportId } from "#codebase/tcmts/core/hash"; import type { DefRecord } from "#codebase/tcmts/core/types"; import { materialize, moduleFile } from "#codebase/tcmts/loader"; import type { DefSource } from "#codebase/tcmts/loader"; import { ensureExternals } from "#codebase/tcmts/loader/packages"; import fs from "node:fs"; import path from "node:path"; export function prepareTestRun( cb: Codebase, tests: { hash: string; componentHash: string }[], src: DefSource, ): { requestFile: string; results: string } { // (Vitest installed with the packages the tests import) const vitestModule = toolModule(cb, "vitest"); materialize( tests.map((t) => t.hash), src, cb.lay, vitestModule ? { also: [{ module: vitestModule, subpath: "", export: "*" }] } : {}, ); const vitest = provideTool(cb, "vitest"); // what's not in the store yet (an unsaved scratch file's definitions), so the child sees it too const unsaved = new Map<string, DefRecord>(); const stack = tests.map((t) => t.hash); while (stack.length) { const h = stack.pop()!; if (unsaved.has(h) || cb.store.hasDef(h)) continue; const rec = src.get(h); if (!rec) continue; unsaved.set(h, rec); for (const m of src.members(rec.componentHash)) for (const s of m.spans) if (s.hash) stack.push(s.hash); } const placement = new Placement(cb, (h) => src.get(h)); const browserWhy = new Map(tests.map((t) => [t.hash, placement.testBrowserWhy(t.hash)])); const entry = (t: { hash: string; componentHash: string }): TestEntry => { const why = browserWhy.get(t.hash); return { hash: t.hash, module: moduleFile(t.componentHash, src), export: exportId(t.hash), ...(why ? { browser: why } : {}), }; }; const inBrowser = tests.filter((t) => browserWhy.get(t.hash) !== undefined); const inNode = tests.filter((t) => !inBrowser.includes(t)); // (the browser's tools, installed together) if (inBrowser.length) { const both = ["@vitest/browser-playwright", "playwright"] .map((t) => toolModule(cb, t)) .filter((m) => m !== undefined); if (both.length) ensureExternals( cb.lay, both.map((module) => ({ module, subpath: "", export: "*" })), ); } const provider = inBrowser.length ? provideTool(cb, "@vitest/browser-playwright") : undefined; if (provider) provideTool(cb, "playwright"); const dir = path.join(cb.lay.tcmDir, "test"); fs.mkdirSync(dir, { recursive: true }); const request: Request = { root: cb.lay.root, vitest: vitest.dir, ...(provider ? { browser: { provider: provider.dir } } : {}), node: inNode.map(entry), browserTests: inBrowser.map(entry), unsaved: [...unsaved.values()], results: path.join(dir, `results-${process.pid}.json`), }; const requestFile = path.join(dir, `request-${process.pid}.json`); fs.writeFileSync(requestFile, JSON.stringify(request)); fs.rmSync(request.results, { force: true }); return { requestFile, results: request.results }; }
uses
- tcmts.cli.codebase.Codebase
- tcmts.cli.lint.provideTool
- tcmts.cli.lint.toolModule
- tcmts.cli.placement.Placement
- tcmts.cli.vitest.Request
- tcmts.cli.vitest.TestEntry
- tcmts.core.hash.exportId
- tcmts.core.types.DefRecord
- tcmts.loader.DefSource
- tcmts.loader.materialize
- tcmts.loader.moduleFile
- tcmts.loader.packages.ensureExternals