鉴于以下服务:
angular.module('app',[]) .service('promisey',function ($q) { this.cakey = function () { return $q.when('brownie') } this.fruity = function () { return $q.when(Promise.resolve('apple')) } })
……以及以下测试:
var self = this describe('when',function () { var promisey var $rootScope beforeEach(module('app')) beforeEach(inject(function(_$rootScope_,_promisey_) { promisey = _promisey_ $rootScope = _$rootScope_ })) it('should give cakes',function (done) { promisey.cakey() .then(function (cake) { expect(cake).toBe('brownie') }) .catch(self.fail.bind()) .finally(done) $rootScope.$apply() }) it('should give fruit',function (done) { promisey.fruity() .then(function (cake) { // XXX: does not resolve expect(cake).toBe('apple') }) .catch(self.fail.bind()) .finally(done) $rootScope.$apply() }) })
…当ngMock来源时,promisey.fruity()永远不会解决.如果我没有源ngMock(并自己处理angular.injector),测试将按预期解决.这是为什么?
可以在tlvince/q-when-reduced-test-case找到该问题的简化测试用例.
解决方法
这是因为本机promise使用与Angular不同的调度程序.角度调度通过其异步队列上的evalAsync进行承诺.不同的promise库可能会以不同的方式调度promise – 在本机promise的用例中,它通过称为“microtask队列”的东西进行调度.
当你调用$rootScope.$应用它“刷新evalAsync队列”,因为运行摘要周期,这模拟“异步”并让你测试promises.
你不能用本机承诺“欺骗”计时器,所以你必须编写一个实际上是异步的测试.
您不能使用ngMock并使用Mocha的promise语法:
it('should give fruit',function () { // no done return promisey.fruity() // see return here .then(function (cake) { expect(cake).toBe('apple') }); // no digest,no `done` });
我觉得它看起来好多了:)