ReactJS - act() Testing Utilities



Testing our components is really important when we are building a web app with React. It is like checking if everything works as expected. To help with this, there is a tool called act() in React. It pretends to be a web browser and makes sure our components talk to each other correctly.

So, act() is like a helper that makes sure your components behave the way they should when you're testing them. It's like a little assistant that helps you get your testing right.

act() is a function that supports us in testing a React component by verifying that it behaves as if it were operating in a real web browser. It is particularly important for components which perform asynchronous tasks such as data extraction, updates, or user interactions.

Syntax

import { act } from 'react-dom/test-utils';

act(() => {
   // The code to interact with React components
});

Parameters

The act() function takes a single input, which is a function containing the code which we are going to test. Any interactions with React components, like rendering, clicks or form submissions should be included in this code.

Return Value

The act() method in React does not return anything.

Examples

Example − State Change App

The provided code is a simple React component called MyComponent and its corresponding test using the @testing-library/react and @testing-library/user-event libraries. The initial state of the component is set to 'Initial State'. The test renders the MyComponent. It simulates a button click using userEvent.click. The component's state is updated to 'New State' when the button is clicked. The test asserts that the text 'New State' is present in the rendered output.

// MyComponent.js
import React, { useState } from 'react';

const MyComponent = () => {
   const [currentState, setCurrentState] = useState('Initial State');   
   const handleButtonClick = () => {
      setCurrentState('New State');
   };   
   return (
      <div>
         <p>{currentState}</p>
         <button onClick={handleButtonClick}>Click me</button>
      </div>
   );
};

export default MyComponent;

MyComponent.test.js

import { render, screen, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MyComponent from './MyComponent';

test('updates state on button click', () => {
   // Render the component
   render(<MyComponent />);
   
   // Use act() to interact with the component
   act(() => {
      userEvent.click(screen.getByRole('button'));
   });
   
   // Assert the expected state
   expect(screen.getByText('New State')).toBeInTheDocument();
});

Output

click initial state

Example − Async Component

In this app we will have a React component called MyAsyncComponent, which simulates asynchronous data fetching using the fetchData function. Also, there is a test code for this component using the @testing-library/react library with the act function to handle asynchronous operations. So the code for the app and its respective test file is given below −

// MyAsyncComponent.js
import React, { useState, useEffect } from 'react';

const fetchData = () => {
   return new Promise((resolve) => {
      // asynchronous data fetching
      setTimeout(() => {
         resolve('Fetched Data');
      }, 1000);
   });
};
const MyAsyncComponent = () => {
   const [data, setData] = useState(null);   
   useEffect(() => {
   const fetchDataAsync = async () => {
      const result = await fetchData();
      setData(result);
   };
   
   fetchDataAsync();
   }, []);
   
   return (
      <div>
         <p>{data ? data : 'Loading...'}</p>
      </div>
   );
};

export default MyAsyncComponent;

MyAsyncComponent.test.js

import { render, screen, act } from '@testing-library/react';
import MyAsyncComponent from './MyAsyncComponent';

   test('renders data after fetching', async () => {
   // Render the component
   render(<MyAsyncComponent />);
   
   // Use act() to wait for the asynchronous data fetching
   await act(async () => {
   });
   
   expect(screen.getByText('Fetched Data')).toBeInTheDocument();
});

Output

loading

Example − Counter App

Let's see an example. We have a Counter component with a button. So when we press the button it will increment a counter and update a title. So for creating this app we will follow below steps −

Setting up the test environment

  • Create a container element before each test.

  • Remove the container after each test.

Component testing

  • We will use act() function to wrap the component's rendering. This makes sure React operates correctly in a browser.

  • The act() function can be used to provide user interactions (like clicking a button).

// Code for Counter component
// Set up a container for rendering the component
let container;

beforeEach(() => {
   container = document.createElement('div');
   document.body.appendChild(container);
});

afterEach(() => {
   document.body.removeChild(container);
   container = null;
});

it('can render and update a counter', () => {
   // Test first render and componentDidMount
   act(() => {
      ReactDOM.createRoot(container).render(<Counter />);
   });
   // A click event
   act(() => {
      button.dispatchEvent(new MouseEvent('click', {bubbles: true}));
   });
});

Summary

act() is a tool that allows us to test React components, especially when we are dealing with asynchronous operations or DOM interactions. We can make sure that our tests correctly follow how our components behave in a real web browser by using act(). Testing is an important part of creating reliable and bug-free programs, and act() is a useful function in this process.

reactjs_reference_api.htm
Advertisements