Testing React Select component
From https://github.com/JedWatson/react-select/issues/1357
Only solution I found was to simulate a selection through key-down events:
wrapper.find('.Select-control').simulate('keyDown', { keyCode: 40 });// you can use 'input' instead of '.Select-control'wrapper.find('.Select-control').simulate('keyDown', { keyCode: 13 });expect(size).to.eql('your first value in the list')
I've tried both answers listed above, and still no luck.
What did work for me was:
Add
classNamePrefix
prop - i.elist
(as mentioned in the other answers) :<Select classNamePrefix='list' options={[ { label: 'one', value: 'one' }, { label: 'two', value: 'two' }]}/>
select the dropdown indicator & simulate a mouseDown => opened dropdown:
wrapper .find('.list__dropdown-indicator') .simulate('mouseDown', { button: 0 });
expect things to happen i.e. in my case I was checking for the number of dropdown options
expect(wrapper.find('.list__option').length).toEqual(2);
if you have control over the props being sent, you can add a
menuIsOpen
prop to always have the menu open (aka step 2 in the list).
To select a value from the dropdown, after opening the dropdown:
wrapper.find('.list__option').last().simulate('click', null);
then you can test either:
expect(wrapper.find('.list__value-container').text()).toEqual('two');
or
expect(wrapper.find('.list__single-value').text()).toEqual('two');
This is a recurrent question. I'm sharing my own code with 100% passing tests which cover 100% of my source code.
My component looks like this
MySelectComponent({ options, onChange }) { return <div data-testid="my-select-component"> <Select className="basic-single" classNamePrefix="select" name="myOptions" placeholder="Select an option" options={options} onChange={e => onChange(e)} /></div>;}
The reason I'm adding a wrapper on my Select
with data-testid="my-select-component"
is that the rendered options element will be available on it otherwise I can't check if a text option exist (you'll understand better when you'll see my tests).
This is a live running example and when rendering it'll show a select component with 10 options.
Test 1 : should render without errors
I render the component.
I search for the placeholder to be present.
Test 2 : should call onChange when the first option is selected
I render the component.
I check if my
mockedOnChange
is not yet called.Simulate an
ArrowDown
event.Click on the first option.
I check if
mockedOnChange
is called 1 time with the 1st option label and value.
Test 3 : should call onChange when the first option is selected then second option then the 9th one
I render the component.
I simulate a select of the first option.
I simulate a select of the 2nd option.
I simulate a select of the 9th option.
I check if the
mockedOnChange
is called 3 times with the 9th option bale and value.
Test 4 : should call onChange when filtering by input value
I render the component.
I simulate a change on the input field by typing "option 1".
I know, based on my
mockedOptions
that the filtered result will be "Mocked option 1" and "Mocked option 10".I simulate 2
ArrowDown
events.I check that the
mockedOnChange
is called with the 2nd filtered option with right label and value.
Complete test file
import React from 'react';import { render, fireEvent, cleanup, waitForElement } from '@testing-library/react';import MySelectComponent from './MySelectComponent';afterEach(cleanup);describe ('Test react-select component', () => { const mockedOptions = [ {label: 'Mocked option 1', value: 'mocked-option-1'}, {label: 'Mocked option 2', value: 'mocked-option-2'}, {label: 'Mocked option 3', value: 'mocked-option-3'}, {label: 'Mocked option 4', value: 'mocked-option-4'}, {label: 'Mocked option 5', value: 'mocked-option-5'}, {label: 'Mocked option 6', value: 'mocked-option-6'}, {label: 'Mocked option 7', value: 'mocked-option-7'}, {label: 'Mocked option 8', value: 'mocked-option-8'}, {label: 'Mocked option 9', value: 'mocked-option-9'}, {label: 'Mocked option 10', value: 'mocked-option-10'}, ]; it('should render without errors', async () => { const mockedOnChange = jest.fn(); const { getByText } = render(<MySelectComponent options={mockedOptions} onChange={mockedOnChange} />); const placeholder = getByText('Select an option'); expect(placeholder).toBeTruthy(); }); it('should call onChange when the first option is selected', async () => { const mockedOnChange = jest.fn(); const { getByText, queryByTestId } = render(<MySelectComponent options={mockedOptions} onChange={mockedOnChange} />); const mySelectComponent = queryByTestId('my-select-component'); expect(mySelectComponent).toBeDefined(); expect(mySelectComponent).not.toBeNull(); expect(mockedOnChange).toHaveBeenCalledTimes(0); fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' }); await waitForElement(() => getByText('Mocked option 1')); fireEvent.click(getByText('Mocked option 1')); expect(mockedOnChange).toHaveBeenCalledTimes(1); expect(mockedOnChange).toHaveBeenCalledWith({label: 'Mocked option 1', value: 'mocked-option-1'}); }); it('should call onChange when the first option is selected then second option then the 9th one', async () => { const mockedOnChange = jest.fn(); const { getByText, queryByTestId } = render(<MySelectComponent options={mockedOptions} onChange={mockedOnChange} />); const mySelectComponent = queryByTestId('my-select-component'); expect(mySelectComponent).toBeDefined(); expect(mySelectComponent).not.toBeNull(); expect(mockedOnChange).toHaveBeenCalledTimes(0); fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' }); await waitForElement(() => getByText('Mocked option 1')); fireEvent.click(getByText('Mocked option 1')); fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' }); await waitForElement(() => getByText('Mocked option 2')); fireEvent.click(getByText('Mocked option 2')); fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' }); await waitForElement(() => getByText('Mocked option 9')); fireEvent.click(getByText('Mocked option 9')); expect(mockedOnChange).toHaveBeenCalledTimes(3); expect(mockedOnChange).toHaveBeenCalledWith({label: 'Mocked option 9', value: 'mocked-option-9'}); }); it('should call onChange when filtering by input value', async () => { const mockedOnChange = jest.fn(); const { getByText, queryByTestId, container } = render(<MySelectComponent options={mockedOptions} onChange={mockedOnChange} />); const mySelectComponent = queryByTestId('my-select-component'); fireEvent.change(container.querySelector('input'), { target: { value: 'option 1' }, }); // select Mocked option 1 fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' }); // select Mocked option 10 fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' }); await waitForElement(() => getByText('Mocked option 10')); fireEvent.click(getByText('Mocked option 10')); expect(mockedOnChange).toHaveBeenCalledTimes(1); expect(mockedOnChange).toHaveBeenCalledWith({label: 'Mocked option 10', value: 'mocked-option-10'}); });});
I hope that this help.