Tutoriel pour tester une webapp à l'aide de FluentLenium, en 5 minutes

Thierry Leriche-Dessirier

Lorsque vous développez un site Web, vous avez besoin de tester que les pages fonctionnent. Et ces tests doivent pouvoir s'automatiser lorsque le site grossit. L'outil le plus populaire est Selenium mais ce dernier n'est pas des plus simples à prendre en main. Heureusement, une bibliothèque française nommée FluentLenium simplifie le travail. C'est ce que nous allons voir dans cet article. Commentez

- Titre : Tutoriel pour tester une webapp à l'aide de FluentLenium, en 5 minutes

- Auteur : Thierry Leriche-Dessirier

- Parution : 30 novembre 2013

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2013 Thierry Leriche-Dessirier. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- I-A. À propos

- I-B. Avant de commencer

- I-C. Mises à jour

- II. Découverte du projet d'exemple

- II-A. Télécharger, installer et importer le projet d'exemple

- II-B. Ce que fait déjà le projet d'exemple

- III. Action

- III-A. Maven

- III-B. Page Object Pattern

- III-C. Un premier test

- III-D. Test de navigation

- III-E. Test du formulaire

- III-F. Des tests et des services

- IV. Conclusion

- V. Remerciements

- VI. Annexes

- VI-A. Liens

- VI-B. Liens perso

- VI-C. Code complet

I - Introduction

Lorsque vous développez un site Web, vous avez besoin de tester que les pages fonctionnent. Et ces tests doivent pouvoir s'automatiser lorsque le site grossit. Dans l'article Tutoriel sur le test d'applications Web avec Selenium, Denis Thomas nous présentait Selenium, l'outil Java le plus utilisé pour tester les IHM. Or Selenium n'est pas si simple à prendre en main.

Dans cet article, nous allons utiliser FluentLenium qui, comme son nom l'indique, permet de simplifier l'utilisation de Selenium tout en proposant de bonnes pratiques.

FluentLenium est une bibliothèque française : cocorico. Elle a été développée par Mathilde Lemée, qu'on croise régulièrement dans des grandes conférences comme Devoxx…

I-A - À propos

Découvrir une technologie n'est pas chose facile. En aborder plusieurs d'un coup l'est encore moins. Partant de ce constat, cet article a été écrit pour aller à l'essentiel. Les points importants sont présentés dans le corps de l'article et les éléments secondaires sont expliqués en annexe.

I-B - Avant de commencer

Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :

- Java JDK 1.6.0_24-b07 ;

- Eclipse Indigo 3.7 JEE 64b ;

- Maven 3.0.3 ;

- Tomcat 7.0.35 ;

- Pretty Faces 3.3.2 ;

- JUnit 4.11 ;

- FluentLenium 0.9.1.

I-C - Mises à jour

xxx: création

II - Découverte du projet d'exemple

II-A - Télécharger, installer et importer le projet d'exemple

Pour commencer, je vous propose de télécharger le fichier Zip« fibo-webapp-fluentlenium.zip », contenant un projet Java-Maven d'exemple (une mini webapp) qui va nous servir de support visuel pour les fonctionnalités présentées dans la suite de cet article.

Cette webapp est celle que nous avions développée dans l'article « De jolies URL dans vos applications Web JSF avec Pretty Faces ».

Compilez le projet d'exemple et importez-le dans Eclipse (comme expliqué dans le tutoriel « Importer un projet Maven dans Eclipse en 5 minutes ») ou dans l'IDE de votre choix.

Installez ensuite la webapp dans le serveur d'application de votre choix, par exemple Tomcat 6, ce que vous pouvez faire directement depuis Eclipse.

Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexe) et de faire confiance aux captures d'écran.

II-B - Ce que fait déjà le projet d'exemple

Le projet d'exemple est une petite webapp permettant de calculer plusieurs fonctions mathématiques célèbres. Cette application Web n'a rien de très complexe. Elle utilise le framework Web JSF, inclus dans Java JEE. Les fonctionnalités (calcul de la suite de Fibonacci et du factoriel) servent uniquement d'illustration.

La webapp est accessible à l'aide d'une adresse ressemblant à la suivante : http://localhost:8080/fibo-webapp-fluentlenium/

Page d'accueil

À partir du menu, on peut aller sur la page qui nous intéresse, permettant de calculer la suite de Fibonacci par exemple. C'est à cette fonction que nous allons plus particulièrement nous intéresser dans la suite. Par défaut, lorsqu'aucun rang n'a été précisé dans l'URL, la page affiche le résultat au rang « 2 », correspondant aux valeurs de base.

Rang 2

Il est bien entendu possible de calculer la suite de Fibonacci pour un autre rang, qu'on choisira à l'aide d'un champ de saisie.

Rang 8

Dans la suite, on va donc tester que ce parcours fonctionne bien.

III - Action

III-A - Maven

Durée estimée : 1 minute.

Pour utiliser FluentLenium, il faut ajouter une dépendance dans le fichier « pom.xml » . Ici on va utiliser la version FestAssert, car elle est pratique, mais on peut se contenter de JUnit.

Dépendance dans le pom.xml

<dependency>
<groupId>org.fluentlenium</groupId>
<artifactId>fluentlenium-festassert</artifactId>
<version>0.9.1</version>
</dependency>

Il n'est pas obligatoire de coder les tests dans le même projet que la webapp. La plupart du temps, vous allez d'ailleurs tester des webapp dont vous n'aurez pas le code. Elles seront peut-être même écrites à l'aide d'une autre techno comme PHP, .net ou tout simplement en HTML classique.

Puis relancer une installation Maven.

Commande Maven

mvn clean install eclipse:eclipse

En fonction des éléments déjà présents sur le disque dur, le résultat de l'installation Maven devrait ressembler à la trace suivante.

Commande Maven

C:\dvp\fibo-webapp-fluentlenium>set JAVA_HOME=C:\dev\javas\jdk1.6.0_24
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building fibo-webapp-fluentlenium 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: http://repo1.maven.org/maven2/org/fluentlenium/fluentlenium-core/0.9.1/fluentlenium-core-0.9.1.pom
Downloaded: http://repo1.maven.org/maven2/org/fluentlenium/fluentlenium-core/0.9.1/fluentlenium-core-0.9.1.pom (4 KB at 7.8 KB/sec)
Downloading: http://repo1.maven.org/maven2/org/fluentlenium/fluentlenium-parent/0.9.1/fluentlenium-parent-0.9.1.pom
Downloaded: http://repo1.maven.org/maven2/org/fluentlenium/fluentlenium-parent/0.9.1/fluentlenium-parent-0.9.1.pom (9 KB at 63.2 KB/sec)
Downloading: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-java/2.35.0/selenium-java-2.35.0.pom
Downloaded: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-java/2.35.0/selenium-java-2.35.0.pom (7 KB at 43.4 KB/sec)
Downloading: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-parent/2.35.0/selenium-parent-2.35.0.pom
Downloaded: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-parent/2.35.0/selenium-parent-2.35.0.pom (10 KB at 58.8 KB/sec)
Downloading: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-android-driver/2.35.0/selenium-android-driver-2.35.0.pom
...
[INFO] Not writing settings - defaults suffice
[INFO] File C:\dvp\fibo-webapp-fluentlenium\.project already exists.
Additional settings will be preserved, run mvn eclipse:clean if you want old settings to be removed.
[INFO] Wrote Eclipse project for "fibo-webapp-fluentlenium" to C:\dvp\fibo-webapp-fluentlenium.
[INFO]
Javadoc for some artifacts is not available.
List of artifacts without a javadoc archive:
o org.apache.httpcomponents:httpclient:4.2.1
o org.apache.httpcomponents:httpcore:4.2.1
o org.apache.httpcomponents:httpmime:4.2.3
o io.netty:netty:3.5.2.Final

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1:55.578s
[INFO] Finished at: Sat Nov 30 16:33:54 CET 2013
[INFO] Final Memory: 13M/118M
[INFO] ------------------------------------------------------------------------

On doit ensuite faire un refresh (touche F5) dans Eclipse pour faire apparaitre FluentLenium dans la liste des bibliothèques référencées.

III-B - Page Object Pattern

Durée estimée : 1 minute.

On va donc s'intéresser à trois écrans : la page d'accueil, la page pour calculer la suite de Fibonacci et la page des résultats. Avant de savoir si ces pages fonctionnent, encore faut-il savoir naviguer dessus.

FluentLenium recommande d'employer le pattern « Page Object Pattern » au lieu de coder les appels en dur.

On va donc créer trois classes dédiées à cette opération : HomePage, FiboPage et FiboResultPage. Il faut redéfinir les méthodes « getUrl() » et « isAt() ». Elles servent respectivement à indiquer l'adresse cible et savoir si on est bien arrivé. Voici ce que ça donne pour la première :

HomePage

public class HomePage extends FluentPage {

private final static String URL = "http://localhost:8080/fibo-webapp-fluentlenium";
private final static String TITLE = "fibowebapp";

@Override
public String getUrl() {
return URL;
}

@Override
public void isAt() {
Assertions.assertThat(title()).isEqualTo(TITLE);
}

}

Le titre des pages reste le même sur tout le site. Du coup, le test de la valeur du titre permet de savoir qu'on est sur le bon site, mais pas forcément sur la page d'accueil. Ici, ce n'est pas bien grave puisqu'on est surtout intéressé de savoir qu'on est bien sur le site, lorsqu'on parle de l'accueil, avec les menus et les éléments englobants. Si on veut vraiment la page d'accueil (et aucune autre), on devra être plus spécifique et on utilisera une des techniques qu'on va voir dans la suite.

Nous reviendrons rapidement sur les deux autres pages.

III-C - Un premier test

Durée estimée : 1 minute.

On peut maintenant tester si les pages fonctionnent bien. Voyons déjà ce que ça donne avec l'accueil. Pour cela, on va écrire un petit test :

Test de la page d'accueil

public class HomeTest extends FluentTest {

public WebDriver webDriver = new HtmlUnitDriver();

@Page
public HomePage homePage;

@Test
public void testHomePage() {
// Aller sur la page d'accueil
goTo(homePage);

// Verifier qu'on est bien arrive
homePage.isAt();
}

@Override
public WebDriver getDefaultDriver() {
return webDriver;
}
}

Avant de lancer le test, il faut évidemment démarrer le serveur.

III-D - Test de navigation

Durée estimée : 2 minutes.

Un test de navigation teste qu'on peut naviguer dans le site. Ici, on va simplement cliquer sur le menu « Fibonacci » et vérifier qu'on arrive sur la bonne page. Pour cela, on va partir de la page d'accueil.

Test de la page Fibonacci

public class FiboTest extends FluentTest {

public WebDriver webDriver = new HtmlUnitDriver();

@Page
public HomePage homePage;

@Page
public FiboPage fiboPage;

@Test
public void testFiboPage() {
// Aller sur la page d'accueil
goTo(homePage);
homePage.isAt();

// Cliquer sur le menu
clicFiboMenu();

// Verifier qu'on est sur la page Fibonacci
fiboPage.isAt();
}

private void clicFiboMenu() {
// TODO
}

@Override
public WebDriver getDefaultDriver() {
return webDriver;
}
}

Il reste à savoir ce qu'on va mettre dans la méthode « clicFiboMenu() ». Le dire en français est simple : on veut cliquer sur le lien « Fibonacci ». Le faire est un peu plus complexe, d'autant qu'il y a plusieurs manières d'y parvenir.

On peut rechercher le texte dans la page et cliquer dessus. Personnellement je ne suis pas fan de cette pratique, car elle nécessite beaucoup de travail dans un environnement multilingue. On peut aussi chercher le lien en parcourant la structure des balises de la page. Mais la moindre évolution dans la page rendra tous les tests obsolètes. On peut encore trouver le lien grâce à son id ou à un attribut de style. C'est ce que nous allons faire.

On va donc ajouter des identifiants à nos liens de menu, comme ça devrait être le cas dans tous les sites Web dignes de ce nom :

Ajout d'un id dans menu.xhtml

<pretty:link mappingId="fibonacci" id="fibo">
Fibonacci
</pretty:link>

Au niveau du HTML généré, cela va se traduire par :

Le HTML du menu

<a id="fibo" href="/fibo-webapp-fluentlenium/fibo">Fibonacci</a>

On peut désormais utiliser cet id dans le test :

Dans le test

private void clicFiboMenu() {
$("#fibo").click();
}

En voyant « $("#fibo") » dans ce bout de code, vous vous dites sûrement que ça ressemble à du jQuery et vous auriez bien raison. Mais n'allez pas vous imaginer que c'en est. Ça y ressemble (volontairement), mais c'est bien du Java. En effet, n'oubliez pas que le dollar est autorisé dans un nom de méthode, même si c'est très rarement utilisé. Vous trouverez la méthode « $(..) » dans la classe « Fluent ». Pour le coup, ici, c'est bien pratique, surtout si on fait le rapprochement avec jQuery qu'on utilise, côté navigateur (i.e. côté client), pour rechercher des éléments dans le DOM.

Il reste encore à écrire la méthode « isAt() » de « FiboPage ». Contrairement à la page d'accueil, on ne va pas se contenter de la valeur du titre.

Dans le code, on a ça :

Code HTML

<div id="content">
<h1>Fibonacci</h1>
<form id="j_idt22" enctype="application/x-www-form-urlencoded"
action="/fibo-webapp-fluentlenium/fibo?r=2" method="post" name="j_idt22">
</div>

Du coup, on peut prendre l'élément « h1 », représentant le titre de la section (supposé unique) dans la « div » avec l'id « content » :

FiboPage

public class FiboPage extends FluentPage {

@Override
public void isAt() {
Assertions.assertThat( find("#content h1").first().getText() )
.isEqualTo("Fibonacci");
}
}

Pour comprendre ce bout de code, il faut savoir que la méthode « find() » renvoie une liste.

III-E - Test du formulaire

Durée estimée : 2 minutes.

Pour tester le formulaire, c'est à peine plus difficile. On va d'abord naviguer vers la bonne page, puis choisir un rang, puis vérifier qu'on arrive sur la page des résultats et enfin tester les valeurs fournies.

On peut se dire qu'on est sur la bonne page, si on voit le tableau des résultats. Pour l'identifier facilement, on peut de nouveau ajouter un id dans le code HTML :

Ajout d'un id

<p id="resultats">
<table border="1">
<thead>
<tr>
<th>Rang</th>
<th>Valeur</th>

La suite est relativement la même que pour les pages précédentes :

FiboResultPage

public class FiboResultPage extends FluentPage {

@Override
public void isAt() {
Assertions.assertThat(find("#resultats table").size()).isGreaterThan(0);
}
}

Dans la suite, on va rester dans la même classe de test : pas la peine de multiplier inutilement les tests alors qu'on reste dans le même sujet… Par contre, on en profite pour factoriser un peu.

Résultats

public class FiboTest extends FluentTest {

public WebDriver webDriver = new HtmlUnitDriver();

@Page
public HomePage homePage;

@Page
public FiboPage fiboPage;

@Page
FiboResultPage fiboResultPage;

@Test
public void testFiboPage() {
goToFibo();
}

@Test
public void testFiboCalcul() {
// Arrange
final String value = "8";
final String expected = "21";

// Act
goToFibo();

selectValue(value);
clicCalculerBouton();

fiboResultPage.isAt();

// Assert
Assertions.assertThat(findFirst("#res_" + value).getText()).isEqualTo(expected);

}

private void goToFibo() {
goTo(homePage);

homePage.isAt();

clicFiboMenu();

fiboPage.isAt();
}

private void selectValue(final String value) {

}

private void clicCalculerBouton() {

}

...
}

Il ne reste plus qu'à coder la sélection d'une valeur et le clic sur le bouton. Pour ce dernier, c'est aussi simple que pour le clic sur le menu.

Clic sur le bouton

private void clicCalculerBouton() {
fiboPage.submit();
}

Comme l'action de validation du formulaire est propre à la page, on va plutôt la coder dans « FiboPage » :

Soumission dans la page

public void submit() {
submit("#fiboform");
}

Pour pouvoir faire ça de cette manière, il suffit de donner l'id « fiboform » au formulaire. Le code HTML n'en sera que plus propre. La bibliothèque va aller chercher toute seule les boutons du formulaire.

Pour choisir une valeur, ce n'est pas beaucoup plus difficile.

private void selectValue(final String value) {
fillSelect("select", FilterConstructor.withId().endsWith("fiboselect")).withValue(value);
}

Vous vous demandez certainement pourquoi on n'indique pas simplement « #fiboselect » comme id. Cela vient du fait que JSF en a changé la valeur en la préfixant par quelque chose qu'on ne peut pas déterminer à l'avance…

On peut maintenant lancer le test qui devrait passer au vert, pour indiquer que tout est bon.

Comme me l'a fait très justement remarquer Nemek, un collègue de Developpez.com, s'il y a un préfixe, c'est qu'il y a un formulaire. Le préfixe est l'id du formulaire. Il suffit donc de donner un id au formulaire :

Un titre pour le formulaire

<h:form id="fiboform">
...

Du coup, on peut trouver la balise « SELECT » à l'aide de l'id généré « fiboform:fiboselect » et donc simplifier le test en conséquence :

Un peu plus simple...

private void selectValue(final String value) {
//fillSelect("select", FilterConstructor.withId().endsWith("fiboselect")).withValue(value);
fillSelect("#fiboform\\:fiboselect").withValue(value);
}

III-F - Des tests et des services

Durée estimée : 2 minutes.

On a déjà bien utilisé le POP (Page Object Pattern), mais nous ne sommes pas allé au bout du concept. En effet, on peut séparer la partie test, qui reprend du fonctionnel, de la partie page, qui gère ce qui est technique comme les sélecteurs CSS (les id pour nous).

Pour faire simple, tout ce qui contient un id (hors test de résultat, quoique  ?… cf. code complet en annexe) doit se trouver dans un objet Page. Et les tests utiliseront alors les nouveaux services proposés par les pages.

Pour la page d'accueil, tout est déjà bon. Pour son menu, on peut déporter le clic sur un menu particulier dans l'objet Page.

HomePage

public class HomePage extends FluentPage {
...

public void clickOnFibonacciMenu() {
$("#fibo").click();
}

goToFibo

public class FiboTest extends FluentTest {
...

private void goToFibo() {
goTo(homePage);

homePage.isAt();

//clicFiboMenu();
homePage.clickOnFibonacciMenu();

fiboPage.isAt();
}

On pourrait même avoir un POP spécifique pour le menu, qu'on inclurait dans les autres pages, comme une sous-page.

On fait de même pour la sélection d'un rang dans la liste et le clic sur le bouton de calcul :

FiboPage

public class FiboPage extends FluentPage {
...

public void selectValue(final String value) {
fillSelect("#fiboform\\:fiboselect").withValue(value);
}

Test

public class FiboTest extends FluentTest {
...

@Test
public void testFiboCalcul() {
// Arrange
final String value = "8";
final String expected = "21";

// Act
goToFibo();

//selectValue(value);
fiboPage.selectValue(value);

//clicCalculerBouton();
fiboPage.submit();

fiboResultPage.isAt();

// Assert
Assertions.assertThat(findFirst("#res_" + value).getText()).isEqualTo(expected);

}

Le code complet est proposé en annexe…

IV - Conclusion

Le contrat n'est pas tout à fait rempli puisqu'il aura fallu un peu plus de cinq minutes pour venir à bout de ce petit tutoriel. Toutefois on n'en est pas loin.

Les exemples utilisés peuvent sembler simples, voire trop simples, mais ils devraient être représentatifs des pages auxquelles vous allez (probablement) vous attaquer en premier. En quelques cas, on couvre donc une bonne partie des problématiques. Toutefois, on pourra aller bien plus loin avec FluentLenium (ainsi qu'avec Selenium), comme écrire des tests d'acceptance en mode BDD (Behavior Driven Developpement) par exemple. Ce sera le sujet d'un prochain article, car FluentLenium existe aussi en version utilisant Cucumber.

Notez tout de même qu'on a pris le problème un peu à l'envers puisqu'on écrit les tests après coup. On a donc été obligé d'adapter des pages déjà existantes. Dans une démarche TDD (Test Driven Development), BDD (Behavior Driven Development) ou encore 3T (Tests en Trois Temps), on aurait dû écrire les tests avant le code des pages. On aurait donc décidé à l'avance des points importants à repérer dans les pages. Et on les aurait écrites comme il faut, durant le développement, et non juste modifiées pour les faire coller à un besoin a posteriori…

Vos retours nous aident à améliorer nos publications. N'hésitez donc pas à commenter cet article sur le forum : Commentez

V - Remerciements

D'abord j'adresse mes remerciements aux créateurs de FluentLenium, qui simplifient mon quotidien, pour avoir développé une bibliothèque aussi utile et pour la maintenir. Je n'oublie pas tous les contributeurs qui rendent le projet encore meilleur.

Plus spécifiquement en ce qui concerne cet article, je tiens à remercier Mathilde Lemée et les membres de Developpez.com qui m'ont aidé à écrire cet article : Nemek, Mickael Baron et Claude Leloup.

VI - Annexes

VI-A - Liens

FluentLenium :https://github.com/FluentLenium/FluentLenium/wiki

Blog de Mathilde :http://www.java-freelance.fr/

Selenium :http://www.seleniumhq.org/

Cucumber :http://cukes.info/

VI-B - Liens perso

Retrouvez ma page et mes autres articles sur Developpez.com à l'adresse
https://thierry-leriche-dessirier.developpez.com/#page_articles

Suivez-moi sur Twitter : @thierryleriche (https://twitter.com/thierryleriche)

Et mon site perso : www.icauda.com

VI-C - Code complet

menu.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:pretty="http://ocpsoft.com/prettyfaces">

<div id="menus">
<pretty:link mappingId="fibonacci" id="fibo">
Fibonacci
</pretty:link><br/>

<pretty:link mappingId="fibonacci2" id="fibo10">
<f:param value="10" />
Fibonacci de 10
</pretty:link><br/>

<pretty:link mappingId="fibonacci2" id="fiboDef">
<f:param value="#{fiboBean.defaultRang}" />
Fibonacci au rang DEFAULT_RANG
</pretty:link><br/>

<pretty:link mappingId="factoriel" id="fact">
Factoriel
</pretty:link><br/>
</div>
</ui:composition>

fibonacci.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
template="/template.xhtml">

<ui:define name="mainContent">
<div id="content">
<h1>Fibonacci</h1>

<h:form id="fiboform">
<table>
<tr>
<td>Rang :</td>
<td>
<h:selectOneMenu id="fiboselect" value="#{fiboBean.rang}">
<c:forEach var="entry" begin="1" end="90">
<f:selectItem itemLabel="#{entry}" itemValue="#{entry}" />
</c:forEach>

</h:selectOneMenu >
</td>
<td>
<h:commandButton id="fibobutton" value="Calculer" action="#{fiboBean.calculer}" />
</td>
</tr>
</table>

<c:if test="#{fiboBean.valeur ne null}">
<p>La valeur de la suite de Fibonacci pour le rang <b>#{fiboBean.rang}</b> est <b>#{fiboBean.valeur}</b>.</p>
</c:if>

<c:if test="#{fiboBean.valeurs ne null}">
<p id="resultats">
<table border="1">
<thead>
<tr>
<th>Rang</th>
<th>Valeur</th>
<th>Valeur approximative</th>
<th>Approximation</th>
</tr>
</thead>

<tbody>
<c:forEach var="item" items="#{fiboBean.valeursInversees}">
<tr>
<td>#{item.rang}</td>
<td id="res_#{item.rang}">#{item.valeurExacte}</td>
<td>#{item.valeurApproximative}</td>
<td>#{item.approximation}</td>
</tr>
</c:forEach>
</tbody>
</table>
</p>
</c:if>
</h:form>
</div>
</ui:define>

</ui:composition>

HomePage.java

package com.dvp.fibowebapp.page;

import org.fest.assertions.Assertions;
import org.fluentlenium.core.FluentPage;

public class HomePage extends FluentPage {

private final static String URL = "http://localhost:8080/fibo-webapp-fluentlenium";
private final static String TITLE = "fibowebapp";

@Override
public String getUrl() {
return URL;
}

@Override
public void isAt() {
Assertions.assertThat(title()).isEqualTo(TITLE);
}

public void clickOnFibonacciMenu() {
$("#fibo").click();
}
}

FiboPage.java

package com.dvp.fibowebapp.page;

import org.fest.assertions.Assertions;
import org.fluentlenium.core.FluentPage;

public class FiboPage extends FluentPage {

@Override
public void isAt() {
Assertions.assertThat(find("#content h1").first().getText()).isEqualTo("Fibonacci");
}

public void submit() {
submit("#fiboform");
}

public void selectValue(final String value) {
fillSelect("#fiboform\\:fiboselect").withValue(value);
}

}

FiboResultPage.java

package com.dvp.fibowebapp.page;

import org.fest.assertions.Assertions;
import org.fluentlenium.core.FluentPage;

public class FiboResultPage extends FluentPage {

@Override
public void isAt() {
Assertions.assertThat(find("#resultats table").size()).isGreaterThan(0);
}

public String getResultat(final String indice) {
return findFirst("#res_" + indice).getText();
}
}

HomeTest.java

package com.dvp.fibowebapp;

import org.fluentlenium.adapter.FluentTest;
import org.fluentlenium.core.annotation.Page;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;

import com.dvp.fibowebapp.page.HomePage;

public class HomeTest extends FluentTest {

public WebDriver webDriver = new HtmlUnitDriver();

@Page
public HomePage homePage;

@Test
public void testHomePage() {
goTo(homePage);

homePage.isAt();
}

@Override
public WebDriver getDefaultDriver() {
return webDriver;
}
}

FiboTest.java

package com.dvp.fibowebapp;

import org.fest.assertions.Assertions;
import org.fluentlenium.adapter.FluentTest;
import org.fluentlenium.core.annotation.Page;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;

import com.dvp.fibowebapp.page.FiboPage;
import com.dvp.fibowebapp.page.FiboResultPage;
import com.dvp.fibowebapp.page.HomePage;

public class FiboTest extends FluentTest {

public WebDriver webDriver = new HtmlUnitDriver();

@Page
public HomePage homePage;

@Page
public FiboPage fiboPage;

@Page
FiboResultPage fiboResultPage;

@Test
public void testFiboPage() {
goToFibo();
}

@Test
public void testFiboCalcul() {
// Arrange
final String rang = "8";
final String expected = "21";

// Act
goToFibo();

// selectValue(value);
fiboPage.selectValue(rang);

// clicCalculerBouton();
fiboPage.submit();

fiboResultPage.isAt();

// Assert
Assertions.assertThat(fiboResultPage.getResultat(rang)).isEqualTo(expected);
}

private void goToFibo() {
goTo(homePage);

homePage.isAt();

// clicFiboMenu();
homePage.clickOnFibonacciMenu();

fiboPage.isAt();
}

// private void selectValue(final String value) {
// fillSelect("select",
// FilterConstructor.withId().endsWith("fiboselect")).withValue(value);
// fillSelect("#fiboform\\:fiboselect").withValue(value);
// }

// private void clicCalculerBouton() {
// fiboPage.submit();
// }

// private void clicFiboMenu() {
// $("#fibo").click();
// }

@Override
public WebDriver getDefaultDriver() {
return webDriver;
}
}