React-testing-library: `onChange` not called for checkboxes in rtl@5

Created on 10 Aug 2018  Â·  7Comments  Â·  Source: testing-library/react-testing-library

  • react-testing-library version: 5.0.0
  • react version: 16.4.2
  • node version: 8.11.3
  • npm (or yarn) version: 1.9.4

Relevant code or config:

const onChange = jest.fn();
const { container } = render(<input type="checkbox" onChange={onChange} />);
const checkbox = container.firstChild as HTMLInputElement;

// This was working for react-testing-library@4:
// checkbox.checked = true;
// fireEvent.change(checkbox);

// This does not call the event handler:
fireEvent.change(checkbox, { target: { checked: true } });
// This does not call it either:
fireEvent.change(checkbox, { target: { value: true } });

expect(onChange).toHaveBeenCalledTimes(1);

What you did:

Simulate onChange event on checkbox.

What happened:

onChange does not get called anymore after upgrade to react-testing-library 5.0.0 and adjusting event handler code to match new shape as outlined in the release notes.

Reproduction:

Minimal reproduction repository: https://github.com/sgoll/rtl-checkbox

Problem description:

Testing checkboxes becomes impossible until the event handler get fired/simulated again.

bug help wanted needs investigation

Most helpful comment

I was able to locate the problem: to improve compatibility with IE8, react-dom internally uses the click event for checkboxes (and radio inputs)—although mapping it to the onChange handler passed as prop.

https://github.com/facebook/react/blob/72434a7686035b4af766ee7d06c070d7f5d6a5f2/packages/react-dom/src/events/ChangeEventPlugin.js#L210

So the proper way to simulate the toggling of a checkbox is as follows:

const onChange = jest.fn();
const { container } = render(<input type="checkbox" onChange={onChange} />);
const checkbox = container.firstChild as HTMLInputElement;

// This works for react-testing-library@5:
fireEvent.click(checkbox);

expect(onChange).toHaveBeenCalledTimes(1);

The change in commit 32f3e65 actually only exposes this behavior by avoiding the simulated call of the change handler. Interestingly, running the code above (with click) in react-testing-library 4.x.x calls the onChange handler twice. ¯\_(ツ)_/¯

Anyway, as this issue is not caused by react-testing-library after all, it can be closed.

All 7 comments

I was able to locate the problem: to improve compatibility with IE8, react-dom internally uses the click event for checkboxes (and radio inputs)—although mapping it to the onChange handler passed as prop.

https://github.com/facebook/react/blob/72434a7686035b4af766ee7d06c070d7f5d6a5f2/packages/react-dom/src/events/ChangeEventPlugin.js#L210

So the proper way to simulate the toggling of a checkbox is as follows:

const onChange = jest.fn();
const { container } = render(<input type="checkbox" onChange={onChange} />);
const checkbox = container.firstChild as HTMLInputElement;

// This works for react-testing-library@5:
fireEvent.click(checkbox);

expect(onChange).toHaveBeenCalledTimes(1);

The change in commit 32f3e65 actually only exposes this behavior by avoiding the simulated call of the change handler. Interestingly, running the code above (with click) in react-testing-library 4.x.x calls the onChange handler twice. ¯\_(ツ)_/¯

Anyway, as this issue is not caused by react-testing-library after all, it can be closed.

I literally just discovered this minutes ago and was making an example for you: https://codesandbox.io/s/0xw7401o50

Haha, glad we got it worked out!

Interestingly, running the code above (with click) in react-testing-library 4.x.x calls the onChange handler twice. ¯_(ツ)_/¯

The reason for this as I discovered in my research is that click will actually cause React to fire the input, change, and click events for some reason. Kinda weird stuff, but I'm glad we got this worked out.

We should probably document this. I think I'll do that because I want to explain a few things. Thanks!

Interestingly, running the code above (with click) in react-testing-library 4.x.x calls the onChange handler twice. ¯_(ツ)_/¯
'''

Hey @kentcdodds This is quite an old issue, but I'm facing a similar issue as the one above. If I try to call fireEvent.click for the second time, the handler function is being called twice

I'm currently using @testing-library/react version ^8.0.4

Is this still an issue or it has workarounds?

I'm not sure that I understand your issue. Could you ask about this on https://spectrum.chat/testing-library/help-react and see if someone can help you there? If it's concluded that there is a bug, then feel free to open a new issue. Thanks!

Sorry, I later found that it was being caused by the redux. Thanks!

I'm running into this issue trying to fire a change event on a radio. Tried the suggested workaround with .firstChild as well as the solution suggested here but neither seem to work. My use case is also a bit different from the stack overflow question as I'm checking a callback has been called not that the value of the radio has been updated.

Using "^9.3.0"
Here's my test

const onStaffIdChangeMock = jest.fn();

const { getByTestId } = render(<MergeDialogBody onStaffIdChange={onStaffIdChangeMock}/>);

const mergeToRadio = getByTestId('MergeToStaffIdRadio');
expect(mergeToRadio).toBeDefined();
fireEvent.click(mergeToRadio);

expect(onStaffIdChangeMock).toHaveBeenCalled();

Output

    expect(jest.fn()).toHaveBeenCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

Hi @emily-ellevation,

Could you make a reproduction of your issue in a codesandbox and post it to https://spectrum.chat/testing-library/help-react

Thanks!

Was this page helpful?
0 / 5 - 0 ratings