Модульное тестирование трансляции событий директив angularjs

Мне никогда раньше не приходилось тестировать мои директивы angularjs, а директивы, которые я написал для моей нынешней компании, используют события для передачи директив директивам и службам.

И поэтому я написал директиву, например. директива поиска.

<m-search />

Эта директива транслирует событие "searchbox-valuechanged" и ключ, теперь мне нужно написать для него тесты.

'use strict';

describe('<m-search>', function() {

  beforeEach(module('hey.ui'));
  var rootScope;
  beforeEach(inject(function($injector) {
    rootScope = $injector.get('$rootScope');
    spyOn(rootScope, '$broadcast');
  }));

  it("should broadcast something", function() {
    expect(rootScope.$broadcast).toHaveBeenCalledWith('searchbox-valuechanged');
  });

});

Обновить При изменении ввода

<input class="m-input m-input--no-border" type="search" placeholder="Search"
       ng-model="ctrl.searchValue"
       ng-model-options="{debounce: 100}"
       ng-change="ctrl.onChange({search: ctrl.searchValue})">

Он вызывает метод в контроллере директивы

vm.onChange = function (searchValue) {
  $rootScope.$broadcast('searchbox-valuechanged', {data: searchValue});
};

Как протестировать вещание?


person Joey Hipolito    schedule 18.05.2015    source источник
comment
Где обрабатывается событие searchbox-valuechanged? Вне директивы?   -  person Michael Benford    schedule 18.05.2015
comment
да, searchbox-valuechanged передается с использованием $rootScope, поэтому $rootScope является единственной зависимостью, а директивы полностью отделены друг от друга.   -  person Joey Hipolito    schedule 18.05.2015
comment
Что запускает трансляцию? Вам нужно воспроизвести это в своем тестовом коде.   -  person Phil    schedule 18.05.2015
comment
Хорошо, я отредактирую вопрос, кстати, это запускает трансляцию. 'ng-change="ctrl.onChange({search: ctrl.searchValue})">' +, который является частью шаблона, а в контроллере директив вызывает ctrl.onChange   -  person Joey Hipolito    schedule 18.05.2015


Ответы (1)


Вот как бы я это сделал...

describe('m-search directive', function() {
    var ctrl, // your directive's controller
        $rootScope; // a reference to $rootScope

    beforeEach(function() {
        // bootstrap your module
        module('hey.ui');

        inject(function($compile, _$rootScope_) {
            $rootScope = _$rootScope_;
            // see https://docs.angularjs.org/api/ngMock/function/angular.mock.inject#resolving-references-underscore-wrapping-

            // create an instance of your directive
            var element = $compile('<m-search></m-search')($rootScope.$new());
            $rootScope.$digest();

            // get your directive's controller
            ctrl = element.controller('mSearch');
            // see https://docs.angularjs.org/api/ng/function/angular.element#methods

            // spy on $broadcast
            spyOn($rootScope, '$broadcast').and.callThrough();
        });
    });

    it('broadcasts searchbox-valuechanged on change', function() {
        var searchValue = {search: 'search string'};
        ctrl.onChange(searchValue);

        expect($rootScope.$broadcast).toHaveBeenCalledWith(
            'searchbox-valuechanged', {data: searchValue});
    });
});

Вы заметите, что это вообще не зависит от шаблона вашей директивы. Я не верю, что функциональность шаблона находится в сфере модульного тестирования; это то, что лучше всего оставить для e2e-тестирования с помощью транспортира. Модульное тестирование — это тестирование API ваших компонентов, чтобы убедиться, что они делают то, для чего предназначены.

person Phil    schedule 18.05.2015
comment
не могу найти переменную $rootscope - person Joey Hipolito; 18.05.2015
comment
@JoeyHipolito К сожалению, я забыл сделать его доступным за пределами beforeEach. Исправлено сейчас - person Phil; 18.05.2015