Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I trigger the change event on a react-select component with react-testing-library?

Given that I can't test internals directly with react-testing-library, how would I go about testing a component that uses react-select? For instance, if I have a conditional render based on the value of the react-select, which doesn't render a traditional <select/>, can I still trigger the change?

import React, { useState } from "react";
import Select from "react-select";

const options = [
  { value: "First", label: "First" },
  { value: "Second", label: "Second" },
  { value: "Third", label: "Third" },
];

function TestApp() {
  const [option, setOption] = useState(null);
  return (
    <div>
      <label htmlFor="option-select">Select Option</label>
      <Select
        value={option}
        options={options}
        onChange={option => setOption(option)}
      />
      {option && <div>{option.label}</div>}
    </div>
  );
}

export default TestApp;

I'm not even sure what I should query for. Is it the hidden input?

like image 870
jktravis Avatar asked Feb 24 '19 03:02

jktravis


1 Answers

My team has a test utility in our project that lets us select an item easily after spending too much time trying to figure out how to do this properly. Sharing it here to hopefully help others.

This doesn't rely on any React Select internals or mocking but does require you to have set up a <label> which has a for linking to the React Select input. It uses the label to select a given choice value just like a user would on the real page.

const KEY_DOWN = 40

// Select an item from a React Select dropdown given a label and
// choice label you wish to pick.
export async function selectItem(
  container: HTMLElement,
  label: string,
  choice: string
): Promise<void> {
  // Focus and enable the dropdown of options.
  fireEvent.focus(getByLabelText(container, label))
  fireEvent.keyDown(getByLabelText(container, label), {
    keyCode: KEY_DOWN,
  })

  // Wait for the dropdown of options to be drawn.
  await findByText(container, choice)

  // Select the item we care about.
  fireEvent.click(getByText(container, choice))

  // Wait for your choice to be set as the input value.
  await findByDisplayValue(container, choice)
}

It can be used like this:

it('selects an item', async () => {
  const { container } = render(<MyComponent/>)

  await selectItem(container, 'My label', 'value')
})
like image 87
Daniel Avatar answered Sep 28 '22 02:09

Daniel