# Tests unitaires sur un composant Angular utilisant @Input() et @Output()

Nombreux sont les développeurs Angular qui ont peur d'écrire des tests unitaires ou ne savent carrément pas comment faire et par où commencer. Le but de cet article est de prendre un léger exemple afin de démystifier la complexité autour des tests unitaires. Nous utiliserons bien-sûr le combo `Jasmine/Karma` qui est déjà présent lors de la création d'un projet Angular.

En effet, `Jasmine` est un framework qui nous permet d'aller vite dans l'écriture de nos tests unitaires et `Karma` est un serveur qui nous permet de lancer nos tests avec un rendu de tout ce qui se passe sur notre navigateur.

> Considérons un composant réutilisable `HelloComponent` qui permet d'afficher le nom de l'utilisateur (`username`) dès qu'on clique sur un bouton (`Hello`).

```xml
<div>
    <p> {{ username }} </p>
   <button (click)='sayHello(username)'> Hello </button>
</div>
```

```typescript
export class HelloComponent {
    @Input() username = '';
    @Output() hello = new EventEmitter<string>()

    public sayHello(username: string): void {
        this.hello.emit(username);
    }
}
```

Comme nous pouvons le pouvoir, nous avons notre composant `HelloComponent` qui comprend :

* `username` qui est notre propriété `Input()`
    
* `hello` qui est notre évènement `Output()`
    

Notre composant réutilisable pourra être appelé par un composant parent comme ceci par exemple :

```xml
<app-hello [username]="'john'" (hello)="onSayHello($event)">
</app-hello>
```

En créant un composant Angular, nous avons généralement un fichier qui a pour extension `` `.spec.ts` ``. C'est le fichier dédié à l'écriture des tests unitaires liés à notre composant. En ouvrant le fichier `hello.component.spec.ts` qui fait référence à notre composant HelloComponent, nous avons ce code de base :

```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { NotificationToastComponent } from './hello.component';

describe('HelloComponent', () => {
  let component: HelloComponent;
  let fixture: ComponentFixture<HelloComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ HelloComponent ]
    })
    .compileComponents();

    fixture = TestBed.createComponent(HelloComponent);
    component = fixture.componentInstance;
    component.username = 'john';
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});
```

* Le code généré nous a créé une instance du composant `HelloComponent`. Ensuite, il a fait appel à la méthode `detectChanges()` pour mettre à jour la vue si entre temps une propriété du composant a été modifié.
    
* Nous avons rajouté `component.username = 'john';` afin qu'il initialise la valeur de `username` avec `'john'` lors de la création de l'instance.
    

Nous pouvons à présent écrire les tests unitaires qu'il faut par rapport à notre logique métier. Nous écrirons deux tests unitaires :

**1) Le premier test vise à vérifier que notre variable** `username` **est bien affichée sur notre interface :**

```typescript
it('should display username', () => {
  const messageElement = fixture.nativeElement.querySelector('p');
  expect(messageElement.textContent).toContain('john');
});
```

* Dans notre premier test ci-dessus, nous avons sélectionné l'élément `HTML` qui affiche la propriété `username` et vérifié qu'il contient la valeur `"john"`. La valeur de `username` a été initialisée dans la méthode `beforeEach()` .
    

**2) Le second test vise à vérifier que l'évènement** `hello()` **est émise lorsqu'on fait appel à la méthode** `sayHello()` **:**

```typescript
   it('should emit hello event', () => {
    spyOn(component.hello, 'emit');
    component.sayHello('john');
    expect(component.hello.emit).toHaveBeenCalledWith('john');
  });
```

* Dans notre second test ci-dessus, nous avons utilisé la méthode `spyOn()` pour espionner l'évènement `hello()`. En effet, `spyOn()` est une fonction qui enregistre des informations sur les appels de la méthode à espionner, comme le nombre de fois où elle a été appelée, avec quels arguments et ce qu'elle a renvoyé. Enfin, nous avons vérifié que l'événement `hello()` a été émis avec la valeur `'john'` lorsqu'on appelle la fonction `sayHello()`.
    

> Nous pouvons lancer la commande `ng test` pour lancer le serveur `Karma` et voir le rendu de nos tests unitaires sur un navigateur.

Pour finir, voici le code complet lié aux tests unitaires sur notre composant `HelloComponent` :

```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { NotificationToastComponent } from './hello.component';

describe('HelloComponent', () => {
  let component: HelloComponent;
  let fixture: ComponentFixture<HelloComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ HelloComponent ]
    })
    .compileComponents();

    fixture = TestBed.createComponent(HelloComponent);
    component = fixture.componentInstance;
    component.username = 'john';
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should display username', () => {
      const messageElement = fixture.nativeElement.querySelector('p');
      expect(messageElement.textContent).toContain('john');
  });
   
  it('should emit hello event', () => {
    spyOn(component.hello, 'emit');
    component.sayHello('john');
    expect(component.hello.emit).toHaveBeenCalledWith('john');
  });
});
```

En somme, nous avons exploré comment écrire des tests unitaires pour un composant Angular qui utilise les décorateurs `@Input()` et `@Output()`. Les tests unitaires sont une partie importante du processus de développement logiciel et nous espérons que nous les aborderons davantage avec plus d'aisance et moins de peur.

> Pour plus d'informations :
> 
> 👉 [Angular Testing](https://angular.io/guide/testing)
> 
> 👉 [Jasmine Documentation](https://jasmine.github.io/pages/getting_started.html)
