Trovella Wiki

Test Configuration

Vitest workspace setup, per-package configs, environment selection, coverage providers, and how Turborepo orchestrates test runs.

Workspace Configuration

The monorepo uses Vitest's workspace feature to discover and run tests across all packages. The root vitest.workspace.ts is minimal -- it globs for per-package configs:

// vitest.workspace.ts
import { defineWorkspace } from "vitest/config";

export default defineWorkspace(["apps/*/vitest.config.ts", "packages/*/vitest.config.ts"]);

Turborepo orchestrates test runs via the test and test:coverage scripts defined in each package's package.json:

{
  "scripts": {
    "test": "vitest run",
    "test:coverage": "vitest run --coverage"
  }
}

Per-Package Configs

Every package has its own vitest.config.ts. There are two patterns depending on whether the package needs a browser-like environment.

Node Environment (Most Packages)

Used by @repo/db, @repo/api, @repo/ai, @repo/mcp, @repo/search, @repo/auth, @repo/cache, @repo/logger, @repo/utils, @repo/validators:

import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    environment: "node",
    passWithNoTests: true,
    coverage: {
      provider: "v8",
      reporter: ["json", "json-summary", "text"],
      reportsDirectory: "./coverage",
    },
  },
});

jsdom Environment (Web App)

Used by apps/web for React component tests:

import react from "@vitejs/plugin-react";
import path from "node:path";
import { defineConfig } from "vitest/config";

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src"),
    },
  },
  test: {
    globals: true,
    environment: "jsdom",
    passWithNoTests: true,
    coverage: {
      provider: "v8",
      reporter: ["json", "json-summary", "text"],
      reportsDirectory: "./coverage",
    },
  },
});

Key differences from the node config:

  • environment: "jsdom" -- provides window, document, and other browser globals
  • @vitejs/plugin-react -- enables JSX transformation for React components
  • Path alias -- @ resolves to src/ to match the Next.js path alias convention

Extended Timeout (Database Package)

@repo/db has a 30-second test timeout because RLS integration tests connect to a real PostgreSQL instance, run migrations, and execute transactions:

test: {
  globals: true,
  environment: "node",
  passWithNoTests: true,
  testTimeout: 30_000, // RLS tests need real DB connections
  // ...coverage config
},

Common Config Options

passWithNoTests: true

Every package sets this flag. Without it, Vitest exits with code 1 when there are no test files in a package, which would fail CI for packages that legitimately have no tests yet. At baseline, six packages have zero test files.

globals: true

Enables global describe, it, expect, beforeAll, afterAll without imports. Every test file still imports from vitest explicitly for clarity and IDE support:

import { describe, expect, it } from "vitest";

Coverage Configuration

All packages use the same coverage setup:

OptionValuePurpose
provider"v8"V8's built-in coverage instrumentation -- faster than Istanbul's source-code rewriting
reporter["json", "json-summary", "text"]json for CLI tool aggregation, json-summary for quick stats, text for terminal output
reportsDirectory"./coverage"Each package writes to its own coverage/ dir, consumed by trovella-test-audit

The json reporter produces coverage-final.json in Istanbul format, which trovella-test-audit consumes via istanbul-lib-coverage for cross-package merging.

Adding Tests to a New Package

When creating a new @repo/* package:

  1. Add a vitest.config.ts using the node environment template above
  2. Add test and test:coverage scripts to package.json
  3. Create a src/__tests__/ directory for test files
  4. Verify passWithNoTests: true is set (CI will fail otherwise if there are no test files yet)

This is documented in ADR-011 (package creation) and enforced manually during code review.

On this page