/** * Vitest configuration for singularity-forge. * * Runs tests directly from TypeScript source — no esbuild pre-compilation needed. * Vitest handles TypeScript transformation via esbuild (bundled, not separate process). * * Coverage uses @vitest/coverage-v8 (same engine as c8, but integrated). * * Usage: * npx vitest run # run all tests once * npx vitest # watch mode * npx vitest run --changed # only tests affected by recent changes */ import { existsSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { defineConfig } from "vitest/config"; const __dirname = import.meta.dirname; export default defineConfig({ plugins: [ { name: "sf-resource-js-extension-resolver", enforce: "pre", resolveId(source, importer) { if ( !source.endsWith(".ts") || !source.includes("resources/extensions") ) { return null; } const importerPath = importer?.startsWith("file://") ? fileURLToPath(importer) : importer; const tsPath = source.startsWith("/") ? resolve(__dirname, source.slice(1)) : importerPath ? resolve(dirname(importerPath), source) : resolve(__dirname, source); const jsPath = tsPath.replace(/\.ts$/, ".js"); if (!existsSync(tsPath) && existsSync(jsPath)) return jsPath; return null; }, }, ], // ── TypeScript / module resolution ───────────────────────────────────────── // Vitest uses esbuild for TS transform (fast, bundled). We still set up // NodeNext module resolution and path aliases to match the project's tsconfig. resolve: { alias: { "@singularity-forge/coding-agent": resolve( __dirname, "packages/coding-agent/src/index.ts", ), "@singularity-forge/ai/oauth": resolve( __dirname, "packages/ai/src/utils/oauth/index.ts", ), "@singularity-forge/ai/bedrock-provider": resolve( __dirname, "packages/ai/src/bedrock-provider.ts", ), "@singularity-forge/ai": resolve( __dirname, "packages/ai/src/index.ts", ), "@singularity-forge/agent-core": resolve( __dirname, "packages/agent-core/src/index.ts", ), "@singularity-forge/tui": resolve( __dirname, "packages/tui/src/index.ts", ), "@singularity-forge/native/ast": resolve( __dirname, "packages/native/src/ast/index.ts", ), "@singularity-forge/native/clipboard": resolve( __dirname, "packages/native/src/clipboard/index.ts", ), "@singularity-forge/native/diff": resolve( __dirname, "packages/native/src/diff/index.ts", ), "@singularity-forge/native/edit": resolve( __dirname, "packages/native/src/edit/index.ts", ), "@singularity-forge/native/fd": resolve( __dirname, "packages/native/src/fd/index.ts", ), "@singularity-forge/native/forge-parser": resolve( __dirname, "packages/native/src/forge-parser/index.ts", ), "@singularity-forge/native/glob": resolve( __dirname, "packages/native/src/glob/index.ts", ), "@singularity-forge/native/grep": resolve( __dirname, "packages/native/src/grep/index.ts", ), "@singularity-forge/native/highlight": resolve( __dirname, "packages/native/src/highlight/index.ts", ), "@singularity-forge/native/html": resolve( __dirname, "packages/native/src/html/index.ts", ), "@singularity-forge/native/image": resolve( __dirname, "packages/native/src/image/index.ts", ), "@singularity-forge/native/json-parse": resolve( __dirname, "packages/native/src/json-parse/index.ts", ), "@singularity-forge/native/ps": resolve( __dirname, "packages/native/src/ps/index.ts", ), "@singularity-forge/native/stream-process": resolve( __dirname, "packages/native/src/stream-process/index.ts", ), "@singularity-forge/native/text": resolve( __dirname, "packages/native/src/text/index.ts", ), "@singularity-forge/native/truncate": resolve( __dirname, "packages/native/src/truncate/index.ts", ), "@singularity-forge/native/ttsr": resolve( __dirname, "packages/native/src/ttsr/index.ts", ), "@singularity-forge/native/xxhash": resolve( __dirname, "packages/native/src/xxhash/index.ts", ), "@singularity-forge/native": resolve( __dirname, "packages/native/src/index.ts", ), "@singularity-forge/rpc-client": resolve( __dirname, "packages/rpc-client/src/index.ts", ), }, }, test: { // ── File patterns ───────────────────────────────────────────────────────── // Files without vitest imports (standalone test scripts that run assertions // directly at module load time — these are skipped by the old node --test // runner and must be excluded here too to avoid "No test suite found" errors. include: [ "src/tests/**/*.test.ts", "src/tests/**/*.test.mjs", "src/resources/extensions/sf/tests/**/*.test.ts", "src/resources/extensions/sf/tests/**/*.test.mjs", "src/resources/extensions/sf/learning/*.test.mjs", "src/resources/extensions/sf-permissions/tests/**/*.test.ts", "src/resources/extensions/shared/tests/**/*.test.ts", "src/resources/extensions/claude-code-cli/tests/**/*.test.ts", "src/resources/extensions/github-sync/tests/**/*.test.ts", "src/resources/extensions/universal-config/tests/**/*.test.ts", "src/resources/extensions/voice/tests/**/*.test.ts", "src/resources/extensions/vectordrive/tests/**/*.test.ts", "src/resources/extensions/mcp-client/tests/**/*.test.ts", "src/resources/extensions/async-jobs/*.test.ts", "src/resources/extensions/browser-tools/tests/*.test.mjs", "packages/coding-agent/src/**/*.test.ts", "packages/ai/src/**/*.test.ts", "packages/agent-core/src/**/*.test.ts", "packages/tui/src/**/*.test.ts", "packages/daemon/src/**/*.test.ts", "packages/rpc-client/src/**/*.test.ts", "packages/native/src/**/*.test.mjs", "web/lib/**/*.test.ts", "scripts/*.test.mjs", ], // ── Timeouts ────────────────────────────────────────────────────────────── // Cold vitest+esbuild module-graph import takes 16-25s on this repo // (dynamic imports of captures.js and friends). 30s tests-timeout was // racing the import phase, producing spurious 30s failures across // dev-engine, ensure-db-open, workflow-tools, sf-tools, verification-gate, // etc. 60s gives the import time to settle without losing real-bug signal. testTimeout: 60_000, hookTimeout: 60_000, // ── Pool: forks = one Node process per test file (best for Node.js tests) ─ pool: "forks", // Single worker in CI; parallel in dev for speed singleFork: process.env.CI === "true", // ── Coverage ────────────────────────────────────────────────────────────── coverage: { provider: "v8", reporter: ["text", "lcov"], exclude: [ "src/resources/extensions/sf/tests/**", "src/tests/**", "scripts/**", "rust-engine/**", "node_modules/**", "dist/**", "dist-test/**", "web/**", ], thresholds: { statements: 40, lines: 40, branches: 20, functions: 20, "src/resources/extensions/sf/auto/**": { statements: 60, lines: 60, branches: 40, functions: 60, }, "src/resources/extensions/sf/uok/**": { statements: 60, lines: 60, branches: 40, functions: 60, }, }, }, }, });