Il semble que les promesses ne se résolvent pas dans les tests Angular/Jasmine sauf si vous forcez une $scope.$digest()
. C'est idiot IMO mais très bien, j'ai ça qui fonctionne le cas échéant (contrôleurs).
La situation dans laquelle je me trouve maintenant est que j'ai un service qui se soucie moins des étendues de l'application, tout ce qu'il fait, il renvoie des données du serveur mais la promesse ne semble pas se résoudre.
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();
});
});
});
Quelle est la bonne façon de tester cette fonctionnalité?
Edit: Solution pour référence. Apparemment, vous êtes obligé d'injecter et de digérer $ rootScope même si le service ne l'utilise pas.
it('should get something', function($rootScope, done) {
var promise = myService.getSomething();
promise.then(function(resp) {
expect(resp).toBe('test');
});
$rootScope.$digest();
done();
});
Vous devez injecter $rootScope
dans votre test et déclenchez $digest
dessus.
il y a toujours $ rootScope, utilisez-le
inject(function($rootScope){
myRootScope=$rootScope;
})
....
myRootScope.$digest();
De la documentation 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);
}));
J'ai donc du mal avec tout cet après-midi. Après avoir lu ce post, j'ai moi aussi senti qu'il y avait quelque chose qui clochait dans la réponse; Aucune des réponses ci-dessus ne précise clairement où et pourquoi utiliser $rootScope.$digest
. Alors, voici ce que j'ai trouvé.
D'abord pourquoi? Vous devez utiliser $rootScope.$digest
chaque fois que vous répondez d'un événement ou d'un rappel non angulaire. Cela inclurait des événements DOM purs, des événements jQuery et d'autres bibliothèques Promise tierces autres que $q
qui fait partie de l'angulaire.
Deuxièmement, où? Dans votre code, PAS votre test. Il n'est pas nécessaire d'injecter $rootScope
dans votre test, il n'est nécessaire que dans votre service angular angulaire. C'est là que toutes les réponses ci-dessus ne parviennent pas à clarifier la réponse, elles indiquent $rootScope.$digest
comme étant appelé à partir du test.
J'espère que cela aide la prochaine personne qui vient un long qui a le même problème.
J'ai supprimé ce post hier quand il a été rejeté. Aujourd'hui, j'ai continué à avoir ce problème en essayant d'utiliser les réponses, gracieusement fournies ci-dessus. Donc, je réserve ma réponse au prix de points de réputation, et en tant que telle, je la supprime.
C'est ce dont vous avez besoin dans les gestionnaires d'événements qui ne sont pas angulaires, et vous utilisez $ q et essayez de tester avec Jasmine.
something.on('ready', function(err) {
$rootScope.$apply(function(){deferred.resolve()});
});
Notez qu'il peut avoir besoin d'être enveloppé dans un délai d'attente $ dans certains cas.
something.on('ready', function(err) {
$timeout(function(){
$rootScope.$apply(function(){deferred.resolve()});
});
});
Encore une note. Dans les exemples de problèmes d'origine, vous appelez
done
au mauvais moment. Vous devez appelerdone
à l'intérieur de la méthodethen
(oucatch
oufinally
), de la promesse, après que résolve. Vous l'appelez avant la résolution de la promesse, ce qui entraîne la fin de la clauseit
.