2017-01-13 17 views
3

valueChangesdebounceTimeを使用して変更を検出するフォームコントロールを使用しています。私はitemServiceを偵察して、updateメソッドが呼び出されているかどうかを調べるテストを書いています。フォームコントロールからdebounceTimeを削除すると、テストは正常に動作します。Angular2 - debounceTimeを使用した呼び出しをテストする

コンポーネントのフォームコントロールは次のとおりです。

this.itemControl.valueChanges.debounceTime(300).subscribe(response => { 
    this.itemService.update(response); 
}); 

はここにここでテスト

it('should do stuff', 
    inject([ItemService], (itemService) => { 
     return new Promise((res, rej) =>{ 
     spyOn(itemService, 'update'); 
     let item = { 
      test: 'test' 
     }; 
     fixture.whenStable().then(() => { 
      let itemControl = new FormControl('test'); 
      fixture.componentInstance.itemControl = itemControl; 
      fixture.autoDetectChanges(); 

      fixture.componentInstance.saveItem(item); 
      expect(itemService.update).toHaveBeenCalled(); 

})})); 

だ私が言ったように、私はテストがうまく実行されるフォームコントロールからdebounceTimeを削除する場合は、コンポーネントのsaveItem機能

saveItem(item): void { 
    this.itemControl.setValue(item); 
} 

だが、私はすることができますそれをしないでください。私はあなたがfakeAsync()ダニ()を使用する必要がありますexpect呼び出しの前にtick()呼び出しを追加しようとしたが、私はちょうどこのエラーを取得する

Unhandled Promise rejection: The code should be running in the fakeAsync zone to call this function ; Zone: ProxyZone ; Task: Promise.then ; Value: Error: The code should be running in the fakeAsync zone to call this function Error: The code should be running in the fakeAsync zone to call this function 
+0

私はあなたが 'tick'を使用するasync''にテストをラップする必要があると思います。告発されない1つのオプションは、デバウンス時間を注入することです、あなたはテストを速く保つためにそれを小さい数に設定することができます。 – jonrsharpe

+0

は、デバウンス時間が0か1かどうかは関係ありません。「スパイアップデートが呼び出されました。 – avoliva

答えて

8

てきました。問題のテストコードに基づいて私の最後で正常に実行された(.spec.tsファイル)以下のコードを確認してください。

以下のコードの説明:
fakeAsync()及び(ダニ)は常に一緒に使用されるべきです。 async()/ fixtureInstance.whenStable()を一緒に使用することはできますが、プログラマの観点からはあまり予測できません。これまでにfakeAsync()/ tick()を使用することをお勧めします:)。 onlyは、テストコードがXHR呼び出しを行うときにasync()/ fixtureInstance.whenStable()を使用する必要があります(別名Http要求のテスト)。

テストコードで非同期コードがどのように動作するかを手動で制御できるため、できればfakeAsync()/ tick()を使用することをお勧めします。 :)

以下のコード(.spec.tsファイル)で確認できます。仮にあなたが設定したデバウンス値が300だったので、メソッドパラメータ "300"、tick(300)でtickメソッドを呼び出すことは非常に重要です。仮にあなたのデバウンス値を500に設定すると、tick値は500になりますこのような状況でテストコードを渡したい場合は、テストコードで指定します。

tick(299)を設定した場合、テストは失敗しますが、デバウンスの値を "300"に設定するため、これが正しいことがわかります。これはあなたにfakeAsync()/ tick()を使う力を示し、あなたはコードのタイミングを制御します(あなたはfakeAsync()/ tick():Pを使うときはMASTER OF TIMEです)。


// component.sandbox.spec.ts 
import { async, TestBed, fakeAsync, tick, inject } from "@angular/core/testing"; 
import { ReactiveFormsModule } from "@angular/forms"; 
import { SandboxComponent } from "./component.sandbox"; 
import { ItemService } from "../../Providers"; 
import "rxjs/add/operator/debounceTime"; 

describe("testFormControl",() => { 
    beforeEach(async(() => { 
    TestBed.configureTestingModule({ 
     imports: [ReactiveFormsModule], 
     declarations: [SandboxComponent], 
     providers: [ItemService], 
    }).compileComponents(); 
    })); 

    // The test you had questions about :) 
    it("(fakeAsync usage) Should hit the ItemService instance's 'update' method once", fakeAsync(inject([ItemService], (itemService: ItemService) => { 
    spyOn(itemService, "update"); 
    let fixture = TestBed.createComponent(SandboxComponent); 
    fixture.detectChanges(); // It is best practices to call this after creating the component b/c we want to have a baseline rendered component (with ng2 change detection triggered) after we create the component and trigger all of its lifecycle events of which may cause the need for change detection to occur, in the case attempted template data bounding occurs. 

    let componentUnderTest = fixture.componentInstance; 

    componentUnderTest.saveItem("someValueIWantToSaveHEHEHE"); 

    tick(300); // avoliva :) 

    expect(itemService.update).toHaveBeenCalled(); 

    }))); 

}); 

​​
// ../../Provider/index.ts 
export class ItemService { 
    public update(formControlInstanceValue: any) { 
    // Makes http request to api to update item 
    console.log(`HEY PROGRAMMER, YEAH YOU! :P \n => http request could have been made 
    here to update an 'item' in the database.`); 
    } 
} 
関連する問題