UNPKG

8.06 kBMarkdownView Raw
1# jest-mock-extended
2> Type safe mocking extensions for Jest 🃏
3
4[![Build Status](https://travis-ci.com/marchaos/jest-mock-extended.svg?branch=master)](https://travis-ci.com/marchaos/jest-mock-extended)
5[![Coverage Status](https://coveralls.io/repos/github/marchaos/jest-mock-extended/badge.svg?branch=master)](https://coveralls.io/github/marchaos/jest-mock-extended?branch=master)
6[![npm version](https://badge.fury.io/js/jest-mock-extended.svg)](https://badge.fury.io/js/jest-mock-extended)
7[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8[![npm downloads](https://badgen.net/npm/dw/jest-mock-extended)](https://badge.fury.io/js/jest-mock-extended)
9
10## Features
11- Provides complete Typescript type safety for interfaces, argument types and return types
12- Ability to mock any interface or object
13- calledWith() extension to provide argument specific expectations, which works for objects and functions.
14- Extensive Matcher API compatible with Jasmine matchers
15- Supports mocking deep objects / class instances.
16- Familiar Jest like API
17
18## Installation
19```bash
20npm install jest-mock-extended --save-dev
21```
22or
23```bash
24yarn add jest-mock-extended --dev
25```
26
27## Example
28
29```ts
30import { mock } from 'jest-mock-extended';
31
32interface PartyProvider {
33 getPartyType: () => string;
34 getSongs: (type: string) => string[]
35 start: (type: string) => void;
36}
37
38describe('Party Tests', () => {
39 test('Mock out an interface', () => {
40 const mock = mock<PartyProvider>();
41 mock.start('disco party');
42
43 expect(mock.start).toHaveBeenCalledWith('disco party');
44 });
45
46
47 test('mock out a return type', () => {
48 const mock = mock<PartyProvider>();
49 mock.getPartyType.mockReturnValue('west coast party');
50
51 expect(mock.getPartyType()).toBe('west coast party');
52 });
53
54 test('throwing an error if we forget to specify the return value')
55 const mock = mock<PartyProvider>(
56 {},
57 {
58 fallbackMockImplementation: () => {
59 throw new Error('not mocked');
60 },
61 }
62 );
63
64 expect(() => mock.getPartyType()).toThrowError('not mocked');
65 });
66```
67
68## Assigning Mocks with a Type
69
70If you wish to assign a mock to a variable that requires a type in your test, then you should use the MockProxy<> type
71given that this will provide the apis for calledWith() and other built-in jest types for providing test functionality.
72
73```ts
74import { MockProxy, mock } from 'jest-mock-extended';
75
76describe('test', () => {
77 let myMock: MockProxy<MyInterface>;
78
79 beforeEach(() => {
80 myMock = mock<MyInterface>();
81 })
82
83 test(() => {
84 myMock.calledWith(1).mockReturnValue(2);
85 ...
86 })
87});
88
89```
90
91## calledWith() Extension
92
93```jest-mock-extended``` allows for invocation matching expectations. Types of arguments, even when using matchers are type checked.
94
95```ts
96const provider = mock<PartyProvider>();
97provider.getSongs.calledWith('disco party').mockReturnValue(['Dance the night away', 'Stayin Alive']);
98expect(provider.getSongs('disco party')).toEqual(['Dance the night away', 'Stayin Alive']);
99
100// Matchers
101provider.getSongs.calledWith(any()).mockReturnValue(['Saw her standing there']);
102provider.getSongs.calledWith(anyString()).mockReturnValue(['Saw her standing there']);
103
104```
105You can also use ```mockFn()``` to create a ```jest.fn()``` with the calledWith extension:
106
107```ts
108 type MyFn = (x: number, y: number) => Promise<string>;
109 const fn = mockFn<MyFn>();
110 fn.calledWith(1, 2).mockReturnValue('str');
111```
112
113## Clearing / Resetting Mocks
114
115```jest-mock-extended``` exposes a mockClear and mockReset for resetting or clearing mocks with the same
116functionality as ```jest.fn()```.
117
118```ts
119import { mock, mockClear, mockReset } from 'jest-mock-extended';
120
121describe('test', () => {
122 const mock: UserService = mock<UserService>();
123
124 beforeEach(() => {
125 mockReset(mock); // or mockClear(mock)
126 });
127 ...
128})
129```
130
131## Deep mocks
132
133If your class has objects returns from methods that you would also like to mock, you can use ```mockDeep``` in
134replacement for mock.
135
136```ts
137import { mockDeep } from 'jest-mock-extended';
138
139const mockObj: DeepMockProxy<Test1> = mockDeep<Test1>();
140mockObj.deepProp.getNumber.calledWith(1).mockReturnValue(4);
141expect(mockObj.deepProp.getNumber(1)).toBe(4);
142```
143if you also need support for properties on functions, you can pass in an option to enable this
144
145```ts
146import { mockDeep } from 'jest-mock-extended';
147
148const mockObj: DeepMockProxy<Test1> = mockDeep<Test1>({ funcPropSupport: true });
149mockObj.deepProp.calledWith(1).mockReturnValue(3)
150mockObj.deepProp.getNumber.calledWith(1).mockReturnValue(4);
151
152expect(mockObj.deepProp(1)).toBe(3);
153expect(mockObj.deepProp.getNumber(1)).toBe(4);
154```
155
156Can can provide a fallback mock implementation used if you do not define a return value using `calledWith`.
157
158```ts
159import { mockDeep } from 'jest-mock-extended';
160const mockObj = mockDeep<Test1>({
161 fallbackMockImplementation: () => {
162 throw new Error('please add expected return value using calledWith');
163 },
164});
165expect(() => mockObj.getNumber()).toThrowError('not mocked');
166```
167
168
169## Available Matchers
170
171
172| Matcher | Description |
173|-----------------------|-----------------------------------------------------------------------|
174|any() | Matches any arg of any type. |
175|anyBoolean() | Matches any boolean (true or false) |
176|anyString() | Matches any string including empty string |
177|anyNumber() | Matches any number that is not NaN |
178|anyFunction() | Matches any function |
179|anyObject() | Matches any object (typeof m === 'object') and is not null |
180|anyArray() | Matches any array |
181|anyMap() | Matches any Map |
182|anySet() | Matches any Set |
183|isA(class) | e.g isA(DiscoPartyProvider) |
184|includes('value') | Checks if value is in the argument array |
185|containsKey('key') | Checks if the key exists in the object |
186|containsValue('value') | Checks if the value exists in an object |
187|has('value') | checks if the value exists in a Set |
188|notNull() | value !== null |
189|notUndefined() | value !== undefined |
190|notEmpty() | value !== undefined && value !== null && value !== '' |
191|captor() | Used to capture an arg - alternative to mock.calls[0][0] |
192
193## Writing a Custom Matcher
194
195Custom matchers can be written using a ```MatcherCreator```
196
197```ts
198import { MatcherCreator, Matcher } from 'jest-mock-extended';
199
200// expectedValue is optional
201export const myMatcher: MatcherCreator<MyType> = (expectedValue) => new Matcher((actualValue) => {
202 return (expectedValue === actualValue && actualValue.isSpecial);
203});
204```
205
206By default, the expected value and actual value are the same type. In the case where you need to type the expected value
207differently than the actual value, you can use the optional 2 generic parameter:
208
209```ts
210import { MatcherCreator, Matcher } from 'jest-mock-extended';
211
212// expectedValue is optional
213export const myMatcher: MatcherCreator<string[], string> = (expectedValue) => new Matcher((actualValue) => {
214 return (actualValue.includes(expectedValue));
215});
216```