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:
-
Provides a DOM container – The
@cypress/mount-utilsutility supplies a hidden<div>element in the Cypress test runner page viagetContainerEl. -
Creates a React root – Using React 18's
ReactDOM.createRoot(as seen innpm/react/src/mount.tslines 13‑18), Cypress maintains a singlerootinstance for the component lifecycle. -
Renders the JSX – The supplied JSX is passed to
ReactDOM.Root.render(seemount.tslines 55‑60). -
Exposes Cypress commands – The
mountcall returns aCypress.Chainable, allowing you to chain standard commands against the mounted component. -
Handles cleanup – A
cleanuphelper unmounts the previous component before each newmountcall (seemount.tslines 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/reactadapter, which is bundled with the main Cypress CLI. - The
mountfunction creates a React 18 root viaReactDOM.createRootand renders your JSX into a hidden container provided by@cypress/mount-utils. - Automatic cleanup occurs between tests via the
cleanuphelper inmount.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 --componentor thecy:openscript defined innpm/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →