У меня такой контроллер ...

 angular.module('jobBoard').controller('JobListController', ['$scope','$window', function($scope, $window){

    $scope.keywordPlaceholder = 'What kind of job?';
    $scope.locationPlaceholder = 'Where? (city, state or zip)';

    $scope.onResize = function(){
        if ($window.innerWidth <= 480){
            $scope.keywordPlaceholder = 'What?';
            $scope.locationPlaceholder = 'Where?';
        }
    }

    angular.element($window).bind('resize', function(){
        $scope.onResize();
        $scope.$apply();
    })

    $scope.onResize();
    $scope.loadJobs();
}]);

А это жасминовый тест ...

describe('JobListController', function(){
    var scope, controller;

    describe('binding resize to window', function(){
        var mockWindow = {
            resize: function(){}
        }

        beforeEach(inject(function($rootScope, $controller){
            scope = $rootScope.$new();
            $controller('JobListController', { $scope:scope, $window: mockWindow});
        }))

        it('binds to the resize function', function(){
            spyOn(scope, 'onResize');
            spyOn(scope, '$apply');
            mockWindow.resize();
            expect(scope.onResize).toHaveBeenCalled();
            expect(scope.$apply).toHaveBeenCalled();
        })
    })
})

Но это не соответствует ожиданиям scope.onResize. Я как сумасшедший гуглил, как правильно это сделать, но не могу найти правильный ответ. Есть идеи? Спасибо.

1
geoff swartz 6 Мар 2015 в 00:57

2 ответа

Лучший ответ

Если честно, я никогда этого не пробовал, поэтому не могу сказать, сработает ли это. Однако - вы путаете вызов функции с запуском события. Ваш оператор bind привязан к событию, а не к вызову функции.

Из документов MDN о событиях JavaScript вы должны можно сделать что-то вроде этого, чтобы создать событие с именем «изменение размера» и запустить его:

describe('binding resize to window', function(){
    // Get a DOM element (there's probably a better way to do this...)
    var mockWindow = angular.element('<div>')[0];
    // create the event
    var resizeEvent = new Event('resize');


    beforeEach(inject(function($rootScope, $controller){
        scope = $rootScope.$new();
        $controller('JobListController', { $scope:scope, $window: mockWindow});
    }))

    it('binds to the resize function', function(){
        spyOn(scope, 'onResize');
        spyOn(scope, '$apply');
        // call the event.
        mockWindow.dispatchEvent(event);
        expect(scope.onResize).toHaveBeenCalled();
        expect(scope.$apply).toHaveBeenCalled();
    })
})
1
Ed Hinchliffe 5 Мар 2015 в 22:37

Если вы хотите проверить, что вы прикрепляете к событию, служба Angular $window отлично подходит для этой цели:

describe('JobListController', function(){
  var scope, controller;

  describe('binding resize to window', function(){
    beforeEach(inject(function($rootScope, $controller){
      scope = $rootScope.$new();
      spyOn($window, 'addEventListener').and.callThrough();
      $controller('JobListController', { $scope:scope });
    }))

    it('binds to the resize function', function() {
      expect($window.addEventListener).toHaveBeenCalledWith('resize', scope.onResize);
    })
  })
})

В вашем контроллере выполните привязку, используя вместо этого addEventListener:

$window.addEventListener('resize', scope.onResize);

Это также позволяет проверить, когда вы отключаете событие:

it('stop listening to window resize', function () {
    compileDirective();
    spyOn($window, 'removeEventListener');

    scope.$destroy();

    expect($window.removeEventListener).toHaveBeenCalledWith('resize', scope.onResize);
});

После этого вы можете самостоятельно протестировать свою логику scope.onResize.

Плюсы:

  • Легко сделать.
  • Разрешить проверить развязку события
  • Хорошо работает в любом браузере (даже PhantomJS)

Минусы:

  • Он не проверяет взаимодействие между частями (событие, слушатель, обработчик). Для этого я полагаюсь на тесты более высокого уровня (например, E2E).
0
Julien Bérubé 29 Апр 2015 в 18:56