Como resolver promessas em AngularJS, Jasmim 2.0 quando não há $escopo para forçar um resumo?
-
21-12-2019 - |
Pergunta
Parece que promete não resolverem Angular/Jasmim testes, a menos que você force uma $scope.$digest()
.Isso é bobagem, IMO, mas bem, eu tenho que trabalhar, quando aplicável (controladores).
A situação que eu estou agora é que eu tenho um serviço que poderia cuidar menos sobre qualquer escopos no aplicativo, tudo o que ele faz é retornar alguns dados do servidor, mas a promessa não parece estar a ser resolvido.
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();
});
});
});
Qual é a maneira correta para testar essa funcionalidade?
Editar:Solução de referência.Aparentemente, você é forçado a injetar e digerir a $rootScope mesmo se o serviço não estiver usando ele.
it('should get something', function($rootScope, done) {
var promise = myService.getSomething();
promise.then(function(resp) {
expect(resp).toBe('test');
});
$rootScope.$digest();
done();
});
Solução
Você precisa injetar $rootScope
em seu teste e disparar $digest
sobre ele.
Outras dicas
há sempre o $rootScope, usá-lo
inject(function($rootScope){
myRootScope=$rootScope;
})
....
myRootScope.$digest();
Então, eu tenho de estar lutando com isso a tarde toda.Depois de ler este post, eu também senti que havia algo de fora com a resposta;acontece que existe.Nenhuma das respostas acima dá uma clara explicação de como, onde e por que usar $rootScope.$digest
.Então, aqui está o que eu encontrei.
Primeiro por que?Você precisa usar $rootScope.$digest
sempre que responder a um não-angular de eventos ou de retorno de chamada.Isso inclui puro DOM de eventos, jQuery, eventos, e outras 3rd party Promessa de bibliotecas que $q
qual é a parte angular.
Em segundo lugar, onde?No seu código, e NÃO o seu teste.Não é necessário injetar $rootScope
em seu teste, é necessária apenas em sua real angular de serviço.Que é onde tudo acima falhar, deixar claro que a resposta é, eles mostram $rootScope.$digest
como está sendo chamado de teste.
Espero que isso ajude a próxima pessoa que vem de uma longa, que tem o mesmo problema.
Atualização
Eu apaguei esse post de ontem, quando ele tem votado para baixo.Hoje eu continuava a ter esse problema ao tentar usar as respostas, graciosamente fornecido acima.Então, eu espera a minha resposta o custo de pontos de reputação e, como tal , estou desfazendo-lo.
Isso é o que você precisa em manipuladores de eventos que não são angulares, e você estiver usando o $q e tentar testar com Jasmine.
something.on('ready', function(err) {
$rootScope.$apply(function(){deferred.resolve()});
});
Observe que ele pode precisar de ser envolvido em um jogo de $tempo de espera em alguns casos.
something.on('ready', function(err) {
$timeout(function(){
$rootScope.$apply(function(){deferred.resolve()});
});
});
Uma observação mais.No problema original exemplos que você está chamando
done
na hora errada.Você precisa chamardone
dentro dothen
o método (ou ocatch
oufinally
), da promessa, depois é resolvida.Você está chamando-o antes que a promessa resolve, o que está causando oit
cláusula terminar.
A partir angular documentação.
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);
}));