Q22 of 48 · Cypress

What is component testing in Cypress and when would you use it over E2E?

CypressMidcypresscomponent-testingctmid

Short answer

Short answer: Cypress component testing mounts a single component in isolation and tests it like a real browser — clicks, hovers, accessibility — without rendering the full app. Use it for UI components with rich behaviour (forms, complex state) where a unit test wouldn't catch DOM bugs but full E2E is overkill.

Detail

Cypress component testing (introduced in 10.0) mounts a single React/Vue/Angular component into a real browser and runs your tests against it. It sits between unit tests (no DOM) and E2E tests (full app):

  • Unit test (Jest + JSDOM): no real browser, no real CSS, can't test layout or interactivity faithfully.
  • Component test (Cypress CT): real browser, real CSS, real interactivity, but only one component — fast and isolated.
  • E2E (Cypress): full app, all the network and routing, but slow.

When component testing is the right fit:

  • Complex interactive components (date picker, autocomplete, drag-and-drop).
  • Behaviour that depends on real CSS (sticky positioning, focus styles, transitions).
  • Form validation paths that don't need backend.
  • Visual regression of a single component.
  • Component-level accessibility (axe-core works in CT).

When E2E is still required:

  • Routing, navigation, auth flows.
  • Anything that depends on the real backend or real fixtures.
  • User journeys spanning multiple pages.

The configuration adds a component block to cypress.config.ts with a dev server (Vite, Webpack, Next). Tests live in cypress/component/ (or co-located) and are typically named *.cy.tsx. The cy.mount(<Component />) command (provided by the framework integration) puts the component in the test runner.

A common mistake is using component tests for everything UI-shaped. They're not a replacement for E2E — the routing, real API, and journey verification still belong there.

// EXAMPLE

Counter.cy.tsx

import { Counter } from './Counter';

describe('Counter', () => {
  it('increments and decrements', () => {
    cy.mount(<Counter initial={3} />);

    cy.get('[data-test=value]').should('have.text', '3');
    cy.get('[data-test=inc]').click();
    cy.get('[data-test=value]').should('have.text', '4');
    cy.get('[data-test=dec]').click().click();
    cy.get('[data-test=value]').should('have.text', '2');
  });

  it('clamps at zero', () => {
    cy.mount(<Counter initial={0} />);
    cy.get('[data-test=dec]').click();
    cy.get('[data-test=value]').should('have.text', '0');
    cy.get('[data-test=dec]').should('be.disabled');
  });
});

// WHAT INTERVIEWERS LOOK FOR

Knowing CT is real-browser single-component testing, the unit-CT-E2E hierarchy, and that CT doesn't replace E2E.

// COMMON PITFALL

Using component tests for end-to-end flows — they don't have routing, the real API, or the whole-app context that E2E covers.