Publié le 08/16/2017, rédigé par Chloé MAHALIN

Angular 4

Tester un composant HTML select dans un composant Angular

Prérequis
- [ajouter un select à une vue](/university/frameworks/angular/104_add_select_component_in_view).

Objectif

Angular4 est un framework web qui n'exclue pas le test unitaire. Un code maintenable et durable passe par la mise en place de tests unitaires et d'intégration. D'autant plus que Karma et Jasmine.js

Mais encore faut-il savoir gérer l'événementiel des composants HTML dans les TU avec Angular.

Ici

Préparons notre test

Créons un composant simple :

myComponent.html

<div>
    <select [(ngModel)]="selected">
        <option [ngValue]="''"> -- Choisir -- </option>
        <option [ngValue]="'FRANCE'">France</option>
        <option [ngValue]="'CANADA'">Canada</option>
        <option [ngValue]="'MAROC'">Maroc</option>
    </select>
    {{selected}}
</div>

myComponent.ts

import { Component } from '@angular/core';

@Component({
  selector: 'myComponent-tag'
    -
  templateUrl: './myComponent.html'
    -
  styleUrls: ['./myComponent.css']
})
export class MyComponent {

  selected: string;
}

Je vous épargne la rédaction du css

Pour résumer ! Nous disposons dans la vue d'un select dont la valeur est liée à la variable 'selected' du model de mon composant.

Lorsqu'une sélection aura lieu

Créons la classe de test associée :

myComponent.spec.ts

import { ComponentFixture
    - TestBed
    - tick
    - fakeAsync
    - async } from '@angular/core/testing';
import { FormBuilder
    - FormsModule
    - ReactiveFormsModule  } from '@angular/forms';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { MyComponent } from './myComponent';

describe('Input testing :'
    - () => {

  let comp:                 MyComponent;
  let fixture:              ComponentFixture<MyComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ FormsModule
    - ReactiveFormsModule ]
    -
      declarations: [ MyComponent ]
    -
      providers:    [ FormBuilder ]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    comp = fixture.componentInstance;
  });

});

On peut constater que nous allons évaluer dans un environnement de test simulé asynchrone. Ceci afin de permettre les mises à jour depuis et vers la vue. Nous allons ajouter des tests à cette classe.

Vérifier la valeur contenue dans un select

myComponent.spec.ts

  it('the selected value should be updated with the variable value'
    - fakeAsync(() => {
    // On met à jour la variable dans le modèle
    comp.selected = 'MAROC';
    // On détecte les modifications depuis le modèle.
    fixture.detectChanges();
    tick();

    // On récupère le select dans la vue
    const select = fixture.debugElement.query(By.css('select')).nativeElement;

    // On vérifie la valeur du select
    expect(select.value).toEqual('3: MAROC');
  }));

Pour faire ce test

Dans cet exemple

Déclencher la mise à jour du modèle depuis le select

Maintenant

myComponent.spec.ts

  it('the variable should be updated with the selection'
    - () => {
    // On récupère le select dans la vue
    const select = fixture.debugElement.query(By.css('select')).nativeElement;

    // On sélectionne dans la liste
    select.value = '2: CANADA';
    select.dispatchEvent(new Event('change'));

    // On vérifie la valeur de la variable
    expect(comp.selected).toEqual('CANADA');
  });

Nous avons pu tester que le model est mis à jour depuis la vue. Maintenant

Simuler un évènement sur un input

Reprenons notre composant et rajoutons-lui un peu de contenu :

myComponent.html

<div>
  <select [(ngModel)]="selected" (change)='checkSelectedIsNotEmpty()'>
    <option selected [ngValue]="''"> -- Choisir -- </option>
    <option [ngValue]="'FRANCE'">France</option>
    <option [ngValue]="'CANADA'">Canada</option>
    <option [ngValue]="'MAROC'">Maroc</option>
  </select>
  {{selected}} {{ selectedIsEmpty ? 'A selection should be done' : '' }}
</div>

myComponent.ts

import { Component } from '@angular/core';

@Component({
  selector: 'myComponent-tag'
    -
  templateUrl: './myComponent.html'
    -
  styleUrls: ['./myComponent.css']
})
export class MyComponent {

    selected: string = '';
    selectedIsEmpty: boolean = true;

    checkSelectedIsNotEmpty(): void {
        this.selectedIsEmpty = this.selected.length == 0;
    }
}

Nous avons rajouté une méthode qui se déclenchera à chaque fois d'une sélection aura lieu dans le select. Elle vérifie qu'une valeur a été selectionnée.

Maintenant

myComponent.spec.ts

it('the method should be triggered with the selection'
    - () => {
    // On récupère le select dans la vue
    const select = fixture.debugElement.query(By.css('select')).nativeElement;

    // On sélectionne dans la liste
    select.value = '2: CANADA';
    select.dispatchEvent(new Event('change'));

    // On vérifie la valeur de la variable
    expect(comp.selectedIsEmpty).toBeFalsy();
});

En fait