From fbf51979d8f6eddc465e7497492cd44937569b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Thu, 18 Aug 2022 18:38:48 +0000 Subject: [PATCH] feat(coverage-istanbul): add "all" option - Similar as nyc and c8 has --- docs/config/index.md | 7 ++++ packages/coverage-istanbul/src/provider.ts | 40 ++++++++++++++++++- packages/vitest/src/types/coverage.ts | 6 ++- .../coverage-test/coverage.istanbul.test.ts | 9 ++++- test/coverage-test/src/untested-file.ts | 3 ++ test/coverage-test/vitest.config.ts | 1 + 6 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 test/coverage-test/src/untested-file.ts diff --git a/docs/config/index.md b/docs/config/index.md index e10422b5c36b..478c5b5a68e5 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -518,6 +518,13 @@ Set to array of class method names to ignore for coverage. Watermarks for statements, lines, branches and functions. +##### all + +- **Type:** `boolean` +- **Default:** false + +Whether to include all files, including the untested ones into report. + ### testNamePattern - **Type** `string | RegExp` diff --git a/packages/coverage-istanbul/src/provider.ts b/packages/coverage-istanbul/src/provider.ts index 82614cedd688..ad5d54037201 100644 --- a/packages/coverage-istanbul/src/provider.ts +++ b/packages/coverage-istanbul/src/provider.ts @@ -23,7 +23,10 @@ interface TestExclude { exclude?: string | string[] extension?: string | string[] excludeNodeModules?: boolean - }): { shouldInstrument(filePath: string): boolean } + }): { + shouldInstrument(filePath: string): boolean + glob(cwd: string): Promise + } } export class IstanbulCoverageProvider implements CoverageProvider { @@ -95,12 +98,15 @@ export class IstanbulCoverageProvider implements CoverageProvider { } async reportCoverage() { - const mergedCoverage = this.coverages.reduce((coverage, previousCoverageMap) => { + const mergedCoverage: CoverageMap = this.coverages.reduce((coverage, previousCoverageMap) => { const map = libCoverage.createCoverageMap(coverage) map.merge(previousCoverageMap) return map }, {}) + if (this.options.all) + await this.includeUntestedFiles(mergedCoverage) + const sourceMapStore = libSourceMaps.createSourceMapStore() const coverageMap: CoverageMap = await sourceMapStore.transformCoverage(mergedCoverage) @@ -175,6 +181,36 @@ export class IstanbulCoverageProvider implements CoverageProvider { } } } + + async includeUntestedFiles(coverageMap: CoverageMap) { + const files = await this.testExclude.glob(this.ctx.config.root) + + for (const file of files) { + const filename = resolve(this.ctx.config.root, file) + + // Load, instrument and collect empty coverages from all files which + // are not already in the coverage map + if (!coverageMap.data[filename]) { + const transformResult = await this.ctx.vitenode.transformRequest(filename) + const sourceMap = transformResult?.map + + if (sourceMap) { + this.instrumenter.instrumentSync( + transformResult.code, + filename, + { + ...sourceMap, + version: sourceMap.version.toString(), + }, + ) + + const lastCoverage = this.instrumenter.lastFileCoverage() + if (lastCoverage) + coverageMap.data[lastCoverage.path] = lastCoverage + } + } + } + } } function resolveIstanbulOptions(options: CoverageIstanbulOptions, root: string) { diff --git a/packages/vitest/src/types/coverage.ts b/packages/vitest/src/types/coverage.ts index d1adf01b48d2..f68fd07ed18f 100644 --- a/packages/vitest/src/types/coverage.ts +++ b/packages/vitest/src/types/coverage.ts @@ -137,6 +137,11 @@ export interface BaseCoverageOptions { * Extensions for files to be included in coverage */ extension?: string | string[] + + /** + * Whether to include all files, including the untested ones into report + */ + all?: boolean } export interface CoverageIstanbulOptions extends BaseCoverageOptions { @@ -166,7 +171,6 @@ export interface CoverageC8Options extends BaseCoverageOptions { */ excludeNodeModules?: boolean - all?: boolean src?: string[] 100?: boolean diff --git a/test/coverage-test/coverage-test/coverage.istanbul.test.ts b/test/coverage-test/coverage-test/coverage.istanbul.test.ts index c2188e16ec90..72dfddfbdcdc 100644 --- a/test/coverage-test/coverage-test/coverage.istanbul.test.ts +++ b/test/coverage-test/coverage-test/coverage.istanbul.test.ts @@ -3,7 +3,7 @@ import { resolve } from 'pathe' import { expect, test } from 'vitest' test('istanbul html report', async () => { - const coveragePath = resolve('./coverage') + const coveragePath = resolve('./coverage/coverage-test/src') const files = fs.readdirSync(coveragePath) expect(files).toContain('index.html') @@ -22,3 +22,10 @@ test('istanbul lcov report', async () => { expect(lcovReportFiles).toContain('index.html') }) + +test('all includes untested files', () => { + const coveragePath = resolve('./coverage/coverage-test/src') + const files = fs.readdirSync(coveragePath) + + expect(files).toContain('untested-file.ts.html') +}) diff --git a/test/coverage-test/src/untested-file.ts b/test/coverage-test/src/untested-file.ts new file mode 100644 index 000000000000..1d1313eef8d4 --- /dev/null +++ b/test/coverage-test/src/untested-file.ts @@ -0,0 +1,3 @@ +export default function untestedFile() { + return 'This file should end up in report when {"all": true} is given' +} diff --git a/test/coverage-test/vitest.config.ts b/test/coverage-test/vitest.config.ts index 3d4e9cf640f3..0570d7959b7b 100644 --- a/test/coverage-test/vitest.config.ts +++ b/test/coverage-test/vitest.config.ts @@ -19,6 +19,7 @@ export default defineConfig({ coverage: { enabled: true, clean: true, + all: true, reporter: ['html', 'text', 'lcov'], }, },