/** Level-aware `wrnexus test` runner with Bun and optional Playwright backends. */ import { existsSync, readdirSync, readFileSync } from "node:fs"; import { spawn, type ChildProcess } from "node:child_process"; import { join, relative, resolve } from "node:path"; export const TEST_LEVELS = [ "unit", "component", "api", "browser", "visual", "accessibility", "performance", ] as const; export type TestLevel = (typeof TEST_LEVELS)[number]; export interface TestCommandPlan { command: string; args: string[]; cwd: string; level?: TestLevel; files: string[]; setup?: { command: string; args: string[] }; } function shardFiles(files: string[], value?: string): string[] { if (!value) return files; const match = /^(\d+)\/(\d+)$/.exec(value); if (!match) throw new Error("WRN-TEST-SHARD: expected --shard=/"); const index = Number(match[1]); const total = Number(match[2]); if (index < 1 || total < 1 || index > total) throw new Error("WRN-TEST-SHARD: index must be between 1 and total"); return files.filter((_file, position) => position % total === index - 1); } function testFiles(root: string): string[] { const files: string[] = []; const walk = (directory: string): void => { if (!existsSync(directory)) return; for (const entry of readdirSync(directory, { withFileTypes: true })) { if (["node_modules", "dist", ".wrnexus", "coverage"].includes(entry.name)) continue; const path = join(directory, entry.name); if (entry.isDirectory()) walk(path); else if (/\.(?:test|spec)\.[cm]?[jt]sx?$/i.test(entry.name)) files.push(path); } }; for (const directory of ["app", "test", "tests"]) walk(join(root, directory)); return files.sort(); } function hasPlaywright(root: string): boolean { if ( ["playwright.config.ts", "playwright.config.js", "playwright.config.mjs"].some((file) => existsSync(join(root, file)), ) ) return true; try { const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); return Boolean( manifest.dependencies?.["@playwright/test"] || manifest.devDependencies?.["@playwright/test"], ); } catch { return false; } } export function createTestPlan(appRoot: string, args: string[]): TestCommandPlan { const root = resolve(appRoot); const level = args.find((value): value is TestLevel => TEST_LEVELS.includes(value as TestLevel)); const watch = args.includes("--watch"); const shard = args.find((value) => value.startsWith("--shard="))?.slice(8); const browsers = (args.find((value) => value.startsWith("--browsers="))?.slice(11) ?? "chromium") .split(",") .filter(Boolean); const passthrough = args.filter( (value) => !value.startsWith("--profile=") && value !== "--watch" && value !== appRoot && value !== level && !value.startsWith("--browsers=") && !value.startsWith("--shard=") && value !== "--install-browsers", ); if ((level === "browser" || level === "visual") && hasPlaywright(root)) { return { command: process.execPath, args: [ "x", "playwright", "test", ...(level === "visual" ? ["--grep", "@visual"] : []), ...browsers.flatMap((browser) => ["--project", browser]), ...(shard ? [`--shard=${shard}`] : []), "--reporter=line,html", ...passthrough, ], cwd: root, level, files: [], ...(args.includes("--install-browsers") ? { setup: { command: process.execPath, args: ["x", "playwright", "install", ...browsers] }, } : {}), }; } const pattern = level === "accessibility" ? /(?:accessibility|a11y)/i : level === "performance" ? /(?:performance|benchmark)/i : level ? new RegExp(level, "i") : null; const files = shardFiles( pattern ? testFiles(root).filter((file) => pattern.test(relative(root, file))) : [], shard, ); return { command: process.execPath, args: ["test", ...(watch ? ["--watch"] : []), ...(pattern ? files : []), ...passthrough], cwd: root, level, files, }; } export function runTests(appRoot: string, args: string[]): ChildProcess | null { const plan = createTestPlan(appRoot, args); if (plan.level && !plan.files.length && !plan.args.includes("playwright")) { console.error( `WRN-TEST-NO-FILES: no ${plan.level} tests found. Name a file or directory with '${plan.level}' under app/, test/, or tests/.`, ); process.exitCode = 1; return null; } const launch = () => spawn(plan.command, plan.args, { stdio: "inherit", cwd: plan.cwd }); if (plan.setup) { const setup = spawn(plan.setup.command, plan.setup.args, { stdio: "inherit", cwd: plan.cwd }); setup.on("exit", (code, signal) => { if (signal || code !== 0) { process.exitCode = code ?? 1; return; } const test = launch(); test.on("exit", (testCode, testSignal) => { if (!testSignal) process.exitCode = testCode ?? 0; }); }); return setup; } const child = launch(); child.on("exit", (code, signal) => { if (!signal) process.exitCode = code ?? 0; }); return child; }