From afb4bf5817781c333acb389e123f15d8ae6c6de2 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 11 Oct 2017 22:39:09 +0200 Subject: [PATCH] Add a serializer for jest.fn to jest-snapshot (#4668) * Add a serializer for jest.fn to jest-snapshot * Add link to PR in changelog * Don't depend on jest-mock * Remove instances from the snapshots They don't seem as useful as I though --- CHANGELOG.md | 1 + docs/MockFunctions.md | 8 ++++ .../mock_serializer.test.js.snap | 43 +++++++++++++++++++ .../src/__tests__/mock_serializer.test.js | 36 ++++++++++++++++ .../src/__tests__/plugins.test.js | 2 +- packages/jest-snapshot/src/mock_serializer.js | 30 +++++++++++++ packages/jest-snapshot/src/plugins.js | 9 +++- 7 files changed, 127 insertions(+), 2 deletions(-) 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..61244390d64b 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 ([#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 diff --git a/docs/MockFunctions.md b/docs/MockFunctions.md index 2548273d8951..c4f712dfe903 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 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,11 @@ 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.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/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..fa1ad70b96ea --- /dev/null +++ b/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap @@ -0,0 +1,43 @@ +// 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", + }, + 42, + ], + ], + "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..74bf87e79f80 --- /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'}, 42); + + 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/__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 new file mode 100644 index 000000000000..4b440d30e98a --- /dev/null +++ b/packages/jest-snapshot/src/mock_serializer.js @@ -0,0 +1,30 @@ +/** + * 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'; + +export const serialize = ( + val: any, + config: Config, + indentation: string, + depth: number, + refs: Refs, + printer: Printer, +): string => { + const mockObject = { + calls: val.mock.calls, + name: val.getMockName(), + }; + + return printer(mockObject, config, indentation, depth, refs); +}; + +export const test = (val: any) => val && !!val._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) => {