Find out what’s new in the React Native Testing Library 2.0

We are happy to announce the release of version 2.0 of React Native Testing Library. For the last couple of weeks, we’ve been working really hard to bring you useful new features and to polish our APIs and their documentation, as well as improve compatibility with other Testing Library implementations.

We also use this release as a chance to remove a small number of deprecated APIs, in accordance with semver, to encourage more robust test writing.

If you’re looking for the migration guide only, it’s right at the bottom of this post.

What is React Native Testing Library?

The React Native Testing Library, or RNTL in short, is a lightweight solution for testing your React Native components. It provides helpful utility functions on top of official react-test-renderer letting you always be up to date with the latest React features. Its opinionated API aims to prevent developers from testing implementation details of their React components while focusing on user experience and accessibility.

So, what’s new in the new version of the React Native Testing Library?

We bid a farewell to Node 8 and shallow rendering

Node 8 is long past its support date, which ended with the year 2019. We moved to Node 10 like the rest of the ecosystem. You should too!

Also, we decided to remove shallow rendering because this way of rendering React components is usually not a good idea, as it frequently fails to detect application errors.

However, if you find it useful or need to support legacy tests we’ve got you covered. The shallow helper is quite simple to implement by yourself. Feel free to use the code snippet provided in our migration guide.

Fixing getByTestId query behavior

Previous version of getByTestId (and queryByTestId) had a bug that allowed the queries to find custom components that would not pass testID to the native (host) components. This resulted in finding more testIDs than there was in the native hierarchy. Curiously, this bug was absent in their plural implementation getAllByTestId (and queryAllByTestId).

As some users might have relied on this invalid behavior, the bug has intentionally not been fixed in version 1.x.

Automatic cleanup after each test

Following the path of React Testing Library we are now automatically calling cleanup after each test if your testing framework supports afterEach hook (which jest, mocha, and jasmine do). Therefore, you should be able to remove any afterEach(cleanup) calls in your test files.

This generally should not break any of your tests, unless so of them are not isolated. Which basically means calling render outside for test block.

Generally, you should keep your tests isolated, but if you can’t or don’t want to do this right away you can easily prevent this behavior in one for three ways:

  • by importing react-native-testing-library/pure instead of react-native-testing-library
  • by importing react-native-testing-library/dont-cleanup-after-each before your react-native-testing-library import (or in setupFiles in your jest configuration file)
  • be setting the RNTL_SKIP_AUTO_CLEANUP env variable.

waitFor and findBy automatically wrapped in act

Your waitFor and hence findBy calls are now automatically wrapped in act utility. This helps you avoid dreaded act warning in tests involving asynchronous state mutation, e.g., when simulating fetch data from API or using animations.

This feature is active only if you use React Native >= 0.61 or React >= 16.9.0, because asynchronous act was added then.

Other breaking changes

Marking the byType and byProps queries as unsafe

These queries families have been prefixed with UNSAFE_ to indicate that you generally should avoid using them. They often result in fragile and less reliable tests. They also make it easy to write tests that hide unexpected behavior that affects users, if not backed by sufficient code coverage.

Even though marked unsafe, we’re still keeping these APIs, because there are users who invested a lot of time in writing their tests and we, as library maintainers, would not be able to provide them with a simple migration path. These queries may also be helpful if you prefer to unit-test your components, instead of integration-test them.

Removal of byName queries and debug export

These queries have been removed after being long deprecated. Using them tied your component tests really closely to their implementation details and e.g. could easily break your tests when upgrading React Native versions, making tests fragile and not really reliable.

debug export was a leftover from the initial implementation of RNTL, which was later superseded by the debug function returned from render.

New APIs

Even though you don’t need to upgrade to v2 to benefit these APIs, we still wanted to mention them here because why not.

findBy queries

These queries are the simple, yet useful combination of waitFor and getBy queries. Available queries and their basic arguments are the same as respective getBy queries. However, they return Promise instead of the actual element. Optionally they accept custom values for timeout and query interval. These queries are useful for situations you have to wait for a particular UI element to appear or to change its state.

Example code:

within operator

within operator enables you to perform queries scoped to given element and its children. Its main use cases are querying elements for a particular list of repeating items, e.g. inside a FlatList or querying elements inside given screen components for tests involving screen transitions. 

This operator provides the same query functions as render functions, so getBy, queryBy, findBy as well as getAllBy, queryAllBy and findAllBy. It does not, however,  provide other methods returned by render such as update/rerender, debug, or toJSON.

Improved documentation

We migrated our documentation to use Docusaurus v2, which comes with a refreshed design, improved accessibility and themes support (yes, there is a dark mode). We used new doc engine capabilities to sprinkle improvements in various places, like adding useful hints, cautions and warnings about using different parts of the API.

We’re also heavy at work to provide you with high-quality guides and examples of testing React Navigation, Redux, or JS side of native modules.

Community compatibility

We want RNTL to be as compatible with the Testing Library community as possible. That’s why we’ve put effort into making sure you can use some community projects known from other platforms.

@testing-library/jest-native matchers

You can improve some of your test assertions by using React Native-specific matchers from @testing-library/jest-native matchers project.

When using React Native Testing Library with Jest by default you only have access to generic Jest matchers that contain various general-purpose checks like toBeTruthy, toHaveLength or toHaveBeenCalled

By adding @testing-library/jest-native package you gain access to some React Native-specific matchers like toBeEnabled/toBeDisabled, toHaveStyle, toHaveProp, toHaveTextContent, toBeEmpty and toContainElement.

eslint-plugin-testing-library

We’ve made sure RNTL is compatible with eslint-plugin-testing-library, so you can freely use it in your project and benefit the collective testing wisdom of the Testing Library community. The only rule that’s not compatible is prefer-screen-queries since we’re not providing the screen object.

Migration guide

To ease the transition to the new version, we prepared a migration guide covering all of the breaking changes.

Full Changelog can be found here.

Summary

To wrap everything up, we are happy that you find our library helpful. Your recognition is the best price we can get for our effort. We hope that the aforementioned upgrades will make your daily work easier than ever before.

Also, special thanks to Maciej Jastrzębski and Kenneth Kwakye-Gyamfi for their help with making this release happen.