问题
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.
回答1:
For this kind of tests, the common path is to call your handler methods on your component instance instead of simulating the event.
You can be sure the onClick
prop is test by the React team, what you can check is what happens when "they" call your handler.
This also allows you to use shallow rendering which at least for me is much faster. You can get a reference to the instance easily with the instance()
method in your wrapper, and you can then call your handler and spy on whatever you want.
const wrapper = mount(<MyComponent />)
const instance = wrapper.instance()
instance.clickHandler()
//assert whatever
In fact, probably attaching your spies to the instance`s methods (that have already been binded) will do the trick as well. :)
http://airbnb.io/enzyme/docs/api/ReactWrapper/instance.html
Hope it helps!
来源:https://stackoverflow.com/questions/42016405/cant-spy-on-an-event-handler-even-though-i-can-spy-on-other-methods