Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test form submission with data using react testing library

I have a react component with a form. I want to unit test (using jest and RTL) if form gets submitted with correct data. Here are my component and unit test method:

Component:

class AddDeviceModal extends Component {
  handleOnSave(event) {
    const { deviceName } = event.target;
    const formData = {
      deviceName: deviceName.value,
    };
    this.props.onSave(formData);
  }

  render() {
    return (
      <Form onSubmit={this.handleOnSave}>
        <Form.Label>Device Name</Form.Label>
        <Form.Control name="deviceName" placeholder="Device Name" required />
        <Button type="submit">Save Device</Button>
      </Form>
    );
  }
}

Unit Test:

it("Test form submit and validation", () => {
  const handleSave = jest.fn();
  const props = {
    onSave: handleSave,
  };
  render(<AddDeviceModal {...props} />);
  const deviceNameInput = screen.getByPlaceholderText(/device name/i);
  fireEvent.change(deviceNameInput, { target: { value: "AP VII C2230" } });
  fireEvent.click(getByText(/save device/i));
});

However, in handleOnSave(), I get error as deviceName is undefined. For some reason, it is not able to get the textbox value from event.target. Am I doing something wrong in above code? Needed help in fixing this issue.

like image 924
Saket Kumar Avatar asked Feb 10 '26 19:02

Saket Kumar


2 Answers

The problem you have it with trying to access the input directly from event.target. You should access it from event.target.elements instead: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements.

function handleOnSave(event) {
  event.preventDefault();
  const { deviceName } = event.target.elements;
  const formData = {
    deviceName: deviceName.value
  };

  // this will log the correct formData even in tests now
  console.log(formData);
  this.props.onSave(formData);
}

And here is your test:

it("Test form submit and validation", () => {
  const { getByPlaceholderText, getByText } = render(<App />);
  const deviceNameInput = getByPlaceholderText(/device name/i);

  fireEvent.change(deviceNameInput, { target: { value: "AP VII C2230" } });
  fireEvent.click(getByText(/Save Device/i));
});

I created a codesandbox where you can see this in action: https://codesandbox.io/s/form-submit-react-testing-library-45pt8?file=/src/App.js

like image 70
tudor.gergely Avatar answered Feb 13 '26 18:02

tudor.gergely


I used jest and react-testing-library.

I personally don't like the idea of changing the Form component code by passing a mock or spy function just for testing purpose.

For my form, I come up with this idea (find the code samples and full answer here) -

  • basically I created handleOnSubmitMock function, and then assigned it to screen.getByRole("form", { name: "signup-form" }).onsubmit GlobalEventHandler. (Not passing the mock function to the Form)
  • then I checked if expect(handleOnSubmitMock).toHaveBeenCalled() or expect(handleOnSubmitMock).not.toHaveBeenCalled() passes.

You should be able to modify the code for your need from the descriptive code samples in the link, and it should work. The goal is to -

  • render the Form component.
  • get the necessary elements.
  • fire the button click event.
  • expect onSubmit handler to be either called or not called depending on the test conditions.
like image 23
Mehedi Avatar answered Feb 13 '26 18:02

Mehedi