I want to test an event handler in React using Jest/Jasmine/Enzyme.
MyComponent.js:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.clickHandler = this.clickHandler.bind(this);
this.otherMethod = this.otherMethod .bind(this);
}
clickHandler() { this.otherMethod(); }
otherMethod() {}
render() { return <div onClick={this.clickHandler}/>; }
}
export default MyComponent;
MyComponent.test.js:
import React from 'react';
import {mount} from 'enzyme';
import MyComponent from './MyComponent';
it('should work', () => {
const componentWrapper = mount(<MyComponent/>);
const component = componentWrapper.get(0);
spyOn(component, 'otherMethod' ).and.callThrough();
spyOn(component, 'clickHandler').and.callThrough();
componentWrapper.find('div').simulate('click');
expect(component.otherMethod ).toHaveBeenCalled(); // works
expect(component.clickHandler).toHaveBeenCalled(); // does not work
});
In spite of the fact that I think I'm spying on the two component methods identically, one of them (for otherMethod
) works while the other (for clickHandler
) does not. I clearly am calling clickHandler
as otherMethod
wouldn't be called if I wasn't, but toHaveBeenCalled
isn't being picked up for clickHandler
somehow. Why?
I understand that I don't really have to use either .bind(this)
or .and.callThrough()
on otherMethod
but I use both just to treat the two methods identically and using them on otherMethod
shouldn't actually make any difference.
This other SO answer states that I have to spy on a function before attaching it as a listener. If this is my problem then I don't know how to resolve it: The spyOn
syntax requires the object that the method is a property of (component
in this case) but using component
requires prior mounting of MyComponent
which forces me to attach the listener first.
It may be relevant that my code uses React (and thus I include reactjs
as a question tag) but somehow I doubt it.