diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 8cf008d52ab380..389fd070176e30 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -106,7 +106,9 @@ const kShouldSkipModuleHooks = { __proto__: null, shouldSkipModuleHooks: true }; * @param {boolean} isMain - Whether the module is the entrypoint */ function loadCJSModule(module, source, url, filename, isMain) { - const compileResult = compileFunctionForCJSLoader(source, filename, false /* is_sea_main */, false); + // Use the full URL as the V8 resource name so that any search params + // (e.g. ?node-test-mock) are preserved in coverage reports. + const compileResult = compileFunctionForCJSLoader(source, url, false /* is_sea_main */, false); const { function: compiledWrapper, sourceMapURL, sourceURL } = compileResult; // Cache the source map for the cjs module if present. diff --git a/test/fixtures/test-runner/coverage-with-mock/dependency.cjs b/test/fixtures/test-runner/coverage-with-mock/dependency.cjs new file mode 100644 index 00000000000000..fa305d24a3f3c1 --- /dev/null +++ b/test/fixtures/test-runner/coverage-with-mock/dependency.cjs @@ -0,0 +1,9 @@ +throw new Error('This should never be called'); + +exports.dependency = function dependency() { + return 'foo'; +} + +exports.unused = function unused() { + return 'bar'; +} diff --git a/test/fixtures/test-runner/coverage-with-mock/subject.mjs b/test/fixtures/test-runner/coverage-with-mock/subject.mjs new file mode 100644 index 00000000000000..ae63dd386c4998 --- /dev/null +++ b/test/fixtures/test-runner/coverage-with-mock/subject.mjs @@ -0,0 +1,5 @@ +import { dependency } from './dependency.cjs'; + +export function subject() { + return dependency(); +} diff --git a/test/fixtures/test-runner/output/coverage-with-mock-cjs.mjs b/test/fixtures/test-runner/output/coverage-with-mock-cjs.mjs new file mode 100644 index 00000000000000..4841aa03e6904a --- /dev/null +++ b/test/fixtures/test-runner/output/coverage-with-mock-cjs.mjs @@ -0,0 +1,11 @@ +import { mock, test } from 'node:test'; + +const dependency = mock.fn(() => 'mock-return-value'); +mock.module('../coverage-with-mock/dependency.cjs', { namedExports: { dependency } }); + +const { subject } = await import('../coverage-with-mock/subject.mjs'); + +test('subject calls dependency', (t) => { + t.assert.strictEqual(subject(), 'mock-return-value'); + t.assert.strictEqual(dependency.mock.callCount(), 1); +}); diff --git a/test/fixtures/test-runner/output/coverage-with-mock-cjs.snapshot b/test/fixtures/test-runner/output/coverage-with-mock-cjs.snapshot new file mode 100644 index 00000000000000..6d19904b02228a --- /dev/null +++ b/test/fixtures/test-runner/output/coverage-with-mock-cjs.snapshot @@ -0,0 +1,31 @@ +TAP version 13 +# Subtest: subject calls dependency +ok 1 - subject calls dependency + --- + duration_ms: * + type: 'test' + ... +1..1 +# tests 1 +# suites 0 +# pass 1 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms * +# start of coverage report +# ------------------------------------------------------------------------------- +# file | line % | branch % | funcs % | uncovered lines +# ------------------------------------------------------------------------------- +# test | | | | +# fixtures | | | | +# test-runner | | | | +# coverage-with-mock | | | | +# subject.mjs | 100.00 | 100.00 | 100.00 | +# output | | | | +# coverage-with-mock-cjs.mjs | 100.00 | 100.00 | 100.00 | +# ------------------------------------------------------------------------------- +# all files | 100.00 | 100.00 | 100.00 | +# ------------------------------------------------------------------------------- +# end of coverage report diff --git a/test/test-runner/test-output-coverage-with-mock-cjs.mjs b/test/test-runner/test-output-coverage-with-mock-cjs.mjs new file mode 100644 index 00000000000000..3f8152a5cdcd89 --- /dev/null +++ b/test/test-runner/test-output-coverage-with-mock-cjs.mjs @@ -0,0 +1,22 @@ +import * as common from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import { spawnAndAssert, defaultTransform, ensureCwdIsProjectRoot } from '../common/assertSnapshot.js'; + +if (!process.features.inspector) { + common.skip('inspector support required'); +} + +ensureCwdIsProjectRoot(); +await spawnAndAssert( + fixtures.path('test-runner/output/coverage-with-mock-cjs.mjs'), + defaultTransform, + { + flags: [ + '--disable-warning=ExperimentalWarning', + '--test-reporter=tap', + '--experimental-test-module-mocks', + '--experimental-test-coverage', + '--test-coverage-exclude=!test/**', + ], + }, +);