Unit Testing React Native with Mocha and Enzyme

February 8, 2016

Working in React Native has been an amazing experience. Coming from React, the workflow has been nearly frictionless. There has, however, been one question lingering: How the hell am I going to test this?

shrugs

Specifically, what is the best way to unit test my component logic? Testing JavaScript that compiles to native code using DOM based testing utilities won’t work. I can do my functional testing using Appium or the built-in Xcode UI tests, but I needed a way to unit test my components.

## Mocks to the rescue

It turns out that you can unit test React Native component logic in isolation using traditional JS test libraries by tricking React Native into returning regular React components instead of native ones.

Below is my shim for React Native components and methods that allowed me to render them in my test environment:

## Mocking React Native with Mocha

First I tried mocking all the things with Jest, mostly because that is what was recommended officially. I was able to prove the concept but there were a couple of drawbacks:

  • Jest is unreasonably slow, at least compared to the alternatives
  • We typically use a Karma/Mocha/Chai on web React projects at Formidable, so it’d be nice to continue that convention

After bidding Jest farewell, I had to figure out how this was going to work with Mocha. I couldn’t use a Karma/Webpack setup like I would on the web because React Native uses its own packager, so using Webpack would be a redundancy. This means I had to to write a compiler to a) transpile Babel code and b) resolve the React Native module with a mock version.

Mocha takes a — compiler argument that I used to create a custom module loader. I created one below that will transpile .js files and inject the mocked React Native methods into the react-native requires:

Now, any time a module in a test file requires react-native, it will get the shim instead.

## Putting it all together

Now I had a mock set up and a custom compiler in place, and I want to see it in action. My first order of business was to install the dependencies required to run the tests. To make things simple, I just ran:

```bash npm i --save-dev mocha chai sinon react react-dom react-addons-test-utils enzyme ```

To briefly review the role each tool plays in the testing architecture:

Next I had to set up a mocha.opts file that is used to provide options to Mocha. In a /test directory, I created the file mocha.opts and added the following:

Next I created compile.js and setup.js in our test directory. The compiler code I wrote earlier went in compile.js and I put the following code into setup.js so that I could provide chai.expect globally, mostly for ergonomics:

Next up, I created react-native.js in a new mocks directory under /test at /test/mocks/react-native.js and put the React Native mock code from earlier in there.

The final piece of the puzzle is pointing my test npm script at Mocha with the specified options. I opened package.json and changed test under scripts to:

```bash "test": "mocha --opts test/mocha.opts src/**/__specs__/*.spec.js" ```

In addition to pointing to the defined options, I also set the target to tests that use the `*.spec.js` convention, located in folders named __specs__.

Using this convention, I colocate my tests in the folders that contain the components that I’m testing, avoiding lengthy file paths when requiring our components.

Now it’s time to test!

I enjoy watching those tests run and pass.

## Getting my test on

Say we have a simple React Native component that we want to test to make sure that it renders child nodes in response an items prop:

We want to start by creating a __specs__ directory in src/components/. Inside of that directory, we create our-component.spec.js as our test spec for the above component.

For this test, we will be using shallow rendering, which renders components one level deep and lets us assert against the virtual DOM structure. We will also be using the enzyme library from the fine folks at Airbnb, which is an amazing utility for working with shallow renders.

Let’s start by importing React, enzyme and our component, and creating a describe grouping:

Now that we have our stage set, let’s create some mock prop data, shallow render our component, and use enzyme’s findWhere method to see if everything is in working order:

Now, all that’s left to do is run npm test and let the magic happen. We are unit testing React Native components!

## Wrap Up

I’ve found this approach to be pretty flexible so far, and I am feeling much better about the sturdiness of my React Native code. You may have noticed that in the React Native mock above, I had only mocked out a subset of the functionality. Using this approach may require mocking out additional components and methods depending upon what you are using in your app. I also recommend exploring all the features of enzyme, as it has an elegant API for traversing and querying a ShallowRender objects. Now go write some tests!

Thanks to Ryan Roemer and Alex Lande.

Related Posts

The Myth About Code Comments

February 28, 2024
Where to use them, when to use them, how to structure them, and how much detail should they have? These are the wrong questions: instead we should be asking ourselves, “should I even be writing a comment at all?”

Iterables in JS

July 12, 2022
A perhaps less well-known addition of the ES2015 spec is the addition of the iteration protocols. These protocols allow us JS developers to make use of iterables — a very powerful language feature that you’re likely already using in your day-to-day development, but maybe haven’t given too much thought to!

The Case for Consistent Documentation

April 21, 2021
Words can't begin to express the anxiety I felt leaving my first job last spring. As I put in my notice, a question kept nagging me: how could I wrap up two years in two weeks?