diff --git a/docs/config/index.md b/docs/config/index.md index f3028ada12fb..73131c2c866c 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -723,6 +723,9 @@ List of files included in coverage as glob patterns 'dist/**', 'packages/*/test?(s)/**', '**/*.d.ts', + '**/virtual:*', + '**/__x00__*', + '**/\x00*', 'cypress/**', 'test?(s)/**', 'test?(-*).?(c|m)[jt]s?(x)', diff --git a/packages/vitest/src/defaults.ts b/packages/vitest/src/defaults.ts index 10040a9486dc..2f80f9e85321 100644 --- a/packages/vitest/src/defaults.ts +++ b/packages/vitest/src/defaults.ts @@ -15,6 +15,9 @@ const defaultCoverageExcludes = [ 'dist/**', 'packages/*/test?(s)/**', '**/*.d.ts', + '**/virtual:*', + '**/__x00__*', + '**/\x00*', 'cypress/**', 'test?(s)/**', 'test?(-*).?(c|m)[jt]s?(x)', diff --git a/test/coverage-test/coverage-report-tests/generic.report.test.ts b/test/coverage-test/coverage-report-tests/generic.report.test.ts index c9b62ddce129..350c23c3677e 100644 --- a/test/coverage-test/coverage-report-tests/generic.report.test.ts +++ b/test/coverage-test/coverage-report-tests/generic.report.test.ts @@ -101,3 +101,19 @@ test('coverage provider does not conflict with built-in reporter\'s outputFile', expect(files).toContain('junit.xml') }) + +test('virtual files should be excluded', () => { + const files = fs.readdirSync(resolve('./coverage')) + const srcFiles = fs.readdirSync(resolve('./coverage/src')) + + for (const file of [...files, ...srcFiles]) { + expect(file).not.toContain('virtual:') + + // Vitest in node + expect(file).not.toContain('__x00__') + expect(file).not.toContain('\0') + + // Vitest browser + expect(file).not.toContain('\x00') + } +}) diff --git a/test/coverage-test/test/coverage.test.ts b/test/coverage-test/test/coverage.test.ts index 6d3e20f399a3..fcf719945215 100644 --- a/test/coverage-test/test/coverage.test.ts +++ b/test/coverage-test/test/coverage.test.ts @@ -1,9 +1,16 @@ import { expect, test } from 'vitest' + +// @ts-expect-error -- untyped virtual file provided by custom plugin +import virtualFile1 from 'virtual:vitest-custom-virtual-file-1' + import { implicitElse } from '../src/implicitElse' import { useImportEnv } from '../src/importEnv' import { second } from '../src/function-count' import { runDynamicFileCJS, runDynamicFileESM } from '../src/dynamic-files' +// @ts-expect-error -- untyped virtual file provided by custom plugin +import virtualFile2 from '\0vitest-custom-virtual-file-2' + // Browser mode crashes with dynamic files. Enable this when browser mode works. // To keep istanbul report consistent between browser and node, skip dynamic tests when istanbul is used. const skipDynamicFiles = globalThis.process?.env.COVERAGE_PROVIDER === 'istanbul' || !globalThis.process?.env.COVERAGE_PROVIDER @@ -40,3 +47,8 @@ test.skipIf(skipDynamicFiles)('run dynamic ESM file', async () => { test.skipIf(skipDynamicFiles)('run dynamic CJS file', async () => { await runDynamicFileCJS() }) + +test('virtual file imports', () => { + expect(virtualFile1).toBe('This file should be excluded from coverage report #1') + expect(virtualFile2).toBe('This file should be excluded from coverage report #2') +}) diff --git a/test/coverage-test/vitest.config.ts b/test/coverage-test/vitest.config.ts index 0eb103425292..258ea5e8bf7b 100644 --- a/test/coverage-test/vitest.config.ts +++ b/test/coverage-test/vitest.config.ts @@ -7,6 +7,33 @@ const provider = process.argv[1 + process.argv.indexOf('--provider')] export default defineConfig({ plugins: [ vue(), + { + // Simulates Vite's virtual files: https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention + name: 'vitest-custom-virtual-files', + resolveId(id) { + if (id === 'virtual:vitest-custom-virtual-file-1') + return 'src/virtual:vitest-custom-virtual-file-1.ts' + + if (id === '\0vitest-custom-virtual-file-2') + return 'src/\0vitest-custom-virtual-file-2.ts' + }, + load(id) { + if (id === 'src/virtual:vitest-custom-virtual-file-1.ts') { + return ` + const virtualFile = "This file should be excluded from coverage report #1" + export default virtualFile; + ` + } + + // Vitest browser resolves this as "\x00", Node as "__x00__" + if (id === 'src/__x00__vitest-custom-virtual-file-2.ts' || id === 'src/\x00vitest-custom-virtual-file-2.ts') { + return ` + const virtualFile = "This file should be excluded from coverage report #2" + export default virtualFile; + ` + } + }, + }, ], define: { MY_CONSTANT: '"my constant"',