Как разрешить промисы в AngularJS, Jasmine 2.0, когда нет $scope для принудительного дайджеста?

StackOverflow https://stackoverflow.com//questions/24021031

Вопрос

Кажется, обещает не разрешайте в тестах 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();
  }); 
Это было полезно?

Решение

Вам нужно сделать инъекцию $rootScope в вашем тесте и триггере $digest в теме.

Другие советы

Всегда есть $ rootscope, используйте его

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

myRootScope.$digest();
.

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

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

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

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

Обновить


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

Это то, что вам нужно в обработчиках событий, которые не являются угловыми, и вы используете $ 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 пункт о расторжении договора.

из угловой документации.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top