I want to mock a constructor function named Dog
Dog = jest.fn(()=>{
return{
name:"spike",
bark:function(){
return "bhow " +this.name;
}
}
})
function foo(){
const d = new Dog();
return d.bark();
}
test("testing foo",()=>{
const result = foo();
expect(Dog).toHaveBeenCalledTimes(1);
expect(result).toBe("bhow spike");
expect(Dog.mock.instances.length).toBe(1);
expect(Dog.mock.instances[0].name).toBe("spike");
//this test failed with expected spike received undefined
});
but the expect(Dog.mock.instances[0].name).toBe("spike");
fails with expected spike received undefined
jest version 24.8.0 node version 10.15.0
When you call a function with the new
operator, a new object is created and passed as the execution context (aka this
) to the function. This object is then implicitly returned if the function does not return anything explicitly. You can have a look at the detailed explanation.
Also, take into account that an arrow function can never be used as a constructor.
From Jest documentation for mock functions:
mockFn.mock.instances
An array that contains all the object instances that have been instantiated from this mock function using new.
So, Jest mock functions are storing in the instances
attribute the list of object instances that are being passed to the function (the newly created object that is passed as this
to the function) every time you call it with the new
operator.
But your constructor is not using the this
object, so it remains empty. That is why when you check Dog.mock.instances[0].name
you are getting undefined
. If you change slightly your constructor to assign the name attribute to the this
object you can see that your test passes:
Dog = jest.fn(function() {
this.name = "spike";
return{
name:"spike",
bark:function(){
return "bhow " +this.name;
}
}
})
Returning explicitly an object from a constructor function as you are doing is rarely used. The most usual way to define a constructor is to assign its properties to the this
object. So, a solution to your problem would be to change your constructor function to:
Dog = jest.fn(function() {
this.name = "spike";
this.bark = function(){
return "bhow " +this.name;
}
})
Another solution, if you don't want to change the definition of your constructor function, would be to use the results
attribute of the mock function in your test:
test("testing foo",()=>{
const result = foo();
expect(Dog).toHaveBeenCalledTimes(1);
expect(result).toBe("bhow spike");
expect(Dog.mock.instances.length).toBe(1);
expect(Dog.mock.results[0].value.name).toBe("spike");
});