2

I have this code in my Search component render method:

   <button className="searchButton" onClick={this.handleSearch}>{this.state.on ? 'Search' : null}</button>

and then I have this:

  handleSearch = (e) => {
    this.setState(prevState => ({
      on: !prevState.on
    }));
  }

this definitely gets called when I click the button. however, my test is not simulating it even though I feel like I am doing it the correct way.

it.only('calls handleSearch', () => {
  searchButton = renderedOutput.find('button').at(0);
  searchButton.simulate('click');
  expect(handleSearchStub).to.have.been.called;
});

however, for some reason it does not think that my function has been called even though surely that is the way to simulate it? (there is only one button on the page)

The worm
  • 5,580
  • 14
  • 36
  • 49
  • just `.click() ` like in normal dom ? – Maciej Kozieja Mar 07 '17 at 11:34
  • @MaciejKozieja where are you referring to? – The worm Mar 07 '17 at 11:36
  • It would be good to see how you are passing the stub to the component in your test, as the onClick handler is a method not a passed in function prop, and `handleSearch` method doesnt call any passed in function prop either. I can only presume you are spying on the `handleSearch` method itself? – alechill Mar 07 '17 at 11:42
  • @alechill the only thing I have done is: ` handleSearchStub = sinon.stub();` set it up as a sinon stub – The worm Mar 07 '17 at 11:44
  • Then you would need to pass it into the component. I think a stub is the wrong approach anyway here, as your method does not call anything external that you would need to pass in as a stub. Testing internal method calls is too tied to implementation details. Instead test the end result... I would simulate the click, then assert that the state has in fact changed either by `expect(renderedOutput.state().on).to.be.true` OR the end result of this state ie that the button has text in it `expect(renderedOutput.find('button').at(0).text()).to.be.equal('Search')` – alechill Mar 07 '17 at 11:53

1 Answers1

0

The problem here is enzyme considers handle search method as a constant. Try something like this. it should work

handleSearch(e){
    this.setState(prevState => ({
      on: !prevState.on
    }));
  }

 <button className="searchButton" onClick={(e) => this.handleSearch(e)}>{this.state.on ? 'Search' : null}</button>
duwalanise
  • 1,312
  • 1
  • 14
  • 24
  • This would have identical behaviour, except as the onClick handler is now an anonymous function, it will cause a re-render of the button component every time even if nothing else has changed. In this component as its just a small button then that will likely have no real performance impact, but if this was done higher up the tree, it can cripple performance. One to keep an eye out for – alechill Mar 07 '17 at 12:15
  • yeah that's true. So i usually bind function once in constructor and call it. that way will address the problem. – duwalanise Mar 07 '17 at 12:19
  • Yep good plan, the way the OP does it also works instead of binding in constructor, as they have used an arrow function when defining the method, so is already bound to the lexical `this`, scoping to the class – alechill Mar 07 '17 at 12:22