Test-driving a Redux App
Published by Carlos Blé on 05/04/2017
React, Redux, JavaScript, Testing, TDD
I like starting every new feature with a failing coarse-grained test that exercises most of the layers I’ll have to cross in order to get the feature done. During that cycle I may write smaller tests to get faster feedback. Pretty much anytime I feel the need to debug my big test, I rather write small tests to confirm that smaller chunks of code work as expected. Some of those tests will stay when development is done and some others will be deleted, they are used only as a scaffolding mechanism. This is one way to approach outside-in TDD. In a frontend app, the boundaries of the system are the server API and the GUI. I usually stub or spy on the server API - a simple AJAX client. However I do use the actual GUI, well, in the case of React the wrapper provided by Enzyme’s mount, because it’s fast anyway and gives me a feeling of realistic behavior. The server API is pretty much the only thing I mock, for everything else I prefer to use the actual artifacts.
For the Profile Page described in the previous post, this would be a good test to start from:
Initially the store contains an empty profile to render the page. At the beginning of the test I wait for the profile to be retrieved from the server. I assume the download is finished as soon as the notifier is called to let the user know about the end of the request. At that point the action should have been dispatched by Redux and I can assert that the form renders the server’s data. Here I am stubbing out the query to the server and spying on the notifier method which is a void function.
In order to make this test pass I must write the action, the reducer and the method in the component. Notice that I am using the factory we saw in the previous post. This would be the code required by the component:
The test above covers the factory which includes the call to connect thus testing mapStateToProps and mapDispatchToProps. It also covers the stores’ configuration and the component including all its children. It integrates pretty much all the layers. Only routing and server side are left out. It’s fast to run and gives me a lot of confidence. I can write additional fine-grained tests for the reducer in isolation or the component using Enzyme’s shallow. In fact, as we’ll explore in an upcoming blog post, Enzyme’s mount is not the best fit for components that handle their own state calling React’s setState.
In case you miss it, this is the rest of the code required by the test:
The action creator above requires react-thunk middleware to work.