Éradiquer les régressions visuelles grâce à BackstopJS

Corinne Durrmeyer - PARIS-WEB 2018

Préparation

Récupérer les sources

https://github.com/inseo/atelier-BSjs

Ouvrez le dossier dans le terminal

$ cd ~/…/atelier-BSjs/

Installer BackstopJS

Pré-requis : node (v8 min) et npm

$ npm install backstopjs

Configuration

Initialiser BackstopJS

  1. Exécutez la commande : $ backstop init
  2. Renommez backstop.json en backstop.json.save
  3. Renommez backstop-starter.json en backstop.json
  4. Ouvrez le fichier backstop.json

Paramétrer BackstopJS

  • id : identifiant utilisé pour le nommage des captures
  • viewport : tableau des résolutions pour lesquels les tests doivent être effectués
  • scenarios : scénarios de tests à réaliser
    • label : nom donné aux captures du scénario
    • url : url à tester (relative ou absolue)
  • paths : chemin des dossiers BackstopJS
  • report : format du rapport de sortie (HTML ou jUnit)
  • engine : moteur de rendu utilisé par BackstopJS (Chrome-Headless, PhantomJS or SlimerJS)
  • asyncCaptureLimit : nombres de captures d'écran générées en parallèle
  • asyncCompareLimit : nombres de captures d'écran comparées en parallèle
  • misMatchThreshold : pourcentage de différence autorisé avant que le temps n'échoue

Utilisation basique

Créer un set de référence

$ backstop reference

Exécuter un premier test

$ backstop test

Approuver une évolution

  1. Ajoutez les lignes suivantes dans le fichier _src/css/custom.css :

    .label {
      display: inline-block;
      padding-top: .3em;
      padding-bottom: .4em;
    }
  2. Relancez le test : $ backstop test
  3. Validez les changements : $ backstop approve

Utilisation avancée

Cibler une zone spécifique

selectors : "document" | "viewport" | ".selecteur"

  1. Ajoutez les lignes suivantes dans le tableau de scénario du fichier backstop.json :
  2. ,
    {
      "label": "Viewport",
      "url": "/_src/index.html",
      "selectors": [
        "viewport"
      ]
    }
  3. Relancez un test : $ backstop test
  4. Créez les références manquantes :$ backstop reference --filter=Viewport

Cibler un sélecteur spécifique

  1. Ajoutez le scénario suivant :
    ,
    {
      "label": "Alerts",
      "url": "/_src/index.html",
      "selectors": [
        ".alert"
      ]
    }
  2. Et créez une nouvelle référence : $ backstop reference
  3. Donnez la valeur true à la propriété selectorExpansion
    {
      "label": "Alerts",
      "url": "/_src/index.html",
      "selectors": [ ".alert" ],
      "selectorExpansion": true
    }
  4. Et générez une nouvelle référence

Vérifier le nombre d'occurences trouvées et occulter un sélecteur

  1. Ajoutez la propriété suivante : "expect": 3
    {
      "label": "Alerts",
      "url": "/_src/index.html",
      "selectors": [ ".alert" ],
      "selectorExpansion": true,
      "expect": 3
    }
  2. Et lancez un test : $ backstop test
  3. La propriété removeSelectors permet de masquer un sélecteur
    avant que la capture ne soit effectuée (via un display: none;)
    {
      "label": "Alerts",
      "url": "/_src/index.html",
      "removeSelectors" : [
        ".alert-danger"
      ],
      "selectors": [ ".alert" ],
      "selectorExpansion": true,
      "expect": 3
    }
  4. Et lancez un test : $ backstop test

Capturer un effet de survol

  1. Ajoutez la ligne suivante : "onReadyScript": "puppet/onReady.js",
    "viewports": […],
    "onReadyScript": "puppet/onReady.js",
    
  2. Créez un nouveau scénario :
    ,
    {
      "label": "Hover",
      "url": "/_src/index.html",
      "hoverSelectors": [
        ".nav-pills li:nth-child(2) a"
      ],
      "selectors": [
        ".nav-pills"
      ]
    }
    
  3. Puis créez une nouvelle référence : $ backstop reference

Capturer un effet de survol (doté d'un délai)

  1. Éditez le fichier _src/css/custom.css pour y ajouter la règle suivante :
    .nav > li > a {
      transition: background-color 1.25s ease-in-out;
    }
    
  2. Et lancez un test : $ backstop test
  3. Utilisez la propriété postInteractionWait pour retarder la capture le temps que l'interaction ait lieu
    {
      "label": "Hover",
      "url": "/_src/index.html",
      "postInteractionWait": 1250,
      "hoverSelectors": [
        ".nav-pills li:nth-child(2) a"
      ],
      "selectors": [
        ".nav-pills"
      ]
    }
    
  4. Et lancez un nouveau test : $ backstop test

Capturer un clic

  1. Créez un nouveau scénario :
    ,
    {
      "label": "Click",
      "url": "/_src/index.html",
      "clickSelectors": [
       ".navbar-inverse .dropdown-toggle"
      ],
      "selectors": [
        ".navbars"
      ]
    }
    
  2. Essayez de créer une nouvelle référence : $ backstop reference
  3. Modifiez son intitulé et ajoutez-lui un viewport spécifique :
    {
      "label": "Click : tablet",
      "url": "/_src/index.html",
      "viewports": [
        {
          "label": "tablet",
          "width": 1024,
          "height": 768
        }
      ],
      "clickSelectors": [ ".navbar-inverse .dropdown-toggle" ],
      "selectors": [ ".navbars" ]
    }
    
  4. Générez la référence : $ backstop reference

Capturer un clic (sur les téléphones)

,
{
  "label": "Click : phone",
  "url": "/_src/index.html",
  "viewports": [
    {
      "label": "phone",
      "width": 320,
      "height": 480
    }
  ],
  "postInteractionWait" : 300,
  "clickSelectors": [
   ".navbar-toggle"
  ],
  "selectors": [
    ".navbar-inverse"
  ]
}

Capturer un clic (sur les téléphones)

{
  "label": "Click : phone",
  "url": "/_src/index.html",
  "viewports": [
    {
      "label": "phone",
      "width": 320,
      "height": 480
    }
  ],
  "postInteractionWait" : ".navbar-collapse.in",
  "clickSelectors": [ ".navbar-toggle" ],
  "selectors": [ ".navbar-inverse" ]
}

Paramètres supplémentaires

  • scrollToSelector : génère un scroll initial avant que la capture ne soit prise
    (fonctionnalité disponible par défaut via le script onReady)
  • cookiePath : permet l'import de cookie au format JSON
    (fonctionnalité disponible par défaut via le script onBefore)
  • readySelector : conditionne la prise de capture à l'existence du sélecteur dans le DOM
  • readyEvent : conditionne la prise de capture à un log spécifique dans la console.
  • delay : impose un délai avant que la capture soit prise

Exécuter BackstopJS via un script npm

  1. Renseigner dans le fichier package.json les lignes suivantes :

    {
      "scripts": {
        "reference": "backstop reference",
        "test": "backstop test",
        "approve": "backstop approve"
      }
    }
  2. Exécuter la commande npm run test
  3. Modifier le format du rapport dans le fichier de configuration :
    "report": ["CI"]
  4. Et ajouter la commande "report" : "backstop openReport" dans package.json

Et voilà !

Pour en savoir plus, je vous invite à consulter le dépôt officiel :
https://github.com/garris/BackstopJS