Error: <toHaveBeenCalled> : Expected a spy, but got Function

11,051

I just run the following test and it works on [email protected]

fit('Spy on map works', () => {
        let someArray = [1, 3, 5];
        spyOn(someArray, 'map').and.callThrough();
        someArray.map(function(r){ console.log(r); });
        expect(someArray.map).toHaveBeenCalled();
 });

You might want to run this example to know if it works in your tests.

As I said in the comment your list map method overrides the list.values with a new array. Hence, the spy is not there anymore. try something like:

someArray.forEach((item, index) => {
                   someArray[index] = f(item);
});

To explain what is happening:

//WORKS
 fit('Spy on map works', () => {
    let someArray = [1, 3, 5];
    spyOn(someArray, 'map').and.callThrough();
    someArray.forEach((item, index) => {
        someArray[index] = (item + '_t');
    });
    someArray.map(function(r){ console.log(r); });
    expect(someArray.map).toHaveBeenCalled();
});
//FAILS because array is another object.
fit('Spy on map fails', () => {
    let someArray = [1, 3, 5];
    spyOn(someArray, 'map').and.callThrough();

    let tempArray = [];
    someArray.forEach((item, index) => {
        tempArray.push(item + '_t');
    });
    someArray = tempArray;

    someArray.map(function(r){ console.log(r); });
    expect(someArray.map).toHaveBeenCalled();
});

However, you could just spy on prototype. Something like that:

 spyOn(Array.prototype, 'map').and.callThrough();

And then, your test should work.

Share:
11,051
John
Author by

John

Updated on June 08, 2022

Comments

  • John
    John about 2 years

    Here is the test code

    var list = new List([1, 2, 3, 4]);
    var list2 = new List([5, 1]);
    
    beforeAll(function () {
      spyOn(list.values, 'map').and.callThrough();
    
      list.map(plusOne);
    });
    
    it('Array.prototype.map()', function () {
      expect(list.values.map).not.toHaveBeenCalled();
    });
    
    This results in the following error 1) List must not call native Array function Array.prototype.map()   Message:
        Error: <toHaveBeenCalled> : Expected a spy, but got Function.
        Usage: expect(<spyObj>).toHaveBeenCalled()
    
      class List {
        constructor(clist = []) {
            this.values = clist;
        }
        map(f) {
            var temp = [];
            this.values.forEach((item, index) => {
                       temp.push(f(item));
                    });
            this.values = temp;
            return this;
        }
    }
    module.exports = { List };
    

    I do not think this is a unit test fail as such because I get the same message whether I call not.tohaveBeenCalled() or toHaveBeenCalled().

    I am using node 8.9.4 and jasmine 2.8.0.

    I believe the syntax is correct because when I run others code against these tests they pass. But my code causes this error.

    My question is what does the above error mean? Regards,

  • John
    John over 6 years
    thanks for this. I upgraded jasmine. Same result. As I mentioned, I do have code from others where it works. So there is obviously a problem with my code that needs fixing. What I do not understand is what that error actually means. My class List has a map method. That contains a class variable of values which is an array. And the test is checking that the class uses List.map and not array.map. And the fact that I can remove the not and get the same error suggests that the test is not failing but that there is an error.
  • kimy82
    kimy82 over 6 years
    Could you paste your List class. Is the map function in List class reinstantiating the values array?
  • kimy82
    kimy82 over 6 years
    Yeah, the list map is overriding the values with a new array of objects. Hence, your spy is not applying to this new object.
  • John
    John over 6 years
    This is strange. When I run your test, it works. I have changed the code so that values is copied, emptied and then acted on and I get the same result of "expected a spy ...". I think I am doing something fundamentally wrong
  • John
    John over 6 years
    I can see the point you are making. But if I run another version of the code, it works. If I run my version of the code, then get error. If I take the code from another and paste the method into my code, it fails. The normal unit tests work. It is just spyOn which fails. Would you like to me put the code in a gist on GitHub?
  • kimy82
    kimy82 over 6 years
    yeah, put it on github