Skip to content

Commit 13b78d9

Browse files
feat(coverage)!: allow thresholds.perFile to accept an object (#10190)
Co-authored-by: Ari Perkkiö <ari.perkkio@gmail.com>
1 parent 361cf5d commit 13b78d9

10 files changed

Lines changed: 672 additions & 81 deletions

File tree

docs/config/coverage.md

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,67 @@ Global threshold for statements.
233233

234234
### coverage.thresholds.perFile
235235

236-
- **Type:** `boolean`
236+
- **Type:** `boolean | { 100?: boolean, lines?: number, functions?: number, branches?: number, statements?: number }`
237237
- **Default:** `false`
238238
- **Available for providers:** `'v8' | 'istanbul'`
239239
- **CLI:** `--coverage.thresholds.perFile`, `--coverage.thresholds.perFile=false`
240240

241-
Check thresholds per file.
241+
When `true`, each file is checked against the top-level thresholds instead of the project-wide aggregate. When set to an object, both are checked: the aggregate against the top-level thresholds, and every file against these per-file minimums.
242+
243+
<!-- eslint-skip -->
244+
```ts
245+
{
246+
coverage: {
247+
thresholds: {
248+
lines: 80,
249+
functions: 80,
250+
branches: 80,
251+
statements: 80,
252+
perFile: {
253+
lines: 50,
254+
functions: 50,
255+
branches: 50,
256+
statements: 50,
257+
},
258+
}
259+
}
260+
}
261+
```
262+
263+
`{ 100: true }` is also accepted inside the object as a shortcut for setting all four metrics to `100`:
264+
265+
<!-- eslint-skip -->
266+
```ts
267+
{
268+
coverage: {
269+
thresholds: {
270+
lines: 80,
271+
perFile: {
272+
100: true,
273+
},
274+
}
275+
}
276+
}
277+
```
278+
279+
`perFile` can also be set on an individual [glob-pattern threshold](/config/coverage#coverage-thresholds-glob-pattern). Glob patterns do **not** inherit the top-level `perFile`; set it on each glob explicitly.
280+
281+
<!-- eslint-skip -->
282+
```ts
283+
{
284+
coverage: {
285+
thresholds: {
286+
perFile: true,
287+
lines: 80,
288+
289+
'src/utils/**': {
290+
lines: 90,
291+
perFile: true,
292+
},
293+
}
294+
}
295+
}
296+
```
242297

243298
### coverage.thresholds.autoUpdate
244299

@@ -257,9 +312,6 @@ You can also pass a function for formatting the updated threshold values. The fu
257312
{
258313
coverage: {
259314
thresholds: {
260-
// Update thresholds without decimals
261-
autoUpdate: (newThreshold) => Math.floor(newThreshold),
262-
263315
// Log the change and update without decimals
264316
autoUpdate: (newThreshold, previousThreshold) => {
265317
console.log(`Updated threshold from ${previousThreshold} to ${newThreshold}`)
@@ -285,12 +337,14 @@ Shortcut for `--coverage.thresholds.lines 100 --coverage.thresholds.functions 10
285337

286338
### coverage.thresholds[glob-pattern]
287339

288-
- **Type:** `{ statements?: number functions?: number branches?: number lines?: number }`
340+
- **Type:** `{ statements?: number, functions?: number, branches?: number, lines?: number, perFile?: boolean | object }`
289341
- **Default:** `undefined`
290342
- **Available for providers:** `'v8' | 'istanbul'`
291343

292344
Sets thresholds for files matching the glob pattern.
293345

346+
Each glob pattern can set its own `perFile` (`boolean | object`), checked exactly like the top-level `perFile` but scoped to the matched files. Glob patterns do not inherit the top-level `perFile` — set it per glob.
347+
294348
::: tip NOTE
295349
Vitest counts all files, including those covered by glob-patterns, into the global coverage thresholds.
296350
This is different from Jest behavior.
@@ -311,6 +365,8 @@ This is different from Jest behavior.
311365
functions: 90,
312366
branches: 85,
313367
lines: 80,
368+
// each matching file must individually hit the thresholds above
369+
perFile: true,
314370
},
315371

316372
// Files matching this pattern will only have lines thresholds set.

docs/guide/cli-generated.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,10 @@ Shortcut to set all coverage thresholds to 100 (default: `false`)
197197

198198
### coverage.thresholds.perFile
199199

200-
- **CLI:** `--coverage.thresholds.perFile`
200+
- **CLI:** `--coverage.thresholds.perFile <boolean>`
201201
- **Config:** [coverage.thresholds.perFile](/config/coverage#coverage-thresholds-perfile)
202202

203-
Check thresholds per file. See `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches` and `--coverage.thresholds.statements` for the actual thresholds (default: `false`)
203+
Check thresholds per file. See `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches` and `--coverage.thresholds.statements` for the actual thresholds (default: `false`). Object form is available in config files only.
204204

205205
### coverage.thresholds.autoUpdate
206206

docs/guide/migration.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,27 @@ await expect.element(banner).toMatchTextContent(/error/i) // [!code ++]
125125
await expect.element(banner).toHaveTextContent('Error!')
126126
```
127127

128+
### Glob Coverage Thresholds No Longer Inherit `perFile`
129+
130+
`coverage.thresholds.perFile` previously applied to every threshold set, including files matched by glob-pattern thresholds. Glob patterns now control their own per-file checking and no longer inherit the top-level `perFile` — set `perFile` on each glob that needs it.
131+
132+
```ts [vitest.config.ts]
133+
export default defineConfig({
134+
test: {
135+
coverage: {
136+
thresholds: {
137+
'perFile': true,
138+
139+
'src/utils/**': {
140+
lines: 80,
141+
perFile: true, // [!code ++]
142+
},
143+
},
144+
},
145+
},
146+
})
147+
```
148+
128149
### Config Files Are Not Looked Up From Parent Directories
129150

130151
Vitest no longer searches parent directories for config files. If you previously relied on running `vitest` from a subdirectory while using a config file from a parent directory, pass the config explicitly and scope test discovery with `--dir`. For example,

packages/vitest/src/node/cli/cli-config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,9 @@ export const cliOptionsConfig: VitestCLIOptions = {
215215
subcommands: {
216216
perFile: {
217217
description:
218-
'Check thresholds per file. See `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches` and `--coverage.thresholds.statements` for the actual thresholds (default: `false`)',
218+
'Check thresholds per file. See `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches` and `--coverage.thresholds.statements` for the actual thresholds (default: `false`). Object form is available in config files only.',
219+
subcommands: null,
220+
argument: '<boolean>',
219221
},
220222
autoUpdate: {
221223
description:

0 commit comments

Comments
 (0)