【问题标题】:Unable to test a rejected promise after migrating to Angular 1.6.3迁移到 Angular 1.6.3 后无法测试被拒绝的承诺
【发布时间】:2017-03-11 09:37:02
【问题描述】:

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

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

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

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

但是,它现在发现了另一个问题,即当我在代码中调用 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 中的变化

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

谢谢

【问题讨论】:

    标签: angularjs jasmine angular-promise angularjs-1.6


    【解决方案1】:

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

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

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

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

    欲了解更多信息,请参阅Catch method not working with $http get request


    AngularJS V1.6 对 $q 的更改

    报告带有非拒绝回调的承诺

    没有回调来处理拒绝报告的被拒绝承诺 将此发送到$exceptionHandler,以便他们可以登录到控制台。

    重大变化

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

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

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

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

    这种行为的原因是未捕获的错误与常规拒绝不同,因为 例如,它可能是由编程错误引起的。在实践中,这被证明是令人困惑的 或不适合用户,因为本机承诺或任何其他流行的承诺库都不是 将抛出的错误与常规拒绝区分开来。 (注意:虽然此行为不违反Promises/A+ spec,但也没有规定。)

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

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

    欲了解更多信息,请参阅AngularJS Developer Guide - Migrating from V1.5 to V1.6

    【讨论】:

      【解决方案2】:

      通过此配置禁用 Possibly Unhandled Rejection 并再次测试。

      app.config(['$qProvider', function ($qProvider) {
          $qProvider.errorOnUnhandledRejections(false);
      }]);
      

      【讨论】:

      • 我忘了说我已经看到了这个配置选项并且也添加到了我的应用配置中
      猜你喜欢
      • 2018-02-25
      • 1970-01-01
      • 2015-10-28
      • 1970-01-01
      • 2017-06-02
      • 2015-08-26
      • 2019-03-27
      • 2021-01-10
      • 1970-01-01
      相关资源
      最近更新 更多