How can I use Jest to spy on a method call?
I recently wanted to test that some custom method gets conditionally called in the componentDidMount
method of a React component.
componentDidMount() {
if (this.props.initOpen) {
this.methodName();
}
}
I'm using Jest as my testing framework, which includes jest.fn()
for mocks/spies. I've read that this would be fairly trivial to test with Sinon, by doing something like the following:
sinon.spy(Component.prototype, "methodName");
const wrapper = mount(<Component {...props} />);
expect(wrapper.instance().methodName).toHaveBeenCalled();
I'm trying to recreate this with Jest like so:
Component.prototype.methodName = jest.fn();
const wrapper = mount(<Component {...props} />);
expect(wrapper.instance().methodName).toHaveBeenCalled();
This code fails and throws the following error:
jest.fn() value must be a mock function or spy.
Received:
function: [Function bound mockConstructor]
Is it possible to test this functionality with Jest? And if so, how?
Solution 1:
The key is using jests spyOn
method on the object's prototype
. It should be like this:
const spy = jest.spyOn(Component.prototype, 'methodName');
const wrapper = mount(<Component {...props} />);
wrapper.instance().methodName();
expect(spy).toHaveBeenCalled();
As found here e.g.: Test if function is called react and enzyme
Please note it is also best practice to clear the spied function after each test run
let spy
afterEach(() => {
spy.mockClear()
})
https://facebook.github.io/jest/docs/en/jest-object.html#jestclearallmocks
Solution 2:
I know its a bit late, but I came across this and would suggest that to test componentDidMount
initiates the call to your nested method that your test should look something like:
Module
componentDidMount() {
if (this.props.initOpen) {
this.methodName();
}
}
Test - Good
it('should call methodName during componentDidMount', () => {
const methodNameFake = jest.spyOn(MyComponent.prototype, 'methodName');
const wrapper = mount(<MyComponent {...props} />);
expect(methodNameFake).toHaveBeenCalledTimes(1);
});
If you call componentDidMount
then the assertion that methodName
was called via componentDidMount
is more valid.
Test - Bad
it('should call methodName during componentDidMount', () => {
const spy = jest.spyOn(Component.prototype, 'methodName');
const wrapper = mount(<Component {...props} />);
wrapper.instance().methodName();
expect(spy).toHaveBeenCalled();
}
By writing the test like this - you call the method and then assert that it was called. Which of course it will have given you just called it.