Comprehensive Guide to UI Testing in React with JEST
Written on
Chapter 1: Introduction to UI Testing in React
This chapter explores a variety of examples highlighting different testing patterns and typical applications of the testing library within a React project. For earlier installments, refer to part 1, part 2, and part 3.
Section 1.1: Testing Components by Querying Elements
This pattern is beneficial for verifying that a component displays specific text or elements immediately after a straightforward action, such as rendering.
For instance, consider a widget (CardsWidget) that shows a list of cards. If there are no cards in the account state, it will display a message indicating 'no cards attached.' This example demonstrates two methods for confirming that the appropriate message is displayed, relying on the immediate rendering of the message instead of a delayed action or lifecycle event.
Section 1.2: Testing Components with Event Simulation
This pattern is ideal for checking that a change occurs in the component after an action, like a click.
In this example, a generic Tabs component is rendered, with the first tab selected by default. Using fireEvent, a click event is triggered, expecting that the second tab becomes selected. This method can be adapted for various events beyond just clicks and assumes that the component's response is immediate.
Additionally, if you need to verify whether the component triggers an event for its parent or calls a function passed as a prop, you can utilize Jest's mocked functions when rendering.
Chapter 2: Advanced Testing Techniques
The video "UI Testing with React, Mirage, Jest and Testing Library" offers practical insights into effective testing strategies using these tools.
Section 2.1: Mocking API Calls in Tests
This pattern is crucial for components that make API calls using fetch or Redux actions, allowing you to mock these calls with ease, whether simulating data or errors.
For example, the CardsWidget component, which fetches data internally, can have its API call mocked to return a single item. During the assertion phase, you can check that the table displays one row. The syntax for selecting elements based on class is also demonstrated.
This approach effectively replaces any actual fetch calls, ensuring consistent test results, provided that each test resets mocks during cleanup—a standard practice in any testing suite.
The video "React JS - Material UI - Testing UI Layer in Score Counter App with Jest for Beginners" provides a beginner-friendly perspective on testing UI layers using Jest.
Section 2.2: Validating Redux Actions
This pattern proves useful when dispatching actions with Redux, allowing verification that specific actions are triggered following an event.
For instance, the action notificationActions.openNotification is a genuine action from the application, with assertions confirming its invocation when a fetch operation fails.
If you want to use the actual dispatch while also performing checks, consider maintaining a reference to the original dispatch and wrapping it with a mocked function.
Section 2.3: Managing Global Constants and Styles
This pattern assists in modifying global environment variables or exported constants. It also demonstrates how to validate component styles, whether they are declarative or inherited.
Section 2.4: Utilizing Fake Timers in Tests
This technique is beneficial for controlling the resolution of time-based methods, such as setTimeout. The tested component displays a loading screen until the API call completes.
By mocking the API call with a Promise that resolves only after setTimeout concludes (triggered by jest.runAllTimers()), you can confirm that the loading indicator remains visible until the request is finished.
Section 2.5: Testing Redux Reducers and Actions
This section covers the importance of ensuring Redux actions and reducers transition through states correctly, preventing potential mistakes during development.
Section 2.6: Isolated Testing with Enzyme
When working with Redux, most components are connected to a global store. However, there are instances where components are not linked, and you may need to test their internal functionalities.
Enzyme, an extension for Jest, allows for 'shallow' rendering, enabling the testing of components in isolation. A simple example illustrates this approach effectively.