Comment puis-je tester les routeurs dans la version angulaire 2.0.0 avec le karma et le jasmin?
Voici à quoi ressemble mon ancien test unitaire dans la version 2.0.0-beta.14
import {
it,
inject,
injectAsync,
beforeEach,
beforeEachProviders,
TestComponentBuilder
} from 'angular2/testing';
import { RootRouter } from 'angular2/src/router/router';
import { Location, RouteParams, Router, RouteRegistry, ROUTER_PRIMARY_COMPONENT } from 'angular2/router';
import { SpyLocation } from 'angular2/src/mock/location_mock';
import { provide } from 'angular2/core';
import { App } from './app';
describe('Router', () => {
let location, router;
beforeEachProviders(() => [
RouteRegistry,
provide(Location, {useClass: SpyLocation}),
provide(Router, {useClass: RootRouter}),
provide(ROUTER_PRIMARY_COMPONENT, {useValue: App})
]);
beforeEach(inject([Router, Location], (_router, _location) => {
router = _router;
location = _location;
}));
it('Should be able to navigate to Home', done => {
router.navigate(['Home']).then(() => {
expect(location.path()).toBe('');
done();
}).catch(e => done.fail(e));
});
});
Pour tester, nous créons maintenant un module de test utilisant TestBed
. Nous pouvons utiliser le TestBed#configureTestingModule
et lui transmettre un objet de métadonnées de la même manière que nous le transmettrions à @NgModule
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ /* modules to import */ ],
providers: [ /* add providers */ ],
declarations: [ /* components, directives, and pipes */ ]
});
});
Pour le routage, au lieu d'utiliser la variable normale RouterModule
, nous utiliserions plutôt RouterTestingModule
. Ceci configure les Router
et Location
, de sorte que vous n'avez pas besoin de vous-même. Vous pouvez également y emprunter des routes en appelant RouterTestingModule.withRoutes(Routes)
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])
]
})
Pour obtenir Location
et Router
dans le test, la même chose fonctionne, comme dans votre exemple.
let router, location;
beforeEach(() => {
TestBed...
});
beforeEach(inject([Router, Location], (_router: Router, _location: Location) => {
router = _router;
location = _location;
}));
Vous pouvez également injecter dans chaque test si nécessaire
it('should go home',
async(inject([Router, Location], (router: Router, location: Location) => {
})));
La async
ci-dessus est utilisée comme done
sauf que nous n'avons pas besoin d'appeler explicitement done
. Angular le fera pour nous une fois toutes les tâches asynchrones terminées.
Une autre façon d’obtenir les fournisseurs est de passer au banc d’essai.
let location, router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])],
});
let injector = getTestBed();
location = injector.get(Location);
router = injector.get(Router);
});
Voici un test complet, refactoring votre exemple
import { Component } from '@angular/core';
import { Location } from '@angular/common';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { fakeAsync, async, inject, TestBed, getTestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
@Component({
template: `
<router-outlet></router-outlet>
`
})
class RoutingComponent { }
@Component({
template: ''
})
class DummyComponent { }
describe('component: RoutingComponent', () => {
let location, router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])],
declarations: [RoutingComponent, DummyComponent]
});
});
beforeEach(inject([Router, Location], (_router: Router, _location: Location) => {
location = _location;
router = _router;
}));
it('should go home', async(() => {
let fixture = TestBed.createComponent(RoutingComponent);
fixture.detectChanges();
router.navigate(['/home']).then(() => {
expect(location.path()).toBe('/home');
console.log('after expect');
});
}));
});
De plus, si vous voulez simplement simuler le routeur, ce qui pourrait être le meilleur moyen de procéder à un test unitaire, vous pouvez simplement le faire.
let routerStub;
beforeEach(() => {
routerStub = {
navigate: jasmine.createSpy('navigate'),
};
TestBed.configureTestingModule({
providers: [ { provide: Router, useValue: routerStub } ],
});
});
Et dans vos tests, tout ce que vous voulez faire est de vérifier que le stub est appelé avec le bon argument, lorsque le composant interagit avec celui-ci.
expect(routerStub.navigate).toHaveBeenCalledWith(['/route']);
À moins que vous ne souhaitiez réellement tester un routage, c'est probablement la voie à suivre. Pas besoin de configurer un routage. Dans un test unitaire, si vous utilisez un routage réel, vous induisez des effets secondaires inutiles qui pourraient affecter ce que vous essayez réellement de tester, à savoir le comportement du composant. Et le comportement du composant est simplement d'appeler la méthode navigate
. Il n'est pas nécessaire de vérifier que le routeur fonctionne. Angular garantit déjà cela.
Au lieu d'utiliser useValue
pour routerStub
, vous pouvez utiliser useClass
dans providers
et cela a vraiment fonctionné pour moi.
export class RouterStub {
public url: string = '/';
constructor() { }
enter code here
navigateByUrl(url: any) {
this.url = url;
}
}
Et dans la beforeEach
, il suffit d'instancier l'objet routerStub
comme
routerStub = new RouterStub()
Et dans les cas de test
component.router.navigateByUrl('/test');
fixture.detectChanges();
Bonne approche suggérée par Paul J'ai également configuré mon routage de la même manière mais en plus, j'ai ajouté un service permettant de mettre à jour certaines données pour le routage, puis de vérifier l'emplacement actuel.
afin que vous puissiez ajouter un service pour mettre à jour les données sur les composants qui rendent certaines données et ensuite vérifier la navigation.
configurer ci-dessous dans TestBed.configureTestingModule
providers : [MyService]
puis créer obtenir un service dans foreach
myService= TestBed.get(MyService);
mettre à jour des données de service comme
myService.someMethodCall();
De cette façon, vous pouvez jouer après un rendu de données.