-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
working mock test #39240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
working mock test #39240
Changes from 14 commits
13ab19e
ffdaa30
f5e96f3
f923cce
0e1e124
4e4ed13
8369c4a
57ace81
7416b27
d0276c6
0e11bde
172c038
b9e1380
5ad4c1b
d61b7d4
93ba88a
1c5996d
b9f339f
05e71c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| 'use strict'; | ||
|
|
||
|
bmeck marked this conversation as resolved.
|
||
| const { getOptionValue } = require('internal/options'); | ||
| const experimentalImportMetaResolve = | ||
| getOptionValue('--experimental-import-meta-resolve'); | ||
| const { PromisePrototypeThen, PromiseReject } = primordials; | ||
| const asyncESM = require('internal/process/esm_loader'); | ||
|
|
||
| function createImportMetaResolve(defaultParentUrl) { | ||
| return async function resolve(specifier, parentUrl = defaultParentUrl) { | ||
| return PromisePrototypeThen( | ||
| asyncESM.esmLoader.resolve(specifier, parentUrl), | ||
|
bmeck marked this conversation as resolved.
|
||
| ({ url }) => url, | ||
| (error) => ( | ||
| error.code === 'ERR_UNSUPPORTED_DIR_IMPORT' ? | ||
| error.url : PromiseReject(error)) | ||
| ); | ||
| }; | ||
|
bmeck marked this conversation as resolved.
|
||
| } | ||
|
|
||
| function initializeImportMeta(meta, context) { | ||
| const url = context.url; | ||
|
|
||
| // Alphabetical | ||
| if (experimentalImportMetaResolve) | ||
| meta.resolve = createImportMetaResolve(url); | ||
|
bmeck marked this conversation as resolved.
|
||
| meta.url = url; | ||
| } | ||
|
|
||
| module.exports = { | ||
| initializeImportMeta | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ const { | |
| SafeWeakMap, | ||
| globalThis, | ||
| } = primordials; | ||
| const { MessageChannel } = require('internal/worker/io'); | ||
|
|
||
| const { | ||
| ERR_INVALID_ARG_TYPE, | ||
|
|
@@ -39,6 +40,9 @@ const { | |
| defaultResolve, | ||
| DEFAULT_CONDITIONS, | ||
| } = require('internal/modules/esm/resolve'); | ||
| const { | ||
| initializeImportMeta | ||
| } = require('internal/modules/esm/initialize_import_meta'); | ||
| const { defaultLoad } = require('internal/modules/esm/load'); | ||
| const { translators } = require( | ||
| 'internal/modules/esm/translators'); | ||
|
|
@@ -76,6 +80,8 @@ class ESMLoader { | |
| defaultResolve, | ||
| ]; | ||
|
|
||
| #importMetaInitializer = initializeImportMeta; | ||
|
|
||
| /** | ||
| * Map of already-loaded CJS modules to use | ||
| */ | ||
|
|
@@ -359,7 +365,18 @@ class ESMLoader { | |
| if (!count) return; | ||
|
|
||
| for (let i = 0; i < count; i++) { | ||
| const preload = this.#globalPreloaders[i](); | ||
| const channel = new MessageChannel(); | ||
| const { | ||
| port1: insidePreload, | ||
| port2: insideLoader, | ||
| } = channel; | ||
|
|
||
| insidePreload.unref(); | ||
| insideLoader.unref(); | ||
|
|
||
| const preload = this.#globalPreloaders[i]({ | ||
| port: insideLoader | ||
| }); | ||
|
|
||
| if (preload == null) return; | ||
|
|
||
|
|
@@ -373,22 +390,44 @@ class ESMLoader { | |
| const { compileFunction } = require('vm'); | ||
| const preloadInit = compileFunction( | ||
| preload, | ||
| ['getBuiltin'], | ||
| ['getBuiltin', 'port', 'setImportMetaCallback'], | ||
| { | ||
| filename: '<preload>', | ||
| } | ||
| ); | ||
| const { NativeModule } = require('internal/bootstrap/loaders'); | ||
|
|
||
| FunctionPrototypeCall(preloadInit, globalThis, (builtinName) => { | ||
| if (NativeModule.canBeRequiredByUsers(builtinName)) { | ||
| return require(builtinName); | ||
| let finished = false; | ||
| let replacedImportMetaInitializer = false; | ||
| let next = this.#importMetaInitializer; | ||
| try { | ||
| FunctionPrototypeCall(preloadInit, globalThis, (builtinName) => { | ||
| if (NativeModule.canBeRequiredByUsers(builtinName)) { | ||
| return require(builtinName); | ||
| } | ||
| throw new ERR_INVALID_ARG_VALUE('builtinName', builtinName); | ||
| }, insidePreload, (fn) => { | ||
| if (finished || typeof fn !== 'function') { | ||
| throw new ERR_INVALID_ARG_TYPE('fn', fn); | ||
| } | ||
| replacedImportMetaInitializer = true; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’m struggling to follow this code. Are we in a callback here? Can this be split out? I see that by now we’ve apparently replaced |
||
| const parent = next; | ||
| next = (meta, context) => { | ||
| return fn(meta, context, parent); | ||
| }; | ||
| }); | ||
| } finally { | ||
| finished = true; | ||
| if (replacedImportMetaInitializer) { | ||
| this.#importMetaInitializer = next; | ||
|
GeoffreyBooth marked this conversation as resolved.
|
||
| } | ||
| throw new ERR_INVALID_ARG_VALUE('builtinName', builtinName); | ||
| }); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| importMetaInitialize(meta, context) { | ||
| this.#importMetaInitializer(meta, context); | ||
| } | ||
|
GeoffreyBooth marked this conversation as resolved.
|
||
|
|
||
| /** | ||
| * Resolve the location of the module. | ||
| * | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| // Flags: --loader ./test/fixtures/es-module-loaders/mock-loader.mjs | ||
| import '../common/index.mjs'; | ||
| import assert from 'assert/strict'; | ||
|
|
||
| // This is provided by test/fixtures/es-module-loaders/mock-loader.mjs | ||
| import mock from 'node:mock'; | ||
|
bmeck marked this conversation as resolved.
|
||
|
|
||
| mock('node:events', { | ||
| EventEmitter: 'This is mocked!' | ||
| }); | ||
|
|
||
| // This resolves to node:events | ||
| // It is intercepted by mock-loader and doesn't return the normal value | ||
| assert.deepStrictEqual(await import('events'), Object.defineProperty({ | ||
|
Comment on lines
+10
to
+14
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes |
||
| __proto__: null, | ||
| EventEmitter: 'This is mocked!' | ||
| }, Symbol.toStringTag, { | ||
| enumerable: false, | ||
| value: 'Module' | ||
| })); | ||
|
|
||
| const mutator = mock('node:events', { | ||
| EventEmitter: 'This is mocked v2!' | ||
| }); | ||
|
|
||
| // It is intercepted by mock-loader and doesn't return the normal value. | ||
| // This is resolved separately from the import above since the specifiers | ||
| // are different. | ||
| const mockedV2 = await import('node:events'); | ||
| assert.deepStrictEqual(mockedV2, Object.defineProperty({ | ||
| __proto__: null, | ||
| EventEmitter: 'This is mocked v2!' | ||
| }, Symbol.toStringTag, { | ||
| enumerable: false, | ||
| value: 'Module' | ||
| })); | ||
|
|
||
| mutator.EventEmitter = 'This is mocked v3!'; | ||
| assert.deepStrictEqual(mockedV2, Object.defineProperty({ | ||
| __proto__: null, | ||
| EventEmitter: 'This is mocked v3!' | ||
| }, Symbol.toStringTag, { | ||
| enumerable: false, | ||
| value: 'Module' | ||
| })); | ||
Uh oh!
There was an error while loading. Please reload this page.