user1995781
user1995781

Reputation: 19463

AngularJS - Unit Test with Windows Scrolling

I have a directive that look like this:

angular.directive('myDirective', ['$window', function($window){
    return function (scope, element) {
        var w = angular.element($window);
        var top = element.offset().top-w.scrollTop();

        function adjustTop(){
            var oldtop = scope.top;
            var scrolltop = w.scrollTop();
            var winHeight = w.height();
            console.log("scrolltop:"+scrolltop);
            console.log("winHeight :"+winHeight);
            var newtop = top - scrolltop;
            if(newtop>15){
                scope.top = top - scrolltop;
            }else{
                scope.top = 15;
            }
            if(oldtop!=newtop){
                scope.$apply();
            }
        }

        w.bind('scroll', function () {
            adjustTop();
        });

        adjustTop();
    };
}]);

I want to do an unit test to detect its adjustment on the element top position based on the window scrolling.

Here are my questions:

  1. How can I mock to simulate the window scrolling in a unit test?
  2. How can I have the web-page document to be longer than browser height to enable scrolling simulation?

Update:

After taking Andrew's advice, this is my $window mock:

var mock$window;
beforeEach(module('my-app', function ($provide) {
        mock$window = {
          scrollTop : 200,
          height: 960
        };
        $provide.value('$window', mock$window);
    })
);

When I run the test, I am able to get the result of w.scrollTop(), but w.height() returns the error

Cannot use 'in' operator to search for 'height' in undefined.

Without mocking, I don't get any JavaScript error in the test, but the w.scrollTop() value is 0 and the w.height() is the browser window height of the PhantomJS browser running the test.

So, How can I get a w.height() mock works in unit tests?

Here is the sample of code to better illustrate the problem: http://jsfiddle.net/w4h5q5hr/

Upvotes: 1

Views: 6184

Answers (2)

Tom Feldmann
Tom Feldmann

Reputation: 39

Create spys for things you want to mock like:

spyOn($window, 'scrollTop').and.returnValue(100);

If you're mocking jQuery calls you can use $.fn like so:

spyOn($.fn, 'scrollTop').and.returnValue(100);

Upvotes: 2

Andrew Eisenberg
Andrew Eisenberg

Reputation: 28757

Your best bet is to provide a mock $window object. You can provide a mock $window in a beforeEach clause. The idea here is that you are unit testing and you can just assume that $window works as designed.

Something like this will work:

var mock$window, scrollTop = 100;
beforeEach(module('my-app', function ($provide) {
            mock$window = {
              scrollTop : function() { return scrollTop; }
              bind : function(eventName, cb) { ... }
            };
            $provide.value('$window', mock$window);
        })
);

Then, in your tests, you can:

  • spy on the window methods
  • ensure that bind is called on the proper event
  • ensure that adjustTop works appropriately with different scrollTop values.

This is sufficient for unit testing your code, but if you want to truly see that this code works in an actual application setting, you may want to try something like protractor.

Upvotes: 2

Related Questions