Material-ui: Testing a <Switch /> component with React Testing Library, can't simulate a click event

Created on 4 Oct 2019  路  4Comments  路  Source: mui-org/material-ui

  • [x] The issue is present in the latest release.
  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 馃槸


I'm trying to test that when a <Switch /> component is clicked, my application responds in the appropriate way. I've had great success using React Testing Library, but in this case I can't seem to simulate a click on a <Switch /> component.

A simple component and a simple test:

import React, {useState} from 'react';
import {fireEvent, render} from '@testing-library/react';
import wait from 'waait';
import Switch from '@material-ui/core/Switch';

const MyComponent = () => {
  const [checked, setChecked] = useState(false);

  return (
    <Switch
      data-testid="foo"
      checked={checked}
      onChange={() => setChecked(!checked)}
    />
  );
};

describe('Testing a Switch', () => {
  it('works', async () => {
    const {getByTestId} = render(<MyComponent />);
    const myComponent = getByTestId('foo');

    expect(myComponent).not.toHaveAttribute('checked', '');

    fireEvent.click(myComponent);
    fireEvent.change(myComponent, {target: {checked: true}});

    // just in case
    await wait(1000);

    expect(myComponent).toHaveAttribute('checked', '');
  });
});

When the test runs, it fails at the last assertion. The virtual representation of the MUI Switch looks like:

<input
  class="PrivateSwitchBase-input-24 MuiSwitch-input"
  type="checkbox"
  value=""
/>

None of the fireEvent.click or fireEvent.change events from RTL Seem to have any affect.

I realize this could be an issue on RTL or even jest-dom but I'm not certain yet. I realize MUI is tested with RTL so I looked at the MUI tests for <Switch /> but they still seem to use Enzyme.

Expected Behavior 馃

firing event clicks should result in

<input
  class="PrivateSwitchBase-input-24 MuiSwitch-input"
  type="checkbox"
  value=""
  checked=""
/>

Steps to Reproduce 馃暪

I'm not sure that a live example would be helpful for a test running issue, but I'd be happy to put together a repo to recreate what I'm experiencing.

Context 馃敠

Your Environment 馃寧

| Tech | Version |
| ----------- | ------- |
| Material-UI | v4.4.2 |
| React | 16.9 |
| Browser | |
| TypeScript | |
| etc. | |

Most helpful comment

const { getByRole } = render(<Switch defaultChecked />);

// how a user would trigger it
getByRole('checkbox').click();
fireEvent.change(getByRole('checkbox'), { target: { checked: '' } });

expect(getByRole('checkbox')).to.have.property('checked', false);

For more context (checkbox vs switch) see #17870

All 4 comments

You should use byRole queries. These should be your go-to query. If these don't work with our components then this is a bug.

We don't have any guarantee that the root element matches the semantics of it's native counterpart.

I realize MUI is tested with RTL so I looked at the MUI tests for but they still seem to use Enzyme.

Yeah :sweat_smile:

@eps1lon Thanks so much for your reply!

I tried getByRole but still no luck in getting the switch to change states:

describe('Testing a Switch', () => {
  it('works', async () => {
    const {getByRole} = render(<MyComponent />);
    const myComponent = getByRole('checkbox');

    fireEvent.click(myComponent);
    fireEvent.change(myComponent, {target: {checked: ''}});

    // just in case ?
    await wait(1000);

    expect(myComponent).toHaveAttribute('checked', '');
  });
});

鈽濓笍 this still results in an unchanged (unchecked) switch. I also tried the role "switch" but computer said no.

    Unable to find an accessible element with the role "switch"

    Here are the accessible roles:

      checkbox:

      <input
        class="PrivateSwitchBase-input-16 MuiSwitch-input"
        type="checkbox"
        value=""
      />

Unable to find an accessible element with the role "switch"

Yeah that is definitely a bug. Switch should have the switch role. Thank you for testing this.

const { getByRole } = render(<Switch defaultChecked />);

// how a user would trigger it
getByRole('checkbox').click();
fireEvent.change(getByRole('checkbox'), { target: { checked: '' } });

expect(getByRole('checkbox')).to.have.property('checked', false);

For more context (checkbox vs switch) see #17870

Was this page helpful?
0 / 5 - 0 ratings