Визуальное регрессионное тестирование с PhantomCSS
24.08.2016

Визуальное регрессионное тестирование с PhantomCSS

Оригинал: Visual Regression Testing with PhantomCSS, Pavels Jelisejevs

Если вы работали над большими серьезными проектами, вы уже вероятно почувствовали важность автоматизированного тестирования в процессе разработки. В зависимости от опыта, это осознание может прийти внезапно как большой взрыв или постепенно, но оно становится второй натурой. Автоматизированное тестирование может иметь разные формы: это и модульное тестирование, когда проверяются отдельные изолированные куски кода, и интерграционное или функциональное тестирование, когда проверяется взаимодействие отдельных частей в системе. Но эта статья посвящена не обзору автоматизированного тестирования в целом, а одному конкретному его виду, появившемуся сравнительно недавно — визуальному регрессионному тестированию.

Визуальное регрессионное тестирование применяет альтернативный подход к тестированию веб-страниц. Вместо того, чтобы просто убедиться, что какой-то элемент или текст присутствует в DOM, тест открывает страницу и проверяет, что конкретный блок выглядит точно так же, как вы хотите. Просто чтобы убедиться, что вы поняли разницу, позвольте мне привести пример. Представьте, что вы хотите, чтобы ваш сайт приветствовал своих посетителей дружественным сообщением:


<div>Hello, %username%!</div>

Чтобы убедиться, что эта функциональноть работает, вы можете (и должны) проверить код, генерирующий сообщение, убедиться, что он подставляет корректное значение. Также вы можете написать функциональный тест с помощью Selenium или Protractor, чтобы убедиться, что элемент присутствует на странице и содержит корректный текст. Но этого недостаточно. Мы хотим проверить не только то, что элемент содержит правильный текст, но и то, что он выглядит правильно, например, не скрыт с помощью display: none или имеет правильный цвет. Существует несколько инструментов для этого, но сегодня мы рассмотрим один из них — PhantomCSS.

Что такое PhantomCSS?

PhantomCSS — это инструмент для Node.js для выполнения визуального регрессионного тестирования. Он имеет открытые исходные коды и разрабатывается ребятами из Huddle. PhantomCSS позволяет запустить браузер, открыть страницу и сделать скриншот всей страницы или определенного элемента на странице. Этот скриншот будет сохранен в качестве базового образа для использования в будущем. Когда вы что-либо измените на сайте, вы можете снова запустить PhantomCSS. Он сделает еще один скриншот и сравнит его с исходным. Если никаких отличий не обнаружено, тест пройден. Если скриншоты не совпадают, тест считается проваленным, создается новое изображение, показывающее различия. Такой инструмент идеально подходит для тестирования изменений в CSS.

PhantomCSS построен на основе нескольких компонентов:

  • CasperJS — инструмент для взаимодействия с браузером PhantomJS или SlimerJS. Он позволяет открывать страницу и взаимодействовать с ней, например, произвести клик по кнопке или ввод значения. В дополнение, CasperJS предоставляет свой фреймворк для тестирования и возможность сделать скриншот страницы.
  • PhantomJS 2 или SlimerJS — два headless-браузера, каждый из которых может использоваться в PhantomCSS. Headless-браузер — это обычный браузер без пользовательского интерфейса.
  • Resemble.js — библиотека для сравнения изображений.

PhantomCSS может использовать PhantomJS и SlimerJS вместе, но в этой статье мы будем использовать PhantomJS.

Начнем тестировать

Давайте создадим крошечный тестовый проект, чтобы посмотреть, как мы можем использовать этот инструмент на практике. Для этого нам понадобится веб-страница, которую мы будем тестировать, и простой Node.js веб-сервер для CasperJS, чтобы иметь возможность открывать страницы.

Настройка тестового проекта

Создайте файл index.html со следующим содержимым:


<!doctype html>
<html>
  <head>
    <style>
      .tag {
        color: #fff;
        font-size: 30px;
        border-radius: 10px;
        padding: 10px;
        margin: 10px;
        width: 500px;
      }

      .tag-first {
        background: lightcoral;
      }

      .tag-second {
        background: lightskyblue;
      }
    </style>
  </head>

  <body>
    <div class="tag tag-first">The moving finger writes, and having written moves on.</div>
    <div class="tag tag-second">Nor all thy piety nor all thy wit, can cancel half a line of it.</div>
  </body>
</html>

Чтобы установить веб-сервер, инициализируем npm-проект и установим пакет http-server.


npm init
npm install http-server --save-dev

Чтобы запускать сервер, создадим простой npm-скрипт. Добавьте блок scripts в package.json:


"scripts": {
  "start": "http-server"
},

Теперь вы можете выполнить команду npm start в директории проекта и индекстная сраница будет доступна по адресу http://127.0.0.1:8080. Запустите сервер и оставьте его работать. Он нам понадобится.

Установка PhantomCSS

Установить PhantomCSS очень просто, все, что вам нужно, это добавить несколько зависимостей в проект:


npm install phantomcss casperjs phantomjs-prebuilt --save-dev

Создание теста

У нас есть все для создания первого теста. Тест PhantomCSS представляет собой Node.js скрипт, который открывает нужную страницу на сайте, делает скриншот и сравнивает его с предыдущим. Начнем с простого теста, основанного на демо PhantomCSS.


var phantomcss = require('phantomcss');

// start a casper test
casper.test.begin('Tags', function(test) {

  phantomcss.init({
    rebase: casper.cli.get('rebase')
  });

  // open page
  casper.start('http://127.0.0.1:8080/');

  // set your preferred view port size
  casper.viewport(1024, 768);

  casper.then(function() {
      // take the screenshot of the whole body element and save it under "body.png". The first parameter is actually a CSS selector
      phantomcss.screenshot('body', 'body');
  });

  casper.then(function now_check_the_screenshots() {
    // compare screenshots
    phantomcss.compareAll();
  });

  // run tests
  casper.run(function() {
    console.log('\nTHE END.');
    casper.test.done();
  });
});

Тест открывает страницу http://127.0.0.1:8080/, делает скриншот элемента body и сохраняет его в файл screenshots/body.png.

Осталось создать npm-скрипт для запуска теста. Добавьте следующий скрипт в package.json после скрипта “start”:


"test": "casperjs test test.js"

Теперь вы можете запустить тест следующей командой:


npm test

Вывод команды будет выглядеть примерно так:


Test file: test.js
# Tags
PASS Tags (NaN test)

New screenshot at ./screenshots/body_0.png

Must be your first time?
Some screenshots have been generated in the directory ./screenshots
This is your 'baseline', check the images manually. If they're wrong, delete the images.
The next time you run these tests, new screenshots will be taken.  These screenshots will be compared to the original.
If they are different, PhantomCSS will report a failure.

THE END.
WARN Looks like you didn't run any tests.
npm ERR! Test failed.  See above for more details.

Поскольку вы запустили тест в первый раз, он сохранил скриншот и вывел предупреждение о том, что его не с чем сравнить. В директории screenshots должно появится изображение, похожее на следующее:

Это изображение станет золотым стандартом того, как должен выглядеть ваш сайт и следующие запуски теста будут сравнвать результат с этим изображением.

Введение в регрессию

Если вы запустите ту же команду еще раз, вы увидите, что тест выполнился успешно:


Test file: test.js                                                              
# Tags
PASS Tags (NaN test)


PASS No changes found for screenshot ./screenshots/body_0.png

PhantomCSS found 1 tests, None of them failed. Which is good right?

If you want to make them fail, change some CSS.

THE END.
PASS 1 test executed in 0.827s, 1 passed, 0 failed, 0 dubious, 0 skipped.

Этого и следовало ожидать, поскольку мы не вносили никаких изменений на сайт. Давайте что-нибудь сломаем и снова запустим тест. Попробуйте изменить какие-нибудь стили в index.html, например, уменьшить размер блоков до 400 пикселей. Теперь давайте снова запустим тест и посмотрим, что произойдет:


Test file: test.js                                                              
# Tags
PASS Tags (NaN test)
Failure! Saved to ./failures/body_0.fail.png


FAIL Visual change found for screenshot ./screenshots/body_0.png (11.41% mismatch)
#    type: fail
#    file: test.js
#    subject: false

PhantomCSS found 1 tests, 1 of them failed.

PhantomCSS has created some images that try to show the difference (in the directory ./failures). Fuchsia colored pixels indicate a difference between the new and old screenshots.

THE END.
FAIL 1 test executed in 1.082s, 0 passed, 1 failed, 0 dubious, 0 skipped.       

Details for the 1 failed test:

In test.js
  Tags
    fail: Visual change found for screenshot ./screenshots/body_0.png (11.41% mismatch)
npm ERR! Test failed.  See above for more details.

Можно отметить несколько важных вещей. Во-первых, PhantomCSS сообщил о том, что тест провален, поскольку скриншот страницы не совпадает с body_0.png. Расхождение составляет 11.41%. Во-вторых, разница между текущим и предыдущим скриншотами сохранена в директории failures. Если вы откроете эту директорию, вы увидите изображение вроде этого:

На скриншоте выделены области, которые отличаются.

Принятие изменений

Что если мы хотим принять изменения? Должна быть возможность сказать инструменту, что изменения являются ожидаемыми, и сохранить их как новый стандарт. Для этого можно выполнить команду test с дополнительным параметром -- —rebase:


npm test -- —rebase

Обратите внимание на две пары тире. Так параметр из npm передается в команду. В результате вызова команды выше вызовется casperjs test test.js —rebase. Теперь изменения приняты, базовое изображение заменено на новое.

Дальнейшее использование

Теперь, когда мы разобрались с основами, вы можете подумать о том, как интегрировать этот инструмент в свой рабочий процесс. Я не буду вдаваться в подробности, т.к. это зависит от конкретного проекта, но вот некоторые вопросы для размышления:

  • Вы планируете запускать тесты на реальном сайте или на какой-то странице, где присутствуют только визуальные компоненты интерфейса?
  • Есть ли на вашем сайте динамический контент? Если да, то из-за изменений в контенте тесты будут падать. Чтобы избежать этого, для тестирования вам нужно настроить отдельную версию сайта со статическим контентом.
  • Собираетесь ли вы добавить скриншоты в систему контроля версий? Да, вы должны.
  • Собираетесь ли вы делать скриншоты всей страницы или отдельных элементов?

С помощью PhantomCSS вы можете покрыть автоматизированными тестами визуальный аспект вашего сайта. Это будет отличным дополнением к модульным и функциональным тестам. Даже если вы еще новичок в тестировании — это хороший вариант для начала!