From 8818c6c88a78ff69f794ca0f90457ec32beb8975 Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sun, 22 Sep 2024 20:32:06 -0400 Subject: [PATCH] test_runner: report error on missing sourcemap source Co-Authored-By: Jayden Seric Co-Authored-By: Colin Ihrig PR-URL: https://github.com/nodejs/node/pull/55037 Reviewed-By: Chemi Atlow Reviewed-By: Colin Ihrig --- doc/api/errors.md | 6 ++++++ lib/internal/errors.js | 1 + lib/internal/test_runner/coverage.js | 8 ++++++++ .../source-map-missing-sources/index.js | 2 ++ .../source-map-missing-sources/index.js.map | 1 + test/parallel/test-runner-coverage.js | 15 +++++++++++++++ 6 files changed, 33 insertions(+) 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 663fd7d35ba561..fd76b2a1f8a7ee 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -2586,6 +2586,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 91b87023110487..ac88cbcf8bcf60 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1708,6 +1708,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-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..77e0afadbdff95 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',