Как проверить поведение в функции ссылки директивы

В некоторых моих директивах я добавляю функции в область для обработки логики, специфичной для этой директивы. Например:

link: function(scope, element, attrs) {
         scope.doStuff = function() {
            //do a bunch of stuff I want to test
         }        
      }

Как мне пройти тестирование этой функции? Я googled вокруг для того, чтобы проверить директиву, но вещи, которые я нашел, были больше связаны с тестированием изменений в элементе. Я могу, конечно, скомпилировать свою директиву перед каждым из моих тестов, но это уничтожит мой охват каждый раз. Я хочу проверить функцию как свойства в моих изменениях области.

Есть ли способ получить объект, который возвращается из определения директивы? Затем я мог просто вызвать функцию связи напрямую и проверить поведение каждой из функций, определенных в области. Есть ли лучший способ сделать все это?

Я использую Jasmine для запуска своих тестов, и я хочу настроить мою область в функциях describe, поэтому я могу иметь несколько it для тех же данных области.

Ответ 1

В принципе, вместо того, чтобы тестировать функцию связи, вы должны тестировать результат директивы программно. Что бы вы сделали, это написать директиву для строки и использовать $compile, чтобы angular обработать ее. Затем вы проверяете выход, чтобы убедиться, что все правильно подключено.

Angular источник полон хороших примеров того, как это сделать... например Angular проверка директивы ngRepeat

Вы можете видеть, что они делают, настраивая директиву, меняя область (в данном случае $rootScope), убедившись, что она $digest ed, а затем тестирует DOM, которую она выводит, чтобы убедиться, что все подключено правильно. Вы также можете проверить, что в области действия, если директива меняет это.

Тест для ngClick также довольно интересен, потому что он показывает тестирование взаимодействия с браузером и влияет на область действия.

Для полноты, здесь фрагмент из тестов ngClick, который, я думаю, подводит итог, проверяя директиву достаточно хорошо:

 it('should get called on a click', inject(function($rootScope, $compile) {
   element = $compile('<div ng-click="clicked = true"></div>')($rootScope);
   $rootScope.$digest();
   expect($rootScope.clicked).toBeFalsy();

   browserTrigger(element, 'click');
   expect($rootScope.clicked).toEqual(true);
 }));

Итак, в случае вашей функции scope.doStuff я бы не стал проверять, что она делает, насколько я бы тестировал все, что затронуло ее область действия, а затем выполнял элементы DOM.

Ответ 2

Я решил эту проблему немного по-другому.

Если у вас есть очень простая функция ссылок в вашей директиве, и вам не нужен третий аргумент (attrs), просто избавитесь от функции ссылки и назначьте директиву контроллер.

app.directive('loadIndicator', function() {
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'blahblah/indicator.html',
    controller: 'LoadIndicatorController'
  };
});

так же, как у вас есть аргументы для области и элемента в функции директивной ссылки, эти 2 аргумента могут быть введены в простой в тестировании контроллер как $scope и $element.

Если вы способны создавать контроллеры и модулировать эти контроллеры, тогда это будет очень легко сделать.

Ответ 3

При необходимости можно напрямую unit test использовать метод ссылки для директивы. См. Тестер модулей модуля angular: "Проверка конфигурации директивы"

http://bverbist.github.io/angular-ice/#/unitTester

пример использования: https://github.com/bverbist/angular-ice/blob/master/app/components/icebank/bank-account-number-directive_link_test.js

В вашем случае вы можете сохранить ссылку на объект области, который вы передаете методу директивной ссылки, а затем вы можете непосредственно протестировать функцию doStuff в этой области.

Ответ 4

Как указано в ответе на комментарий к @sqlexception. Вам просто нужно получить представление о области действия директивы, что делать не сложно. То, что вы не хотите делать, это изменить свой код, чтобы удовлетворить ваши тесты, так как это должно быть наоборот.

Чтобы получить область действия директивы, просто выполните ее следующим образом:

var element = $compile(<directive html>).($scope)

где $scope объявляется с помощью $scope = $rootScrope.$new(). Теперь мы можем получить область выделения, выполнив element.scope()

Недавно я написал короткую запись в блоге об этом, найденном здесь Тестирование связующей функции  с помощью плункера, чтобы помочь: