React with Redux has become a very common stack these days. People with very little background of front-end, like me, can write something that turns out not bad. However, testing a React component connected to the Redux can sometimes be painful.
In this post, I want to share some of the ideas about how to test against a Redux container.
First of all, we need a container to be tested against.
In the following gist, we have a text box that:
- saves the value of input into component’s local state
- submits the input value via Redux action dispatch to the Redux store.
- shows the input value in the Redux store.
Note this component is only used for this example. Separating the text box and the representative part is more practical in a real project.
I highly recommend using Enzyme with all your React components’ tests. This utility makes it much easier to traverse and assert your React/Redux components.
Besides, it now works pretty well with Mocha and Karma and other stuff you might use in your test.
Redux store wrapper for the tests
One of the painful parts of testing a Redux container is that we can’t just render a container and then evaluate the DOM anymore. That’s because container will ask for the Redux store in mapStateToProps() when you connect your component to Redux, and without it, test fails.
So, before we start to write testing code, we will need a “Redux wrapper” for all of our testing components to provide Redux store, which is something pretty much like what we have usually done to our root component in the application.
Luckily, Enzyme provides a shallow-render function that can take a context as second parameter, where we can put a Redux store for our tests.
Make sure it’s working
shallowWithStore with the mocked store, we can finally shallow-render our container.
To test the DOM structure, you can use find() to traverse the rendered result, then use prop() to get the desired attribute then make the assertion. To test event handler, you can first get the element with find(), then use simulate() to trigger the event. After that, just make assertion as usual. Please note that we call dive() before calling find().
Test non-Redux feature with Enzyme
There are two non-Redux features we might want to test:
- DOM structure.
- handleInput function in the component.
Achieving these two goals is extremely simple with the Enzyme.
To test event handler, you can first get the element with
find(), then use simulate() to trigger the event. After that, just make assertion as usual.
Please note that we call
dive() before calling
I used Chai for assertion. It might look different from what you would write depending on your setup.
One thing that should be careful about is that if we shallow-render a connected container, the result of rendering will not reach the DOM inside the component.
This means the whole DOM inside ShowBox will not be rendered, which will cause following assertion to fail:
The reason is that shallow-render only renders the direct children of a component.
When we shallow-render connected container
<ConnectedShowBox />, the deepest level it gets rendered is
<ShowBox />. All the stuff inside the ShowBox’s
render() will not be rendered at all.
To make the result of shallow-render go one layer deeper( to render the stuff inside the
<ShowBox />), we need to call dive() first.
You can also test mapStateToProps here by simply changing the mocked
Test Redux dispatch mapDispatchToProps
mapDispatchToProps with Enzyme is really easy.
Just like what we did to test
handleInput(). First we use
find() to get the element that we need to trigger, then use the
simulate() to trigger the event.
isActionDispatched() to check whether the expected action is dispatched.
And that is it! I think this is enough for most the use cases in testing.
Here is some further challenges for this topic:
- Make it work with code coverage utilities.
- Make it work with GraphQL(Apollo)