React Testing Strategy
Put logic in plain functions and unit-test them; test hooks and pages as integration tests against a mocked network; assert only on what users can observe.
On this page
The testing strategy I’ve settled on for React apps is short enough to fit on a sticky note: logic in services gets unit tests; hooks and pages get integration tests against a mocked network; every assertion is about observable behaviour.
The layers
| Layer | Test type | Why |
|---|---|---|
| Plain functions — transforms, validation, business rules | Unit | Fast, simple, no React needed |
| Hooks, components, whole pages | Integration with Testing Library + MSW (Mock Service Worker) | Exercises real data fetching, state and rendering together |
| Critical user journeys | End-to-end with Playwright | Proves the deployed thing works |
Most of the confidence comes from the middle row. That’s the “testing trophy” idea from Kent C. Dodds: weight your effort towards integration tests.
Rules I hold to
- Test what the user observes, not implementation details. Query by role and label; assert on text and behaviour, not on state variables or which hook was called.
- Move logic out of components so it’s trivially unit-testable. Don’t write extra code purely so something can be tested in isolation.
- Mock only what you don’t control. Mock the network at the boundary. Never mock in-memory stores like Zustand or Redux — reset them between tests instead.
- Reuse tested components. A shared component that’s already tested doesn’t need re-testing in every feature. (AI assistants often miss this, because they don’t know which components exist.)
- Watch effect dependencies. Depend on
query.data, not the whole query object, which changes identity every render.
Snapshot tests: cheap change detectors
Snapshots are easy to update blindly, so they guard against unnoticed change, not wrong change. Their real value is in code review: the list of changed snapshots tells a reviewer exactly which components a change touched. Keep them small and focused so people actually read the diff.
The process side
A large merge request without tests can’t be merged safely, however good the code looks. More than once I’ve found it cheaper to reject a big untested change and redo it as several small, tested ones. And an honest confession: on big tickets I’m tempted to push before writing tests and docs. Writing them while the understanding is fresh is far cheaper than coming back later.
In practice
This strategy took a team from patchy coverage to high, meaningful coverage on several services without brittle mocks — see A Testing Strategy Teams Actually Adopted. The broader principle of catching problems early and cheaply is Shift Left Testing.
- #testing
- #react
- #testing-library
- #integration-tests
- #msw
↩ Linked from (8)
…ic moved into plain functions with unit tests; hooks and pages got integration tests. This is the strategy in React Testing Strategy. Got a free offline mode. The same handlers ran in the browser, so the app could run lo…
- Bulletproof ReactGrowing
…sts by intent: .test.ts for unit, .spec.ts for integration, stories for visual and interaction tests. More in React Testing Strategy.
- MSW (Mock Service Worker)Evergreen
…he tests: demos and development stopped depending on a shared test environment being up. Pairs naturally with React Testing Strategy and Playwright.
- PlaywrightGrowing
…ment you actually run (SAID: Train for the Production You Actually Run). Where it fits in the bigger picture: React Testing Strategy and A Testing Strategy Teams Actually Adopted.
- Shift Left TestingGrowing
…too: see Removing Secrets from Git History and Preventing XSS in React. The testing layers themselves are in React Testing Strategy, and the feedback-loop view of testing in TDD as a Feedback Loop.
Pair Programming · SLA vs SLO vs SLI · React Testing Strategy · Architecture Decision Records
- Stop Mocking FetchEvergreen
…ough refactors. It was the backbone of A Testing Strategy Teams Actually Adopted and sits at the centre of my React Testing Strategy.
- StorybookGrowing
…e components story-friendly are in Headless Component Libraries, and stories as test fixtures fit neatly into React Testing Strategy.
↪ Links to (5)
Related by topic
- Evergreen
API Modelling
Frontend craft - Growingcase study
Building a Graph Component Library
Frontend craft - Growingcase study
Building a Low-Code BPMN Workflow Platform
Frontend craft - Growingcase study
Chairing a Cross-Team UI Guild
Career