Richard Jarram
Richard Jarram

Reputation: 1004

How to test a click on a select's drop-down option?

I'm writing a test using @testing-library/react for React 16.4.0 & react-scripts 4.0.1 to test the functionality of a select dropdown.

select-dropdown

I want the test runner to click on the select drop-down and then click on its child with value regular. However, I can't seem to capture the DOM element of the options for the select in the test:

// Toolbar.test.tsx
render(<Toolbar/>)

const difficultySelect = screen.getByLabelText('difficulty')

console.log(difficultySelect.children)
// => HTMLCollection {}

The weird thing is that if I inspect the DOM with the following code, I do return the expected value (an array of the options):

// in browser console
const toggler = document.querySelector('toolbar-toggler');
toggler.children
// => HTMLCollection(4) [option, option, option, option]

I've done some research and my intuition is that I should be using useRef to access the select toolbar options. However I've struggled to implement this.

The actual component code is as follows:

// Toolbar.tsx
function Toggler({setting, options}: { setting: string, options: string[]}) {
  const handleChange = (option: string) => {
    // ... snip ... 
  }

  return (
    <div key={setting} className={`${setting}-select-container`}>
      <label htmlFor={setting}>{setting}</label>
      <select id={setting} data-testid='toolbar' key={setting} onChange={(event) => handleChange(event.target.value)}>
        {
          options.map((option: any, index: number) => (
            <option value={option} key={index}>{option}</option>
          ))
        }
      </select>
    </div>
  )
}

Upvotes: 2

Views: 1880

Answers (1)

juliomalves
juliomalves

Reputation: 50268

Once you've accessed the <select /> element you can fire a click event on it and then get the required option you want to click on.

// In your test case
render(<Toolbar options={['easy', 'regular', 'hard']} setting="difficulty" />)
const difficultySelect = screen.getByLabelText('difficulty')
fireEvent.click(difficultySelect)
const regularOption = screen.getByRole('option', { name: 'regular' })
fireEvent.click(regularOption)

Ideally, you'd want the test to follow the same steps as if a user would be interacting with the UI elements.

Upvotes: 3

Related Questions