Skip to content

Commit 18f8ed2

Browse files
committed
test_runner: refactor mock_loader
1 parent 7327e44 commit 18f8ed2

File tree

3 files changed

+21
-75
lines changed

3 files changed

+21
-75
lines changed

lib/internal/test_runner/mock/mock.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const {
3434
} = require('internal/errors');
3535
const esmLoader = require('internal/modules/esm/loader');
3636
const { getOptionValue } = require('internal/options');
37-
const { fileURLToPath, toPathIfFileURL, URL } = require('internal/url');
37+
const { fileURLToPath, toPathIfFileURL, URL, pathToFileURL } = require('internal/url');
3838
const {
3939
emitExperimentalWarning,
4040
getStructuredStack,
@@ -508,7 +508,7 @@ class MockTracker {
508508

509509
// Get the file that called this function. We need four stack frames:
510510
// vm context -> getStructuredStack() -> this function -> actual caller.
511-
const caller = getStructuredStack()[3]?.getFileName();
511+
const caller = pathToFileURL(getStructuredStack()[3]?.getFileName()).href;
512512
const { format, url } = sharedState.moduleLoader.resolveSync(
513513
mockSpecifier, caller, null,
514514
);

lib/test/mock_loader.js

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,16 @@ const {
1010
},
1111
} = primordials;
1212
const {
13-
ensureNodeScheme,
1413
kBadExportsMessage,
1514
kMockSearchParam,
1615
kMockSuccess,
1716
kMockExists,
1817
kMockUnknownMessage,
1918
} = require('internal/test_runner/mock/mock');
20-
const { pathToFileURL, URL } = require('internal/url');
21-
const { normalizeReferrerURL } = require('internal/modules/helpers');
19+
const { URL, URLParse } = require('internal/url');
2220
let debug = require('internal/util/debuglog').debuglog('test_runner', (fn) => {
2321
debug = fn;
2422
});
25-
const { createRequire, isBuiltin } = require('module');
26-
const { defaultGetFormatWithoutErrors } = require('internal/modules/esm/get_format');
27-
const { defaultResolve } = require('internal/modules/esm/resolve');
2823

2924
// TODO(cjihrig): This file should not be exposed publicly, but register() does
3025
// not handle internal loaders. Before marking this API as stable, one of the
@@ -85,46 +80,18 @@ async function initialize(data) {
8580

8681
async function resolve(specifier, context, nextResolve) {
8782
debug('resolve hook entry, specifier = "%s", context = %o', specifier, context);
88-
let mockSpecifier;
8983

90-
if (isBuiltin(specifier)) {
91-
mockSpecifier = ensureNodeScheme(specifier);
92-
} else {
93-
let format;
94-
95-
if (context.parentURL) {
96-
format = defaultGetFormatWithoutErrors(pathToFileURL(context.parentURL));
97-
}
98-
99-
try {
100-
if (format === 'module') {
101-
specifier = defaultResolve(specifier, context).url;
102-
} else {
103-
specifier = pathToFileURL(
104-
createRequire(context.parentURL).resolve(specifier),
105-
).href;
106-
}
107-
} catch {
108-
const parentURL = normalizeReferrerURL(context.parentURL);
109-
const parsedURL = URL.parse(specifier, parentURL)?.href;
110-
111-
if (parsedURL) {
112-
specifier = parsedURL;
113-
}
114-
}
115-
116-
mockSpecifier = specifier;
117-
}
84+
const nextResolveResult = await nextResolve(specifier, context);
85+
const mockSpecifier = nextResolveResult.url;
11886

11987
const mock = mocks.get(mockSpecifier);
12088
debug('resolve hook, specifier = "%s", mock = %o', specifier, mock);
12189

12290
if (mock?.active !== true) {
123-
return nextResolve(specifier, context);
91+
return nextResolveResult;
12492
}
12593

12694
const url = new URL(mockSpecifier);
127-
12895
url.searchParams.set(kMockSearchParam, mock.localVersion);
12996

13097
if (!mock.cache) {
@@ -133,13 +100,14 @@ async function resolve(specifier, context, nextResolve) {
133100
mock.localVersion++;
134101
}
135102

136-
debug('resolve hook finished, url = "%s"', url.href);
137-
return nextResolve(url.href, context);
103+
const { href } = url;
104+
debug('resolve hook finished, url = "%s"', href);
105+
return { __proto__: null, url: href, format: nextResolveResult.format };
138106
}
139107

140108
async function load(url, context, nextLoad) {
141109
debug('load hook entry, url = "%s", context = %o', url, context);
142-
const parsedURL = URL.parse(url);
110+
const parsedURL = URLParse(url);
143111
if (parsedURL) {
144112
parsedURL.searchParams.delete(kMockSearchParam);
145113
}

test/parallel/test-runner-module-mocking.js

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const fixtures = require('../common/fixtures');
1010
const assert = require('node:assert');
1111
const { relative } = require('node:path');
1212
const { test } = require('node:test');
13-
const { pathToFileURL } = require('node:url');
13+
const { fileURLToPath, pathToFileURL } = require('node:url');
1414

1515
test('input validation', async (t) => {
1616
await t.test('throws if specifier is not a string', (t) => {
@@ -514,41 +514,21 @@ test('CJS mocks can be used by both module systems', async (t) => {
514514
const cjsMock = t.mock.module(cjsFixture, {
515515
namedExports: { fn() { return 42; } },
516516
});
517-
let esmImpl = await import(cjsFixture);
517+
let esmImpl = await import(pathToFileURL(cjsFixture));
518518
let cjsImpl = require(cjsFixture);
519519

520520
assert.strictEqual(esmImpl.fn(), 42);
521521
assert.strictEqual(cjsImpl.fn(), 42);
522522

523523
cjsMock.restore();
524524

525-
esmImpl = await import(cjsFixture);
525+
esmImpl = await import(pathToFileURL(cjsFixture));
526526
cjsImpl = require(cjsFixture);
527527

528528
assert.strictEqual(esmImpl.default.string, 'original cjs string');
529529
assert.strictEqual(cjsImpl.string, 'original cjs string');
530530
});
531531

532-
test('ESM mocks can be used by both module systems', async (t) => {
533-
const esmFixture = fixtures.path('module-mocking', 'basic-esm.mjs');
534-
const esmMock = t.mock.module(esmFixture, {
535-
namedExports: { fn() { return 42; } },
536-
});
537-
538-
let cjsImpl = require(esmFixture);
539-
let esmImpl = await import(esmFixture);
540-
541-
assert.strictEqual(cjsImpl.fn(), 42);
542-
assert.strictEqual(esmImpl.fn(), 42);
543-
544-
esmMock.restore();
545-
cjsImpl = require(esmFixture);
546-
esmImpl = await import(esmFixture);
547-
548-
assert.strictEqual(esmImpl.string, 'original esm string');
549-
assert.strictEqual(cjsImpl.string, 'original esm string');
550-
});
551-
552532
test('relative paths can be used by both module systems', async (t) => {
553533
const fixture = relative(
554534
__dirname, fixtures.path('module-mocking', 'basic-esm.mjs')
@@ -586,9 +566,7 @@ test('node_modules can be used by both module systems', async (t) => {
586566
});
587567

588568
test('file:// imports are supported in ESM only', async (t) => {
589-
const fixture = pathToFileURL(
590-
fixtures.path('module-mocking', 'basic-esm.mjs')
591-
).href;
569+
const fixture = fixtures.fileURL('module-mocking', 'basic-esm.mjs').href;
592570
const mock = t.mock.module(fixture, {
593571
namedExports: { fn() { return 42; } },
594572
});
@@ -604,9 +582,9 @@ test('file:// imports are supported in ESM only', async (t) => {
604582
});
605583

606584
test('mocked modules do not impact unmocked modules', async (t) => {
607-
const mockedFixture = fixtures.path('module-mocking', 'basic-cjs.js');
608-
const unmockedFixture = fixtures.path('module-mocking', 'basic-esm.mjs');
609-
t.mock.module(mockedFixture, {
585+
const mockedFixture = fixtures.fileURL('module-mocking', 'basic-cjs.js');
586+
const unmockedFixture = fixtures.fileURL('module-mocking', 'basic-esm.mjs');
587+
t.mock.module(`${mockedFixture}`, {
610588
namedExports: { fn() { return 42; } },
611589
});
612590
const mockedImpl = await import(mockedFixture);
@@ -625,18 +603,18 @@ test('defaultExports work with CJS mocks in both module systems', async (t) => {
625603
assert.strictEqual(original.string, 'original cjs string');
626604
t.mock.module(fixture, { defaultExport });
627605
assert.strictEqual(require(fixture), defaultExport);
628-
assert.strictEqual((await import(fixture)).default, defaultExport);
606+
assert.strictEqual((await import(pathToFileURL(fixture))).default, defaultExport);
629607
});
630608

631609
test('defaultExports work with ESM mocks in both module systems', async (t) => {
632-
const fixture = fixtures.path('module-mocking', 'basic-esm.mjs');
610+
const fixture = fixtures.fileURL('module-mocking', 'basic-esm.mjs');
633611
const original = await import(fixture);
634612
const defaultExport = Symbol('default');
635613

636614
assert.strictEqual(original.string, 'original esm string');
637-
t.mock.module(fixture, { defaultExport });
615+
t.mock.module(`${fixture}`, { defaultExport });
638616
assert.strictEqual((await import(fixture)).default, defaultExport);
639-
assert.strictEqual(require(fixture), defaultExport);
617+
assert.strictEqual(require(fileURLToPath(fixture)), defaultExport);
640618
});
641619

642620
test('wrong import syntax should throw error after module mocking.', async () => {

0 commit comments

Comments
 (0)