Ответ 1
Вам нужно ввести $rootScope
в свой тест и запустить $digest
.
Кажется, что promises не разрешают в тестах Angular/Jasmine, если вы не нажмете $scope.$digest()
. Это глупая ИМО, но это нормально, я работаю там, где это необходимо (контроллеры).
Ситуация, в которой я сейчас работаю, - это сервис, который может заботиться о каких-либо областях приложения, но он возвращает некоторые данные с сервера, но обещание, похоже, не решает.
app.service('myService', function($q) {
return {
getSomething: function() {
var deferred = $q.defer();
deferred.resolve('test');
return deferred.promise;
}
}
});
describe('Method: getSomething', function() {
// In this case the expect()s are never executed
it('should get something', function(done) {
var promise = myService.getSomething();
promise.then(function(resp) {
expect(resp).toBe('test');
expect(1).toEqual(2);
});
done();
});
// This throws an error because done() is never called.
// Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
it('should get something', function(done) {
var promise = myService.getSomething();
promise.then(function(resp) {
expect(resp).toBe('test');
expect(1).toEqual(2);
done();
});
});
});
Каков правильный способ протестировать эту функциональность?
Изменить: решение для справки. Очевидно, вы вынуждены вводить и переваривать $rootScope, даже если служба не использует его.
it('should get something', function($rootScope, done) {
var promise = myService.getSomething();
promise.then(function(resp) {
expect(resp).toBe('test');
});
$rootScope.$digest();
done();
});
Вам нужно ввести $rootScope
в свой тест и запустить $digest
.
всегда существует $rootScope, используйте его
inject(function($rootScope){
myRootScope=$rootScope;
})
....
myRootScope.$digest();
Итак, я все время борюсь с этим днем. Прочитав этот пост, я тоже почувствовал, что с ответом что-то есть, оказывается. Ни один из приведенных выше ответов не дает ясного объяснения, где и почему использовать $rootScope.$digest
. Итак, вот что я придумал.
Во-первых, почему? Вы должны использовать $rootScope.$digest
всякий раз, когда вы отвечаете на событие не-w500 > или обратный вызов. Это будет включать в себя чистые события DOM, события jQuery и другие сторонние библиотеки Promise, отличные от $q
, которые являются частью angular.
Во-вторых, где? В вашем коде, не ваш тест. Нет необходимости вводить $rootScope
в ваш тест, это необходимо только в вашем фактическом сервисе angular. Вот где все вышеизложенное не дает четкого ответа на вопрос, они показывают, что $rootScope.$digest
вызывается из теста.
Я надеюсь, что это поможет следующему человеку, который приходит долго, это одна и та же проблема.
Я удалил этот пост вчера, когда его проголосовали. Сегодня я продолжал эту проблему, пытаясь использовать ответы, любезно предоставленные выше. Итак, я жду своего ответа ценой очков репутации, и поэтому я его отменяю.
Это то, что вам нужно в обработчиках событий, которые не являются angular, и вы используете $q и пытаетесь протестировать Jasmine.
something.on('ready', function(err) {
$rootScope.$apply(function(){deferred.resolve()});
});
Обратите внимание, что в некоторых случаях его, возможно, придется обернуть в $timeout.
something.on('ready', function(err) {
$timeout(function(){
$rootScope.$apply(function(){deferred.resolve()});
});
});
Еще одно примечание. В исходных примерах проблем вы вызываете
done
в неподходящее время. Вы должны вызватьdone
внутри методаthen
(илиcatch
илиfinally
) обещания после того, как будет разрешено. Вы вызываете его до того, как обетование будет разрешено, что приводит к завершению предложенияit
.
Из документации angular.
https://docs.angularjs.org/api/ng/service/ $q
it('should simulate promise', inject(function($q, $rootScope) {
var deferred = $q.defer();
var promise = deferred.promise;
var resolvedValue;
promise.then(function(value) { resolvedValue = value; });
expect(resolvedValue).toBeUndefined();
// Simulate resolving of promise
deferred.resolve(123);
// Note that the 'then' function does not get called synchronously.
// This is because we want the promise API to always be async, whether or not
// it got called synchronously or asynchronously.
expect(resolvedValue).toBeUndefined();
// Propagate promise resolution to 'then' functions using $apply().
$rootScope.$apply();
expect(resolvedValue).toEqual(123);
}));