Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Added support for naming mocked functions #4586

Merged
merged 18 commits into from
Oct 8, 2017
Merged
Show file tree
Hide file tree
Changes from 6 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
17 changes: 14 additions & 3 deletions docs/en/JestObjectAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The `jest` object is automatically in scope within every test file. The methods
- [`jest.clearAllTimers()`](#jestclearalltimers)
- [`jest.disableAutomock()`](#jestdisableautomock)
- [`jest.enableAutomock()`](#jestenableautomock)
- [`jest.fn(implementation)`](#jestfnimplementation)
- [`jest.fn(implementation, name)`](#jestfnimplementation)
- [`jest.isMockFunction(fn)`](#jestismockfunctionfn)
- [`jest.genMockFromModule(moduleName)`](#jestgenmockfrommodulemodulename)
- [`jest.mock(moduleName, factory, options)`](#jestmockmodulename-factory-options)
Expand Down Expand Up @@ -65,8 +65,8 @@ Returns the `jest` object for chaining.

*Note: this method was previously called `autoMockOn`. When using `babel-jest`, calls to `enableAutomock` will automatically be hoisted to the top of the code block. Use `autoMockOn` if you want to explicitly avoid this behavior.*

### `jest.fn(implementation)`
Returns a new, unused [mock function](/jest/docs/mock-function-api.html). Optionally takes a mock implementation.
### `jest.fn(implementation, name)`
Returns a new, unused [mock function](/jest/docs/mock-function-api.html). Optionally takes a mock implementation and/or a mock name.

```js
const mockFn = jest.fn();
Expand All @@ -77,6 +77,17 @@ Returns a new, unused [mock function](/jest/docs/mock-function-api.html). Option
const returnsTrue = jest.fn(() => true);
console.log(returnsTrue()); // true;
```
With mock name:
```js
const mockFn = jest.fn('doesNothing');
mockFn();
expect(mockFn).toHaveBeenCalled();

// With a mock implementation:
const returnsTrue = jest.fn(() => true, 'returnsTrue');
console.log(returnsTrue()); // true;
```


### `jest.isMockFunction(fn)`
Determines if the given function is a mocked function.
Expand Down
29 changes: 24 additions & 5 deletions docs/en/MockFunctionAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,32 @@ console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
> 'first call', 'second call', 'default', 'default'
```

### `mockFn.mockReturnThis()`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like an accident on my part. I'll fix it.

Just a simple sugar function for:
### `mockFn.mockName(value)`
Accepts a string to use in test result output in place of "jest.fn()" to indicate which mock function is being referenced.

*Note: `jest.fn(implementation, name)` is a shorthand for `jest.fn().mockImplementation(implementation).mockName(name)`. Also, if you only provide a string to jest.fn(), it will be used as the mock name value.*

For example:

```js
jest.fn(function() {
return this;
});
const mockFn = jest.fn().mockName('mockedFunction');
// mockFn();
expect(mockFn).toHaveBeenCalled();
```

Will result in this error:
```
expect(mockedFunction).toHaveBeenCalled()

Expected mock function to have been called.
```

Shorthand examples:

```js
const mockFn = jest.fn('mockedFunction');

const mockFn2 = jest.fn(scalar => 42 + scalar, 'add42');
```

### `mockFn.mockReturnValue(value)`
Expand Down
21 changes: 21 additions & 0 deletions docs/en/MockFunctions.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,27 @@ const otherObj = {
};
```

## Mock Names
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it include a "availble in jest 21.4" or something?


You can optionally provide a name for your mock functions, which will be displayed instead of "jest.fn()" in test error output. Use this if you want to be able to quickly identify the mock function reporting an error in your test output.

```javascript
const myMockFn = jest.fn()
.mockReturnValue('default')
.mockImplementation(scalar => 42 + scalar)
.mockName('add42');

const myMockFn2 = jest.fn(scalar => 42 + scalar, 'add42');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is wrong now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damn. I thought I caught all the doc references. Can I still commit changes for this PR, or is that done since it's merged?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New PR is needed

```

You can also pass a mock name without providing a mock implementation:

```javascript
const myMockFn = jest.fn('myMockFunction');
// myMockFn();
expect(myMockFn).toHaveBeenCalled();
```

## Custom Matchers

Finally, in order to make it simpler to assert how mock functions have been
Expand Down
70 changes: 70 additions & 0 deletions integration_tests/__tests__/mock_names.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
Copy link
Member

@SimenB SimenB Oct 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test for failing expect(mockWithName).not.toHaveBeenCalled() and expect(mockWithName).toHaveBeenCalledTimes(5) to assert on the name for them as well? I see no reason for them not to work as you expect, but having the assertions would be nice

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, a test where the assertion expect(mockWithName).not.toHaveBeenCalled() will fail, and then check for that error?

And a test for expect(mockWithName).toHaveBeenCalledTimes(5) when it's not called 5 times?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've added more tests to cover those.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Thanks!

* 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');
const {extractSummary} = require('../utils');

test('suite without mock name, mock called', () => {
const {stderr, status} = runJest('mock-names/without-mock-name');

expect(status).toBe(0);
expect(stderr).toMatch(/PASS/);
});

test('suite without mock name, mock not called', () => {
const {stderr, status} = runJest('mock-names/without-mock-name-not-called');

expect(status).toBe(1);
expect(stderr).toMatch(/expect\(jest\.fn\(\)\)\.toHaveBeenCalled/);
});

test('suite with mock name, mock called', () => {
const {stderr, status} = runJest('mock-names/with-mock-name');

expect(status).toBe(0);
expect(stderr).toMatch(/PASS/);
});

test('suite with mock name, mock not called', () => {
const {stderr, status} = runJest('mock-names/with-mock-name-not-called');

expect(status).toBe(1);
expect(stderr).toMatch(/expect\(myMockedFunction\)\.toHaveBeenCalled/);
});

test('suite with mock name, long form, mock called', () => {
const {stderr, status} = runJest('mock-names/with-mock-name-long');

expect(status).toBe(0);
expect(stderr).toMatch(/PASS/);
});

test('suite with mock name, long form, mock not called', () => {
const {stderr, status} = runJest('mock-names/with-mock-name-long-not-called');

expect(status).toBe(1);
expect(stderr).toMatch(/expect\(myMockedFunctionLong\)\.toHaveBeenCalled/);
});

test('suite with mock name, short form, mock called', () => {
const {stderr, status} = runJest('mock-names/with-mock-name-short');

expect(status).toBe(0);
expect(stderr).toMatch(/PASS/);
});

test('suite with mock name, short form, mock not called', () => {
const {stderr, status} = runJest(
'mock-names/with-mock-name-short-not-called',
);

expect(status).toBe(1);
expect(stderr).toMatch(/expect\(myMockedFunctionShort\)\.toHaveBeenCalled/);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* 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';

jest.mock('../');
const importedFn = require('../');
// empty mock name should result in default 'jest.fn()' output
const mockFn = jest.fn(importedFn, '');

test('first test', () => {
// mockFn explicitly not called to test error snapshot
expect(mockFn).toHaveBeenCalled();
expect(mockFn.mock.calls.length).toBe(1);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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
*/

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

jest.mock('../');
const importedFn = require('../');
// empty mock name should result in default 'jest.fn()' output
const mockFn = jest.fn(importedFn, '');

test('first test', () => {
mockFn();
expect(mockFn).toHaveBeenCalled();
expect(mockFn.mock.calls.length).toBe(1);
Copy link
Member

@SimenB SimenB Oct 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any particular reason why you do this instead of expect(mockFn).toHaveBeenCalledTimes(1)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason. I just copied what was in another test suite in there that I based mine on.

});
10 changes: 10 additions & 0 deletions integration_tests/mock-names/with-empty-mock-name/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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
*/

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

jest.mock('../');
const importedFn = require('../');
const mockFn = jest.fn(importedFn).mockName('myMockedFunctionLong');

test('first test', () => {
// mockFn explicitly not called to test error snapshot
expect(mockFn).toHaveBeenCalled();
expect(mockFn.mock.calls.length).toBe(1);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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
*/

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

jest.mock('../');
const importedFn = require('../');
const mockFn = jest.fn(importedFn).mockName('myMockedFunctionLong');

test('first test', () => {
mockFn();
expect(mockFn).toHaveBeenCalled();
expect(mockFn.mock.calls.length).toBe(1);
});
10 changes: 10 additions & 0 deletions integration_tests/mock-names/with-mock-name-long/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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
*/

module.exports = () => {};
6 changes: 6 additions & 0 deletions integration_tests/mock-names/with-mock-name-long/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"jest": {
"testEnvironment": "node",
"clearMocks": true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* 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';

jest.mock('../');
const importedFn = require('../');
const mockFn = jest.fn(importedFn, 'myMockedFunction');

test('first test', () => {
// mockFn explicitly not called to test error snapshot
expect(mockFn).toHaveBeenCalled();
expect(mockFn.mock.calls.length).toBe(1);
});
10 changes: 10 additions & 0 deletions integration_tests/mock-names/with-mock-name-not-called/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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
*/

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

jest.mock('../');
const mockFn = jest.fn('myMockedFunctionShort');

test('first test', () => {
// mockFn explicitly not called to test error snapshot
expect(mockFn).toHaveBeenCalled();
expect(mockFn.mock.calls.length).toBe(1);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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
*/

module.exports = () => {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"jest": {
"testEnvironment": "node",
"clearMocks": true
}
}
Loading