Skip to content

Commit 280e674

Browse files
authored
fix(coverage): v8 provider to pick source maps without url query params (#3784)
1 parent cdab465 commit 280e674

File tree

3 files changed

+30
-26
lines changed

3 files changed

+30
-26
lines changed

packages/coverage-v8/src/provider.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import remapping from '@ampproject/remapping'
1313
import { normalize, resolve } from 'pathe'
1414
import c from 'picocolors'
1515
import { provider } from 'std-env'
16-
import type { EncodedSourceMap } from 'vite-node'
16+
import { cleanUrl } from 'vite-node/utils'
17+
import type { EncodedSourceMap, FetchResult } from 'vite-node'
1718
import { coverageConfigDefaults, defaultExclude, defaultInclude } from 'vitest/config'
1819
import { BaseCoverageProvider } from 'vitest/coverage'
1920
import type { AfterSuiteRunMeta, CoverageProvider, CoverageV8Options, ReportContext, ResolvedCoverageOptions } from 'vitest'
@@ -36,6 +37,7 @@ interface TestExclude {
3637
}
3738

3839
type Options = ResolvedCoverageOptions<'v8'>
40+
type TransformResults = Map<string, FetchResult>
3941

4042
// TODO: vite-node should export this
4143
const WRAPPER_LENGTH = 185
@@ -99,18 +101,19 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
99101
if (provider === 'stackblitz')
100102
this.ctx.logger.log(c.blue(' % ') + c.yellow('@vitest/coverage-v8 does not work on Stackblitz. Report will be empty.'))
101103

104+
const transformResults = normalizeTransformResults(this.ctx.projects.map(project => project.vitenode.fetchCache))
102105
const merged = mergeProcessCovs(this.coverages)
103106
const scriptCoverages = merged.result.filter(result => this.testExclude.shouldInstrument(fileURLToPath(result.url)))
104107

105108
if (this.options.all && allTestsRun) {
106109
const coveredFiles = Array.from(scriptCoverages.map(r => r.url))
107-
const untestedFiles = await this.getUntestedFiles(coveredFiles)
110+
const untestedFiles = await this.getUntestedFiles(coveredFiles, transformResults)
108111

109112
scriptCoverages.push(...untestedFiles)
110113
}
111114

112115
const converted = await Promise.all(scriptCoverages.map(async ({ url, functions }) => {
113-
const sources = await this.getSources(url, functions)
116+
const sources = await this.getSources(url, transformResults, functions)
114117

115118
// If no source map was found from vite-node we can assume this file was not run in the wrapper
116119
const wrapperLength = sources.sourceMap ? WRAPPER_LENGTH : 0
@@ -177,14 +180,14 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
177180
}
178181
}
179182

180-
private async getUntestedFiles(testedFiles: string[]): Promise<Profiler.ScriptCoverage[]> {
183+
private async getUntestedFiles(testedFiles: string[], transformResults: TransformResults): Promise<Profiler.ScriptCoverage[]> {
181184
const includedFiles = await this.testExclude.glob(this.ctx.config.root)
182185
const uncoveredFiles = includedFiles
183186
.map(file => pathToFileURL(resolve(this.ctx.config.root, file)))
184187
.filter(file => !testedFiles.includes(file.href))
185188

186189
return await Promise.all(uncoveredFiles.map(async (uncoveredFile) => {
187-
const { source } = await this.getSources(uncoveredFile.href)
190+
const { source } = await this.getSources(uncoveredFile.href, transformResults)
188191

189192
return {
190193
url: uncoveredFile.href,
@@ -204,16 +207,14 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
204207
}))
205208
}
206209

207-
private async getSources(url: string, functions: Profiler.FunctionCoverage[] = []): Promise<{
210+
private async getSources(url: string, transformResults: TransformResults, functions: Profiler.FunctionCoverage[] = []): Promise<{
208211
source: string
209212
originalSource?: string
210213
sourceMap?: { sourcemap: EncodedSourceMap }
211214
}> {
212215
const filePath = normalize(fileURLToPath(url))
213-
const transformResult = this.ctx.projects
214-
.map(project => project.vitenode.fetchCache.get(filePath)?.result)
215-
.filter(Boolean)
216-
.shift()
216+
217+
const transformResult = transformResults.get(filePath)
217218

218219
const map = transformResult?.map
219220
const code = transformResult?.code
@@ -277,3 +278,18 @@ function findLongestFunctionLength(functions: Profiler.FunctionCoverage[]) {
277278
return Math.max(previous, maxEndOffset)
278279
}, 0)
279280
}
281+
282+
function normalizeTransformResults(fetchCaches: Map<string, { result: FetchResult }>[]) {
283+
const normalized: TransformResults = new Map()
284+
285+
for (const fetchCache of fetchCaches) {
286+
for (const [key, value] of fetchCache.entries()) {
287+
const cleanEntry = cleanUrl(key)
288+
289+
if (!normalized.has(cleanEntry))
290+
normalized.set(cleanEntry, value.result)
291+
}
292+
}
293+
294+
return normalized
295+
}

test/coverage-test/coverage-report-tests/__snapshots__/v8.report.test.ts.snap

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -704,12 +704,11 @@ exports[`v8 json report 1`] = `
704704
"0": 1,
705705
"1": 1,
706706
"2": 1,
707-
"3": 1,
708707
},
709708
"statementMap": {
710709
"0": {
711710
"end": {
712-
"column": 50,
711+
"column": 38,
713712
"line": 1,
714713
},
715714
"start": {
@@ -719,7 +718,7 @@ exports[`v8 json report 1`] = `
719718
},
720719
"1": {
721720
"end": {
722-
"column": 38,
721+
"column": 0,
723722
"line": 2,
724723
},
725724
"start": {
@@ -729,24 +728,14 @@ exports[`v8 json report 1`] = `
729728
},
730729
"2": {
731730
"end": {
732-
"column": 0,
731+
"column": 21,
733732
"line": 3,
734733
},
735734
"start": {
736735
"column": 0,
737736
"line": 3,
738737
},
739738
},
740-
"3": {
741-
"end": {
742-
"column": 39,
743-
"line": 4,
744-
},
745-
"start": {
746-
"column": 0,
747-
"line": 4,
748-
},
749-
},
750739
},
751740
},
752741
"<process-cwd>/src/Defined.vue": {
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import CounterComponent from './Counter.component'
21
import CounterVue from './Counter.vue'
32

4-
export { CounterComponent, CounterVue }
3+
export { CounterVue }

0 commit comments

Comments
 (0)