From f8e711c75ef26daacec38aaea5ad6318f908419c Mon Sep 17 00:00:00 2001 From: cpojer Date: Fri, 6 Nov 2015 22:27:20 -0800 Subject: [PATCH] Simplify module execution. --- src/HasteModuleLoader/HasteModuleLoader.js | 73 ++++++++++--------- .../__mocks__/JSDOMEnvironment.js | 8 +- src/lib/utils.js | 40 ---------- 3 files changed, 43 insertions(+), 78 deletions(-) diff --git a/src/HasteModuleLoader/HasteModuleLoader.js b/src/HasteModuleLoader/HasteModuleLoader.js index a1cfb0eed893..7e99a992ca03 100644 --- a/src/HasteModuleLoader/HasteModuleLoader.js +++ b/src/HasteModuleLoader/HasteModuleLoader.js @@ -20,7 +20,6 @@ const resolve = require('resolve'); const transform = require('../lib/transform'); const utils = require('../lib/utils'); -const COVERAGE_STORAGE_VAR_NAME = '____JEST_COVERAGE_DATA____'; const NODE_PATH = (process.env.NODE_PATH ? process.env.NODE_PATH.split(path.delimiter) : null); const IS_PATH_BASED_MODULE_NAME = /^(?:\.\.?\/|\/)/; @@ -168,52 +167,58 @@ class Loader { * objects. */ _execModule(moduleObj) { - const modulePath = moduleObj.__filename; - let moduleContent = transform(modulePath, this._config); + // If the environment was disposed, prevent this module from + // being executed. + if (!this._environment.global) { + return; + } + + const filename = moduleObj.__filename; + let moduleContent = transform(filename, this._config); + let collectorStore; - // Every module, if loaded for jest, should have a parent - // so they don't think they are run standalone + // Every module receives a mock parent so they don't assume they are run + // standalone. moduleObj.parent = mockParentModule; - moduleObj.require = this.constructBoundRequire(modulePath); - - const moduleLocalBindings = { - module: moduleObj, - exports: moduleObj.exports, - require: moduleObj.require, - __dirname: path.dirname(modulePath), - __filename: modulePath, - global: this._environment.global, - jest: this._createRuntimeFor(modulePath), - }; + moduleObj.require = this.constructBoundRequire(filename); const onlyCollectFrom = this._config.collectCoverageOnlyFrom; const shouldCollectCoverage = - this._config.collectCoverage === true && !onlyCollectFrom - || (onlyCollectFrom && onlyCollectFrom[modulePath] === true); + (this._config.collectCoverage === true && !onlyCollectFrom) || + (onlyCollectFrom && onlyCollectFrom[filename] === true); if (shouldCollectCoverage) { - if (!hasOwnProperty.call(this._coverageCollectors, modulePath)) { - this._coverageCollectors[modulePath] = - new this._CoverageCollector(moduleContent, modulePath); + if (!hasOwnProperty.call(this._coverageCollectors, filename)) { + this._coverageCollectors[filename] = + new this._CoverageCollector(moduleContent, filename); } - const collector = this._coverageCollectors[modulePath]; - moduleLocalBindings[COVERAGE_STORAGE_VAR_NAME] = - collector.getCoverageDataStore(); + const collector = this._coverageCollectors[filename]; + collectorStore = collector.getCoverageDataStore(); moduleContent = - collector.getInstrumentedSource(COVERAGE_STORAGE_VAR_NAME); + collector.getInstrumentedSource('____JEST_COVERAGE_DATA____'); } const lastExecutingModulePath = this._currentlyExecutingModulePath; - this._currentlyExecutingModulePath = modulePath; - + this._currentlyExecutingModulePath = filename; const origCurrExecutingManualMock = this._isCurrentlyExecutingManualMock; - this._isCurrentlyExecutingManualMock = modulePath; - - utils.runContentWithLocalBindings( - this._environment, - moduleContent, - modulePath, - moduleLocalBindings + this._isCurrentlyExecutingManualMock = filename; + + // Use this name for the module wrapper for consistency with node. + const evalResultVariable = 'Object.'; + const wrapper = 'this["' + evalResultVariable + '"] = function(module, exports, require, __dirname, __filename, global, jest, ____JEST_COVERAGE_DATA____) {' + moduleContent + '\n};'; + this._environment.runSourceText(wrapper, filename); + const wrapperFunc = this._environment.global[evalResultVariable]; + delete this._environment.global[evalResultVariable]; + wrapperFunc.call( + moduleObj.exports, // module context + moduleObj, + moduleObj.exports, + moduleObj.require, + path.dirname(filename), + filename, + this._environment.global, + this._createRuntimeFor(filename), + collectorStore ); this._isCurrentlyExecutingManualMock = origCurrExecutingManualMock; diff --git a/src/environments/__mocks__/JSDOMEnvironment.js b/src/environments/__mocks__/JSDOMEnvironment.js index e38c5eb3bbf6..1903305aa492 100644 --- a/src/environments/__mocks__/JSDOMEnvironment.js +++ b/src/environments/__mocks__/JSDOMEnvironment.js @@ -11,7 +11,7 @@ JSDOMEnvironment.mockImplementation(function(config) { this.global = { console: {}, mockClearTimers: jest.genMockFn(), - JSON: JSON, + JSON, }; const globalValues = utils.deepCopy(config.globals); @@ -21,9 +21,9 @@ JSDOMEnvironment.mockImplementation(function(config) { }); JSDOMEnvironment.prototype.runSourceText.mockImplementation( - function(codeStr, fileName) { - vm.runInNewContext(codeStr, this.global, { - filename: fileName, + function(sourceText, filename) { + vm.runInNewContext(sourceText, this.global, { + filename, displayErrors: false, }); } diff --git a/src/lib/utils.js b/src/lib/utils.js index 461425a7c1ac..101db51b2793 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -45,11 +45,6 @@ const DEFAULT_CONFIG_VALUES = { useStderr: false, }; -// This shows up in the stack trace when a test file throws an unhandled error -// when evaluated. Node's require prints Object. when initializing -// modules, so do the same here solely for visual consistency. -const EVAL_RESULT_VARIABLE = 'Object.'; - function _replaceRootDirTags(rootDir, config) { switch (typeof config) { case 'object': @@ -367,40 +362,6 @@ function loadConfigFromPackageJson(filePath) { }); } -function runContentWithLocalBindings(environment, scriptContent, scriptPath, - bindings) { - const boundIdents = Object.keys(bindings); - try { - const wrapperScript = 'this["' + EVAL_RESULT_VARIABLE + '"] = ' + - 'function (' + boundIdents.join(',') + ') {' + - scriptContent + - '\n};'; - environment.runSourceText( - wrapperScript, - scriptPath - ); - } catch (e) { - e.message = scriptPath + ': ' + e.message; - throw e; - } - - const wrapperFunc = environment.global[EVAL_RESULT_VARIABLE]; - delete environment.global[EVAL_RESULT_VARIABLE]; - - const bindingValues = boundIdents.map(function(ident) { - return bindings[ident]; - }); - - try { - // Node modules are executed with the `exports` as context. - // If not a node module then this should be undefined. - wrapperFunc.apply(bindings.exports, bindingValues); - } catch (e) { - e.message = scriptPath + ': ' + e.message; - throw e; - } -} - /** * Given a test result, return a human readable string representing the * failures. @@ -503,5 +464,4 @@ exports.getLinePercentCoverageFromCoverageInfo = exports.loadConfigFromFile = loadConfigFromFile; exports.loadConfigFromPackageJson = loadConfigFromPackageJson; exports.normalizeConfig = normalizeConfig; -exports.runContentWithLocalBindings = runContentWithLocalBindings; exports.formatFailureMessage = formatFailureMessage;