Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add restoreMocks config to fix #3580 #5327

Merged
merged 4 commits into from
Jan 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

* `[jest-cli]` Fix `EISDIR` when a directory is passed as an argument to `jest`.
([#5317](https://github.com/facebook/jest/pull/5317))
* `[jest-config]` Added restoreMocks config option.
([#5327](https://github.com/facebook/jest/pull/5327))

## jest 22.1.0

Expand Down
9 changes: 9 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,15 @@ argument:
The function should either return a path to the module that should be resolved
or throw an error if the module can't be found.

### `restoreMocks` [boolean]

Default: `false`

Automatically restore mock state between every test. Equivalent to calling
`jest.restoreAllMocks()` between each test. This will lead to any mocks having
their fake implementations removed and restores their initial
implementation.

### `rootDir` [string]

Default: The root of the directory containing your jest's [config file](#) _or_
Expand Down
3 changes: 3 additions & 0 deletions docs/MockFunctionAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ Beware that `mockFn.mockRestore` only works when mock was created with
`jest.spyOn`. Thus you have to take care of restoration yourself when manually
assigning `jest.fn()`.

The [`restoreMocks`](configuration.html#restoremocks-boolean) configuration
option is available to restore mocks automatically between tests.

### `mockFn.mockImplementation(fn)`

Accepts a function that should be used as the implementation of the mock. The
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
\\"name\\": \\"[md5 hash]\\",
\\"resetMocks\\": false,
\\"resetModules\\": false,
\\"restoreMocks\\": false,
\\"rootDir\\": \\"<<REPLACED_ROOT_DIR>>\\",
\\"roots\\": [
\\"<<REPLACED_ROOT_DIR>>\\"
Expand Down
21 changes: 21 additions & 0 deletions integration-tests/__tests__/auto_restore_mocks.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* 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');

test('suite with auto-restore', () => {
const result = runJest('auto-restore-mocks/with-auto-restore');
expect(result.status).toBe(0);
});

test('suite without auto-restore', () => {
const result = runJest('auto-restore-mocks/without-auto-restore');
expect(result.status).toBe(0);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* 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.
*/

'use strict';

const TestClass = require('../');
const localClass = new TestClass();

test('first test', () => {
jest.spyOn(localClass, 'test').mockImplementation(() => 'ABCD');
expect(localClass.test()).toEqual('ABCD');
expect(localClass.test).toHaveBeenCalledTimes(1);
});

test('second test', () => {
expect(localClass.test()).toEqual('12345');
expect(localClass.test.mock).toBe(undefined);
});
12 changes: 12 additions & 0 deletions integration-tests/auto-restore-mocks/with-auto-restore/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* 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.
*/

module.exports = class Test {
test() {
return '12345';
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"jest": {
"testEnvironment": "node",
"restoreMocks": true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* 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.
*/

'use strict';

const TestClass = require('../');
const localClass = new TestClass();

describe('without an explicit restore', () => {
jest.spyOn(localClass, 'test').mockImplementation(() => 'ABCD');

test('first test', () => {
expect(localClass.test()).toEqual('ABCD');
expect(localClass.test).toHaveBeenCalledTimes(1);
});

test('second test', () => {
expect(localClass.test()).toEqual('ABCD');
expect(localClass.test).toHaveBeenCalledTimes(2);
});
});

describe('with an explicit restore', () => {
beforeEach(() => {
jest.restoreAllMocks();
});

test('first test', () => {
jest.spyOn(localClass, 'test').mockImplementation(() => 'ABCD');
expect(localClass.test()).toEqual('ABCD');
expect(localClass.test).toHaveBeenCalledTimes(1);
});

test('second test', () => {
expect(localClass.test()).toEqual('12345');
expect(localClass.test.mock).toBe(undefined);
});
});
12 changes: 12 additions & 0 deletions integration-tests/auto-restore-mocks/without-auto-restore/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* 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.
*/

module.exports = class Test {
test() {
return '12345';
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"jest": {
"testEnvironment": "node"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ const jestAdapter = async (
runtime.resetAllMocks();
}

if (config.restoreMocks) {
runtime.restoreAllMocks();
}

if (config.timers === 'fake') {
environment.fakeTimers.useFakeTimers();
}
Expand Down
7 changes: 7 additions & 0 deletions packages/jest-cli/src/cli/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,13 @@ export const options = {
description: 'A JSON string which allows the use of a custom resolver.',
type: 'string',
},
restoreMocks: {
default: undefined,
description:
'Automatically restore mock state and implementation between every test. ' +
'Equivalent to calling jest.restoreAllMocks() between each test.',
type: 'boolean',
},
rootDir: {
description:
'The root directory that Jest should scan for tests and ' +
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default ({
preset: null,
resetMocks: false,
resetModules: false,
restoreMocks: false,
runTestsByPath: false,
runner: 'jest-runner',
snapshotSerializers: [],
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ const getConfigs = (
resetMocks: options.resetMocks,
resetModules: options.resetModules,
resolver: options.resolver,
restoreMocks: options.restoreMocks,
rootDir: options.rootDir,
roots: options.roots,
runner: options.runner,
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ export default function normalize(options: InitialOptions, argv: Argv) {
case 'reporters':
case 'resetMocks':
case 'resetModules':
case 'restoreMocks':
case 'rootDir':
case 'runTestsByPath':
case 'silent':
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/valid_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export default ({
resetMocks: false,
resetModules: false,
resolver: '<rootDir>/resolver.js',
restoreMocks: false,
rootDir: '/',
roots: ['<rootDir>'],
runTestsByPath: false,
Expand Down
4 changes: 4 additions & 0 deletions packages/jest-jasmine2/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ async function jasmine2(
environment.fakeTimers.useFakeTimers();
}
}

if (config.restoreMocks) {
runtime.restoreAllMocks();
}
});

env.addReporter(reporter);
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-validate/src/__tests__/fixtures/jest_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const defaultConfig = {
preset: null,
resetMocks: false,
resetModules: false,
restoreMocks: false,
roots: ['<rootDir>'],
snapshotSerializers: [],
testEnvironment: 'jest-environment-jsdom',
Expand Down Expand Up @@ -98,6 +99,7 @@ const validConfig = {
preset: 'react-native',
resetMocks: false,
resetModules: false,
restoreMocks: false,
rootDir: '/',
roots: ['<rootDir>'],
setupFiles: ['<rootDir>/setup.js'],
Expand Down
1 change: 1 addition & 0 deletions test_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const DEFAULT_PROJECT_CONFIG: ProjectConfig = {
resetMocks: false,
resetModules: false,
resolver: null,
restoreMocks: false,
rootDir: '/test_root_dir/',
roots: [],
runner: 'jest-runner',
Expand Down
1 change: 1 addition & 0 deletions types/Argv.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export type Argv = {|
resetMocks: boolean,
resetModules: boolean,
resolver: ?string,
restoreMocks: boolean,
rootDir: string,
roots: Array<string>,
setupFiles: Array<string>,
Expand Down
3 changes: 3 additions & 0 deletions types/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type DefaultOptions = {|
preset: ?string,
resetMocks: boolean,
resetModules: boolean,
restoreMocks: boolean,
runner: string,
runTestsByPath: boolean,
snapshotSerializers: Array<Path>,
Expand Down Expand Up @@ -117,6 +118,7 @@ export type InitialOptions = {
resetMocks?: boolean,
resetModules?: boolean,
resolver?: ?Path,
restoreMocks?: boolean,
rootDir: Path,
roots?: Array<Path>,
runner?: string,
Expand Down Expand Up @@ -227,6 +229,7 @@ export type ProjectConfig = {|
resetMocks: boolean,
resetModules: boolean,
resolver: ?Path,
restoreMocks: boolean,
rootDir: Path,
roots: Array<Path>,
runner: string,
Expand Down