我正试图让chai-as-promised
与karma单元测试一起使用$q
承诺。
svc.test = function(foo){
if (!foo){
// return Promise.reject(new Error('foo is required'));
return $q.reject(new Error('foo is required'));
} else {
// get data via ajax here
return $q.resolve({});
}
};
it.only('should error on no foo', function(){
var resolvedValue = MyServices.test();
$rootScope.$apply();
return resolvedValue.should.eventually.be.rejectedWith(TypeError, 'foo is required');
});
单元测试只是超时了。我不确定我在这里做错了什么来得到正确解决的承诺。使用$q
似乎是一个问题 - 当我使用原生Promise.reject()
时,它运行正常。
我在这里提交了一张票,但似乎没有人回应: https://github.com/domenic/chai-as-promised/issues/150
答案 0 :(得分:2)
template<class T> inline std::vector<std::shared_ptr<T>> * getVector() const
{
auto key = getKey<T>();
return reinterpret_cast<std::vector<std::shared_ptr<T>> *>( (_componentMap.count(key) ? _componentMap.at(key).get() : const_cast<std::vector<std::shared_ptr<Component>> *>(&_emptyComponentSharedPtrVec)) );
}
期望修改承诺断言的方式是transferPromiseness
method。
默认情况下,Chai作为Promised的断言返回的承诺是 常规的Chai断言对象,用单个then方法扩展 源自输入承诺。例如,要更改此行为 用更有用的糖方法输出一个承诺,例如找到的 在大多数promise库中,您可以覆盖 chaiAsPromised.transferPromiseness。
对于Angular 1.3+支持,chai-as-promised
承诺可以由$q
属性进行鸭子类型化,因此本机承诺不会受到影响:
$$state
chaiAsPromised.transferPromiseness = function (assertion, promise) {
assertion.then = promise.then.bind(promise);
if (!('$$state' in promise))
return;
inject(function ($rootScope) {
if (!$rootScope.$$phase)
$rootScope.$digest();
});
};
个链都声明了chaiAsPromised
的承诺。即使承诺已经解决,链的其余部分仍然需要使用then
手动触发摘要。
只要规范不包含异步代码,它就会变成同步,不需要返回promise:
$rootScope.$digest()
在未设置it('...', () => {
...
expect(...).to.eventually...;
expect(...).to.eventually...;
});
的每组$rootScope.$digest()
断言/期望之后,等于强制eventually
:
transferPromiseness
答案 1 :(得分:1)
您需要更改测试中的执行顺序。具有chai-as-promise的异步任务需要在期望之前发生。
it('does not work', () => {
$timeout.flush();
expect(myAsyncTask()).to.eventually.become('foo');
})
it('does work', () => {
expect(myAsyncTask()).to.eventually.become('foo');
$timeout.flush();
})
在刷新异步任务队列之前,需要启动对异步任务的调用。
另外,请勿使用$rootScope.$digest
。 可能还有其他副作用,这些副作用在您的测试中是不可取的。
$timeout.flush
正是您正在寻找的。
https://docs.angularjs.org/api/ngMock/service/ $超时
让您的特定测试工作:
it('should error on no foo', function(){
MyServices.test().should.eventually.be.rejectedWith(TypeError, 'foo is required')
$rootScope.$apply();
});
it('should pass on foo', function(){
MyServices.test('foo').should.eventually.become({});
$rootScope.$apply();
}
tl; dr
it('async test', () => {
setup();
expect();
execute();
})
it('sync test', () => {
setup();
execute();
expect();
})
鉴于发布的评论:
是否应该提到在你回答的问题上对“竞争对手”的答案进行投票是不道德的?
足够公平。我认为答案是误导性的,因为没有必要进行额外的设置,以便在不必处理done
回调的情况下使用Angular进行chai-as-promise。 Fwiw,我会继续尝试撤销所说的downvote并对此有道德。
OP在代码中没有超时的迹象,并且没有说明任务是异步的。在范围摘要之外调用时,
$rootScope.$digest()
在规范中没有副作用。不建议在生产中使用它的原因是因为它没有$apply
所具有的安全措施。
$rootScope.$digest
实际上与$rootScope.$apply
(和$scope.$apply
相同)。 source
$timeout.flush
也会刷新非基于$timeout
的函数。它不是基于$timeout
的函数所独有的。
Plunker展示 just works™: plunker