2017-06-09 11 views
2

私は予想通りの模擬試験からの約束拒否を処理していないコンポーネント単体テストを持っています。角試験部品 - 模擬試験からPromise.rejectを返すときのエラー

IはaddUserToOrganisationにいくつかのデータを送信し、それを返すことを約束を処理するコンポーネントにこの機能を持っている:このコンポーネントをテストする場合

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

、IはaddUserToOrganisationにスパイUserServiceためのモックを提供していますエンドポイントといくつかの種類の約束を返します。

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('[email protected]'); 
    component.onSubmit(); 

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

しかし、私は 'sad'パスのテストに問題があります。私はonSubmit.catchを持っているが、私は、Promise.rejectを返すために、私のモックを変更すると、私はこのエラーを取得しています:

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('[email protected]'); 
    component.onSubmit(); 

    tick(); 
    fixture.detectChanges(); 

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

誰にでもアイデアはありますか?

答えて

2

プロミスの拒否は捕捉されているとみなされ、処理されていないとAngularアプリケーションで使用されているZone.js約束の実装と、Chrome、core-js promise 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()があるが、「念のため」であり、それの本当の使用は、それが最初の場所であってはならないがない場合は

問題を作成する事が

tick(); 
fixture.detectChanges(); 

です。その場合、未処理の約束を作成しないようにコードを変更する必要があります。

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

私は 'tick()'を削除しようとしましたが、まだエラーがあります。どのようにそれが不必要であるか私はかなり理解していない?しかし、私の模擬応答を 'returnValue ...'から 'callFake ...'に変更することは、このトリックを行っています。私はここでニュアンスを100%理解しているとは思わない。 – dafyddPrys

+0

'callFake'は呼び出された時点で拒否された約束事を作成します。したがって、' component.onSubmit() '呼び出し中に' .catch'で連鎖され、処理された約束を得ます。'returnValue'は、直ちに' .catch'でチェーンされるべき既存の拒否された約束を受け入れますが、タイマーは 'tick()'で次のティックに移動されてから 'component.onSubmit()'に拒否されます。 'setTimeout'を使った例は、何が起こっているのかを正確に示しています。それは 'tick()'なしで動作するはずです。私はなぜあなたはまだそれなしでこのエラーを取得する理由を言うことはできません。 – estus