Привет, разработчик!

Частая проблема верстальщика - поправил стили в одном месте, а изменилось в нескольких местах. И верстальщик замечает это слишком поздно. В данном посте я расскажу о регрессивном тестировании. Суть метода заключается в том, что вы делаете скриншоты сайта(не вручную конечно), а затем после внесения каких-либо правок вы делаете новые скриншоты и сравниваете их с предыдущими. Если есть какие-либо отличия - тесты об этом говорят и показывают. Можно делать скриншоты как сайтов, так и отдельных блоков.

Для данного метода нам потребуется:

  • 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. Для того, чтобы все корректно работало, нужно подключать более старые форматы.

На этом все.