reactjssinonreactjs-testutilssinon-chai

Sinon.stub getting called in test, but expect to be called statement fails


I have a stateless react component that has an onClick method that I'm trying to test is getting called.

The way I'm doing it is to set a prop with a default value pointing towards the method that will be called in production, so that I can test the click event in my test through a sinon.stub().

So this is all gong well. The stub is getting called. I know this because I added .returns(console.log("called")); to the stub and see this printing out in the console.

But when it comes to expect(onClickStub).to.have.been.called, my test fails saying that it has not been called.

My code involves a stateless component, so I am wrapping it with a quick TestWrapper class for the purposes of testing. I'm not sure how the context is working out, but I don't think that's totally necessary for testing.

Here it all is:

function _handleTabChange(eventKey, id, tabsChange, e) {
  e.preventDefault();
  tabsChange({ id, eventKey });
  console.log("clicked");
}

const _Tab = ({ onClick = _handleTabChange, eventKey, children, ...props }, { activeKey, parentContainer, tabsChange }) => (
  <li className={classNames('b-tab', { active: eventKey === activeKey })} {...props}>
    <a href="#"
      role="tab"
      data-toggle="tab"
      onClick={onClick.bind(this, eventKey, parentContainer, tabsChange)}>
      {children}
    </a>
  </li>
);

  

it('onclick event', () =>{

    const props = {
      tabsAddContainer : sinon.spy(),
      tabsRemoveContainer : sinon.spy(),
      tabsChange : sinon.stub(),
      tabs : {},
      tabContainerID : 'company-management-tabs',
      onClick: sinon.stub.returns(console.log("HELLO")),
    }
    const onClickStub = sinon.stub.returns(console.log("HELLO"));
  
    class TestWrapper extends React.Component {
      render() {
        return <Tab {...props} {...context} />
      }
    }

    const renderTab = TestUtils.renderIntoDocument(
        <TestWrapper onClick={onClickStub} tabsChange={props.tabsChange} active={true} context={{tabsChange: function(){}, parentContainer:"parent-container"}}/>
    )

    const tabElements = TestUtils.scryRenderedDOMComponentsWithTag(renderTab, "a");
    console.log("tabElements", tabElements);
    TestUtils.Simulate.click(tabElements[0], {});
    
    expect(onClickStub).to.have.been.called

  });


Solution

  • Well, this had to do with the .bind in the onClick call. The solution was to organize the props to accept a sinon stub, but in all other, production cases, to call the _handleTabChange function by default.

    This meant that handleTabChange had to return a function.

    Now it correctly registers the sinon.stub in the test, and in production calls _handleTabChange without the need of a .bind.