Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assert toHaveBeenCalledWith with a React input components onChange handler

I am working on a test that checks that a React input component's onChange handler is called. I am using React 17, the react-testing-library, and jest.

const Input = ({ value, onChange }) => {
  return <input type="text" value={value} onChange={onChange} />;
};
test("calling onChange works", () => {
  const value = "default value";
  const handleChange = jest.fn();
  handleChange.mockImplementation((e) =>
    console.log("value is correct here", e.target.value)
  );

  const { container } = render(<Input value={value} onChange={handleChange} />);

  const input = container.querySelector("input");
  fireEvent.change(input, { target: { value: "new value" } });

  // works
  expect(handleChange).toHaveBeenCalled();

  /// does not work
  expect(handleChange).toHaveBeenCalledWith(
    expect.objectContaining({
      target: expect.objectContaining({
        value: "new value"
      })
    })
  );
});

The first assertion, checking that the handler was called, works, but I am not able to assert that the event properly contains the new value. Interestingly, mocking the implementation shows that the correct value is being passed.

https://codesandbox.io/s/jest-testing-react-forked-7gytg?file=/src/components/Input.test.js:116-763

I am aware that it would be easier to test the parent form component, seeing if the new input is displayed; however, I would like to unit test this individual component if possible.

like image 714
Dynamic Avatar asked Sep 19 '25 00:09

Dynamic


1 Answers

I think it's ok to put your assertion(s) in the mock implementation. I have something similar, testing a checkbox component.

it('should raise on onChange event when there is a state change', () => {
    let spy = jest.fn();
    spy.mockImplementation((e) => {
        expect(e.target.checked).toBe(true);
        expect(e.target.value).toBe('foo');
    })
    render(<Checkbox value={'foo'} checked={false} onChange={spy} />);
    
    userEvent.click(screen.getByRole('checkbox')); 

    expect(spy).toHaveBeenCalledTimes(1);
});

If you put in an assertion that you know will fail and see the test fail, you know they're getting hit.

like image 144
Stuart Avatar answered Sep 21 '25 14:09

Stuart