Testing React Native apps with Jest

React Native allows developers to develop mobile applications easily, and that means testing is more important than ever. You should test the code you write for a number of reasons, most importantly, to ensure that it actually works. In this article, I will explain some principles of unit testing and show you how it is done in React Native.

If you don’t like unit testing your product, most likely your customers won’t like to test it either.

Anonymous

Here is what Wikipedia has to say about unit testing: “unit testing is a software testing method by which individual units of source code […] are tested to determine whether they are fit for use”. In other words, while performing unit testing, you test different bits of your code in isolation. This is different from other types of testing, such as integration testing or functional testing, where you look at how your code performs as a whole.

One principle that is closely related to testing is TDD: Test-Driven Development. When practicing TDD, you write tests first, describing the desired behavior and interfaces. These tests fail (obviously) and you write production code that fixes them. After you get tests to pass, you refactor production code and go back to writing more tests. You can refer to this diagram to get an idea of what I am talking about:

diagram showing a typical TDD lifecycle: write tests, pass tests, refactor, start over

Why bother?

A perfectly reasonable question. We are constantly bombarded with deadlines and crises and feature requests that must be implemented yesterday. It seems impossible to be writing tests under these conditions. But what if I told you that you can ship faster if you use testing correctly.

But that does not make any sense. How can you ship faster if you spend time writing tests? It is happening because while you spend more time writing test code, you will save even more time writing production code. With tests in place, you can change any class, function or algorithm and know within minutes if this change has broken anything. You no longer have to skim the code looking for usages of come particular snippet or dive into documentation to see if you can delete some lines altogether.

The test code itself can be used instead of documentation. If you do not know how a particular API works, you can open unit tests for it as see a couple of examples along with the expected output. This also means that you have to keep your testing code clean and readable, the same rule that applies to production code.

Getting started with Jest

Jest is a testing framework developed by Facebook. It was designed specifically for React. To show you Jest in action, I am going to set up a simple app with Expo and configure unit tests for it. To get started, you will need node.js installed. Then, install expo-cli package and use it to create the project:

When Expo will ask for the template, choose Blank. Now, with the project created, we can add the dependencies:

Jest is the test runner and assertion library. It handles most of the testing-related stuff. jest-expo is a preset for jest to make it work effortlessly with expo. react-native-testing-library handles rendering and interacting with rendered components.

Setting up Jest

To start using jest, you need to add 2 things to your package.json : a test script and a jest config. Like this:

The "test": "jest" line lets us type npm test and npm knows it has to run jest. The jest config later on just makes jest use the jest-expo preset. The universal keyword means jest will test our app in 4 different platforms: IOS, Android, Web and Node.

Why not Enzyme?

If you have experience with unit testing in React, you might be wondering why are we using react-native-testing-library instead of Enzyme. The reason is that Enzyme is not very well ported to React Native. It requires a poyfilled DOM (using JSDOM) and may introduce more bugs. There is a discussion to fix it, but until then I suggest to stick with react-native-testing-library.

Writing your first test

In the project folder, create a file App.test.js . Jest is set up in such a way that it will pick up tests from any file that ends in .test or .spec. Additionally, you may add .ios , .android, .native , .web or .node to write platform-specific tests. You can now write your first test case:

The describe function defines a test suite. It is a group of tests, related to the same aspect of code. The it function marks one test case. The expect function is also provided by jest and is used for the actual testing. In this case, we calculate 2 + 2 and use expect to check if it is really 4.

Using these three functions, you can test pretty much everything. There are some advanced cases when you will need mocking or other helper functions, and I will cover them later.

Snapshot testing

To test your React components, use snapshot testing. Snapshot testing means that react-native-testing-library will render a component and store the result in JSON. Jest will then compare this snapshot with the last snapshot, stored on the disk. If there is a mismatch, you will have to manually check it and determine if it was intended or not. To show you the power of snapshot testing, let us test the App component:

If you run the test now, Jest will receive the snapshot, but it has nothing to compare it to. So, on the first run it is going to write the snapshots to memory:

If you try to run it again, you will notice that this time jest is not writing any snapshots, but comparing the new ones to the old ones. Now, if you change anything in App, like the text that is being written on the center of the screen, the tests will fail with this error:

› 1 snapshot failed.
Snapshot Summary
 › 4 snapshots failed from 4 test suites. Inspect your code changes or run `yarn test -u` to update them.

To make our life easier, let us add a new script to package.json:

Now, whenever a snapshot test fails, you have 2 options:

  1. You have inspected the new snapshot output and decided that this change was intended. To update the snapshots, run yarn test:update-snapshots
  2. You have inspected the new snapshot output and decided that this change was not intended. You now need to fix the production code to get the correct output.

I hope now you have a good understanding of unit testing and how it is done in react native. In the following posts, I will explore some advanced topics about unit testing, such as mocking and extensive components testing.

Get new content delivered to your mailbox:

leave a comment