Wie löst man Versprechen in AngularJS, Jasmine 2.0 auf, wenn es keinen $scope gibt, um einen Digest zu erzwingen?
-
21-12-2019 - |
Frage
Das scheint vielversprechend Wird in Angular/Jasmine-Tests nicht aufgelöst, es sei denn, Sie erzwingen a $scope.$digest()
.Das ist meiner Meinung nach albern, aber in Ordnung, ich habe das, wo es anwendbar ist (Controller).
Die Situation, in der ich mich jetzt befinde, ist, dass ich einen Dienst habe, der sich weniger um Bereiche in der Anwendung kümmert. Er gibt lediglich einige Daten vom Server zurück, aber das Versprechen scheint nicht aufgelöst zu werden.
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();
});
});
});
Wie kann diese Funktionalität richtig getestet werden?
Bearbeiten:Lösung als Referenz.Anscheinend sind Sie gezwungen, den $rootScope einzuschleusen und zu verarbeiten, auch wenn der Dienst ihn nicht verwendet.
it('should get something', function($rootScope, done) {
var promise = myService.getSomething();
promise.then(function(resp) {
expect(resp).toBe('test');
});
$rootScope.$digest();
done();
});
Lösung
Sie müssen spritzen $rootScope
in Ihrem Test und Trigger $digest
drauf.
Andere Tipps
Es gibt immer den $rootScope, verwenden Sie ihn
inject(function($rootScope){
myRootScope=$rootScope;
})
....
myRootScope.$digest();
Ich habe also den ganzen Nachmittag damit zu kämpfen.Nachdem ich diesen Beitrag gelesen hatte, hatte auch ich das Gefühl, dass mit der Antwort etwas nicht stimmte; es stellte sich heraus, dass es so war.Keine der oben genannten Antworten gibt eine klare Erklärung, wo und warum die Verwendung erfolgen soll $rootScope.$digest
.Also, hier ist, was ich mir ausgedacht habe.
Zunächst einmal: Warum?Sie müssen verwenden $rootScope.$digest
wann immer Sie auf ein nicht-angulares Ereignis oder einen Rückruf antworten.Dazu gehören reine DOM-Ereignisse, jQuery-Ereignisse und andere Promise-Bibliotheken von Drittanbietern als $q
was Teil von eckig ist.
Zweitens: Wo?In Ihrem Code, NICHT in Ihrem Test.Eine Injektion ist nicht erforderlich $rootScope
In Ihren Test wird es nur in Ihrem eigentlichen Winkeldienst benötigt.Das ist der Punkt, an dem all das oben Gesagte nicht klar macht, was die Antwort ist, zeigen sie $rootScope.$digest
als vom Test abgerufen.
Ich hoffe, das hilft der nächsten Person, die das gleiche Problem hat.
Aktualisieren
Ich habe diesen Beitrag gestern gelöscht, als er abgelehnt wurde.Heute hatte ich weiterhin dieses Problem, als ich versuchte, die oben freundlicherweise bereitgestellten Antworten zu verwenden.Daher halte ich meine Antwort auf Kosten von Reputationspunkten bereit und stelle sie daher wieder her.
Dies ist, was Sie in nicht-eckigen Event-Handlern benötigen, und Sie verwenden $q und versuchen, mit Jasmine zu testen.
something.on('ready', function(err) {
$rootScope.$apply(function(){deferred.resolve()});
});
Beachten Sie, dass es in manchen Fällen möglicherweise in ein $timeout eingeschlossen werden muss.
something.on('ready', function(err) {
$timeout(function(){
$rootScope.$apply(function(){deferred.resolve()});
});
});
Noch eine Anmerkung.In den ursprünglichen Problembeispielen rufen Sie an
done
zur falschen Zeit.Sie müssen anrufendone
innerhalb derthen
Methode (oder diecatch
oderfinally
), des Versprechens, nachdem es aufgelöst wird.Sie rufen es auf, bevor das Versprechen aufgelöst wird, was die Ursache istit
Klausel zur Kündigung.
Aus der Winkeldokumentation.
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);
}));