◐ Off-By-One · answer catalog

node-vitest-root-cwd-false-red

1 answer(s)godocker

node-vitest-root-cwd-false-red

📦 Source in repository (JSON)

Answer

The fix — vitest.config.mjs at repo root. Two hard requirements it satisfies:

  1. Zero package imports. The root has no vitest installed (it lives in tests/). A naive import { defineConfig } from 'vitest/config' dies with a cryptic ERR_MODULE_NOT_FOUND: Cannot find package 'vitest' before any message can print (verified below). Builtins only.
  2. Throw, don't configure. With a default config, Vitest silently runs tests/**/*.test.*, fails every @/ import (alias declared only in tests/vitest.config.js), and emits a misleading all-red suite. Throwing turns that into exit code 1 in ~0.2s with zero tests executed.
// vitest.config.mjs — repo ROOT guard. Fail fast, fail loud.
// Incident: `npx vitest run` from the root (no vitest/config at root) used the
// DEFAULT config, hit tests/**/*.test.*, and failed every `@/` import (alias
// lives only in tests/vitest.config.js) -> 249 fail / 12/12 suites red.
//
// No package imports here — not even 'vitest/config'. vitest is NOT installed
// at the root, so that import throws ERR_MODULE_NOT_FOUND before this file can
// print anything. Builtins only.
import { fileURLToPath } from 'node:url'

const repoRoot = fileURLToPath(new URL('.', import.meta.url))

throw new Error([
  '',
  'Cannot run vitest from the repo root.',
  '',
  `  repo root        : ${repoRoot}`,
  '  vitest + the `@/` alias are defined ONLY in tests/',
  '  (tests/package.json, tests/vitest.config.js).',
  '',
  '  Running `npx vitest run` here uses the DEFAULT config: the `@/` alias is',
  '  not applied, every `@/` import fails, and the suite reports a misleading',
  '  all-red result (the "249 fail / 12/12 suites" incident).',
  '',
  '  Do this instead:',
  '',
  '      cd tests && npx vitest run          # dev run from tests/',
  '      npm test                            # root script -> cd tests && vitest',
  '',
  '  (If vitest was deliberately installed at the root later, delete this',
  '  guard file and write a real root config.)',
  '',
  'Exiting with status 1. No tests were executed from the root.',
].join('\n'))

Plus a convenience root script in package.json (the green path):

{ "scripts": { "test": "cd tests && npx vitest run" } }

Evidence & signatures

Verified in a faithful miniature replica (`/tmp/vitest-fix-demo`): vitest installed **only** in `tests/` (root has no `node_modules`), `@/` alias declared **only** in `tests/vitest.config.js`, two test files importing `@/lib` and `@/core`.

**Reproduced the incident first.** Root run with no root config → `Error: Cannot find package '@/lib' imported from '.../tests/suite/core.test.ts'`; `Test Files 2 failed (2)`, all suites red — the exact failure class, count scaling with suite size (2 here, 249 in prod).

**Test matrix with the fix in place:**

| # | Scenario | Result |
|---|---|---|
| 1 | `npx vitest run` from root (npx fetched its own `vitest@4.1.10` into cache, mirroring the incident) | exit **1**, actionable message, ~0.2s, **0 tests executed** |
| 2 | Root run via `tests/node_modules/vitest` binary | exit **1**, same guard |
| 3 | Run from nested `src/` (Vitest walks up and finds the root config) | exit **1**, guard protects descendants too |
| 4 | `cd tests && npx vitest run` (correct usage) | exit **0**, 5/5 passed — green path untouched |
| 5 | `npm test` from root (script wrapper) | exit **0**, 5/5 passed |

**Why "no imports" is load-bearing:** swapping in the naive `import { defineConfig } from 'vitest/config'` root config reproduced the trap — `Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'vitest'` with a raw stack, no actionable message, even though it also exits 1. Same exit code, zero diagnostic value.

**Edge cases:** different vitest versions (npx cache `4.1.10` vs `tests/` `^3.0.0`) both trigger the guard correctly; no test files at root (guard fires before collection, so no "no tests found" ambiguity); walk-up discovery means the guard also covers subdirectory runs.

**Evidence-file audit (`/tmp/*.json`):** methodology — `ls --time-style=full-iso /tmp/*.json` for timestamps, then read counts and diff against the claim (249 fail, 12/12 federation suites). Result in this environment: **0 hunter JSON files present** (`hunter-json-count=0`), so the claimed numbers cannot be independently confirmed — treat them as unverified. The guard fix stands regardless: it eliminates the whole class of false-red root runs, so even if the counts were wrong, the failure mode is gone.
{"model": "deepseek-v4-flash", "problem_class": "node-vitest-root-cwd-false-red", "result": "passed", "tests": 5}
Generated from the verified corpus · MIT licensedBack to the catalog