Seems like the way Material UI works is it renders a different SVG when the checkbox is clicked, and not changing the attributes or anything on the actual input element. So how do I actually test that the element is checked in line with the react-testing-library
philosophy?
Here's a rough example of the
Checkbox component usage
export const CheckBoxContainer = () => (
<Checkbox inputProps={{ 'data-testid': `clickable-checkbox-1234` }} data-testid={`checkbox-1234`} />
);
Test
test('check the box', async () => {
const { getByTestId } = render(<CheckBoxContainer />);
await waitForElement(() => getByTestId(`checkbox-1234`));
const checkbox = getByTestId(`checkbox-1234`);
fireEvent.click(getByTestId(`clickable-checkbox-1234`));
expect(checkbox).toHaveAttribute('checked');
});
Generated HTML by Material UI
<span
class="MuiButtonBase-root-54 MuiIconButton-root-48 MuiSwitchBase-root-231 MuiCheckbox-root-225 MuiCheckbox-colorSecondary-230 MuiSwitchBase-checked-232 MuiCheckbox-checked-226"
data-testid="checkbox-1234"
>
<span class="MuiIconButton-label-53">
<svg
class="MuiSvgIcon-root-57"
focusable="false"
viewBox="0 0 24 24"
aria-hidden="true"
role="presentation"
>
<path
d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"
></path>
</svg>
<input
class="MuiSwitchBase-input-234"
type="checkbox"
data-indeterminate="false"
data-testid="clickable-checkbox-1234"
value=""
/>
</span>
<span class="MuiTouchRipple-root-66"> </span>
</span>
Using the Material UI Checkbox is essentially the same as native React inputs. You have a checked prop, a boolean set to either true or false, which determines whether the Checkbox is checked or not. You use the onChange prop and React hooks to set and maintain the state of the checkbox.
To check or uncheck the checkbox using react-testing-library, you simply want to fireEvent.click the checkbox. There was a discussion about this on react-testing-library Issue #175.
By not relying on the React component tree you make your test more robust against internal changes in MUI or, if you need snapshot testing, adding additional wrapper components such as context providers. We don't recommend snapshot testing though.
In the event handler, we can look at event.target.checked to know what the new state value should be set to. For handling multiple checkboxes, we can look at the target.name to identify which checkbox we touched and then store that as a key in our React state.
The easiest way I have found to locate a checkbox is by adding a label to it
<FormControlLabel
htmlFor="first-checkBox"
label="First Checkbox"
control={ <Checkbox
checked={checked}
onChange={handleChange}
inputProps={{ 'aria-label': 'primary checkbox' }}
/>
}
/>
later in test case
const checkboxEl = screen.getByLabelText('First Checkbox') as HTMLInputElement
expect(checkboxEl).toBeChecked()
if the test fails because doesn't recognize toBeChecked as part of the available assertions is because you need to import
import '@testing-library/jest-dom/extend-expect'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With