From ae06df4876aed66ca87b8f8fbd1a199f3913ceda Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 11 Oct 2017 21:42:55 +0200 Subject: [PATCH 1/4] Add a serializer for jest.fn to jest-snapshot --- CHANGELOG.md | 1 + docs/MockFunctions.md | 9 ++++ packages/jest-snapshot/package.json | 1 + .../mock_serializer.test.js.snap | 42 +++++++++++++++++++ .../src/__tests__/mock_serializer.test.js | 36 ++++++++++++++++ packages/jest-snapshot/src/mock_serializer.js | 33 +++++++++++++++ packages/jest-snapshot/src/plugins.js | 9 +++- 7 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap create mode 100644 packages/jest-snapshot/src/__tests__/mock_serializer.test.js create mode 100644 packages/jest-snapshot/src/mock_serializer.js diff --git a/CHANGELOG.md b/CHANGELOG.md index ebbb28d19c4f..59d771b42e12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ * `[jest-runtime]` Add `module.loaded`, and make `module.require` not enumerable ([#4623](https://github.com/facebook/jest/pull/4623)) * `[jest-runtime]` Add `module.parent` ([#4614](https://github.com/facebook/jest/pull/4614)) * `[jest-runtime]` Support sourcemaps in transformers ([#3458](https://github.com/facebook/jest/pull/3458)) +* `[jest-snapshot]` Add a serializer for `jest.fn` to allow a snapshot of a jest mock (TBD) * `[jest-worker]` Initial version of parallel worker abstraction, say hello! ([#4497](https://github.com/facebook/jest/pull/4497)) ### Chore & Maintenance diff --git a/docs/MockFunctions.md b/docs/MockFunctions.md index 2548273d8951..01a0a75f997e 100644 --- a/docs/MockFunctions.md +++ b/docs/MockFunctions.md @@ -238,6 +238,9 @@ expect(mockFunc).toBeCalledWith(arg1, arg2); // The last call to the mock function was called with the specified args expect(mockFunc).lastCalledWith(arg1, arg2); + +// All calls, instantiations and the name of the mock is written as a snapshot +expect(mockFunc).toMatchSnapshot(); ``` These matchers are really just sugar for common forms of inspecting the `.mock` @@ -259,6 +262,12 @@ expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1]).toEqual( // The first arg of the last call to the mock function was `42` // (note that there is no sugar helper for this specific of an assertion) expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1][0]).toBe(42); + +// A snapshot will check that a mock was invoked the same number of times, +// in the same order, with the same arguments. It will also assert on the name. +expect(mockFunc.mock.calls).toEqual([[arg1, arg2]]); +expect(mockFunc.mock.instances).toEqual([{name: 'some name'}]); +expect(mockFunc.mock.getMockName()).toBe('a mock name'); ``` For a complete list of matchers, check out the [reference docs](/jest/docs/en/expect.html). diff --git a/packages/jest-snapshot/package.json b/packages/jest-snapshot/package.json index 48580bb8b6ed..f4d4a771125f 100644 --- a/packages/jest-snapshot/package.json +++ b/packages/jest-snapshot/package.json @@ -11,6 +11,7 @@ "chalk": "^2.0.1", "jest-diff": "^21.2.1", "jest-matcher-utils": "^21.2.1", + "jest-mock": "^21.2.0", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "pretty-format": "^21.2.1" diff --git a/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap b/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap new file mode 100644 index 000000000000..d2a97ff751b2 --- /dev/null +++ b/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap @@ -0,0 +1,42 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`empty with no calls mock 1`] = ` +Object { + "calls": Array [], + "name": "jest.fn()", +} +`; + +exports[`instantiated mock 1`] = ` +Object { + "calls": Array [ + Array [ + Object { + "name": "some fine name", + }, + ], + ], + "name": "jest.fn()", +} +`; + +exports[`mock with calls 1`] = ` +Object { + "calls": Array [ + Array [], + Array [ + Object { + "foo": "bar", + }, + ], + ], + "name": "jest.fn()", +} +`; + +exports[`mock with name 1`] = ` +Object { + "calls": Array [], + "name": "name of mock is nice", +} +`; diff --git a/packages/jest-snapshot/src/__tests__/mock_serializer.test.js b/packages/jest-snapshot/src/__tests__/mock_serializer.test.js new file mode 100644 index 000000000000..0b3ba31628f4 --- /dev/null +++ b/packages/jest-snapshot/src/__tests__/mock_serializer.test.js @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2016-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 mock = jest.fn(); + +afterEach(() => mock.mockReset()); + +test('empty with no calls mock', () => { + expect(mock).toMatchSnapshot(); +}); + +test('instantiated mock', () => { + // eslint-disable-next-line no-new + new mock({name: 'some fine name'}); + + expect(mock).toMatchSnapshot(); +}); + +test('mock with calls', () => { + mock(); + mock({foo: 'bar'}); + + expect(mock).toMatchSnapshot(); +}); + +test('mock with name', () => { + const mockWithName = jest.fn().mockName('name of mock is nice'); + + expect(mockWithName).toMatchSnapshot(); +}); diff --git a/packages/jest-snapshot/src/mock_serializer.js b/packages/jest-snapshot/src/mock_serializer.js new file mode 100644 index 000000000000..d1a1c68d84de --- /dev/null +++ b/packages/jest-snapshot/src/mock_serializer.js @@ -0,0 +1,33 @@ +/** + * 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 + */ + +import type {Config, NewPlugin, Printer, Refs} from 'types/PrettyFormat'; + +import jestMock from 'jest-mock'; + +export const serialize = ( + val: any, + config: Config, + indentation: string, + depth: number, + refs: Refs, + printer: Printer, +): string => { + const mockObject = { + calls: val.mock.calls, + instances: val.mock.instances, + name: val.getMockName(), + }; + + return printer(mockObject, config, indentation, depth, refs); +}; + +export const test = jestMock.isMockFunction; + +export default ({serialize, test}: NewPlugin); diff --git a/packages/jest-snapshot/src/plugins.js b/packages/jest-snapshot/src/plugins.js index 1ed064749ad0..72798154bb56 100644 --- a/packages/jest-snapshot/src/plugins.js +++ b/packages/jest-snapshot/src/plugins.js @@ -10,6 +10,7 @@ import type {Plugin} from 'types/PrettyFormat'; import prettyFormat from 'pretty-format'; +import jestMockSerializer from './mock_serializer'; const { DOMElement, @@ -18,7 +19,13 @@ const { ReactTestComponent, } = prettyFormat.plugins; -let PLUGINS = [ReactTestComponent, ReactElement, DOMElement, Immutable]; +let PLUGINS = [ + ReactTestComponent, + ReactElement, + DOMElement, + Immutable, + jestMockSerializer, +]; // Prepend to list so the last added is the first tested. export const addSerializer = (plugin: Plugin) => { From d4b42974bbfd8d9323dce8f2efd4e1b0eb8048eb Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 11 Oct 2017 21:47:22 +0200 Subject: [PATCH 2/4] Add link to PR in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59d771b42e12..61244390d64b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ * `[jest-runtime]` Add `module.loaded`, and make `module.require` not enumerable ([#4623](https://github.com/facebook/jest/pull/4623)) * `[jest-runtime]` Add `module.parent` ([#4614](https://github.com/facebook/jest/pull/4614)) * `[jest-runtime]` Support sourcemaps in transformers ([#3458](https://github.com/facebook/jest/pull/3458)) -* `[jest-snapshot]` Add a serializer for `jest.fn` to allow a snapshot of a jest mock (TBD) +* `[jest-snapshot]` Add a serializer for `jest.fn` to allow a snapshot of a jest mock ([#4668](https://github.com/facebook/jest/pull/4668)) * `[jest-worker]` Initial version of parallel worker abstraction, say hello! ([#4497](https://github.com/facebook/jest/pull/4497)) ### Chore & Maintenance From 2c447fb977913f1680237a6ceb29ea5ed32c155b Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 11 Oct 2017 22:07:47 +0200 Subject: [PATCH 3/4] Don't depend on jest-mock --- packages/jest-snapshot/package.json | 1 - .../__snapshots__/mock_serializer.test.js.snap | 10 ++++++++++ .../src/__tests__/mock_serializer.test.js | 2 +- packages/jest-snapshot/src/__tests__/plugins.test.js | 2 +- packages/jest-snapshot/src/mock_serializer.js | 4 +--- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/jest-snapshot/package.json b/packages/jest-snapshot/package.json index f4d4a771125f..48580bb8b6ed 100644 --- a/packages/jest-snapshot/package.json +++ b/packages/jest-snapshot/package.json @@ -11,7 +11,6 @@ "chalk": "^2.0.1", "jest-diff": "^21.2.1", "jest-matcher-utils": "^21.2.1", - "jest-mock": "^21.2.0", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "pretty-format": "^21.2.1" diff --git a/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap b/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap index d2a97ff751b2..9b78752a01f0 100644 --- a/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap +++ b/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap @@ -3,6 +3,7 @@ exports[`empty with no calls mock 1`] = ` Object { "calls": Array [], + "instances": Array [], "name": "jest.fn()", } `; @@ -16,6 +17,9 @@ Object { }, ], ], + "instances": Array [ + mockConstructor {}, + ], "name": "jest.fn()", } `; @@ -28,8 +32,13 @@ Object { Object { "foo": "bar", }, + 42, ], ], + "instances": Array [ + undefined, + undefined, + ], "name": "jest.fn()", } `; @@ -37,6 +46,7 @@ Object { exports[`mock with name 1`] = ` Object { "calls": Array [], + "instances": Array [], "name": "name of mock is nice", } `; diff --git a/packages/jest-snapshot/src/__tests__/mock_serializer.test.js b/packages/jest-snapshot/src/__tests__/mock_serializer.test.js index 0b3ba31628f4..74bf87e79f80 100644 --- a/packages/jest-snapshot/src/__tests__/mock_serializer.test.js +++ b/packages/jest-snapshot/src/__tests__/mock_serializer.test.js @@ -24,7 +24,7 @@ test('instantiated mock', () => { test('mock with calls', () => { mock(); - mock({foo: 'bar'}); + mock({foo: 'bar'}, 42); expect(mock).toMatchSnapshot(); }); diff --git a/packages/jest-snapshot/src/__tests__/plugins.test.js b/packages/jest-snapshot/src/__tests__/plugins.test.js index 7c0cb5db48fe..d316a32fcd44 100644 --- a/packages/jest-snapshot/src/__tests__/plugins.test.js +++ b/packages/jest-snapshot/src/__tests__/plugins.test.js @@ -31,7 +31,7 @@ const testPath = names => { it('gets plugins', () => { const {getSerializers} = require('../plugins'); const plugins = getSerializers(); - expect(plugins.length).toBe(4); + expect(plugins).toHaveLength(5); }); it('adds plugins from an empty array', () => testPath([])); diff --git a/packages/jest-snapshot/src/mock_serializer.js b/packages/jest-snapshot/src/mock_serializer.js index d1a1c68d84de..7a3f363856e9 100644 --- a/packages/jest-snapshot/src/mock_serializer.js +++ b/packages/jest-snapshot/src/mock_serializer.js @@ -9,8 +9,6 @@ import type {Config, NewPlugin, Printer, Refs} from 'types/PrettyFormat'; -import jestMock from 'jest-mock'; - export const serialize = ( val: any, config: Config, @@ -28,6 +26,6 @@ export const serialize = ( return printer(mockObject, config, indentation, depth, refs); }; -export const test = jestMock.isMockFunction; +export const test = (val: any) => val && !!val._isMockFunction; export default ({serialize, test}: NewPlugin); From 3514516a29300afdebcd0a834a3239d2cd675423 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 11 Oct 2017 22:13:46 +0200 Subject: [PATCH 4/4] Remove instances from the snapshots They don't seem as useful as I though --- docs/MockFunctions.md | 3 +-- .../__tests__/__snapshots__/mock_serializer.test.js.snap | 9 --------- packages/jest-snapshot/src/mock_serializer.js | 1 - 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/docs/MockFunctions.md b/docs/MockFunctions.md index 01a0a75f997e..c4f712dfe903 100644 --- a/docs/MockFunctions.md +++ b/docs/MockFunctions.md @@ -239,7 +239,7 @@ expect(mockFunc).toBeCalledWith(arg1, arg2); // The last call to the mock function was called with the specified args expect(mockFunc).lastCalledWith(arg1, arg2); -// All calls, instantiations and the name of the mock is written as a snapshot +// All calls and the name of the mock is written as a snapshot expect(mockFunc).toMatchSnapshot(); ``` @@ -266,7 +266,6 @@ expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1][0]).toBe(42); // A snapshot will check that a mock was invoked the same number of times, // in the same order, with the same arguments. It will also assert on the name. expect(mockFunc.mock.calls).toEqual([[arg1, arg2]]); -expect(mockFunc.mock.instances).toEqual([{name: 'some name'}]); expect(mockFunc.mock.getMockName()).toBe('a mock name'); ``` diff --git a/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap b/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap index 9b78752a01f0..fa1ad70b96ea 100644 --- a/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap +++ b/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap @@ -3,7 +3,6 @@ exports[`empty with no calls mock 1`] = ` Object { "calls": Array [], - "instances": Array [], "name": "jest.fn()", } `; @@ -17,9 +16,6 @@ Object { }, ], ], - "instances": Array [ - mockConstructor {}, - ], "name": "jest.fn()", } `; @@ -35,10 +31,6 @@ Object { 42, ], ], - "instances": Array [ - undefined, - undefined, - ], "name": "jest.fn()", } `; @@ -46,7 +38,6 @@ Object { exports[`mock with name 1`] = ` Object { "calls": Array [], - "instances": Array [], "name": "name of mock is nice", } `; diff --git a/packages/jest-snapshot/src/mock_serializer.js b/packages/jest-snapshot/src/mock_serializer.js index 7a3f363856e9..4b440d30e98a 100644 --- a/packages/jest-snapshot/src/mock_serializer.js +++ b/packages/jest-snapshot/src/mock_serializer.js @@ -19,7 +19,6 @@ export const serialize = ( ): string => { const mockObject = { calls: val.mock.calls, - instances: val.mock.instances, name: val.getMockName(), };