From 488d6af1dfb4530a9fe347152a4d3f09b740c834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Sun, 14 Jul 2024 10:22:34 +0300 Subject: [PATCH] fix(coverage): v8 sourcemaps with multiple sources --- packages/coverage-v8/src/provider.ts | 22 +- test/config/test/exec-args.test.ts | 4 + .../fixtures/src/pre-bundle/bundle.js | 30 ++ .../fixtures/src/pre-bundle/bundle.js.map | 17 + .../fixtures/src/pre-bundle/bundle.ts | 2 + .../fixtures/src/pre-bundle/first.ts | 7 + .../fixtures/src/pre-bundle/second.ts | 7 + .../bundled-istanbul.snapshot.json | 168 +++++++++ .../__snapshots__/bundled-v8.snapshot.json | 346 ++++++++++++++++++ .../test/bundled-sources.test.ts | 36 ++ 10 files changed, 629 insertions(+), 10 deletions(-) create mode 100644 test/coverage-test/fixtures/src/pre-bundle/bundle.js create mode 100644 test/coverage-test/fixtures/src/pre-bundle/bundle.js.map create mode 100644 test/coverage-test/fixtures/src/pre-bundle/bundle.ts create mode 100644 test/coverage-test/fixtures/src/pre-bundle/first.ts create mode 100644 test/coverage-test/fixtures/src/pre-bundle/second.ts create mode 100644 test/coverage-test/test/__snapshots__/bundled-istanbul.snapshot.json create mode 100644 test/coverage-test/test/__snapshots__/bundled-v8.snapshot.json create mode 100644 test/coverage-test/test/bundled-sources.test.ts diff --git a/packages/coverage-v8/src/provider.ts b/packages/coverage-v8/src/provider.ts index aa01dced6bfe..e477b556e4a3 100644 --- a/packages/coverage-v8/src/provider.ts +++ b/packages/coverage-v8/src/provider.ts @@ -465,39 +465,41 @@ export class V8CoverageProvider const map = transformResult?.map as EncodedSourceMap | undefined const code = transformResult?.code - const sourcesContent - = map?.sourcesContent?.[0] - || (await fs.readFile(filePath, 'utf-8').catch(() => { + const sourcesContent = map?.sourcesContent || [] + + if (!sourcesContent[0]) { + 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) { return { isExecuted, - source: code || sourcesContent, - originalSource: sourcesContent, + source: code || sourcesContent[0], + originalSource: sourcesContent[0], } } - const sources = [url] + const sources = map.sources || [url] if (map.sources && map.sources[0] && !url.endsWith(map.sources[0])) { sources[0] = new URL(map.sources[0], url).href } return { isExecuted, - originalSource: sourcesContent, - source: code || sourcesContent, + originalSource: sourcesContent[0], + source: code || sourcesContent[0], sourceMap: { sourcemap: excludeGeneratedCode(code, { ...map, version: 3, sources, - sourcesContent: [sourcesContent], + sourcesContent, }), }, } diff --git a/test/config/test/exec-args.test.ts b/test/config/test/exec-args.test.ts index add2796a5da3..fa79b75b9add 100644 --- a/test/config/test/exec-args.test.ts +++ b/test/config/test/exec-args.test.ts @@ -10,6 +10,10 @@ test.each([ const root = './fixtures/exec-args-fixtures' const fileToTest = `${pool}.test.ts` + if (process.version === 'v20.15.0' && pool !== 'forks') { + return + } + const vitest = await runVitest({ root, include: [fileToTest], diff --git a/test/coverage-test/fixtures/src/pre-bundle/bundle.js b/test/coverage-test/fixtures/src/pre-bundle/bundle.js new file mode 100644 index 000000000000..e946da37baf8 --- /dev/null +++ b/test/coverage-test/fixtures/src/pre-bundle/bundle.js @@ -0,0 +1,30 @@ +function covered$1() { + return "First"; +} + +function uncovered$1() { + return "Uncovered"; +} + +var first = /*#__PURE__*/Object.freeze({ + __proto__: null, + covered: covered$1, + uncovered: uncovered$1 +}); + +function covered() { + return "Second"; +} + +function uncovered() { + return "Uncovered"; +} + +var second = /*#__PURE__*/Object.freeze({ + __proto__: null, + covered: covered, + uncovered: uncovered +}); + +export { first, second }; +//# sourceMappingURL=bundle.js.map diff --git a/test/coverage-test/fixtures/src/pre-bundle/bundle.js.map b/test/coverage-test/fixtures/src/pre-bundle/bundle.js.map new file mode 100644 index 000000000000..13d34ae1da4f --- /dev/null +++ b/test/coverage-test/fixtures/src/pre-bundle/bundle.js.map @@ -0,0 +1,17 @@ +{ + "version": 3, + "file": "bundle.js", + "sources": [ + "./first.ts", + "./second.ts" + ], + "sourcesContent": [ + "export function covered() {\n return \"First\";\n}\n\nexport function uncovered() {\n return \"Uncovered\";\n}\n", + "export function covered() {\n return \"Second\";\n}\n\nexport function uncovered() {\n return \"Uncovered\";\n}\n" + ], + "names": [ + "covered", + "uncovered" + ], + "mappings": "AAAO,SAASA,SAAO,GAAG;AAC1B,EAAE,OAAO,OAAO,CAAC;AACjB,CAAC;AACD;AACO,SAASC,WAAS,GAAG;AAC5B,EAAE,OAAO,WAAW,CAAC;AACrB;;;;;;;;ACNO,SAAS,OAAO,GAAG;AAC1B,EAAE,OAAO,QAAQ,CAAC;AAClB,CAAC;AACD;AACO,SAAS,SAAS,GAAG;AAC5B,EAAE,OAAO,WAAW,CAAC;AACrB;;;;;;;;;;" +} diff --git a/test/coverage-test/fixtures/src/pre-bundle/bundle.ts b/test/coverage-test/fixtures/src/pre-bundle/bundle.ts new file mode 100644 index 000000000000..181090555ccf --- /dev/null +++ b/test/coverage-test/fixtures/src/pre-bundle/bundle.ts @@ -0,0 +1,2 @@ +export * as first from "./first"; +export * as second from "./second"; diff --git a/test/coverage-test/fixtures/src/pre-bundle/first.ts b/test/coverage-test/fixtures/src/pre-bundle/first.ts new file mode 100644 index 000000000000..93478421809b --- /dev/null +++ b/test/coverage-test/fixtures/src/pre-bundle/first.ts @@ -0,0 +1,7 @@ +export function covered() { + return "First"; +} + +export function uncovered() { + return "Uncovered"; +} diff --git a/test/coverage-test/fixtures/src/pre-bundle/second.ts b/test/coverage-test/fixtures/src/pre-bundle/second.ts new file mode 100644 index 000000000000..20e24039b3fc --- /dev/null +++ b/test/coverage-test/fixtures/src/pre-bundle/second.ts @@ -0,0 +1,7 @@ +export function covered() { + return "Second"; +} + +export function uncovered() { + return "Uncovered"; +} diff --git a/test/coverage-test/test/__snapshots__/bundled-istanbul.snapshot.json b/test/coverage-test/test/__snapshots__/bundled-istanbul.snapshot.json new file mode 100644 index 000000000000..42389d735580 --- /dev/null +++ b/test/coverage-test/test/__snapshots__/bundled-istanbul.snapshot.json @@ -0,0 +1,168 @@ +{ + "/fixtures/src/pre-bundle/first.ts": { + "path": "/fixtures/src/pre-bundle/first.ts", + "statementMap": { + "0": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "1": { + "start": { + "line": 6, + "column": 2 + }, + "end": { + "line": 6, + "column": 21 + } + } + }, + "fnMap": { + "0": { + "name": "covered$1", + "decl": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 3, + "column": 1 + } + } + }, + "1": { + "name": "uncovered$1", + "decl": { + "start": { + "line": 5, + "column": 16 + }, + "end": { + "line": 5, + "column": 25 + } + }, + "loc": { + "start": { + "line": 5, + "column": 28 + }, + "end": { + "line": 7, + "column": null + } + } + } + }, + "branchMap": {}, + "s": { + "0": 1, + "1": 0 + }, + "f": { + "0": 1, + "1": 0 + }, + "b": {} + }, + "/fixtures/src/pre-bundle/second.ts": { + "path": "/fixtures/src/pre-bundle/second.ts", + "statementMap": { + "0": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "1": { + "start": { + "line": 6, + "column": 2 + }, + "end": { + "line": 6, + "column": 21 + } + } + }, + "fnMap": { + "0": { + "name": "covered", + "decl": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 3, + "column": 1 + } + } + }, + "1": { + "name": "uncovered", + "decl": { + "start": { + "line": 5, + "column": 16 + }, + "end": { + "line": 5, + "column": 25 + } + }, + "loc": { + "start": { + "line": 5, + "column": 28 + }, + "end": { + "line": 7, + "column": null + } + } + } + }, + "branchMap": {}, + "s": { + "0": 1, + "1": 0 + }, + "f": { + "0": 1, + "1": 0 + }, + "b": {} + } +} \ No newline at end of file diff --git a/test/coverage-test/test/__snapshots__/bundled-v8.snapshot.json b/test/coverage-test/test/__snapshots__/bundled-v8.snapshot.json new file mode 100644 index 000000000000..5aa335888476 --- /dev/null +++ b/test/coverage-test/test/__snapshots__/bundled-v8.snapshot.json @@ -0,0 +1,346 @@ +{ + "/fixtures/src/pre-bundle/first.ts": { + "path": "/fixtures/src/pre-bundle/first.ts", + "all": false, + "statementMap": { + "0": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 27 + } + }, + "1": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "2": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "3": { + "start": { + "line": 4, + "column": 0 + }, + "end": { + "line": 4, + "column": 0 + } + }, + "4": { + "start": { + "line": 5, + "column": 0 + }, + "end": { + "line": 5, + "column": 29 + } + }, + "5": { + "start": { + "line": 6, + "column": 0 + }, + "end": { + "line": 6, + "column": 21 + } + }, + "6": { + "start": { + "line": 7, + "column": 0 + }, + "end": { + "line": 7, + "column": 1 + } + } + }, + "s": { + "0": 1, + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 0, + "6": 0 + }, + "branchMap": { + "0": { + "type": "branch", + "line": 1, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "locations": [ + { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + } + ] + } + }, + "b": { + "0": [ + 1 + ] + }, + "fnMap": { + "0": { + "name": "covered$1", + "decl": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "line": 1 + }, + "1": { + "name": "uncovered$1", + "decl": { + "start": { + "line": 5, + "column": 7 + }, + "end": { + "line": 7, + "column": 1 + } + }, + "loc": { + "start": { + "line": 5, + "column": 7 + }, + "end": { + "line": 7, + "column": 1 + } + }, + "line": 5 + } + }, + "f": { + "0": 1, + "1": 0 + } + }, + "/fixtures/src/pre-bundle/second.ts": { + "path": "/fixtures/src/pre-bundle/second.ts", + "all": false, + "statementMap": { + "0": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 27 + } + }, + "1": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "2": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "3": { + "start": { + "line": 4, + "column": 0 + }, + "end": { + "line": 4, + "column": 0 + } + }, + "4": { + "start": { + "line": 5, + "column": 0 + }, + "end": { + "line": 5, + "column": 29 + } + }, + "5": { + "start": { + "line": 6, + "column": 0 + }, + "end": { + "line": 6, + "column": 21 + } + }, + "6": { + "start": { + "line": 7, + "column": 0 + }, + "end": { + "line": 7, + "column": 1 + } + } + }, + "s": { + "0": 1, + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 0, + "6": 0 + }, + "branchMap": { + "0": { + "type": "branch", + "line": 1, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "locations": [ + { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + } + ] + } + }, + "b": { + "0": [ + 1 + ] + }, + "fnMap": { + "0": { + "name": "covered", + "decl": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "line": 1 + }, + "1": { + "name": "uncovered", + "decl": { + "start": { + "line": 5, + "column": 7 + }, + "end": { + "line": 7, + "column": 1 + } + }, + "loc": { + "start": { + "line": 5, + "column": 7 + }, + "end": { + "line": 7, + "column": 1 + } + }, + "line": 5 + } + }, + "f": { + "0": 1, + "1": 0 + } + } +} \ No newline at end of file diff --git a/test/coverage-test/test/bundled-sources.test.ts b/test/coverage-test/test/bundled-sources.test.ts new file mode 100644 index 000000000000..d90eb6516966 --- /dev/null +++ b/test/coverage-test/test/bundled-sources.test.ts @@ -0,0 +1,36 @@ +import libCoverage from 'istanbul-lib-coverage' +import { expect } from 'vitest' +import { coverageTest, isV8Provider, normalizeURL, readCoverageJson, runVitest, test } from '../utils.js' +import * as transpiled from '../fixtures/src/pre-bundle/bundle.js' + +test('bundled code with source maps to originals', async () => { + await runVitest({ + include: [normalizeURL(import.meta.url)], + coverage: { + include: ['fixtures/src/**'], + reporter: 'json', + all: false, + }, + }) + + const coverageJson = await readCoverageJson() + const coverageMap = libCoverage.createCoverageMap(coverageJson) + const files = coverageMap.files() + + expect(files).toContain('/fixtures/src/pre-bundle/first.ts') + expect(files).toContain('/fixtures/src/pre-bundle/second.ts') + expect(files.find(file => file.includes('bundle.js'))).toBeFalsy() + expect(files.find(file => file.includes('bundle.js.map'))).toBeFalsy() + expect(files.find(file => file.includes('bundle.ts'))).toBeFalsy() + expect(files.find(file => file.includes('bundle.d.ts'))).toBeFalsy() + + expect(JSON.stringify(coverageJson, null, 2)).toMatchFileSnapshot(`__snapshots__/bundled-${isV8Provider() ? 'v8' : 'istanbul'}.snapshot.json`) +}) + +coverageTest('run bundled sources', () => { + expect(transpiled.first.covered).toBeTypeOf('function') + expect(transpiled.first.covered()).toBe('First') + + expect(transpiled.second.covered).toBeTypeOf('function') + expect(transpiled.second.covered()).toBe('Second') +})