Always Learning
Always Learning

Reputation: 5581

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

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?

Upvotes: 17

Views: 75695

Answers (4)

Karthik Pillai
Karthik Pillai

Reputation: 327

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.

Upvotes: 3

aqteifan
aqteifan

Reputation: 504

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.

Upvotes: 9

atimin
atimin

Reputation: 549

Try this approach:

      wrapper.find('option').at(0).instance().selected = false;
      wrapper.find('option').at(1).instance().selected = true;

Upvotes: 9

kamesh roshan
kamesh roshan

Reputation: 11

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

Upvotes: 1

Related Questions