Жасмин шпионит за $rootScope

Проблема:
 – использование AngularJs
 – наличие реализованного сервиса
 – попытка протестировать его с помощью Jasmine

Вот как выглядит мой сервис:

angular.module('app.common').service('StateInterceptor',['$state','$rootScope',function($state,$rootScope){
    $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){/*stuffs*/}

}

и вот как я пытаюсь проверить, был ли вызван $rootScope.$on:

describe("Testing StateInterceptor service", function(){
var $state, $rootScope, $scope, StateInterceptor;

beforeEach(module('app.common'));

beforeEach(inject(function($injector) {
    $rootScope = $injector.get("$rootScope");
    spyOn($rootScope, "$on");

    $state = $injector.get("$state");

    StateInterceptor = $injector.get("StateInterceptor");
}));

it("WHEN created THEN it should call '$rootScope.$on' event listener", function(){
    //expect($rootScope.$on).toHaveBeenCalled(); //not working neither
    expect($rootScope.$on).toHaveBeenCalledWith("$stateChangeStart", jasmine.any(Function));
});

У меня есть сообщение об ошибке, говорящее:

Ожидалось, что spy $on будет вызван с... (blabla), но он так и не был вызван.

Я пробовал почти все, например: - создание rootscope в этом было: $rootScope = $rootScope.$new(); - шпионить $rootScope.$on вот так: spyOn($rootScope.prototype, "$on")

но ни один не работал. Кто-нибудь знает, как проверить это правильно?

Редактировать1:

исходный код, похоже, работает, поэтому я вставил сюда именно тот код, который у меня есть. Итак, мой сервис выглядит именно так:

angular.module('app.common').service('StateInterceptor',['$state','$rootScope',function($state,$rootScope){
    var self = this;
    self.bootstrapped = false;
    self.changeStart = [];


    self.init = function(){
        if(!self.bootstrapped){
            $rootScope.$on('$stateChangeStart',
                function(event, toState, toParams, fromState, fromParams){
                /*staffs*/
                }
            );
        }
    }
    self.bootstrapped = true;

    self.init();
    return self;
}]);

Редактировать2:

Я добавил несколько console.log, чтобы увидеть, как выполняется код:

beforeEach(inject(function($injector) {
    $rootScope = $injector.get("$rootScope");
    spyOn($rootScope, "$on");

    $state = $injector.get("$state");

    StateInterceptor = $injector.get("StateInterceptor");
}));

И для кода первой строки в функции self.init:

console.log("init runs");

И результат: «инициализация выполняется» «до» «после»

Странный! Любая идея, почему это?


person Iamisti    schedule 29.12.2014    source источник
comment
Пытался воспроизвести его здесь на основе вашего кода, и, похоже, он работает: ?p=предварительный просмотр   -  person tasseKATT    schedule 29.12.2014
comment
вы правы, проверьте мое обновление выше   -  person Iamisti    schedule 29.12.2014
comment
Это точный код? Потому что есть синтаксические ошибки.   -  person tasseKATT    schedule 29.12.2014
comment
извините, в слушателе есть вещи, конечно. Я мог удалить больше, чем хотел. Проверь сейчас.   -  person Iamisti    schedule 29.12.2014
comment
но я предполагаю, что проблема будет заключаться в том, что вызов beforeEach(module(app.common)) также инициализирует службу, и код запускается в этом разделе, прежде чем я добавлю службу в свой набор тестов.   -  person Iamisti    schedule 29.12.2014
comment
но прав ли я в том, что каждый сервис angularJS является синглтоном? Так что нет необходимости делать это.   -  person Iamisti    schedule 29.12.2014
comment
Кажется, все еще работает: plnkr.co/edit/jq4S436NOyZ7hZSnqmzS?p=preview   -  person tasseKATT    schedule 29.12.2014
comment
beforeEach(module('app.common')) не будет инициализировать службу. Он не будет создан, пока кто-то не попросит об этом (этот экземпляр будет кэширован и использован повторно).   -  person tasseKATT    schedule 29.12.2014
comment
Спасибо tasseKATT! Поэтому после того, как я понял, что это должно работать, я провел более масштабное исследование модуля. Был еще один сервис, который использует этот сервис. Поэтому вызов «beforeEach(module(app.common))» вызвал StateInterceptor, прежде чем я смог его протестировать.   -  person Iamisti    schedule 29.12.2014
comment
Итак, я внес изменения, и теперь это работает!   -  person Iamisti    schedule 29.12.2014
comment
Если вы создадите ответ, я могу принять его как решение, потому что вы помогли мне выяснить причину.   -  person Iamisti    schedule 29.12.2014
comment
Не за что :) Я думаю, будет лучше, если вы сами опубликуете ответ, описывающий, в чем проблема, поскольку я никогда не давал реального решения :)   -  person tasseKATT    schedule 29.12.2014


Ответы (2)


Попробуйте вызвать $broadcast для события $stateChangeStart, оно должно автоматически войти в $on().

person Suneet Bansal    schedule 29.12.2014
comment
Он хочет проверить, что служба устанавливает прослушиватель событий, а не то, что $on вызывается при запуске $broadcast. - person tasseKATT; 29.12.2014
comment
но $broadcast отправляет события, пока $on их прослушивает, не так ли? - person Iamisti; 29.12.2014

Прежде всего, большое спасибо tasseKATT за помощь. Он был парнем, который привел меня к решению.

Проблема заключалась в том, что у меня была другая функция в этом модуле, которая запускается сразу же, как я ввожу модуль в свой набор тестов с помощью «beforeEach (module («app.common»))».

Вот как выглядела другая функция:

angular.module('app.common').run(function($q,StateInterceptor,$modal){
  //stuffs, but pls notice that it injects the StateInterceptor which caused the problem!
});

Поэтому я поместил это в другой модуль и сделал его зависимым от другого.

person Iamisti    schedule 29.12.2014