How To Test React App With Jest and React Testing Library?
Jest is a JavaScript testing framework maintained by Facebook, designed with a focus on simplicity and support for large JavaScript applications, especially React. It offers built-in utilities like test runners, mocking, snapshot testing, and code coverage reporting.
React Testing Library (RTL) is a lightweight solution for testing React components. Unlike traditional testing libraries like Enzyme, RTL promotes testing components in a way that closely resembles how users interact with them. Instead of focusing on testing the internal implementation, RTL emphasizes testing the UI behaviour and user interactions.
Key Features:
- Jest: Provides test runners, mocking, snapshot testing, and more.
- RTL: Focuses on how your components are used by simulating real user interactions (e.g., clicks, inputs).
By combining Jest and RTL, you can write powerful, user-centric tests that validate the actual behaviour of your React components.
Steps To Test React Application
Step 1: Create a New React App
Open your terminal and run the following command to create a new React app:
npx create-react-app react-testing-example
Navigate into the project directory:
cd react-testing-example
Step 2: Install React Testing Library Dependencies
npm install @testing-library/react @testing-library/jest-dom --save-dev
Folder Structure
Dependencies
"dependencies": {
"@testing-library/user-event": "^13.5.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
"devDependencies": {
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.1"
}
Step 3: Create and Test Components
1. Create Button.js and Button.test.js Component
// src/components/Button.js
import React from 'react';
function Button({ label, onClick }) {
return <button onClick={onClick}>{label}</button>;
}
export default Button;
// src/components/Button.test.js
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
test('renders button with correct label', () => {
render(<Button label="Click Me" />);
const buttonElement = screen.getByText(/click me/i);
expect(buttonElement).toBeInTheDocument();
});
test('calls onClick handler when button is clicked', () => {
const handleClick = jest.fn(); // Mock function
render(<Button label="Click Me" onClick={handleClick} />);
const buttonElement = screen.getByText(/click me/i);
fireEvent.click(buttonElement);
expect(handleClick).toHaveBeenCalledTimes(1);
});
2. Create FetchButton.js and FetchButton.test.js Component
// src/components/FetchButton.js
import React, { useState } from 'react';
function 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 && <p>{data}</p>}
</div>
);
}
export default FetchButton;
// src/components/FetchButton.test.js
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import FetchButton from './FetchButton';
test('fetches and displays data when button is clicked', async () => {
const mockFetchData = jest.fn().mockResolvedValue('Hello, World!');
render(<FetchButton fetchData={mockFetchData} />);
fireEvent.click(screen.getByText(/fetch data/i));
const dataElement = await screen.findByText(/hello, world!/i);
expect(dataElement).toBeInTheDocument();
expect(mockFetchData).toHaveBeenCalledTimes(1);
});
3. Modify App.js and App.test.js
// src/App.js
import React from 'react';
import Button from './components/Button';
import FetchButton from './components/FetchButton';
import './App.css';
function App() {
// Mock fetchData function for FetchButton
const mockFetchData = async () => {
return "Hello, World!";
};
return (
<div className="App">
<header className="App-header">
<h1>Testing React Components</h1>
{/* Button Component */}
<Button label="Click Me" onClick={() => alert("Button Clicked!")} />
{/* FetchButton Component */}
<FetchButton fetchData={mockFetchData} />
</header>
</div>
);
}
export default App;
// src/App.test.js
import React from "react";
import { render, screen } from "@testing-library/react";
import App from "./App";
test("renders the main heading", () => {
render(<App />);
const headingElement = screen.getByText(/Testing React Components/i);
expect(headingElement).toBeInTheDocument();
});
test('renders the button with label "Click Me"', () => {
render(<App />);
const buttonElement = screen.getByText(/Click Me/i);
expect(buttonElement).toBeInTheDocument();
});
test('renders the fetch button with label "Fetch Data"', () => {
render(<App />);
const fetchButtonElement = screen.getByText(/Fetch Data/i);
expect(fetchButtonElement).toBeInTheDocument();
});
To test the application run the following command.
npm test