Testing is a critical aspect of software development, ensuring that our applications behave as expected and remain bug-free throughout their lifecycle. In this comprehensive guide, we will delve into the intricacies of testing React applications using Jest and React Testing Library (RTL). By the end, you'll be equipped with the knowledge to write robust and reliable tests for your React components.
Getting Started:
Before diving into testing, let's set up our project. We'll create a new React app with TypeScript support using the create-react-app command:
npx create-react-app my-react-app --template typescript
Once the project is created, navigate to the package.json file to confirm that Jest and RTL are installed by default.
Testing Setup:
React projects come pre-configured with a testing setup. The App.tsx file is tested by the App.test.tsx file. To execute tests, run:
npm test
Creating Custom Tests:
Let's create custom tests for our components. Within the src folder, establish a components directory. Inside it, create a welcome directory. Then, within the welcome directory, create two files: Welcome.test.tsx and Welcome.tsx.
// Welcome.tsx
import React from 'react';
type WelcomeProps = {
name: string;
};
const Welcome: React.FC<WelcomeProps> = ({ name }) => {
return <h1>Welcome, {name}!</h1>;
};
export default Welcome;
// Welcome.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import Welcome from './Welcome';
test('renders welcome message', () => {
render(<Welcome name="John" />);
const welcomeElement = screen.getByText(/Welcome, John!/i);
expect(welcomeElement).toBeInTheDocument();
});
Running Tests:
Execute the tests by navigating to the welcome directory and running:
npm test
Integrating Coverage:
Add coverage reporting to your project by updating the package.json file with a new script:
"scripts": {
"coverage": "react-scripts test --coverage --watchAll=false"
}
Run the command:
npm run coverage
Different Test Methods:
Explore various ways to test React components. Create a simple form component within a form directory under components. Include this Form component in App.tsx.
// Form.tsx
import React from 'react';
const Form: React.FC = () => {
return (
<form>
<input type="text" placeholder="Enter your name" />
<textarea placeholder="Enter your message"></textarea>
<button type="submit">Submit</button>
</form>
);
};
export default Form;
// Form.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import Form from './Form';
test('renders form elements', () => {
render(<Form />);
const nameInput = screen.getByPlaceholderText('Enter your name');
const messageTextarea = screen.getByPlaceholderText('Enter your message');
const submitButton = screen.getByRole('button', { name: /submit/i });
expect(nameInput).toBeInTheDocument();
expect(messageTextarea).toBeInTheDocument();
expect(submitButton).toBeInTheDocument();
});
Handling Complex Components:
Add additional elements like headings, labels, placeholders, alt text, and data-testid attributes to the Form component.
// Form.tsx
import React from 'react';
const Form: React.FC = () => {
return (
<form>
<h1>Contact Form</h1>
<label htmlFor="nameInput">Name:</label>
<input id="nameInput" type="text" placeholder="Enter your name" />
<textarea placeholder="Enter your message"></textarea>
<img src="/placeholder.png" alt="Placeholder Image" />
<button type="submit" data-testid="submit-button">Submit</button>
</form>
);
};
export default Form;
// Form.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import Form from './Form';
test('renders form elements with correct attributes', () => {
render(<Form />);
const headingElement = screen.getByRole('heading', { name: /contact form/i });
const nameLabel = screen.getByLabelText('Name:');
const nameInput = screen.getByPlaceholderText('Enter your name');
const messageTextarea = screen.getByPlaceholderText('Enter your message');
const imageAltText = screen.getByAltText('Placeholder Image');
const submitButton = screen.getByTestId('submit-button');
expect(headingElement).toBeInTheDocument();
expect(nameLabel).toBeInTheDocument();
expect(nameInput).toBeInTheDocument();
expect(messageTextarea).toBeInTheDocument();
expect(imageAltText).toBeInTheDocument();
expect(submitButton).toBeInTheDocument();
});
Testing Hooks and State:
Create a Languages component with state management using useState and useEffect.
// Languages.tsx
import React, { useState, useEffect } from 'react';
type LanguagesProps = {
languages: string[];
};
const Languages: React.FC<LanguagesProps> = ({ languages }) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
// Effect logic here
}, []);
return (
<div>
<ul>
{languages.map((lang, index) => (
<li key={index}>{lang}</li>
))}
</ul>
{isLoggedIn ? (
<button>Start Course</button>
) : (
<button onClick={() => setIsLoggedIn(true)}>Login</button>
)}
</div>
);
};
export default Languages;
// Languages.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import Languages from './Languages';
test('renders list of languages', () => {
const languages = ['JavaScript', 'TypeScript', 'Python'];
render(<Languages languages={languages} />);
const listElement = screen.getByRole('list');
const listItems = screen.getAllByRole('listitem');
expect(listElement).toBeInTheDocument();
expect(listItems.length).toBe(languages.length);
});
test('displays login button when not logged in', () => {
render(<Languages languages={[]} />);
const loginButton = screen.getByRole('button', { name: /login/i });
const startCourseButton = screen.queryByRole('button', { name: /start course/i });
expect(loginButton).toBeInTheDocument();
expect(startCourseButton).not.toBeInTheDocument();
});
Conclusion:
Testing React applications with Jest and React Testing Library is crucial for ensuring code quality and functionality. By following this guide and experimenting with various testing scenarios, you'll gain proficiency in writing comprehensive tests for your React components, thereby improving the reliability and maintainability of your applications.
For further reading, check out the original article on Medium by Nabendu82: React Testing with Jest and RTL in TypeScript.
Discussion (undefined)