VOOZH about

URL: https://blog.logrocket.com/user-behavior-testing-react-native-testing-library/

⇱ User behavior testing with React Native Testing Library - LogRocket Blog


2020-12-09
1514
#jest#react native
Zain Sajjad
30235
👁 Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

In frontend development, testing user behavior is crucial for delivering great products. React Native Testing Library (RNTL) makes it a joy to test user journeys in our React Native apps. It has great APIs to make tests immune to implementation details.

👁 User Behavior Testing with React Native Testing Library

By the end of this tutorial, I promise you will feel this joy, too — and I won’t take up too much of your time getting there. You can find the full code for this demo on GitHub.

🚀 Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

Getting started with React Native Testing Library

Let’s begin with adding libraries that we will be using to make our testing a joyful experience.

yarn add -D @testing-library/react-native

One thing to note here — RNTL is a wrapper over react-testing-library that depends on Jest. This combination, in my humble opinion, is a match made in heaven and makes the testing experience amazing.

Testing a Button component

Let’s start small; if you are familiar with testing components, you can skip this section. We will test a simple button component just to make ourselves a bit more familiar with how RNTL works and what we are up to. Here is how our Button component looks:

👁 Code for the Button Component

Here’s the full code for the Button component. We will test that it should call the onPress method when it is pressed by a user. Our test should look like this:

👁 Code for the Button Component Test Suite

RNTL provides a great API to grab components using attributes. Though there are a number of ways to grab a component, I feel getByTestId makes your test code more immune to UI and textual changes.

With the fireEvent API, we can mock many interactions, which allows us to test user behaviors. Here, we have created a mock method and asserted that it should be called only once when a user presses the button. We will use a similar structure for testing our flow further.

Here is how we will execute this test, along with the expected output:

👁 Expected Output for Our Button Component Test

Cool, so we have done some basic testing now and have a good idea of how things will shape up.

Testing a login form

Let’s take a step forward and practice some real-world examples. We will test a form that takes email and password inputs from a user and passes them to the onSubmit method. We will also assert that it renders a validation error if a user has not entered a password. Here’s our component:

👁 Code for the Email Form Component

Let’s test our first use case: the component should display a “password required” error. Here’s our test will look:

👁 Code for the Email Form Component Test

Here we are testing an action that has an impact on state. Since setState is async in React, we have to execute this test in an async way. RNTL provides the waitFor API for this. Also, we have used the same fireEvent API here for changing the text of our input component.

Moving to our next use case, we expect to call onSubmit with email and password:

👁 Mocking the Function Argument in the Form Component Test

We’re taking another step forward by asserting the mock function’s argument to make sure we have the expected output. Here is our full test suite for the EmailPasswordForm component.

Building our testing flow

Now that we’ve built up some confidence, let’s test our complete login flow. This isn’t just about testing methods being called. Login usually includes two main functions: it has some network API call that returns a token, and then we save that token in local storage for later use.

Mocking API

In order to make our test independent of server/network, we will mock our API hits. This is possible with the fabulous open source package fetch-mock-jest. It intercepts all fetch calls and resolves them with given response. This allows us to test all success and error cases. Let’s add it to our code base.

yarn add -D fetch-mock-jest

Here is the simplest mocking we will use; it mocks a login API call with an expected response.

👁 Mocking a Login API Call

Mocking AsyncStorage

React Native apps use a number of native bridges to access platform-specific functionalities. In our case, we have to make sure the login API response is stored in local storage.

RNTL allows us to mock these native bridges so we can run our tests without depending on devices or emulators. In order to mock these libraries, we will add the file jest.mock.js, which will code for mocking all of the native libraries we are using in our app. Here’s our mock file:

jest.mock('@react-native-community/async-storage', () => ({
 setItem: jest.fn(),
}));

One important point to note here: we have to mock all methods that we are using from libraries, as these are not added in our testing environment.

Now we will reference this file from our jest.configs.js file:

module.exports = {
 ...
 setupFiles: ['./jest.mock.js']
 ...
};

Adding this file to the setupFiles array will tell Jest to execute this file before running any test suite.

Full testing suite

Now that we have our mocking in place, let’s take a look at how we’ll test our full flow:

👁 Full Test Flow for Our Login Screen

Don’t worry — it’s just lengthy, not hard to digest. We already know most of this.

To begin with, we have added fetchMock in our beforeAll hook to make sure our fetch mocking begins before this test suite starts. Here we have rendered our screen component with a mocked navigate method; this is how our screen will be rendered in the app.

After executing all user interactions, we start asserting things happen as we expect. Here is the list of our expectations:

  • API is called with expected values
  • App navigates to homescreen once API response is received
  • jwtToken is stored in local storage

If all of these tests pass, we are sure that our login screen works the way we expect it to. This marks our login flow testing as complete.

Pre-test task: Linting

Testing might take a bit longer to execute over time as our test suites grow in number and size. Linting our code before executing any tests will make sure we are not executing tests on code with any obvious bugs. We will add lint tasks in the pre-test script. Here’s what it looks like:

👁 Adding the Pre-test Linter

You can view the full package.json file here.

Post-test task: Adding a reporter

Who doesn’t like charts and dashboards to visualize performance? Here, we will integrate the Jest test reporter, which will deliver us a complete picture of our test execution. This will help us monitor what tests are breaking and how much time each test takes to complete.


Over 200k developers use LogRocket to create better digital experiences

👁 Image
Learn more →

Adding the reporter to our project:

yarn add -D jest-html-reporters

Next up, let’s add this reporter to our jest.configs.js file. Here’s how it looks:

👁 Adding Reporter to Our Configs File

To get it running, let’s open up this reporter automatically every time our tests are executed. It’s simple — we’ll add it to our post-test script as an update to our package.json:

👁 Adding Reporter in the Post-test Script

Here’s the test report for our project:

👁 Visualization of the Project Test Report

And here’s the .html file of the report.

Adding pre-commit hooks

For large-scale applications (and side projects that we work on every seventh day), it’s better to have solid checks in place to maintain code quality. These checks must be enforced to ensure that every PR that arrives in our repos is up to standard and passes defined criteria.

Pre-commit hooks can help us here. These hooks run before every commit. We can add our test task to make sure that no commit is allowed to break any of our tests. We are using husky here, which makes adding commit hooks much easier. This is our last library to add:

yarn add -D husky

Let’s set up our first pre-commit hook here. npx will help us with that:

npx husky add pre-commit "yarn test" # will create .husky/pre-commit file

Running this command will create a .husky/pre-commit file for us. It’s a bash script that will be executed before any commit.

At times, our list tasks have a --fix option that makes changes to our files as we run the command. In our case, we added a Jest reporter in the section above, which will create a new reporting file as we run our tests. In order to add all of these changes to our commit after pre-commit hooks are executed, we will update our pre-commit file. This is how it looks:

👁 Final Update to Our Pre-commit File

And we’re done for today!

Yes, I know how it feels when you have a complete testing ecosystem in place — more relaxed and confident that your code won’t break too soon.

React Native Testing Library makes it easier to follow best practices and keeps your testing experience joyful. It allows you to test your application in the same ways your users interact with it. Making sure all your use cases are covered provides a lot of confidence — you better believe it will get your app’s rating up.

Moving forward from here, you can try out Detox for end-to-end testing; it will help you test for cases that require native APIs, like notifications, deep linking, and sophisticated user interactions.

LogRocket: Instantly identify and recreate issues in your React Native apps

👁 Image

LogRocket's Galileo AI watches sessions for you and and surfaces the technical and usability issues holding back your React Native apps.

LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your React Native apps — try LogRocket for free.

👁 Image
👁 Image
👁 Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

Debug Next.js apps with AI agents and next-browser

Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.

👁 Image
Emmanuel John
Jun 17, 2026 ⋅ 9 min read

Stop hardcoding LLM SDKs: Dynamic LLM routing with OpenRouter and Next.js

Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.

👁 Image
Chizaram Ken
Jun 16, 2026 ⋅ 13 min read

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension — no new framework required.

👁 Image
Ikeh Akinyemi
Jun 12, 2026 ⋅ 6 min read

How to add authentication to a React Native app with Better Auth

Learn how to build a full React Native auth system using Better Auth and Expo — with email/password login, Google OAuth, session persistence, and protected routes.

👁 Image
Chinwike Maduabuchi
Jun 9, 2026 ⋅ 13 min read
View all posts

Would you be interested in joining LogRocket's developer community?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now