Ctrl K
ComunidadGuías…

vitest.config.mts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import path from "node:path";
import { fileURLToPath } from "node:url";
import { playwright } from "@vitest/browser-playwright";
import { configDefaults, defineConfig } from "vitest/config";

const dirname = path.dirname(fileURLToPath(import.meta.url));

// Repeated into each project below, deliberately. `resolve.alias` is **not**
// inherited by inline projects - a project that omits it resolves no `@/...`
// import at all, and the failure reads as a missing module rather than as a
// missing alias.
const alias = { "@": path.resolve(dirname, "./src") };

// Anything ending `.browser.test.ts(x)` belongs to the second project. The unit
// project's own `src/**/*.test.{ts,tsx}` matches those files too - `*` spans
// dots - so the two are separated by an exclude rather than by the include
// patterns being disjoint. `configDefaults.exclude` is spread back in because
// setting `exclude` replaces the defaults outright, and dropping them would
// walk `node_modules` looking for tests.
const BROWSER_TESTS = "src/**/*.browser.test.{ts,tsx}";

// Code that only ever runs on the server - the map renderer, the middleware,
// route handlers and the modules behind them - is tested in Node, where `fetch`,
// `AbortSignal` and `Response` are the ones it runs against in production rather
// than jsdom's. A project of its own, because the unit project's setup file
// patches a `window` that Node does not have.
const NODE_TESTS = [
  "src/map-renderer/**/*.test.ts",
  "src/proxy.test.ts",
  "src/next-config.test.ts",
  "src/app/robots.test.ts",
  "src/app/layout.test.ts",
  "src/app/healthz/route.test.ts",
  "src/lib/api-proxy.test.ts",
  "src/lib/api/config.server.test.ts",
  "src/lib/runtime-config.test.ts",
];

export default defineConfig({
  resolve: { alias },
  test: {
    projects: [
      {
        resolve: { alias },
        test: {
          name: "unit",
          environment: "jsdom",
          include: ["src/**/*.test.{ts,tsx}"],
          exclude: [...configDefaults.exclude, BROWSER_TESTS, ...NODE_TESTS],
          // Scoped to this project, and that is the point rather than tidiness.
          // `vitest.setup.ts` is a jsdom patch kit - a no-op `ResizeObserver`, a
          // `matchMedia` that always answers false, pointer-capture no-ops.
          // Root `setupFiles` *are* inherited by projects, so left at the root
          // it would load into the real browser below and override working
          // implementations with stubs, breaking precisely the behaviour a real
          // browser was brought in to test.
          setupFiles: ["./vitest.setup.ts"],
        },
      },
      {
        resolve: { alias },
        test: {
          name: "node",
          environment: "node",
          include: NODE_TESTS,
          exclude: [...configDefaults.exclude, BROWSER_TESTS],
          setupFiles: ["./vitest.setup.node.ts"],
        },
      },
      {
        resolve: { alias },
        test: {
          name: "browser",
          include: [BROWSER_TESTS],
          setupFiles: ["./vitest.setup.browser.ts"],
          browser: {
            enabled: true,
            headless: true,
            provider: playwright(),
            instances: [{ browser: "chromium" }],
          },
        },
      },
    ],
    coverage: {
      provider: "v8",
      reporter: ["text", "html"],
      // Every layer is in scope, so "coverage is fine" says something about the
      // layers where error handling and stale state go wrong, not only about `lib/`.
      include: [
        "src/lib/**/*.{ts,tsx}",
        "src/hooks/**/*.{ts,tsx}",
        "src/contexts/**/*.{ts,tsx}",
        "src/components/**/*.{ts,tsx}",
        "src/app/**/*.{ts,tsx}",
        "src/proxy.ts",
        "src/map-renderer/**/*.ts",
      ],
      exclude: [
        // Vendored from shadcn/ui and deliberately kept close to upstream, so its
        // coverage number would measure how much of someone else's library this app
        // happens to render rather than anything about this app.
        "src/components/ui/**",
      ],
      // Floors, not targets, checked by `npm run test:coverage` - CI does not run it.
      // Set just under the current numbers so a real drop fails the run without
      // ordinary movement doing so. Raise them as coverage grows; lowering one to
      // make a run pass is the thing they exist to prevent.
      //
      // The global numbers look low because `components/` and `app/` are in scope and
      // almost entirely untested. That is deliberate: the scope makes the gap *visible*
      // in the report rather than flattering the headline figure. The per-directory
      // floors below are what actually hold the tested layers to account.
      thresholds: {
        statements: 24,
        branches: 19,
        functions: 18,
        lines: 23,
        "src/lib/**": {
          statements: 60,
          branches: 70,
          functions: 45,
          lines: 60,
        },
        "src/hooks/**": {
          statements: 42,
          branches: 32,
          functions: 38,
          lines: 44,
        },
        "src/contexts/**": {
          statements: 80,
          branches: 60,
          functions: 78,
          lines: 82,
        },
      },
    },
  },
});