From 4badc52cfbbb55ff36893b5494e46b1007072793 Mon Sep 17 00:00:00 2001 From: RedYetiDev <38299977+RedYetiDev@users.noreply.github.com> Date: Fri, 20 Sep 2024 20:22:08 -0400 Subject: [PATCH] test_runner: report error on missing sourcemap source Fixes #54756 Co-Authored-By: Colin Ihrig Co-Authored-By: Jayden Seric --- doc/api/errors.md | 6 +++ lib/internal/errors.js | 1 + lib/internal/test_runner/coverage.js | 8 ++++ .../line-lengths}/index.js | 0 .../line-lengths}/index.js.map | 0 .../line-lengths}/index.ts | 0 .../source-map/missing-sources/index.js | 2 + .../source-map/missing-sources/index.js.map | 1 + test/parallel/test-runner-coverage.js | 40 +++++++++++++------ 9 files changed, 46 insertions(+), 12 deletions(-) rename test/fixtures/test-runner/{source-map-line-lengths => source-map/line-lengths}/index.js (100%) rename test/fixtures/test-runner/{source-map-line-lengths => source-map/line-lengths}/index.js.map (100%) rename test/fixtures/test-runner/{source-map-line-lengths => source-map/line-lengths}/index.ts (100%) create mode 100644 test/fixtures/test-runner/source-map/missing-sources/index.js create mode 100644 test/fixtures/test-runner/source-map/missing-sources/index.js.map diff --git a/doc/api/errors.md b/doc/api/errors.md index 78456d0d28e0f0..71671c33be47f0 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -2573,6 +2573,12 @@ disconnected socket. A call was made and the UDP subsystem was not running. + + +### `ERR_SOURCE_MAP_MISSING_SOURCE` + +A file imported from a source map was not found. + ### `ERR_SQLITE_ERROR` diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 95acfef204734b..01ba50eb5d0801 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1704,6 +1704,7 @@ E('ERR_SOCKET_CONNECTION_TIMEOUT', E('ERR_SOCKET_DGRAM_IS_CONNECTED', 'Already connected', Error); E('ERR_SOCKET_DGRAM_NOT_CONNECTED', 'Not connected', Error); E('ERR_SOCKET_DGRAM_NOT_RUNNING', 'Not running', Error); +E('ERR_SOURCE_MAP_MISSING_SOURCE', `Cannot find '%s' imported from the source map for '%s'`, Error); E('ERR_SRI_PARSE', 'Subresource Integrity string %j had an unexpected %j at position %d', SyntaxError); diff --git a/lib/internal/test_runner/coverage.js b/lib/internal/test_runner/coverage.js index 7ef57020728302..1b5ba7912dcb7d 100644 --- a/lib/internal/test_runner/coverage.js +++ b/lib/internal/test_runner/coverage.js @@ -30,6 +30,11 @@ const { tmpdir } = require('os'); const { join, resolve, relative, matchesGlob } = require('path'); const { fileURLToPath } = require('internal/url'); const { kMappings, SourceMap } = require('internal/source_map/source_map'); +const { + codes: { + ERR_SOURCE_MAP_MISSING_SOURCE, + }, +} = require('internal/errors'); const kCoverageFileRegex = /^coverage-(\d+)-(\d{13})-(\d+)\.json$/; const kIgnoreRegex = /\/\* node:coverage ignore next (?\d+ )?\*\//; const kLineEndingRegex = /\r?\n$/u; @@ -390,6 +395,9 @@ class TestCoverage { newUrl ??= startEntry?.originalSource; const mappedLines = this.getLines(newUrl); + if (!mappedLines) { + throw new ERR_SOURCE_MAP_MISSING_SOURCE(newUrl, url); + } const mappedStartOffset = this.entryToOffset(startEntry, mappedLines); const mappedEndOffset = this.entryToOffset(endEntry, mappedLines) + 1; for (let l = startEntry.originalLine; l <= endEntry.originalLine; l++) { diff --git a/test/fixtures/test-runner/source-map-line-lengths/index.js b/test/fixtures/test-runner/source-map/line-lengths/index.js similarity index 100% rename from test/fixtures/test-runner/source-map-line-lengths/index.js rename to test/fixtures/test-runner/source-map/line-lengths/index.js diff --git a/test/fixtures/test-runner/source-map-line-lengths/index.js.map b/test/fixtures/test-runner/source-map/line-lengths/index.js.map similarity index 100% rename from test/fixtures/test-runner/source-map-line-lengths/index.js.map rename to test/fixtures/test-runner/source-map/line-lengths/index.js.map diff --git a/test/fixtures/test-runner/source-map-line-lengths/index.ts b/test/fixtures/test-runner/source-map/line-lengths/index.ts similarity index 100% rename from test/fixtures/test-runner/source-map-line-lengths/index.ts rename to test/fixtures/test-runner/source-map/line-lengths/index.ts diff --git a/test/fixtures/test-runner/source-map/missing-sources/index.js b/test/fixtures/test-runner/source-map/missing-sources/index.js new file mode 100644 index 00000000000000..f8a711af8c0098 --- /dev/null +++ b/test/fixtures/test-runner/source-map/missing-sources/index.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/test/fixtures/test-runner/source-map/missing-sources/index.js.map b/test/fixtures/test-runner/source-map/missing-sources/index.js.map new file mode 100644 index 00000000000000..12cacc226ac5c1 --- /dev/null +++ b/test/fixtures/test-runner/source-map/missing-sources/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js.map","sourceRoot":"","sources":["nonexistent.js"],"names":[],"mappings":"AAAA,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC"} \ No newline at end of file diff --git a/test/parallel/test-runner-coverage.js b/test/parallel/test-runner-coverage.js index ba767283e672c4..320de4ae17643a 100644 --- a/test/parallel/test-runner-coverage.js +++ b/test/parallel/test-runner-coverage.js @@ -6,6 +6,7 @@ const { readdirSync } = require('node:fs'); const { test } = require('node:test'); const fixtures = require('../common/fixtures'); const tmpdir = require('../common/tmpdir'); +const { pathToFileURL } = require('node:url'); const skipIfNoInspector = { skip: !process.features.inspector ? 'inspector disabled' : false }; @@ -320,6 +321,20 @@ test('coverage with source maps', skipIfNoInspector, () => { assert.strictEqual(result.status, 1); }); +test('coverage with source maps missing sources', skipIfNoInspector, () => { + const file = fixtures.path('test-runner', 'source-map', 'missing-sources', 'index.js'); + const missing = fixtures.path('test-runner', 'source-map', 'missing-sources', 'nonexistent.js'); + const result = spawnSync(process.execPath, [ + '--test', + '--experimental-test-coverage', + file, + ]); + + const error = `Cannot find '${pathToFileURL(missing)}' imported from the source map for '${pathToFileURL(file)}'`; + assert(result.stdout.toString().includes(error)); + assert.strictEqual(result.status, 1); +}); + test('coverage with ESM hook - source irrelevant', skipIfNoInspector, () => { let report = [ '# start of coverage report', @@ -487,24 +502,25 @@ test('coverage with included and excluded files', skipIfNoInspector, () => { }); test('properly accounts for line endings in source maps', skipIfNoInspector, () => { - const fixture = fixtures.path('test-runner', 'source-map-line-lengths', 'index.js'); + const fixture = fixtures.path('test-runner', 'source-map', 'line-lengths', 'index.js'); const args = [ '--test', '--experimental-test-coverage', '--test-reporter', 'tap', fixture, ]; const report = [ '# start of coverage report', - '# ----------------------------------------------------------------------------', - '# file | line % | branch % | funcs % | uncovered lines', - '# ----------------------------------------------------------------------------', - '# test | | | | ', - '# fixtures | | | | ', - '# test-runner | | | | ', - '# source-map-line-lengths | | | | ', - '# index.ts | 100.00 | 100.00 | 100.00 | ', - '# ----------------------------------------------------------------------------', - '# all files | 100.00 | 100.00 | 100.00 | ', - '# ----------------------------------------------------------------------------', + '# ------------------------------------------------------------------', + '# file | line % | branch % | funcs % | uncovered lines', + '# ------------------------------------------------------------------', + '# test | | | | ', + '# fixtures | | | | ', + '# test-runner | | | | ', + '# source-map | | | | ', + '# line-lengths | | | | ', + '# index.ts | 100.00 | 100.00 | 100.00 | ', + '# ------------------------------------------------------------------', + '# all files | 100.00 | 100.00 | 100.00 | ', + '# ------------------------------------------------------------------', '# end of coverage report', ].join('\n');