How to simulate selecting from dropdown in Jest / enzyme testing?
Asked Answered
A

4

17

I'm trying to write jest tests for my React component that has a dropdown like this:

<select id="dropdown" onChange={this.handlechange} ref={this.refDropdown}>
    {this.props.items.map(item => {
        return (
            <option key={item.id} value={item.id}>
                {item.name}
            </option>
        );
    })}
</select>

and the handler looks like this:

handlechange = () => {
    const sel = this.refDropdown.current;
    const value = sel.options[sel.selectedIndex].value;
    //...
}

I want to simulate a user selecting the 2nd entry (or anything other than the first) in the list but am having trouble. If I simulate a "change" event it does fire the call to handlechange() but selectedIndex is always set to zero.

I tried this code in the jest test but it doesn't cause selectedIndex to be accessible in the handler.

const component = mount(<MyComponent/>);
component.find("#dropdown").simulate("change", {
    target: { value: "item1", selectedIndex: 1 }
});

What happens is almost correct. If I look at the incoming event, I can see e.value is set to "item1" as I set, but it doesn't act like the selection was actually made.

I've also tried trying to send "click" simulations to the Option element directly but that does nothing.

What's the right way to simulate a selection from a dropdown?

Anjanetteanjela answered 22/10, 2018 at 13:19 Comment(0)
T
9

Try this approach:

      wrapper.find('option').at(0).instance().selected = false;
      wrapper.find('option').at(1).instance().selected = true;
Tideland answered 27/10, 2019 at 16:58 Comment(1)
This was neccessary - thanks. Looks like the simulate doesn't actually change the selected value as I hoped, so before calling dropdown.simulate("change"...) I added the manual setting of which option was selected as you suggested, and it works.Anjanetteanjela
P
9

You can trigger a change event since you have your this.handlechange trigger onChange:

const component = mount(<MyComponent/>);
component.find('#dropdown').at(0).simulate('change', {
    target: { value: 'item1', name: 'item1' }
});

I would say you have to add .at(0) because Enzyme will find a list of values even if you only have one element with that ID.

Preamplifier answered 2/11, 2020 at 22:9 Comment(0)
T
2

Short Answer - Use the following snippet

import userEvent from "@testing-library/user-event"; 

userEvent.selectOptions(screen.getByTestId("select-element-test-id"), ["option1"]);

Detailed Answer -

.tsx file

    .
    .
    <Form.Select
     aria-label="Select a value from the select dropdown"
     required
     onChange={(e) => {
         console.log("Option selected from the dropdown list", e.target.value);
         optionChangedHandler(e.target.value);
     }}
     data-testid="select-element-test-id"
     >
     ...CODE FOR RENDERING THE LIST OF OPTIONS...
    </Form.Select>
    .
    .

.test.tsx file

import userEvent from "@testing-library/user-event";
   
it("Check entire flow", async () => {
    
    render(
          <YourComponent/>
        );

    // CHECK IF SELECT DROPDOWN EXISTS
    const selectDropdown = await waitFor(
      () => screen.getByTestId("select-element-test-id"),
      {
        timeout: 3000,
      }
    );
    expect(selectDropdown ).toBeInTheDocument();

    //"option2" is the element in the select dropdown list
    userEvent.selectOptions(screen.getByTestId("select-element-test-id"), [
          "option2",
        ]);
}

The above code will trigger the onChange function of the select element.

Toolmaker answered 8/6, 2022 at 11:5 Comment(0)
R
1

Try changing the html "onInput" to "onChange" because you are simulating the "change" event in jest.

Radiosensitive answered 18/10, 2019 at 4:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.