Trying to spy (Jasmine) on Array.prototype methods causes stack overflow

两盒软妹~` 提交于 2019-12-22 05:41:51

问题


This is pretty odd. Using the testem runner with jasmine2 and the following spec executes (though it correctly flags that there are no expectations):

describe('Spying on array.prototype methods', function(){
  it('should work this way', function(){
    spyOn( Array.prototype, 'push' ).and.callThrough();
    // expect(1).toBe(1);
  });
});

However, add an expect (any expect!) and it causes the stack to overflow with the following message in the testem console: RangeError: Maximum call stack size exceeded. at http://localhost:7357/testem/jasmine2.js, line 980 The html report page gets up to the spec and then hangs without showing any actual results.

Ultimately I'd like to do something like this:

describe('Some structure.method', function(){
  it('does not use native push', function(){
    spyOn( Array.prototype, 'push' ).and.callThrough();
    [].push(1); // actually more like `myStructure.myMethod('test')`
    expect( Array.prototype.push ).not.toHaveBeenCalled();
  });
});

Thanks in advance to anyone who can shed light on this oddity. Can I not spy on native prototypical methods?


回答1:


When you spy on something jasmine creates a wrapper inorder to track the invocation of that function. Here when you spy on the prototype method basically even the push operation in jasmine itself invokes the spy instead of the actual push method on the array and it causes an infinite loop.

When you call [].push(1) it actually calls the tracker like below:

   spy = function() {
    callTracker.track({ //<-- Calls tracker to track invocation
      object: this,
      args: Array.prototype.slice.apply(arguments)
    });

which in turn calls the call tracker and pushes the call context to its internal tracker array and goes in an recursive loop till the call stack blows out.

this.track = function(context) {
  calls.push(context); //Now this again calls the spy
};

Instead if you spy on the method on array instance, you wont have this issue, since it creates a spy wrapper for the push property of that array instance (or in other words reference (currently inherited from the Array prototype) held by push of that instance gets overwritten by the new function reference of the spy created by jasmine): example:

it('does not use native push', function(){
  var arr = [];
  spyOn(arr, 'push' ).and.callThrough();
  arr.push(1);
  expect(arr.push).toHaveBeenCalledWith(1);
});

But as a real use case (at least i never had to) you could always check for the length of the target array and get the last item to compare against after a specific operation. You probably would never need to spy on native methods ( atleast not an array :) ), instead test against the object of your interest and spy on those target methods.



来源:https://stackoverflow.com/questions/30769204/trying-to-spy-jasmine-on-array-prototype-methods-causes-stack-overflow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!