ESC

Type to search the knowledge base.

Testing Pyramid for Frontend

Balance unit, integration, and E2E tests for UI apps — the testing trophy mindset, what each layer owns, and allocation rules of thumb.

beginner3 min read
  • testing
  • testing-pyramid

The classic testing pyramid says: many unit tests, fewer integration tests, fewest E2E. Frontend work often prefers Kent C. Dodds’ testing trophy: more integration-style UI tests because components without children/network lie.

Docs: Testing Trophy, Testing Library guiding principles.

Layers for a SPA/Next app

        /\
       /E2E\         few critical journeys
      /------\
     / Integr.\      pages + MSW + router
    /----------\
   /    Unit    \    pure logic, hooks, utils
  /--------------\
 /  Static checks \  types, lint, a11y lint

Static analysis is free confidence — tsc, ESLint, jsx-a11y.

What each layer owns

Layer Owns Avoid
Unit Parsers, formatters, reducers, price math Reimplementing the DOM
Integration Forms, data fetch UI, routing states Mocking every child
E2E Login, checkout, smoke deploy Entire design-system matrix
Visual CSS regressions on key components Full-site daily pixel noise

Rule of thumb allocation

For many product teams:

  • 60–70% integration UI (RTL + MSW)
  • 20–30% unit pure logic
  • 5–10% E2E
  • Plus Storybook/visual where design systems matter

Adjust: data-heavy libs invert toward unit; consumer marketing sites may lean visual/E2E smoke.

Example mapping a feature

Feature: invite teammate by email

Case Layer
Email validation function Unit
Form submit, error from API, success toast Integration + MSW
Full login → invite → appears in list 1 E2E
Button variants Storybook / unit render

Anti-patterns

  1. Ice cream cone — mostly E2E, almost no unit/integration. Slow, flaky.
  2. Only unit tests with enzyme-style shallow — high coverage, low confidence.
  3. Duplicate the same path at every layer — pick one owner.
  4. No tests on error paths — happy path trophy is still a lie.

CI ordering

typecheck && lint && unit+integration && e2e-smoke

Fail fast on cheap checks. Parallelize E2E shards.

Footguns

  • Measuring success only by coverage %.
  • E2E for every tooltip.
  • Integration tests that mock the component under test.
  • Skipping a11y automated checks entirely.

Interview out-loud answer

“I use a trophy-shaped suite: static checks, lots of UI integration tests with MSW, unit tests for pure logic, and a thin E2E layer for critical journeys. Each bug class should have one primary layer so we don’t triple-maintain.”

When the trophy flips

Component libraries may invert toward unit + visual tests with fewer app-level integration tests. Consumer apps lean integration. Match the shape to the failure modes you actually ship — don’t cargo-cult ratios from blog posts without looking at your bug history.

Extra practice

Write a minimal demo in a scratch file or the playground: one happy path, one failure path, and one boundary input. If you cannot exhibit a bug that the pattern prevents, you do not own the concept yet — re-read the primary docs linked below and tighten the example until the failure is obvious.

Notes from real codebases

Teams that succeed here keep the rules mechanical: lint where possible, CI for the rest, and a short human checklist for what automation cannot see. Document exceptions with an owner name and a removal date so “temporary” escapes do not become permanent architecture.

Further reading

Related guides