2016-04-05 19 views
1

我想測試一個angular2應用程序。我有一個登錄表單,它使用可觀察到的數據發送給後端:茉莉花:測試事件的可觀察性

doLogin() { 
    this.usersService.login(this.model) 
     .subscribe((data) => { 
      console.log("In observable: " + data.isSuccess); 
      if (!data.isSuccess) { 
       this.alerts.push({}); 
      } 
     }); 
} 

在測試中我加入的服務功能,它返回觀察到的間諜,使該組成部分能夠在它的工作:

usersService.login.and.returnValue(Observable.of(
    <LoginResponse>{ 
     isSuccess: true 
    })); 

當一切準備就緒,我派遣上提交按鈕的事件,這將觸發doLogin功能組件:

submitButton.dispatchEvent(new Event("click")); 
fixture.detectChanges(); 

它正常工作。不幸的是,當我檢查是否usersService.login被稱爲測試:

expect(usersService.login).toHaveBeenCalled(); 

我得到一個錯誤,因爲觀察到沒有完成,已登錄尚未調用。

我應該如何確定,在observable完成後檢查我的間諜?

回答

1

我不知道如何在組件上配置服務,但是當我覆蓋從TestComponentBuilder創建的組件的提供者時,它適用於我。

讓我們來看一個例子。我有一個返回字符串列表的服務:

import {Observable} from 'rxjs/Rx'; 

export class MyService { 
    getDogs() { 
    return Observable.of([ 's1', 's2', ... ]); 
    } 
} 

組件使用該服務來異步顯示列表中點擊一個按鈕時:

@Component({ 
    selector: 'my-list', 
    providers: [MyService], 
    template: ` 
    <ul><li *ngFor="#item of items">{{ item }}</li></ul> 
    <div id="test" (click)="test()">Test</div> 
    ` 
}) 
export class MyList implements OnInit { 
    items:Array<string>; 
    service:MyService; 

    constructor(private service:MyService) { 
    } 

    test() { 
    this.service.getDogs().subscribe(
     (dogs) => { 
     this.items = dogs; 
     }); 
    } 
} 

我想測試,當我點擊「測試」按鈕,將調用該組件的test方法,並間接調用該服務的getDogs方法。

爲此,我創建了一個測試,它直接實例化服務並使用TestComponentBuilder加載組件。在這種情況下,我需要在調用createAsync之前調用overrideProviders方法。這樣,您將能夠提供您的間諜服務以獲得通知。下面是一個示例:

let service:MyService = new MyService(); 

beforeEach(() => { 
    spyOn(service, 'getDogs').and.returnValue(Observable.of(
     ['dog1', 'dog2', 'dog3'])); 

}); 

it('should test get dogs', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => { 
    return tcb.overrideProviders(MyList, [provide(MyService, { useValue: service })]) 
       .createAsync(MyList).then((componentFixture: ComponentFixture) => { 
     const element = componentFixture.nativeElement; 
     componentFixture.detectChanges(); 

     var clickButton = document.getElementById('test'); 
     clickButton.dispatchEvent(new Event("click")); 

     expect(service.getDogs).toHaveBeenCalled(); 
    }); 
})); 

編輯

由於該事件是異步觸發,您可以考慮使用fakeAsync。後者允許您完全控制何時處理異步處理,並將異步事件轉換爲同步處理。爲你解答

+0

感謝:

你可以換你的測試加工成

fakeAsync((): void => { var clickButton = document.getElementById('test'); clickButton.dispatchEvent(new Event("click")); expect(service.getDogs).toHaveBeenCalled(); }); 

有關詳細信息,你可以看看這個問題。我以同樣的方式執行,但在我的情況下,在組件調用服務方法之前,正在檢查toHaveBeenCalled。 –

+0

我不確定要理解;-)組件同步調用該服務,服務方法執行異步並返回可觀察對象。對? –

+0

是的,沒錯,但據我所知,dispatchEvent是異步的,所以test()函數在異步模式下調用,期望在調用getDogs之前檢查。 –