Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(coverage): add allowExternal option #3894

Merged
merged 9 commits into from Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/config/index.md
Expand Up @@ -980,6 +980,15 @@ Since Vitest 0.31.0, you can check your coverage report in Vitest UI: check [Vit

Generate coverage report even when tests fail.

#### coverage.allowExternal

- **Type:** `boolean`
- **Default:** `false`
- **Available for providers:** `'v8' | 'istanbul'`
- **CLI:** `--coverage.allowExternal`, `--coverage.allowExternal=false`

Collect coverage of files outside the [project `root`](https://vitest.dev/config/#root).

#### coverage.skipFull

- **Type:** `boolean`
Expand Down
2 changes: 2 additions & 0 deletions packages/coverage-istanbul/src/provider.ts
Expand Up @@ -23,6 +23,7 @@ interface TestExclude {
exclude?: string | string[]
extension?: string | string[]
excludeNodeModules?: boolean
relativePath?: boolean
}): {
shouldInstrument(filePath: string): boolean
glob(cwd: string): Promise<string[]>
Expand Down Expand Up @@ -79,6 +80,7 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co
exclude: [...defaultExclude, ...defaultInclude, ...this.options.exclude],
excludeNodeModules: true,
extension: this.options.extension,
relativePath: !this.options.allowExternal,
})
}

Expand Down
2 changes: 2 additions & 0 deletions packages/coverage-v8/src/provider.ts
Expand Up @@ -30,6 +30,7 @@ interface TestExclude {
exclude?: string | string[]
extension?: string | string[]
excludeNodeModules?: boolean
relativePath?: boolean
}): {
shouldInstrument(filePath: string): boolean
glob(cwd: string): Promise<string[]>
Expand Down Expand Up @@ -79,6 +80,7 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
exclude: [...defaultExclude, ...defaultInclude, ...this.options.exclude],
excludeNodeModules: true,
extension: this.options.extension,
relativePath: !this.options.allowExternal,
})
}

Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/defaults.ts
Expand Up @@ -38,6 +38,7 @@ export const coverageConfigDefaults: ResolvedCoverageOptions = {
reportOnFailure: false,
reporter: [['text', {}], ['html', {}], ['clover', {}], ['json', {}]],
extension: ['.js', '.cjs', '.mjs', '.ts', '.mts', '.cts', '.tsx', '.jsx', '.vue', '.svelte'],
allowExternal: false,
}

export const fakeTimersDefaults = {
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/config.ts
Expand Up @@ -273,7 +273,7 @@ export function resolveConfig(
?? resolve(resolved.root, file),
),
)
resolved.coverage.exclude.push(...resolved.setupFiles.map(file => relative(resolved.root, file)))
resolved.coverage.exclude.push(...resolved.setupFiles.map(file => `${resolved.coverage.allowExternal ? '**/' : ''}${relative(resolved.root, file)}`))
AriPerkkio marked this conversation as resolved.
Show resolved Hide resolved

resolved.forceRerunTriggers = [
...resolved.forceRerunTriggers,
Expand Down
8 changes: 8 additions & 0 deletions packages/vitest/src/types/coverage.ts
Expand Up @@ -78,6 +78,7 @@ type FieldsWithDefaultValues =
| 'exclude'
| 'extension'
| 'reportOnFailure'
| 'allowExternal'

export type ResolvedCoverageOptions<T extends Provider = Provider> =
& CoverageOptions<T>
Expand Down Expand Up @@ -216,6 +217,13 @@ export interface BaseCoverageOptions {
* @default false
*/
reportOnFailure?: boolean

/**
* Collect coverage of files outside the project `root`.
*
* @default false
*/
allowExternal?: boolean
}

export interface CoverageIstanbulOptions extends BaseCoverageOptions {
Expand Down
20 changes: 20 additions & 0 deletions test/coverage-test/coverage-report-tests/allow-external.test.ts
@@ -0,0 +1,20 @@
import fs from 'node:fs'
import { expect, test } from 'vitest'

const allowExternal = import.meta.env.VITE_COVERAGE_ALLOW_EXTERNAL

test.skipIf(!allowExternal)('{ allowExternal: true } includes files outside project root', async () => {
expect(fs.existsSync('./coverage/test-utils/fixtures/math.ts.html')).toBe(true)

// Files inside project root should always be included
expect(fs.existsSync('./coverage/coverage-test/src/utils.ts.html')).toBe(true)
})

test.skipIf(allowExternal)('{ allowExternal: false } excludes files outside project root', async () => {
expect(fs.existsSync('./coverage/test-utils/fixtures/math.ts.html')).toBe(false)
expect(fs.existsSync('./test-utils/fixtures/math.ts.html')).toBe(false)
expect(fs.existsSync('./fixtures/math.ts.html')).toBe(false)

// Files inside project root should always be included
expect(fs.existsSync('./coverage/utils.ts.html')).toBe(true)
})
12 changes: 12 additions & 0 deletions test/coverage-test/option-tests/allow-external.test.ts
@@ -0,0 +1,12 @@
import { expect, test } from 'vitest'

import { multiply } from '../src/utils'
import * as ExternalMath from '../../test-utils/fixtures/math'

test('calling files outside project root', () => {
expect(ExternalMath.sum(2, 3)).toBe(5)
})

test('multiply - add some files to report', () => {
expect(multiply(2, 3)).toBe(6)
})
3 changes: 2 additions & 1 deletion test/coverage-test/package.json
Expand Up @@ -2,11 +2,12 @@
"name": "@vitest/test-coverage",
"private": true,
"scripts": {
"test": "pnpm test:v8 && pnpm test:istanbul && pnpm test:custom && pnpm test:browser && pnpm test:types",
"test": "pnpm test:v8 && pnpm test:istanbul && pnpm test:custom && pnpm test:browser && pnpm test:options && pnpm test:types",
"test:v8": "node ./testing.mjs --provider v8",
"test:custom": "node ./testing.mjs --provider custom",
"test:istanbul": "node ./testing.mjs --provider istanbul",
"test:browser": "node ./testing.mjs --browser --provider istanbul",
"test:options": "node ./testing-options.mjs",
"test:types": "vitest typecheck --run --reporter verbose"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions test/coverage-test/test/configuration-options.test-d.ts
Expand Up @@ -103,6 +103,7 @@ test('provider module', () => {
reporter: [['html', {}], ['json', { file: 'string' }]],
reportsDirectory: 'string',
reportOnFailure: true,
allowExternal: true,
}
},
clean(_: boolean) {},
Expand Down
69 changes: 69 additions & 0 deletions test/coverage-test/testing-options.mjs
@@ -0,0 +1,69 @@
import { startVitest } from 'vitest/node'

/** @type {Record<string, Partial<import('vitest/config').UserConfig['test']>>[]} */
const testCases = [
{
testConfig: {
name: 'allowExternal: true',
include: ['option-tests/allow-external.test.ts'],
coverage: {
allowExternal: true,
include: ['**/src/**', '**/test-utils/fixtures/**'],
reporter: 'html',
},
},
assertionConfig: {
include: ['coverage-report-tests/allow-external.test.ts'],
env: { VITE_COVERAGE_ALLOW_EXTERNAL: true },
},
},
{
testConfig: {
name: 'allowExternal: false',
include: ['option-tests/allow-external.test.ts'],
coverage: {
allowExternal: false,
include: ['**/src/**', '**/test-utils/fixtures/**'],
reporter: 'html',
},
},
assertionConfig: {
include: ['coverage-report-tests/allow-external.test.ts'],
},
},
]

for (const provider of ['v8', 'istanbul']) {
for (const { testConfig, assertionConfig } of testCases) {
// Run test case
await startVitest('test', ['option-tests/'], {
config: false,
watch: false,
...testConfig,
name: `${provider} - ${testConfig.name}`,
coverage: {
enabled: true,
clean: true,
provider,
...testConfig.coverage,
},
})

checkExit()

// Check generated coverage report
await startVitest('test', ['coverage-report-tests'], {
config: false,
watch: false,
...assertionConfig,
name: `${provider} - assert ${testConfig.name}`,
})

checkExit()
}
}

function checkExit() {
if (process.exitCode)
process.exit(process.exitCode)
}
7 changes: 7 additions & 0 deletions test/test-utils/fixtures/math.ts
@@ -0,0 +1,7 @@
export function sum(a: number, b: number) {
return a + b
}

export function multiply(a: number, b: number) {
return a * b
}