Testing React Applications

Good React tests give you confidence to change code without fear. The trick is testing what users experience — what renders, what happens on click — rather than how the component is built internally. Tests coupled to implementation break on every refactor and protect nothing.

React Testing Library encodes this philosophy: query the DOM the way a user (or screen reader) would, interact, and assert on visible results.

TL;DR

Quick Example

Render, interact, assert on what the user sees:

Core Concepts

The testing pyramid

What to test (and not)

Patterns

Async UI

Mock the network with MSW

MSW intercepts requests at the network layer, so your component and data-fetching code run for real.

Comparison: Jest vs Vitest

Common Mistakes

Testing implementation details

Querying by test id when a role works

FAQ

Jest or Vitest?

Vitest for Vite-based projects — it's faster and shares Vite's config, with a Jest-compatible API. Jest remains the standard for older or Create-React-App-era setups. Migrating is usually straightforward because the APIs align.

What should I actually test?

User-visible behavior: what renders for given props, what happens on interaction, and the loading/empty/error states. Skip internal state shape, exact CSS, and third-party internals.

How do I test components that fetch data?

Mock at the network layer with MSW so your real fetching code runs against fake responses. Avoid mocking your own modules — it couples tests to implementation and tests less.

Why query by role instead of test IDs?

Querying by accessible role/label tests the app the way users and assistive tech experience it, and it doubles as a basic accessibility check. Reserve test IDs for when there's genuinely no accessible query.

Related Topics

References