Представьте: вы работник стартапа, сварганили по-быстрому прототип и постепенно начинаете его развивать. И вот вам уже хочется, чтобы во время очередного спешного релиза не приходилось перепроверять все разделы сайта вручную (руками директора по продукту). Конечно, можно нанять отдельного тестировщика, но на это в вашем LEAN-стартапе бюджета не дают — «лучше давайте купим наконец-то кофе-машину». Знакомо?
И тут кто-то произносит слово «автотесты».
И сразу начинается: это целая история, это очень сложно, это очень дорого, от этого будет больше вреда, чем пользы и вообще это кровавый Enterprise и СЕЛЕНИУМ.
А вам всего-то надо, чтобы какая-то программа открывала браузер и там тыкала ссылки, вбивала тексты и смотрела, что получится. Неужели это так сложно и дорого?
Теперь можно с уверенностью сказать: нет.
Всё изменилось недавно — с приходом Headless Chrome: в очередной версии Хрома он просто научился запускаться в «headless» режиме (т.е. без интерфейса).
И даже главный разработчик PhantomJS'а написал в связи с этим:
This is the end — https://t.co/GVmimAyRB5 #phantomjs 2.5 will not be released. Sorry, guys!
— Vitaly Slobodin (@Vitalliumm) April 13, 2017
Переходя к делу
Итак, всё, что вам нужно для запуска автотестов в современном мире, это:
1) Chrome версии 59 (на данный момент это beta) или Chromium Browser
2) nodejs + npm
Всё!
(Конечно, если вы делаете что-то специфическое, что нужно проверять в разных браузерах, тогда увы. Можете дальше не читать.)
Хром в этой связке выступает, очевидно, в качестве headless-браузера, открывающего ссылки и рендерящего страницы. (Что может быть лучше в роли headless-браузера, чем сам браузер?!) Вот как легко можно установить тот же Chromium Browser в Ubuntu:
sudo apt-get install chromium-browser
В качестве так называемого WebDriver'а, предоставляющего API, чтобы «тыкать на ссылки и вбивать тексты», мы будем использовать Chromedriver. Устанавливаем через npm:
npm install chromedriver
Сами тесты мы, конечно, хотим писать на чистом JavaScript'е (2к17 год на дворе). Для этого возьмём Nightwatch.js — это весьма известная библиотека для написания и запуска автотестов (от разработчиков LinkedIn). Первоначально Nightwatch.js заточен на работу с тем самым Селениумом. Но не все знают, что оно также умеет работать с Chromedriver напрямую. Устанавливаем:
npm install nightwatch
Вкратце вся схема выглядит так (тест на Nightwatch.js → серия запросов к Chromedriver → тыканье ссылок в Headless Chrome):
→ Chromedriver →
И как настроить-то?
По умолчанию конфигурация для Nightwatch берётся из файла nightwatch.json из папки node_modules/nightwatch/bin.
Нам нужна собственная конфигурация. Для этого создадим файл nightwatch.json в корне проекта и пропишем туда всё необходимое, чтобы Chromedriver использовался напрямую (без Селениума) и Chromium запускался в «headless» режиме:
nightwatch.json
{
"src_folders": ["tests"], // путь к папке с тестами
"output_folder": "reports",
"custom_commands_path": "",
"custom_assertions_path": "",
"page_objects_path": "",
"globals_path": "globals.js", // путь к файлу, в котором задаётся глобальный контекст для всех тестов
"selenium": {
"start_process": false // отменяем запуск Селениума, т.к. будем обращаться к Chromedriver напрямую
},
"test_settings": {
"default": {
"selenium_port": 9515, // номер порта Chromedriver по умолчанию ("selenium_" в имени поля — это пережиток прошлого)
"selenium_host": "localhost",
"default_path_prefix" : "",
"desiredCapabilities": {
"browserName": "chrome",
"chromeOptions" : {
"args" : ["--no-sandbox", "--headless", "--disable-gpu"], // специальные флаги для работы Хрома в headless-режиме
"binary" : "/usr/bin/chromium-browser" // путь к исполняемому файлу Хрома
},
"acceptSslCerts": true
}
}
}
}
Обратите внимание на строку с globals.js. Внутри этого файла можно задать глобальный контекст для всех тестов. Пропишем туда, чтобы Chromedriver стартовал перед запуском всех тестов и прибивался в конце:
globals.js
const chromedriver = require('chromedriver');
module.exports = {
before: function(done) {
chromedriver.start();
done();
},
after: function(done) {
chromedriver.stop();
done();
}
};
Осталось написать какой-нибудь тест для проверки. Например: открыть ya.ru, поискать что-нибудь и проверить результаты поиска. Конечно, Nightwatch.js API предоставляет ещё кучу всяких методов для всевозможных проверок, но для начала нам хватит:
tests/ya.js
module.exports = {
'Test ya.ru': function(browser) {
const firstResultSelector = '.serp-list .organic__subtitle b';
browser
.url('https://ya.ru', () => {
console.log('Loading ya.ru...');
})
.waitForElementVisible('#text', 5000)
.execute(function() {
document.getElementById('text').value = 'Привет!';
})
.submitForm('form')
.waitForElementVisible(firstResultSelector, 5000)
.getText(firstResultSelector, result => {
browser.assert.equal(result.value, 'm.habrahabr.ru');
})
.end();
}
};
Проверяем!
$ nightwatch --test tests/ya.js
[Ya] Test Suite
===================
Running: Test ya.ru
Loading ya.ru...
Element <#text> was visible after 70 milliseconds.
Warn: WaitForElement found 10 elements for selector ".serp-list .organic__subtitle b". Only the first one will be checked.
Element <.serp-list .organic__subtitle b> was visible after 1706 milliseconds.
Passed [equal]: m.habrahabr.ru == m.habrahabr.ru
OK. 3 assertions passed. (4.992s)
Итого
Итого весь процесс настройки Системы Автотестов занял менее получаса. И, главное, ту же систему можно быстро развернуть на практически любом сервере, что даёт прекрасную масштабируемость.
Так что прощай Java, прощайте тесты на Python'е, прощай Selenium.
А вот кофе-машина действительно нужна.
полезные ссылки:
1) «Getting Started with Headless Chrome»: developers.google.com/web/updates/2017/04/headless-chrome
2) «Nightwatch.js API reference»: nightwatchjs.org/api
3) хорошая презентация на тему Nightwatch.js: www.youtube.com/watch?v=794uaoenv_M
Автор: Aralot