Angular - 测试组件 - 从mock返回Promise.reject时出错

时间:2017-06-09 09:42:07

标签: javascript angular unit-testing promise angular-components

我有一个组件单元测试,它没有像我预期的那样处理模拟的承诺拒绝。

我在一个组件上有这个函数,它将一些数据发送到addUserToOrganisation并处理它返回的Promise:

 public onSubmit() {
    this.saveStatus = 'Saving';
    this.user = this.prepareSaveUser();
    this._userService.addUserToOrganisation(this.user)
    .then(() => this._router.navigate(['/profile']))
    .catch(error => this.reportError(error));
  }

在测试这个组件时,我为UserService提供了一个模拟器,它监视addUserToOrganisation端点并返回某种类型的Promise:

 mockUserService = jasmine.createSpyObj('mockUserService', ['getOrgId', 'addUserToOrganisation']);
 mockUserService.getOrgId.and.returnValue(Promise.resolve('an id'));
 mockUserService.addUserToOrganisation.and.returnValue(Promise.resolve());

这适用于快乐路径(解决) - 我可以测试this._router.navigate()被调用等等。以下是这条快乐路径的通过测试:

it('should navigate to /profile if save is successful', fakeAsync(() => {
    fixture.detectChanges();
    tick();
    fixture.detectChanges();

    component.userForm.controls['firstName'].setValue('John');
    component.userForm.controls['lastName'].setValue('Doe');
    component.userForm.controls['email'].setValue('j.d@gmail.com');
    component.onSubmit();

    tick();
    fixture.detectChanges();
    expect(mockRouter.navigate).toHaveBeenCalledWith(['/profile']);
  }));

然而,我在测试“悲伤”时遇到了麻烦。路径。我改变我的模拟以返回Promise.reject,虽然.catch中有onSubmit,但我收到此错误:

Error: Uncaught (in promise): no

这令人困惑。这是我对这条悲伤道路的考验。请注意,我更改了模拟调用的响应。

it('should show Failed save status if the save function fails', fakeAsync(() => {
    mockUserService.addUserToOrganisation.and.returnValue(Promise.reject('no'));
    fixture.detectChanges();
    tick();
    fixture.detectChanges();

    component.userForm.controls['firstName'].setValue('John');
    component.userForm.controls['lastName'].setValue('Doe');
    component.userForm.controls['email'].setValue('j.d@gmail.com');
    component.onSubmit();

    tick();
    fixture.detectChanges();

    expect(component.saveStatus).toEqual('Failed! no');
  }));

有没有人有任何想法?

1 个答案:

答案 0 :(得分:2)

应该捕获Promise拒绝,如果未处理它们将导致Zone.js承诺实现(在Angular应用程序中使用)和其他一些(Chrome,core-js承诺polyfill等)中出错。

应该同步捕获拒绝以便被视为处理。这样可以保证始终处理错误。

这是处理承诺:

const p = Promise.reject();
p.catch(err => console.error(err));

这是未经处理的承诺:

const p = Promise.reject();
setTimeout(() => {
  p.catch(err => console.error(err));
}, 1000);

即使将来可能会处理拒绝,但实施方式也无法知道'关于这一点,所以承诺被认为是未处理的,并且unhandledrejection事件被触发。

造成问题的是

tick();
fixture.detectChanges();

如果tick()存在,则只是以防万一'并且没有真正使用它,它首先不应该存在。如果它应该然后代码需要更改为不创建未处理的承诺:

mockUserService.addUserToOrganisation.and.callFake(() => Promise.reject('no'));