How Cypress Component Testing Integrates with React, Vue, Angular, and Svelte

Cypress component testing integrates with React, Vue, Angular, and Svelte through framework-specific adapters that wrap each library's native rendering APIs into a unified cy.mount interface.

Cypress provides dedicated npm packages for component testing across major JavaScript frameworks. According to the cypress-io/cypress source code, each adapter lives under the npm/ directory and exports a mount function that bridges the framework's internal rendering mechanisms with Cypress's command chain.

Framework-Specific Adapters

Each framework adapter implements a consistent pattern while using the library's native testing APIs under the hood.

React Adapter

The React adapter (npm/react/src/mount.ts) bootstraps components using ReactDOM.render (or createRoot in React 18+). It wraps the rendered output in a Cypress.ReactWrapper object that exposes the component instance to Cypress commands.

The adapter handles JSX transformation and automatically attaches the component to a temporary DOM node (<div id="cypress-root">) within the test runner iframe. After each test, it unmounts the component and cleans up the DOM, ensuring test isolation.

Vue Adapter

In npm/vue/src/index.ts, the Vue adapter delegates to @vue/test-utils and its mount helper. It supports both Vue 2 and Vue 3 by detecting the version and applying the appropriate mounting strategy.

The adapter accepts standard Vue Test Utils options (like props, global, and slots) and wraps the result in a Cypress.VueWrapper. This wrapper exposes Vue-specific methods such as vm (the component instance) while remaining compatible with standard Cypress queries like cy.get() and cy.contains().

Angular Adapter

The Angular implementation in npm/angular/src/mount.ts uses Angular's TestBed to compile a testing module and create a component fixture. Unlike React or Vue, Angular requires explicit dependency injection setup, so the adapter accepts a TestBed configuration object alongside the component class.

It creates a Cypress.AngularWrapper that holds the component fixture, allowing you to access the component instance via wrapper.component and trigger change detection manually when needed.

Svelte Adapter

For Svelte, the adapter in npm/svelte/src/mount.ts instantiates components using the native Svelte component constructor: new Component({ target, props }). It mounts the component to the Cypress-controlled DOM element and creates a Cypress.SvelteWrapper that maintains a reference to the component instance.

The Svelte adapter handles both prop passing and event forwarding, ensuring that reactive updates flow correctly through the component tree during test execution.

Shared Mount Utilities

All adapters rely on npm/mount-utils/src/index.ts, a common library that supplies helpers for DOM attachment, logging, and cleanup. This shared infrastructure ensures consistent behavior across frameworks while allowing each adapter to focus on framework-specific rendering logic.

The mount-utils package handles:

  • Attaching the temporary DOM container to the test runner iframe
  • Providing a stable unmount function that works across all frameworks
  • Propagating rendering errors to Cypress's command log
  • Supporting re-mounting when cy.mount is called multiple times in the same test

How the Mount Command Works

When you call cy.mount(<Component />), the execution flow follows this pattern:

  1. The framework-specific adapter receives the component and options
  2. It calls the library's native render API (e.g., ReactDOM.render, TestBed.createComponent, or new SvelteComponent)
  3. It wraps the rendered result in a framework-specific wrapper object (Cypress.ReactWrapper, Cypress.VueWrapper, etc.)
  4. It stores the wrapper on the global Cypress object and registers cleanup hooks
  5. It returns the wrapper so you can chain Cypress commands immediately

Because the wrapper is stored globally, Cypress can automatically clean up the component after each test, preventing state leakage between tests.

Installation and Setup

Each adapter is published as a separate npm package under the @cypress scope. Install only the adapters you need for your project:

npm install --save-dev @cypress/react   # React

npm install --save-dev @cypress/vue     # Vue

npm install --save-dev @cypress/angular # Angular

npm install --save-dev @cypress/svelte  # Svelte

After installation, import the mount function in your test files. The adapters automatically register cy.mount as a global Cypress command, so no additional configuration is required in your cypress.config.js or cypress.config.ts.

Code Examples by Framework

The following examples demonstrate the consistent API across all frameworks. Each uses cy.mount followed by standard Cypress assertions.

React Component Test

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

describe('Counter', () => {
  it('increments when clicked', () => {
    mount(<Counter initialCount={0} />)
    cy.contains('Count: 0')
    cy.get('button').click()
    cy.contains('Count: 1')
  })
})

Vue Component Test

// cypress/component/HelloWorld.cy.ts
import { mount } from '@cypress/vue'
import HelloWorld from '../../src/HelloWorld.vue'

describe('HelloWorld', () => {
  it('renders props correctly', () => {
    mount(HelloWorld, { 
      props: { msg: 'Hello from Cypress' } 
    })
    cy.contains('Hello from Cypress')
  })
})

Angular Component Test

// cypress/component/app.component.cy.ts
import { mount } from '@cypress/angular'
import { AppComponent } from '../../src/app/app.component'

describe('AppComponent', () => {
  it('displays the title', () => {
    mount(AppComponent)
    cy.get('h1').should('contain', 'Welcome to Angular')
  })
})

Svelte Component Test

// cypress/component/Counter.cy.js
import { mount } from '@cypress/svelte'
import Counter from '../../src/Counter.svelte'

describe('Counter', () => {
  it('reacts to button clicks', () => {
    mount(Counter, { props: { initial: 0 } })
    cy.contains('Count: 0')
    cy.get('button').click()
    cy.contains('Count: 1')
  })
})

Summary

Cypress component testing provides seamless integration with React, Vue, Angular, and Svelte through architectural patterns that balance framework-specific needs with a consistent developer experience:

  • Framework adapters in npm/<framework>/ wrap native rendering APIs (ReactDOM, Vue Test Utils, Angular TestBed, Svelte constructors) into a unified mount function
  • Cypress wrappers (Cypress.ReactWrapper, Cypress.VueWrapper, etc.) bridge framework component instances with Cypress command chains
  • Shared mount utilities (npm/mount-utils/src/index.ts) handle DOM attachment, automatic cleanup, and error logging across all frameworks
  • Global cy.mount command becomes available immediately after installing the respective adapter, requiring no additional configuration
  • Automatic isolation ensures components unmount after each test, preventing state leakage and flaky tests

Frequently Asked Questions

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

Cypress component testing mounts individual components in isolation using the actual framework rendering engine, while end-to-end testing drives a full application through a browser. Component tests run faster, require no server, and focus on component-level behavior, whereas E2E tests verify complete user workflows across multiple pages.

Can I use the same Cypress commands in component tests that I use in E2E tests?

Yes. After calling cy.mount(), you have access to the full Cypress API including cy.get(), cy.contains(), cy.click(), and custom commands. The framework adapters ensure that queried elements reference the mounted component's DOM subtree, maintaining the same query behavior as E2E tests.

Do I need to configure a development server for Cypress component testing?

No. Cypress component testing runs your components directly in the browser without requiring a separate development server or build step during test execution. The framework adapters handle the compilation and mounting internally, though you need the respective adapter package installed (@cypress/react, @cypress/vue, etc.) for your framework.

How does the automatic cleanup work between tests?

Each adapter registers an afterEach hook that calls the framework-specific unmount function. This removes the component from the DOM and destroys the wrapper instance stored on Cypress. The shared npm/mount-utils/src/index.ts library coordinates this cleanup, ensuring that DOM nodes and component state do not persist between tests, which prevents cross-test contamination.

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 →