Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a spy with toHaveBeenCalledWith and a mutable array in Jasmine.js?

I have some code which calls a callback function with an array as single argument. After calling the callback, the code changes the array contents. It is similar to this code:

function myCode( callback ) {
    var someArray = [ 1, 2, 3, 4 ];
    callback( someArray );

    // change someArray in arbitrary ways
    someArray.splice( 2 );
    ...
}

Now, I want to verify that the callback is called with the correct array content. Using Jasmine.js I would write my spec like this:

describe( "My code", function() {
    var callback;

    beforeEach( function() {
        callback = jasmine.createSpy( "My callback" );
        myCode( callback );
    });

    it( "calls the callback and passes the correct array", function() {
        expect( callback ).toHaveBeenCalledWith( [ 1, 2, 3, 4 ] );
    });
});

This fails. The problem is, that Jasmine.js records the array but does not make a copy of it. Since the array is changed after the call, the expect()-Line fails, even though the actual call fulfilled the expectation. The same problem occurs with mutable objects.

How can I test such code?

like image 912
h2stein Avatar asked Oct 18 '12 22:10

h2stein


1 Answers

Jasmine does shallow copy the arguments passed on to the spy, which mean the arguments object will have reference to the same objects with which it has been called (in your case arguments will have the reference to someArray object only.

Jasmine code reference for spy implementation:

  spy = function() {
    callTracker.track({
      object: this,
      args: Array.prototype.slice.apply(arguments)
    });
    return spyStrategy.exec.apply(this, arguments);
  };

Deep copy of array (arguments) is not possible as a generic solution, problems are explained at link.

A solution to your problem could be writing your own callback and matcher for your specific use case, where you know what you have to copy (clone) exactly.

like image 172
user3037143 Avatar answered Oct 11 '22 11:10

user3037143