12

I have a form with 3 radio buttons like follows (fake names):

<form className="myForm" onSubmit={this.done}>
  <input className="myRadio" checked={ŧrue} type="radio" name="myRadio" onChange={this.change} value="value1"
  <input className="myRadio" type="radio" name="myRadio" onChange={this.change} value="value2"
  <input className="myRadio" type="radio" name="myRadio" onChange={this.change} value="value3"
<input type="submit" className="submit" />
</form>

And I am having very hard time trying to test the onChange and the onSubmit events.

inputs = TestUtils.scryRenderedDOMComponentsWithClass(MyComponentRendered, 'myRadio');
myForm = TestUtils.findRenderedDOMComponentWithClass(MyComponentRendered, 'myForm');

I have a test like:

it("changes the checked state when clicked", function() {
  MyComponent.change = jest.genMockFunction();

  expect(inputs[0].getDOMNode().checked).toBe(true);
  TestUtils.Simulate.change(inputs[1], {target: {value: 'value2'}});
  expect(inputs[0].getDOMNode().checked).toBe(false);
  expect(inputs[1].getDOMNode().checked).toBe(true);
  expect(inputs[2].getDOMNode().checked).toBe(false);

  expect(MyComponent.change).toBeCalled(); //Fails
  expect(MyComponent.change.mock.calls.length).toBe(1); //Fails too
});

That works except for the function (MyComponent.change) that should be called but it is not.

I also have one test for onSubmit:

it("saves on submit", function()
  MyComponent.done = jest.genMockFunction();
  MyComponent.insideDone = jest.genMockFunction();
  TestUtils.Simulate.submit(myForm);
  expect(MyComponent.done).toBeCalled(); //Fails
  expect(MyComponent.insideDone).toBeCalled(); //Success
});

Notice: MyComponent.insideDone is a function that is called by 'done' function.

Which fails too. I am pretty sure that the problem here is that I am not simulating the events in a correct way. However, I didn't find example of this using Jest and TestUtils from React.

Ferran Negre
  • 3,453
  • 3
  • 32
  • 55
  • I tried submitting a form using the click event but ended up nowhere, but what helped was getting hold of the form element itself and calling TestUtils.Simulate.submit(form) – nimgrg Oct 21 '14 at 12:58
  • As for the change function I would probably check MyComponent.change.mock.calls.length to be equal to 1, to check that the mocked function has been called. – nimgrg Oct 21 '14 at 13:04
  • @nimgrg, that mock.calls.length fails too. I updated my answer. Looks like for the last example, "done" function calls another function... and that one it's reported as called. – Ferran Negre Oct 21 '14 at 15:22
  • Not really sure I have limited and painful experience with Jest and React tests myself. What do you get when you do 'console.log(MyComponent.change.mock.calls)' – nimgrg Oct 21 '14 at 15:40
  • Oh, that just prints "[]". – Ferran Negre Oct 21 '14 at 16:32
  • Ignore my earlier comment. I tried the same setup as to yours and I see the same problem. The done function that is being called when the form is submitted is the actual done function with which the component was rendered, the mocked done function never gets called. Hopefully someone can shed some light on it. – nimgrg Oct 21 '14 at 17:49
  • @FerranNegre can you show some more source from your component? A jsbin/fiddle would also be of great help. – Nick Tomlin Dec 15 '14 at 23:04
  • I opened an issue here https://github.com/facebook/jest/issues/232 . @NickTomlin you can just write a component like the one from the issue, it is stateless and with a checkbox in the render function. – Ferran Negre Jan 27 '15 at 15:14

1 Answers1

2

The problem is that you are replacing the function after you have already given the original function to React. The expression onSubmit={this.done} is that function, and that is set as the event handler. After the render function finishes, you replace instance.done but React already got the old function. What you should do is instead:

<form className="myForm" onSubmit={() => this.done()}>

This makes sure that the event handler always invokes the method on the instance (the one you replaced). This has the nice side effect of being future compatible with React, since they will stop autobinding all methods to the instance.

Anders Ekdahl
  • 21,370
  • 4
  • 67
  • 57