Testing React & React Native — Jest vs the rest
For me, there is no better feeling than working on a project with a high test coverage. You get to refactor your components and even your application without (in the best case) any worry of breaking the current behavior. So, naturally, you want to test your React and React Native codebase. What tools do you have at your service for testing and what are their pros and cons for which environment? I would like to share my insights with you:
Before we begin with the evaluation, it is necessary to understand the difference in the environment. If you would like to test your React Web application, you can use the “usual” web testing tools like karma or mocha. The way you test with them is that a complete rendering of the component you test occurs, and you may run assertions on the rendered output. There are two problems with this approach of testing: first, it is time and resource consuming to render in a browser instance, and second, there is currently no way (that I know of) to render a React Native application to a unit test context. So how is this solved?
Enzyme is a library by AirBnB which aims to make testing React Applications easier by introducing a reasonably simple assertion interface and three types of renderers: shallow, full DOM, static rendered markup. For us, the only relevant one is shallow as the other ones have no improvement compared to mocha or karma. Shallow rendering renders your component to a pure JS representation, which may then be used in assertions. This way the tests run much faster and you can test even React Native Apps with it if you use React Native Mock to mock React Natives internals. The only problem for me with this setup was: I was not able to test some features in React Native that I would have liked to be tested, like user interaction or exported API. The project I am currently working on is a polyfill for the React Native Drawer Layout Android which exports an imperative API to open or close the drawer. As I don’t mount the component, I don’t get to use this API in my tests, which leaves me in an unsatisfied state.
The most recent version of Jest (0.14) has a new feature introduced: snapshot testing. I explained how snapshot testing works and what it is in this previous post, so let me just remind you of what it does: Instead of rendering to native or DOM (or art or …) you use the test renderer with Jest to generate a JSON representation of your rendered component. Unfortunately, there is currently no event system in this test renderer, so you have no way of simulating a click or use an imperative API. So, sadly there is no way to test other things than you could test with mocha, karma and so on. But at least you can test the other things faster: As you have no full DOM implementation running and as Jest is designed to run tests in parallel you may run your test suite much quicker. And additionally, as mentioned in the previous post, you may write simple tests much quicker: Just one toMatchSnapshot expectation may ensure you didn’t screw up during the last refactoring.
But there is one thing with jest I have to warn you about: The dependency hell: The cross dependencies between React, React Native, Jest and the test renderer lead to a few wasted hours reinstalling the packages over and over again with different versions and I still don’t have a version without unmet peer dependencies warning. To check out my currently working profile, please see my playground here.