Как разрешить обещания $q.all в модульных тестах Jasmine?

Мой контроллер имеет код, как показано ниже:

$q.all([qService.getData($scope.id), dService.getData(), qTService.get()])
.then(function (allData) {
  $scope.data1 = allData[0];
  $scope.data2 = allData[1];
  $scope.data3 = allData[2];
});

И в своих модульных тестах я делаю что-то вроде этого:

beforeEach(inject(function($rootScope, $q, $location){// and other dependencies... 
  qServiceSpy = spyOn(_qService, 'getData').andCallFake(function () {
    var data1 = {
      id: 1,
      sellingProperty: 1,
    };
    var d = $q.defer();
    d.resolve(data1);
    return d.promise;
  });

  dServiceSpy = spyOn(_dService, 'getData').andCallFake(function () {
    var data2 = [{ "id": "1", "anotherProp": 123 }];
    var d = $q.defer();
    d.resolve(data2);
    return d.promise;
  });
  qTServiceSpy = spyOn(_qTService, 'get').andCallFake(function () {
    var data3 = [{ id: 0, name: 'Rahul' }];
    var d = $q.defer();
    d.resolve(data3);
    return d.promise;
  });
  rootScope = $rootScope;
});

Теперь в моем тесте я проверяю, вызываются ли службы, а данные1, данные2 не являются неопределенными.

it('check if qService' got called, function() {
  expect(scope.data1).toBeUndefined();
  rootScope.$digest();
  expect(_quoteService.getQuote).toHaveBeenCalled();
});
it('check if "data1" is defined', function () {
  expect(scope.data1).toBeUndefined();
  rootScope.$digest();
  expect(scope.data1).toBeDefined();
});

моя проблема в том, что это работало нормально, пока я не заменил свои отдельные вызовы службы в контроллере на q.all и в тестах scope.$apply на rootScope.$digest. С q.all и rootScope.$digest (также пытался использовать scope.$apply) оба теста завершаются с ошибкой:

Достигнуто 10 итераций $digest(). Прерывание!

если я удалю rootScope.$digest, то обещания никогда не будут разрешены, а тесты не сработают, говоря

ожидается, что undefined будет определено.

Любая помощь, как я должен код модульных тестов с q.all?

наткнулся на этот пост

Но это тоже не помогает, так как я уже пытаюсь использовать $digest.


person Rahul R.    schedule 01.05.2013    source источник


Ответы (1)


Вы можете попробовать поместить $rootScope.$apply() в функцию обратного вызова afterEach(). Промисы разрешаются на $apply() в Angular.

afterEach(function(){
    rootScope.$apply();
});
person Thomas Schultz    schedule 07.08.2013
comment
Если вам интересно, где это задокументировано: Различия между Q Криса Ковала и $q и тестирование - person the_karel; 07.03.2014
comment
$apply обычно получает обратный вызов. Я предпочитаю scope.$digest(), который обрабатывает только текущую область видимости, поэтому имеет лучшую производительность. - person Frank van Wijk; 16.04.2015
comment
afterEach было достаточно для меня. Я только что проверил обещания внутри функции afterEach(), и это сработало. Тай человек - person messerbill; 09.07.2015
comment
Я лично испытываю проводное поведение с этим. У меня было 3 обещания. До добавления afterEach...rootScope.$apply() никто не работает. Ведь работает только один из них. - person Gabriel; 28.08.2015
comment
Разрешает ли scope.digest все промисы? Даже вложенные обещания? Или мне нужно вызывать его несколько раз, чтобы код продолжался? - person Edward; 12.01.2016
comment
@ Эдвард - исходя из моего опыта, это не разрешает вложенные обещания. Буду признателен, если кто-нибудь объяснит, как это сделать. В моем случае я использую $q.all(). Первый уровень промисов разрешается с помощью $digest (или $apply), но окончательный обработчик успеха для группы промисов никогда не запускается. - person pmont; 09.03.2016
comment
Я тестировал jasmine v1 и забыл заключить код в функцию runs (я также добавил waits(1); непосредственно перед этим), чтобы запустить асинхронность. Как только я это сделал, $rootScope.$digest(); заработало, как и ожидалось. - person Pat; 18.07.2016