5

I want to check that when a button is clicked on my component, it calls the method I have created to handle the click. Here is my component:

import React, { PropTypes, Component } from 'react';

class Search extends Component {

  constructor(){
    super();
    this.state = { inputValue: '' };
  }

  handleChange = (e) => {
    this.setState({ inputValue: e.target.value });
  }

  handleSubmit = (e) => {
    e.preventDefault();
    return this.state.inputValue;
  }

  getValue = () => {
    return this.state.inputValue;
  }

  render(){
    return (
      <form>
        <label htmlFor="search">Search stuff:</label>
        <input id="search" type="text" value={this.state.inputValue} onChange={this.handleChange} placeholder="Stuff" />
        <button onClick={this.handleSubmit}>Search</button>
      </form>
    );
  }
}

export default Search;

and here is my test

  import React from 'react';
  import { mount, shallow } from 'enzyme';
  import Search from './index';
  import sinon from 'sinon';

  describe('Search button', () => {

    it('calls handleSubmit', () => {
      const shallowWrapper = shallow(<Search />);
      const stub = sinon.stub(shallowWrapper.instance(), 'handleSubmit');
      shallowWrapper.find('button').simulate('click', { preventDefault() {}     });
      stub.called.should.be.true();
    });

  });

The call called property comes back false. I have tried loads of variation on the syntax and I think maybe I'm just missing something fundamental. Any help would be greatly appreciated.

Andy Briggs
  • 107
  • 1
  • 5

1 Answers1

10

I'm relatively new to Sinon as well. I have generally been passing spy()s into component props, and checking those (though you can use stub() in the same way):

let methodSpy = sinon.spy(),
  wrapper = shallow(<MyComponent someMethod={methodSpy} />)

wrapper.find('button').simulate('click')

methodSpy.called.should.equal(true)

I point this out because I think it's the most straightforward way to unit test components (testing internal methods can be problematic).

In your example, where you're trying to test internal methods of a component, this wouldn't work. I came across this issue, though, which should help you out. Try:

it('calls handleSubmit', () => {
  const shallowWrapper = shallow(<Search />)
  let compInstance = shallowWrapper.instance()

  let handleSubmitStub = sinon.stub(compInstance, 'handleSubmit');
  // Force the component and wrapper to update so that the stub is used
  compInstance.forceUpdate()
  shallowWrapper.update()

  shallowWrapper.find('button').simulate('click', { preventDefault() {} });

  handleSubmitStub.called.should.be.true();
});
bjudson
  • 4,073
  • 3
  • 29
  • 46
  • The second code snippet does indeed pass my test. Interesting article on testing internal methods, I did not know that. I'm fairly new to TDD in general so perhaps my understanding if what I should be testing is incorrect. Many thanks, I will persevere with my research! – Andy Briggs Oct 02 '16 at 07:11
  • There are different opinions on what the boundary of a "unit" should be, I don't think your approach is necessarily incorrect. But thought I should pass that along, as it is a commonly held opinion. Enjoy your testing journey :) – bjudson Oct 02 '16 at 23:30
  • Many thanks, it help me a lot, I checked a lot of issue on enzyme repo, but it doesn't work with internal method of a component. – Huy Nguyen Jun 01 '17 at 02:09
  • Nearly a year later and this answer saved me. Thanks! – Matt Shirley Aug 22 '17 at 19:42