Tests de bout en bout
Commandes Git
Les commandes GIT suivantes permettent d’accéder au code source des chapitres précédents :
cd C:\
git clone https://github.com/EditionsENI/JavaScriptEtAngular.git
cd C:\JavaScriptEtAngular\Angular
git checkout chapitre18
code .
Introduction
Un test de bout en bout est exactement l’inverse d’un test unitaire. Cette fois-ci, le but est de vérifier l’application entière, du début jusqu’à la fin, et en passant par toutes les étapes possibles. L’ensemble des cas d’utilisation devant être testé.
Le développeur va donc chercher à tester tous les composants, tous les services, toutes les dépendances et même tous les clics de souris possibles. Si l’utilisateur peut le faire, le test de bout en bout doit l’avoir testé avant.
Lancer les tests de bout en bout d’un projet Angular est très simple. Il suffit, à la racine du projet, de lancer la commande :
ng e2e
Exécution d’un test de bout en bout sans aucun test
Protractor
Protractor est un cadriciel développé pour Angular basé sur Selenium. Il est écrit en Node.js et est une surcouche de WebDriverJS, l’implémentation officielle de Selenium dans le monde JavaScript. Sa configuration se résume à un seul fichier qu’Angular CLI a créé dans le dossier e2e : protractor.conf.js.
Dans ce fichier figurent le ou les navigateurs qui seront lancés et un patron pour retrouver les fichiers de tests de bout en bout dans le projet Angular.
// C:\JavaScriptEtAngular\Angular\monProjetAngular\e2e\
protractor.conf.js
const { SpecReporter } = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function () { }
},
onPrepare() {
require('ts-node').register({ ...
Tester les actions utilisateurs
Tester le contenu d’une balise HTML statique reste assez simple, mais la plupart des applications web travaillent avec des boutons, des champs de formulaire et des données affichées en constante évolution. Les tests de bout en bout ne sont pas complets si le remplissage des champs et les clics sur les boutons ne sont pas testés.
Le gabarit du composant c18 subit une modification afin d’intégrer un bouton et l’affichage d’un message suite à un clic.
<!-- C:\JavaScriptEtAngular\Angular\monProjetAngular\src\app\
composants\c18.component.html -->
<div>
<button name="guerre" class="des" id="boutons"
(click)="clique()"> Un bouton</button>
<div id="message">{{message}}</div>
</div>
La classe TypeScript est modifiée pour ajouter un peu d’interaction.
// C:\JavaScriptEtAngular\Angular\monProjetAngular\src\app\
composants\c18.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-c18',
templateUrl: './c18.component.html',
styleUrls: ['./c18.component.css']
})
export class C18Component implements OnInit {
message: String = "";
...
Et à part cliquer ?
L’ensemble des actions disponibles est répertorié sur le site web de Protractor : http://www.protractortest.org/#/api
Les éléments les plus utilisés peuvent être regroupés en deux familles : ceux qui concernent le navigateur et ceux qui concernent les actions sur les éléments récupérés.
1. Au niveau du navigateur
-
browser.get() permet de naviguer vers l’adresse donnée en paramètre. Cette méthode charge l’ensemble des éléments nécessaires au rendu de la page Angular. La méthode brower.getCurrentUrl() retourne l’URL complète actuelle.
-
browser.refresh() recharge la page web actuelle.
-
browser.actions() permet de définir une séquence d’actions qui ne sera exécutée qu’à l’appel de la méthode perform().
Pour enchaîner plusieurs actions il suffit de les séparer par un point : browser.actions( .doubleClick().clickAndHold().release().click().perform().
L’ensemble des actions disponibles figure sur le site de Selenium : https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/interactions/Actions.html.
2. Au niveau d’un élément
Le développeur testeur peut vouloir récupérer un élément ou plusieurs. element.all() permet de récupérer...
Cas concret : une liste et des boutons
Le composant C18 est, une nouvelle fois, modifié. Son gabarit affiche une liste HTML et un champ de saisie suivi d’un bouton pour ajouter un élément à la liste.
<!-- C:\JavaScriptEtAngular\Angular\monProjetAngular\src\app\
composants\c18.component.html -->
<div>
<ul *ngFor="let j of jedi" id="liste">
<li>{{j}}</li>
</ul>
<input type="text" name="prenom" id="prenom" #prenom>
<button (click)="ajoutJedi(prenom.value)" id="bouton">
Ajouter un Jedi</button>
</div>
La partie TypeScript du composant initialise la liste des Jedi avec trois éléments et implémente une méthode qui permet, à partir d’un paramètre, d’ajouter un élément à la liste. Bien entendu, un élément vide ou bien un élément déjà présent dans la liste ne doit pas pouvoir être ajouté.
// C:\JavaScriptEtAngular\Angular\monProjetAngular\src\app\
composants\c18.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-c18',
templateUrl: './c18.component.html', ...
Mise en pratique
1. Énoncé
À partir de l’application PokemonManager développée dans les chapitres précédents, effectuez les tests de bout en bout suivants :
-
Sur la page principale :
-
La navigation vers la page principale.
-
Le lien hypertexte vers /generations.
-
Le lien hypertexte vers /pokemons.
-
Sur la page Générations
-
La navigation au sein de la page.
-
Le nombre de générations de Pokémon doit être supérieur à zéro.
-
Sur la page Pokémons :
-
Le nombre de Pokémon doit être supérieur à zéro.
-
L’easter egg doit être caché au départ.
-
L’easter egg apparaît si le Pokémon recherché est C3PO.
Bien évidemment, tous les tests de bout en bout que vous jugerez nécessaires sont à ajouter à cette liste.
2. Correction
a. Page principale
La page principale app.po.ts ne possède que trois méthodes, dont deux, très similaires, qui s’appuient sur des balises <a>.
// C:\JavaScriptEtAngular\Angular\PokemonManager\e2e\src\
app.po.ts
import { browser, by, element } from 'protractor';
export class AppPage {
// Navigation vers la page principale
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
// Lien hypertexte vers /generations
lienGenerations() {
return element(by.id('lienGenerations'));
}
// Lien hypertexte vers /pokemons
lienPokemons() {
return element(by.id('lienPokemons'));
}
}
Les tests implantés sont relativement simples. Ils simulent un clic sur un bouton puis l’autre et espèrent provoquer une navigation vers une autre page.
// C:\JavaScriptEtAngular\Angular\PokemonManager\e2e\src\
app.e2e-spec.ts
import { AppPage } from './app.po';
import { browser...