How to Test React Components with Cypress: The Complete Guide

Cypress can test React components directly using the @cypress/react adapter, which mounts components in a real browser via React 18's createRoot API and exposes them to standard Cypress commands like cy.get() and cy.click().

The cypress-io/cypress repository provides first-class support for React component testing through its dedicated Component Testing feature. By leveraging the @cypress/react package bundled with the main Cypress CLI, you can import the mount function to render individual React components in isolation and interact with them using Cypress's full browser automation capabilities.

How Cypress Mounts React Components

Cypress tests React components by creating a specialized test harness that bridges React's rendering layer with the Cypress command chain. This architecture is implemented in the npm/react package and follows a precise lifecycle:

  1. Provides a DOM container – The @cypress/mount-utils utility supplies a hidden <div> element in the Cypress test runner page via getContainerEl.

  2. Creates a React root – Using React 18's ReactDOM.createRoot (as seen in npm/react/src/mount.ts lines 13‑18), Cypress maintains a single root instance for the component lifecycle.

  3. Renders the JSX – The supplied JSX is passed to ReactDOM.Root.render (see mount.ts lines 55‑60).

  4. Exposes Cypress commands – The mount call returns a Cypress.Chainable, allowing you to chain standard commands against the mounted component.

  5. Handles cleanup – A cleanup helper unmounts the previous component before each new mount call (see mount.ts lines 15‑25), ensuring isolated test state between assertions.

The Mount API Implementation

The core implementation lives in npm/react/src/mount.ts. This file exports the mount function that integrates React 18's concurrent rendering features with Cypress's testing infrastructure.

When you call mount(), the adapter checks for existing React roots and creates a new one if necessary:

// From npm/react/src/mount.ts (lines 13-18)
import { getContainerEl } from '@cypress/mount-utils'

const container = getContainerEl()
const root = ReactDOM.createRoot(container)

The rendering process then delegates to the React root:

// From npm/react/src/mount.ts (lines 55-60)
root.render(
  <StrictMode>
    {component}
  </StrictMode>
)

Between test runs, the cleanup mechanism ensures no state leaks:

// From npm/react/src/mount.ts (lines 15-25)
const cleanup = () => {
  if (root) {
    root.unmount()
  }
}

Setting Up Component Testing

According to npm/react/package.json, Cypress component testing requires no separate installation of the React adapter for typical use cases. The package declares React as a peer dependency and provides convenience scripts in your package.json:

{
  "scripts": {
    "cy:open": "cypress open --component",
    "cy:run": "cypress run --component"
  }
}

These scripts launch Cypress in component-testing mode, which configures the test runner to use the @cypress/react adapter automatically.

Writing Your First React Component Test

Create a test file with the .cy.jsx or .cy.tsx extension and import the mount function from @cypress/react:

// Counter.cy.jsx
import { mount } from '@cypress/react'
import { Counter } from './Counter'

it('increments the counter when clicked', () => {
  mount(<Counter />)
  
  cy.get('[data-cy=increment]').click()
  cy.get('[data-cy=counter]').should('have.text', '1')
})

This test mounts the Counter component in a real browser, then uses standard Cypress commands to interact with it and assert on the rendered output.

Advanced Mount Options

Custom Wrapper Components

You can wrap your component with providers or context using the wrapper option:

import { mount } from '@cypress/react'
import { ThemeProvider } from './ThemeProvider'

it('renders with theme context', () => {
  const wrapper = ({ children }) => (
    <ThemeProvider>{children}</ThemeProvider>
  )

  mount(<MyComponent />, { wrapper })
  cy.get('[data-theme]').should('exist')
})

Forcing Rerenders

To test component updates with new props, use a unique key for each mount call:

import { mount } from '@cypress/react'

it('updates when props change', () => {
  const Comp = ({ text }) => <span>{text}</span>

  mount(<Comp text="first" />, {}, 'key-1')
  cy.contains('first')

  mount(<Comp text="second" />, {}, 'key-2')
  cy.contains('second')
})

The third argument (key) forces React to unmount the previous instance and mount a new one with the updated props.

Summary

  • Cypress tests React components through the @cypress/react adapter, which is bundled with the main Cypress CLI.
  • The mount function creates a React 18 root via ReactDOM.createRoot and renders your JSX into a hidden container provided by @cypress/mount-utils.
  • Automatic cleanup occurs between tests via the cleanup helper in mount.ts, ensuring isolated component state.
  • Standard Cypress commands work immediately after mounting, allowing you to query and interact with components as if in a real application.
  • Component testing mode is launched via cypress open --component or the cy:open script defined in npm/react/package.json.

Frequently Asked Questions

Can Cypress test React components without running a full application?

Yes. Cypress Component Testing mounts individual React components in isolation without requiring a running development server or built application. The mount function from @cypress/react renders your component into a detached DOM node within the Cypress test runner, allowing you to test component logic, props, and state independently of your application's routing or data fetching layers.

What versions of React does Cypress support?

The @cypress/react package supports React 18 and newer versions, leveraging the ReactDOM.createRoot API introduced in React 18. As defined in npm/react/package.json, React is listed as a peer dependency, meaning you must have React installed in your project. The adapter handles both the legacy and concurrent rendering modes through React 18's client-side hydration APIs.

How does component testing differ from end-to-end testing in Cypress?

End-to-end (E2E) tests visit full URLs and test complete user flows through your application, while component tests focus on individual React components in isolation. Component tests use the mount command instead of cy.visit(), run faster because they don't require server infrastructure, and allow you to pass props directly to test specific component states. Both test types use the same Cypress commands (cy.get, cy.click, etc.) and run in the same browser-based test runner.

Do I need to install @cypress/react separately?

No separate installation is required for typical use cases. The @cypress/react adapter is bundled with the main Cypress CLI when you install Cypress. However, you must ensure React is installed in your project as a peer dependency, as declared in npm/react/package.json. The adapter automatically wires itself into the component testing runner when you execute the cy:open or cy:run scripts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →