From c3eb8deb768f6ef1adff8e6644ce99de58fd8b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Mon, 4 Mar 2024 22:03:15 +0200 Subject: [PATCH] fix(coverage): v8 to ignore type-only files (#5328) --- packages/coverage-v8/package.json | 1 + packages/coverage-v8/src/provider.ts | 26 ++++++++++++++++++++------ pnpm-lock.yaml | 3 +++ test/coverage-test/src/types.ts | 3 +++ 4 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 test/coverage-test/src/types.ts diff --git a/packages/coverage-v8/package.json b/packages/coverage-v8/package.json index 569920243152..d01b01765276 100644 --- a/packages/coverage-v8/package.json +++ b/packages/coverage-v8/package.json @@ -55,6 +55,7 @@ "magicast": "^0.3.3", "picocolors": "^1.0.0", "std-env": "^3.5.0", + "strip-literal": "^2.0.0", "test-exclude": "^6.0.0", "v8-to-istanbul": "^9.2.0" }, diff --git a/packages/coverage-v8/src/provider.ts b/packages/coverage-v8/src/provider.ts index 517f446618cb..2f52cf8bf386 100644 --- a/packages/coverage-v8/src/provider.ts +++ b/packages/coverage-v8/src/provider.ts @@ -14,6 +14,7 @@ import remapping from '@ampproject/remapping' import { normalize, resolve } from 'pathe' import c from 'picocolors' import { provider } from 'std-env' +import { stripLiteral } from 'strip-literal' import createDebug from 'debug' import { cleanUrl } from 'vite-node/utils' import type { EncodedSourceMap, FetchResult } from 'vite-node' @@ -260,7 +261,13 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage } const coverages = await Promise.all(chunk.map(async (filename) => { - const { source } = await this.getSources(filename.href, transformResults) + const transformResult = await this.ctx.vitenode.transformRequest(filename.pathname).catch(() => {}) + + // Ignore empty files, e.g. files that contain only typescript types and no runtime code + if (transformResult && stripLiteral(transformResult.code).trim() === '') + return null + + const { originalSource } = await this.getSources(filename.href, transformResults) const coverage = { url: filename.href, @@ -269,7 +276,7 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage functions: [{ ranges: [{ startOffset: 0, - endOffset: source.length, + endOffset: originalSource.length, count: 0, }], isBlockCoverage: true, @@ -281,7 +288,10 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage return { result: [coverage] } })) - merged = mergeProcessCovs([merged, ...coverages]) + merged = mergeProcessCovs([ + merged, + ...coverages.filter((cov): cov is NonNullable => cov != null), + ]) } return merged @@ -289,7 +299,7 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage private async getSources(url: string, transformResults: TransformResults, functions: Profiler.FunctionCoverage[] = []): Promise<{ source: string - originalSource?: string + originalSource: string sourceMap?: { sourcemap: EncodedSourceMap } }> { const filePath = normalize(fileURLToPath(url)) @@ -306,8 +316,12 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage }) // These can be uncovered files included by "all: true" or files that are loaded outside vite-node - if (!map) - return { source: code || sourcesContent } + if (!map) { + return { + source: code || sourcesContent, + originalSource: sourcesContent, + } + } return { originalSource: sourcesContent, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b79c7577f3a..62d5671c7555 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1054,6 +1054,9 @@ importers: std-env: specifier: ^3.5.0 version: 3.5.0 + strip-literal: + specifier: ^2.0.0 + version: 2.0.0 test-exclude: specifier: ^6.0.0 version: 6.0.0 diff --git a/test/coverage-test/src/types.ts b/test/coverage-test/src/types.ts new file mode 100644 index 000000000000..439f557c49cf --- /dev/null +++ b/test/coverage-test/src/types.ts @@ -0,0 +1,3 @@ +export type First = 'This' | 'file' | 'should' + +export type Second = 'be' | 'excluded' | 'from' | 'report'