Sortie de Panther 1.0 !

Read the original version of this post written by Kévin Dunglas.

2 ans après sa première publication, nous sommes ravis de vous annoncer la disponibilité immédiate de la version 1.0 de Panther

panther

Panther est une bibliothèque de tests qui s'appuie sur la spécification W3C WebDriver pour manipuler de vrais navigateurs web. Les navigateurs Chrome et Firefox sont nativement supportés tandis que Safari, Edge et Opera peuvent être utilisés avec une configuration supplémentaire. Les services Cloud de tests avec navigateur comme Sauce Labs ou Browserstack sont également pris en charge. 

Comme vous le savez sûrement, l’équipe qui maintient Symfony travaille d’arrache-pied pour fournir une intégration moderne et simple de JavaScript directement dans le framework via l'initiative UX. Dans ce contexte, il devient indispensable de disposer d'une bonne bibliothèque de tests de navigateurs qui supporte JavaScript. 

Puisque Panther implémente l'API de BrowserKit, il est facile de l'utiliser avec le reste de l'écosystème Symfony. Par exemple, les tests fonctionnels existants peuvent être exécutés à l'aide d'un véritable navigateur via Panther (presque) sans aucune modification du code :


 namespace App\Tests\Controller;

-use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+use Symfony\Component\Panther\PantherTestCase;

-class PostControllerTest extends WebTestCase
+class PostControllerTest extends PantherTestCase
 {
     public function testShowPost()
     {
-        $client = static::createClient();
+        $client = static::createPantherClient();
 
         $client->request('GET', '/post/hello-world');
         $this->assertSelectorTextContains('html h1.title', 'Hello World');
    }
 }

Cela signifie également que vous pouvez tester vos templates Twig améliorés avec du JavaScript directement avec PHPUnit (et d'autres outils de test) !

Sous le capot, Panther démarre automatiquement un serveur web exposant votre application et le pilote du navigateur (Selenium Server n'est pas nécessaire), puis utilise la bibliothèque PHP WebDriver (nous contribuons à sa maintenance et son amélioration) pour exécuter le scénario.

Au cours de ces deux dernières années, 69 personnes ont travaillé à la stabilisation de Panther, à l'amélioration de son expérience utilisateur et à sa rapidité ! Ces derniers jours, nous avons également considérablement amélioré l'API de test, l'intégration avec les autres composants du framework, y compris Flex et MakerBundle, ainsi que l'expérience de débogage. Découvrons ensemble ces nouveautés.

Une meilleure expérience

Pour améliorer l'expérience initiale avec Panther, nous avons ajouté une recette Flex générant la configuration nécessaire. Exécutez la commande suivante pour installer Panther et son intégration PHPUnit dans n'importe quel projet Symfony : composer req --dev panther phpunit

Comme indiqué dans le message de post-installation, vous avez également besoin de ChromeDriver ou geckodriver selon que vous souhaitez effectuer vos tests avec Google Chrome (par défaut) ou Mozilla Firefox. Vous pouvez également exécuter toute votre suite de tests en utilisant les deux pour vous assurer que votre projet fonctionne correctement avec les deux navigateurs les plus populaires.

Pour installer ces pilotes, utilisez le gestionnaire de paquets de votre système d'exploitation ou exécutez le Browser Driver Installer de Daniël Brekelmans, qui est maintenant supporté par Panther :

composer require --dev dbrekelmans/bdi
vendor/bin/bdi detect drivers

Mieux encore : si vous utilisez une définition Docker compatible, vous n'avez rien à faire, Flex met automatiquement à jour le Dockerfile pour installer ChromeDriver dans l'image. Nous reviendrons sur cette nouvelle intégration de Docker dans un prochain article ! Enfin, ouvrez phpunit.xml.dist et décommentez le bloc ajouté par Flex pour enregistrer l'extension PHPUnit :

 <extensions>
        <extension class="Symfony\Component\Panther\ServerExtension" />
    </extensions>

Utilisation de MakerBundle pour générer des classes de test

Nous avons également amélioré l'intégration de Panther avec MakerBundle ! Il contient maintenant une commande dédiée pour générer des squelettes de test Panther. Utilisez-la pour créer votre premier test Panther :  bin/console make:test

Lorsque l’on vous demandera le type de test à générer, choisissez PantherTestCase. Un fichier test similaire à celui-ci sera généré :

<?php
// tests/MyPantherTest.php

namespace App\Tests;

use Symfony\Component\Panther\PantherTestCase;

class MyPantherTest extends PantherTestCase
{
    public function testSomething(): void
    {
        $client = static::createPantherClient();
        $crawler = $client->request('GET', '/');

        $this->assertSelectorTextContains('h1', 'Hello World');
    }
}

Faîtes-le avec : 

php bin/phpunit

Amélioration de l'expérience de débogage

Bien évidemment, ce test va échouer puisque nous n'avons pas encore créé de pages dans notre application. Jetez un coup d'œil aux contenus du répertoire var/error-screenshots/ ! Pour vous aider à déboguer vos tests, Panther prend désormais automatiquement une capture d'écran de la fenêtre du navigateur lorsqu'un test échoue : 

screen

Ce n’est pas tout ! Parfois, il peut être pratique d'inspecter les logs de la console, d'utiliser un débogueur JavaScript ou de jouer avec l'application pour comprendre le problème.

Exécutez :

PANTHER_NO_HEADLESS=1 bin/phpunit --debug

screen 2

Grâce à la variable d'environnement PANTHER_NO_HEADLESS, Panther ouvre une véritable fenêtre de navigateur afin que vous puissiez voir ce qu’il se passe. Et comme l'option --debug est activée (ajoutée par Dany Maillard), si le test échoue, Panther conservera la fenêtre ouverte jusqu'à ce que vous appuyiez sur “entrée” dans le terminal. Cela vous permet de voir l'application dans l'état exact où elle se trouvait lorsque l'erreur s'est produite, et d'utiliser les outils de développement du navigateur pour résoudre le problème.

Amélioration des tests asynchrones

En plus des assertions fournies par PHPUnit et par Symfony, Panther comprend de nombreuses assertions consacrées aux tests de sites web utilisant JavaScript et CSS. Grâce à ces assertions, il est facile d'exécuter des scénarios tels que "cet élément doit apparaître après un clic sur ce bouton", "ce texte doit être masqué avant que cette action de l'utilisateur ne se produise", "ce bouton doit être désactivé lorsque le formulaire n'est pas valide"...

Dans cette nouvelle version de Panther, nous avons ajouté de nouvelles assertions permettant de vérifier facilement qu’une action prévue se produise effectivement.

Supposons que Symfony UX soit installé. Si ce n'est pas le cas, lancez composer require ux. N'oubliez pas de suivre les instructions affichées par la recette Flex pour terminer l'installation et démarrer le serveur de développement de Webpack Encore. Pour plus de détails, consultez la documentation du bridge Stimulus.

Ensuite, créez un contrôleur Stimulus :

// assets/controllers/hello_controller.js
export default class extends Controller {
    connect() {
        setTimeout(
            () => this.element.textContent = 'Ceci remplacera le contenu du div après 1 seconde !',
            1000
        );
    }
}

Et voici le template Twig correspondant à une page accessible via /hello :

{# templates/hello/hello.html.twig #}
<div data-controller="hello">Contenu initial</div>

Le texte "Contenu initial" sera affiché pendant 1 seconde, puis remplacé par le contrôleur Stimulus. Nous utilisons setTimeout() par souci de simplification, mais dans les applications en situation réelle, votre contrôleur ira probablement chercher des données avec fetch() auprès d’un endpoint API Platform ou attendra des données provenant d'un hub Mercure.

Comment pouvons-nous vérifier que le texte est réellement remplacé ? En utilisant Panther, bien évidemment !

Jusqu'à la sortie de Panther 1.0, voici le test que vous deviez écrire :

<?php

namespace App\Tests;

use Symfony\Component\Panther\PantherTestCase;

class HelloControllerTest extends PantherTestCase
{
    public function testSomething(): void
    {
        $client = static::createPantherClient();
        $client->request('GET', '/hello');

        $this->assertSelectorTextContains('div[data-controller="hello"]', 'Contenu initial');

        // Wait for the text to change
        $client->waitForElementToContain('div[data-controller="hello"]', 'Ceci remplacera le contenu du div après 1 seconde !');
        // Then assert
        $this->assertSelectorTextContains('div[data-controller="hello"]', 'Ceci remplacera le contenu du div après 1 seconde !');
    }
}

Comme vous pouvez le constater, le fait de devoir utiliser le client pour attendre le résultat de l'opération asynchrone avant l’assertion est lourd et répétitif. 

Pour Panther 1.0, Grégory Copin (l’un de nos coopérateurs) a ajouté un certain nombre de nouvelles assertions qui améliorent considérablement l'expérience du développeur. Voici à quoi cela ressemble :

<?php

namespace App\Tests;

use Symfony\Component\Panther\PantherTestCase;

class HelloControllerTest extends PantherTestCase
{
    public function testSomething(): void
    {
        static::createPantherClient()->request('GET', '/hello');

        $this->assertSelectorTextContains('div[data-controller="hello"]', 'Contenu initial');
        $this->assertSelectorWillContain('div[data-controller="hello"]', 'Ceci remplacera le contenu du div après 1 seconde !');
    }
}

Une communauté et une utilisation grandissante

Panther commence à être utilisé comme base pour d’autres bibliothèques, voici celles que nous trouvons particulièrement intéressantes :  

  • Arachnid Web Crawler, une bibliothèque qui parcourt votre site en utilisant Panther pour extraire des informations liées au référencement.   
  • zenstruck/browser, une bibliothèque construite sur BrowserKit et Panther fournissant une interface fluide pour écrire vos tests d'intégration et vos tests de bout en bout.
  • Blackfire PHP SDK permet d'ajouter des assertions de performance à vos tests en utilisant Blackfire, et dispose maintenant d'un support natif pour Panther.
  • BehatPantherExtension est une extension ajoutant le support de Panther au framework de tests Behat.  

Sauvez les (vraies) panthères !

Alors que nous utilisons Panther pour tester nos web apps, nos félins à l'état sauvage sont en voie d'extinction. Si vous ou votre entreprise utilisez Panther (la bibliothèque) et que vous êtes rémunéré·s grâce à son utilisation, pensez à faire un don à Panthera, une ONG qui s'efforce de protéger ces animaux.

Vous pouvez aussi nous contacter si vous avez besoin d'expertise sur l’utilisation de cette bibliothèque, et même sponsoriser son créateur

Par ailleurs, savez-vous pourquoi le félin sur le logo de Panther n’est pas de couleur noire ? Tout comme le f de Symfony, ce n’est pas une erreur ! Le nom initial du projet était Panthère, en français, qui se traduit par “leopard” en anglais. Quand la Core Team Symfony a décidé d’accueillir le projet au sein du framework, elle a également décidé de retirer le e final et l’accent pour rendre le nom plus facile à écrire par les non-francophones, mais le logo est resté. 

Mais ce n’est pas l’histoire intégrale. Les panthères peuvent être de plusieurs couleurs, alors pourquoi avoir choisi un pelage jaune avec des taches noires pour ce logo ? Si vous êtes lillois·e ou originaire du Nord Pas-de-Calais, vous devez sûrement le savoir... Si cela ne vous parle pas, demandez-nous ! On se fera un plaisir de vous l’expliquer lors d’une conférence ou d’un meetup