¿Cómo resolver promesas en AngularJS, Jasmine 2.0 cuando no hay $scope para forzar un resumen?
-
21-12-2019 - |
Pregunta
Parece que promete no resuelva en pruebas de Angular/Jasmine a menos que fuerce un $scope.$digest()
.Esto es una tontería en mi opinión, pero está bien, lo tengo funcionando cuando corresponde (controladores).
La situación en la que me encuentro ahora es que tengo un servicio al que no le importan los alcances de la aplicación, todo lo que hace es devolver algunos datos del servidor, pero la promesa no parece resolverse.
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();
});
});
});
¿Cuál es la forma correcta de probar esta funcionalidad?
Editar:Solución como referencia.Aparentemente estás obligado a inyectar y digerir $rootScope incluso si el servicio no lo está utilizando.
it('should get something', function($rootScope, done) {
var promise = myService.getSomething();
promise.then(function(resp) {
expect(resp).toBe('test');
});
$rootScope.$digest();
done();
});
Solución
Necesitas inyectar $rootScope
en tu prueba y disparador $digest
en eso.
Otros consejos
siempre existe el $rootScope, úsalo
inject(function($rootScope){
myRootScope=$rootScope;
})
....
myRootScope.$digest();
Así que he estado luchando con esto toda la tarde.Después de leer esta publicación, yo también sentí que había algo mal en la respuesta; resulta que sí.Ninguna de las respuestas anteriores da una explicación clara de dónde y por qué utilizar $rootScope.$digest
.Entonces, esto es lo que se me ocurrió.
En primer lugar ¿por qué?Necesitas usar $rootScope.$digest
siempre que responda desde un evento no angular o una devolución de llamada.Esto incluiría eventos DOM puros, eventos jQuery y otras bibliotecas Promise de terceros distintas a $q
que es parte de angular.
En segundo lugar ¿dónde?En su código, NO en su prueba.No es necesario inyectar $rootScope
en su prueba, solo es necesario en su servicio angular real.Ahí es donde todo lo anterior no logra dejar claro cuál es la respuesta, muestran $rootScope.$digest
como si fuera llamado de la prueba.
Espero que esto ayude a la próxima persona que venga hace mucho tiempo y tenga el mismo problema.
Actualizar
Eliminé esta publicación ayer cuando fue rechazada.Hoy seguí teniendo este problema al intentar utilizar las respuestas proporcionadas anteriormente.Entonces, dejo en espera mi respuesta a costa de puntos de reputación y, como tal, la voy a recuperar.
Esto es lo que necesita en los controladores de eventos que no son angulares y está usando $q e intentando realizar pruebas con Jasmine.
something.on('ready', function(err) {
$rootScope.$apply(function(){deferred.resolve()});
});
Tenga en cuenta que es posible que deba incluirse en un $timeout en algún caso.
something.on('ready', function(err) {
$timeout(function(){
$rootScope.$apply(function(){deferred.resolve()});
});
});
Una nota más.En los ejemplos de problemas originales que estás llamando
done
En el momento equivocado.necesitas llamardone
dentro de lathen
método (o elcatch
ofinally
), de la promesa, después de que se resuelva.Lo está llamando antes de que se resuelva la promesa, lo que está provocando queit
cláusula de rescisión.
De la documentación 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);
}));