Tutorial: UI Testing in React Native with testing-library

Ben Hur
TribalScale
Published in
6 min readMar 22, 2022

Written by: Ben Hur Martins Carvalho, Agile Software Engineer, TribalScale

📫 Subscribe to receive our content here.

💬 Have any questions about UI testing in React Native? Click here to chat with one of our experts!

A user interface for a website side-by-side with it’s code
Photo by Daniel Korpai on Unsplash

UI is the what users interact with when they use your app. UI issues are oftentimes not visible to the eye and can be costly to fix later down the road. Faulty UI also negatively impacts your brand and user adoption, making UI testing a necessity before an application can be released to production.

In this tutorial, we’ll be building a recipe book app where we’ll have a home screen with a list of recipes, a screen to add new recipes and a screen to detail our recipe. We’ll focus only on UI testing, we won’t be focusing on Redux and React Navigation although we’ll also be using those libraries.

Setup

Start the project with the following command:

$ npx react-native init UITestApp --template react-native-template-typescript

Let’s set up the dependencies inside the root of our project, starting with Redux.

$ yarn add react-redux @reduxjs/toolkit

Then we’ll install the React Navigation library.

$ yarn add @react-native-community/masked-view @react-navigation/native @react-navigation/stack react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-screen

And last but not least, the star of our show: testing-library.

$ yarn add -dev @testing-library/react-native

For iOS run the following command:

$ npx pod-install

Creating the reducers and the store

Let’s create our recipe model first. We’ll keep it simple with one recipeId, recipeName and recipe.

Now let’s create our reducer inside ./src/redux/Recipes/.

With a few words, our reducer will add and remove recipes from our app state. Now we can set up the store.

Simple as that.

Creating the screens and the navigation structure

We’ll be creating three screens: Home, NewRecipe and Detail.

Home

This screen will have the option to navigate to the other screens. We’ll use hooks, and for that we need to set up the types. Our Home.tsx file will look like this:

NewRecipe

Our NewRecipe.tsx file will look like this:

Detail

Our Detail.tsx file will look like this:

Navigation

Now we’ll set up our navigation using a simple Stack structure.

Our app should now run like this:

Testing setup

Setup? I thought that I could start to code tests! Not too fast, we first have to set up jest. We’ll create a jest setup file and a helper file that will wrap each component with our reducer store, we’ll then have access to selectors and actions.

Update your package.json file in the jest node.

Create a setup.js file inside the jest folder.

The last line can change depending on the react-native version.

In our helper file, this is where all the magic happens. It allows us to override the default store of our app to another that can fit our test case better, this is a very important step when we have Redux or some other kind of provider.

And we are finally ready to start testing 😅.

Testing NewRecipe

We can start with the NewRecipe screen. The screen will have two input fields, one for recipe name and another one for the recipe, and a label with the id of the recipe. We’ll access the id with our reducer and obtain the length of the recipe array. After submitting a new recipe, the input fields should be cleared. There is also TDD (test-driven development), but for tutorial purposes I will just show the code.

Update the NewRecipe.tsx file:

Let the testing begin. Create a new file in the same folder and name it NewRecipe.test.tsx.

The tests

  • After changing the recipe name input text, we should find the same text on the screen.
  • After changing the recipe input text, we should find the same text on the screen.
  • After clicking on the submit button, the input fields should be cleared and the label showing the id should increment 1.

We already have the setup file that will wrap our component with Redux, but we will need to wrap it in the navigator container too. We can see that below on line 14:

The test:

PASS  src/screens/NewRecipe/NewRecipe.test.tsxNewRecipe✓ should change the text in the recipe name input field (242 ms)
✓ should change the text in the recipe input field (10 ms)
✓ should change the label id after including a new recipe (10 ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.473 s, estimated 2 s

Testing Home

On the Home screen we’ll have a list of recipes, a button to include a new recipe and each recipe in the list should lead to the Detail screen. For the test we will mock the store, there is not much to test except finding some components and counting them up in the FlatList.

Update the Home.tsx file:

We’ll add a special test for the extra component that we have on the Home screen, ListItemRecipe.

The tests

  • Find both recipes on the screen.
  • Get the list component by id and check if there are two components.
  • Bonus test, this one is to learn how to scroll the FlatList, very useful to test lazy loading lists.

Create a new file in the same folder and name it Home.test.tsx. To test this UI we are pre-loading the store with two recipes, we can see that below on line 14:

Testing Detail

This screen will be simple, one title, the recipe and a button to return. We can test if the title and recipe matches.

Update the Detail.tsx file:

Create a new file in the same folder and name it Detail.test.tsx. This is a simple test, but we’ll have to initialize the component with some parameters as we can see on line 19:

We have one more component to test, ListItemRecipe. So far we’ve tested the whole screen but it is also important to test isolated components. The component will receive a title and callback as properties so we can test if the callback is being called, the component is clicked, and if our title shows in the component.

Results

When we reach the end of our cases, we can see how it covered most of the lines in the test:

I hope this tutorial was useful for you, you can find the final code here.

Ben is an Agile Software Engineer here at TribalScale and is based in Brazil. He is a front-end developer and his stack today is React Native and ReactJS, before TribalScale he worked as a full stack developer for 8 years. Outside of work he has multiple hobbies, a recent one is leather craft, and loves spending time with his 1 year old son.

TribalScale is a global innovation firm that helps enterprises adapt and thrive in the digital era. We transform teams and processes, build best-in-class digital products, and create disruptive startups. Learn more about us on our website. Connect with us on Twitter, LinkedIn & Facebook!

--

--

Ben Hur
TribalScale

I am a React Native Developer with passion to build things.