0

I'm trying to test a component that have a <Switch/> (using Material-UI) and a <TextField/>. When user clicks in this Switch, it makes another field (<TextField/>) enable/disabled. The code works well, but my test using JEST always fails.

...
export function MyComponent(): JSX.Element{
  const [enableExpiresOn, setEnableExpiresOn] = useState(false);
  ...
  function handleAccountExpiresOn(e: React.ChangeEvent<HTMLInputElement>) {
    setEnableExpiresOn(e.target.checked);
  }

  return (
    <form ...>
      ...
      <div>
        <FormControlLabel
            control={
              <Switch
                id="account-expires"
                onChange={handleAccountExpiresOn}
                name="account-expires"
                color="primary"
                checked={enableExpiresOn}
              />
            }
            label={t("Account Expires On")}
          />
      </div>
      <div>
          <TextField
            id="account-expires-on"
            label={t("Account Expires On")}
            type="datetime-local"
            variant="outlined"
            required={enableExpiresOn}
            InputLabelProps={{
              shrink: true,
            }}
            disabled={!enableExpiresOn}
          />
      </div>
      ...
    </form>
  );

}

And in my JEST test file, I have the follow (as you can see, I'm trying to simulate a click in the Switcher):

  describe("Should render correctly", () => {
    let wrapper;

    beforeAll(() => {
      wrapper = mount(<MyComponent />);
    });
    ...
    fit("Should enable Account Expires On when switcher is on/checked", async () => {
        wrapper.find("#account-expires").at(0).simulate("click");
        expect(
          wrapper.find("#account-expires-on").get(0).props.disabled
        ).toEqual(false);
    });

However, Jest gives me an error in this expectation, saying that it have received true instead false.

I tried to put a setTimeout around the expectation, hoping that it would solve the problem because maybe we need to wait for the click to have effect, but it doesn't work.

I'm newer with JEST and React Hooks. So, I don't know if it is the best way to test what this behaviour or there is a better way.

Used Technologies

  • React Hooks
  • NextJS
  • Material UI
  • TypeScript
  • Jest
  • Enzyme
Ken White
  • 123,280
  • 14
  • 225
  • 444

1 Answers1

0

useState is async, jest check assertion before element get disabled.

Can try:

 describe("Should render correctly", () => {
    let wrapper;

    beforeAll(() => {
      wrapper = mount(<MyComponent />);
    });
    ...
    fit("Should enable Account Expires On when switcher is on/checked", () => {
        jest.useFakeTimers()
        wrapper.find("#account-expires").at(0).simulate("click");

        jest.runAllTimers()
        // or possibly
        // await new Promise(resolve => setTimeout(resolve, 0))

        expect(
          wrapper.find("#account-expires-on").get(0).props.disabled
        ).toEqual(false);
    });

And can google it

UPD

Can try to simulate onChange event or wrapper.find("#account-expires").at(0).props().onChange(); from here

Similar troubles with testing-library https://github.com/mui-org/material-ui/issues/17697

  • Thx Aleksandr. However, it brings the same result (`true` instead `false`). I have already tried it before. I also tried your suggestion using the `await new Promise(..)` but it gives me the follow error: `Error: thrown: "Exceeded timeout of 5000 ms for a test. Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."` – William Zimmermann Jul 16 '21 at 21:02
  • 1
    Possibly something with materialUI, it's use onChange, not onClick. Check out this one https://stackoverflow.com/questions/42854223/simulate-click-on-material-ui-toggle-component-test – Aleksandr Smyshliaev Jul 16 '21 at 21:12
  • Thx. However, this gives me another error: `TypeError: Cannot read property 'target' of undefined`. – William Zimmermann Jul 16 '21 at 22:42
  • Something like `wrapper.find("#account-expires").at(0).simulate('change', { target: { checked: true } });` from here https://stackoverflow.com/questions/39892256/checkbox-is-not-checked-after-simulate-change-with-enzyme Personally i prefer testing-library. – Aleksandr Smyshliaev Jul 16 '21 at 22:49
  • Unfortunately it doesn't work - same problem: expected false and received true... How would you do this kind of test using testing-library? – William Zimmermann Jul 19 '21 at 13:31
  • Seems like it issue with material ui itself. Like this https://github.com/mui-org/material-ui/issues/17697 – Aleksandr Smyshliaev Jul 19 '21 at 14:41
  • I tried to do the same that the github post suggested. However, it only works to verify if the same component (the Switch) is checked or not. It doesn't work to check if the TextField is enabled after check the Switch. Thank you any way. – William Zimmermann Jul 19 '21 at 20:48