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

Angular - Testing component - Error when returning Promise.reject from mock

我有一个组件单元测试,它没有按照我预期的方式处理来自模拟的承诺拒绝。

我在一个组件上有这个功能,它向 addUserToOrganisation 发送一些数据并处理 returns:

的 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 端点并且 return 是某种 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']);
  }));

但是,我无法测试 'sad' 路径。我将模拟更改为 return a Promise.reject,虽然我在 onSubmit 中有一个 .catch,但我收到此错误:

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

有没有人有什么想法?

承诺拒绝应该被捕获,不处理它们将导致 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);

即使将来可能会处理拒绝,但实施方式无法 'know',因此承诺被视为未处理并触发 unhandledrejection 事件。

造成问题的是

tick();
fixture.detectChanges();

如果 tick() 存在 'just in case' 并且没有实际用途,那么它一开始就不应该存在。如果应该,则需要更改代码以不创建未处理的承诺:

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