← Back to React Testing Library Mastery
Basic18 min read

React Testing Library Basics

Learn RTL philosophy, setup, rendering, and writing your first component test.

Testing Philosophy

React Testing Library (RTL) guides you to test components the way users interact with them—by visible text, labels, and roles—not implementation details like state variable names or component class instances.

Tests that mirror user behavior survive refactors. When a test breaks because you renamed an internal hook but UI unchanged, that test was coupled to implementation.

  • Query what users see and do, not internal component API
  • Avoid testing library internals or child component props unless integration requires
  • Confidence comes from behavior assertions, not snapshot-only coverage

Installation and Setup

Install @testing-library/react, @testing-library/jest-dom, and user-event. Configure jest-dom matchers in setupFilesAfterEnv. Use @testing-library/react with Vitest by matching test environment to jsdom.

Import render and screen from @testing-library/react in every component test file.

npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event

// test/setup.ts
import "@testing-library/jest-dom";

First Component Test

render mounts component into jsdom document. screen queries document globally. Assert with expect and jest-dom matchers like toBeInTheDocument and toHaveTextContent.

Start with simple presentational component before forms and async data fetching.

import { render, screen } from "@testing-library/react";
import { Greeting } from "./Greeting";

test("greets by name", () => {
  render(<Greeting name="Ada" />);
  expect(screen.getByText("Hello, Ada")).toBeInTheDocument();
});

Rendering Components

render returns utilities: rerender for prop updates, unmount for cleanup, container rarely needed. Wrap with providers via wrapper option or custom render helper.

Strict Mode double-invoking effects in React 18 dev may affect test counts—use waitFor for async assertions.

  • Default container is document.body appended div
  • Use baseElement option if portaling outside default
  • cleanup automatic after each test in RTL v13+ with Jest
function renderWithTheme(ui: React.ReactElement) {
  return render(ui, { wrapper: ThemeProvider });
}

Relationship to Jest and Vitest

RTL is renderer and query library; Jest or Vitest is test runner. Same RTL API across runners—only config differs.

Pair with MSW for network mocking and jest-dom for DOM assertions in both ecosystems.

  • Import test from vitest when migrating runner, keep RTL imports same
  • Avoid Enzyme shallow render—deprecated pattern incompatible with modern React
  • Official docs: testing-library.com/docs/react-testing-library/intro

Get In Touch


Ready to discuss your next project? Drop me a message.