---
title: Set up Detox for end-to-end testing in your React Native App
teaser: Looking to set up Detox in your next React Native application? Here we have
  a guide to make your life easier!
tags: react native,mobile,ios,android,detox,typescript
author:
- Rémy Hannequin
- Jose Blanco
published_on: 2024-04-04
---

Recently some of us have been working on a React Native project to improve
our skills and learn more about mobile development. The tech background for
the majority of us is Ruby and Ruby on Rails so you can imagine that we love to
[TDD] the features we create.

We want to bring this practice to our React Native project and we found [Detox]
as a great tool to create end-to-end tests. When using Detox with Expo and
TypeScript, a lot of different configurations and steps are required. The
documentation exists for each tool but is scattered over the internet. We
decided to write this guide to help others that are in the same situation as us.

## Pre-requisites

In this post we will assume that you have setup an [Expo] React Native project
with TypeScript and Jest for the testing library.

A few tools are required to have a fully working testing environment. While they
are not always directly linked with the purpose of this article, we found that
some steps were suffering from a lack of documentation on the internet. We are
going to list some important requirements for the sake of helping you have
everything set up, but please feel free to jump to the next section if you want
to start with Detox immediately.

`Java` is required to run the tests on Android and [applesimutils] is needed to
run the tests on iOS.

### Java

You can install Java using Homebrew:

```bash
brew install java
```

Make sure Java is properly installed and available in your terminal
using `java -version`. You should see a result like:

```bash
openjdk version "21.0.2" 2024-01-16
OpenJDK Runtime Environment Homebrew (build 21.0.2)
OpenJDK 64-Bit Server VM Homebrew (build 21.0.2, mixed mode, sharing)
```

Otherwise, one workaround is to create a symlink to the Java installation:

```bash
sudo ln -sfn /opt/homebrew/opt/openjdk/libexec/openjdk.jdk \
     /Library/Java/JavaVirtualMachines/openjdk.jdk
```

### `applesimutils`

You can install `applesimutils` using Homebrew:

```bash
brew tap wix/brew
brew install applesimutils
```

### Path to `node_modules` binaries

As a final note, you should have access to the `bin` directory
from `node_modules` in your path.

```bash
# .zshrc or .bashrc

export PATH=$PATH:./node_modules/.bin
```

## What is Detox and why should I use it?

[Detox] is a testing library for React Native that allows us to write end-to-end
tests for both iOS and Android applications. Thanks to Detox we can write end to
end tests of our features in a way that simulates the user interactions with
the application.

In the documentation of Detox we can find the following features that make it a
great tool for testing React Native:

> - Cross Platform: Write end-to-end tests in JavaScript for React Native apps (Android & iOS).
> - Debuggable: Modern async-await API allows breakpoints in asynchronous tests to work as expected.
> - Automatically Synchronized: Stops flakiness at the core by monitoring asynchronous operations in your app.
> - Made For CI: Execute your E2E tests on CI platforms like Travis CI, Circle CI or Jenkins without grief.
> - Runs on Devices: Gain confidence to ship by testing your app on a device/simulator just like a real user (not yet supported on iOS).
> - Test Runner Agnostic: Detox provides a set of APIs to use with any test runner without it. It comes with Jest integration out of the box.

## Let's start! Adding Detox to our project

First we need to install Detox in our project as a development dependency. [Yarn]
is our default utility but the commands in this article can be performed with
other tools like NPM, NPX and others.

```bash
yarn add --dev detox
yarn add --dev @config-plugins/detox
```

We then need to add or update the `"plugins"` key in `app.json`, to include the
detox plugin to add support for Android.

```json
{
  "expo": {
    "plugins": ["@config-plugins/detox"]
  }
}
```

## Prebuild

Expo provides a `prebuild`command to generate native code for a React Native
project. This step is necessary for us as it will create the package/bundle
structure and configuration that Detox depends on.

```bash
yarn expo prebuild
```

We will be prompted with a few questions related to the name of the package.

## Configure Detox with Jest

If you don't have Jest declared as a development dependency, you can add it with
the following method.

```bash
yarn add --dev jest
```

Detox provides an `init` command that supports different testing environments,
which is Jest in our case. It generates a new `e2e` folder where the Jest
configuration and tests resides and `.detoxrc.js` file at your project root to
configure Detox.

```bash
yarn detox init -r jest
```

By default, the command will create a starter test that you can keep, change or
delete. We will add our own test later in this article.

`.detoxrc.js` configures the simulators/emulators used during the tests,
and the name of the packages. Feel free to check the `devices` key and ensure
Detox will use the devices you intend to.

You will find the value `YOUR_APP` multiple times in the file. This value needs
to be updated with the name of your project. We named ours `Pokedex`. You might
want to check the name created in the `ios/` folder, generated by
the`expo prebuild` command, if you are ensure about the name of the format for
your application.

```javascript
module.exports = {
  // ...
  devices: {
    simulator: {
      type: "ios.simulator",
      device: {
        type: "iPhone 15",
      },
    },
    emulator: {
      type: "android.emulator",
      device: {
        avdName: "pixel_4",
      },
    },
  },
};
```

## Configuring Jest with TypeScript

While this step is not necessary, we recommend using [TypeScript] in your  
project and in your tests. This will add consistency, confidence and
efficiency to your testing process. Let's first add the dependencies.

```bash
yarn add --dev ts-jest @types/jest
```

We also need to change the supported test file extensions
in `e2e/jest.config.js`, to support JavaScript and TypeScript files:

```javascript
module.exports = {
  // ....
  testMatch: ["<rootDir>/e2e/**/*.test.[jt]s?(x)"],
};
```

## Adding our first test

At this point, all the configuration should be over, but we still need to create
a brand new test and generate the
packages for Detox to run the tests. Let's add a new test in the `e2e/`
directory:

```typescript
// e2e/App.test.ts

import { expect, by, device, element } from "detox";

describe("Home screen", () => {
  beforeAll(async () => {
    await device.launchApp();
  });

  beforeEach(async () => {
    await device.reloadReactNative();
  });

  it("shows a visible button", async () => {
    await expect(element(by.text("Open Pokedex"))).toBeVisible();
  });

  it("shows the surprise after tapping the button", async () => {
    await element(by.text("Open Pokedex")).tap();
    await expect(element(by.text("Gotta Catch ’Em All"))).toBeVisible();
  });
});
```

## Building our debug iOS and Android apps

We are getting close to running our first end-to-end test! But first we need to
build the debug versions of our iOS and Android apps. The Apple platform needs an
extra step to install all the dependencies.

```bash
cd ios
pod install
cd ...
```

We can now build the apps:

```bash
detox build --configuration ios.sim.debug
detox build --configuration android.emu.debug
```

## Running the test

Finally we can run the test! First, make sure the iPhone Simulator and the
Android Emulator are up and running.

Then, each of the following commands will run our end-to-end test on the
appropriate platform.

```bash
detox test --configuration ios.sim.debug
```

```bash
detox test --configuration android.emu.debug
```

Now is the time to celebrate our first big victory: A failing test suite! 🤡

The failing test should look like this:

![Picture of a failing test](https://images.thoughtbot.com/xl46hajs1vp81vq12agffoxauf1l_image.png)

This is actually a very important goal we just reached: Our testing environment
is now configured and working and we are already engaged in our TDD process. Now
let's make this test pass.

## Let's add our business code

Here is one of the simplest implementations we can produce to satisfy the test's
requirements.

```tsx
// App.tsx

import { useState } from "react";
import { Pressable, StyleSheet, Text, View } from "react-native";

export default function App() {
  const [clicked, setClicked] = useState(false);

  return (
    <View style={styles.container}>
      {!clicked && (
        <Pressable style={styles.button} onPress={() => setClicked(true)}>
          <Text style={styles.text}>Open Pokedex</Text>
        </Pressable>
      )}
      {clicked && <Text style={styles.surprise}>Gotta Catch ’Em All</Text>}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
  },
  text: {
    fontSize: 16,
    fontWeight: "bold",
    color: "white",
  },
  surprise: {
    fontSize: 30,
    color: "#ff0000",
  },
  button: {
    paddingVertical: 12,
    paddingHorizontal: 32,
    backgroundColor: "#ff0000",
  },
});
```

Now, if all the configuration went well, running the test commands again should
show you a passing test suite.

![Picture of a passing test](https://images.thoughtbot.com/ih0mg0x1jvbbcw88bn2fp619kch6_image.png)

Congratulations! 🎉

## Adding new scripts to our package.json

To simplify the introduction of end-to-end tests in your testing process, we
suggest to add a simple custom command in `package.json` which runs Detox on both
platforms at the same time.

```json
{
  "test:detox:android": "detox test --configuration android.emu.debug",
  "test:detox:ios": "detox test --configuration ios.sim.debug",
  "test:detox": "yarn test:detox:ios && yarn test:detox:android"
}
```

Now we can run the tests with a single command:

```bash
yarn test:detox
```

## Conclusion

We have seen how to setup Detox in a React Native project with TypeScript and
Jest. We have also seen how to configure Jest with TypeScript and how to build
the debug versions of our app for iOS and Android. We have also written our test
first, and then implemented the code to make the test pass following the TDD
approach.

We hope this guide helps you to setup Detox in your project. We now have a great
tool configured to continue writing end-to-end tests and make sure that any
feature we add to our application is working as expected.

[applesimutils]: https://github.com/wix/AppleSimulatorUtils
[Detox]: https://github.com/wix/Detox
[Expo]: https://docs.expo.dev/
[TDD]: https://thoughtbot.com/playbook/developing/test-driven-development
[TypeScript]: https://www.typescriptlang.org/docs/handbook/
[Yarn]: https://yarnpkg.com/cli
