~/
hackweb.dev
Testing React
Quiz
⌘K
...
~/
/tutorials
/react/react-testing/edit
~ Contribute
Suggest a correction or improvement. The author reviews it before it goes live.
Loading...
Comment
0 / 300
Typo
Grammar
Broken link
Clarify
Code
en/tutorials/react/21react-testing
Write
Preview
Diff
# Testing React Test what users see and do, not how components work internally. React Testing Library (RTL) encourages this approach. ## What to Test - Renders correctly with different data - Responds to user interactions (clicks, input) - Shows the right content based on props or state - Handles loading, error, and empty states Don't test implementation details like internal state or hook calls. ## Setup Install the required packages. ```bash npm install -D vitest @testing-library/react @testing-library/jest-dom jsdom ``` Configure Vitest with a DOM environment. ```js // vitest.config.js import { defineConfig } from "vitest/config"; export default defineConfig({ test: { environment: "jsdom", setupFiles: ["./setup.js"], }, }); ``` ```js // setup.js import "@testing-library/jest-dom"; ``` ## Basic Test ```jsx import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Counter from "./Counter"; test("increments count on click", async () => { render(<Counter />); const button = screen.getByRole("button", { name: /count/i }); await userEvent.click(button); expect(button).toHaveTextContent("1"); }); ``` ## Querying Elements Use queries that reflect what users see. ```jsx screen.getByRole("button", { name: "Submit" }); // Accessible role screen.getByText("Welcome"); // Text content screen.getByLabelText("Email"); // Form labels screen.getByPlaceholderText("Search"); // Placeholder screen.queryByText("Not here"); // Returns null if missing ``` Prefer `getByRole` and `getByLabelText` over `getByTestId`. ## Testing Async Behavior ```jsx test("loads user data", async () => { render(<UserProfile userId={1} />); expect(await screen.findByText("John Doe")).toBeInTheDocument(); }); ``` Use `findBy` for elements that appear after an async operation. ## Mocking Mock API calls with `vi.fn()`. ```jsx vi.mock("./api", () => ({ fetchUser: vi.fn(), })); import { fetchUser } from "./api"; test("displays error on failure", async () => { fetchUser.mockRejectedValue(new Error("Network error")); render(<UserProfile userId={1} />); expect(await screen.findByText("Error")).toBeInTheDocument(); }); ``` ## Best Practices - Test user behavior, not implementation - Use accessible queries (`getByRole`, `getByLabelText`) - Use `userEvent` over `fireEvent` for realistic interactions - Mock at the network level, not component internals - Keep tests focused — one behavior per test ## Common Mistakes - Testing internal state or hook return values - Using `getByTestId` as the first choice - Writing tests that depend on rendering order - Not cleaning up between tests (RTL handles this automatically) - Over-mocking — mock only what you need
No changes yet
Reset to original
Submit suggestion
cancel