What to Test

The useful rule is the one Testing Library 221,825 was built around: test the contract, not the construction. A component's contract is what it promises the person looking at the screen and the parent that renders it. Everything else is construction: which hook holds which value, how often the body ran.

The four things a component promises, and how each is checked
Contract Assert with Example
What the user sees a query for text or role the alert appears after a failed save
What the user can do user-event plus a query submit enables once both fields are filled
What the parent gets a mock function onSelect is called with the row id
What the outside world gets a request handler a PATCH is sent with the edited fields

Renaming a state variable or replacing useState with useReducer changes nothing a user can observe, so it must not change a test.

The classic pyramid over-weights unit tests for front-end work, because an isolated React 7,897 component rarely has interesting logic in it. React bugs live in the seams, so the shape that fits is heaviest in the middle: static checking first (TypeScript and Linting Hooks), unit tests for reducers and custom hooks, integration tests for whole features — a form with its validation and submit handler is one test, not seven — and Playwright 26,280 for the few flows that must never break.

Write each test at the highest level that still fails for a single reason: if a broken form can only be diagnosed from a stack trace the test was too high, and if renaming a label breaks nine tests it was too low. Skip third-party code — React Router 139,386 tests its own Link — and styling that carries no meaning: an assertion on class="btn btn-primary" fails on a design refresh while a genuinely broken button passes.