9

我有一個角度爲2的組件,它響應路由參數的變化(組件不會從頭開始重新加載,因爲我們沒有移出主路徑。組件代碼:Angular 2 - 測試路由參數變化

export class MyComponent{ 
    ngOnInit() { 
     this._routeInfo.params.forEach((params: Params) => { 
      if (params['area']){ 
       this._pageToShow =params['area']; 
      } 
     }); 
    } 
} 

這個工作的治療和_pageToShow是在導航設置適當

我試圖測試上更改了航線(所以觀察到的第二個觸發的行爲,但它。拒絕爲我工作。)這是我的嘗試:

it('sets PageToShow to new area if params.area is changed', fakeAsync(() => { 
    let routes : Params[] = [{ 'area': "Terry" }]; 
    TestBed.overrideComponent(MyComponent, { 
     set: { 
      providers: [{ provide: ActivatedRoute, 
       useValue: { 'params': Observable.from(routes)}}] 
     } 
    }); 

    let fixture = TestBed.createComponent(MyComponent); 
    let comp = fixture.componentInstance; 
    let route: ActivatedRoute = fixture.debugElement.injector.get(ActivatedRoute); 
    comp.ngOnInit(); 

    expect(comp.PageToShow).toBe("Terry"); 
    routes.splice(2,0,{ 'area': "Billy" }); 

    fixture.detectChanges(); 
    expect(comp.PageToShow).toBe("Billy"); 
})); 

但是,當我運行它時,會拋出TypeError: Cannot read property 'subscribe' of undefined異常。如果我運行它沒有fixture.detectChanges();行,它會失敗,因爲第二個期望失敗。

回答

14

首先,您應該使用Subject而不是Observable。觀察者只能訂閱一次。所以它只會發出第一組參數。使用Subject,您可以繼續排放物品,單個訂閱將繼續獲取它們。

let params: Subject<Params>; 

beforeEach(() => { 
    params = new Subject<Params>(); 
    TestBed.configureTestingModule({ 
    providers: [ 
     { provide: ActivatedRoute, useValue: { params: params }} 
    ] 
    }) 
}) 

然後在你的測試中,發出新值params.next(newValue)

其次,您需要確保致電tick()。這是fakeAsync的工作原理。您控制異步任務解決方案。由於可觀察性是asychrounous,我們發送事件的時刻,它不會同步到達用戶。因此,我們需要強行與tick()

下面是一個完整的測試(Subject'rxjs/Subject'進口)

@Component({ 
    selector: 'test', 
    template: ` 
    ` 
}) 
export class TestComponent implements OnInit { 

    _pageToShow: string; 

    constructor(private _route: ActivatedRoute) { 
    } 

    ngOnInit() { 
    this._route.params.forEach((params: Params) => { 
     if (params['area']) { 
     this._pageToShow = params['area']; 
     } 
    }); 
    } 
} 

describe('TestComponent',() => { 
    let fixture: ComponentFixture<TestComponent>; 
    let component: TestComponent; 
    let params: Subject<Params>; 

    beforeEach(() => { 
    params = new Subject<Params>(); 
    TestBed.configureTestingModule({ 
     declarations: [ TestComponent ], 
     providers: [ 
     { provide: ActivatedRoute, useValue: { params: params } } 
     ] 
    }); 
    fixture = TestBed.createComponent(TestComponent); 
    component = fixture.componentInstance; 
    }); 

    it('should change on route param change', fakeAsync(() => { 
    // this calls ngOnInit and we subscribe 
    fixture.detectChanges(); 

    params.next({ 'area': 'Terry' }); 

    // tick to make sure the async observable resolves 
    tick(); 

    expect(component._pageToShow).toBe('Terry'); 

    params.next({ 'area': 'Billy' }); 
    tick(); 

    expect(component._pageToShow).toBe('Billy'); 
    })); 
}); 
+1

同步行爲,確保在這個解決方案中包含的'滴答向下滾動()'函數!我第一次完全錯過了。感謝您的解決方案,這對我工作:) –

+0

我已經能夠使用這種方法'片段'也用於內部鏈接:'片段=新主題();',這適用於隱藏/顯示標籤內容, 例如。 –