Skip to main content

How to test a Material UI Select component using React Testing Library

Saturday, October 23rd, 2021

As great as the library is, testing Material UI components can be tricky at times. This is mainly due to how the components are nested within the DOM on render, which can sometimes make it difficult to know what elements to target using React Testing Library.

One component that often trips me up when writing tests is the Select component. I often find myself searching through previous test files to find an example of how to target the dropdown and select a menu item.

Here is the valuable code snippet that often saves my bacon:

jsx

// MySelectComponent.js
<MuiSelect
...
SelectProps={{
SelectDisplayProps: {
['data-testid']: 'select-id',
},
}}
>

js

import { render, fireEvent, within } from "@testing-library/react";
// MySelectComponent.test.js
const { findByTestId, getByRole } = render(<MySelectComponent />)
const selectElement = await findByTestId('select-id');
fireEvent.mouseDown(selectElement);
const dropdownList = getByRole('listbox');
fireEvent.click(
within(dropdownList).getByText('Menu item text')
);

At this stage, you may want to take this snippet and run with it (I know I would). But if you do find yourself thirsty for some extra knowledge, I'm here to break down the 'why' for you...

  1. Firstly, we add a test-id attribute to the select element we wish to target within our test. It is important that we add the data-testid attribute to the correct component as Material UI nests the Select in a few wrapping elements:

    js

    <MuiSelect
    ...
    SelectProps={{
    SelectDisplayProps: {
    ['data-testid']: 'select-id',
    },
    }}
    >
  2. After adding the attribute to the correct DOM element, we can target it by using the findByTestId selector within our test. React Testing Library's findByTestId selector returns a promise, which allows us to wait for an element to be available within the DOM. We then call the mouseDown event on the Select input to open the dropdown menu.

    js

    const { findByTestId, getByRole } = render(<MySelectComponent />)
    const selectElement = await findByTestId('select-id');
    fireEvent.mouseDown(selectElement);
  3. Clicking the select renders a Material UI dropdown menu in the DOM. The dropdown menu element is a ul with a "role" of listbox. Therefore, we can target the list element by using React Testing Library's getByRole selector.

    js

    const dropdownList = getByRole('listbox');

    FYI: This could potentially be an unreliable selector if you have multiple elements with a role of listbox within the DOM, so you may need to get more specific with your selector here.

  4. Finally, we can target the dropdown item by its label text and click on the element to change the input value. Note that we are using the within method from React Testing Library to narrow the scope of our selector. What we are essentially saying here is "select an element with the text 'Menu item text' from within my dropdown list".

    js

    fireEvent.click(
    within(dropdownList).getByText('Menu item text')
    );

    Annnndddd you're done! Now that you know how to confidently test a Material UI Select component you can continue to make the web a better place with smashing test coverage.

Hey there 👋 - I'm Luke Brown, a frontend web developer who often doesn't write about development at all.