简体   繁体   English

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

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

I have a component unit test which isn't handling a promise rejection from a mock in the way I expected it to. 我有一个组件单元测试,它没有以我预期的方式处理模拟的承诺拒绝。

I have this function on a component which sends some data to addUserToOrganisation and handles the Promise that it returns: 我在一个组件上有这个函数,它发送一些数据到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));
  }

When testing this component, I have provided a mock for UserService which spies on the addUserToOrganisation endpoint and returns a Promise of some kind: 在测试这个组件时,我为UserService提供了一个模拟,它addUserToOrganisation端点并返回某种Promise:

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

This works fine for happy paths (resolve) - I can test that this._router.navigate() is called and so on. 这适用于快乐路径(解决) - 我可以测试this._router.navigate()被调用等等。 Here is the passing test for this happy path: 这是这条快乐路径的通过测试:

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

However, I am having trouble testing the 'sad' path. 但是,我在测试“悲伤”的路径时遇到了麻烦。 I alter my mock to return a Promise.reject and, although I have a .catch in onSubmit , I am getting this error: 我改变我的模拟以返回Promise.reject ,虽然我在onSubmit有一个.catch ,但是我收到了这个错误:

Error: Uncaught (in promise): no

So that's confusing. 这令人困惑。 Here is my test for this sad path. 这是我对这条悲伤道路的考验。 Note that I change the response of the mock call. 请注意,我更改了模拟调用的响应。

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

Does anyone have any ideas? 有没有人有任何想法?

Promise rejections are supposed to be caught, having them unhandled will result in error in Zone.js promise implementation (which is used in Angular applications) and some others (Chrome, core-js promise polyfill, etc). 承诺拒绝应该被捕获,如果未处理它们将导致Zone.js承诺实现(在Angular应用程序中使用)和其他一些(Chrome,core-js承诺polyfill等)中的错误。

A rejection should be caught synchronously in order to be considered handled. 应同步捕获拒绝以便考虑处理。 It is guaranteed this way that an error will always be handled. 这样可以保证始终处理错误。

This is handled promise: 这是承诺:

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

This is unhandled promise: 这是未经处理的承诺:

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

Even though a rejection will possibly be handled in future, there's no way how implementation can 'know' about that, so a promise is considered unhandled and unhandledrejection event is triggered. 即使将来可能会处理拒绝,但实施方式也无法“知道”这一点,因此承诺被视为未处理,并且unhandledrejection的拒绝事件被触发。

The thing that creates the problem is 造成问题的是

tick();
fixture.detectChanges();

If tick() is there 'just in case' and there's no real use of it, it shouldn't be there in the first place. 如果tick()是'以防万一'并且没有真正使用它,那么首先它不应该存在。 If it should then code needs to be changed to not create unhandled promises: 如果它应该然后代码需要更改为不创建未处理的承诺:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM