React Select Event Simulation

5.5.1 · active · verified Sun Apr 19

react-select-event is a specialized companion library for React Testing Library, designed to accurately simulate user interactions on `react-select` components in unit and integration tests. The current stable version is `5.5.1`. This library has an active release cadence, with frequent minor and patch updates, alongside occasional major versions introducing significant features or breaking changes. Its key differentiators include its tight integration with `react-testing-library`'s ecosystem, enabling robust testing of complex `react-select` scenarios like asynchronous option loading, multi-select, and portal-rendered menus. It automatically wraps actions in React's `act` utility (since v5.1.0) to prevent common `act` warnings, and supports `react-select` versions from 2.1.0 onwards. It streamlines testing workflows by providing high-level event simulation functions that mimic real user behavior, unlike lower-level `fireEvent` calls that might not fully replicate `react-select`'s internal state management.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates selecting single and multiple options in a `react-select` component, including handling async selects, and verifying form values using `react-testing-library`.

import React from 'react';
import Select from 'react-select';
import { render, screen, fireEvent } from '@testing-library/react';
import selectEvent from 'react-select-event';

const OPTIONS = [
  { value: 'chocolate', label: 'Chocolate' },
  { value: 'strawberry', label: 'Strawberry' },
  { value: 'vanilla', label: 'Vanilla' },
  { value: 'mango', label: 'Mango' },
];

const MyForm = ({ isMulti = false, menuPortalTarget = undefined }) => (
  <form data-testid="form">
    <label htmlFor="food">Favorite Food</label>
    <Select
      options={OPTIONS}
      name="food"
      inputId="food"
      isMulti={isMulti}
      menuPortalTarget={menuPortalTarget}
    />
  </form>
);

describe('react-select-event basic usage', () => {
  it('should select a single option', async () => {
    render(<MyForm />);
    expect(screen.getByTestId('form')).toHaveFormValues({ food: '' });

    await selectEvent.select(screen.getByLabelText('Favorite Food'), 'Vanilla');

    expect(screen.getByTestId('form')).toHaveFormValues({ food: 'vanilla' });
  });

  it('should select multiple options when isMulti is true', async () => {
    render(<MyForm isMulti />);
    expect(screen.getByTestId('form')).toHaveFormValues({ food: [] });

    await selectEvent.select(screen.getByLabelText('Favorite Food'), ['Strawberry', 'Mango']);

    expect(screen.getByTestId('form')).toHaveFormValues({ food: ['strawberry', 'mango'] });
  });

  it('should handle async select options by typing', async () => {
    const loadOptions = (inputValue: string) =>
      Promise.resolve(
        OPTIONS.filter(option => option.label.toLowerCase().includes(inputValue.toLowerCase()))
      );
    // A minimal Async component for demonstration
    const AsyncSelect = (props: any) => (
      <Select {...props} loadOptions={loadOptions} cacheOptions defaultOptions />
    );

    render(
      <form data-testid="async-form">
        <label htmlFor="async-food">Async Food</label>
        <AsyncSelect name="async-food" inputId="async-food" />
      </form>
    );
    expect(screen.getByTestId('async-form')).toHaveFormValues({ 'async-food': '' });

    // Simulate typing to trigger loadOptions
    fireEvent.change(screen.getByLabelText('Async Food'), { target: { value: 'choco' } });
    await selectEvent.select(screen.getByLabelText('Async Food'), 'Chocolate');

    expect(screen.getByTestId('async-form')).toHaveFormValues({ 'async-food': 'chocolate' });
  });
});

view raw JSON →