Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS Ant design select component mock change event

Having a component MyComp which contains a Select Ant component and willing to test MyComp to make sure that handlers are correct and being called

class MyComp extends Component {
    constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(value) {
        this.props.doSomething();
    }

    render() {
        return (
            <Select onChange={this.props.handleChange}>
                <Option value={"Op0"} >Opt0</Option>
                <Option value={"Op1"} >Opt1</Option>
                <Option value={"Op2"} >Opt2</Option>
            </Select>
        )
    }
}

I want to be able to test it as follows:

it('calls the right callback', () => {
    const Option = Select.Option;
    const mockHandler = jest.fn();
    const wrapper = mount(<MyComp handleChange ={mockHandler}/>);
    let select = wrapper.find(Select);
    select.simulate("onChange"); // also tried 'change'
    expect(mockHandler).toHaveBeenCalled()
});

Please bare in mind that it's 'mount' not shallow, so it actually renders children components

like image 500
AMTourky Avatar asked May 28 '18 12:05

AMTourky


2 Answers

A bit late, but another solution to get rid of all the pain trying to interact with Ant Design Selects with Jest would be to mock the Select component, by placing this kind of mock in a Jest setup file (or in a particular test suite only). By doing so, all Select will be replaced by good old native selects, which are more friendly in a unit test context.

It may also be a good thing to decouple unit tests from a UI library that could change (or be completely removed...), and it can make your tests faster too (UI components like Ant Design Selects can be complicated).

Using this mock you can do cool things like that (I'm using react-testing-library but this should work with Enzyme I guess) :

// Assuming a <Select data-testid="mySelect">...</Select> in component tested

// Update the selected option, triggering a onChange event
// No more click / mouseDown the input, find the right option in virtual list...
fireEvent.change(getByTestId('mySelect'), { target; { value: 'optionValue' } });

const options = getByTestId('mySelect').querySelectorAll('option');
expect(options[0].textContent).toEqual('first option text');
expect(options[0]).toHaveValue('option1Value');

// or test all in one shot
expect(Array.from(options).map(o => o.getAttribute('value'))).toEqual(['value1', 'value2']);

So far this is really more convenient than interacting with real Selects.

like image 179
Florian Motteau Avatar answered Nov 13 '22 14:11

Florian Motteau


As one approach you can use

select.prop('onChange')()

instead of select.simulate.


Additional you can open the antd select menu, check the values and go on with testing (depending on the used antd version).

In antd V3 you can use a simple fireEvent.click

// Opens the Drop down
fireEvent.click(getByText("Value 1"));

But with antd V4 you need to use mouseDown call

const elt = getByTestId('your-select-test-id').firstElementChild;
fireEvent.mouseDown(elt); // THIS WILL OPEN THE SELECT !
expect(getByText('Option from Select')).toBeInTheDocument(); // WORKS !

See depending github issue.

like image 1
zerocewl Avatar answered Nov 13 '22 15:11

zerocewl