React has become one of the most popular front-end JavaScript frameworks in recent years, thanks to its fast and efficient rendering capabilities and its ability to create reusable components. However, with great power comes great responsibility, and as applications become more complex, the need for robust testing frameworks becomes increasingly important. One such framework that has gained popularity in the React community is React Testing Library (RTL). This library is designed to focus on testing the user behavior of a React application, rather than its implementation details.
React Testing Library is the officially recommended library for testing React applications. It is built based on the DOM testing library and focuses on testing user behavior on web pages, rather than implementation details. There are two main differences between React Testing Library and Enzyme, the previously popular testing library. The first is their testing concepts. Enzyme heavily relies on querying component state and props, while React Testing Library focuses on user-flow-based testing. The second difference is their rendering methods. Enzyme offers both shallow rendering and full rendering, while React Testing Library only offers full rendering. This can result in longer test runtimes, but the use of jest.mock or jest.fn to create test dummies can help reduce the impact.
React Testing Library provides queries such as get*, find*, and query*, which can be combined with options like byRole, byPlaceholderText, or byText to locate elements in a way that is similar to how users interact with them on web pages. The choice of query depends on the test case. Generally, get is used to check for the existence of elements, find is used to check for elements that might not be present immediately, and query is used to check for the absence of elements. The byRole option should be used whenever possible, as outlined in the library’s priority guidelines.
With React Testing Library, testers also have access to the user-event library, which can be used to simulate actions such as clicking, double-clicking, typing, or submitting. This is useful for testing whether typing into a text box results in the correct value being displayed or whether clicking on a button triggers the correct changes. However, these actions can cause the component’s state to update, leading to changes in the UI. Therefore, testers must use asynchronous functions to wait for the changes to take effect. Fortunately, React Testing Library provides functions such as waitFor and waitForElementToBeRemoved to wait for updates to occur before performing assertions. Not using these functions may result in a React warning or a failed test.
When using the waitFor function, it’s important to avoid passing multiple callbacks or empty callbacks, as this can increase the test runtime and make the test fragile. It’s also not recommended to perform user actions or side effects, as this can cause the action to execute multiple times before the test passes or fails.
With the deprecation of Enzyme in React 18, React Testing Library will be the choice for developers moving forward. Combined with Jest, the library offers a wide range of functions for testing, but it’s important to use them effectively. In large applications, structuring test cases is also important to optimize test runtimes.
In conclusion, React Testing Library is an effective and recommended library for testing React applications. By using the library’s queries and user-event library effectively, developers can write tests that simulate user behavior and ensure their applications are functioning as intended.
This article is based on the thesis work done by Mai Tran, and supervised by Anna-Kaisa Saari. The thesis permalink is https://urn.fi/URN:NBN:fi:amk-202304145317