web-dev-qa-db-fra.com

Tester une méthode souscrite à un observable - Angular 2

Je souhaite tester une méthode dans un composant Angular 2 qui est abonné à un observable renvoyé par une méthode dans un service. Voici le code de la méthode de service en résumé: 

public create(user: User): Observable<any> {
  return this.http.post(this._api.create,
    JSON.stringify(user), {
      headers: this.apiConfig.getApiHeaders()
    }).map((res: Response) => res.json());
  }

Il est facile de tester cette méthode à l'unité, car elle renvoie un résultat observable afin que je puisse simplement m'abonner. Mais je veux tester la méthode dans le composant qui est déjà abonné à ceci: 

public onSubmit(user: User): void {
  this._authentication.create(user).subscribe((token) => {
    localStorage.setItem('token', token);
    this.router.navigate(['/Home']);
  });
}

Heres mes spécifications jusqu'à présent, mais lorsque j'essaie d'espionner le localStorage.setItem, il revient comme n'étant pas appelé. D'après ce que j'ai compris, il vérifie probablement si l'appel a été fait avant l'appel.

it('Should login a user and on success store a token in localStorage',
  injectAsync([TestComponentBuilder], (tcb) => {
    return tcb.createAsync(Login).then((fixture) => {
      let instance = fixture.debugElement.componentInstance;
      localStorage.clear();
      spyOn(localStorage, 'setItem');
      instance.onSubmit({userId: '[email protected]', password: 'password', siteName: 'sample'});
      expect(localStorage.setItem).toHaveBeenCalled();
    });
  })
);

Je me demande si je dois me moquer de la méthode this._authentication.create pour renvoyer une nouvelle observable avec une réponse fictive. 

Après plus de recherches, quelques articles ont indiqué que je devais simuler le service et renvoyer un Observable.of () qui fonctionne de manière synchrone pour résoudre le problème, copions le code ci-dessous. Cependant, cela ne fonctionne toujours pas, j'ai travaillé dessus presque toute la journée, je ne pense pas que cela devrait être si difficile, aucune aide appréciée. 

class MockAuthentication extends Authentication {
  public create(user: Object): Observable<any> {
    return Observable.of({'test': 'test'});
  }
}
8
HomeBrew

Ok, ça m’a pris presque toute la journée, mais j’ai finalement craqué. Au lieu d'utiliser injectAsync et TestComponentBuilder pour configurer la spécification, j'ai simplement besoin d'utiliser inject et injecter le composant comme vous le faites pour un service. Cela semble bien car je n'ai pas besoin de tester quoi que ce soit dans la vue, comme les événements. 

Voici la spécification finale qui fonctionne: 

it('Should set token in localStorage, set the new user, 
and navigate to home page on succesful login', 
  inject([Login], (login) => {
    login.router.config([ { path: '/', name: 'Home', component: Home }]);
    spyOn(localStorage, 'setItem');
    spyOn(login._currentUser, 'set');
    spyOn(login.router, 'navigate');
    login.onSubmit({ userId: '[email protected]', password: 'password', siteName: 'sample' });
    expect(localStorage.setItem).toHaveBeenCalledWith('token', 'newToken');
    expect(login._currentUser.set).toHaveBeenCalledWith({ 'test': 'one' });
    expect(login.router.navigate).toHaveBeenCalledWith(['/Home']);
}));

J'espère que cela pourrait aider quelqu'un à l'avenir. 

3
HomeBrew

Je suppose que vous voulez injecter une instance Router fictive à votre composant, puis après l'appel de navigate(['/Home']) sur la maquette Router, vous vérifiez si localStorage.setItem(...) a été appelé.

1
Günter Zöchbauer