TIL -“act” and “waitFor” react-testing-library

act

The act function is a utility provided by the React Testing Library that wraps around your code, ensuring that all updates related to state changes, effects, and other asynchronous actions are flushed before proceeding. This is crucial when testing components with asynchronous behavior, as it helps maintain a consistent and predictable test environment.

A simple example of using act with Jest is shown below:

import React, { useState } from 'react';
import { render, fireEvent, act } from '@testing-library/react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);

test('increments the counter when the button is clicked', async () => {
const { getByText } = render(<Counter />);
const incrementButton = getByText('Increment');
const counterDisplay = getByText('0');
await act(async () => {
fireEvent.click(incrementButton);
});
expect(counterDisplay.textContent).toBe('1');
});

In this example, we use the act function to wrap the fireEvent.click call, ensuring that the state update is completed before we check the updated value of the counter.

waitFor

The waitFor function is another utility provided by the React Testing Library that helps deal with asynchronous behavior in your components. It is used when you need to wait for an element to appear or change, or when you expect some action to occur after a certain period of time.

waitFor returns a Promise that resolves when the specified condition is met. It retries the condition every 50ms (by default) until it passes or times out after 1000ms (by default).

Here’s a simple example using waitFor with Jest:

import React, { useEffect, useState } from 'react';
import { render, waitFor } from '@testing-library/react';

function AsyncMessage() {
const [message, setMessage] = useState('');
useEffect(() => {
const timer = setTimeout(() => {
setMessage('Hello, World!');
}, 500);
return () => clearTimeout(timer);
}, []);
return <p>{message}</p>;
}

test('displays the message after a delay', async () => {
const { getByText } = render(<AsyncMessage />);
await waitFor(() => {
expect(getByText('Hello, World!')).toBeInTheDocument();
});
});

In this example, the AsyncMessage component sets a message after a 500ms delay. We use waitFor to wait for the message to appear before checking that it is present in the document.