Автоматическое тестирование верстки с BackstopJS
Привет, разработчик!
Частая проблема верстальщика - поправил стили в одном месте, а изменилось в нескольких местах. И верстальщик замечает это слишком поздно. В данном посте я расскажу о регрессивном тестировании. Суть метода заключается в том, что вы делаете скриншоты сайта(не вручную конечно), а затем после внесения каких-либо правок вы делаете новые скриншоты и сравниваете их с предыдущими. Если есть какие-либо отличия - тесты об этом говорят и показывают. Можно делать скриншоты как сайтов, так и отдельных блоков.
Для данного метода нам потребуется:
- Gulp - система сборки. Если с gulp’ом вы знакомо слабо, на нашем блоге есть статья “Начинаем работать с gulp”.
- PhantomJS - это все плюшки WebKit из консоли с управлением на JS и поддержкой различных стандартов и технологий: DOM, CSS, JSON, Canvas и SVG. Технически - это обычный браузер, но без интерфейса пользователя
- CasperJS - инструмент для написания сценариев навигации и для тестирования.
- BackstopJS библиотека позволяет автоматизировать перечисленные выше задачи.
Установка
Устанавливаем gulp:
npm install gulp -g
В корне вашего проекта инициализируем npm:
npm init
Устанавливаем PhantomJS:
npm install phantomjs
CasperJS:
npm install -g casperjs
Для работы CasperJS также требуется установка python, версии не ниже 2.7.
Устанавливаем BackstopJS с помощью bower:
bower install backstopjs
Устанавливаем npm-зависимости backstopjs:
cd bower_components/backstopjs
npm install
Тестовый запуск
Теперь все команды запускаются из директории bower_components/backstopjs. Для начала создадим конфиг для BackstopJS. Для этого служит следующая команда:
gulp genConfig
Команда создает json файл в корне вашего проекта - backstop.json со следующим содержимым:
{
"viewports": [
{
"name": "phone",
"width": 320,
"height": 480
},
{
"name": "tablet_v",
"width": 568,
"height": 1024
},
{
"name": "tablet_h",
"width": 1024,
"height": 768
}
],
"scenarios": [
{
"label": "My Homepage",
"url": "http://getbootstrap.com",
"hideSelectors": [],
"removeSelectors": [
"#carbonads-container"
],
"selectors": [
"header",
"main",
"body .bs-docs-featurette:nth-of-type(1)",
"body .bs-docs-featurette:nth-of-type(2)",
"footer",
"body"
],
"readyEvent": null,
"delay": 500,
"misMatchThreshold" : 0.1,
"onBeforeScript": "onBefore.js",
"onReadyScript": "onReady.js"
}
],
"paths": {
"bitmaps_reference": "../../backstop_data/bitmaps_reference",
"bitmaps_test": "../../backstop_data/bitmaps_test",
"compare_data": "../../backstop_data/bitmaps_test/compare.json",
"casper_scripts": "../../backstop_data/casper_scripts"
},
"engine": "phantomjs",
"report": ["CLI", "browser"],
"cliExitOnFail": false,
"casperFlags": [],
"debug": false,
"port": 3001
}
Мы вернемся к этому файлу позже, а пока обратите внимание на следующий параметр:
"port": 3001
Это номер порта, на котором будет расположена наша страница со сравнением скриншотов. Если вы используете на проекте browsersync, советую изменить номер порта(чтобы проектный browsersync не конфликтовал с browsersync библиотеки):
"port": 3002
Далее запустим тестовый сервер(также из папки bower_components/backstopjs):
gulp start
Эта команда запускает тестовый сервер. В браузере открываем страницу http://localhost:3002/compare.
Вы должны увидеть примерно следующее:
Пока мы не совершили ни одного теста.
Делаем исходные скриншоты
Для начала в конфиге опишем, на каких разрешениях мы хотим получить снимки.
backstop.json:
{
"viewports": [
{
"name": "phone",
"width": 320,
"height": 480
},
{
"name": "tablet_v",
"width": 568,
"height": 1024
},
{
"name": "tablet_h",
"width": 1024,
"height": 768
}
]
}
Добавим еще одно разрешение - для десктопа:
{
"viewports": [
{
"name": "phone",
"width": 320,
"height": 480
},
{
"name": "tablet_v",
"width": 568,
"height": 1024
},
{
"name": "tablet_h",
"width": 1024,
"height": 768
},
{
"name": "desctop",
"width": 1280,
"height": 1024
}
]
}
Также опишем скриншоты каких блоков нам нужны.
{
"selectors": [
".wrapper",
".header"
]
}
Опишем блоки, которые мы не хотим видеть в скриншотах, например виджет от browsersync:
{
"removeSelectors": [
".widget_wrap",
"#__bs_notify__"
]
}
Также впишем адрес страницы в параметр url(в моем случае это http://localhost:1337). Итоговый backstop.json:
{
"viewports": [
{
"name": "phone",
"width": 320,
"height": 480
},
{
"name": "tablet_v",
"width": 568,
"height": 1024
},
{
"name": "tablet_h",
"width": 1024,
"height": 768
}
],
"scenarios": [
{
"label": "My Homepage",
"url": "http://localhost:1337",
"hideSelectors": [],
"removeSelectors": [
".widget_wrap",
"#__bs_notify__"
],
"selectors": [
".wrapper",
".header"
],
"readyEvent": null,
"delay": 500,
"misMatchThreshold": 0.1,
"onBeforeScript": "onBefore.js",
"onReadyScript": "onReady.js"
}
],
"paths": {
"bitmaps_reference": "../../backstop_data/bitmaps_reference",
"bitmaps_test": "../../backstop_data/bitmaps_test",
"compare_data": "../../backstop_data/bitmaps_test/compare.json",
"casper_scripts": "../../backstop_data/casper_scripts"
},
"engine": "phantomjs",
"report": [
"CLI",
"browser"
],
"cliExitOnFail": false,
"casperFlags": [],
"debug": false,
"port": 3002
}
Далее запускаем команду для составления начальных скриншотов:
gulp reference
После её отработки в корне вашего проекта в папке backstop_data/bitmaps_reference появятся картинки. Эти картинки - наши исходники, с которыми мы в дальнейшем будем сравнивать новые скриншоты.
Тестирование
Для запуска тестов запускаем команду:
gulp test
Автоматически откроется окно http://localhost:3002/compare/(если нет- открывайте вручную) на котором отобразятся результаты тестов. Так как мы еще ничего не изменили, все тесты пройдут успешно:
Ниже в таблице мы видим исходный скриншот, новый скриншот и разницу между ними наглядно. Обратите внимание на параметр misMatchPercentage - это процент несоответствия скриншотов.
Теперь давайте изменим что-нибудь в проекте, например я изменю цвет заголовка и его отступ.
Было:
.promo_title {
font-size: 7.1rem;
color:greenyellow;
padding:4rem;
}
Стало:
.promo_title {
font-size: 7.1rem;
color:black;
padding:5rem;
}
Теперь снова запускаем тест:
gulp test
Видим, что некоторые тесты не прошли:
Ниже показаны результаты упавших тестов:
misMatchPercentage(процент несоответствия скриншотов) - теперь довольно большой, поэтому тесты и упали. Настроить порог несоответствия можно в конфиге backstop.json:
{
"misMatchThreshold": 0.1
}
Взаимодействие со страницей
Если перед тем, как сделать скриншот вам нужно произвести какие-либо действия со страницей на помощь приходит CasperJS. Подробно как работать с ним вы можете посмотреть в документации. Например, я хочу открывать всплывающее окно с каталогом, и после этого делать скриншот. В папке backstop_data/casper_scripts создаем скрипт открытия и ожидания в 1 секунду.
openCatalog.js:
module.exports = function(casper, scenario, vp) {
casper.click( '#catalog_show' );
casper.wait(1000);
};
В конфиге в сценарии добавляем скрипт:
{
"onReadyScript": "openCatalog.js"
}
Теперь перед тем как сделать скриншот будет открываться каталог.
Делаем скриншот в нужное время
Если вы хотите отсрочить время скриншота можно сделать это с помощью параметра delay в конфиге(по умолчанию 500). Или вы можете указать в вашем js-файле, когда сделать скриншот. Например так:
$(window).on('load', function () {
console.log('page_loaded');
});
А в конфиге изменить параметр “readyEvent”:
{
"readyEvent": "page_loaded"
}
Запускаем таски из корня проекта
До этого мы запускали gulp-задачи из папки bower_components/backstopjs. Для того, чтобы запускать таски из корня можно использовать плагин gulp-chug. Устанавливаем:
npm install gulp-chug --save-dev
Прописываем зависимость: var chug = require(‘gulp-chug’); Пишем таск:
//gulp chug (BackstopJS: $ gulp reference)
gulp.task( 'reference', function () {
gulp.src( './bower_components/backstopjs/gulpfile.js' )
.pipe( chug({
tasks: [ 'reference' ]
}));
});
Итого в gulpfile имеем следующее:
var gulp = require('gulp'),
chug = require('gulp-chug');
gulp.task( 'genConfig', function () {
gulp.src( './bower_components/backstopjs/gulpfile.js' )
.pipe( chug({
tasks: [ 'genConfig' ]
}));
});
gulp.task( 'reference', function () {
gulp.src( './bower_components/backstopjs/gulpfile.js' )
.pipe( chug({
tasks: [ 'reference' ]
}));
});
gulp.task( 'test', function () {
gulp.src( './bower_components/backstopjs/gulpfile.js' )
.pipe( chug({
tasks: [ 'test' ]
}));
});
Теперь можно запускать команды из корня проекта.
Шрифты
У phantomJS на момент написания публикации есть проблема с шрифтами в современном формате woff, woff2. Для того, чтобы все корректно работало, нужно подключать более старые форматы.
На этом все.