在Karma单元测试中解决嵌套的AngularJS承诺

时间:2015-05-27 17:16:19

标签: javascript angularjs karma-jasmine angular-promise angular-digest

我尝试测试一个使用嵌套promises的函数(让我们假设这个函数不能改变)。为了处理这些承诺,我必须至少调用$rootScope.$digest()两次。我提出了这个有效的解决方案,每隔10毫秒调用$digest()

// Set some async data to scope.key
// Note: This function is just for demonstration purposes.
//       The real code makes async calls to localForage.
function serviceCall(scope, key) {
  var d1 = $q.defer(), d2 = $q.defer();

  setTimeout(function () {
    d1.resolve('d1');
  });

  d1.promise.then(function (data) {
    setTimeout(function () {
      d2.resolve(data + ' - d2');
    }, 100); // simulate longer async call
  });

  d2.promise.then(function (data) {
    scope[key] = data;
  });
}

it('nested promises service', function (done) {
  var interval = setInterval(function () {
      $rootScope.$digest();
    }, 10),
    myKey = 'myKey',
    scope = {};

  serviceCall(scope, myKey);

  setTimeout(function () {
    expect(scope[myKey]).toEqual('d1 - d2');
    window.clearInterval(interval);
    done();
  }, 120); // What is the right timeout?
});

问题是估计消化足够时间以解决所有承诺所需的超时持续时间。如果服务对例如服务进行真正的异步调用,则会变得更加复杂。 localStorage的。

还有另一种解决方法吗?有没有办法获得所有剩余的承诺?

1 个答案:

答案 0 :(得分:2)

您应该使用jasmine spies来模拟/存根任何外部服务调用,以便您可以控制服务何时解析/拒绝。您的服务应该备份其内部功能的测试。

请注意,这个例子并不完美,但为了清楚起见缩写。

var service = jasmine.createSpyObj('service', ['call']);
var defServiceCall;
var $scope;

beforeEach(function () {
  module('myModule', function ($provide) {
    // NOTE: Replaces the service definition with mock.
    $provide.value('service', service);
  });
  inject(function($q, $rootScope) {
    $scope = $rootScope.$new();
    defServiceCall = $q.defer();
    service.call.and.returnValue(defServiceCall.promise);
  });
});
describe('When resolved', function () {
  beforeEach(function () {
    myFunctionCall(); // Sets myVar on the scope
    defServiceCall.resolve('data');
    $scope.$digest(); // NOTE: Must digest for promise to update
  });
  it('should do something awesome when resolved', function () {
    expect($scope.myVar).toEqual('data');
  });
});