From 88fec3d1cca79634e47cd78d5fd2714fdb8c7cb7 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 7 Oct 2017 21:48:42 +0200 Subject: [PATCH] Add `module.loaded`, and `module.require` should not be enumerable (#4623) * Make `module.require` non-enumerable * Add `module.loaded` * Tighten type definition of `Module` --- .../__tests__/runtime_require_module.test.js | 34 +++++++++++++++++-- .../src/__tests__/test_root/RegularModule.js | 3 ++ packages/jest-runtime/src/index.js | 20 ++++++++--- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/packages/jest-runtime/src/__tests__/runtime_require_module.test.js b/packages/jest-runtime/src/__tests__/runtime_require_module.test.js index c88f0668c930..0bc393f34320 100644 --- a/packages/jest-runtime/src/__tests__/runtime_require_module.test.js +++ b/packages/jest-runtime/src/__tests__/runtime_require_module.test.js @@ -27,6 +27,23 @@ describe('Runtime requireModule', () => { expect(exports.isRealModule).toBe(true); })); + it('provides `module` to modules', () => + createRuntime(__filename).then(runtime => { + const exports = runtime.requireModule( + runtime.__mockRootPath, + 'RegularModule', + ); + expect(Object.keys(exports.module)).toEqual([ + 'children', + 'exports', + 'filename', + 'id', + 'loaded', + 'parent', + 'paths', + ]); + })); + it('provides `module.parent` to modules', () => createRuntime(__filename).then(runtime => { const exports = runtime.requireModule( @@ -34,13 +51,13 @@ describe('Runtime requireModule', () => { 'RequireRegularModule', ); expect(Object.keys(exports.parent)).toEqual([ + 'children', 'exports', 'filename', 'id', - 'children', + 'loaded', 'parent', 'paths', - 'require', ]); })); @@ -74,6 +91,19 @@ describe('Runtime requireModule', () => { ); })); + it('provides `module.loaded` to modules', () => + createRuntime(__filename).then(runtime => { + const exports = runtime.requireModule( + runtime.__mockRootPath, + 'RegularModule', + ); + + // `exports.loaded` is set while the module is loaded, so should be `false` + expect(exports.loaded).toEqual(false); + // After the module is loaded we can query `module.loaded` again, at which point it should be `true` + expect(exports.isLoaded()).toEqual(true); + })); + it('provides `module.filename` to modules', () => createRuntime(__filename).then(runtime => { const exports = runtime.requireModule( diff --git a/packages/jest-runtime/src/__tests__/test_root/RegularModule.js b/packages/jest-runtime/src/__tests__/test_root/RegularModule.js index c66118146053..1370098e928a 100644 --- a/packages/jest-runtime/src/__tests__/test_root/RegularModule.js +++ b/packages/jest-runtime/src/__tests__/test_root/RegularModule.js @@ -39,3 +39,6 @@ exports.object = {}; exports.parent = module.parent; exports.paths = module.paths; exports.setModuleStateValue = setModuleStateValue; +exports.module = module; +exports.loaded = module.loaded; +exports.isLoaded = () => module.loaded; diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 991c0e2f2917..bf40fdf8f3cb 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -29,13 +29,14 @@ import {run as cilRun} from './cli'; import {options as cliOptions} from './cli/args'; type Module = {| - children?: Array, + children: Array, exports: any, filename: string, id: string, + loaded: boolean, parent?: Module, paths?: Array, - require?: Function, + require?: (id: string) => any, |}; type HasteMapOptions = {| @@ -311,10 +312,12 @@ class Runtime { // We must register the pre-allocated module object first so that any // circular dependencies that may arise while evaluating the module can // be satisfied. - const localModule = { + const localModule: Module = { + children: [], exports: {}, filename: modulePath, id: modulePath, + loaded: false, }; moduleRegistry[modulePath] = localModule; if (path.extname(modulePath) === '.json') { @@ -327,6 +330,8 @@ class Runtime { } else { this._execModule(localModule, options, moduleRegistry, from); } + + localModule.loaded = true; } return moduleRegistry[modulePath].exports; } @@ -381,13 +386,16 @@ class Runtime { } if (manualMock) { - const localModule = { + const localModule: Module = { + children: [], exports: {}, filename: modulePath, id: modulePath, + loaded: false, }; this._execModule(localModule, undefined, this._mockRegistry, from); this._mockRegistry[moduleID] = localModule.exports; + localModule.loaded = true; } else { // Look for a real module to generate an automock from this._mockRegistry[moduleID] = this._generateMock(from, moduleName); @@ -508,7 +516,9 @@ class Runtime { ); localModule.paths = this._resolver.getModulePaths(dirname); - localModule.require = this._createRequireImplementation(filename, options); + Object.defineProperty(localModule, 'require', { + value: this._createRequireImplementation(filename, options), + }); const transformedFile = this._scriptTransformer.transform( filename,