Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 500
seansean11 Avatar asked Apr 06 '17 03:04

seansean11


People also ask

How do you spy a method in Jest?

To spy on an exported function in jest, you need to import all named exports and provide that object to the jest. spyOn function. That would look like this: import * as moduleApi from '@module/api'; // Somewhere in your test case or test suite jest.

What is difference between mock and spy Jest?

The difference is that in mock, you are creating a complete mock or fake object while in spy, there is the real object and you just spying or stubbing specific methods of it. When using mock objects, the default behavior of the method when not stub is do nothing.

What is Jest fn ()?

The jest. fn method allows us to create a new mock function directly. If you are mocking an object method, you can use jest.


2 Answers

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

like image 177
Jonathan Avatar answered Sep 18 '22 06:09

Jonathan


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.

like image 37
hloughrey Avatar answered Sep 19 '22 06:09

hloughrey