diff --git a/integration_tests/__tests__/leak_detection.test.js b/integration_tests/__tests__/leak_detection.test.js deleted file mode 100644 index d6838809f6f8..000000000000 --- a/integration_tests/__tests__/leak_detection.test.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ -'use strict'; - -const runJest = require('../runJest'); - -it('Makes sure that Jest does not leak the environment', () => { - const result = runJest.json('leak-detection', ['--detectLeaks']).json; - - expect(result.success).toBe(true); -}); diff --git a/integration_tests/__tests__/require_all_modules.test.js b/integration_tests/__tests__/require_all_modules.test.js deleted file mode 100644 index 5012efbb064a..000000000000 --- a/integration_tests/__tests__/require_all_modules.test.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ -'use strict'; - -const runJest = require('../runJest'); - -it('Makes sure that no native module makes Jest crash', () => { - const result = runJest.json('require-all-modules').json; - - if (!result.success) { - console.warn(result); - } - - expect(result.success).toBe(true); -}); diff --git a/integration_tests/leak-detection/package.json b/integration_tests/leak-detection/package.json deleted file mode 100644 index 148788b25446..000000000000 --- a/integration_tests/leak-detection/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "jest": { - "testEnvironment": "node" - } -} diff --git a/integration_tests/leak-detection/test.js b/integration_tests/leak-detection/test.js deleted file mode 100644 index c36d6aa9e22c..000000000000 --- a/integration_tests/leak-detection/test.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -const fs = require('fs'); -const http = require('http'); - -it('expands a native module', () => { - fs.expandingNativeObject = () => { - console.log(global); - }; -}); - -it('expands the prototype of a native constructor', () => { - http.ServerResponse.prototype.expandingNativePrototype = () => { - console.log(global); - }; -}); - -it('adds listeners to process', () => { - process.on('foo', () => { - console.log(global); - }); -}); diff --git a/integration_tests/require-all-modules/package.json b/integration_tests/require-all-modules/package.json deleted file mode 100644 index 148788b25446..000000000000 --- a/integration_tests/require-all-modules/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "jest": { - "testEnvironment": "node" - } -} diff --git a/integration_tests/require-all-modules/test.js b/integration_tests/require-all-modules/test.js deleted file mode 100644 index 084fb77ca1da..000000000000 --- a/integration_tests/require-all-modules/test.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -it('requires all native modules to check they all work', () => { - const modules = Object.keys(process.binding('natives')).filter(module => - /^[^_][^\/]*$/.test(module) - ); - - // Node 6 has 34 native modules; so the total value has to be >= than 34. - expect(modules.length).not.toBeLessThan(34); - - // Require all modules to verify they don't throw. - modules.forEach(module => require(module)); -}); diff --git a/jest-inspect b/jest-inspect deleted file mode 100755 index 94f7c764a274..000000000000 --- a/jest-inspect +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env node --inspect-brk -/** - * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -require('./packages/jest-cli/bin/jest'); diff --git a/packages/jest-editor-support/src/__tests__/runner.test.js b/packages/jest-editor-support/src/__tests__/runner.test.js index 12e55c4a2f64..5bcfd6623d64 100644 --- a/packages/jest-editor-support/src/__tests__/runner.test.js +++ b/packages/jest-editor-support/src/__tests__/runner.test.js @@ -15,10 +15,6 @@ const {readFileSync} = require('fs'); const fixtures = path.resolve(__dirname, '../../../../fixtures'); import ProjectWorkspace from '../project_workspace'; -// Win32 requires to spawn a process to kill the first one, by using "taskkill". -// Mocking "child_process" avoids the async spawn. -jest.mock('child_process'); - // Replace `readFile` with `readFileSync` so we don't get multiple threads jest.doMock('fs', () => { return { diff --git a/packages/jest-jasmine2/src/index.js b/packages/jest-jasmine2/src/index.js index e55d247aba76..724d0e03e921 100644 --- a/packages/jest-jasmine2/src/index.js +++ b/packages/jest-jasmine2/src/index.js @@ -25,17 +25,10 @@ const JASMINE = require.resolve('./jasmine/jasmine_light.js'); async function jasmine2( globalConfig: GlobalConfig, config: ProjectConfig, - environment: ?Environment, + environment: Environment, runtime: Runtime, testPath: string, ): Promise { - // The "environment" parameter is nullable just so that we can clean its - // reference after adding some variables to it; but you still need to pass - // it when calling "jasmine2". - if (!environment) { - throw new ReferenceError('Please pass a valid Jest Environment object'); - } - const reporter = new JasmineReporter( globalConfig, config, @@ -92,17 +85,12 @@ async function jasmine2( if (config.resetMocks) { runtime.resetAllMocks(); - if (environment && config.timers === 'fake') { + if (config.timers === 'fake') { environment.fakeTimers.useFakeTimers(); } } }); - // Free references to environment to avoid leaks. - env.afterAll(() => { - environment = null; - }); - env.addReporter(reporter); runtime @@ -126,9 +114,7 @@ async function jasmine2( if (config.setupTestFramework && config.setupTestFramework.length) { config.setupTestFramework.forEach(module => { - if (environment) { - require(module)(environment.global); - } + require(module)(environment.global); }); } diff --git a/packages/jest-message-util/src/index.js b/packages/jest-message-util/src/index.js index 296040b8795c..3ed544fdffbb 100644 --- a/packages/jest-message-util/src/index.js +++ b/packages/jest-message-util/src/index.js @@ -40,8 +40,6 @@ type StackTraceOptions = { // filter for noisy stack trace lines const JASMINE_IGNORE = /^\s+at(?:(?:.*?vendor\/|jasmine\-)|\s+jasmine\.buildExpectationResult)/; const JEST_INTERNALS_IGNORE = /^\s+at.*?jest(-.*?)?(\/|\\)(build|node_modules|packages)(\/|\\)/; - -const JEST_NODE_NATIVE_IGNORE = /^\s+at.*?jest-node-native-/; const ANONYMOUS_FN_IGNORE = /^\s+at .*$/; const ANONYMOUS_PROMISE_IGNORE = /^\s+at (new )?Promise \(\).*$/; const ANONYMOUS_GENERATOR_IGNORE = /^\s+at Generator.next \(\).*$/; @@ -140,10 +138,6 @@ const removeInternalStackEntries = (lines, options: StackTraceOptions) => { return false; } - if (JEST_NODE_NATIVE_IGNORE.test(line)) { - return false; - } - if (!STACK_PATH_REGEXP.test(line)) { return true; } diff --git a/packages/jest-runner/src/run_test.js b/packages/jest-runner/src/run_test.js index 94642ad4edf8..9c54916c522a 100644 --- a/packages/jest-runner/src/run_test.js +++ b/packages/jest-runner/src/run_test.js @@ -74,8 +74,7 @@ async function runTestInternal( RuntimeClass, >); - let environment = new TestEnvironment(config); - + const environment = new TestEnvironment(config); const leakDetector = config.detectLeaks ? new LeakDetector(environment) : null; @@ -99,24 +98,15 @@ async function runTestInternal( testConsole = new BufferedConsole(); } - let cacheFS = {[path]: testSource}; + const cacheFS = {[path]: testSource}; setGlobal(environment.global, 'console', testConsole); - const coverageOptions = { + const runtime = new Runtime(config, environment, resolver, cacheFS, { collectCoverage: globalConfig.collectCoverage, collectCoverageFrom: globalConfig.collectCoverageFrom, collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom, mapCoverage: globalConfig.mapCoverage, - }; - - let runtime = new Runtime( - config, - environment, - resolver, - cacheFS, - coverageOptions, - path, - ); + }); const start = Date.now(); await environment.setup(); @@ -139,23 +129,19 @@ async function runTestInternal( result.skipped = testCount === result.numPendingTests; result.displayName = config.displayName; + if (globalConfig.logHeapUsage) { + if (global.gc) { + global.gc(); + } + result.memoryUsage = process.memoryUsage().heapUsed; + } + // Delay the resolution to allow log messages to be output. return new Promise(resolve => { setImmediate(() => resolve({leakDetector, result})); }); } finally { - if (environment.teardown) { - await environment.teardown(); - } - - if (runtime.reset) { - await runtime.reset(); - } - - // Free references to environment to avoid leaks. - cacheFS = null; - environment = null; - runtime = null; + await environment.teardown(); } } @@ -172,11 +158,6 @@ export default async function runTest( resolver, ); - if (globalConfig.logHeapUsage) { - global.gc && global.gc(); - result.memoryUsage = process.memoryUsage().heapUsed; - } - // Resolve leak detector, outside the "runTestInternal" closure. result.leaks = leakDetector ? leakDetector.isLeaking() : false; diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 4ece57b268ca..9a322f6fc32d 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -19,7 +19,7 @@ import type {MockFunctionMetadata, ModuleMocker} from 'types/Mock'; import path from 'path'; import HasteMap from 'jest-haste-map'; import Resolver from 'jest-resolve'; -import {createDirectory, deepCyclicCopy} from 'jest-util'; +import {createDirectory} from 'jest-util'; import {escapePathForRegex} from 'jest-regex-util'; import fs from 'graceful-fs'; import stripBOM from 'strip-bom'; @@ -49,7 +49,6 @@ type HasteMapOptions = {| type InternalModuleOptions = {| isInternalModule: boolean, - isNativeModule: boolean, |}; type CoverageOptions = { @@ -97,8 +96,6 @@ class Runtime { _mockRegistry: {[key: string]: any, __proto__: null}; _moduleMocker: ModuleMocker; _moduleRegistry: ModuleRegistry; - _nativeModuleRegistry: ModuleRegistry; - _path: Path; _resolver: Resolver; _shouldAutoMock: boolean; _shouldMockModuleCache: BooleanObject; @@ -115,10 +112,7 @@ class Runtime { resolver: Resolver, cacheFS?: CacheFS, coverageOptions?: CoverageOptions, - path?: Path, ) { - this.reset(); - this._cacheFS = cacheFS || Object.create(null); this._config = config; this._coverageOptions = coverageOptions || { @@ -127,18 +121,22 @@ class Runtime { collectCoverageOnlyFrom: null, mapCoverage: false, }; - this._currentlyExecutingModulePath = ''; this._environment = environment; this._explicitShouldMock = Object.create(null); + this._internalModuleRegistry = Object.create(null); this._isCurrentlyExecutingManualMock = null; + this._mockFactories = Object.create(null); + this._mockRegistry = Object.create(null); this._moduleMocker = this._environment.moduleMocker; - this._path = path || ''; + this._moduleRegistry = Object.create(null); this._resolver = resolver; this._scriptTransformer = new ScriptTransformer(config); this._shouldAutoMock = config.automock; + this._sourceMapRegistry = Object.create(null); this._virtualMocks = Object.create(null); + this._mockMetaDataCache = Object.create(null); this._shouldMockModuleCache = Object.create(null); this._shouldUnmockTransitiveDependenciesCache = Object.create(null); this._transitiveShouldMock = Object.create(null); @@ -269,69 +267,40 @@ class Runtime { return cliOptions; } - reset() { - // Clean mock data. - this._mockFactories = Object.create(null); - this._mockMetaDataCache = Object.create(null); - this._mockRegistry = Object.create(null); - - // Clean registry data. - this._internalModuleRegistry = Object.create(null); - this._moduleRegistry = Object.create(null); - this._nativeModuleRegistry = Object.create(null); - - // Clean other registries. - this._cacheFS = Object.create(null); - this._sourceMapRegistry = Object.create(null); - - // $FlowFixMe: de-reference environment. - this._environment = null; - } - requireModule( from: Path, moduleName?: string, options: ?InternalModuleOptions, ) { - const isNativeModule = - moduleName && - ((options && options.isNativeModule) || - this._resolver.isCoreModule(moduleName)); - - const moduleID = - !isNativeModule && - this._resolver.getModuleID(this._virtualMocks, from, moduleName); - - let moduleRegistry; + const moduleID = this._resolver.getModuleID( + this._virtualMocks, + from, + moduleName, + ); let modulePath; - if (isNativeModule) { - moduleRegistry = this._nativeModuleRegistry; - } else if (options && options.isInternalModule) { - moduleRegistry = this._internalModuleRegistry; - } else { - moduleRegistry = this._moduleRegistry; - } + const moduleRegistry = + !options || !options.isInternalModule + ? this._moduleRegistry + : this._internalModuleRegistry; // Some old tests rely on this mocking behavior. Ideally we'll change this // to be more explicit. const moduleResource = moduleName && this._resolver.getModule(moduleName); const manualMock = moduleName && this._resolver.getMockModule(from, moduleName); - if ( (!options || !options.isInternalModule) && !moduleResource && manualMock && manualMock !== this._isCurrentlyExecutingManualMock && - moduleID && this._explicitShouldMock[moduleID] !== false ) { modulePath = manualMock; } - if (isNativeModule) { - modulePath = moduleName; + if (moduleName && this._resolver.isCoreModule(moduleName)) { + return this._requireCoreModule(moduleName); } if (!modulePath) { @@ -349,9 +318,7 @@ class Runtime { id: modulePath, loaded: false, }; - moduleRegistry[modulePath] = localModule; - if (path.extname(modulePath) === '.json') { localModule.exports = this._environment.global.JSON.parse( stripBOM(fs.readFileSync(modulePath, 'utf8')), @@ -359,38 +326,17 @@ class Runtime { } else if (path.extname(modulePath) === '.node') { // $FlowFixMe localModule.exports = require(modulePath); - } else if (moduleName && isNativeModule) { - // Use a special resolution when requiring Node's internal modules. For - // instance, the "util" module requires "internal/util" which refers to - // an internal file and not to the NPM "internal" module. - this._requireNativeModule( - localModule, - moduleName, - moduleRegistry, - from, - ); } else { this._execModule(localModule, options, moduleRegistry, from); } localModule.loaded = true; } - return moduleRegistry[modulePath].exports; } requireInternalModule(from: Path, to?: string) { - return this.requireModule(from, to, { - isInternalModule: true, - isNativeModule: false, - }); - } - - requireNativeModule(from: Path, to?: string) { - return this.requireModule(from, to, { - isInternalModule: true, - isNativeModule: true, - }); + return this.requireModule(from, to, {isInternalModule: true}); } requireMock(from: Path, moduleName: string) { @@ -541,30 +487,19 @@ class Runtime { moduleRegistry: ModuleRegistry, from: Path, ) { - if (!this._environment) { - throw new Error( - `A module was required after the test suite ${this._path} finished.\n` + - `In most cases this is because an async operation was not cleaned ` + - `up or mocked properly.`, - ); - } - // If the environment was disposed, prevent this module from being executed. if (!this._environment.global) { return; } const isInternalModule = !!(options && options.isInternalModule); - const isNativeModule = !!(options && options.isNativeModule); const filename = localModule.filename; - const lastExecutingModulePath = this._currentlyExecutingModulePath; this._currentlyExecutingModulePath = filename; - const origCurrExecutingManualMock = this._isCurrentlyExecutingManualMock; this._isCurrentlyExecutingManualMock = filename; - const dirname = isNativeModule ? '' : path.dirname(filename); + const dirname = path.dirname(filename); localModule.children = []; Object.defineProperty( @@ -580,16 +515,10 @@ class Runtime { ); localModule.paths = this._resolver.getModulePaths(dirname); - Object.defineProperty(localModule, 'require', { value: this._createRequireImplementation(filename, options), }); - const fileSource = isNativeModule - ? // $FlowFixMe: process.binding exists. - process.binding('natives')[filename] - : this._cacheFS[filename]; - const transformedFile = this._scriptTransformer.transform( filename, { @@ -597,10 +526,9 @@ class Runtime { collectCoverageFrom: this._coverageOptions.collectCoverageFrom, collectCoverageOnlyFrom: this._coverageOptions.collectCoverageOnlyFrom, isInternalModule, - isNativeModule, mapCoverage: this._coverageOptions.mapCoverage, }, - fileSource, + this._cacheFS[filename], ); if (transformedFile.sourceMapPath) { @@ -610,7 +538,6 @@ class Runtime { const wrapper = this._environment.runScript(transformedFile.script)[ ScriptTransformer.EVAL_RESULT_VARIABLE ]; - wrapper.call( localModule.exports, // module context localModule, // module object @@ -630,41 +557,13 @@ class Runtime { this._currentlyExecutingModulePath = lastExecutingModulePath; } - _requireNativeModule( - localModule: Module, - moduleName: string, - moduleRegistry: ModuleRegistry, - from: Path, - ) { - switch (moduleName) { - case 'async_hooks': // Pure native module. - case 'buffer': // Causes issues when passing buffers to another context. - case 'module': // Calls into native_module, which is not mockable. - // $FlowFixMe: dynamic require needed. - localModule.exports = require(moduleName); - break; - - case 'os': // Pure native module. - case 'v8': // Contains invalid references. - // $FlowFixMe: dynamic require needed. - localModule.exports = deepCyclicCopy(require(moduleName)); - break; - - case 'process': // Make sure that the returned reference is consistent. - localModule.exports = this._environment.global.process; - break; - - default: - this._execModule( - localModule, - { - isInternalModule: true, - isNativeModule: true, - }, - moduleRegistry, - from, - ); + _requireCoreModule(moduleName: string) { + if (moduleName === 'process') { + return this._environment.global.process; } + + // $FlowFixMe + return require(moduleName); } _generateMock(from: Path, moduleName: string) { @@ -777,22 +676,15 @@ class Runtime { from: Path, options: ?InternalModuleOptions, ): LocalModuleRequire { - let moduleRequire; - - if (options && options.isNativeModule) { - moduleRequire = this.requireNativeModule.bind(this, from); - } else if (options && options.isInternalModule) { - moduleRequire = this.requireInternalModule.bind(this, from); - } else { - moduleRequire = this.requireModuleOrMock.bind(this, from); - } - + const moduleRequire = + options && options.isInternalModule + ? (moduleName: string) => this.requireInternalModule(from, moduleName) + : this.requireModuleOrMock.bind(this, from); moduleRequire.cache = Object.create(null); moduleRequire.extensions = Object.create(null); moduleRequire.requireActual = this.requireModule.bind(this, from); moduleRequire.requireMock = this.requireMock.bind(this, from); moduleRequire.resolve = moduleName => this._resolveModule(from, moduleName); - return moduleRequire; } diff --git a/packages/jest-runtime/src/script_transformer.js b/packages/jest-runtime/src/script_transformer.js index 0c97ea28f935..482cc2b0d1e3 100644 --- a/packages/jest-runtime/src/script_transformer.js +++ b/packages/jest-runtime/src/script_transformer.js @@ -33,7 +33,7 @@ export type Options = {| collectCoverage: boolean, collectCoverageFrom: Array, collectCoverageOnlyFrom: ?{[key: string]: boolean, __proto__: null}, - isNativeModule?: boolean, + isCoreModule?: boolean, isInternalModule?: boolean, mapCoverage: boolean, |}; @@ -276,7 +276,7 @@ export default class ScriptTransformer { fileSource?: string, ): TransformResult { const isInternalModule = !!(options && options.isInternalModule); - const isNativeModule = !!(options && options.isNativeModule); + const isCoreModule = !!(options && options.isCoreModule); const content = stripShebang( fileSource || fs.readFileSync(filename, 'utf8'), ); @@ -286,7 +286,7 @@ export default class ScriptTransformer { const willTransform = !isInternalModule && - !isNativeModule && + !isCoreModule && (shouldTransform(filename, this._config) || instrument); try { @@ -307,7 +307,7 @@ export default class ScriptTransformer { return { script: new vm.Script(wrappedCode, { displayErrors: true, - filename: isNativeModule ? 'jest-node-native-' + filename : filename, + filename: isCoreModule ? 'jest-nodejs-core-' + filename : filename, }), sourceMapPath, }; @@ -329,7 +329,7 @@ export default class ScriptTransformer { let instrument = false; let result = ''; - if (!options.isNativeModule) { + if (!options.isCoreModule) { instrument = shouldInstrument(filename, options, this._config); scriptCacheKey = getScriptCacheKey(filename, this._config, instrument); result = cache.get(scriptCacheKey); diff --git a/packages/jest-util/src/__tests__/create_process_object.test.js b/packages/jest-util/src/__tests__/create_process_object.test.js index 798260a01413..1417c5fed9d4 100644 --- a/packages/jest-util/src/__tests__/create_process_object.test.js +++ b/packages/jest-util/src/__tests__/create_process_object.test.js @@ -5,14 +5,14 @@ * LICENSE file in the root directory of this source tree. */ +import EventEmitter from 'events'; import createProcessObject from '../create_process_object'; it('creates a process object that looks like the original one', () => { const fakeProcess = createProcessObject(); - // "process" should expose EventEmitter methods through the prototype chain. - expect(typeof fakeProcess.on).toBe('function'); - expect(typeof fakeProcess.removeListener).toBe('function'); + // "process" inherits from EventEmitter through the prototype chain. + expect(fakeProcess instanceof EventEmitter).toBe(true); // They look the same, but they are NOT the same (deep copied object). The // "_events" property is checked to ensure event emitter properties are diff --git a/packages/jest-util/src/index.js b/packages/jest-util/src/index.js index 12c8a3a51590..859398dd5bc4 100644 --- a/packages/jest-util/src/index.js +++ b/packages/jest-util/src/index.js @@ -12,7 +12,6 @@ import mkdirp from 'mkdirp'; import BufferedConsole from './buffered_console'; import clearLine from './clear_line'; import Console from './Console'; -import deepCyclicCopy from './deep_cyclic_copy'; import FakeTimers from './fake_timers'; import formatTestResults from './format_test_results'; import getConsoleOutput from './get_console_output'; @@ -38,7 +37,6 @@ module.exports = { NullConsole, clearLine, createDirectory, - deepCyclicCopy, formatTestResults, getConsoleOutput, installCommonGlobals, diff --git a/packages/jest-util/src/install_common_globals.js b/packages/jest-util/src/install_common_globals.js index 93ab37445fca..feba4a9f9bf9 100644 --- a/packages/jest-util/src/install_common_globals.js +++ b/packages/jest-util/src/install_common_globals.js @@ -13,18 +13,15 @@ import type {Global} from 'types/Global'; import createProcesObject from './create_process_object'; import deepCyclicCopy from './deep_cyclic_copy'; -// Matches macros referenced in Node repository, under the "src" folder. -const MACROS = Object.keys(global).filter(key => { - return /^(?:DTRACE|LTTNG|COUNTER)_/.test(key); -}); +const DTRACE = Object.keys(global).filter(key => key.startsWith('DTRACE')); export default function(globalObject: Global, globals: ConfigGlobals) { globalObject.process = createProcesObject(); // Forward some APIs. - MACROS.forEach(macro => { - globalObject[macro] = function(...args) { - return global[macro].apply(this, args); + DTRACE.forEach(dtrace => { + globalObject[dtrace] = function(...args) { + return global[dtrace].apply(this, args); }; });