J'ai un composant dans angular 2 qui répond aux changements dans les paramètres de route (le composant ne se recharge pas à partir de zéro car nous ne sortons pas de la route principale. Voici le code du composant:
export class MyComponent{
ngOnInit() {
this._routeInfo.params.forEach((params: Params) => {
if (params['area']){
this._pageToShow =params['area'];
}
});
}
}
Cela fonctionne avec un traitement et _pageToShow
est défini de manière appropriée sur la navigation.
J'essaie de tester le comportement sur une modification de la route (donc un deuxième déclencheur de l'observable, mais il refuse de travailler pour moi.) Voici ma tentative:
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");
}));
Mais cela génère une exception TypeError: Cannot read property 'subscribe' of undefined
lorsque je l'exécute. Si je l'exécute sans la ligne fixture.detectChanges();
, il échoue, comme la deuxième attente échoue.
Premièrement, vous devriez utiliser une Subject
au lieu d'une Observable
. L'observable n'est souscrit qu'une seule fois. Donc, il n’émettra que le premier ensemble de paramètres. Avec une Subject
, vous pouvez continuer à émettre des éléments, et l'abonnement unique continuera à les obtenir.
let params: Subject<Params>;
beforeEach(() => {
params = new Subject<Params>();
TestBed.configureTestingModule({
providers: [
{ provide: ActivatedRoute, useValue: { params: params }}
]
})
})
Ensuite, dans votre test, émettez simplement de nouvelles valeurs avec params.next(newValue)
.
Deuxièmement, vous devez vous assurer d’appeler tick()
. C’est ainsi que fonctionne fakeAsync
. Vous contrôlez la résolution des tâches asynchrones. Comme l’observable est asynchrone, au moment où nous envoyons l’événement, il ne sera pas transmis à l’abonné de manière synchrone. Nous devons donc forcer le comportement synchrone avec tick()
Voici un test complet (Subject
est importé de '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');
}));
});
Je préfère obtenir les paramètres de route et les données de ActivatedRouteSnapshot comme ceci this.route.snapshot.params['type']
Si vous utilisez la même manière, vous pouvez le tester comme ceci
1) chez vos prestataires de test
{provide: ActivatedRoute, useValue: {snapshot: { params: { type: '' } }}}
2) dans vos spécifications de test
it('should...', () => {
component.route.snapshot.params['type'] = 'test';
fixture.detectChanges();
// ...
});