我最近将我的应用程序从Angular 1.5更新到1.6.3并开始使用我编写的基于承诺的代码获取Jasmine单元测试失败(使用PhantomJS):
可能未处理的拒绝:未定义的抛出
阅读我看到接受的解决方案是使用.catch()块链接.then()以优雅地处理拒绝。
我为我测试的一个源文件做了这个,以证明它已经超出了它所犯的错误。
然而,它现在已经发现了一个进一步的问题,即我在代码中调用promise promise时我正在测试的期望不再通过。
这是我试图测试的功能(在添加所需的catch块之后)
public deleteSomething = (thing) => {
return this.UserMessages.buildConfirmDialog().then(() => {
this.someService.remove(thing)
.then(() => {
this.UserMessages.showToast('Something deleted');
})
.catch((error) => {
//handle error
});
})
.catch((error) => {
//handle error
});
}
这是测试:
var thing = {foo: 'bar'},
deferredRemove,
deferredConfirm,
//Mock service below injected into controller later on before test are run
UserMessages = {
buildConfirmDialog: jasmine.createSpy('buildConfirmDialog').and.callFake(function() {
deferredConfirm = $q.defer();
return deferredConfirm.promise.catch(angular.noop);
})
};
//Inject and controller setup here...
describe('When deleting something', function() {
beforeEach(function() {
deferredRemove = $q.defer();
spyOn(someService, 'remove').and.returnValue(deferredRemove.promise.catch(angular.noop));
});
describe('and the user confirms the deletion', function() {
beforeEach(function() {
ctrl.deleteSomething(thing);
deferredConfirm.resolve();
deferredRemove.resolve();
$rootScope.$apply();
});
it('should call remove on someService', function() {
console.log('someService.remove.calls = ' + someService.remove.calls.count());
expect(someService.remove).toHaveBeenCalled();
});
});
describe('and the user cancels the deletion', function() {
beforeEach(function() {
someService.remove.calls.reset();
vm.deleteSomething(thing);
deferredConfirm.reject({});
$rootScope.$apply();
});
it('should not call remove on someService', function() {
console.log('someService.remove.calls = ' + someService.remove.calls.count());
expect(someService.remove.calls.count()).toEqual(0);
});
});
});
在升级到1.6.3之前,我没有.catch(angular.noop)
个部分,并且发现了一些帖子,建议这样做以便让测试变得愉快,这对我来说有助于克服未处理的拒绝错误在我的测试中。
我现在面临的问题是,对于拒绝测试规范,我的服务中不应该对删除函数进行调用,因此调用次数应该为零,但它会一直显示为1.我添加了一行来重置我的测试中的调用,以确保它不是之前的测试贡献(我知道调用是在测试之间重置)。
当我在1.5上时,这个测试运行得很好,所以这必须与我的代码\测试编写的方式不符合1.6.x中的更改
有人可以对这里可能发生的事情有所了解吗?
由于
答案 0 :(得分:5)
在升级到1.6.3之前,我没有.catch(angular.noop)
个部分,并且发现了一些帖子,建议这样做是为了让测试更快乐,这对我来说有助于我我的测试运行中未处理的拒绝错误。
添加.catch(angular.noop)
肯定会处理未处理的拒绝。
它将被拒绝的承诺转换为履行承诺!!
您的测试正确失败,因为您破坏了代码。
有关详细信息,请参阅Catch method not working with $http get request
拒绝承诺没有回调来处理拒绝报告 这到
$exceptionHandler
,所以他们可以登录到控制台。突然改变
未处理拒绝的承诺将记录到
$exceptionHandler
。依赖于
$exceptionHandler
中特定顺序或消息数量的测试 将需要处理被拒绝的承诺报告。
以前,承诺的
onFulfilled
或onRejected
处理程序中出现的错误都是在 与常规拒绝略有不同的方式: 他们被传递到$exceptionHandler()
(除了被转换为拒绝)。这种行为的原因是未被捕获的错误与常规拒绝不同,因为 例如,它可能是由编程错误引起的。实际上,这结果令人困惑 或者对用户不利,因为既不是本地承诺也不是任何其他受欢迎的承诺库 将抛出的错误与常规拒绝区分开来。 (注意:虽然此行为不会违反Promises/A+ spec,但也没有规定。)
此提交通过跳过对
$exceptionHandler()
的调用来消除区别,从而进行处理 经常拒绝抛出错误。注意:强> 除非明确禁用,否则仍可能会发现未处理的拒绝并将其传递给
$exceptionHandler()
,因为编程错误引发错误,而不是以其他方式处理(使用 后续onRejected
处理程序)不会被忽视。
有关详细信息,请参阅AngularJS Developer Guide - Migrating from V1.5 to V1.6
答案 1 :(得分:4)
通过此配置禁用可能未处理的拒绝并再次测试。
app.config(['$qProvider', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);