From 93a11a134a609d6c492860222e56f203bcfddb7c Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Thu, 12 Jul 2018 17:28:47 -0700 Subject: [PATCH 01/10] First iteration of withResetModules --- .../runtime_require_module_or_mock.test.js | 94 +++++++++++++++++++ .../__tests__/test_root/ModuleWithState.js | 16 ++++ .../src/__tests__/test_root/root.js | 1 + packages/jest-runtime/src/index.js | 32 ++++++- types/Jest.js | 1 + 5 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 packages/jest-runtime/src/__tests__/test_root/ModuleWithState.js diff --git a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js index 267236621968..3f90e4ae7976 100644 --- a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js +++ b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js @@ -175,3 +175,97 @@ it('unmocks modules in config.unmockedModulePathPatterns for tests with automock const moduleData = nodeModule(); expect(moduleData.isUnmocked()).toBe(true); })); + +describe('resetModules', () => { + it('resets all the modules', () => + createRuntime(__filename, { + moduleNameMapper, + }).then(runtime => { + let exports = runtime.requireModuleOrMock( + runtime.__mockRootPath, + 'ModuleWithState', + ); + expect(exports.getState()).toBe(1); + exports.increment(); + expect(exports.getState()).toBe(2); + runtime.resetModules(); + exports = runtime.requireModuleOrMock( + runtime.__mockRootPath, + 'ModuleWithState', + ); + expect(exports.getState()).toBe(1); + })); +}); + +describe('withResetModules', () => { + it('resets all modules after the block', async () => + createRuntime(__filename, { + moduleNameMapper, + }).then(async runtime => { + let exports; + await runtime.withResetModules(() => { + exports = runtime.requireModuleOrMock( + runtime.__mockRootPath, + 'ModuleWithState', + ); + expect(exports.getState()).toBe(1); + exports.increment(); + expect(exports.getState()).toBe(2); + }); + + exports = runtime.requireModuleOrMock( + runtime.__mockRootPath, + 'ModuleWithState', + ); + expect(exports.getState()).toBe(1); + })); + + it('can call resetModules within a withResetModules block', async () => + createRuntime(__filename, { + moduleNameMapper, + }).then(async runtime => { + let exports; + await runtime.withResetModules(() => { + exports = runtime.requireModuleOrMock( + runtime.__mockRootPath, + 'ModuleWithState', + ); + expect(exports.getState()).toBe(1); + + exports.increment(); + runtime.resetModules(); + + exports = runtime.requireModuleOrMock( + runtime.__mockRootPath, + 'ModuleWithState', + ); + expect(exports.getState()).toBe(1); + }); + + exports = runtime.requireModuleOrMock( + runtime.__mockRootPath, + 'ModuleWithState', + ); + expect(exports.getState()).toBe(1); + })); + + describe('can use withResetModules from a beforeEach block', () => { + let exports; + beforeEach(() => { + jest.withResetModules(() => { + exports = require('./test_root/ModuleWithState'); + }); + }); + + it('can use the required module from beforeEach and re-require it', () => { + expect(exports.getState()).toBe(1); + exports.increment(); + expect(exports.getState()).toBe(2); + + exports = require('./test_root/ModuleWithState'); + expect(exports.getState()).toBe(1); + exports.increment(); + expect(exports.getState()).toBe(2); + }); + }); +}); diff --git a/packages/jest-runtime/src/__tests__/test_root/ModuleWithState.js b/packages/jest-runtime/src/__tests__/test_root/ModuleWithState.js new file mode 100644 index 000000000000..2fef497ab498 --- /dev/null +++ b/packages/jest-runtime/src/__tests__/test_root/ModuleWithState.js @@ -0,0 +1,16 @@ +/** + * 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. + * + * @providesModule ModuleWithState + */ + +let state = 1; + +export const increment = () => { + state += 1; +}; + +export const getState = () => state; diff --git a/packages/jest-runtime/src/__tests__/test_root/root.js b/packages/jest-runtime/src/__tests__/test_root/root.js index 8c2e2309a034..f47121fb47f6 100644 --- a/packages/jest-runtime/src/__tests__/test_root/root.js +++ b/packages/jest-runtime/src/__tests__/test_root/root.js @@ -12,6 +12,7 @@ require('ExclusivelyManualMock'); require('ManuallyMocked'); require('ModuleWithSideEffects'); +require('ModuleWithState'); require('RegularModule'); // We only care about the static analysis, not about the runtime. diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index d6612eb42221..044f09604f90 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -97,6 +97,7 @@ class Runtime { _mockMetaDataCache: {[key: string]: MockFunctionMetadata, __proto__: null}; _mockRegistry: {[key: string]: any, __proto__: null}; _moduleMocker: ModuleMocker; + _sandboxRegistries: Array; _moduleRegistry: ModuleRegistry; _needsCoverageMapped: Set; _resolver: Resolver; @@ -131,6 +132,7 @@ class Runtime { this._mockFactories = Object.create(null); this._mockRegistry = Object.create(null); this._moduleMocker = this._environment.moduleMocker; + this._sandboxRegistries = []; this._moduleRegistry = Object.create(null); this._needsCoverageMapped = new Set(); this._resolver = resolver; @@ -281,11 +283,6 @@ class Runtime { ); let modulePath; - 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); @@ -309,6 +306,19 @@ class Runtime { modulePath = this._resolveModule(from, moduleName); } + let moduleRegistry; + + if (!options || !options.isInternalModule) { + moduleRegistry = + this._sandboxRegistries.find( + registry => modulePath && registry[modulePath], + ) || + this._sandboxRegistries[0] || + this._moduleRegistry; + } else { + moduleRegistry = this._internalModuleRegistry; + } + if (!moduleRegistry[modulePath]) { // We must register the pre-allocated module object first so that any // circular dependencies that may arise while evaluating the module can @@ -418,7 +428,14 @@ class Runtime { } } + async withResetModules(fn: () => Promise<*> | void) { + this._sandboxRegistries.unshift(Object.create(null)); + await fn(); + this._sandboxRegistries.shift(); + } + resetModules() { + this._sandboxRegistries = []; this._mockRegistry = Object.create(null); this._moduleRegistry = Object.create(null); @@ -875,6 +892,10 @@ class Runtime { this.resetModules(); return jestObject; }; + const withResetModules = async (fn: () => Promise<*>) => { + await this.withResetModules(fn); + return jestObject; + }; const fn = this._moduleMocker.fn.bind(this._moduleMocker); const spyOn = this._moduleMocker.spyOn.bind(this._moduleMocker); @@ -932,6 +953,7 @@ class Runtime { unmock, useFakeTimers, useRealTimers, + withResetModules, }; return jestObject; } diff --git a/types/Jest.js b/types/Jest.js index 88966e299f2c..8972c8753977 100644 --- a/types/Jest.js +++ b/types/Jest.js @@ -49,4 +49,5 @@ export type Jest = {| unmock(moduleName: string): Jest, useFakeTimers(): Jest, useRealTimers(): Jest, + withResetModules(fn: () => Promise<*>): Promise, |}; From 1f86b12fefb07d118a70b9cc62c6c9511fd4841f Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Tue, 17 Jul 2018 11:43:31 -0700 Subject: [PATCH 02/10] Make withResetModules "not async" --- .../src/__tests__/runtime_require_module_or_mock.test.js | 8 ++++---- packages/jest-runtime/src/index.js | 8 ++++---- types/Jest.js | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js index 3f90e4ae7976..1dea08c53f29 100644 --- a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js +++ b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js @@ -201,9 +201,9 @@ describe('withResetModules', () => { it('resets all modules after the block', async () => createRuntime(__filename, { moduleNameMapper, - }).then(async runtime => { + }).then(runtime => { let exports; - await runtime.withResetModules(() => { + runtime.withResetModules(() => { exports = runtime.requireModuleOrMock( runtime.__mockRootPath, 'ModuleWithState', @@ -223,9 +223,9 @@ describe('withResetModules', () => { it('can call resetModules within a withResetModules block', async () => createRuntime(__filename, { moduleNameMapper, - }).then(async runtime => { + }).then(runtime => { let exports; - await runtime.withResetModules(() => { + runtime.withResetModules(() => { exports = runtime.requireModuleOrMock( runtime.__mockRootPath, 'ModuleWithState', diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 044f09604f90..70a917e68916 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -428,9 +428,9 @@ class Runtime { } } - async withResetModules(fn: () => Promise<*> | void) { + withResetModules(fn: () => void) { this._sandboxRegistries.unshift(Object.create(null)); - await fn(); + fn(); this._sandboxRegistries.shift(); } @@ -892,8 +892,8 @@ class Runtime { this.resetModules(); return jestObject; }; - const withResetModules = async (fn: () => Promise<*>) => { - await this.withResetModules(fn); + const withResetModules = (fn: () => void) => { + this.withResetModules(fn); return jestObject; }; const fn = this._moduleMocker.fn.bind(this._moduleMocker); diff --git a/types/Jest.js b/types/Jest.js index 8972c8753977..95c63650a2f6 100644 --- a/types/Jest.js +++ b/types/Jest.js @@ -49,5 +49,5 @@ export type Jest = {| unmock(moduleName: string): Jest, useFakeTimers(): Jest, useRealTimers(): Jest, - withResetModules(fn: () => Promise<*>): Promise, + withResetModules(fn: () => void): Jest, |}; From 65e426ea5dcb886315c48dbb7f867d598ad471e1 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Wed, 18 Jul 2018 08:30:58 -0700 Subject: [PATCH 03/10] Reimplement withResetModules without the stack --- .../runtime_require_module_or_mock.test.js | 13 +++++ packages/jest-runtime/src/index.js | 48 +++++++++++-------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js index 1dea08c53f29..d3692a6970c6 100644 --- a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js +++ b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js @@ -220,6 +220,19 @@ describe('withResetModules', () => { expect(exports.getState()).toBe(1); })); + it('cannot nest withResetModules blocks', async () => + createRuntime(__filename, { + moduleNameMapper, + }).then(runtime => { + expect(() => { + runtime.withResetModules(() => { + runtime.withResetModules(() => {}); + }); + }).toThrowError( + 'withResetModules cannot be nested inside another withResetModules.', + ); + })); + it('can call resetModules within a withResetModules block', async () => createRuntime(__filename, { moduleNameMapper, diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 70a917e68916..f3d253a8c3d0 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -96,8 +96,9 @@ class Runtime { _mockFactories: {[key: string]: () => any, __proto__: null}; _mockMetaDataCache: {[key: string]: MockFunctionMetadata, __proto__: null}; _mockRegistry: {[key: string]: any, __proto__: null}; + _sandboxMockRegistry: ?{[key: string]: any, __proto__: null}; _moduleMocker: ModuleMocker; - _sandboxRegistries: Array; + _sandboxModuleRegistry: ?ModuleRegistry; _moduleRegistry: ModuleRegistry; _needsCoverageMapped: Set; _resolver: Resolver; @@ -132,7 +133,7 @@ class Runtime { this._mockFactories = Object.create(null); this._mockRegistry = Object.create(null); this._moduleMocker = this._environment.moduleMocker; - this._sandboxRegistries = []; + this._sandboxModuleRegistry = null; this._moduleRegistry = Object.create(null); this._needsCoverageMapped = new Set(); this._resolver = resolver; @@ -309,12 +310,11 @@ class Runtime { let moduleRegistry; if (!options || !options.isInternalModule) { - moduleRegistry = - this._sandboxRegistries.find( - registry => modulePath && registry[modulePath], - ) || - this._sandboxRegistries[0] || - this._moduleRegistry; + if (this._moduleRegistry[modulePath] || !this._sandboxModuleRegistry) { + moduleRegistry = this._moduleRegistry; + } else { + moduleRegistry = this._sandboxModuleRegistry; + } } else { moduleRegistry = this._internalModuleRegistry; } @@ -360,12 +360,16 @@ class Runtime { moduleName, ); - if (this._mockRegistry[moduleID]) { + if (this._sandboxMockRegistry && this._sandboxMockRegistry[moduleID]) { + return this._sandboxMockRegistry[moduleID]; + } else if (this._mockRegistry[moduleID]) { return this._mockRegistry[moduleID]; } + const mockRegistry = this._sandboxMockRegistry || this._mockRegistry; + if (moduleID in this._mockFactories) { - return (this._mockRegistry[moduleID] = this._mockFactories[moduleID]()); + return (mockRegistry[moduleID] = this._mockFactories[moduleID]()); } let manualMock = this._resolver.getMockModule(from, moduleName); @@ -409,15 +413,15 @@ class Runtime { // Only include the fromPath if a moduleName is given. Else treat as root. const fromPath = moduleName ? from : null; - this._execModule(localModule, undefined, this._mockRegistry, fromPath); - this._mockRegistry[moduleID] = localModule.exports; + this._execModule(localModule, undefined, mockRegistry, fromPath); + 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); + mockRegistry[moduleID] = this._generateMock(from, moduleName); } - return this._mockRegistry[moduleID]; + return mockRegistry[moduleID]; } requireModuleOrMock(from: Path, moduleName: string) { @@ -429,16 +433,23 @@ class Runtime { } withResetModules(fn: () => void) { - this._sandboxRegistries.unshift(Object.create(null)); + if (this._sandboxModuleRegistry || this._sandboxMockRegistry) { + throw new Error( + 'withResetModules cannot be nested inside another withResetModules.', + ); + } + this._sandboxModuleRegistry = Object.create(null); + this._sandboxMockRegistry = Object.create(null); fn(); - this._sandboxRegistries.shift(); + this._sandboxModuleRegistry = null; + this._sandboxMockRegistry = null; } resetModules() { - this._sandboxRegistries = []; + this._sandboxModuleRegistry = null; + this._sandboxMockRegistry = null; this._mockRegistry = Object.create(null); this._moduleRegistry = Object.create(null); - if (this._environment && this._environment.global) { const envGlobal = this._environment.global; Object.keys(envGlobal).forEach(key => { @@ -450,7 +461,6 @@ class Runtime { globalMock._isMockFunction && globalMock.mockClear(); } }); - if (envGlobal.mockClearTimers) { envGlobal.mockClearTimers(); } From 927773dbc8fc091c5938d802b02975f2bec69402 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Thu, 4 Oct 2018 23:05:23 -0700 Subject: [PATCH 04/10] Rename withResetModules to isolateModules --- .../runtime_require_module_or_mock.test.js | 20 +++++++++---------- packages/jest-runtime/src/index.js | 10 +++++----- types/Jest.js | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js index d3692a6970c6..2eb01b1b0bad 100644 --- a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js +++ b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js @@ -197,13 +197,13 @@ describe('resetModules', () => { })); }); -describe('withResetModules', () => { +describe('isolateModules', () => { it('resets all modules after the block', async () => createRuntime(__filename, { moduleNameMapper, }).then(runtime => { let exports; - runtime.withResetModules(() => { + runtime.isolateModules(() => { exports = runtime.requireModuleOrMock( runtime.__mockRootPath, 'ModuleWithState', @@ -220,25 +220,25 @@ describe('withResetModules', () => { expect(exports.getState()).toBe(1); })); - it('cannot nest withResetModules blocks', async () => + it('cannot nest isolateModules blocks', async () => createRuntime(__filename, { moduleNameMapper, }).then(runtime => { expect(() => { - runtime.withResetModules(() => { - runtime.withResetModules(() => {}); + runtime.isolateModules(() => { + runtime.isolateModules(() => {}); }); }).toThrowError( - 'withResetModules cannot be nested inside another withResetModules.', + 'isolateModules cannot be nested inside another isolateModules.', ); })); - it('can call resetModules within a withResetModules block', async () => + it('can call resetModules within a isolateModules block', async () => createRuntime(__filename, { moduleNameMapper, }).then(runtime => { let exports; - runtime.withResetModules(() => { + runtime.isolateModules(() => { exports = runtime.requireModuleOrMock( runtime.__mockRootPath, 'ModuleWithState', @@ -262,10 +262,10 @@ describe('withResetModules', () => { expect(exports.getState()).toBe(1); })); - describe('can use withResetModules from a beforeEach block', () => { + describe('can use isolateModules from a beforeEach block', () => { let exports; beforeEach(() => { - jest.withResetModules(() => { + jest.isolateModules(() => { exports = require('./test_root/ModuleWithState'); }); }); diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index f4564d9ca9a3..37df7cce4bdb 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -433,10 +433,10 @@ class Runtime { } } - withResetModules(fn: () => void) { + isolateModules(fn: () => void) { if (this._sandboxModuleRegistry || this._sandboxMockRegistry) { throw new Error( - 'withResetModules cannot be nested inside another withResetModules.', + 'isolateModules cannot be nested inside another isolateModules.', ); } this._sandboxModuleRegistry = Object.create(null); @@ -903,8 +903,8 @@ class Runtime { this.resetModules(); return jestObject; }; - const withResetModules = (fn: () => void) => { - this.withResetModules(fn); + const isolateModules = (fn: () => void) => { + this.isolateModules(fn); return jestObject; }; const fn = this._moduleMocker.fn.bind(this._moduleMocker); @@ -964,7 +964,7 @@ class Runtime { unmock, useFakeTimers, useRealTimers, - withResetModules, + isolateModules, }; return jestObject; } diff --git a/types/Jest.js b/types/Jest.js index 95c63650a2f6..8e90e57dcc07 100644 --- a/types/Jest.js +++ b/types/Jest.js @@ -49,5 +49,5 @@ export type Jest = {| unmock(moduleName: string): Jest, useFakeTimers(): Jest, useRealTimers(): Jest, - withResetModules(fn: () => void): Jest, + isolateModules(fn: () => void): Jest, |}; From fffd74f0239cb3d2cff357e58a9fc530e686b190 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Thu, 4 Oct 2018 23:06:38 -0700 Subject: [PATCH 05/10] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddc5f5af354c..ae15e7442c54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[jest-runtime]` Add `jest.isolateModules` for scoped module initialization ([#6701](https://github.com/facebook/jest/pull/6701)) - `[jest-jasmine2/jest-circus/jest-cli]` Add test.todo ([#6996](https://github.com/facebook/jest/pull/6996)) - `[pretty-format]` Option to not escape strings in diff messages ([#5661](https://github.com/facebook/jest/pull/5661)) - `[jest-haste-map]` Add `getFileIterator` to `HasteFS` for faster file iteration ([#7010](https://github.com/facebook/jest/pull/7010)). From 8c6910d1beee92ad59b563869ab994ba7c3aab4c Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Sun, 7 Oct 2018 22:10:33 -0700 Subject: [PATCH 06/10] Fix eslint --- packages/jest-runtime/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 37df7cce4bdb..50dc0a6d92bd 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -942,6 +942,7 @@ class Runtime { genMockFromModule: (moduleName: string) => this._generateMock(from, moduleName), isMockFunction: this._moduleMocker.isMockFunction, + isolateModules, mock, requireActual: localRequire.requireActual, requireMock: localRequire.requireMock, @@ -964,7 +965,6 @@ class Runtime { unmock, useFakeTimers, useRealTimers, - isolateModules, }; return jestObject; } From 9e4c58cc86e846c5285287f2a83234ed554e547e Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Fri, 12 Oct 2018 08:21:13 -0700 Subject: [PATCH 07/10] Add docs for isolateModules --- docs/Configuration.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/Configuration.md b/docs/Configuration.md index 5e68d10c74a0..08845c47059f 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -551,6 +551,21 @@ Default: `false` By default, each test file gets its own independent module registry. Enabling `resetModules` goes a step further and resets the module registry before running each individual test. This is useful to isolate modules for every test so that local module state doesn't conflict between tests. This can be done programmatically using [`jest.resetModules()`](#jest-resetmodules). +### `isolateModules` [boolean] + +Default: `false` + +`isolateModules` goes a step further than `resetModules` and creates a sanbox registry for the modules that are loaded inside the callback function. This is useful to isolate modules for every test so that local module state doesn't conflict between tests. This can be done programmatically using [`jest.isolateModules()`](#jest-isolatemodules). + +```js +let myModule; +jest.isolateModules(() => { + myModule = require('myModule'); +}); + +let otherCopyOfMyModule = require('myModule'); +``` + ### `resolver` [string] Default: `undefined` From 59fb053c8993aadcdcb20e67e653df9bb4449a1b Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Fri, 12 Oct 2018 12:51:09 -0700 Subject: [PATCH 08/10] Fix typo, remove provideModules and extra async stuff --- docs/Configuration.md | 2 +- .../src/__tests__/runtime_require_module_or_mock.test.js | 6 +++--- .../jest-runtime/src/__tests__/test_root/ModuleWithState.js | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 963b51a36e0f..8be79de92e52 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -555,7 +555,7 @@ By default, each test file gets its own independent module registry. Enabling `r Default: `false` -`isolateModules` goes a step further than `resetModules` and creates a sanbox registry for the modules that are loaded inside the callback function. This is useful to isolate modules for every test so that local module state doesn't conflict between tests. This can be done programmatically using [`jest.isolateModules()`](#jest-isolatemodules). +`isolateModules` goes a step further than `resetModules` and creates a sandbox registry for the modules that are loaded inside the callback function. This is useful to isolate modules for every test so that local module state doesn't conflict between tests. This can be done programmatically using [`jest.isolateModules()`](#jest-isolatemodules). ```js let myModule; diff --git a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js index 2eb01b1b0bad..f2d0127d6100 100644 --- a/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js +++ b/packages/jest-runtime/src/__tests__/runtime_require_module_or_mock.test.js @@ -198,7 +198,7 @@ describe('resetModules', () => { }); describe('isolateModules', () => { - it('resets all modules after the block', async () => + it('resets all modules after the block', () => createRuntime(__filename, { moduleNameMapper, }).then(runtime => { @@ -220,7 +220,7 @@ describe('isolateModules', () => { expect(exports.getState()).toBe(1); })); - it('cannot nest isolateModules blocks', async () => + it('cannot nest isolateModules blocks', () => createRuntime(__filename, { moduleNameMapper, }).then(runtime => { @@ -233,7 +233,7 @@ describe('isolateModules', () => { ); })); - it('can call resetModules within a isolateModules block', async () => + it('can call resetModules within a isolateModules block', () => createRuntime(__filename, { moduleNameMapper, }).then(runtime => { diff --git a/packages/jest-runtime/src/__tests__/test_root/ModuleWithState.js b/packages/jest-runtime/src/__tests__/test_root/ModuleWithState.js index 2fef497ab498..85359a4f70c5 100644 --- a/packages/jest-runtime/src/__tests__/test_root/ModuleWithState.js +++ b/packages/jest-runtime/src/__tests__/test_root/ModuleWithState.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ModuleWithState */ let state = 1; From 6eab501a7b13460a5faff8e29f2604f80ee11e20 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 13 Oct 2018 00:56:25 +0200 Subject: [PATCH 09/10] Update Configuration.md --- docs/Configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 8be79de92e52..f846b7992967 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -563,7 +563,7 @@ jest.isolateModules(() => { myModule = require('myModule'); }); -let otherCopyOfMyModule = require('myModule'); +const otherCopyOfMyModule = require('myModule'); ``` ### `resolver` [string] From 380e9c686575abe6ff880dce95213f8c05c73c75 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Sun, 28 Oct 2018 09:46:50 -0700 Subject: [PATCH 10/10] Rename implementation to isolated* and change docs to JestObjectAPI --- docs/Configuration.md | 15 --------------- docs/JestObjectAPI.md | 13 +++++++++++++ packages/jest-runtime/src/index.js | 30 +++++++++++++++--------------- 3 files changed, 28 insertions(+), 30 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index dd7b21dd6a39..edd6a0f1cf54 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -551,21 +551,6 @@ Default: `false` By default, each test file gets its own independent module registry. Enabling `resetModules` goes a step further and resets the module registry before running each individual test. This is useful to isolate modules for every test so that local module state doesn't conflict between tests. This can be done programmatically using [`jest.resetModules()`](#jest-resetmodules). -### `isolateModules` [boolean] - -Default: `false` - -`isolateModules` goes a step further than `resetModules` and creates a sandbox registry for the modules that are loaded inside the callback function. This is useful to isolate modules for every test so that local module state doesn't conflict between tests. This can be done programmatically using [`jest.isolateModules()`](#jest-isolatemodules). - -```js -let myModule; -jest.isolateModules(() => { - myModule = require('myModule'); -}); - -const otherCopyOfMyModule = require('myModule'); -``` - ### `resolver` [string] Default: `undefined` diff --git a/docs/JestObjectAPI.md b/docs/JestObjectAPI.md index 58c86823eb64..beeb8831060e 100644 --- a/docs/JestObjectAPI.md +++ b/docs/JestObjectAPI.md @@ -265,6 +265,19 @@ test('works too', () => { Returns the `jest` object for chaining. +### `jest.isolateModules(fn)` + +`jest.isolateModules(fn)` goes a step further than `jest.resetModules()` and creates a sandbox registry for the modules that are loaded inside the callback function. This is useful to isolate specific modules for every test so that local module state doesn't conflict between tests. + +```js +let myModule; +jest.isolateModules(() => { + myModule = require('myModule'); +}); + +const otherCopyOfMyModule = require('myModule'); +``` + ## Mock functions ### `jest.fn(implementation)` diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 80f343bbad83..8e93379b5375 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -97,9 +97,9 @@ class Runtime { _mockFactories: {[key: string]: () => any, __proto__: null}; _mockMetaDataCache: {[key: string]: MockFunctionMetadata, __proto__: null}; _mockRegistry: {[key: string]: any, __proto__: null}; - _sandboxMockRegistry: ?{[key: string]: any, __proto__: null}; + _isolatedMockRegistry: ?{[key: string]: any, __proto__: null}; _moduleMocker: ModuleMocker; - _sandboxModuleRegistry: ?ModuleRegistry; + _isolatedModuleRegistry: ?ModuleRegistry; _moduleRegistry: ModuleRegistry; _needsCoverageMapped: Set; _resolver: Resolver; @@ -134,7 +134,7 @@ class Runtime { this._mockFactories = Object.create(null); this._mockRegistry = Object.create(null); this._moduleMocker = this._environment.moduleMocker; - this._sandboxModuleRegistry = null; + this._isolatedModuleRegistry = null; this._moduleRegistry = Object.create(null); this._needsCoverageMapped = new Set(); this._resolver = resolver; @@ -318,10 +318,10 @@ class Runtime { let moduleRegistry; if (!options || !options.isInternalModule) { - if (this._moduleRegistry[modulePath] || !this._sandboxModuleRegistry) { + if (this._moduleRegistry[modulePath] || !this._isolatedModuleRegistry) { moduleRegistry = this._moduleRegistry; } else { - moduleRegistry = this._sandboxModuleRegistry; + moduleRegistry = this._isolatedModuleRegistry; } } else { moduleRegistry = this._internalModuleRegistry; @@ -368,13 +368,13 @@ class Runtime { moduleName, ); - if (this._sandboxMockRegistry && this._sandboxMockRegistry[moduleID]) { - return this._sandboxMockRegistry[moduleID]; + if (this._isolatedMockRegistry && this._isolatedMockRegistry[moduleID]) { + return this._isolatedMockRegistry[moduleID]; } else if (this._mockRegistry[moduleID]) { return this._mockRegistry[moduleID]; } - const mockRegistry = this._sandboxMockRegistry || this._mockRegistry; + const mockRegistry = this._isolatedMockRegistry || this._mockRegistry; if (moduleID in this._mockFactories) { return (mockRegistry[moduleID] = this._mockFactories[moduleID]()); @@ -456,21 +456,21 @@ class Runtime { } isolateModules(fn: () => void) { - if (this._sandboxModuleRegistry || this._sandboxMockRegistry) { + if (this._isolatedModuleRegistry || this._isolatedMockRegistry) { throw new Error( 'isolateModules cannot be nested inside another isolateModules.', ); } - this._sandboxModuleRegistry = Object.create(null); - this._sandboxMockRegistry = Object.create(null); + this._isolatedModuleRegistry = Object.create(null); + this._isolatedMockRegistry = Object.create(null); fn(); - this._sandboxModuleRegistry = null; - this._sandboxMockRegistry = null; + this._isolatedModuleRegistry = null; + this._isolatedMockRegistry = null; } resetModules() { - this._sandboxModuleRegistry = null; - this._sandboxMockRegistry = null; + this._isolatedModuleRegistry = null; + this._isolatedMockRegistry = null; this._mockRegistry = Object.create(null); this._moduleRegistry = Object.create(null);