Skip to content

Commit

Permalink
fix(coverage): ignore generated TS decorators (#5206)
Browse files Browse the repository at this point in the history
Co-authored-by: Vladimir <sleuths.slews0s@icloud.com>
  • Loading branch information
AriPerkkio and sheremet-va committed Feb 20, 2024
1 parent 5376d5b commit a280451
Show file tree
Hide file tree
Showing 13 changed files with 1,059 additions and 66 deletions.
3 changes: 3 additions & 0 deletions packages/coverage-istanbul/src/provider.ts
Expand Up @@ -114,6 +114,9 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co
const sourceMap = pluginCtx.getCombinedSourcemap()
sourceMap.sources = sourceMap.sources.map(removeQueryParameters)

// Exclude SWC's decorators that are left in source maps
sourceCode = sourceCode.replaceAll('_ts_decorate', '/* istanbul ignore next */_ts_decorate')

const code = this.instrumenter.instrumentSync(sourceCode, id, sourceMap as any)
const map = this.instrumenter.lastSourceMap() as any

Expand Down
24 changes: 14 additions & 10 deletions packages/coverage-v8/src/provider.ts
Expand Up @@ -51,6 +51,7 @@ const WRAPPER_LENGTH = 185

// Note that this needs to match the line ending as well
const VITE_EXPORTS_LINE_PATTERN = /Object\.defineProperty\(__vite_ssr_exports__.*\n/g
const DECORATOR_METADATA_PATTERN = /_ts_metadata\("design:paramtypes"(\s|.)+?]\),/g
const DEFAULT_PROJECT = Symbol.for('default-project')

const debug = createDebug('vitest:coverage')
Expand Down Expand Up @@ -312,7 +313,7 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
originalSource: sourcesContent,
source: code || sourcesContent,
sourceMap: {
sourcemap: removeViteHelpersFromSourceMaps(code, {
sourcemap: excludeGeneratedCode(code, {
...map,
version: 3,
sources: [url],
Expand Down Expand Up @@ -363,21 +364,24 @@ async function transformCoverage(coverageMap: CoverageMap) {
/**
* Remove generated code from the source maps:
* - Vite's export helpers: e.g. `Object.defineProperty(__vite_ssr_exports__, "sum", { enumerable: true, configurable: true, get(){ return sum }});`
* - SWC's decorator metadata: e.g. `_ts_metadata("design:paramtypes", [\ntypeof Request === "undefined" ? Object : Request\n]),`
*/
function removeViteHelpersFromSourceMaps(source: string | undefined, map: EncodedSourceMap) {
if (!source || !source.match(VITE_EXPORTS_LINE_PATTERN))
function excludeGeneratedCode(source: string | undefined, map: EncodedSourceMap) {
if (!source)
return map

const sourceWithoutHelpers = new MagicString(source)
sourceWithoutHelpers.replaceAll(VITE_EXPORTS_LINE_PATTERN, '\n')
if (!source.match(VITE_EXPORTS_LINE_PATTERN) && !source.match(DECORATOR_METADATA_PATTERN))
return map

const trimmed = new MagicString(source)
trimmed.replaceAll(VITE_EXPORTS_LINE_PATTERN, '\n')
trimmed.replaceAll(DECORATOR_METADATA_PATTERN, match => '\n'.repeat(match.split('\n').length - 1))

const mapWithoutHelpers = sourceWithoutHelpers.generateMap({
hires: 'boundary',
})
const trimmedMap = trimmed.generateMap({ hires: 'boundary' })

// A merged source map where the first one excludes helpers
// A merged source map where the first one excludes generated parts
const combinedMap = remapping(
[{ ...mapWithoutHelpers, version: 3 }, map],
[{ ...trimmedMap, version: 3 }, map],
() => null,
)

Expand Down
172 changes: 172 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -20,6 +20,7 @@ exports[`custom json report 1`] = `
"<process-cwd>/src/Defined.vue",
"<process-cwd>/src/Hello.vue",
"<process-cwd>/src/another-setup.ts",
"<process-cwd>/src/decorators.ts",
"<process-cwd>/src/dynamic-file-esm.ignore.js",
"<process-cwd>/src/dynamic-files.ts",
"<process-cwd>/src/function-count.ts",
Expand Down

0 comments on commit a280451

Please sign in to comment.