React Native Testing Library 2.0 - What’s New?
In short
React Native Testing Library has released version 2.0, featuring enhancements like automatic cleanup, improved compatibility, and removal of deprecated APIs. Key changes include bidding farewell to Node 8 and shallow rendering, fixing getByTestId query behavior, and introducing new APIs like findBy queries and within operator. The release also emphasizes community compatibility and improved documentation, making it a significant upgrade for React Native developers focused on robust testing practices.
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 <rte-code>react-test-renderer<rte-code> 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 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 <rte-code>shallow<rte-code> 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 <rte-code>shallow<rte-code> 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 <rte-code>getByTestId<rte-code> (and <rte-code>queryByTestId<rte-code>) had a bug that allowed the queries to find custom components that would not pass <rte-code>testID<rte-code> to the native (host) components. This resulted in finding more <rte-code>testID<rte-code>s than there was in the native hierarchy. Curiously, this bug was absent in their plural implementation <rte-code>getAllByTestId<rte-code> (and <rte-code>queryAllByTestId<rte-code>).
As some users might have relied on this invalid behavior, the bug has intentionally not been fixed in version <rte-code>1.x<rte-code>.
Automatic cleanup after each test
Following the path of React Testing Library we are now automatically calling <rte-code>cleanup<rte-code> after each test if your testing framework supports <rte-code>afterEach<rte-code> hook (which jest, mocha, and jasmine do). Therefore, you should be able to remove any <rte-code>afterEach(cleanup)<rte-code> 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 <rte-code>render<rte-code> outside for <rte-code>test<rte-code> 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 <rte-code>react-native-testing-library/pure<rte-code> instead of <rte-code>react-native-testing-library<rte-code>
- by importing <rte-code>react-native-testing-library/dont-cleanup-after-each<rte-code> before your <rte-code>react-native-testing-library<rte-code> import (or in <rte-code>setupFiles<rte-code> in your jest configuration file)
- be setting the <rte-code>RNTL_SKIP_AUTO_CLEANUP<rte-code> env variable.
waitFor and findBy automatically wrapped in act
Your <rte-code>waitFor<rte-code> and hence <rte-code>findBy<rte-code> 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 <rte-code>act<rte-code> was added then.
Other breaking changes
Marking the byType and byProps queries as unsafe
These queries families have been prefixed with <rte-code>UNSAFE_<rte-code> 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.
<rte-code>debug<rte-code> export was a leftover from the initial implementation of RNTL, which was later superseded by the <rte-code>debug<rte-code> function returned from <rte-code>render<rte-code>.
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 <rte-code>waitFor<rte-code> and <rte-code>getBy<rte-code> queries. Available queries and their basic arguments are the same as respective <rte-code>getBy<rte-code> queries. However, they return <rte-code>Promise<rte-code> instead of the actual element. Optionally they accept custom values for <rte-code>timeout<rte-code> and query <rte-code>interval<rte-code>. 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
<rte-code>within<rte-code> 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 <rte-code>FlatList<rte-code> or querying elements inside given screen components for tests involving screen transitions.
This operator provides the same query functions as <rte-code>render<rte-code> functions, so <rte-code>getBy<rte-code>, <rte-code>queryBy<rte-code>, <rte-code>findBy<rte-code> as well as <rte-code>getAllBy<rte-code>, <rte-code>queryAllBy<rte-code> and <rte-code>findAllBy<rte-code>. It does not, however, provide other methods returned by <rte-code>render<rte-code> such as <rte-code>update<rte-code>/<rte-code>rerender<rte-code>, <rte-code>debug<rte-code>, or <rte-code>toJSON<rte-code>.
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 <rte-code>toBeTruthy<rte-code>, <rte-code>toHaveLength<rte-code> or <rte-code>toHaveBeenCalled<rte-code>.
By adding `@testing-library/jest-native` package you gain access to some React Native-specific matchers like <rte-code>toBeEnabled<rte-code>/<rte-code>toBeDisabled<rte-code>, <rte-code>toHaveStyle<rte-code>, <rte-code>toHaveProp<rte-code>, <rte-code>toHaveTextContent<rte-code>, <rte-code>toBeEmpty<rte-code> and <rte-code>toContainElement<rte-code>.
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 <rte-code>prefer-screen-queries<rte-code> since we’re not providing the <rte-code>screen<rte-code> object.
Migration guide
To ease the transition to the new version, we prepared a migration guide covering all of the breaking changes, and here's a full changelog for React Native Testing Library 2.0.
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.