or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

angular-testing.mdcli-integration.mdconfiguration.mdcustom-frameworks.mdindex.mdinteractive-testing.mdprogrammatic-execution.mdreact-testing.mdvue-testing.md
tile.json

react-testing.mddocs/

React Component Testing

Mount and test React components in isolation with full Cypress testing capabilities. The @cypress/react package provides seamless integration between React components and Cypress's powerful testing commands.

Capabilities

Mount React Components

Mount React components for isolated testing with props, context, and full Cypress command support.

// From cypress/react
import { mount } from '@cypress/react';

/**
 * Mount a React component for testing
 * @param jsx - React JSX element to mount
 * @param options - Mounting options and configuration
 * @returns Cypress chainable with component and rerender function
 */
function mount(
  jsx: React.JSX.Element,
  options?: MountOptions
): Cypress.Chainable<MountReturn>;

interface MountOptions {
  /** Log the mounting command into Cypress Command Log, true by default */
  log?: boolean;
  /** Render component in React strict mode */
  strict?: boolean;
  /** ReactDOM instance to use for rendering */
  ReactDom?: typeof import('react-dom/client');
}

interface MountReturn {
  /** The component that was rendered */
  component: React.ReactNode;
  /** Rerenders the specified component with new props */
  rerender: (component: React.ReactNode) => Cypress.Chainable<MountReturn>;
}

Usage Examples:

// cypress/component/Button.cy.js
import { mount } from '@cypress/react';
import Button from './Button';

describe('Button Component', () => {
  it('renders with text', () => {
    mount(<Button>Click me</Button>);
    cy.contains('Click me').should('be.visible');
  });

  it('handles click events', () => {
    const handleClick = cy.stub();
    mount(<Button onClick={handleClick}>Click me</Button>);
    
    cy.contains('Click me').click();
    cy.wrap(handleClick).should('have.been.called');
  });

  it('supports different variants', () => {
    mount(<Button variant="primary">Primary Button</Button>);
    cy.get('button').should('have.class', 'btn-primary');
  });
});

Mount with Props

Pass props to components and test different configurations.

// Testing with various props
describe('UserCard Component', () => {
  const mockUser = {
    id: 1,
    name: 'John Doe',
    email: 'john@example.com',
    avatar: 'https://example.com/avatar.jpg'
  };

  it('displays user information', () => {
    mount(<UserCard user={mockUser} />);
    
    cy.contains('John Doe').should('be.visible');
    cy.contains('john@example.com').should('be.visible');
    cy.get('[data-cy=avatar]').should('have.attr', 'src', mockUser.avatar);
  });

  it('handles missing avatar', () => {
    const userWithoutAvatar = { ...mockUser, avatar: null };
    mount(<UserCard user={userWithoutAvatar} />);
    
    cy.get('[data-cy=avatar-placeholder]').should('be.visible');
  });

  it('updates when props change via rerender', () => {
    mount(<UserCard user={mockUser} />).then(({ rerender }) => {
      cy.contains('John Doe').should('be.visible');
      
      // Update user data
      const updatedUser = { ...mockUser, name: 'Jane Doe' };
      rerender(<UserCard user={updatedUser} />);
      
      cy.contains('Jane Doe').should('be.visible');
      cy.contains('John Doe').should('not.exist');
    });
  });
});

Mount with Context Providers

Test components that depend on React Context.

// Testing with Context providers
import { ThemeProvider } from '@mui/material/styles';
import { mount } from '@cypress/react';
import ThemedButton from './ThemedButton';

describe('ThemedButton Component', () => {
  const lightTheme = createTheme({ palette: { mode: 'light' } });
  const darkTheme = createTheme({ palette: { mode: 'dark' } });

  it('renders with light theme', () => {
    mount(
      <ThemeProvider theme={lightTheme}>
        <ThemedButton>Light Button</ThemedButton>
      </ThemeProvider>
    );
    
    cy.get('button').should('have.class', 'light-theme');
  });

  it('renders with dark theme', () => {
    mount(
      <ThemeProvider theme={darkTheme}>
        <ThemedButton>Dark Button</ThemedButton>
      </ThemeProvider>
    );
    
    cy.get('button').should('have.class', 'dark-theme');
  });
});

Testing with React Router

Test components that use React Router for navigation.

import { mount } from '@cypress/react';
import { MemoryRouter } from 'react-router-dom';
import Navigation from './Navigation';

describe('Navigation Component', () => {
  it('highlights active route', () => {
    mount(
      <MemoryRouter initialEntries={['/dashboard']}>
        <Navigation />
      </MemoryRouter>
    );
    
    cy.get('[data-cy=nav-dashboard]').should('have.class', 'active');
    cy.get('[data-cy=nav-profile]').should('not.have.class', 'active');
  });

  it('navigates between routes', () => {
    mount(
      <MemoryRouter initialEntries={['/']}>
        <Navigation />
      </MemoryRouter>
    );
    
    cy.get('[data-cy=nav-profile]').click();
    cy.url().should('include', '/profile');
  });
});

Testing Forms and User Interactions

Test complex user interactions with forms and input handling.

import { mount } from '@cypress/react';
import LoginForm from './LoginForm';

describe('LoginForm Component', () => {
  it('validates required fields', () => {
    const onSubmit = cy.stub();
    mount(<LoginForm onSubmit={onSubmit} />);
    
    cy.get('button[type=submit]').click();
    cy.contains('Email is required').should('be.visible');
    cy.contains('Password is required').should('be.visible');
    cy.wrap(onSubmit).should('not.have.been.called');
  });

  it('submits valid form data', () => {
    const onSubmit = cy.stub();
    mount(<LoginForm onSubmit={onSubmit} />);
    
    cy.get('[data-cy=email-input]').type('user@example.com');
    cy.get('[data-cy=password-input]').type('password123');
    cy.get('button[type=submit]').click();
    
    cy.wrap(onSubmit).should('have.been.calledWith', {
      email: 'user@example.com',
      password: 'password123'
    });
  });

  it('displays loading state during submission', () => {
    mount(<LoginForm onSubmit={() => new Promise(() => {})} />);
    
    cy.get('[data-cy=email-input]').type('user@example.com');
    cy.get('[data-cy=password-input]').type('password123');
    cy.get('button[type=submit]').click();
    
    cy.get('button[type=submit]').should('be.disabled');
    cy.contains('Logging in...').should('be.visible');
  });
});

Testing with Redux

Test components connected to Redux store.

import { mount } from '@cypress/react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import TodoList from './TodoList';
import todoReducer from './todoReducer';

describe('TodoList Component', () => {
  const createMockStore = (initialState) => {
    return createStore(todoReducer, initialState);
  };

  it('displays todos from store', () => {
    const store = createMockStore({
      todos: [
        { id: 1, text: 'Learn Cypress', completed: false },
        { id: 2, text: 'Write tests', completed: true }
      ]
    });

    mount(
      <Provider store={store}>
        <TodoList />
      </Provider>
    );

    cy.contains('Learn Cypress').should('be.visible');
    cy.contains('Write tests').should('be.visible');
    cy.get('[data-cy=todo-item]').should('have.length', 2);
  });

  it('dispatches actions on user interaction', () => {
    const store = createMockStore({ todos: [] });
    const dispatchSpy = cy.spy(store, 'dispatch');

    mount(
      <Provider store={store}>
        <TodoList />
      </Provider>
    );

    cy.get('[data-cy=add-todo-input]').type('New todo');
    cy.get('[data-cy=add-todo-button]').click();

    cy.wrap(dispatchSpy).should('have.been.calledWith', {
      type: 'ADD_TODO',
      payload: 'New todo'
    });
  });
});

Advanced Component Testing Patterns

// Testing custom hooks with components
import { mount } from '@cypress/react';
import { useCounter } from './useCounter';

function CounterTestComponent() {
  const { count, increment, decrement, reset } = useCounter(0);
  
  return (
    <div>
      <span data-cy="count">{count}</span>
      <button data-cy="increment" onClick={increment}>+</button>
      <button data-cy="decrement" onClick={decrement}>-</button>
      <button data-cy="reset" onClick={reset}>Reset</button>
    </div>
  );
}

describe('useCounter Hook', () => {
  it('manages counter state', () => {
    mount(<CounterTestComponent />);
    
    cy.get('[data-cy=count]').should('contain', '0');
    
    cy.get('[data-cy=increment]').click();
    cy.get('[data-cy=count]').should('contain', '1');
    
    cy.get('[data-cy=decrement]').click();
    cy.get('[data-cy=count]').should('contain', '0');
    
    cy.get('[data-cy=increment]').click().click().click();
    cy.get('[data-cy=count]').should('contain', '3');
    
    cy.get('[data-cy=reset]').click();
    cy.get('[data-cy=count]').should('contain', '0');
  });
});

Component Testing Configuration

Configure component testing in your Cypress configuration:

// cypress.config.js
const { defineConfig } = require('cypress');

module.exports = defineConfig({
  component: {
    devServer: {
      framework: 'create-react-app',
      bundler: 'webpack',
    },
    specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}',
    supportFile: 'cypress/support/component.js',
    indexHtmlFile: 'cypress/support/component-index.html'
  }
});

Mount Utilities Access

Access mounting utilities for custom setup and teardown:

// From cypress/mount-utils
const ROOT_SELECTOR = '[data-cy-root]';

function getContainerEl(): HTMLElement;
function setupHooks(optionalCallback?: Function): void;

Custom Component Setup:

// cypress/support/component.js
import { mount } from '@cypress/react';
import { getContainerEl } from '@cypress/mount-utils';

// Custom mount command
Cypress.Commands.add('mountWithProviders', (component, options = {}) => {
  const { providers = [], ...mountOptions } = options;
  
  let wrappedComponent = component;
  providers.forEach(Provider => {
    wrappedComponent = <Provider>{wrappedComponent}</Provider>;
  });
  
  return mount(wrappedComponent, mountOptions);
});

// Global component setup
beforeEach(() => {
  // Reset any global state
  // Clear local storage, etc.
});

The React component testing integration provides a powerful way to test React components in isolation while leveraging all of Cypress's testing capabilities, including real browser rendering, network stubbing, and comprehensive assertion libraries.