← Back to blog Post

Creating React Native apps with Enzyme

Hosted here as an English translation. Originally published on Medium.

As a developer, one of the things I value most about JavaScript is being able to build very different kinds of solutions without losing the language itself or the way I like to work. When I moved from web development to mobile apps with React Native, that continuity was one of the biggest attractions. I could keep applying the same mindset, including TDD.

Before getting into the solution, it helps to review a bit of context.

React Native

React Native is a library created by Facebook for building native Android and iOS applications with JavaScript. It is based on React, but instead of rendering HTML in a browser it renders interfaces through native device components.

That means we can reuse much of the knowledge and workflow we already have from React on the web while getting something much closer to a native app than a hybrid application running inside a WebView.

Enzyme

Testing is a non-negotiable part of software development. For a long time, one of the most widely used libraries for testing React components was Enzyme, created by Airbnb. It can also be used with React Native to validate rendering, component mounting and event handling.

The important difference is that Enzyme was designed with the web in mind. Because of that, interactions with native components are not exactly the same, and some extra setup is required. A few methods that feel normal in React web testing are simply not available here.

Even so, it is still possible to test a large part of the application behaviour in a practical way.

Creating the project

At the time of the original article, one of the fastest ways to start was create-react-native-app:

npm install -g create-react-native-app
create-react-native-app my-test-app-enzyme

After creating the app, we can launch it with:

npm start

One of the easiest ways to run it on a real device is Expo, which lets us open the app by scanning a QR code.

Installing Enzyme

Once the base application is running, we can install the dependencies needed for Enzyme:

npm install --save-dev enzyme enzyme-to-json enzyme-adapter-react-16 react-dom

create-react-native-app already gives us Jest, so the testing baseline is there. What we need now is to configure Enzyme so it can understand the output produced by React Native instead of a regular HTML DOM.

Creating our test

The project includes a default App.test.js built with react-test-renderer. That is a good starting point for a simple check, but the goal here is to go a step further and reproduce that kind of test using Enzyme.

Before changing anything, it is worth verifying that the default test works:

npm run test

If we want continuous feedback while developing:

npm run test -- --watch

From there we can apply TDD in a very direct way. For example, we can write a test that expects a Button to exist in the view, watch it fail, and only then implement the button until the test goes from red to green.

That already proves an important point: Enzyme can still help us validate structure and component presence in React Native.

Simulating press events

The interesting part is not only checking whether elements are rendered, but also validating how the interface reacts to user actions.

This is where a key difference from web usage appears: simulate() is not available in the same way for native components. A practical approach for a button press is to locate the Button, access its node, and call the callback exposed through props, such as onPress().

By itself, that only proves the test does not crash. To make the test meaningful, we need to observe a real effect.

One simple way to do that is to allow the component to receive, through props, the function that should run when the button is pressed. Then the test can inject a mock and verify that it was called. The example in the article is intentionally small, but the idea is the same one we can later use for REST clients, Redux actions or any other external logic.

Simulating change events

Text input changes follow the same principle. First we add the element to the interface and then we verify how it behaves.

Instead of calling onPress(), we call onChangeText() with a fake input value. Once again, the component needs to expose or delegate that behaviour in a way the test can observe.

The main lesson is that when direct simulation helpers are missing or awkward, injecting callbacks and asserting observable effects remains a solid testing strategy.

Conclusion

Testing a React Native application with Enzyme requires accepting a few differences compared with React on the web, but it is still a very useful way to validate behaviour automatically.

The benefit is not only more coverage. In mobile development, compiling, deploying and manually checking an app on a device is usually slower than in web development. A solid test suite shortens that cycle and gives us much more confidence when changing the code.

In short:

  • We can reuse much of the testing mindset we already know from React.
  • Some events are not simulated the same way as on the web.
  • Injecting callbacks through props makes behaviour easier to verify.
  • Good automated coverage reduces the cost of manual validation.

If you are starting to test a React Native app, Enzyme can be a natural bridge from the traditional React ecosystem.

  • react-native
  • enzyme
  • testing
  • tdd