2015-09-22 4 views
9

В настоящее время мы пытаемся проверить наши угловые службы, которые используют обещания вернуть значения контроллерам. Проблема в том, что функции, которые мы прикрепляем к., Не вызываем в Жасмине.

Мы обнаружили, что добавление функции $ rootScope.digest() в функцию после возврата обещания позволяет синхронно выполнять обещания, но по-прежнему не работает для асинхронных обещаний.

код до сих пор

beforeEach(inject(function (Service, $rootScope) 
    { 
     service = Service; 
     root = $rootScope; 
    })); 

    it('gets all the available products', function (done) 
    { 
     service.getData().then(function (data) 
     { 
      expect(data).not.toBeNull(); 
      expect(data.length).toBeGreaterThan(0); 
      done(); 
     }); 
     root.$digest(); 
    }); 

В этом случае обещание вызывается нормально, но если это асинхронное это будет называться не потому, что обещание не готов к «переваривания» к тому времени корень. Вызывается $ digest().

Есть ли способ рассказать, когда обещание после решения принято, чтобы я мог вызвать дайджест? Или может быть что-то, что сделает это автоматически? Спасибо;)

Частичной службы мы должны проверить (обработка ошибок удалена):

var app = angular.module('service', []); 

/** 
* Service for accessing data relating to the updates/downloads 
* */ 
app.factory('Service', function ($q) 
{ 
    ... init 

    function getData() 
    { 
     var deffered = $q.defer(); 

     var processors = [displayNameProc]; 

     downloads.getData(function (err, data) 
     { 
      chain.process(processors, data, function (err, processedData) 
      { 
       deffered.resolve(processedData); 
      }); 
     }); 

     return deffered.promise; 
    } 
    ... 

В том случае, когда есть проблема, когда service.getData является асинхронным обещание решено, но функция прилагается к этому обещанию из тестового кода не вызывается, потому что корневой. $ digest уже вызван. Надеюсь, что это дает больше информации

Обход

var interval; 
beforeEach(inject(function ($rootScope) 
{ 
    if(!interval) 
    { 
     interval = function() 
     { 
      $rootScope.$digest(); 
     }; 
     window.setInterval(interval, /*timing*/); 
    } 
})); 

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

+0

Вы издевательский вашей службы и, следовательно, возвращенный обещание? – CainBot

+0

Нет. Я пытался проверить фактическое обслуживание. – BrendanM

+0

Если вы тестируете фактический сервис и внутренне используете службу $ http, то я считаю, что дайджест будет вызываться angularjs, когда удаленный вызов удастся или не удастся. – CainBot

ответ

0

вы должны двигаться утверждает за пределами тогда я верю:

beforeEach(inject(function (Service, $rootScope) 
{ 
    service = Service; 
    root = $rootScope; 
})); 

it('gets all the available products', function (done) 
{ 
    var result; 
    service.getData().then(function (data) 
    { 
     result = data; 
     done(); 
    }); 

    root.$digest(); 

    expect(result).not.toBeNull(); 
    expect(result .length).toBeGreaterThan(0); 
}); 

Обновление

Внесите комментарий plunkr, чтобы показать, как вы можете протестировать асинхронный вызов.

Добавлен $ таймаут к услуге:

var app = angular.module('bad-service', []); 

app.service('BadService', function ($q, $interval, $timeout) 
{ 
    this.innerPromise = function(){ 
     var task = $q.defer(); 
     console.log('Inside inner promise'); 

     $timeout(function() { 
     console.log('Inner promise timer fired'); 
     task.resolve(); 
     }, 500); 
     // $interval(function(){ 

     // }, 500, 1); 
     return task.promise; 
    } 
}); 

И я промывке $ таймаут до утверждения:

beforeEach(module('test')); 


describe('test', function(){ 
    var service, root, $timeout; 

    beforeEach(inject(function (Service, $rootScope, _$timeout_) 
    { 
     $timeout = _$timeout_; 
     console.log('injecting'); 
     service = Service; 
     root = $rootScope; 
    })); 

    /** 
    Test one 
    */ 
    it('Should work', function(done){ 
     console.log('Before service call'); 
     service.outerPromise().then(function resolve(){ 
     console.log('I should be run!'); 
     expect(true).toBeTruthy(); 
     done(); 
     }); 
     // You will have to use the correct "resolve" here. For example when using: 
     // $httpbackend - $httpBackend.flush(); 
     // $timeout- $timeout.flush(); 
     $timeout.flush(); 

     console.log('After service call'); 
    }); 
}); 
+0

К сожалению, это не будет работать в нашем случае, потому что getData является асинхронным, что означает, что результат будет быть нулевым к моменту достижения первого ожидания (результата) .nottoBeNull(); – BrendanM

+0

Это решение специфично для асинхронных вызовов; вы протестировали, если он не работает? Сочетание «done()»; и 'root. $ digest();' убедитесь, что ваш асинхронный вызов будет разрешен до вызова ожиданий. –

+0

Да, извините, я вижу, что теперь больно дать ему выстрел – BrendanM

Смежные вопросы