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

我已经能够使用这种方法'片段'也用于内部链接:'片段=新主题();',这适用于隐藏/显示标签内容, 例如。 –