Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test props that are updated by an onChange handler in react testing library?

I've got an onChange handler on an input that I'm trying to test based on what I've read in the Dom Testing Library docs here and here.

One difference in my code is that rather than using local state to control the input value, I'm using props. So the onChange function is actually calling another function (also received via props), which updates the state which has been "lifted up" to another component. Ultimately, the value for the input is received as a prop by the component and the input value is updated.

I'm mocking the props and trying to do a few simple tests to prove that the onChange handler is working as expected.

I expect that the function being called in the change handler to be called the same number of times that fireEvent.change is used in the test, and this works with:

const { input } = setup();
fireEvent.change(input, { target: { value: "" } });
expect(handleInstantSearchInputChange).toHaveBeenCalledTimes(1);

I expect that the input.value is read from the original mock prop setup, and this works with:

  const { input } = setup();
  expect(input.value).toBe("bacon");

However, I'm doing something stupid (not understanding mock functions at all, it would seem), and I can't figure out why the following block does not update the input.value, and continues to read the input.value setup from the original mock prop setup.

This fails with expecting "" / received "bacon" <= set in original prop

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

QUESTION: How can I write a test to prove that the input.value has been changed given the code below? I assume that I need the mock handleInstantSearchInputChange function to do something, but I don't really know what I'm doing here quite yet.

Thanks for any advice on how to do and/or better understand this.

Test File

import React from "react";
import InstantSearchForm from "../../components/InstantSearchForm";
import { render, cleanup, fireEvent } from "react-testing-library";

afterEach(cleanup);

let handleInstantSearchInputChange, props;
  handleInstantSearchInputChange = jest.fn();
  props = {
    foodSearch: "bacon",
    handleInstantSearchInputChange: handleInstantSearchInputChange
  };

const setup = () => {
  const utils = render(<InstantSearchForm {...props} />);
  const input = utils.getByLabelText("food-search-input");
  return {
    input,
    ...utils
  };
};

it("should render InstantSearchForm correctly with provided foodSearch prop", () => {
  const { input } = setup();
  expect(input.value).toBe("bacon");
});

it("should handle change", () => {
  const { input } = setup();
  fireEvent.change(input, { target: { value: "" } });
  expect(input.value).toBe("");
  fireEvent.change(input, { target: { value: "snickerdoodle" } });
  expect(input.value).toBe("snickerdoodle");
});

Component

import React from "react";
import PropTypes from "prop-types";

const InstantSearchForm = props => {
  const handleChange = e => {
    props.handleInstantSearchInputChange(e.target.value);
  };
  return (
    <div className="form-group">
      <label className="col-form-label col-form-label-lg" htmlFor="food-search">
        What did you eat, fatty?
      </label>
      <input
        aria-label="food-search-input"
        className="form-control form-control-lg"
        onChange={handleChange}
        placeholder="e.g. i ate bacon and eggs for breakfast with a glass of whole milk."
        type="text"
        value={props.foodSearch}
      />
    </div>
  );
};

InstantSearchForm.propTypes = {
  foodSearch: PropTypes.string.isRequired,
  handleInstantSearchInputChange: PropTypes.func.isRequired
};

export default InstantSearchForm;
like image 611
Kim Avatar asked Oct 11 '25 17:10

Kim


1 Answers

The way you are thinking about your tests is slightly incorrect. The behavior of this component is purely the following:

  1. When passed a text as a prop foodSearch renders it correctly.
  2. Component calls the appropriate handler on change.

So only test for the above.

What happens to the foodSearch prop after the change event is triggered is not the responsibility of this component(InstantSearchForm). That responsibility lies with the method that handles that state. So, you would want to test that handler method specifically as a separate test.


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!