Leo Messi
Leo Messi

Reputation: 6166

How to test that a dropdown selector has value set in React with React Testing Library?

Having the following code:

    import { useForm, Controller } from 'react-hook-form';
    ...
      const { handleSubmit, reset, control, register, watch } = useForm({
        resolver: yupResolver(schema)
      });
    
    
    const sensorOptions = [
      { id: '0', name: 'sensor 0' },
      { id: '1', name: 'sensor 1' },
      { id: '2', name: 'sensor 2' }
    ];
    
    
    ...

onSubmit={handleSubmit(onAddSubmit)} // the action when the submit is called

...
  const onAddSubmit = (data) => {
    postData(data); // the API call if all is good
    toggle();
    reset();
  };

...
    
              <div data-testid={TestIds.SENSOR}>
                <Controller
                  control={control}
                  name='availableSensor'
                  render={({ field: { onChange } }) =>
                    <SelectInput
                      label='sensor')}
                      initialSelectedOption={{ id: '0', name: '' }}
                      onChange={onChange}
                      options={sensorOptions}
                    />
                  }
                />
              </div>

There are multiple SelectInputs like thi, but in this example it will be only one

const schema = yup.object().shape({
  sensor: yup.object().shape({
    id: yup.string(),
    name: yup.string()
  })
});

  const { handleSubmit, reset, control, register, watch } = useForm({
    resolver: yupResolver(schema)
  });

And here is the test:

import { fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { renderWithClientInstance } from '../shared/test-utils';

import '@testing-library/jest-dom';
import MyModal from './my-modal';
describe('MyModal', () => {
  const title = 'title';
  const toggle = jest.fn();
  const postData = jest.fn();

  it('should call postData function on clicking in Save button successfully', async () => {
    const { getByTestId, getByLabelText } = renderWithClientInstance(
      <MyModal title={title} open={true} toggle={toggle} />
    );

    const saveButton = getByTestId('submit-button');
    expect(saveButton).toBeInTheDocument();

    userEvent.selectOptions(
      getByLabelText('sensor'),
      'sensor 0'
    );

    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(postData).toBeCalled();
    });
  });
});

it fails with the error:

TestingLibraryElementError: Value "sensor 0" not found in options

Upvotes: 0

Views: 16107

Answers (1)

Som Shekhar Mukherjee
Som Shekhar Mukherjee

Reputation: 8168

So, since the select behavior is being achieved using a button and spans.

You need to first click the button this would bring all the options on the screen and then you need to click one of those options.

And then you can finally test that the selected option is now on the screen.

it("test dropdpwn", async () => {
  const { getByTestId, getByLabelText } = renderWithClientInstance(
    <MapSignalModal title={title} open={true} toggle={toggle} />
  );

  userEvent.click(screen.getAllByTestId("selectButton")[0]);
  userEvent.click(screen.getByText("sensor pool 1"));

  expect(
    await screen.findByText(screen.getByText("sensor pool 1"))
  ).toBeInTheDocument();
});

Also, to be really sure you can try the following, this should fail because "sensor pool 1" option is not initially on the screen.

And it should pass when the text is changed to "sensor pool 0" because that's there on the screen initially.

it("test dropdpwn", async () => {
  const { getByTestId, getByLabelText } = renderWithClientInstance(
    <MapSignalModal title={title} open={true} toggle={toggle} />
  );

  expect(screen.getByText("sensor pool 1")).toBeInTheDocument();
  // if you replace the above text to "sensor pool 0", it should work
});

For testing if postSignalMapping is being called you can mock it as shown below:

let mockPostSignalMapping = jest.fn();
jest.mock("../lib/hooks/use-post-signal-mapping", () => ({
  mutate: mockPostSignalMapping,
}));

it("test dropdpwn", async () => {
  // Do stuff

  await waitFor(() => {
    expect(mockPostSignalMapping).toBeCalled();
  });
});

Upvotes: 5

Related Questions