claude-code-router/build/run-tests.mjs

98 lines
3.1 KiB
JavaScript

import electron from "electron";
import { spawn, spawnSync } from "node:child_process";
import { existsSync, mkdtempSync, readdirSync, rmSync } from "node:fs";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const projectRoot = path.resolve(__dirname, "..");
const testsOutDir = path.join(projectRoot, ".test-dist");
const testProjects = {
architecture: { runtime: "node" },
cli: { runtime: "node" },
core: { runtime: "node-with-electron-fallback" },
electron: { runtime: "electron" },
ui: { runtime: "node" }
};
const requestedProjects = process.argv.slice(2);
const projects = requestedProjects.length === 0 ? Object.keys(testProjects) : requestedProjects;
for (const project of projects) {
if (!testProjects[project]) {
throw new Error(`Unknown test project: ${project}`);
}
}
for (const project of projects) {
await runProject(project);
}
async function runProject(project) {
const testFiles = findCompiledTests(path.join(testsOutDir, project, "test"));
if (testFiles.length === 0) {
console.log(`No ${project} tests found.`);
return;
}
const testHome = mkdtempSync(path.join(os.tmpdir(), `ccr-${project}-test-home-`));
const runtime = resolveRuntime(testProjects[project].runtime);
const executable = runtime === "electron" ? electron : process.execPath;
console.log(`\nRunning ${project} tests with ${runtime}...`);
try {
await new Promise((resolve, reject) => {
const child = spawn(executable, ["--test", ...testFiles], {
cwd: projectRoot,
env: {
...process.env,
CCR_INTERNAL_APP_DATA_DIR: path.join(testHome, "app-data"),
CCR_INTERNAL_HOME_DIR: testHome,
CCR_INTERNAL_USER_DATA_DIR: path.join(testHome, "user-data"),
HOME: testHome,
...(runtime === "electron" ? { ELECTRON_RUN_AS_NODE: "1" } : {})
},
stdio: "inherit"
});
child.on("error", reject);
child.on("exit", (code, signal) => {
if (signal) {
reject(new Error(`${project} tests exited from signal ${signal}`));
return;
}
if (code === 0) {
resolve();
return;
}
reject(new Error(`${project} tests exited with code ${code ?? 1}`));
});
});
} finally {
rmSync(testHome, { force: true, recursive: true });
}
}
function resolveRuntime(runtime) {
if (runtime !== "node-with-electron-fallback") {
return runtime;
}
const probe = spawnSync(process.execPath, [
"-e",
"const Database = require('better-sqlite3'); const db = new Database(':memory:'); db.close();"
], { stdio: "ignore" });
return probe.status === 0 ? "node" : "electron";
}
function findCompiledTests(dir) {
if (!existsSync(dir)) {
return [];
}
return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const file = path.join(dir, entry.name);
if (entry.isDirectory()) {
return findCompiledTests(file);
}
return entry.isFile() && entry.name.endsWith(".test.js") ? [file] : [];
}).sort();
}