Monday, 24 July 2023

Jest capture input change event and verify it was called with the correct value on a controlled react component

I am trying to use jest and @testing-library/react to verify that a react component (which wraps an HTML input element) is calling it's onChange callback with the correct value in response to a ChangeEvent.

Here is the react component

export const MyInput = ({ onChange, value }) => {
  const handleChange = (event) => {
    console.log(event.target.value);
    onChange(event);
  };

  return (
    <div>
      <input
        type="text"
        onChange={handleChange}
        label={"test-component"}
        data-testid={"test"}
        value={value}
      />
    </div>
  );
};

And here is the test

test("onChange should work", () => {
  const onChangeMock = jest.fn();
  let inputValue = 1;

  const { getByTestId } = render(
    <MyInput onChange={onChangeMock} value={inputValue} />
  );
  const input = getByTestId("test");

  fireEvent.change(input, { target: { value: "23" } });

  expect(onChangeMock).toHaveBeenCalled();
  expect(onChangeMock).toHaveBeenCalledWith(
    expect.objectContaining({
      target: expect.objectContaining({
        value: "23"
      })
    })
  );
});

And here is a link to a codesandbox which reproduces the problem.

The second assertion in my tests fails, because the onChangeMock's caller is an event whose' target.value is equal to 1, rather than 23.

And what's even weirder is that when logging event.target.value inside the handleChange function - it has the correct value of 23. Inspecting with a debugger also shows that the jest mock has a correct caller (event with a target value of 23 up until the debugger leaves the scope of the handleChange function). The moment I get back to the test scope and perform the assertion, the mock's event has a target value of 1.

So I am trying to understand Why am I observing this behavior and what is causing it ?

(I assume that the event's target gets set (by what though?) to my html input element the moment the event handler scope ends, and jest does not capture a deep clone of the event, as it was passed to the external function, but I could not find any documentation to support this)



from Jest capture input change event and verify it was called with the correct value on a controlled react component

No comments:

Post a Comment