Back

How to Mock Using Jest.spyOn (Part 2)

Jeffrey ZhenWednesday, October 16, 2019
Black and white cat standing under window

This is part 2 of my JavaScript testing series. You can check out How to Write Functional Tests in React (Part 1) here!

Mocking is an important concept in testing where a subject that is dependent on data has said data replaced so that it can be controlled and measured.

There are a handful of ways you can mock in Jest. You can mock a function with jest.fn or mock a module with jest.mock, but my preferred method of mocking is by using jest.spyOn.

Tracking Calls

jest.spyOn allows you to mock either the whole module or the individual functions of the module. At its most general usage, it can be used to track calls on a method:

const video = { play() { return true; }, }; export default video;
import video from './video'; test('plays video', () => { const spy = jest.spyOn(video, 'play'); video.play(); expect(spy).toHaveBeenCalledTimes(1); }); view raw

Any call to video.play, either in this test file or (if the function is being called as a side-effect) in some other file, will be tracked within this test('plays video', () =>{}) function.

Overwriting/Mocking A Function

If you want to mock out an implementation and overwrite the original function, you can chain .mockImplementation to the end of jest.spyOn:

test('creates Contract on correct date', () => { const NOW = '2019-05-03T08:00:00.000Z'; const mockDateNow = jest .spyOn(global.Date, 'now') .mockImplementation(() => new Date(NOW).getTime()); const mutation = ` mutation createContract { createContract { startedOn } } `; const response = await graphQLRequestAsUser(mutation); const { data } = response.body; expect(data.startedOn).toEqual(NOW); mockDateNow.mockRestore(); });

In this test, we are mocking the implementation of JavaScript’s global Date.now() function. We set it to return a static value of 2019-05-03T08:00:00.000Z (converted to milliseconds).

On the backend, where createContract is implemented, we use Date.now() to define the startedOn field of a Contract. When graphQLRequestAsUser is called, createContract will be run on the backend and will use the mocked Date.now() to return the date we set (instead of the actual Date.now()).

By mocking Date.now(), we can ensure that:

  1. createContract is creating Contract records with a startedOn field in the correct format
  2. our tests will pass consistently because Date.now() is returning a value that we can confirm every time

BONUS: before/after Hooks

We can use jest’s beforeEach and afterEach hooks so that we keep our tests DRY when they have similar environments to setup:

const now = '2019-05-03T08:00:00.000Z'; let mockDateNow; beforeEach(() => { mockDateNow = jest.spyOn(global.Date, 'now').mockImplementation(() => new Date(now).getTime()); }); afterEach(() => { mockDateNow.mockRestore(); }); test('some test name', () => { //...do some test stuff here }) test('another test name', () => { //...do some more test stuff here })

Before every test function is run in the file, jest will mock Date.now(), and after every test, jest will restore the function to its original implementation. Using the beforeEach/afterEach hooks for setup ensures that every test is fresh and independent of each other.

Note: we could probably use beforeAll/afterAll instead of the tests aren’t mutating the date.

I hope this article helped you understand the usage of mocks a litter better. Please don’t hesitate to reach out if you have any questions. You can drop us a line through Echobind’s contact page or just leave a comment here. I wish you the best of luck to you on your next npm run jest!

Share this post

twitterfacebooklinkedin

Related Posts:

Interested in working with us?

Give us some details about your project, and our team will be in touch with how we can help.

Get in Touch