Подтвердить что ты не робот

Как разрешить promises в AngularJS, Jasmine 2.0, когда не существует $scope, чтобы заставить дайджест?

Кажется, что promises не разрешают в тестах Angular/Jasmine, если вы не нажмете $scope.$digest(). Это глупая ИМО, но это нормально, я работаю там, где это необходимо (контроллеры).

Ситуация, в которой я сейчас работаю, - это сервис, который может заботиться о каких-либо областях приложения, но он возвращает некоторые данные с сервера, но обещание, похоже, не решает.

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

Каков правильный способ протестировать эту функциональность?

Изменить: решение для справки. Очевидно, вы вынуждены вводить и переваривать $rootScope, даже если служба не использует его.

  it('should get something', function($rootScope, done) {
    var promise = myService.getSomething();

    promise.then(function(resp) {
      expect(resp).toBe('test');      
    });

    $rootScope.$digest();
    done();
  }); 
4b9b3361

Ответ 1

Вам нужно ввести $rootScope в свой тест и запустить $digest.

Ответ 2

всегда существует $rootScope, используйте его

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

myRootScope.$digest();

Ответ 3

Итак, я все время борюсь с этим днем. Прочитав этот пост, я тоже почувствовал, что с ответом что-то есть, оказывается. Ни один из приведенных выше ответов не дает ясного объяснения, где и почему использовать $rootScope.$digest. Итак, вот что я придумал.

Во-первых, почему? Вы должны использовать $rootScope.$digest всякий раз, когда вы отвечаете на событие не-w500 > или обратный вызов. Это будет включать в себя чистые события DOM, события jQuery и другие сторонние библиотеки Promise, отличные от $q, которые являются частью angular.

Во-вторых, где? В вашем коде, не ваш тест. Нет необходимости вводить $rootScope в ваш тест, это необходимо только в вашем фактическом сервисе angular. Вот где все вышеизложенное не дает четкого ответа на вопрос, они показывают, что $rootScope.$digest вызывается из теста.

Я надеюсь, что это поможет следующему человеку, который приходит долго, это одна и та же проблема.

Update


Я удалил этот пост вчера, когда его проголосовали. Сегодня я продолжал эту проблему, пытаясь использовать ответы, любезно предоставленные выше. Итак, я жду своего ответа ценой очков репутации, и поэтому я его отменяю.

Это то, что вам нужно в обработчиках событий, которые не являются angular, и вы используете $q и пытаетесь протестировать Jasmine.

something.on('ready', function(err) {
    $rootScope.$apply(function(){deferred.resolve()});              
});

Обратите внимание, что в некоторых случаях его, возможно, придется обернуть в $timeout.

something.on('ready', function(err) {
    $timeout(function(){
      $rootScope.$apply(function(){deferred.resolve()});    
    });     
});

Еще одно примечание. В исходных примерах проблем вы вызываете done в неподходящее время. Вы должны вызвать done внутри метода then (или catch или finally) обещания после того, как будет разрешено. Вы вызываете его до того, как обетование будет разрешено, что приводит к завершению предложения it.

Ответ 4

Из документации 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);
}));