Is it possible to stub out or spy on the setState method in React when doing unit tests?

intuition17 picture intuition17 · Apr 30, 2017 · Viewed 8.6k times · Source

I have the following function in my component:

method(args) {
 fetch(args)
  .then((response) => {
    this.setState({
      element: response
      error: false
    });
  })
  .catch((error) => {
    this.setState({
      error: true
    });
  });
}

I am trying to write a unit test for it so I have mocked out the fetch call using fetch-mock with a custom response. I want to check if the state was updated when this method is called and it doesn't seem to be working. I am using enzyme, expect, and sinon and have been unsuccessful in getting the spy to be called when I set component.setState = sinon.spy or stubbing it out. How can I check to see if setState was called with certain elements or is my approach to unit testing this wrong?

Answer

Will picture Will · Oct 4, 2017

It appears that you'll need to spy on/stub out setState in the prototype before instantiating your component. I was having a similar issue where simply spying on the setState method of an instance did not work. Based on https://medium.com/@tjhubert/react-js-testing-setstates-callback-907df1fe720d, here's an approach for sinon:

Component.js

...
method {
  this.setState({property:'value'})
}
...

Component.test.js

...
const setState = sinon.stub(Component.prototype, ‘setState’);
const component = shallow(<Component />);
component.instance().method();
expect(setState).to.be.calledOnce;
...

Note: my use case was using jasmine, and eschews rendering to test behavior, so the solution I know works looks like:

Component.prototype.setState = jasmine.createSpy();
const sut = new Component();
sut.method();
expect(sut.setState).toHaveBeenCalledWith({property:'value'});