Skip to content

Commit 139f976

Browse files
m4n3z40cpojer
authored andcommitted
Adding async versions of mockReturnValue & mockreturnValueOnce (#5318)
* Adding async utility versions of mockReturnValue & mockreturnValueOnce * Fixing rejection tests * simplify assertions * Adding changes to CHANGELOG and Docs * Fixing doc examples
1 parent 36c705b commit 139f976

File tree

4 files changed

+155
-0
lines changed

4 files changed

+155
-0
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## master
22

3+
### features
4+
5+
* `[jest-mock]` Add util methods to create async functions.
6+
([#5318](https://github.com/facebook/jest/pull/5318))
7+
38
### Fixes
49

510
* `[jest]` Add `import-local` to `jest` package.

docs/MockFunctionAPI.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,3 +241,84 @@ const myMockFn = jest.fn()
241241
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
242242
> 'first call', 'second call', 'default', 'default'
243243
```
244+
245+
### `mockFn.mockResolvedValue(value)`
246+
247+
Simple sugar function for:
248+
249+
```js
250+
jest.fn().mockReturnValue(Promise.resolve(value));
251+
```
252+
253+
Useful to mock async functions in async tests:
254+
255+
```js
256+
test('async test', async () => {
257+
const asyncMock = jest.fn().mockResolvedValue(43);
258+
259+
await asyncMock(); // 43
260+
});
261+
```
262+
263+
### `mockFn.mockRejectedValueOnce(value)`
264+
265+
Simple sugar function for:
266+
267+
```js
268+
jest.fn().mockReturnValueOnce(Promise.resolve(value));
269+
```
270+
271+
Useful to resolve different values over multiple async calls:
272+
273+
```js
274+
test('async test', async () => {
275+
const asyncMock = jest.fn()
276+
.mockResolvedValue('default')
277+
.mockResolvedValueOnce('first call')
278+
.mockResolvedValueOnce('second call');
279+
280+
await asyncMock(); // first call
281+
await asyncMock(); // second call
282+
await asyncMock(); // default
283+
await asyncMock(); // default
284+
});
285+
```
286+
287+
### `mockFn.mockRejectedValue(value)`
288+
289+
Simple sugar function for:
290+
291+
```js
292+
jest.fn().mockReturnValue(Promise.reject(value));
293+
```
294+
295+
Useful to create async mock functions that will always reject:
296+
297+
```js
298+
test('async test', async () => {
299+
const asyncMock = jest.fn().mockRejectedValue(new Error('Async error'));
300+
301+
await asyncMock(); // throws "Async error"
302+
});
303+
```
304+
305+
### `mockFn.mockRejectedValueOnce(value)`
306+
307+
Simple sugar function for:
308+
309+
```js
310+
jest.fn().mockReturnValueOnce(Promise.reject(value));
311+
```
312+
313+
Example usage:
314+
315+
```js
316+
test('async test', async () => {
317+
const asyncMock = jest.fn()
318+
.mockResolvedValueOnce('first call')
319+
.mockRejectedValueOnce(new Error('Async error'));
320+
321+
await asyncMock(); // first call
322+
await asyncMock(); // throws "Async error"
323+
});
324+
```

packages/jest-mock/src/__tests__/jest_mock.test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,53 @@ describe('moduleMocker', () => {
391391
expect(fake(2)).toEqual(4);
392392
});
393393

394+
it('supports mocking resolvable async functions', () => {
395+
const fn = moduleMocker.fn();
396+
fn.mockResolvedValue('abcd');
397+
398+
const promise = fn();
399+
400+
expect(promise).toBeInstanceOf(Promise);
401+
402+
return expect(promise).resolves.toBe('abcd');
403+
});
404+
405+
it('supports mocking resolvable async functions only once', () => {
406+
const fn = moduleMocker.fn();
407+
fn.mockResolvedValue('abcd');
408+
fn.mockResolvedValueOnce('abcde');
409+
410+
return Promise.all([
411+
expect(fn()).resolves.toBe('abcde'),
412+
expect(fn()).resolves.toBe('abcd'),
413+
]);
414+
});
415+
416+
it('supports mocking rejectable async functions', () => {
417+
const err = new Error('rejected');
418+
const fn = moduleMocker.fn();
419+
fn.mockRejectedValue(err);
420+
421+
const promise = fn();
422+
423+
expect(promise).toBeInstanceOf(Promise);
424+
425+
return expect(promise).rejects.toBe(err);
426+
});
427+
428+
it('supports mocking rejectable async functions only once', () => {
429+
const defaultErr = new Error('default rejected');
430+
const err = new Error('rejected');
431+
const fn = moduleMocker.fn();
432+
fn.mockRejectedValue(defaultErr);
433+
fn.mockRejectedValueOnce(err);
434+
435+
return Promise.all([
436+
expect(fn()).rejects.toBe(err),
437+
expect(fn()).rejects.toBe(defaultErr),
438+
]);
439+
});
440+
394441
describe('timestamps', () => {
395442
const RealDate = Date;
396443

packages/jest-mock/src/index.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,17 @@ function getSlots(object?: Object): Array<string> {
227227
return Object.keys(slots);
228228
}
229229

230+
function wrapAsyncParam(
231+
fn: any => any,
232+
asyncAction: 'resolve' | 'reject',
233+
): any => any {
234+
if (asyncAction === 'reject') {
235+
return value => fn(Promise.reject(value));
236+
}
237+
238+
return value => fn(Promise.resolve(value));
239+
}
240+
230241
class ModuleMockerClass {
231242
_environmentGlobal: Global;
232243
_mockState: WeakMap<Function, MockFunctionState>;
@@ -407,6 +418,13 @@ class ModuleMockerClass {
407418
return f;
408419
};
409420

421+
f.mockResolvedValueOnce = wrapAsyncParam(
422+
f.mockReturnValueOnce,
423+
'resolve',
424+
);
425+
426+
f.mockRejectedValueOnce = wrapAsyncParam(f.mockReturnValueOnce, 'reject');
427+
410428
f.mockReturnValue = value => {
411429
// next function call will return specified return value or this one
412430
const mockConfig = this._ensureMockConfig(f);
@@ -415,6 +433,10 @@ class ModuleMockerClass {
415433
return f;
416434
};
417435

436+
f.mockResolvedValue = wrapAsyncParam(f.mockReturnValue, 'resolve');
437+
438+
f.mockRejectedValue = wrapAsyncParam(f.mockReturnValue, 'reject');
439+
418440
f.mockImplementationOnce = fn => {
419441
// next function call will use this mock implementation return value
420442
// or default mock implementation return value

0 commit comments

Comments
 (0)