fix(coverage): istanbul provider to not break source maps (#9040)

This commit is contained in:
Ari Perkkiö 2025-11-26 10:15:47 +02:00 committed by GitHub
parent 9ca74cfb20
commit e4ca917f18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 116 additions and 10 deletions

View File

@ -45,6 +45,8 @@
},
"dependencies": {
"@istanbuljs/schema": "^0.1.3",
"@jridgewell/gen-mapping": "^0.3.13",
"@jridgewell/trace-mapping": "catalog:",
"istanbul-lib-coverage": "catalog:",
"istanbul-lib-instrument": "^6.0.3",
"istanbul-lib-report": "catalog:",

View File

@ -5,6 +5,8 @@ import type { CoverageProvider, ReportContext, ResolvedCoverageOptions, Vite, Vi
import { existsSync, promises as fs } from 'node:fs'
// @ts-expect-error missing types
import { defaults as istanbulDefaults } from '@istanbuljs/schema'
import { addMapping, GenMapping, toEncodedMap } from '@jridgewell/gen-mapping'
import { eachMapping, TraceMap } from '@jridgewell/trace-mapping'
import libCoverage from 'istanbul-lib-coverage'
import { createInstrumenter } from 'istanbul-lib-instrument'
import libReport from 'istanbul-lib-report'
@ -85,6 +87,30 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider<ResolvedCover
id,
sourceMap as any,
)
const transformMap = new GenMapping(sourceMap)
eachMapping(new TraceMap(sourceMap as any), (mapping) => {
addMapping(transformMap, {
generated: { line: mapping.generatedLine, column: mapping.generatedColumn },
original: { line: mapping.generatedLine, column: mapping.generatedColumn },
content: sourceCode,
name: mapping.name || '',
source: mapping.source || '',
})
})
const encodedMap = toEncodedMap(transformMap)
delete encodedMap.file
delete encodedMap.ignoreList
delete encodedMap.sourceRoot
this.instrumenter.instrumentSync(
sourceCode,
id,
encodedMap as any,
)
const map = this.instrumenter.lastSourceMap() as any
this.transformedModuleIds.add(id)

18
pnpm-lock.yaml generated
View File

@ -553,6 +553,12 @@ importers:
'@istanbuljs/schema':
specifier: ^0.1.3
version: 0.1.3
'@jridgewell/gen-mapping':
specifier: ^0.3.13
version: 0.3.13
'@jridgewell/trace-mapping':
specifier: 'catalog:'
version: 0.3.31
istanbul-lib-coverage:
specifier: 'catalog:'
version: 3.2.2
@ -3097,9 +3103,6 @@ packages:
resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
engines: {node: '>=8'}
'@jridgewell/gen-mapping@0.3.12':
resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==}
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@ -9780,7 +9783,7 @@ snapshots:
'@ampproject/remapping@2.3.0':
dependencies:
'@jridgewell/gen-mapping': 0.3.12
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
'@antfu/eslint-config@6.2.0(@vue/compiler-sfc@3.5.25)(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)(vitest@packages+vitest)':
@ -9931,7 +9934,7 @@ snapshots:
dependencies:
'@babel/parser': 7.28.5
'@babel/types': 7.28.4
'@jridgewell/gen-mapping': 0.3.12
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
jsesc: 3.1.0
@ -11278,11 +11281,6 @@ snapshots:
'@istanbuljs/schema@0.1.3': {}
'@jridgewell/gen-mapping@0.3.12':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5

View File

@ -0,0 +1,42 @@
/**
* Some padding
*/
export function uncovered() {
return "uncoverd";
}
/**
* Some padding
*/
export function throwsError(condition: Boolean) {
/**
* Some padding
*/
if(condition === false) {
/**
* Some padding
*/
return;
}
/**
* Some padding
*/
function throws() {
throw new Error("Expected error")
}
/**
* Some padding
*/
throws()
}
/**
* Some padding
*/
export function uncovered2() {
return "uncoverd";
}

View File

@ -0,0 +1,6 @@
import { test } from "vitest"
import { throwsError } from "../src/throws-error"
test("throws error", async () => {
throwsError(true)
})

View File

@ -0,0 +1,30 @@
import { expect } from 'vitest'
import { isBrowser, runVitest, test } from '../utils'
test('errors point to correct location', async () => {
const { stderr } = await runVitest({
include: ['fixtures/test/error-location.test.ts'],
coverage: { reporter: 'json' },
}, { throwOnError: false })
if (isBrowser()) {
expect(stderr).toMatch(`
throws fixtures/src/throws-error.ts:29:11
27| */
28| function throws() {
29| throw new Error("Expected error")
| ^
30| }
`.trim())
}
else {
expect(stderr).toMatch(`
throws fixtures/src/throws-error.ts:29:12
27| */
28| function throws() {
29| throw new Error("Expected error")
| ^
30| }
`.trim())
}
})

View File

@ -87,6 +87,7 @@ export default defineConfig({
'**/in-source.test.ts',
'**/query-param-transforms.test.ts',
'**/test/cjs-dependency.test.ts',
'**/test/source-maps.test.ts',
],
exclude: [FIXTURES],
},
@ -118,6 +119,7 @@ export default defineConfig({
'**/in-source.test.ts',
'**/query-param-transforms.test.ts',
'**/test/cjs-dependency.test.ts',
'**/test/source-maps.test.ts',
],
exclude: [FIXTURES],
},