Variants of the jest.mock call
Before we finish up this chapter, let’s take a look at some variations on the jest.mock
call that you may end up using.
The key thing to remember is to keep your mocks as simple as possible. If you start to feel like your mocks need to become more complex, you should treat that as a sign that your components are overloaded and should be broken apart in some way.
That being said, there are cases where you must use different forms of the basic component mock.
Removing the spy function
To begin with, you can simplify your jest.mock
calls by not using jest.fn
:
jest.mock("../src/AppointmentsDayView", () => ({ AppointmentsDayView: () => ( <div id="AppointmentsDayView" /> ), }));
With this form, you’ve set a stub return value, but you won’t be able to spy on any props. This is sometimes useful if, for example, you’ve got multiple files that are testing this same component but only some of them verify the mocked component props. It can also be useful with third-party components.
Rendering the children of mocked components
Sometimes, you’ll want to render grandchild components, skipping out the child (their parent). This often happens, for example, when a third-party component renders a complex UI that is difficult to test: perhaps it loads elements via the shadow DOM, for example. In that case, you can pass children
through your mock:
jest.mock("../src/AppointmentsDayView", () => ({ AppointmentsDayView: jest.fn(({ children }) => ( <div id="AppointmentsDayView">{children}</div> )), }));
We will see examples of this in Chapter 11, Test-Driving React Router.
Checking multiple instances of the rendered component
There are occasions when you’ll want to mock a component that has been rendered multiple times into the document. How can you tell them apart? If they have a unique ID prop (such as key
), you can use that in the id
field:
jest.mock("../src/AppointmentsDayView", () => ({ AppointmentsDayView: jest.fn(({ key }) => ( <div id={`AppointmentsDayView${key}`} /> )), }));
Approach with caution!
One of the biggest issues with mocking components is that mock definitions can get out of control. But mock setup is complicated and can be very confusing. Because of this, you should avoid writing anything but the simplest mocks.
Thankfully, most of the time, the plain form of component mock is all you’ll need. These variants are useful occasionally but should be avoided.
We’ll see this variation in action in Chapter 11, Test-Driving React Router.
Alternatives to module mocks
Mocking out an entire module is fairly heavy-handed. The mock you set up must be used for all the tests in the same test module: you can’t mix and match tests, some using the mock and some not. If you wanted to do this with jest.mock
, you’d have to create two test suites. One would have the mock and the other wouldn’t.
You also have the issue that the mock is at the module level. You can’t just mock out one part of the module. Jest has functions that allow you to reference the original implementation called requireActual
. For me, that involves moving into the danger zone of overly complex test doubles, so I refrain from using it – I have encountered a use case that needed it.
However, there are alternatives to using jest.mock
. One is shallow rendering, which utilizes a special renderer that renders a single parent component, ignoring all child components other than standard HTML elements. In a way, this is even more heavy-handed because all your components end up mocked out.
For CommonJS
modules, you can also overwrite specific exports inside modules, simply by assigning new values to them! This gives you a much more granular way of setting mocks at the test level. However, this is not supported in ECMAScript, so in the interests of maximum capability, you may want to avoid this approach.
For examples of these alternative approaches and a discussion on when you may want to use them, take a look at https://reacttdd.com/alternatives-to-module-mocks.