Eine einfache BackstopJs Test-Instanz

BackstopJS auf GitHub - Screenshot

Visuelle Regressionstests

Mit dem folgenden npm Befehl installiert man Backstop global (natürlich ist auch eine lokale Installation oder die Einbindung zum Beispiel in einen Gulp-Task möglich). Voraussetzung ist natürlich das node.js installiert ist und falls ihr nvm nutzt, achtet darauf das ihr mindesten node Version 12 verwendet, ansonsten kann es Probleme mit dem Download des Chromium-Treiber geben.

npm install -g backstopjs

In ein Verzeichnis wechseln, bzw. eines erstellen, z.B. testing/backstop:

backstop init

Der init Befehlt installiert einige Beispiel-Dateien. Man kann die URL in der backstop.json durch eine eigene ersetzen und einen ersten Test ausführen. Zeile 21:

"url": "https://garris.github.io/BackstopJS/",

Natürlich kann man auch für komplexere Umgebungen zum Beispiel ein env-File mit Variablen erstellen.

Zuerst erstellt man Reference-Dateien (Referenz kann eine Website auf Localhost sein oder die ein produktive Website (dafür ist der key referenceUrl vorgesehen, bei Tests ausschließlich gegen eine lokalen Installation kann der Wert leer bleiben).

Reference Bilder erstellen

backstop reference

Nun kann gegen die Referenz ein erster Test durchgeführt werden.

backstop test

Fertig. Jetzt kann bei jeder Änderung im Code überprüft werden: Hey Frontend, bist du stabil.

Voll.

github.com/garris/BackstopJS

Login in eine Drupal Website

Hier meine Beispiel backstop.json - wer genau hinschaut, sieht, dass ich ich gegen ein Drupal Backend teste, dafür habe ich mir ein kleines Puppeteer Script gebaut. Keys ohne Value können übrigens gelöscht werden.

Hier eine backstop.json mit drei Beispiel-Scenarios:

{
  "id": "backstop_default",
  "viewports": [
    {
      "label": "phone",
      "width": 320,
      "height": 480
    },
    {
      "label": "tablet",
      "width": 1024,
      "height": 768
    }
  ],
  "onBeforeScript": "puppet/onBefore.js",
  "onReadyScript": "puppet/onReady.js",
  "scenarios": [
    {
      "label": "Homepage",
      "cookiePath": "backstop_data/engine_scripts/cookies.json",
      "url": "http://gnuschichten.test/",
      "referenceUrl": "",
      "readyEvent": "",
      "readySelector": "",
      "delay": 0,
      "hideSelectors": [],
      "removeSelectors": [],
      "hoverSelector": "",
      "clickSelector": "",
      "postInteractionWait": 0,
      "selectors": [],
      "selectorExpansion": true,
      "expect": 0,
      "misMatchThreshold" : 0.1,
      "requireSameDimensions": true
    },
    {
      "label": "Header",
      "url": "http://gnuschichten.test/",
      "postInteractionWait": 0,
      "selectors": [
        ".section .section--header"
      ]
    },
    {
      "label": "DrupalBackend",
      "onBeforeScript": "puppet/userLogin.js",
      "url": "http://gnuschichten.test/",
      "delay": 1000,
      "hideSelectors": [
        ".messages-list"
      ],
      "selectors": [
        ".page-wrapper"
      ]
    }
  ],
  "paths": {
    "bitmaps_reference": "backstop_data/bitmaps_reference",
    "bitmaps_test": "backstop_data/bitmaps_test",
    "engine_scripts": "backstop_data/engine_scripts",
    "html_report": "backstop_data/html_report",
    "ci_report": "backstop_data/ci_report"
  },
  "report": ["browser"],
  "engine": "puppeteer",
  "engineOptions": {
    "args": ["--no-sandbox"]
  },
  "asyncCaptureLimit": 5,
  "asyncCompareLimit": 50,
  "debug": false,
  "debugWindow": false
}

Die Debug Optionen sind sehr nützlich und über DebugWindow true bekommt der Headless-Chromium wieder einen Kopf und man kann ihm beim Testen zuschauen.

Mein Login-Script unter backstop_data/engine_scripts/puppet/userLogin.js

module.exports = async (page, scenario) => {
  await page.goto('http://gnuschichten.local/user/login');
  await page.click('input#edit-name');
  await page.type('input#edit-name', 'admin');
  await page.type('input#edit-pass', 'admin');
  await page.click('button#edit-submit');
  await page.waitFor(10000);
  await page.goto(scenario.url);
};

Der Wert für die Url muss angepasst werden.

Natürlich kann man auch Cookies über den entsprechenden Key verwenden, die Beispiel-Installation über backstop init liefert die entsprechenden Hinweise. Ein Cookie-Hinweis kann aber auch unkompliziert über den Schlüsselwert "removeSelectors" entfernt werden. Überhaupt würde ich empfehlen keine ganzen Seiten zu testen, sondern nur Komponenten (siehe Scenario "Header").

Hier noch ein paar interessante Links:

Einige interessante Puppeteer Scripts und eine Gulp Integration findet hier (Backstop-Testing für eine Drupal-based CiviCRM).

Testing Your Website for Visual

Wichtig, wenn ihr Tests auf verschiedenen Rechner durchführt, kann es z.B. aufgrund leicht abweichender Schriftarten auf unterschiedlichen Betriebssystem zu fehlschlagenden Test kommen. Deshalb ist es besser Backstop in einen Docker-Contaioner auszulagern. Der Maintainer von BackstopJS selbst erklärt in dieser Issue, wie das geht:
github.com/garris/BackstopJS/issues/796

hub.docker.com/r/backstopjs/backstopjs/