Unit Testing React Native with Mocha and Enzyme


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:

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:

"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.


We Are Formidable

Formidable is a Seattle-based consultancy and open source shop, with an emphasis on Node.js and React.js. We deploy a mixture of consulting, staff augmentation, and training to level up teams and solve engineering problems. Whether it’s transitioning walmart.com to React, moving speedtest.net off Flash, or helping a startup build and scale an MVP, we’re ready to help teams of any size.

Interested in hiring or working for us? Get in touch or view our careers page.