Setting Up Cypress Component Testing — React, Vue and Angular Configuration

Cypress component testing uses the same Cypress Test Runner you already know from E2E testing — the same command chain, the same assertions, the same time-travel debugging. The difference is the setup: instead of visiting a URL, you mount() a single component. Cypress needs to know which framework (React, Vue, Angular) and bundler (Vite, Webpack) your project uses so it can compile and render your component correctly.

Configuring Component Testing — Framework and Bundler Setup

The setup process detects your framework and bundler, adds the necessary dependencies, and generates the configuration.

// ── STEP 1: Open Cypress and select Component Testing ──
// $ npx cypress open
// → Select "Component Testing" (not E2E Testing)
// → Cypress detects your framework (React, Vue, Angular)
// → Cypress detects your bundler (Vite, Webpack, Next.js, Create React App)
// → Click "Continue" — Cypress generates the configuration


// ── STEP 2: cypress.config.ts — component testing section ──

import { defineConfig } from 'cypress';

export default defineConfig({
  // E2E testing config (existing)
  e2e: {
    baseUrl: 'https://www.saucedemo.com',
    specPattern: 'cypress/e2e/**/*.cy.{js,ts}',
  },

  // Component testing config (NEW)
  component: {
    devServer: {
      framework: 'react',       // 'react', 'vue', 'angular', 'svelte'
      bundler: 'vite',          // 'vite', 'webpack'
      // For Next.js: framework: 'next'
      // For Create React App: bundler: 'webpack'
    },
    specPattern: 'src/**/*.cy.{js,ts,jsx,tsx}',  // CT specs live next to components
    supportFile: 'cypress/support/component.ts',
  },
});


// ── STEP 3: cypress/support/component.ts — CT support file ──

/*
import { mount } from 'cypress/react18';   // React 18
// import { mount } from 'cypress/react';  // React 17
// import { mount } from 'cypress/vue';    // Vue 3
// import { mount } from 'cypress/angular'; // Angular

// Add the mount command globally
Cypress.Commands.add('mount', mount);

// Optional: import global CSS so components render with your app styles
import '../../src/index.css';
import '../../src/App.css';

// TypeScript declaration
declare global {
  namespace Cypress {
    interface Chainable {
      mount: typeof mount;
    }
  }
}
*/


// ── STEP 4: Run component tests ──
// Interactive: npx cypress open --component
// Headless CI: npx cypress run --component


// ── Project structure with CT specs alongside components ──

/*
src/
  components/
    ProductCard/
      ProductCard.tsx           ← The component
      ProductCard.cy.tsx        ← Component test (RIGHT NEXT TO IT)
      ProductCard.module.css    ← Component styles
    LoginForm/
      LoginForm.tsx
      LoginForm.cy.tsx          ← Component test
    Modal/
      Modal.tsx
      Modal.cy.tsx              ← Component test
cypress/
  e2e/                          ← E2E test specs (separate)
    checkout.cy.ts
    login.cy.ts
  support/
    component.ts                ← CT support (mount command, global CSS)
    e2e.ts                      ← E2E support (custom commands)
*/


// ── Framework-specific setup differences ──

const FRAMEWORK_SETUP = {
  'React + Vite': {
    devServer: "{ framework: 'react', bundler: 'vite' }",
    mount_import: "import { mount } from 'cypress/react18'",
    spec_extension: '.cy.tsx',
    notes: 'Fastest setup — Vite HMR provides instant recompilation',
  },
  'React + Webpack (CRA)': {
    devServer: "{ framework: 'create-react-app', bundler: 'webpack' }",
    mount_import: "import { mount } from 'cypress/react18'",
    spec_extension: '.cy.tsx',
    notes: 'Use create-react-app framework preset for automatic config',
  },
  'Vue 3 + Vite': {
    devServer: "{ framework: 'vue', bundler: 'vite' }",
    mount_import: "import { mount } from 'cypress/vue'",
    spec_extension: '.cy.ts',
    notes: 'Mount accepts component + options (props, slots, plugins)',
  },
  'Angular': {
    devServer: "{ framework: 'angular', bundler: 'webpack' }",
    mount_import: "import { mount } from 'cypress/angular'",
    spec_extension: '.cy.ts',
    notes: 'Mount accepts component class + TestBed-like configuration',
  },
  'Next.js': {
    devServer: "{ framework: 'next', bundler: 'webpack' }",
    mount_import: "import { mount } from 'cypress/react18'",
    spec_extension: '.cy.tsx',
    notes: 'Supports Next.js App Router and Pages Router components',
  },
};

Object.entries(FRAMEWORK_SETUP).forEach(([fw, info]) => {
  console.log(`\n${fw}:`);
  console.log(`  devServer: ${info.devServer}`);
  console.log(`  mount:     ${info.mount_import}`);
  console.log(`  Spec ext:  ${info.spec_extension}`);
  console.log(`  Notes:     ${info.notes}`);
});
Note: Component test specs live next to the component they test — ProductCard.cy.tsx sits in the same folder as ProductCard.tsx. This is different from E2E tests, which live in cypress/e2e/. The co-location makes it obvious which components have tests and which do not. When a developer modifies ProductCard.tsx, the test file is right there — impossible to forget. This convention is enforced by the specPattern: 'src/**/*.cy.{js,ts,jsx,tsx}' config.
Tip: Import your global CSS files in cypress/support/component.ts so that mounted components render with the same styles they have in the full application. Without these imports, components mount with no styling — bare HTML with default browser styles. Adding import '../../src/index.css' and any Tailwind/Bootstrap CSS ensures visual consistency between CT and the real app.
Warning: The devServer configuration must match your actual project setup. If your project uses Vite but you configure bundler: 'webpack', component mounting will fail with cryptic compilation errors. Cypress’s auto-detection (via npx cypress open --component) usually gets this right, but verify manually if you use a custom build configuration or monorepo structure.

Common Mistakes

Mistake 1 — Putting component tests in cypress/e2e/ instead of next to the component

❌ Wrong: cypress/e2e/ProductCard.cy.tsx — separated from the component it tests, easy to forget and hard to find.

✅ Correct: src/components/ProductCard/ProductCard.cy.tsx — co-located, discoverable, and always visible when the component is modified.

Mistake 2 — Not importing global styles in the CT support file

❌ Wrong: Components mount with no CSS, making visual assertions meaningless and rendering unrecognisable.

✅ Correct: Adding import '../../src/index.css' to cypress/support/component.ts so all components render with the application’s real styles.

🧠 Test Yourself

Where should Cypress component test files be located in a React project?