React-select: Simulate 'change' doesn't work for select

Created on 7 Nov 2016  路  12Comments  路  Source: JedWatson/react-select

Hi, i'm adding tests to my pagination component based on Select

PageSizeSelector.js

class PageSizeSelector extends PureComponent {
    ..
    render() {
        const {pageSize} = this.props;
        return <Select
            options={this.pageSizeOptions}
            value={pageSize}
            onChange={(option) => this.pageSizeChangeFunc(option.value)()}
            clearable={false}
        />
    }
}

PageSizeSelector.test.js

import {mount} from 'enzyme'
...
it('changing pageSize', () => {
        let size = 0;
        const onPageSizeChanged = (pageSize) => size = pageSize;

        const wrapper = mount(
            <PageSizeSelector
                pageSize={10}
                onPageSizeChanged={onPageSizeChanged}
            />
        );

        wrapper.find('Select').simulate('change', {target: {value: 50}});
        expect(size).to.eql(50);
    })

onPageSizeChanged isn't called.
If replace simulate line with

   wrapper.find('Select').find('input').simulate('change', {target: {value: 50}});

get exception

- TypeError: str.replace is not a function
        at stripDiacritics (node_modules/react-select/lib/utils/stripDiacritics.js:7:13)
        at filterOptions (node_modules/react-select/lib/utils/defaultFilterOptions.js:13:50)
        at filterOptions (node_modules/react-select/lib/Select.js:992:11)
        at render (node_modules/react-select/lib/Select.js:1116:45)
        at node_modules/react/lib/ReactCompositeComponent.js:793:21
        at measureLifeCyclePerf (node_modules/react/lib/ReactCompositeComponent.js:74:12)

Using react-select@^1.0.0-rc.2
Looked at https://github.com/airbnb/enzyme/issues/400 as well
Thanks

Most helpful comment

+10000000000000000 馃幈

All 12 comments

+10000000000000000 馃幈

@nbotalov hey, went across the same problem... 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 had to add the classNamePrefix prop to the Select component otherwise I didn't get any "control" classes to latch onto.

This stackoverflow link shows how to simulate keyDown event. But if I do so, its not calling the onChange function.

The following should:

  1. Find the Select component in your wrapper.
  2. Get its instance.
  3. Set the value to { label: "...", value: 50 }
wrapper.find('Select').instance().selectOption({ label: "...", value: 50 });

If you can you should use the original options from your options array for tests.

@Rall3n Thanks! Your solution worked for me!

I answered the question using testing-library, easily adaptable to enzyme. For me, the Select is embedded in a component, but this still works, as long as you can pick the right input value.

https://stackoverflow.com/a/57699061/141552

Basically pretend to be a screen reader.

Using testing-library and v2.0

Trying to avoid using anything very specific like classNamePrefix or hacking into the way the component operates by looking for the onChange prop or whatever.

const callback = jest.fn();
const { container, getByText} = render(<Select ... onChange={callback} />);

Now we basically pretend to be a screen reader and focus, and press the down arrow.

fireEvent.focus(container.querySelector('input'));
fireEvent.keyDown(container.querySelector('input'), { key: 'ArrowDown', code: 40 });

And now click on the value you want

fireEvent.click(getByText('Option Two'));

And assert.

expect(callback).toHaveBeenCalledWith({ value: 'two', label: 'Option Two'});

@Rall3n your solution worked for me!

And case I want remove?
wrapper.find('Select').instance().removeOption({ label: "...", value: 50 })?

The following should:

1. Find the `Select` component in your wrapper.

2. Get its instance.

3. Set the value to `{ label: "...", value: 50 }`
wrapper.find('Select').instance().selectOption({ label: "...", value: 50 });

If you can you should use the original options from your options array for tests.

It seems functions like selectOptions and removeOptions are in wrapper.find('Select').instance().props, not in wrapper.find('Select').instance()

The react-testing-library solution has been extracted into a helper package: https://github.com/romgain/react-select-event

Hello -

In an effort to sustain the react-select project going forward, we're closing old issues.

We understand this might be inconvenient but in the best interest of supporting the broader community we have to direct our efforts towards the current major version.

If you aren't using the latest version of react-select please consider upgrading to see if it resolves any issues you're having.

However, if you feel this issue is still relevant and you'd like us to review it - please leave a comment and we'll do our best to get back to you!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MalcolmDwyer picture MalcolmDwyer  路  3Comments

steida picture steida  路  3Comments

x-yuri picture x-yuri  路  3Comments

mbonaci picture mbonaci  路  3Comments

mjuopperi picture mjuopperi  路  3Comments