Test React Form Submission With Jest & TestUtils

3.1k views Asked by At

I'm having trouble testing a form submit event using React, TestUtils and Jest.

I have a component that renders a <form> DOM element; the same component also has a method that handles the onSubmit event and logs a statement. My goal is to mock the onSubmit handler and assert that it is called.

form-component.cjsx

module.exports = React.createClass

  # Handle form submissions
  handleSubmit: (e) ->
    console.log 'Make async call'

  # Render a form
  render: ->
    <form onSubmit={@handleSubmit}>
      <input type="submit" />
    </form>

__tests__/test-form-component.coffee

jest
  .dontMock '../form-component'

React = require 'react/addons'
TestUtils = React.addons.TestUtils
FormComponent = require '../form-component'

describe 'FormComponent', ->
  it 'creates a log statement upon form submission', ->
    # Render a FormComponent into the dom
    formInstance = TestUtils.renderIntoDocument(<FormComponent />)

    # Mock the `handleSubmit` method
    formInstance.handleSubmit = jest.genMockFunction()

    # Simulate a `submit` event on the form
    TestUtils.Simulate.submit(formInstance)
    # TestUtils.Simulate.submit(formInstance.getDOMNode()) ???

    # I would have expected the mocked function to have been called
    # What gives?!
    expect(formInstance.handleSubmit).toBeCalled()

Related Questions:

2

There are 2 answers

0
Hartator On

What seems to be your issue exactly?

React.addons.TestUtils.Simulate.submit() works for me.

If it can help, I was in similar situation and I testing the submit handler this way (using sinon.js, mocha and chai):

var renderDocumentJQuery = $(renderDocument.getDOMNode())
this.xhr = sinon.useFakeXMLHttpRequest();
var requests = this.requests = [];
this.xhr.onCreate = function (xhr) {
    requests.push(xhr);
};
renderDocumentJQuery.find('input#person_email').val('[email protected]');
React.addons.TestUtils.Simulate.submit(renderDocumentJQuery.find('form')[0]);
var requestFired = requests[0];
this.xhr.restore();
it('should fire an AJAX with the right params', function(){
  assert.equal(requestFired.requestBody,'campaign_id=123&owner_id=456&person%5Bemail%5D=test%40email.com')
});
it('should fire an AJAX with a POST method', function(){
  assert.equal(requestFired.method,'POST')
});
it('should fire an AJAX with the correct url', function(){
  assert.equal(requestFired.url,'url-for-testing')
});
0
Adam Stone On

There's an issue with the way React calls event handlers that causes the original handler function to continue to be called even if you attempt to mock it first.

This can apparently be avoided by switching to the ES6 class syntax to create component classes, but another simple workaround is to have the event handler just call a second function and mock that. For example:

onSubmit: function() {
    this.handleSubmit();  // extra fn needed for Jest
},
handleSubmit: function(){
    this.setState({
        submitted: true
    });
}

You would set the form's onSubmit={this.onSubmit} and mock handleSubmit instead of onSubmit. Since this introduces a seemingly unnecessary extra function, if you decide to do this it's probably worth adding a comment to anticipate later attempts to "fix it" which would break the test.