How to test React Native applications

Lauren Steven
NicaSource
Published in
5 min readSep 19, 2022

As your codebase grows, issues and bugs might appear. Errors in your application can lead to a bad user experience, business losses, and, ultimately, stress developers.

To prevent chaos, testing your code before releasing it is crucial, and I’ll teach you the foundations to test your apps.

What is testing?

Testing is the process of evaluating and confirming that a software application does what it’s supposed to do in different scenarios. The goal is to have information about the quality of your application at any moment while you’re building it.

The testing pyramid

In 2012, Martin Fowler introduced the concept of the test pyramid. The metaphor explains a way of thinking that to create a balanced portfolio; we should use different automated tests. The main takeaway of the concept is that you should have many more low-level UnitTests than high-level BroadStackTests running through a GUI.

As seen in the image above, the three testing categories are:

  • Unit tests
  • Integration tests
  • End-to-end tests

We’ll implement the first two types on a React Native app in the following examples.

React Native Testing Library

The React Native Test Library (RNTL) is the best solution for testing React Native components as it uses the best testing practices. RNTL encourages you to test your application by avoiding the implementation details. The previous avoids refactors breaking your tests (false negatives) or your tests passing when you break your code (false positives). Also, the test style is very close to how the users would use your application.

Installation

You will need to add Jest to your project. Jest is a JavaScript library that allows us to create, structure, and run tests. To do so, in your project’s folder, run:

yarn add — dev @testing-library/react-native @testing-library/jest-native react-test-renderer

The @testing-library/jest-native in the command above gives us additional React Native-specific jest matchers. Now that you have installed the libraries, go to your Jest configuration (jest.config.js) file and add this:

{
"preset": "react-native",
"setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"]
}

And add the test script in the package.json

"scripts": {
...
"test": "jest",
},

Our first test

Suppose you have the typical counter component and want to test its behavior.

As shown in the above code, you have a <Counter /> component (line 4) with two buttons, one for increasing the counter (line 10) and the other for decreasing it (line 11). You also have a <Text> component (line 9) that shows the counter’s value.

If you want to test this component, RNTL gives some methods to render it, fire events, and get elements that may exist in your component.

Let’s see the first test:

First, you’ll need to define your test using the test function provided by jest. Then, in the first line of your test (line 8), you must use the render utility to render your component. Once your component is rendered, you can query some elements.

For this test, I’m using the getBy* query, which returns the first matching node if it exists. Otherwise, it throws an error. As you can see in line 9, the first expectation is to verify if the default counter value has the 0 value.

After it, you have to fire an event. The fireEvent.press invokes the press event handler on the element or parent element in the tree. In this case, line 12 will “press” the Increase button, passing the button’s reference to the press function.

Once you press that, the counter text should increase. Thus, in line 15, we verify that the counter text is now “1”.

Now, if you run the yarn test command, you will see that our test passed.

As I mentioned at the beginning of the article, RNTL encourages you to test your application by avoiding implementation details. So, for example, if you refactor your code and rename the count and setCount the test still works as it should because your test is not coupled to your logic.

You can find more information here if you want to read more details about testing implementation.

Testing an Error Boundary

According to the official React documentation:

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

In our next component, you have an error boundary class component. The only way we have to create error boundaries is by using Classes. You can read more information here. It uses the children prop to render whatever you want to pass a child (wrap any part of your app with the error boundary) when there are no errors.

But, when there’s an unhandled error, the ErrorBoundary will render a fallback UI with information and one action to restore the app’s state and render the children prop again.

Then if you want to wrap either a component or the whole app, you can use:

<ErrorBoundary>
<MyApp />
</ErrorBoundary>

Let’s see how to test this:

First, you will create a component that allows us to simulate the error. Then, you need to verify that the component renders its children correctly when there are no errors. I’ll call the component “Bomb,” and it will receive the shouldThrow boolean prop to throw the error.

The next test case should render the component and then re-render it with the error. To simulate the error, the prop shouldThrow is used in the re-render.

Final Thoughts

Well, we have come to the end of the article, and we have covered the React Native Testing Library’s main functions and a couple of examples to understand how to test components. In future articles, I will focus on more realistic cases, such as navigation between screens and integration with redux or API calls. See you then!

--

--

Lauren Steven
NicaSource

Mobile Developer | ReactJS, React Native, GraphQL