web-dev-qa-db-fra.com

Comment résoudre les promesses dans AngularJS, Jasmine 2.0 quand il n'y a pas de $ scope pour forcer un digest?

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();
  }); 
47
Terry

Vous devez injecter $rootScope dans votre test et déclenchez $digest dessus.

41

il y a toujours $ rootScope, utilisez-le

inject(function($rootScope){
myRootScope=$rootScope;
})
....

myRootScope.$digest();
12
mpm

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);
}));
3
Rentering.com

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.

Mise à jour


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 appeler done à l'intérieur de la méthode then (ou catch ou finally), 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 clause it.

3
Jeffrey A. Gochin