Understanding the shallow function in Enzyme
As an alternative to mounting React components during unit tests, you can use Enzyme’s shallow()
to render your component only “one level deep”. Essentially this will render only the code that is defined inside of that component - anything that is imported from elsewhere will not be included.
Let’s take a look at a couple of examples to see how this works in practice.
Shallow rendering some divs
Given a basic component:
We can use Enzyme’s handy debug
function to see what shallow()
is rendering:
Since all our app’s code is defined in the same place, what you will see in your terminal will look identical to your code:
Shallow rendering externally defined components
Here our app is rendering two child components - one defined in a separate file, and the other in the same file as App
:
Since both these components were defined outside of the App
component, their internals won’t be rendered in a shallow render:
Shallow rendering with the render prop pattern
If you are using the render prop pattern:
You will get something like this:
Using the dive function to go one level deeper
If we wanted to test any of the nested child components in the above examples, we can make use of Enzyme’s dive
function.
In the second example where you can see the name of the child component:
You will first need to find()
the child component before then diving into it:
In the render props example, you’ll be able to just dive()
right in!
When is shallow() useful?
Shallow rendering can be faster than mounting your component, and allows you to focus your unit tests on a specific component without having to worry about what any of its children may be doing.
However there is a fairly popular post from Kent C Dodds about how he never uses shallow rendering. Some of the things he points out are that:
- If you test a component using shallow rendering you’re not guaranteeing that the component is actually rendering correctly e.g. if any child components are broken, it won’t cause the test to fail
- If you’re shallow rendering, you’re going to be testing implementation details, which you shouldn’t be doing
- Even if mounting your component is slower, it’s worth it!
Tim Doherty has posted a rebuttal in defense of shallow rendering in which he talks about what constitutes an “implementation detail” and when shallow()
might be useful.
For example if you had an onChange
prop in your React component:
Tim argues that it would be okay to test that the onChange
prop being called causes the desired behaviour to occur, since the onChange
prop counts as part of the public interface for that component and therefore isn’t an “implementation detail”.
Enzyme can be used with any number of testing libraries, but in this post I am using Jest for assertions
Personally I’ve done a similar sort of thing in scenarios where we might want to assert that a function isn’t being called more than a certain number of times (due to it being expensive, or triggering other unwanted effects in our app):
shallow() won’t always work
Another thing to point out is that not everything is going to work if you shallow render a component, such as:
useEffect
- your code will run, but it will never enter this hookuseContext
- you’re never going to get a value back from your context- refs - setting a ref won’t work
In these cases you will definitely have to use mount()
.
Switching out shallow() for mount()
One of the downsides I find with mount()
is that if your app’s child components make some endpoint calls and/or have dependencies on things that aren’t going to be available in tests, mocking all of those things can take a bit of time and effort.
One way you could work around this problem is to mount your component, and mock any children components that are causing issues (and that you don’t need in your tests):
However if you end up mocking all of your children components, at that point you may as well just use shallow()
anyway - unless of course you want to test things like useEffect
or useContext
in which case this will come in handy.
If you want to learn more about mocks, I have an article on mocking with Jest you can check out.
Conclusion
I started off writing this post wanting to properly understand what it means to use shallow()
in Enzyme, and then I got a bit sidetracked reading about the pros and cons of whether we should even be doing shallow rendering at all!
I think shallow rendering still has its uses, and I will continue to use it, but if you are interested in moving away from shallow()
then a “best of both worlds” approach may be to use mount()
, but then selectively mock out any child components that you don’t want to include in your tests.
Thanks for reading!