125 votes

Comment tester un composant qui dépend des paramètres de ActivatedRoute ?

Je teste un composant qui est utilisé pour modifier un objet. L'objet a un nom unique id qui est utilisé afin de saisir l'objet spécifique à partir d'un tableau d'objets qui sont hébergés dans un service. L'objet spécifique id est obtenu par le biais d'un paramètre qui est transmis via le routage, plus précisément par le biais de la fonction ActivatedRoute classe.

Le constructeur est le suivant :

 constructor(private _router:Router, private _curRoute:ActivatedRoute, private _session:Session) {
}

ngOnInit() {
    this._curRoute.params.subscribe(params => {
        this.userId = params['id'];
        this.userObj = this._session.allUsers.filter(user => user.id.toString() === this.userId.toString())[0];

Je veux exécuter des tests unitaires de base sur ce composant. Cependant, je ne suis pas sûr de la manière dont je peux injecter le composant id et le composant besoins ce paramètre.

Au fait : J'ai déjà une maquette pour le Session service, donc pas d'inquiétude à ce sujet.

4voto

Diego Herrera Points 121

J'ai rencontré le même problème en créant des suites de test pour un chemin de routage comme :

{
   path: 'edit/:property/:someId',
   component: YourComponent,
   resolve: {
       yourResolvedValue: YourResolver
   }
}

Dans le composant, j'ai initialisé la propriété passée comme :

ngOnInit(): void {    
   this.property = this.activatedRoute.snapshot.params.property;
   ...
}

Lors de l'exécution des tests, si vous ne passez pas une valeur de propriété dans votre mock ActivatedRoute "useValue", vous obtiendrez un résultat indéfini lors de la détection des changements à l'aide de "fixture.detectChanges()". Ceci est dû au fait que les valeurs fantaisie pour ActivatedRoute ne contiennent pas la propriété params.property. Il est donc nécessaire que la valeur fictive useValue contienne ces paramètres pour que le dispositif fixe puisse initialiser la propriété 'this.property' dans le composant. Vous pouvez l'ajouter comme :

  let fixture: ComponentFixture<YourComponent>;
  let component: YourComponent;
  let activatedRoute: ActivatedRoute; 

  beforeEach(done => {
        TestBed.configureTestingModule({
          declarations: [YourComponent],
          imports: [ YourImportedModules ],
          providers: [
            YourRequiredServices,
            {
              provide: ActivatedRoute,
              useValue: {
                snapshot: {
                  params: {
                    property: 'yourProperty',
                    someId: someId
                  },
                  data: {
                    yourResolvedValue: { data: mockResolvedData() }
                  }
                }
              }
            }
          ]
        })
          .compileComponents()
          .then(() => {
            fixture = TestBed.createComponent(YourComponent);
            component = fixture.debugElement.componentInstance;
            activatedRoute = TestBed.get(ActivatedRoute);
            fixture.detectChanges();
            done();
          });
      });

Vous pouvez alors commencer à faire des tests, par exemple :

it('should ensure property param is yourProperty', async () => {
   expect(activatedRoute.snapshot.params.property).toEqual('yourProperty');
   ....
});

Maintenant, si vous souhaitez tester une autre valeur de propriété, vous pouvez mettre à jour votre mock ActivatedRoute comme suit :

  it('should ensure property param is newProperty', async () => {
    activatedRoute.snapshot.params.property = 'newProperty';
    fixture = TestBed.createComponent(YourComponent);
    component = fixture.debugElement.componentInstance;
    activatedRoute = TestBed.get(ActivatedRoute);
    fixture.detectChanges();

    expect(activatedRoute.snapshot.params.property).toEqual('newProperty');
});

J'espère que cela vous aidera !

4voto

Wy-Xc Points 11

Angular 11 : ajoutez ceci dans votre fichier spec

imports: [
   RouterTestingModule.withRoutes([])
],

cela m'a aidé avec une seule ligne, avec d'autres vous avez besoin d'un fournisseur de simulacre.

3voto

Shashank Sharma Points 41

Pour certaines personnes travaillant sur Angular > 5, Si Observable.of() ; ne fonctionne pas, on peut utiliser uniquement of() en important import { of } de 'rxjs' ;

0voto

adelinor Points 16

Ajouté le fournisseur dans la classe de test comme :

{
  provide: ActivatedRoute,
  useValue: {
    paramMap: of({ get: v => { return { id: 123 }; } })
  } 
}

0voto

mattanja Points 664

Toutes les autres réponses jusqu'à présent ne fournissent que la valeur de la route param. Que faire si vous voulez tester le déclencheur de changement de route lui-même ? Vous pouvez fournir l'ActivatedRoute dans votre test avec un Subject et son Observable, ainsi vous pouvez déclencher le changement de route avec source.next().

Code en cours de test :

    constructor(private readonly route: ActivatedRoute) {}

    ngOnInit(): void {
      this.routeParamSubscription = this.route.params.subscribe((params) => {
        if (params['id']) {
          this.loadDetails(params['id']);
        }
      });
    }

Code de test :

    let routeChangeSource: BehaviorSubject<Params>;
    // In TestBed.configureTestingMethod
    ...
      providers: [
        {
          provide: ActivatedRoute,
          useValue: {
            params: routeChangeSource.asObservable()
          }
        }
      ]
    ...
    it('loads data on route change', fakeAsync(() => {
      const spy = spyOn(component, 'loadDetails').and.callThrough();
      routeChangeSource.next({ id: 99 });
      tick();
      expect(spy).toHaveBeenCalledOnceWith(99);
    }));

Cela teste l'action déclenchée après le changement d'itinéraire et s'assure qu'elle est activée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X