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 availableSensorPoolOptions = [
      { id: '0', name: 'sensor pool 0' },
      { id: '1', name: 'sensor pool 1' },
      { id: '2', name: 'sensor pool 2' }
    ];
    
    
    ...

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

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

...
    
              <div data-testid={MapSignalModalTestIds.AVAILABLE_SENSOR_POOL}>
                <Controller
                  control={control}
                  name='availableSensorPool'
                  render={({ field: { onChange } }) =>
                    <SelectInput
                      label={t('calculation-engine.available-sensor-pool')}
                      initialSelectedOption={{ id: '0', name: '' }}
                      onChange={onChange}
                      options={availableSensorPoolOptions}
                    />
                  }
                />
              </div>

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

const schema = yup.object().shape({
  availableSensorPool: 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 '@oam/shared/test-utils';

import '@testing-library/jest-dom';
import MapSignalModal from './map-signal-modal';
describe('MapSignalModal', () => {
  const title = 'title';
  const toggle = jest.fn();
  const postSignalMapping = jest.fn();

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

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

    userEvent.selectOptions(
      getByLabelText('calculation-engine.available-sensor-pool'),
      'sensor pool 0'
    );

    fireEvent.click(saveButton);

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

it fails with the error:

TestingLibraryElementError: Value "sensor pool 0" not found in options


Solution 1:

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();
  });
});