Tuesday, December 20, 2016

Testing "this" with Jasmine

I had cause to test a function that references this in JavaScript and, although it ended up being easy, it took some figuring to get there.  Rather than have to figure it all out again (and maybe to save someone else some trouble, too) I'm putting my solutions here (yes, there are two solutions).

Here is the function I needed to test:
$scope.dataBound = function(e) {
    var data = this.dataSource.data();
    for (var i = data.length; --i >= 0;) {
        if (!data[i].IsBundle) {
            var row = $('#grid')
                .data('kendoGrid')
                .tbody.find('tr[data-uid="' + data[i].uid + '"]');
            $(row).find('td.k-hierarchy-cell .k-icon').removeClass();
        }
    }
};

The first - and easiest - solution is to set whatever you need on scope.  In Angular, when this is referenced, it's referring to scope so in my case I was using this.dataSource.data() so I was able to just set an object directly on scope called dataSource that had a data function.
it('should set this on scope', function() {
    // arrange
    scope.dataSource = {
        data: function() {
            return [];
        }
    };
    spyOn(scope.dataSource, 'data').and.callThrough();

    // act
    scope.dataBound();

    // assert
    expect(scope.dataSource.data).toHaveBeenCalledTimes(1);
});

The second - and in my opinion more correct - solution is to invoke the function using call and pass whatever you want this to be as your first parameter.
it('should set pass this using call', function() {
    // arrange
    var thisToSet = {
        dataSource: {
            data: function() {
                return [];
            }
        }
    };
    spyOn(thisToSet.dataSource, 'data').and.callThrough();

    // act
    scope.dataBound.call(thisToSet);

    // assert
    expect(thisToSet.dataSource.data).toHaveBeenCalledTimes(1);
});

They're pretty similar, but I prefer using call because it should work outside Angular as well.

Mozilla has a pretty sweet explanation of this and how to use it in case you want more detailed information.

No comments:

Post a Comment