Testing React Applications with Jest and React Testing Library

Issam Eddine Bouhoush
3 min readJun 20, 2024

--

Testing is a crucial part of developing reliable and maintainable React applications. Jest and React Testing Library (RTL) are popular tools that help developers ensure their components work as expected. This article will cover the basics of using Jest and RTL to test React applications, including setup, writing tests, and useful examples.

Why Test React Applications?

Testing React applications helps ensure:

  • Correctness: Components and features work as intended.
  • Regression Prevention: New changes don’t break existing functionality.
  • Documentation: Tests can serve as documentation for how components are supposed to work.
  • Refactoring: Safe refactoring of code with confidence.

Setting Up Jest and React Testing Library

To start, you need a React application. If you don’t have one, you can create one using Create React App:

npx create-react-app my-app
cd my-app

Next, install Jest (included by default with Create React App) and React Testing Library:

npm install @testing-library/react @testing-library/jest-dom

Configuration

Create React App configures Jest out of the box, so additional configuration is minimal. Ensure you have the following in your package.json:

"scripts": {
"test": "react-scripts test"
}

Writing Tests: Basic Example

Consider a simple Button component:

// Button.js
import React from 'react';

const Button = ({ onClick, children }) => (
<button onClick={onClick}>
{children}
</button>
);

export default Button;

Test for the Button Component

Create a test file named Button.test.js:

// Button.test.js
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Button from './Button';

test('renders the button with correct text', () => {
const { getByText } = render(<Button>Click Me</Button>);
const buttonElement = getByText(/click me/i);
expect(buttonElement).toBeInTheDocument();
});

test('calls onClick handler when clicked', () => {
const onClick = jest.fn();
const { getByText } = render(<Button onClick={onClick}>Click Me</Button>);
fireEvent.click(getByText(/click me/i));
expect(onClick).toHaveBeenCalledTimes(1);
});

Explanation

  • Rendering: The render method renders the component into a virtual DOM.
  • Querying: Methods like getByText are used to find elements in the rendered output.
  • Assertions: expect and matchers like toBeInTheDocument check if conditions are met.
  • Mock Functions: jest.fn() creates a mock function to track calls.

Testing Asynchronous Code

Consider a FetchButton component that fetches data when clicked:

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

const FetchButton = ({ fetchData }) => {
const [data, setData] = useState(null);

const handleClick = async () => {
const result = await fetchData();
setData(result);
};

return (
<div>
<button onClick={handleClick}>Fetch Data</button>
{data && <div>{data}</div>}
</div>
);
};

export default FetchButton;

Test for FetchButton Component

Create a test file named FetchButton.test.js:

// FetchButton.test.js
import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import FetchButton from './FetchButton';

test('fetches and displays data when button is clicked', async () => {
const fetchData = jest.fn().mockResolvedValue('Hello, World!');
const { getByText, findByText } = render(<FetchButton fetchData={fetchData} />);

fireEvent.click(getByText(/fetch data/i));

expect(fetchData).toHaveBeenCalledTimes(1);
const dataElement = await findByText(/hello, world!/i);
expect(dataElement).toBeInTheDocument();
});

Explanation

  • Mocking: jest.fn().mockResolvedValue mocks an async function to return a resolved promise.
  • Async Testing: waitFor and findByText handle assertions that involve asynchronous code.

Best Practices

  • Write meaningful tests: Focus on the component’s behavior rather than implementation details.
  • Use descriptive test names: Clearly describe what each test is verifying.
  • Keep tests independent: Each test should run independently to avoid side effects.
  • Mock external dependencies: Isolate components by mocking external API calls and dependencies.

Conclusion

Testing React applications with Jest and React Testing Library ensures your components behave as expected and can handle various scenarios. By following the examples and best practices outlined in this article, you can start writing effective tests for your React applications. Happy testing!

--

--