Integrated Testing with React Native, Part 2: Minimize Coupling

In the last post, I promised to tell you how breadth-first object traversal came into play testing React Native apps. Today is the day!

As it turns out, unit testing React Native code is really no different than testing any other JavaScript, especially with stateless, functional components. However, unit testing can only get you so far. Inevitably you need to confirm code works in integration. Unfortunately the options we have tend to feel a little heavy-handed with snapspot testing and computer-driven UI tests. Snapshot tests are coupled very tightly the entire structure of a rendered component and thus tend to be brittle. UI tests are difficult to set up and run terribly slow.

Another option is using a tool like Enzyme to make assertions about the VDOM output by the renderer. Unfortunately React Native only works with shallow rendering. It would be great have something resembling full-dom rendering for React Native!

What Is In a DOM?

Enzyme, Jest, and the like use React’s test renderer to produce an in-memory, rendered DOM as a deeplying nested, often recursive JavaScript object tree. One such tree might resemble this:

These tests are written to be very loosely coupled to the structure of the component. All that matters is the tested content is seen in the component. This is done by looking for all Text nodes and testing that the expected content is contained within them.

The Component

To make these tests pass, you can write a relatively simple component.

This component is simple if not naive. However, from the tests’ perspective it doesn’t really matter how it’s built so long as the little bits of text are seen. For example, this same component could be completely re-written in a functional style:

Not only does it look better, but the tests still pass without any changes! That is because the tests are written with a hyper-focus on content. The tests are sufficiently decoupled from the component structure so tests only fail when behavior is broken!

Wrapping Up

This style of testing is a powerful mechanism for validating content without writing tests that are frustratingly brittle (read: prone to false failures). However, it probably does not replace the role of snapshots which ensure that a stable component does not suffer regressions once it’s in place.

What testing strategies have you developed for React and React Native?