From 169bc1fde4aef7efe2171c73a42c3332a0360a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Mon, 1 Jul 2024 10:20:17 +0300 Subject: [PATCH] fix(coverage): support overriding `exclude` (#5997) --- docs/config/index.md | 13 +++- packages/coverage-istanbul/src/provider.ts | 9 +-- packages/coverage-v8/src/provider.ts | 9 +-- packages/vitest/src/defaults.ts | 3 +- packages/vitest/src/node/plugins/index.ts | 9 ++- .../src/test-that-looks-like-source-file.ts | 6 ++ .../coverage-test/test/allow-external.test.ts | 4 +- .../test/include-exclude.test.ts | 69 +++++++++++++++++++ 8 files changed, 102 insertions(+), 20 deletions(-) create mode 100644 test/coverage-test/fixtures/src/test-that-looks-like-source-file.ts create mode 100644 test/coverage-test/test/include-exclude.test.ts diff --git a/docs/config/index.md b/docs/config/index.md index eb9ccb714fca..42e9b8085628 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -32,6 +32,10 @@ All configuration options that are not supported inside a [workspace](/guide/wor A list of glob patterns that match your test files. +::: tip NOTE +When using coverage, Vitest automatically adds test files `include` patterns to coverage's default `exclude` patterns. See [`coverage.exclude`](#coverage-exclude). +::: + ### exclude - **Type:** `string[]` @@ -1111,6 +1115,7 @@ List of files included in coverage as glob patterns [ 'coverage/**', 'dist/**', + '**/node_modules/**', '**/[.]**', 'packages/*/test?(s)/**', '**/*.d.ts', @@ -1120,9 +1125,9 @@ List of files included in coverage as glob patterns 'cypress/**', 'test?(s)/**', 'test?(-*).?(c|m)[jt]s?(x)', - '**/*{.,-}{test,spec}?(-d).?(c|m)[jt]s?(x)', + '**/*{.,-}{test,spec,bench,benchmark}?(-d).?(c|m)[jt]s?(x)', '**/__tests__/**', - '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*', + '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*', '**/vitest.{workspace,projects}.[jt]s?(on)', '**/.{eslint,mocha,prettier}rc.{?(c|m)js,yml}', ] @@ -1146,6 +1151,10 @@ export default defineConfig({ }) ``` +::: tip NOTE +Vitest automatically adds test files `include` patterns to the default value of `coverage.exclude`. +::: + #### coverage.all - **Type:** `boolean` diff --git a/packages/coverage-istanbul/src/provider.ts b/packages/coverage-istanbul/src/provider.ts index 7c1c800ffee6..60b08c6a55c0 100644 --- a/packages/coverage-istanbul/src/provider.ts +++ b/packages/coverage-istanbul/src/provider.ts @@ -15,8 +15,6 @@ import type { } from 'vitest' import { coverageConfigDefaults, - defaultExclude, - defaultInclude, } from 'vitest/config' import { BaseCoverageProvider } from 'vitest/coverage' import c from 'picocolors' @@ -129,11 +127,8 @@ export class IstanbulCoverageProvider this.testExclude = new _TestExclude({ cwd: ctx.config.root, - include: - typeof this.options.include === 'undefined' - ? undefined - : [...this.options.include], - exclude: [...defaultExclude, ...defaultInclude, ...this.options.exclude], + include: this.options.include, + exclude: this.options.exclude, excludeNodeModules: true, extension: this.options.extension, relativePath: !this.options.allowExternal, diff --git a/packages/coverage-v8/src/provider.ts b/packages/coverage-v8/src/provider.ts index 19a88e71e56b..38050f235791 100644 --- a/packages/coverage-v8/src/provider.ts +++ b/packages/coverage-v8/src/provider.ts @@ -25,8 +25,6 @@ import { cleanUrl } from 'vite-node/utils' import type { EncodedSourceMap, FetchResult } from 'vite-node' import { coverageConfigDefaults, - defaultExclude, - defaultInclude, } from 'vitest/config' import { BaseCoverageProvider } from 'vitest/coverage' import type { @@ -126,11 +124,8 @@ export class V8CoverageProvider this.testExclude = new _TestExclude({ cwd: ctx.config.root, - include: - typeof this.options.include === 'undefined' - ? undefined - : [...this.options.include], - exclude: [...defaultExclude, ...defaultInclude, ...this.options.exclude], + include: this.options.include, + exclude: this.options.exclude, excludeNodeModules: true, extension: this.options.extension, relativePath: !this.options.allowExternal, diff --git a/packages/vitest/src/defaults.ts b/packages/vitest/src/defaults.ts index aa9c0aaadfe3..4b1ade73230b 100644 --- a/packages/vitest/src/defaults.ts +++ b/packages/vitest/src/defaults.ts @@ -29,6 +29,7 @@ export const benchmarkConfigDefaults: Required< const defaultCoverageExcludes = [ 'coverage/**', 'dist/**', + '**/node_modules/**', '**/[.]**', 'packages/*/test?(s)/**', '**/*.d.ts', @@ -40,7 +41,7 @@ const defaultCoverageExcludes = [ 'test?(-*).?(c|m)[jt]s?(x)', '**/*{.,-}{test,spec,bench,benchmark}?(-d).?(c|m)[jt]s?(x)', '**/__tests__/**', - '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*', + '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*', '**/vitest.{workspace,projects}.[jt]s?(on)', '**/.{eslint,mocha,prettier}rc.{?(c|m)js,yml}', ] diff --git a/packages/vitest/src/node/plugins/index.ts b/packages/vitest/src/node/plugins/index.ts index 48133fb4db53..ea664d129c4c 100644 --- a/packages/vitest/src/node/plugins/index.ts +++ b/packages/vitest/src/node/plugins/index.ts @@ -1,6 +1,6 @@ import type { UserConfig as ViteConfig, Plugin as VitePlugin } from 'vite' import { relative } from 'pathe' -import { configDefaults } from '../../defaults' +import { configDefaults, coverageConfigDefaults } from '../../defaults' import type { ResolvedConfig, UserConfig } from '../../types' import { deepMerge, @@ -131,6 +131,13 @@ export async function VitestPlugin( }, } + // If "coverage.exclude" is not defined by user, add "test.include" to "coverage.exclude" automatically + if (userConfig.coverage?.enabled && !userConfig.coverage.exclude && userConfig.include && config.test) { + config.test.coverage = { + exclude: [...coverageConfigDefaults.exclude, ...userConfig.include], + } + } + // we want inline dependencies to be resolved by analyser plugin so module graph is populated correctly if (viteConfig.ssr?.noExternal !== true) { const inline = testConfig.server?.deps?.inline diff --git a/test/coverage-test/fixtures/src/test-that-looks-like-source-file.ts b/test/coverage-test/fixtures/src/test-that-looks-like-source-file.ts new file mode 100644 index 000000000000..eece64f17842 --- /dev/null +++ b/test/coverage-test/fixtures/src/test-that-looks-like-source-file.ts @@ -0,0 +1,6 @@ +import { test, expect } from 'vitest' +import { sum } from "./math" + +test("run tests on file that looks like source file", () => { + expect(sum(1,2)).toBe(3) +}) \ No newline at end of file diff --git a/test/coverage-test/test/allow-external.test.ts b/test/coverage-test/test/allow-external.test.ts index 3057f8ed7b1d..08b6e1da0760 100644 --- a/test/coverage-test/test/allow-external.test.ts +++ b/test/coverage-test/test/allow-external.test.ts @@ -6,7 +6,7 @@ import * as ExternalMath from '../../test-utils/fixtures/math' test('{ allowExternal: true } includes files outside project root', async () => { await runVitest({ include: [normalizeURL(import.meta.url)], - coverage: { allowExternal: true, reporter: 'json' }, + coverage: { allowExternal: true, reporter: 'json', include: ['**/fixtures/**'] }, }) const coverageMap = await readCoverageMap() const files = coverageMap.files() @@ -21,7 +21,7 @@ test('{ allowExternal: true } includes files outside project root', async () => test('{ allowExternal: false } excludes files outside project root', async () => { await runVitest({ include: [normalizeURL(import.meta.url)], - coverage: { allowExternal: false, reporter: 'json' }, + coverage: { allowExternal: false, reporter: 'json', include: ['**/fixtures/**'] }, }) const coverageMap = await readCoverageMap() const files = coverageMap.files() diff --git a/test/coverage-test/test/include-exclude.test.ts b/test/coverage-test/test/include-exclude.test.ts new file mode 100644 index 000000000000..fa465184a6b3 --- /dev/null +++ b/test/coverage-test/test/include-exclude.test.ts @@ -0,0 +1,69 @@ +import { expect } from 'vitest' +import { coverageConfigDefaults } from 'vitest/config' +import { coverageTest, normalizeURL, readCoverageMap, runVitest, test } from '../utils' + +test('default exclude should ignore test files', async () => { + await runVitest({ + include: [normalizeURL(import.meta.url)], + coverage: { + all: true, + reporter: 'json', + include: ['fixtures/test/math.test.ts'], + }, + }) + + const coverageMap = await readCoverageMap() + expect(coverageMap.files()).toMatchInlineSnapshot(`[]`) +}) + +test('overriden exclude should not apply defaults', async () => { + await runVitest({ + include: [normalizeURL(import.meta.url)], + coverage: { + all: true, + reporter: 'json', + include: ['fixtures/test/math.test.ts'], + exclude: ['dont-match-anything'], + }, + }) + + const coverageMap = await readCoverageMap() + expect(coverageMap.files()).toMatchInlineSnapshot(` + [ + "/fixtures/test/math.test.ts", + ] + `) +}) + +test('test file is excluded from report when excludes is not set', async () => { + await runVitest({ + include: ['fixtures/src/test-that-looks-like-source-file.ts'], + coverage: { + all: true, + reporter: 'json', + }, + }) + + const coverageMap = await readCoverageMap() + const files = coverageMap.files() + expect(files.find(file => file.includes('test-that-looks-like-source-file'))).toBeFalsy() +}) + +test('test files are not automatically excluded from report when excludes is set', async () => { + await runVitest({ + include: ['fixtures/src/test-that-looks-like-source-file.ts'], + coverage: { + all: true, + reporter: 'json', + exclude: [...coverageConfigDefaults.exclude, '**/something-else/**'], + }, + }) + + const coverageMap = await readCoverageMap() + const files = coverageMap.files() + expect(files).toContain('/fixtures/src/test-that-looks-like-source-file.ts') +}) + +coverageTest('dummy', () => { + expect(1 + 1).toBe(2) +})