迁移到Angular 1.6.3后无法测试被拒绝的承诺

时间:2017-03-11 09:37:02

标签: angularjs jasmine angular-promise angularjs-1.6

我最近将我的应用程序从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中的更改

有人可以对这里可能发生的事情有所了解吗?

由于

2 个答案:

答案 0 :(得分:5)

在升级到1.6.3之前,我没有.catch(angular.noop)个部分,并且发现了一些帖子,建议这样做是为了让测试更快乐,这对我来说有助于我我的测试运行中未处理的拒绝错误。

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

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

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

有关详细信息,请参阅Catch method not working with $http get request

AngularJS V1.6

的$ q更改

报告承诺与拒绝回拨

  

拒绝承诺没有回调来处理拒绝报告       这到$exceptionHandler,所以他们可以登录到控制台。

     

突然改变

     

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

     

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

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

  

以前,承诺的onFulfilledonRejected处理程序中出现的错误都是在       与常规拒绝略有不同的方式:       他们被传递到$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);
}]);