Writing Test Cases
Jest is a popular JavaScript testing framework, and React Testing Library is a set of helpers that allow you to test React components in a way that resembles how users interact with your app.
a. Install the necessary packages:
npm install --save-dev jest @testing-library/react @testing-library/jest-dom @types/jest
b. Configure Jest in your project:
Create a jest.config.js
file in your project root:
module.exports = { testEnvironment: "jsdom", setupFilesAfterEnv: ["@testing-library/jest-dom/extend-expect"], moduleNameMapper: { "\\.(css|less|scss|sass)$": "identity-obj-proxy", },};
This configuration sets up the JSDOM environment (which simulates a browser environment), includes React Testing Library’s custom matchers, and handles CSS imports in your tests.
c. Add test scripts to your package.json
:
"scripts": { "test": "jest", "test:watch": "jest --watch"}
- Write basic unit tests for your components:
Let’s write tests for a simple Button
component and a Counter
component.
a. Button Component:
import React from "react";
function Button({ onClick, children }) { return <button onClick={onClick}>{children}</button>;}
export default Button;
Test file (Button.test.js
):
import React from "react";import { render, fireEvent } from "@testing-library/react";import Button from "./Button";
describe("Button component", () => { test("renders button with correct text", () => { const { getByText } = render(<Button>Click me</Button>); expect(getByText("Click me")).toBeInTheDocument(); });
test("calls onClick prop when clicked", () => { const handleClick = jest.fn(); const { getByText } = render( <Button onClick={handleClick}>Click me</Button>, ); fireEvent.click(getByText("Click me")); expect(handleClick).toHaveBeenCalledTimes(1); });});
This test suite checks if the button renders with the correct text and if it calls the onClick
function when clicked.
b. Counter Component:
import React, { useState } from "react";import Button from "./Button";
function Counter() { const [count, setCount] = useState(0);
const increment = () => setCount(count + 1); const decrement = () => setCount(count - 1);
return ( <div> <h2>Count: {count}</h2> <Button onClick={increment}>Increment</Button> <Button onClick={decrement}>Decrement</Button> </div> );}
export default Counter;
Test file (Counter.test.js
):
import React from "react";import { render, fireEvent } from "@testing-library/react";import Counter from "./Counter";
describe("Counter component", () => { test("renders initial count of 0", () => { const { getByText } = render(<Counter />); expect(getByText("Count: 0")).toBeInTheDocument(); });
test("increments count when increment button is clicked", () => { const { getByText } = render(<Counter />); fireEvent.click(getByText("Increment")); expect(getByText("Count: 1")).toBeInTheDocument(); });
test("decrements count when decrement button is clicked", () => { const { getByText } = render(<Counter />); fireEvent.click(getByText("Decrement")); expect(getByText("Count: -1")).toBeInTheDocument(); });});
This test suite checks the initial render of the counter, and tests both increment and decrement functionality.
Key concepts in these tests:
render
: This function from React Testing Library renders the component into a virtual DOM.getByText
: A query function that finds elements by their text content.fireEvent
: Simulates DOM events like clicks.expect
: Jest’s assertion function, used with various matchers liketoBeInTheDocument()
ortoHaveBeenCalledTimes()
.
To run your tests:
npm test
This will run Jest in watch mode, re-running tests when files change.
These examples demonstrate basic unit testing for React components. They cover rendering, user interactions, and state changes. As you build more complex components, you might need to test things like:
- Asynchronous operations (using
waitFor
orfindBy
queries) - Mocking API calls
- Testing error states
- Checking accessibility
Remember, the goal is to test component behavior from a user’s perspective, focusing on what the component does rather than how it’s implemented.