John
John

Reputation: 1773

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

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,

Upvotes: 5

Views: 15163

Answers (1)

kimy82
kimy82

Reputation: 4495

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.

Upvotes: 4

Related Questions