迁移到 Angular 1.6.3 后无法测试被拒绝的承诺 [英] Unable to test a rejected promise after migrating to Angular 1.6.3

查看:19
本文介绍了迁移到 Angular 1.6.3 后无法测试被拒绝的承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近将我的应用程序从 Angular 1.5 更新到 1.6.3,并开始围绕我编写的基于 Promise 的代码进行 Jasmine 单元测试失败(使用 PhantomJS):

<块引用>

可能未处理的拒绝:未定义的抛出

阅读我发现公认的解决方案是将 .then() 与 .catch() 块链接起来以优雅地处理拒绝.

我已经为我正在测试的源文件之一执行了此操作,以证明这已经克服了它所做的错误.

但是,它现在发现了另一个问题,即当我的代码中调用承诺拒绝时我正在测试的期望不再通过.

这是我要测试的函数(在添加了所需的 catch 块之后)

public deleteSomething = (thing) =>{返回 this.UserMessages.buildConfirmDialog().then(() => {this.someService.remove(东西).then(() => {this.UserMessages.showToast('有些东西被删除了');}).catch((错误) => {//处理错误});}).catch((错误) => {//处理错误});}

这里是测试:

var thing = {foo: 'bar'},延迟删除,延迟确认,//下面的模拟服务稍后在测试运行之前注入控制器用户消息 = {buildConfirmDialog: jasmine.createSpy('buildConfirmDialog').and.callFake(function() {deferredConfirm = $q.defer();返回 deferredConfirm.promise.catch(angular.noop);})};//在这里注入和控制器设置...describe('删除内容时', function() {beforeEach(函数(){deferredRemove = $q.defer();spyOn(someService, 'remove').and.returnValue(deferredRemove.promise.catch(angular.noop));});describe('并且用户确认删除', function() {beforeEach(函数(){ctrl.deleteSomething(东西);deferredConfirm.resolve();deferredRemove.resolve();$rootScope.$apply();});it('应该在 someService 上调用 remove', function() {console.log('someService.remove.calls = ' + someService.remove.calls.count());期望(someService.remove).toHaveBeenCalled();});});describe('并且用户取消删除', function() {beforeEach(函数(){someService.remove.calls.reset();vm.deleteSomething(东西);deferredConfirm.reject({});$rootScope.$apply();});it('不应在 someService 上调用 remove', function() {console.log('someService.remove.calls = ' + someService.remove.calls.count());期望(someService.remove.calls.count()).toEqual(0);});});});

在升级到 1.6.3 之前我没有 .catch(angular.noop) 部分,并且遇到一些建议这样做以使测试愉快的帖子,这当然有帮助帮助我克服测试运行中未处理的拒绝错误.

我现在面临的问题是,对于拒绝测试规范,我的服务中不应该调用 remove 函数,因此调用次数应该为零,但它一直显示为 1.我在我的测试中添加了用于重置调用的行,以确保它不是之前的测试贡献(我知道调用应该在测试之间重置).

当我在 1.5 上时,这个测试运行得很好,所以这一定是我的代码\测试的编写方式与 1.6.x 中的更改不兼容

有人可以解释一下这里发生了什么吗?

谢谢

解决方案

我在升级到 1.6.3 之前没有 .catch(angular.noop) 部分并且遇到一些帖子建议这样做是为了让测试愉快,这无疑帮助我克服了测试运行中未处理的拒绝错误.

添加 .catch(angular.noop) 肯定会处理未处理的拒绝.

它将被拒绝的承诺转换为已履行的承诺!!

您的测试正确失败,因为您破坏了代码.

有关详细信息,请参阅Catch 方法不适用于 $http get 请求

<小时>

AngularJS V1.6 对 $q 的更改

使用非拒绝回调报告承诺

<块引用>

被拒绝的承诺没有回调来处理拒绝报告这到 $exceptionHandler 以便他们可以记录到控制台.

重大变化

未处理的拒绝承诺将被记录到 $exceptionHandler.

依赖于 $exceptionHandler 中的特定顺序或消息数量的测试将需要处理被拒绝的承诺报告.

将抛出的错误视为常规拒绝

<块引用>

以前,promise 的 onFulfilledonRejected 处理程序中抛出的错误在与常规拒绝的方式略有不同:它们被传递给 $exceptionHandler()(除了被转换为拒绝).

这种行为的原因是未捕获的错误与常规拒绝不同,因为例如,它可能是由编程错误引起的.在实践中,这结果令人困惑或者对用户来说是不受欢迎的,因为本地承诺和任何其他流行的承诺库都没有将抛出的错误与常规拒绝区分开来.(注意:虽然这种行为不违反 Promises/A+ 规范,但也没有规定.)

此提交通过跳过对 $exceptionHandler() 的调用来消除区别,从而处理抛出错误作为常规拒绝.

注意:除非明确关闭,否则仍会捕获可能未处理的拒绝并将其传递给$exceptionHandler(),因此由于编程错误而引发的错误不会以其他方式处理(带有随后的 onRejected 处理程序)不会被忽视.

有关更多信息,请参阅 AngularJS 开发人员指南- 从 V1.5 迁移到 V1.6

I have recently updated my application from Angular 1.5 to 1.6.3 and started getting Jasmine unit test failures (with PhantomJS) around promise based code I have written:

Possibly unhandled rejection: undefined thrown

Reading around I see that the accepted solution is to chain .then() with .catch() blocks to handle the rejections gracefully.

I have done this for one of my source files that I am testing to prove this gets past the error which it does.

However, it has now uncovered a further issue where an expectation I am testing when a promise rejection is called in my code is no longer passing.

This is the function I am trying to test (after adding the required catch blocks)

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
    });
}

And here is the test:

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);
            });
        });
    });

I didnt have the .catch(angular.noop) parts in prior to upgrading to 1.6.3 and came across some posts suggesting to do this in order to make the tests happy, which certainly helped for me in getting past the unhandled rejection error in my test run.

The problem I am now facing is that for the reject test spec, there should be no call made to a remove function in my service, and so the number of calls should be zero, but it keeps coming out as 1. I added the line to reset the calls in my test to be sure it wasnt the previous test contributing (I know calls are meant to be reset between tests).

This test was running just fine when I was on 1.5, so this has to be something with the way my code\test is written not playing nicely with changes in 1.6.x

Can someone shed some light on what may be going on here please?

Thanks

解决方案

I didnt have the .catch(angular.noop) parts in prior to upgrading to 1.6.3 and came across some posts suggesting to do this in order to make the tests happy, which certainly helped for me in getting past the unhandled rejection error in my test run.

Adding .catch(angular.noop) will certainly handle the unhandled rejection.

It converts the rejected promise to a fulfilled promise!!

Your test is correctly failing because you broke your code.

For more information, see Catch method not working with $http get request


Changes to $q for AngularJS V1.6

report promises with non rejection callback

Rejected promises that do not have a callback to handle the rejection report this to $exceptionHandler so they can be logged to the console.

BREAKING CHANGE

Unhandled rejected promises will be logged to $exceptionHandler.

Tests that depend on specific order or number of messages in $exceptionHandler will need to handle rejected promises report.

treat thrown errors as regular rejections

Previously, errors thrown in a promise's onFulfilled or onRejected handlers were treated in a slightly different manner than regular rejections: They were passed to the $exceptionHandler() (in addition to being converted to rejections).

The reasoning for this behavior was that an uncaught error is different than a regular rejection, as it can be caused by a programming error, for example. In practice, this turned out to be confusing or undesirable for users, since neither native promises nor any other popular promise library distinguishes thrown errors from regular rejections. (Note: While this behavior does not go against the Promises/A+ spec, it is not prescribed either.)

This commit removes the distinction, by skipping the call to $exceptionHandler(), thus treating thrown errors as regular rejections.

Note: Unless explicitly turned off, possibly unhandled rejections will still be caught and passed to the $exceptionHandler(), so errors thrown due to programming errors and not otherwise handled (with a subsequent onRejected handler) will not go unnoticed.

For more information, see AngularJS Developer Guide - Migrating from V1.5 to V1.6

这篇关于迁移到 Angular 1.6.3 后无法测试被拒绝的承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆