Archives de l’auteur Johan Maïa

ParJohan Maïa

Comment tester une tâche cron correctement sur WordPress ?

Comme je ne développe pas des tâches cron pour chaque plugin WordPress de mes clients, je peux passer parfois plusieurs heures à chercher pourquoi la tâche cron ne marche pas par oubli. Pour au final, comprendre que c´est la façon de tester qui n´est pas la bonne.

J´écris donc ce petit billet comme mémo pour tous ceux qui sont dans mon cas.

Vérifier que la tâche cron est bien enregistrée

Pour cela j´utilise le plugin WP Control qui permet de voir toutes les tâches cron programées.

Vous trouverez la liste de ces tâches cron dans Outils > Événements Cron.

Si la vôtre n´est pas visible, il faut vérifier si le code passe par là par exemple via un wp_die() juste avant comme ça :

if ( ! wp_next_scheduled( 'h4a_cron_hook' ) ) {
    wp_die( 'tu y vas un jour ?');
    wp_schedule_event( time(), 'hourly', 'h4a_cron_hook' );
}

Une autre possibilité pour que la tâche cron ne soit pas visible est le fait que le deuxième paramètre string $recurrence pour la fréquence ne soit pas compatible. Voici donc la liste des possibilités de valeurs:

  • ‘hourly’
  • ‘daily’
  • ‘twicedaily’

Il est possible d´ajouter d´autres valeurs grâce au filtre cron_shedules .

Vérifier le résultat de la tâche

Là où c´est souvent confus est lors de la vérification du résultat. Déjà, le plugin WP Control vous permettra d´exécuter votre tâche cron sans attendre une heure ou un jour ou sans changer la valeur $recurrence à chaque fois.

Mais exécuter ou lancer la tâche ne veut pas dire que votre fonction se lancera. Pour éviter les erreurs il faut bien comprendre le mécanisme de la tâche cron.

Déjà cette tâche n´aboutira pas forcément chaque heure ou quotidiennement ou autres. Elle se lancera sous certaines conditions.

Le script PHP ne peut que se lancer seulement si quelqu´un ou une machine lance le chargement d´une page. Si il y a pas de chargement de page, la tâche cron ne peut aboutir.

De plus, cette tâche cron à l´heure prévue vient se mettre dans une pile pour attendre la prochaine fois que quelqu´un veut bien lancer une page. Sauf que sa place en tête de pile dure un temps limité (peut-être une minute, je dois encore pousser le sujet ). Donc, si personne vient charger une page du site Web où la fonction d´appel est censée se déclencher, il n´y aura aucun résultat et faudra attendre la prochaine fois.

Donc, une fois compris cela, pour tester si sa fonction d´appel de la tâche cron fonctionne, il faut avec WP Control :

  1. Dans la liste des tâches Cron, cliquer sur « Éxecuter maintenant » en dessous du nom de votre tâche.
  2. PUIS rapidement après, charger une page où votre fonction d´appel fait effet.

Et là on est bon pour les tests !

ParJohan Maïa

Tester un clique sur un sous-menu de WordPress via Codeception/wp-browser

Problématique

Lorsque l´on veut vérifier si le lien est correcte dans le menu WordPress via Codeception, on se trouve face à un petit soucis : les sous-menus ne sont pas visibles sauf si on a cliqué sur le lien du menu (lien parent).

Tentatives

    1. Tenter en sélectionnant directement le libellé du sous-menu comme ceci :
      $I->click('All Posts'); ça ne marche pas, car le lien n´est pas visible.
    2. Tenter avec XPath ce qui donne : $I->click( 'All Posts' , \Codeception\Util\Locator::elementAt('//li[@id=menu-posts]/ul/li/a', 0 ) ); ça ne marche pas non plus, sans doute aussi pas le manque de visibilité.
    3. Utiliser le positionnement de la souris mais ça semble un peu l´usine à gaz, et le menu peut-être en mode seulement d´icônes…  bref, c´est compliqué.

Solution

La solution à la fois simple et efficace et d´afficher via jquery le sous-menu pour cliquer ensuite dessus. Voici le test complet :

public function it_should_go_to_posts_page( AcceptanceTester $I ){    
    $I->loginAsAdmin();    
    $I->executeJS( 'jQuery("li#menu-posts > ul").css( { top: "0" } );' );    
    $I->click('All Posts');     
    $I->seeCurrentUrlEquals( "/wp-admin/edit.phps" );
}

 

 

ParJohan Maïa

Tester correctement la désinstallation d´un plugin

Installation/Désinstallation d´un plugin dans WP-Browser

Dans le projet wp-browser (version 06/06/2018),  il est possible de tester directement via la configuration une installation et désinstallation d´un plugin. Par défaut, on retrouve un exemple dans muloader.suite.dist.yml

config:
    WPLoader:
        ...
        plugins: ['mu-plugin-1/plugin.php']
        activatePlugins: ['mu-plugin-1/plugin.php']

Pour tester votre propre plugin, il suffit de :

  1. placer votre plugin (dézippé, pas le zip) dans tests/_data/plugins
  2. dans acceptance.suite.dist.yml, ajouter ceci :
    config: 
        WPLoader: ... 
            plugins: ['mon-plugin/MonPlugin.php'] 
            activatePlugins: ['mon-plugin/MonPlugin.php']

    mon-plugin est le nom du dossier du plugin et MonPlugin.php est la classe d´entrée pour le plugin.

Avec ceci, au lancement de la commande codecept run acceptance, avant les tests, Codeception viendra placer les fichiers du plugin dans le dossier wp-content/plugins du wordpress de test et à la fin des tests, il supprimera les fichiers du plugin.

Une désinstallation incomplète via WP-Browser version 06/06/2018

Le problème, étant que la désinstallation ne consiste pas à cliquer sur le lien « supprimer » pour le plugin, mais elle ne fait que supprimer les fichiers. Ce qui peut-être gênant lorsque dans votre plugin, à la désinstallation, la fonction vient supprimer des tables dans la base de données par exemple. En effet, les tables resteront après le lancement des tests.

La solution proposée

Pour que la suppression du plugin se fasse comme si un administrateur WordPress le ferait, il faut donc simuler le clique sur le lien « supprimer » dans la page des plugins.

Si vous mettez à jour wp-browser, vous devrez refaire ces étapes. C´est une solution provisoire.

Donc…

Étape 1 : création de la méthode « deletePlugin ».

Pour cela, on va se baser sur la méthode « deactivatePlugin » se trouvant dans AcceptanceTesterActions.php pour créer une méthode « deletePlugin » que l´on ajoutera dans cette classe (AcceptanceTesterActions).

AcceptanceTesterActions.php

/**
 * [!] Method is generated. Documentation taken from corresponding module.
 *
 * In the plugin administration screen delete a plugin clicking the "Delete" link.
 *
 * The method will presume the browser is in the plugin screen already.
 *
 * @author Hive 4 Apps
 *
 * @param  string|array $pluginSlug The plugin slug, like "hello-dolly" or a list of plugin slugs.
 *
 * @return void
 * @see \Codeception\Module\WPWebDriver::deletePlugin()
 */
public function deletePlugin($pluginSlug) {
    return $this->getScenario()->runStep(new \Codeception\Step\Action('deletePlugin', func_get_args()));
}

Maintenant on voit, que cette méthode appelle une autre méthode « deletePlugin » qui cette fois-ci doit se trouver dans la classe WPBrowserMethods.php

WPBrowserMethods.php

/**
 * In the plugin administration screen delete a plugin clicking the "Delete" link.
 *
 * The method will presume the browser is in the plugin screen already.
 *
 * @author Hive 4 Apps
 *
 * @param  string|array $pluginSlug The plugin slug, like "hello-dolly" or a list of plugin slugs.
 *
 * @return void
 */
public function deletePlugin($pluginSlug)
{
    $plugins = (array) $pluginSlug;
    foreach ($plugins as $plugin) {
        $option = '//*[@data-slug="' . $plugin . '"]/th/input';
        $this->scrollTo($option, 0, -40);
        $this->checkOption($option);
    }
    $this->scrollTo('select[name="action"]', 0, -40);
    $this->selectOption('action', 'delete-selected');
    $this->click("#doaction");

}

Cette méthode va ajouter le comportement de l´administrateur.

Étape 2 : Ajouter l´action dans notre scénario.

Méthode il est temps de tester notre méthode dans le scénario de test.

MonAcceptanceTestCest.php

   class MonAcceptanceTestCest
   {
      public $plugin_dir_name = 'my-plugin';
      public function it_should_activate_delete_correctly_plugin(AcceptanceTester $I )
      {
        //Install/Activation
        $I->loginAsAdmin();
        $I->amOnPluginsPage();
        $I->activatePlugin($this->plugin_dir_name);
        $I->seePluginActivated($this->plugin_dir_name);
        $I->dontSeeElement('.xdebug-error');

        //Deactivation
        $I->deactivatePlugin($this->plugin_dir_name);
        $I->seePluginDeactivated($this->plugin_dir_name);
       //Delete 
       $I->deletePlugin( $this->plugin_dir_name );
       $I->acceptPopup();
    }
  }

Dans WordPress, pour supprimer un plugin, il faut valider une alerte javascript donc nous sommes obliger pour que tout fonctionne d´ajouter $I->acceptPopup();. Cette méthode ne fonctionne pas avec PhantomJS puisque qu´elle est compatible uniquement si il y a un affichage.

Étape 3 : Désactiver la suppression des fichiers de plugin à la fin du test

En effet, si vous lancez à ce niveau le test, vous obtiendrez sans doute une erreur.

Je vous conseille donc de commenter dans WPFilesystem.php la fonction _after() qui gère la suppression des fichiers du plugin automatiquement. Comme ils sont déjà supprimés, c´est inutile.

Et normalement, tout devrait fonctionner !

 

ParJohan Maïa

Premier pas dans WP-Browser/Codeception – Webdriver

Pour tester un plugin WordPress, j´ai décidé d´utiliser le projet Codeception pour WordPress. Le projet Github à utiliser se nomme  wp-browser.

J´ai utilisé la version datant du 6 juin 2018 ( pas trouvé de numéro de version ).

Une fois l´installation faite, ne connaissant pas le fonctionnement des outils tels que Selenium ou PhantomJS, je pensais que les tests tournaient sur PhantomJS en ayant fait les étapes suivantes :

  •  placé phantomjs.exe dans le dossier vendor/bin
  • complété dans .env la variable PHANTOMJS comme ceci :

    PHANTOMJS="vendor/bin/phantomjs"
    

Je pensais que le framework utilisé la configuration du fichier : phantomjs.suite.dist.yml

En réalité, lorsque je lançais mes tests d´acceptance, Codeception utilisait le fichier : acceptance.suite.dist.yml où il est écrit ceci :

config :
    WPBrowser:
       url: '%WP_URL%'
       adminUsername: 'admin'
       adminPassword: 'admin'
       adminPassword: 'admin'
       adminPath: '/wp-admin'

Les tests étaient lancés donc via WPBrowser qui étend PHPBrowser. Il n´y avait donc pas de possibilité de tester de javascript par exemple. Il faut donc remplacer dans  acceptance.suite.dist.yml WPBrowser par un WPWebDriver.

Codeception propose plusieurs solutions pour ajouter un Webdriver : voir ici

Mais il me semble nécessaire de donner plus de détails si on est comme moi un débutant en la matière.

Le serveur PhantomJS

Avantages :

  • C´est rapide car pas d´affichage écran, tout est en console (headless)

Inconvénients :

Démarrer le serveur

En faite les étapes (en détail) sont les suivantes :

  1. Télécharger phantomjs-2.1.1-windows.zip ici, vous le dézippez et placez le phantomjs.exe dans le dossier vendor/bin du projet wp-browser
  2. Lancer la commande phantomjs --webdriver=4444 via un terminal après s´être placé dans le dossier vendor/bin où se trouve phantomjs.exe. Pour info, avec PhpStorm comme IDE, il suffit de cliquer droit sur phantomjs.exe et cliquer sur « run cmd shell » puis lancer la commande. Le serveur est ainsi lancé ! La preuve étant l´affichage de cette ligne :
    [INFO - 2018-07-06T17:41:57.373Z] GhostDriver - Main - running on port 4444
  3. Ajoutez dans .env
    PHANTOMJS="bin/vendor/phantomjs"

Vous pouvez désormais lancer vos tests d´acceptance.

Le serveur Sélénium

Avantages :

  • Accès à des fonctions javascript liés à la fenêtre d´affichage.

Inconvénients :

  • Le programme de tests est plus lent.
  • C´est la misère pour les compatibilités entre les pilotes et les versions de Sélénium

Démarrer le serveur

Dans ce cas c´est un peu plus compliqué. Sélénium nécessite plus d´outils.

Il va vous falloir :

  • Java installé (JRE)
  • JDK installé (vous pouvez ici installer directement le JDK qui installera le JRE)
  • Avoir ajouté la variable d´environnement dans le PATH (ça c´est sur windows)

Remarque : si vous utilisez le terminal de Phpstorm et que vous venez d´installer JAVA, il va falloir redémarrer jetBrains Toolbox pour que la commande « java » puisse être reconnu.

Puis :

  1. Télecharger le serveur Sélénium standalone (choisissez une version supérieur ou égale à 3.11, sinon vous perdez la compatibilité avec le pilote gecko )
  2. Télecharger les pilotes chromedriver.exe et geckodriver.exe
  3. Les trois fichiers (pour les pilotes, faut les dézipper bien entendu), peuvent être placés dans le dossier vendor/bin/ du projet wp-browser (comme pour phantomjs)
  4. Une fois, les fichiers au bonne endroit, ouvrez le terminal, placez vous au niveau du dossier bin/ puis lancer la commande : java -jar -Dwebdriver.gecko.driver=geckodriver.exe selenium-server-standalone-3.13.0.jar si vous voulez utiliser firefox. ou java -jar -Dwebdriver.chrome.driver=chromedriver.exe selenium-server-standalone-3.13.0.jar pour chrome.

Il se peut que vous ayez pas mal de problèmes à ce stade-ci dû en partie à cause des incompatibilités entre les versions de Sélénium et les pilotes geckodriver et chromedriver. Pour ma part, la version sélénium 3.13 est incompatible avec la version 0.21.0 de geckodriver. Impossible dans les tests de sélectionner des éléments dans la page. Avec chromedriver, j´ai réussi après plusieurs heures en associant la version 2.40 avec sélénium 3.13.

 En savoir plus :

Erreur 1 rencontrée

Au lancement de vos tests, si vous optenez cette erreur :

[ConnectionException] Can't connect to Webdriver at http://127.0.0.1:4444/wd/hub. Please make sure that Selenium Server or PhantomJS is running.

C´est que vous devez lancer un serveur.

Erreur 2 rencontrée

Lorsqu´au lancement de vos tests, vous rencontrez cette erreur :

[Facebook\WebDriver\Exception\UnknownServerException]
Error communicating with the remote browser. It may have died.

L´une des raisons peut-être une mauvaise version de chromedriver.exe, mais aussi, une mauvaise configuration. Dans acceptance.suite.dist.yml WPBrowser,

window_size: false # au lieu de '1024x768' qui n´est pas supporté.

Erreur 3 rencontrée

Au lancement du serveur Sélénium, si vous rencontrez cette erreur :

Exception in thread "main" com.beust.jcommander.ParameterException: Unknown option: -Dwebdriver.chrome.driver=chromedriver.exe

Il est fort possible que c´est parce que le paramètre du webdriver dans la ligne de commande doit être avant selenium-server-standalone-3.13.0.jar, pas après.

Erreur 4 rencontrée

Lorsque l´on utilise le chromedriver.exe avec selenium 3.13 et que l´on obtient au lancement des tests ceci :

[Facebook\WebDriver\Exception\UnknownServerException]

java.net.ConnectException: Connection refused: connect

De mon côté, c´était un problème de version du pilote chromedriver. La version 2.40 est compatible avec le selenium 3.13.

 

ParJohan Maïa

Les différentes méthodes pour tester automatiquement son plugin WordPress

Suite au développement d´un plugin assez copieux associé à plusieurs addons, j´ai fini par perdre mon temps en corrigeant à maintes reprises les mêmes bouts de code.

En effet, une fois avoir terminer une nouvelle fonctionnalité je sauvegardai sur notre projet Github et après plusieurs « commit », je découvrais que j´avais cassé pour la énième fois certaines fonctionnalités.

Il était temps de passer un cran dans la qualité et l´efficacité du travail. Vu l´ampleur des tests à faire avant chaque « commit », il n´y avait qu´une seule solution : les tests automatisés.

Cet article est donc né de mes recherches répondant à la question suivante :

– Quelle est la meilleure méthode pour tester correctement mon plugin avant de sauvegarder et passer à la prochaine version ?

N´ayant pas tout testé, impossible pour moi, comme pour beaucoup de développeur de savoir si il y a vraiment une meilleur méthode. Comme souvent, c´est une question de contexte et de feeling.

Mais au moins mes recherches ont abouti à une liste de 3 méthodes possibles pour tester son plugin WordPress :

Méthode 1 : WordPress-develop / PHPUnit + Qunit

La première solution consiste de faire ses tests avec PHPUnit pour la partie PHP et Qunit pour la partie javascript. Il existe un projet Github qui intègre un wordpress de test avec ces outils intitulé wordpress-develop.

C´est la méthode choisi ici.

Méthode 2 : Behat + WordPress = WordHat

Wordhat est un autre outil pour faire ses tests utilsant Behat mais avec un ensemble de fonctionnalités pour WordPress.

Méthode 3 : Codeception pour WordPress

Une autre alternative à Behat est Codeception. Il existe une version orientée wordpress : wp-browser

Je ne sais pas si ça peut aider car l´article étant sur le site « codeception », il est partisan mais ça a le mérite d´être argumenté. Il s´agit d´un article mettant en comparaison Behat et Codeception : Voici l´article.


A vous de voir.

 

ParJohan Maïa

Spécialisés WordPress

A team specializing in WordPress CMS to meet your needs.
We respond to your expectations in a personalized way and within deadlines.

We perform all types of tasks, from advice to realization:

  • Creation of themes
  • Creation of plugins
  • Security improvement
  • Perfomance improvement
  • Debugs
  • Migration…