javascript - ¿Cómo resuelvo una promesa en una prueba unitaria de AngularJS?
Estoy usando la configuración básica de karma/jasmine para probar mi código Angular. Aquí está mi prueba:
var $controllerConstructor, ctr, mockSuperheroData, scope, deferred, q;
describe('main controller', function() {
var $controllerConstructor, ctr, mockSuperheroData, scope, deferred, q;
beforeEach(inject(function($controller, $rootScope, $q) {
scope = $rootScope.$new();
$controllerConstructor = $controller;
q = $q;
mockSuperheroData = {
getSuperheroes: function() {
deferred = q.defer();
return deferred.promise;
}
};
ctr = $controllerConstructor('MainCtrl', {$scope: scope, $location: {}, superheroService: mockSuperheroData, keys: {}});
}));
it('should set the result of getResource to scope.heroes', function() {
scope.getHeroes();
expect(scope.heroes).toBe(100);
});
}
scope.getHeroes() llama a mockSuperheroData.getSuperheroes() que está devolviendo una promesa. ¿Cómo puedo forzar que la promesa devuelva lo que quiero en la prueba unitaria? ¿Dónde puedo engancharme a la promesa para simular su retorno?
Respuesta #1
¿Cómo hago para forzar que la promesa devuelva lo que quiero en la prueba unitaria?
Básicamente necesitarás llamar a resolve en el Deferred:
deferred.resolve(100);
Puedes poner eso directamente antes del return deferred.promise o en un setTimeout asíncrono.
Respuesta #2
var $controllerConstructor, ctr, mockSuperheroData, scope, deferred, q;
describe('main controller', function() {
var $controllerConstructor, ctr, mockSuperheroData, scope, deferred, q, rootScope;
beforeEach(inject(function($controller, $rootScope, $q) {
scope = $rootScope.$new();
$controllerConstructor = $controller;
q = $q;
rootScope = $rootScope;
mockSuperheroData = {
getSuperheroes: function() {
deferred = q.defer();
return deferred.promise;
}
};
ctr = $controllerConstructor('MainCtrl', {$scope: scope, $location: {}, superheroService: mockSuperheroData, keys: {}});
}));
it('should set the result of getResource to scope.heroes', function() {
scope.getHeroes();
deferred.resolve(100);
rootScope.$apply();
expect(scope.heroes).toBe(100);
});
});
Cabe mencionar que, debido a que $q está integrado con $rootScope, no solo necesitas resolver el objeto diferido, sino que también necesitas propagar los cambios llamando a $rootScope.$apply.
Escribí un blog sobre cómo burlarse de las promesas de Angular en projectpoppycock
y escribí un ejemplo funcional, con pruebas, en plunkr
Realmente me gusta la forma en que estás inyectando el servicio simulado como una dependencia del controlador usando el servicio $controller, puede que necesite revisar mi forma de hacer esto. ¡Tu manera es mejor :) Gracias!
