Vitest monorepo coverage gate at 1%

One package had Vitest. The rest shipped with zero tests and CI stayed green. Root coverage at 1% fails loud with no tests.

Sander Korf2 min read
vitestcitypescriptmonorepo

Turborepo. Packages for backend (Convex), ui, ai, and a Next.js web app. One package got a Vitest runner and a green badge. Everything else could ship with zero tests and CI still smiled. That is not a quality bar. That is a suggestion.

I made the root vitest.config.ts the single coverage process. Provider v8. Reporter includes json-summary so a PR comment can surface the number. Projects point at each package config. Thresholds sit at 1% for lines, functions, branches, and statements. A package without tests fails loudly instead of hiding behind a sibling that already had coverage.

Package pnpm test stays fast and local. pnpm test:coverage at the root is the CI gate. Generated files and **/*.tsx stay excluded until jsdom or happy-dom is ready for the UI packages. I would rather gate TypeScript modules first than invent a flaky DOM harness overnight.

export default defineConfig({
	test: {
		coverage: {
			provider: 'v8',
			reporter: ['text', 'json-summary', 'json'],
			thresholds: { branches: 1, functions: 1, lines: 1, statements: 1 },
			include: ['packages/backend/**/*.ts', 'packages/ui/src/**/*.ts' /* ... */],
			exclude: ['**/_generated/**', '**/*.test.ts', '**/*.tsx'],
		},
		projects: ['packages/backend/vitest.config.ts', 'packages/ui/vitest.config.ts' /* ... */],
	},
});

One percent is not a brag. It is a tripwire. Raise it when the suites earn it. Until then, zero coverage should not look like success.


Happy coding! Sander