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

min*_*rse 1 jasmine angularjs angular-promise angularjs-1.6

我最近将我的应用程序从Angular 1.5更新到1.6.3并开始使用我编写的基于承诺的代码获取Jasmine单元测试失败(使用PhantomJS):

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

阅读我看到接受的解决方案是使用.catch()块链接.then()以优雅地处理拒绝.

我已经为我测试的一个源文件做了这个,以证明它已经过了它所做的错误.

但是,它现在已经发现了另一个问题,即当我的代码中调用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
    });
}
Run Code Online (Sandbox Code Playgroud)

以下是测试:

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);
            });
        });
    });
Run Code Online (Sandbox Code Playgroud)

.catch(angular.noop)在升级到1.6.3之前我没有使用这些部件并且遇到了一些建议要做这个以使测试变得愉快的帖子,这肯定有助于我在测试运行中超过未处理的拒绝错误.

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

当我在1.5时,这个测试运行得很好,所以这必须与我的代码\测试编写方式不符合1.6.x中的更改

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

谢谢

geo*_*awg 5

.catch(angular.noop)在升级到1.6.3之前我没有使用这些部件并且遇到了一些建议要做这个以使测试变得愉快的帖子,这肯定有助于我在测试运行中超过未处理的拒绝错误.

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

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

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

有关更多信息,请参阅Catch方法不使用$ http get请求


AngularJS V1.6对$ q的更改

报告承诺与非拒绝回调

拒绝承诺没有回调来处理拒绝报告,$exceptionHandler因此可以将它们记录到控制台.

突然变化

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

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

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

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

这种行为的原因是未被​​捕获的错误与常规拒绝不同,例如,它可能由编程错误引起.实际上,这对用户来说是混乱或不受欢迎的,因为本机承诺或任何其他流行的承诺库都不会将抛出的错误与常规拒绝区分开来.(注意:虽然这种行为不符合Promises/A +规范,但也没有规定.)

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

注意: 除非明确禁用,否则仍可能会捕获未处理的拒绝并将其传递给 $exceptionHandler(),因此由于编程错误而引发的错误以及未经处理的错误(使用后续onRejected处理程序)将不会被忽视.

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