Coverage `text` reporter prints an empty table frame under agent detection when every file is 100% covered
Description
When vitest detects it is running under an AI agent, it forces skipFull: true onto the coverage text reporter and appends a text-summary reporter.
skipFull makes istanbul's text reporter omit any row whose metrics are all 100%. In a project where every file is fully covered, that removes every row — but the table header and rules are still emitted, so the output is a frame with no body:
% Coverage report from v8
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
----------|---------|----------|---------|---------|-------------------
=============================== Coverage summary ===============================
Statements : 100% ( 1/1 )
Branches : 100% ( 0/0 )
Functions : 100% ( 1/1 )
Lines : 100% ( 1/1 )
================================================================================Forcing skipFull under an agent is reasonable on its own terms — hiding fully-covered rows is exactly the noise reduction it is going for, and text-summary compensates for what is lost. The empty frame looks like an unhandled edge of that, rather than intended output: it spends tokens to communicate nothing, which is the opposite of the goal. It is also mildly alarming to read, since an empty coverage table is what a broken include glob or a wrong working directory looks like.
This is cosmetic — lcov.info is byte-identical between an agent run and a non-agent run, and thresholds are still enforced.
Steps to Reproduce
Minimal project — one source file, one spec, full coverage:
// src/a.ts
export function add(a: number, b: number) { return a + b }// src/a.spec.ts
import { expect, test } from 'vitest'
import { add } from './a.js'
test('add', () => { expect(add(1, 2)).toBe(3) })// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
coverage: { provider: 'v8', include: ['src/**'], reporter: ['text', 'lcov'] }
}
})Then:
# empty frame
CLAUDECODE=1 vitest run --coverage
# rows render
env -u AI_AGENT -u CLAUDECODE vitest run --coverageToggling only the agent env var flips the behaviour in both directions. Any variable std-env treats as agent detection reproduces it; CLAUDECODE=1 alone is sufficient.
Expected Behavior
When skipFull eliminates every row, do not print the table at all — the text-summary block already carries the totals. Keeping the All files summary row would also be an improvement over the current output.
Actual Behavior
The table header and both horizontal rules are printed with no rows between them.
Environment
- OS: Ubuntu 24.04.3 LTS (Noble Numbat), WSL2, kernel 6.18.33.2-microsoft-standard-WSL2
- Architecture: x86_64
- Runtime: Node v26.7.0
- Package manager: npm 12.0.2
- Affected packages:
vitest5.0.0,@vitest/coverage-v85.0.0 - Related:
std-env4.2.0 - Agent env present during the failing run:
CLAUDECODE=1,AI_AGENT
Notes
Reproduces identically on vitest 4.1.11 / @vitest/coverage-v8 4.1.11 — the agent-detection branch in coverage config resolution is unchanged between 4.1.11 and 5.0.0, and both depend on std-env@^4.2.0.
Workaround, since user-supplied reporter options are spread after the forced default:
reporter: [['text', { skipFull: false }], 'lcov']Source: vitest-dev/vitest