Skip to content

Commit

Permalink
fix(coverage): v8 to prevent crash on dynamic CJS files (#3657)
Browse files Browse the repository at this point in the history
  • Loading branch information
AriPerkkio committed Jun 26, 2023
1 parent fbb56ad commit 40f18a0
Show file tree
Hide file tree
Showing 9 changed files with 2,427 additions and 3 deletions.
22 changes: 19 additions & 3 deletions packages/coverage-v8/src/provider.ts
Expand Up @@ -110,7 +110,7 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
}

const converted = await Promise.all(scriptCoverages.map(async ({ url, functions }) => {
const sources = await this.getSources(url)
const sources = await this.getSources(url, functions)

// If no source map was found from vite-node we can assume this file was not run in the wrapper
const wrapperLength = sources.sourceMap ? WRAPPER_LENGTH : 0
Expand Down Expand Up @@ -204,7 +204,7 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
}))
}

private async getSources(url: string): Promise<{
private async getSources(url: string, functions: Profiler.FunctionCoverage[] = []): Promise<{
source: string
originalSource?: string
sourceMap?: { sourcemap: EncodedSourceMap }
Expand All @@ -217,7 +217,12 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage

const map = transformResult?.map
const code = transformResult?.code
const sourcesContent = map?.sourcesContent?.[0] || await fs.readFile(filePath, 'utf-8')
const sourcesContent = map?.sourcesContent?.[0] || await fs.readFile(filePath, 'utf-8').catch(() => {
// If file does not exist construct a dummy source for it.
// These can be files that were generated dynamically during the test run and were removed after it.
const length = findLongestFunctionLength(functions)
return '.'.repeat(length)
})

// These can be uncovered files included by "all: true" or files that are loaded outside vite-node
if (!map)
Expand Down Expand Up @@ -261,3 +266,14 @@ function removeViteHelpersFromSourceMaps(source: string | undefined, map: Encode

return combinedMap as EncodedSourceMap
}

/**
* Find the function with highest `endOffset` to determine the length of the file
*/
function findLongestFunctionLength(functions: Profiler.FunctionCoverage[]) {
return functions.reduce((previous, current) => {
const maxEndOffset = current.ranges.reduce((endOffset, range) => Math.max(endOffset, range.endOffset), 0)

return Math.max(previous, maxEndOffset)
}, 0)
}
1 change: 1 addition & 0 deletions test/coverage-test/.gitignore
@@ -0,0 +1 @@
src/dynamic-file.ignore.*

0 comments on commit 40f18a0

Please sign in to comment.