Angular $q.when не разрешается в модульном тесте Karma

Я использую $q.when, чтобы обернуть другие промисы lib. Это работает как шарм, но когда я пытаюсь запустить его внутри Karma, обещание не выполняется (done() никогда не выполняется), даже если я запустил $digest и даже после тайм-аут. Вот пример кода:

describe('PouchDB', function () {
var $q, $rootScope;

beforeEach(inject(function (_$rootScope_, _$q_) {
    $rootScope = _$rootScope_;
    $q = _$q_;
}));

it("should run", function (done) {

    function getPromise() {
        var deferred = Q.defer();

        deferred.resolve(1);

        return deferred.promise;
    }

    $q.when(getPromise())
        .then(function () {
            done();   // this never runs
        });

    $rootScope.$digest();
});

Почему? Какова причина этого? Я действительно не могу этого понять.

Обновить (обходной путь)

Я не понимаю, почему $q.when не разрешается в Karma - у него что-то с функцией nextTick, но я не могу отладить проблему. Вместо этого я отказался от $q.when и написал простую функцию, которая преобразует PouchDB (или любую другую подобную Q) в $q:

.factory('$utils', function ($q, $rootScope) {
  return {
    to$q: function (promise) {
      var deferred = $q.defer();

      promise.then(function (result) {
        deferred.resolve(result);
        $rootScope.$digest();
      });

      promise.catch(function (error) {
        deferred.reject(error);
        $rootScope.$digest();
      });

      return deferred.promise;
    }
  }
})

person Yoorek    schedule 13.06.2014    source источник
comment
Почему вы используете Q и $q вместе? Возможно, Karma (или библиотека AngularMocks, которую она использует) ожидает промисов, сгенерированных $q.defer() вместо Q.defer()   -  person Sunil D.    schedule 15.06.2014
comment
Я использую PouchDB, у которого есть свои промисы, поэтому мне нужно обернуть их $q. Я использовал Q в образце просто для упрощения - результат тот же: $q.when не разрешается в Karma, когда он оборачивает внешние обещания, что, кстати, является основной целью $q.when   -  person Yoorek    schedule 15.06.2014


Ответы (2)


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

$rootScope.$apply();

У меня была такая же проблема, и это работает для меня; обещания разрешаются при совершении этого вызова.

person Andrew Magee    schedule 16.11.2014

Я скорректировал переменные и ввел имена зависимостей, чтобы все было ясно, пока продолжается написание теста. Если done() является функцией внутри вашего (контроллера? директивы? службы/фабрики?), то ее следует вызывать при запуске теста, не пытаясь передать ее в качестве зависимости. В идеале за done() следует следить, но, не зная, откуда оно берется, невозможно показать вам, как настроить функцию шпиона.

Единственная отсутствующая деталь заключается в том, что в этом наборе тестов отсутствует функция expect(). Без него у меня нет возможности узнать, что вы ожидаете услышать.

describe('PouchDB', function () {
    var scope, db, q, rootScope;

    beforeEach(
        inject(
            function(_$rootScope_, _$q_){
                rootScope = _$rootScope_;
                scope = rootScope.$new();
                q = _$q_;
            }
        )
    );

    it("should run", function(){

        //spy should be constructed here

        function getPromise() {
            var deferred = q.defer();

            deferred.resolve(1);

            return deferred.promise;
        }

        q.when(getPromise)
            .then(function () {
                done();
            });

        scope.$digest();

        //assertion should be here

    });
});
person MBielski    schedule 13.06.2014
comment
Моя подготовка проста, и я не создаю новую область (я редактировал вопрос). Я пробовал с $timeout и сбросом... ничего не изменилось - person Yoorek; 14.06.2014
comment
Попробуйте создать новую область и удалить время ожидания. - person MBielski; 14.06.2014
comment
Я не понимаю, почему это что-то меняет - я не использую $scope явно, все равно это не работает. - person Yoorek; 15.06.2014
comment
Man, done() — это функция Jasmine для асинхронного тестирования внутри Karma. Утверждение не важно, если код недоступен. - person Yoorek; 15.06.2014
comment
У меня никогда не было причин использовать done(), и я обычно забываю об этом. - person MBielski; 16.06.2014