How to simulate window scrolling in a Angular Unit Test?

11,266

Had the same issue recently. For the scrolling to work, you will need to set some dimensions on the body tag, so the window can be scrolled.

var scrollEvent = document.createEvent( 'CustomEvent' ); // MUST be 'CustomEvent'
scrollEvent.initCustomEvent( 'scroll', false, false, null );

var expectedLeft = 123;
var expectedTop = 456;

mockWindow.document.body.style.minHeight = '9000px';
mockWindow.document.body.style.minWidth = '9000px';
mockWindow.scrollTo( expectedLeft, expectedTop );
mockWindow.dispatchEvent( scrollEvent );

Unfortunately this does not work in PhantomJS.

If you are running your tests on Travis CI, you can also use Chrome by adding the following to your .travis.yml

before_install:
   - export CHROME_BIN=chromium-browser
   - export DISPLAY=:99.0
   - sh -e /etc/init.d/xvfb start

And a custom Chrome launcher in your karma config:

module.exports = function(config) {
    var configuration = {

        // ... your default content

        // This is the new content for your travis-ci configuration test
        //  Custom launcher for Travis-CI
        customLaunchers: {
            Chrome_travis_ci: {
                base: 'Chrome',
                flags: ['--no-sandbox']
            }
        },

        // Continuous Integration mode
        // if true, it capture browsers, run tests and exit
        singleRun: true 
    };

    if(process.env.TRAVIS){
        configuration.browsers = ['Chrome_travis_ci'];
    }

    config.set( configuration );

};
Share:
11,266
user1906437
Author by

user1906437

Updated on June 07, 2022

Comments

  • user1906437
    user1906437 almost 2 years

    How can you simulate or mock window scrolling in a Jasmine Unit Test and or set a window.pageYOffset property?

    I am using Angular 1.3, Jasmine 2.1 + Karma 0.12.28 and PhantomJS 1.9.12

    This is my directive:

    'use strict';
    (function () {
    angular
      .module('myApp')
      .directive('scrollNews', scrollNews);
    
      function scrollNews(){
    
        var directive = {
          restrict: 'A',
          scope: false,
          link: link
        };
    
        return directive;
    
        function link(scope, element) {
          scope.limit = 2;
          //add one to the limit
          scope.loadMore = function() {
            scope.limit += 1;
          };
    
          var raw = element[0];
          angular.element(window).on('scroll', function () {
            var scrollFrontier = this.pageYOffset + 800;
            // when scrollFrontier has reached raw.scrollHeight, run loadMore()
            if (scrollFrontier >= raw.scrollHeight) {
              scope.loadMore(); // run the function
              scope.$digest(); // update the HTML
            }
          });
        }
      }
    })();
    

    And this is my testSpec:

    describe('Directive: scroll news', function(){
    
      var element, $scope, $window;
    
      beforeEach(module('myApp'));
    
      beforeEach(inject(function($compile, $rootScope, _$window_){
        $scope = $rootScope;
        $window = _$window_;
    
        element = angular.element('<div scroll-news></div>');
        $compile(element)($scope);
        $scope.$digest();
      }));
    
      it('should have a limit of 2 when no scrolling have occurred', function(){
        expect($scope.limit).toBe(2);
      });
    
      it('should add one to the limit with loadMore function', function(){
        $scope.loadMore();
        expect($scope.limit).toBe(3);
      });
    
      it('should run loadMore() when scrolling has reached a specific height', function(){
        element.scrollHeight = 1400;
    
        var spy = spyOn($window, 'scrollTo');
        $window.scrollTo(0, 1400);
        expect(spy).toHaveBeenCalled();
    
       expect($scope.limit).toBe(3); // Logs: Expected 2 to be 3. - so loadMore() have not called
     });
    });
    

    I want to simulate or mock a window scroll event to the element.scrollHeight, because if these two reaches the same height my directive runs the loadMore() function. But how can I make unit test of that?

    Btw the directive works fine in production :)