Skip to content

Commit c03faa2

Browse files
feat(coverage): add allowExternal option (#3894)
Co-authored-by: Ari Perkkiö <[email protected]>
1 parent 5704b34 commit c03faa2

File tree

12 files changed

+134
-2
lines changed

12 files changed

+134
-2
lines changed

docs/config/index.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,15 @@ Since Vitest 0.31.0, you can check your coverage report in Vitest UI: check [Vit
985985

986986
Generate coverage report even when tests fail.
987987

988+
#### coverage.allowExternal
989+
990+
- **Type:** `boolean`
991+
- **Default:** `false`
992+
- **Available for providers:** `'v8' | 'istanbul'`
993+
- **CLI:** `--coverage.allowExternal`, `--coverage.allowExternal=false`
994+
995+
Collect coverage of files outside the [project `root`](https://vitest.dev/config/#root).
996+
988997
#### coverage.skipFull
989998

990999
- **Type:** `boolean`

packages/coverage-istanbul/src/provider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface TestExclude {
2323
exclude?: string | string[]
2424
extension?: string | string[]
2525
excludeNodeModules?: boolean
26+
relativePath?: boolean
2627
}): {
2728
shouldInstrument(filePath: string): boolean
2829
glob(cwd: string): Promise<string[]>
@@ -79,6 +80,7 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co
7980
exclude: [...defaultExclude, ...defaultInclude, ...this.options.exclude],
8081
excludeNodeModules: true,
8182
extension: this.options.extension,
83+
relativePath: !this.options.allowExternal,
8284
})
8385
}
8486

packages/coverage-v8/src/provider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ interface TestExclude {
3030
exclude?: string | string[]
3131
extension?: string | string[]
3232
excludeNodeModules?: boolean
33+
relativePath?: boolean
3334
}): {
3435
shouldInstrument(filePath: string): boolean
3536
glob(cwd: string): Promise<string[]>
@@ -79,6 +80,7 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
7980
exclude: [...defaultExclude, ...defaultInclude, ...this.options.exclude],
8081
excludeNodeModules: true,
8182
extension: this.options.extension,
83+
relativePath: !this.options.allowExternal,
8284
})
8385
}
8486

packages/vitest/src/defaults.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export const coverageConfigDefaults: ResolvedCoverageOptions = {
3939
reportOnFailure: false,
4040
reporter: [['text', {}], ['html', {}], ['clover', {}], ['json', {}]],
4141
extension: ['.js', '.cjs', '.mjs', '.ts', '.mts', '.cts', '.tsx', '.jsx', '.vue', '.svelte'],
42+
allowExternal: false,
4243
}
4344

4445
export const fakeTimersDefaults = {

packages/vitest/src/node/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ export function resolveConfig(
279279
?? resolve(resolved.root, file),
280280
),
281281
)
282-
resolved.coverage.exclude.push(...resolved.setupFiles.map(file => relative(resolved.root, file)))
282+
resolved.coverage.exclude.push(...resolved.setupFiles.map(file => `${resolved.coverage.allowExternal ? '**/' : ''}${relative(resolved.root, file)}`))
283283

284284
resolved.forceRerunTriggers = [
285285
...resolved.forceRerunTriggers,

packages/vitest/src/types/coverage.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ type FieldsWithDefaultValues =
7878
| 'exclude'
7979
| 'extension'
8080
| 'reportOnFailure'
81+
| 'allowExternal'
8182

8283
export type ResolvedCoverageOptions<T extends Provider = Provider> =
8384
& CoverageOptions<T>
@@ -216,6 +217,13 @@ export interface BaseCoverageOptions {
216217
* @default false
217218
*/
218219
reportOnFailure?: boolean
220+
221+
/**
222+
* Collect coverage of files outside the project `root`.
223+
*
224+
* @default false
225+
*/
226+
allowExternal?: boolean
219227
}
220228

221229
export interface CoverageIstanbulOptions extends BaseCoverageOptions {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import fs from 'node:fs'
2+
import { expect, test } from 'vitest'
3+
4+
const allowExternal = import.meta.env.VITE_COVERAGE_ALLOW_EXTERNAL
5+
6+
test.skipIf(!allowExternal)('{ allowExternal: true } includes files outside project root', async () => {
7+
expect(fs.existsSync('./coverage/test-utils/fixtures/math.ts.html')).toBe(true)
8+
9+
// Files inside project root should always be included
10+
expect(fs.existsSync('./coverage/coverage-test/src/utils.ts.html')).toBe(true)
11+
})
12+
13+
test.skipIf(allowExternal)('{ allowExternal: false } excludes files outside project root', async () => {
14+
expect(fs.existsSync('./coverage/test-utils/fixtures/math.ts.html')).toBe(false)
15+
expect(fs.existsSync('./test-utils/fixtures/math.ts.html')).toBe(false)
16+
expect(fs.existsSync('./fixtures/math.ts.html')).toBe(false)
17+
18+
// Files inside project root should always be included
19+
expect(fs.existsSync('./coverage/utils.ts.html')).toBe(true)
20+
})
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { expect, test } from 'vitest'
2+
3+
import { multiply } from '../src/utils'
4+
import * as ExternalMath from '../../test-utils/fixtures/math'
5+
6+
test('calling files outside project root', () => {
7+
expect(ExternalMath.sum(2, 3)).toBe(5)
8+
})
9+
10+
test('multiply - add some files to report', () => {
11+
expect(multiply(2, 3)).toBe(6)
12+
})

test/coverage-test/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
"name": "@vitest/test-coverage",
33
"private": true,
44
"scripts": {
5-
"test": "pnpm test:v8 && pnpm test:istanbul && pnpm test:custom && pnpm test:browser && pnpm test:types",
5+
"test": "pnpm test:v8 && pnpm test:istanbul && pnpm test:custom && pnpm test:browser && pnpm test:options && pnpm test:types",
66
"test:v8": "node ./testing.mjs --provider v8",
77
"test:custom": "node ./testing.mjs --provider custom",
88
"test:istanbul": "node ./testing.mjs --provider istanbul",
99
"test:browser": "node ./testing.mjs --browser --provider istanbul",
10+
"test:options": "node ./testing-options.mjs",
1011
"test:types": "vitest typecheck --run --reporter verbose"
1112
},
1213
"devDependencies": {

test/coverage-test/test/configuration-options.test-d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ test('provider module', () => {
103103
reporter: [['html', {}], ['json', { file: 'string' }]],
104104
reportsDirectory: 'string',
105105
reportOnFailure: true,
106+
allowExternal: true,
106107
}
107108
},
108109
clean(_: boolean) {},

0 commit comments

Comments
 (0)