Тезисно выкладываю некоторые ключевые моменты по тестированию AngularJS директив.
Подготовительные действия
- ставим тест-драйвер Karma
- определяемся и подключаем к проекту тест-фреймворк (варианты Mocha, Jasmine)
- подключаем к проекту вспомогательную библиотеку angular-mocks
Написание сценария
подключаем Angular-модуль:
[javascript]beforeEach(module(‘myapp’));[/javascript]
подключаем шаблон (предварительно скомпилированный с помощью html2js):
[javascript]beforeEach(module(‘path/to/template’));[/javascript]
инжектим сервисы:
[javascript]
var $timeout, $rootScope;
beforeEach(inject(function(_$timeout_, _$rootScope_){
$timeout = _$timeout_;
$rootScope= _$rootScope_;
}));[/javascript]
прошу обратить внимание на нижнее подчеркивание, которое используется в Ангуляре для удобства и инжектит одноименный сервис.
либо инжектим инжектор и с помощью него уже получаем сервисы:
[javascript]
var $timeout, $rootScope;
beforeEach(inject(function($injector){
$timeout = $injector.get(‘$timeout’);
$rootScope= $injector.get(‘$rootScope’);
}));[/javascript]
для создания нового $scope делаем:
[javascript]
var $scope = $rootScope.$new()
[/javascript]
компиляция директивы для тестирования:
[javascript]
var element = $compile(‘<my-directive></my-directive>’)($scope);
[/javascript]
при этом не забываем инжектить сервис $compile
получение изолированного $scope:
[javascript]
var isolatedScope = element.children().scope()
[/javascript]
либо (работает начиная с версии 1.2):
[javascript]
var isolatedScope = element.isolateScope()
[/javascript]
чтобы запустить все колбэки в таймАут-сервисах:
[javascript]
$timeout.flush()
[/javascript]
чтобы промисы внутри приложения отрезолвились необходимо вручную делать:
[javascript]
scope.$apply();
[/javascript]
если что-то забыл – пиши в комментариях – дополню.
UPD:
подмена сервисов (замена мок-вариатом):
[javascript]
beforeEach(module(function ($provide){
$provide.service(‘SameNameWithRealService’, function(){
//код вашего мок-сервиса
});
}));
[/javascript]
использование “шпионов” для проверки вызова методов:
[javascript]
//переопределение внутреннего метода
$scope.someMethod = sinon.spy();
//вызов внешнего метода, который должен вызвать первый
$scope.someOtherMethod()
//проверка
expect($scope.someMethod.called).equal(true);
[/javascript]