diff --git a/docs/en/MockFunctionAPI.md b/docs/en/MockFunctionAPI.md index b6052928ac3d..29c151831311 100644 --- a/docs/en/MockFunctionAPI.md +++ b/docs/en/MockFunctionAPI.md @@ -18,6 +18,9 @@ Mock functions are also known as "spies", because they let you spy on the behavi ## Reference +### `mockFn.getMockName()` +Returns the mock name string set by calling `mockFn.mockName(value)`. + ### `mockFn.mock.calls` An array that represents all calls that have been made into this mock function. Each call is represented by an array of arguments that were passed during the call. @@ -55,7 +58,7 @@ Beware that `mockClear` will replace `mockFn.mock`, not just [`mockFn.mock.calls The [`clearMocks`](configuration.html#clearmocks-boolean) configuration option is available to clear mocks automatically between tests. ### `mockFn.mockReset()` -Resets all information stored in the mock, including any inital implementation given. +Resets all information stored in the mock, including any initial implementation and mock name given. This is useful when you want to completely restore a mock back to its initial state. @@ -138,6 +141,25 @@ console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn()); > 'first call', 'second call', 'default', 'default' ``` +### `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. + +For example: + +```js +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. +``` + + ### `mockFn.mockReturnThis()` Just a simple sugar function for: diff --git a/docs/en/MockFunctions.md b/docs/en/MockFunctions.md index f0a0c8149477..39db52b77afe 100644 --- a/docs/en/MockFunctions.md +++ b/docs/en/MockFunctions.md @@ -217,6 +217,19 @@ const otherObj = { }; ``` +## Mock Names + +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'); +``` + ## Custom Matchers Finally, in order to make it simpler to assert how mock functions have been diff --git a/integration_tests/__tests__/mock_names.test.js b/integration_tests/__tests__/mock_names.test.js new file mode 100644 index 000000000000..0ba6cf786110 --- /dev/null +++ b/integration_tests/__tests__/mock_names.test.js @@ -0,0 +1,67 @@ +/** + * 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 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, expect mock not called', () => { + const {stderr, status} = runJest('mock-names/with-mock-name-not-called-pass'); + + expect(status).toBe(0); + expect(stderr).toMatch(/PASS/); +}); + +test('suite with mock name, mock called, expect fail', () => { + const {stderr, status} = runJest('mock-names/with-mock-name-not-called-fail'); + + expect(status).toBe(1); + expect(stderr).toMatch(/expect\(myMockedFunction\)\.not\.toHaveBeenCalled/); +}); + +test('suite with mock name, mock called 5 times', () => { + const {stderr, status} = runJest('mock-names/with-mock-name-call-times-pass'); + + expect(status).toBe(0); + expect(stderr).toMatch(/PASS/); +}); + +test('suite with mock name, mock not called 5 times, expect fail', () => { + const {stderr, status} = runJest('mock-names/with-mock-name-call-times-fail'); + + expect(status).toBe(1); + expect(stderr).toMatch(/expect\(myMockedFunction\)\.toHaveBeenCalledTimes/); +}); + +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/); +}); diff --git a/integration_tests/mock-names/with-empty-mock-name-not-called/__tests__/index.js b/integration_tests/mock-names/with-empty-mock-name-not-called/__tests__/index.js new file mode 100644 index 000000000000..5cd94b1c2440 --- /dev/null +++ b/integration_tests/mock-names/with-empty-mock-name-not-called/__tests__/index.js @@ -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('../'); +// empty mock name should result in default 'jest.fn()' output +const mockFn = jest.fn(importedFn).mockName(''); + +test('first test', () => { + // mockFn explicitly not called to test error output + expect(mockFn).toHaveBeenCalledTimes(1); +}); diff --git a/integration_tests/mock-names/with-empty-mock-name-not-called/index.js b/integration_tests/mock-names/with-empty-mock-name-not-called/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/with-empty-mock-name-not-called/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/with-empty-mock-name-not-called/package.json b/integration_tests/mock-names/with-empty-mock-name-not-called/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/with-empty-mock-name-not-called/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/integration_tests/mock-names/with-empty-mock-name/__tests__/index.js b/integration_tests/mock-names/with-empty-mock-name/__tests__/index.js new file mode 100644 index 000000000000..5f49fc4afef6 --- /dev/null +++ b/integration_tests/mock-names/with-empty-mock-name/__tests__/index.js @@ -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('../'); +// empty mock name should result in default 'jest.fn()' output +const mockFn = jest.fn(importedFn).mockName(''); + +test('first test', () => { + mockFn(); + expect(mockFn).toHaveBeenCalledTimes(1); +}); diff --git a/integration_tests/mock-names/with-empty-mock-name/index.js b/integration_tests/mock-names/with-empty-mock-name/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/with-empty-mock-name/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/with-empty-mock-name/package.json b/integration_tests/mock-names/with-empty-mock-name/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/with-empty-mock-name/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/integration_tests/mock-names/with-mock-name-call-times-fail/__tests__/index.js b/integration_tests/mock-names/with-mock-name-call-times-fail/__tests__/index.js new file mode 100644 index 000000000000..6b0ca540f6d6 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-call-times-fail/__tests__/index.js @@ -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('myMockedFunction'); + +test('first test', () => { + mockFn(); + mockFn(); + expect(mockFn).toHaveBeenCalledTimes(5); +}); diff --git a/integration_tests/mock-names/with-mock-name-call-times-fail/index.js b/integration_tests/mock-names/with-mock-name-call-times-fail/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-call-times-fail/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/with-mock-name-call-times-fail/package.json b/integration_tests/mock-names/with-mock-name-call-times-fail/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-call-times-fail/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/integration_tests/mock-names/with-mock-name-call-times-pass/__tests__/index.js b/integration_tests/mock-names/with-mock-name-call-times-pass/__tests__/index.js new file mode 100644 index 000000000000..1d4df77fdddc --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-call-times-pass/__tests__/index.js @@ -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. + */ + +'use strict'; + +jest.mock('../'); +const importedFn = require('../'); +const mockFn = jest.fn(importedFn).mockName('myMockedFunction'); + +test('first test', () => { + mockFn(); + mockFn(); + mockFn(); + mockFn(); + mockFn(); + expect(mockFn).toHaveBeenCalledTimes(5); +}); diff --git a/integration_tests/mock-names/with-mock-name-call-times-pass/index.js b/integration_tests/mock-names/with-mock-name-call-times-pass/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-call-times-pass/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/with-mock-name-call-times-pass/package.json b/integration_tests/mock-names/with-mock-name-call-times-pass/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-call-times-pass/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/integration_tests/mock-names/with-mock-name-not-called-fail/__tests__/index.js b/integration_tests/mock-names/with-mock-name-not-called-fail/__tests__/index.js new file mode 100644 index 000000000000..01aada892249 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-not-called-fail/__tests__/index.js @@ -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 importedFn = require('../'); +const mockFn = jest.fn(importedFn).mockName('myMockedFunction'); + +test('first test', () => { + mockFn(); + expect(mockFn).not.toHaveBeenCalled(); +}); diff --git a/integration_tests/mock-names/with-mock-name-not-called-fail/index.js b/integration_tests/mock-names/with-mock-name-not-called-fail/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-not-called-fail/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/with-mock-name-not-called-fail/package.json b/integration_tests/mock-names/with-mock-name-not-called-fail/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-not-called-fail/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/integration_tests/mock-names/with-mock-name-not-called-pass/__tests__/index.js b/integration_tests/mock-names/with-mock-name-not-called-pass/__tests__/index.js new file mode 100644 index 000000000000..abfe2fcfe604 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-not-called-pass/__tests__/index.js @@ -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 importedFn = require('../'); +const mockFn = jest.fn(importedFn).mockName('myMockedFunction'); + +test('first test', () => { + // mockFn explicitly not called to test error output + expect(mockFn).not.toHaveBeenCalled(); +}); diff --git a/integration_tests/mock-names/with-mock-name-not-called-pass/index.js b/integration_tests/mock-names/with-mock-name-not-called-pass/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-not-called-pass/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/with-mock-name-not-called-pass/package.json b/integration_tests/mock-names/with-mock-name-not-called-pass/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-not-called-pass/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/integration_tests/mock-names/with-mock-name-not-called/__tests__/index.js b/integration_tests/mock-names/with-mock-name-not-called/__tests__/index.js new file mode 100644 index 000000000000..57ed74faed86 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-not-called/__tests__/index.js @@ -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 importedFn = require('../'); +const mockFn = jest.fn(importedFn).mockName('myMockedFunction'); + +test('first test', () => { + // mockFn explicitly not called to test error output + expect(mockFn).toHaveBeenCalledTimes(1); +}); diff --git a/integration_tests/mock-names/with-mock-name-not-called/index.js b/integration_tests/mock-names/with-mock-name-not-called/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-not-called/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/with-mock-name-not-called/package.json b/integration_tests/mock-names/with-mock-name-not-called/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name-not-called/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/integration_tests/mock-names/with-mock-name/__tests__/index.js b/integration_tests/mock-names/with-mock-name/__tests__/index.js new file mode 100644 index 000000000000..b4970abf018e --- /dev/null +++ b/integration_tests/mock-names/with-mock-name/__tests__/index.js @@ -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 importedFn = require('../'); +const mockFn = jest.fn(importedFn).mockName('myMockedFunction'); + +test('first test', () => { + mockFn(); + expect(mockFn).toHaveBeenCalledTimes(1); +}); diff --git a/integration_tests/mock-names/with-mock-name/index.js b/integration_tests/mock-names/with-mock-name/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/with-mock-name/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/with-mock-name/package.json b/integration_tests/mock-names/with-mock-name/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/with-mock-name/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/integration_tests/mock-names/without-mock-name-not-called/__tests__/index.js b/integration_tests/mock-names/without-mock-name-not-called/__tests__/index.js new file mode 100644 index 000000000000..f85711e32fd9 --- /dev/null +++ b/integration_tests/mock-names/without-mock-name-not-called/__tests__/index.js @@ -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 importedFn = require('../'); +const mockFn = jest.fn(importedFn); + +test('first test', () => { + // mockFn explicitly not called to test error output + expect(mockFn).toHaveBeenCalledTimes(1); +}); diff --git a/integration_tests/mock-names/without-mock-name-not-called/index.js b/integration_tests/mock-names/without-mock-name-not-called/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/without-mock-name-not-called/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/without-mock-name-not-called/package.json b/integration_tests/mock-names/without-mock-name-not-called/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/without-mock-name-not-called/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/integration_tests/mock-names/without-mock-name/__tests__/index.js b/integration_tests/mock-names/without-mock-name/__tests__/index.js new file mode 100644 index 000000000000..5ffe16523bd1 --- /dev/null +++ b/integration_tests/mock-names/without-mock-name/__tests__/index.js @@ -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 importedFn = require('../'); +const mockFn = jest.fn(importedFn); + +test('first test', () => { + mockFn(); + expect(mockFn).toHaveBeenCalledTimes(1); +}); diff --git a/integration_tests/mock-names/without-mock-name/index.js b/integration_tests/mock-names/without-mock-name/index.js new file mode 100644 index 000000000000..5233c06878bf --- /dev/null +++ b/integration_tests/mock-names/without-mock-name/index.js @@ -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 = () => {}; diff --git a/integration_tests/mock-names/without-mock-name/package.json b/integration_tests/mock-names/without-mock-name/package.json new file mode 100644 index 000000000000..b54d0a3264e7 --- /dev/null +++ b/integration_tests/mock-names/without-mock-name/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "clearMocks": true + } +} diff --git a/packages/expect/src/spy_matchers.js b/packages/expect/src/spy_matchers.js index 17a681925906..8310e0baad7d 100644 --- a/packages/expect/src/spy_matchers.js +++ b/packages/expect/src/spy_matchers.js @@ -25,17 +25,13 @@ import { import {equals} from './jasmine_utils'; import {iterableEquality, partition} from './utils'; -const RECEIVED_NAME = { - 'mock function': 'jest.fn()', - spy: 'spy', -}; - const createToBeCalledMatcher = matcherName => (received, expected) => { ensureNoExpected(expected, matcherName); ensureMock(received, matcherName); const receivedIsSpy = isSpy(received); const type = receivedIsSpy ? 'spy' : 'mock function'; + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const count = receivedIsSpy ? received.calls.count() : received.mock.calls.length; @@ -45,12 +41,12 @@ const createToBeCalledMatcher = matcherName => (received, expected) => { const pass = count > 0; const message = pass ? () => - matcherHint('.not' + matcherName, RECEIVED_NAME[type], '') + + matcherHint('.not' + matcherName, receivedName, '') + '\n\n' + `Expected ${type} not to be called ` + formatReceivedCalls(calls, CALL_PRINT_LIMIT, {sameSentence: true}) : () => - matcherHint(matcherName, RECEIVED_NAME[type], '') + + matcherHint(matcherName, receivedName, '') + '\n\n' + `Expected ${type} to have been called.`; @@ -65,6 +61,7 @@ const createToBeCalledWithMatcher = matcherName => ( const receivedIsSpy = isSpy(received); const type = receivedIsSpy ? 'spy' : 'mock function'; + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const calls = receivedIsSpy ? received.calls.all().map(x => x.args) : received.mock.calls; @@ -76,12 +73,12 @@ const createToBeCalledWithMatcher = matcherName => ( const message = pass ? () => - matcherHint('.not' + matcherName, RECEIVED_NAME[type]) + + matcherHint('.not' + matcherName, receivedName) + '\n\n' + `Expected ${type} not to have been called with:\n` + ` ${printExpected(expected)}` : () => - matcherHint(matcherName, RECEIVED_NAME[type]) + + matcherHint(matcherName, receivedName) + '\n\n' + `Expected ${type} to have been called with:\n` + formatMismatchedCalls(fail, expected, CALL_PRINT_LIMIT); @@ -97,6 +94,7 @@ const createLastCalledWithMatcher = matcherName => ( const receivedIsSpy = isSpy(received); const type = receivedIsSpy ? 'spy' : 'mock function'; + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const calls = receivedIsSpy ? received.calls.all().map(x => x.args) : received.mock.calls; @@ -104,12 +102,12 @@ const createLastCalledWithMatcher = matcherName => ( const message = pass ? () => - matcherHint('.not' + matcherName, RECEIVED_NAME[type]) + + matcherHint('.not' + matcherName, receivedName) + '\n\n' + `Expected ${type} to not have been last called with:\n` + ` ${printExpected(expected)}` : () => - matcherHint(matcherName, RECEIVED_NAME[type]) + + matcherHint(matcherName, receivedName) + '\n\n' + `Expected ${type} to have been last called with:\n` + formatMismatchedCalls(calls, expected, LAST_CALL_PRINT_LIMIT); @@ -129,23 +127,20 @@ const spyMatchers: MatchersObject = { const receivedIsSpy = isSpy(received); const type = receivedIsSpy ? 'spy' : 'mock function'; + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const count = receivedIsSpy ? received.calls.count() : received.mock.calls.length; const pass = count === expected; const message = pass ? () => - matcherHint( - '.not' + matcherName, - RECEIVED_NAME[type], - String(expected), - ) + + matcherHint('.not' + matcherName, receivedName, String(expected)) + `\n\n` + `Expected ${type} not to be called ` + `${EXPECTED_COLOR(pluralize('time', expected))}, but it was` + ` called exactly ${RECEIVED_COLOR(pluralize('time', count))}.` : () => - matcherHint(matcherName, RECEIVED_NAME[type], String(expected)) + + matcherHint(matcherName, receivedName, String(expected)) + '\n\n' + `Expected ${type} to have been called ` + `${EXPECTED_COLOR(pluralize('time', expected))},` + diff --git a/packages/jest-mock/src/__tests__/jest_mock.test.js b/packages/jest-mock/src/__tests__/jest_mock.test.js index ee734a026768..b012442bf368 100644 --- a/packages/jest-mock/src/__tests__/jest_mock.test.js +++ b/packages/jest-mock/src/__tests__/jest_mock.test.js @@ -458,6 +458,42 @@ describe('moduleMocker', () => { expect(moduleMocker.isMockFunction(mockFn)).toBe(true); }); + test('default mockName is jest.fn()', () => { + const fn = jest.fn(); + expect(fn.getMockName()).toBe('jest.fn()'); + }); + + test('mockName sets the mock name', () => { + const fn = jest.fn(); + fn.mockName('myMockFn'); + expect(fn.getMockName()).toBe('myMockFn'); + }); + + test('mockName gets reset by mockReset', () => { + const fn = jest.fn(); + expect(fn.getMockName()).toBe('jest.fn()'); + fn.mockName('myMockFn'); + expect(fn.getMockName()).toBe('myMockFn'); + fn.mockReset(); + expect(fn.getMockName()).toBe('jest.fn()'); + }); + + test('mockName is not reset by mockRestore', () => { + const fn = jest.fn(() => false); + fn.mockName('myMockFn'); + expect(fn.getMockName()).toBe('myMockFn'); + fn.mockRestore(); + expect(fn.getMockName()).toBe('myMockFn'); + }); + + test('mockName is not reset by mockClear', () => { + const fn = jest.fn(() => false); + fn.mockName('myMockFn'); + expect(fn.getMockName()).toBe('myMockFn'); + fn.mockClear(); + expect(fn.getMockName()).toBe('myMockFn'); + }); + describe('spyOn', () => { it('should work', () => { let isOriginalCalled = false; diff --git a/packages/jest-mock/src/index.js b/packages/jest-mock/src/index.js index 9f14f99f2bb5..2be1e576bba2 100644 --- a/packages/jest-mock/src/index.js +++ b/packages/jest-mock/src/index.js @@ -30,6 +30,7 @@ type MockFunctionConfig = { isReturnValueLastSet: boolean, defaultReturnValue: any, mockImpl: any, + mockName: string, specificReturnValues: Array, specificMockImpls: Array, }; @@ -269,6 +270,7 @@ class ModuleMockerClass { defaultReturnValue: undefined, isReturnValueLastSet: false, mockImpl: undefined, + mockName: 'jest.fn()', specificMockImpls: [], specificReturnValues: [], }; @@ -433,6 +435,19 @@ class ModuleMockerClass { return this; }); + f.mockName = name => { + if (name) { + const mockConfig = this._ensureMockConfig(f); + mockConfig.mockName = name; + } + return f; + }; + + f.getMockName = () => { + const mockConfig = this._ensureMockConfig(f); + return mockConfig.mockName || 'jest.fn()'; + }; + if (metadata.mockImpl) { f.mockImplementation(metadata.mockImpl); }