Ctrl K
ComunidadGuías…

vitest.config.ts

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

Archivo original ↗Preguntar a KiBot
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import { fileURLToPath } from 'node:url'

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
      '@gw/edition': fileURLToPath(new URL('./src/server/edition/community.ts', import.meta.url)),
      // The empty catalogue, which is what a public build has. A test that
      // wants rows mocks this module; one that does not gets the honest
      // nothing rather than a fixture pretending to be a library.
      '@gw/catalog': fileURLToPath(new URL('./src/cloud/catalog/unavailable.ts', import.meta.url)),
      '@gw/billing-adapters': fileURLToPath(
        new URL('./src/cloud/billing/adapters/unavailable.ts', import.meta.url),
      ),
      '@gw/billing-conformance': fileURLToPath(
        new URL('./src/cloud/billing/conformance/index.ts', import.meta.url),
      ),
      '@gw/home': fileURLToPath(
        new URL('./src/components/home/community-home.tsx', import.meta.url),
      ),
      /**
       * What the next-intl plugin does in a Next build, done by hand here.
       *
       * Without it `getTranslations` has no configuration and throws, so
       * anything that renders a message would have to be tested against a mock
       * -- which would assert that the mock was called, not that the catalog
       * says what the test claims. With the alias, a test renders the real
       * German or English sentence out of the real messages/*.json.
       *
       * Only reachable for calls that pass an explicit locale: the other branch
       * of src/i18n/request.ts reads cookies() and headers(), which do not
       * exist outside a request. That is the same boundary production has.
       */
      'next-intl/config': fileURLToPath(new URL('./src/i18n/request.ts', import.meta.url)),
      /**
       * What Next resolves this to in a Server Component: the `react-server`
       * export condition, which is an empty module. Vitest resolves the
       * `default` one, and that is a bare `throw` -- so without this alias no
       * test can import anything marked server-only, and a marker meant to
       * catch a wrong import would decide what is testable.
       */
      'server-only': fileURLToPath(new URL('./node_modules/server-only/empty.js', import.meta.url)),
    },
  },
  test: {
    environment: 'jsdom',
    globals: true,
    setupFiles: ['./vitest.setup.ts'],
    // The shell scripts an operator runs are covered here too: a backup that
    // fails quietly is a bug like any other, and asserting it takes a shell and
    // a fake `docker`, not a browser.
    include: ['src/**/*.{test,spec}.{ts,tsx}', 'scripts/**/*.test.mjs'],
    // Database tests live in their own suite and their own CI job -- they need
    // a real Postgres with migrations applied. See vitest.db.config.ts.
    exclude: ['**/node_modules/**', 'src/**/*.db.test.ts'],
    coverage: {
      provider: 'v8',
      reporter: ['text', 'lcov'],
      // Deliberately not a global target: coverage thresholds only guard the
      // zones where a bug is silent. A repo-wide number just breeds alibi tests.
      include: ['src/domain/**', 'src/features/**', 'src/i18n/**'],
      // Modules whose tests live in another suite. Counting them here would
      // report them as untested and make the threshold measure the wrong thing
      // -- and lowering the threshold to accommodate that would quietly weaken
      // it for the pure logic it exists to protect.
      exclude: [
        // Covered by the `db` suite (*.db.test.ts) against a real Postgres,
        // which is a required check in its own right. Their invariants -- RLS,
        // composite FKs, compare-and-swap -- cannot be asserted without one.
        'src/domain/agenda/access.ts',
        'src/domain/agenda/repo.ts',
        'src/domain/workshop/repo.ts',
        // The library read and the folder tree: the same subject, split out of
        // repo.ts when it outgrew it. Every question they answer is "which rows
        // may this actor see", which is RLS plus a recursive path query -- there
        // is nothing here a unit test could be wrong about on its own.
        'src/domain/workshop/library.ts',
        'src/domain/workshop/folders.ts',
        'src/domain/workshop/collaborators.ts',
        // Folder-level collaboration: the same shape one level up. Its pure
        // half -- who holds what, who may hand on what -- is in
        // folder-access.ts precisely so that it stays counted here, which is
        // where a wrong answer silently grants or denies access.
        'src/domain/workshop/folder-collaborators.ts',
        // The OAuth flow's rows. What makes it safe is not in this file: the
        // single-use code is a `where used_at is null` inside an UPDATE and the
        // rotation is one too, so what is worth asserting is what Postgres does
        // under a race -- which needs Postgres. The decisions live in
        // oauth/rules.ts and are counted here.
        'src/domain/oauth/repo.ts',
        // The same, for guests. Its pure half -- when a link expires, what counts
        // as an address -- was split into share-rules.ts precisely so that it
        // stays counted here: a wrong answer from validUntil silently grants or
        // denies access, which is exactly what this threshold is for.
        'src/domain/workshop/share-links.ts',
        // Membership crosses the auth-role boundary -- member rows behind RLS,
        // e-mail addresses behind a role the application cannot join to. That
        // separation is the thing worth asserting, and it does not exist
        // without a database.
        'src/domain/tenant/members.ts',
        'src/domain/tenant/membership.ts',
        'src/domain/tenant/tokens.ts',
        // Type declarations: nothing to execute.
        '**/types.ts',
        // Browser glue, covered by Playwright: a dnd-kit coordinate getter and a
        // hook wiring dnd-kit's events to a document have no meaningful unit
        // surface. What use-agenda-drag actually has to get right -- the first
        // delta is a position, the first collision is measured from the handle,
        // `over` is one event behind -- is only observable in a real browser, and
        // the five drag tests in e2e/agenda.spec.ts are where it is observed.
        //
        // The sentence the hook has read aloud is NOT here: describeProjection is
        // pure, a wrong answer is silent to everybody who can see the screen, and
        // it has its own test.
        'src/features/agenda/keyboard.ts',
        'src/features/agenda/use-agenda-drag.ts',
        // The same category, and it only appears on this list because Vitest 4
        // started counting files no test imports -- under 3 it was never
        // measured at all, so this restores the intended scope rather than
        // narrowing it. What the hook does is asserted through
        // agenda-surface.test.tsx and by Playwright, which is where a React
        // hook's behaviour is legible.
        'src/features/agenda/use-local-document.ts',
        // A hand-written WebSocket client with reconnect backoff, and the hook
        // that drives it. What matters about them -- that an edit reaches the
        // other browser -- is asserted end to end by Playwright and by the
        // collaboration suite against a real server; a mocked socket here
        // would only assert that the mock was called.
        'src/features/collab/provider.ts',
        'src/features/collab/use-collab-document.ts',
        // Request-scoped wiring: reads cookies(), headers() and the session.
        // The branching worth guarding lives in resolve.ts, which is pure.
        'src/i18n/request.ts',
        'src/i18n/catalogs.ts',
      ],
      thresholds: {
        'src/domain/**': { statements: 80, branches: 80, functions: 80, lines: 80 },
        'src/features/**': { statements: 80, branches: 80, functions: 80, lines: 80 },
        // Language resolution is exactly the silent branching these thresholds
        // exist for: every wrong answer renders a readable page in the wrong
        // language, which no other check notices.
        'src/i18n/**': { statements: 80, branches: 80, functions: 80, lines: 80 },
      },
    },
  },
})