И тут кто-то произносит слово «автотесты».
И сразу начинается: это целая история, это очень сложно, это очень дорого, от этого будет больше вреда, чем пользы и вообще это кровавый 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('http://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»
2) «Nightwatch.js API reference»
3) Хорошая презентация на тему Nightwatch.js
Комментарии (32)
SirEdvin
05.06.2017 22:27+1Так что прощай Java, прощайте тесты на Python'е, прощай Selenium.
Привет JS, привет непонятная либа, привет стремный мир javascript разработки?
Как-то шило на мыло получилось :)
Никогда не понимал в чем проблема писать тесты на Python. Язык то вроде простой как два пальца.
justboris
05.06.2017 23:25+1Совсем недавно занимался переносом автотестов с Ruby+Capybara на Javascript+webdriver.io.
Дело не в том, простой язык или нет, а дело в том, что он инородный для команды JS-разработчиков в целом. Ruby (ну или Python, Java, whatever) будет сложно интегрировать с основным флоу сборки, построенном на каком-нибудь Gulp.
Aralot
05.06.2017 23:30проблем никаких, но зачем?)
плюс, это позволяет избежать смешения кода из разных языков — если потребовалось выполнить какой-то яваскрипт в браузере в процессе теста (вызов функции execute в примере)
вообще основной поинт статьи был в том, чтобы показать как можно максимально быстро начать использовать автотесты человеку без опыта в этой сфере — фронтендеру, например)Free_ze
06.06.2017 13:12если потребовалось выполнить какой-то яваскрипт в браузере в процессе теста
На этом месте я бы уже задумался о качестве тестов.
как можно максимально быстро начать использовать автотесты человеку без опыта в этой сфере
«Скругляем инструмент согласно изгибу рук пользователя...»
kalaider
05.06.2017 23:31Вот что мне не понятно, так это что мешало раньше использовать все то же самое с chrome в "обычном" режиме, если так не хотелось использовать Java+Selenium? Разъясните, пожалуйста.
Aralot
05.06.2017 23:34смысл в том, что эту систему можно развернуть на сервере без иксов! (на самом деле, раньше тоже можно было через xvfb, но, поверьте, это более сложный путь)
Talik0507
05.06.2017 23:42Да ладно)))) Не знаю, как на JS, на Java минут 5 все в общем сложности. А с приходом докера вообще сущией пустики
kalaider
06.06.2017 00:07С этим не спорю. Сюда же дополнительный профит в виде отсутствия затрат на отрисовку страниц.
Так что прощай Java, прощайте тесты на Python'е, прощай Selenium.
Однако автор, по моему скромному мнению, ощутимо более существенным выделяет тезис именно против Selenium и "скачков" из рабочего окружения (js) в тестировочное (java и т.д.), а главное событие — появление headless browser — как-то скралось на его фоне...
Странно, что вообще gui-free-режимы в браузерах стали появляться только сейчас. Автотесты вроде бы уже давно практикуются. И если разработчики тех же firefox и opera подключатся к тренду (в чем я немного сомневаюсь, во всяком случае в плане сроков ожидания данной фичи), то будет великое счастье уже всем тестировщикам и всем тем, кто так или иначе связан с написанием и развертыванием этих тестов.
leorush
05.06.2017 23:35+4Хорошая альтернатива Nightshift, раз уж ноду используете.
http://codecept.io/
nick_volynkin
06.06.2017 04:34+1Суть тестировщика не в том, чтобы ручками тыкать в браузер, а в дизайне тестов. Этот специально обученный человек должен разработать тесты, которые покроют больше функциональности и найдут больше багов, чем если их будет разрабатывать программист. Как эти тесты будут выполняться — автоматически или вручную — второй вопрос.
И вообще, мы же все снисходительны к себе и результатам своего труда. Свой код тестировать не так эффективно, как чужой. А ещё у разработчика и тестировщика разные образы мышления — не так-то просто переключаться между ними.
лучше давайте купим наконец-то кофе-машину
У вас там либо очень дешевые тестировщики, либо очень дорогие кофе-машины.
acmnu
06.06.2017 09:32Мне любопытно, ведь с помощью хедлесс хрома можно сделать следущую конструкцию:
- Сайт написаный плохо.
- Хром
- chromedriver, который перегоняет новости в rss
- Rss ридер
- Профит.
Профит в том, что большинство современных сайтов написаны настолько плохо, что пользоваться на телефоне невозможно, а на ультрабуке — затруднительно. Но контент на них может быть хорошим.
samizdam
06.06.2017 09:50А я запускаю с Селениумом в докер-контейнерах, без иксов. И не парюсь. Если хочется подебажить глазами: гашу контейнер с селениумом, запускаю селениум локально, и любуюсь в иксах.
Под селениум все уже написано до нас, и ничего сложного нет в том, чтобы под любой язык настроить решение. Может не пол часа, но зная свой стек и приложение, пусть час. Основная сложность автотестов не в том чтобы программно запускать браузер.
Не разделяю эйфории автора от описанного велосипеда.
vaniaPooh
06.06.2017 10:55+1На правах рекламы. Путь с xvfb пройден нами полностью. Готовое решение для запуска браузеров в Docker под запрос выложено на Github: http://github.com/aerokube/selenoid Это если вам нужно не только Хром 59+, а любые версии браузеров и желательно, чтобы не загаживать ими систему. Ставится за 5 минут, также не требует Java. В контейнерах Xvfb, но можно смотреть на браузер во время выполнения сессии через мордочку.
aandryashin
06.06.2017 11:08Как это легко сделать описано в статье:
https://habrahabr.ru/post/327184/
Aralot
07.06.2017 13:37взяли готовую либу, готовый Chromedriver и готовый Headless Chrome. по каким признакам велосипед-то?)
а ваш комментарий звучит как «я пользуюсь тем, чем пользуюсь и знать не хочу ничего нового» :)
… по поводу того, что «основная сложность автотестов не в этом» — в принципе, согласен. всё веселье начинается, когда, например, хром внезапно начинает просто зависать на каких-то страницах и начинаешь гадать, что могло послужить причиной) и всё же стереотип по поводу того, что «автотесты — это только для энтерпрайза, а мы пока не доросли» — существует, согласитесь.samizdam
07.06.2017 19:25Аналогия с велосипедом, чисто субъективная, не хотел обидеть.
Навеяна тем что есть готовое решение без иксов, java, но со скриншотами: докерезированный selenium.
А либы предоставляющие биндинг с API selenium есть практически для любого языка.
Т.о. не вижу конкурентных преимуществ Вашего решения. Единственно, если проект на js и команда тоже, а docker не используется. Тогда да, м.б. быстрее.
У меня такого стереотипа нет. Бывал как в интерпрайзе без тестов, так и в стартапах с тестами. Реально внедрить и там и тут, если менеджмент не мешает.Aralot
07.06.2017 19:37готовое решение без иксов, java, но со скриншотами
в том-то и дело, что тут тоже со скриншотами)
либы предоставляющие биндинг с API selenium есть практически для любого языка
да, Nightwatch.js — это по сути и есть такая либа для JS'а
мне просто персонально нравится делать то, что можно делать без докера — без докера)
… но в целом понял вашу точку зрения, спасибо за комментарии!
justboris
06.06.2017 09:59+1С основным тезисом статьи про миграцию тестов на JS и headless Chrome, я согласен, но Nightwatch я бы не выбрал.
Дело в том, что этот инструмент является сразу и инструментом для общения с браузером, и тестовым фреймворком, и библиотекой ассертов. Такой комбайн будет трудно сочетать, например, с остальными тестами, написанными на Mocha или Jasmine.
Гораздо лучше взять отдельные специализированные инструменты для каждой задачи. Я для этого обычно использую такую связку: Mocha, webdriver.io и Allure. Каждый инструмент делает здесь только одну задачу, а значит, делает её хорошо.
igrishaev
06.06.2017 16:42+1Отдельные выражения в адрес Джавы и Питона, скажем, не совсем нейтральны, как будто это что-то плохое. Лучше следовало бы объяснить доступным языком, что если раньше на протяжении долгого времени у разработчика не было выбора, на чем писать тесты, то теперь, с появлением стандарта WebDriver, можно автоматизировать браузер с помощью любого языка.
WebDriver — это веб-сервер на локальном хосте, прокладка между разработчиком и сокет-сервером самого браузера. Это значит, что для написания либы потребуется только HTTP-клиент и парсинг джейсона. Например, клик по ссылке — это запрос вида
POST /session/{session id}/element/{element id}/click
. Управлять браузером становится технически легко (но остается много тонкостей под капотом).
Что касается nightwatch, ты мы использовали эту либу в проекте. У меня сложилось впечатление, что она жульничает. Например, кликает по элементам нулевой толщины. Я полагаю, что под капотом она делает это (а так же другие операции) через Джаваскрипт, что есть читерство. После замены nightwatch на чистый WebDriver-протокол, при использовании тех же селекторов полезли ошибки, что по ним кликать нельзя.
Пользуясь случаем, попиарю свою библиотеку для Кложи — Etaoin. На ней сейчас гоняются наши тесты, полет нормальный.
igrishaev
06.06.2017 16:45И вот что: Headless Chrome не умеет делать скриншоты. Возвращает картинку сплошь залитую серым. Я рекомендую вам использовать обычный Хром. На CircleCI настроен X Display, тесты проходят без проблем.
asm0dey
06.06.2017 21:55Есть шикарный selenium-grid в докере. Вообще ничего делать не надо, просто работать с ремоутным селениумом.
akumidv
07.06.2017 11:48Все это давно делалось с использованием protractor (при установленной node.js):
npm install protractor
Конфигурированием файла protractor.conf.js для автоматического запуска селениума и использования драйвера хрома
exports.config = { seleniumServerJar: './node_modules/protractor/selenium/selenium-server-standalone-2.45.0.jar', chromeOnly: true, chromeDriver: './node_modules/protractor/selenium/chromedriver', capabilities: { browserName: 'chrome' }, specs: ['./test/e2e/**/*.spec.js'], onPrepare: function () { browser.ignoreSynchronization = true;// Позволяет работать со страницами без angular }
+ установка системы тестирования mocha+chai или jasmine.
Но это конечно с окном chrome — надо будет попробовать эту же связку в headless режимеAralot
07.06.2017 13:22я почему-то думал, что protractor — это что-то из мира Angular'a…
но тут у вас опять нужен Selenium Server, т.е. нужна Java)akumidv
08.06.2017 04:20+1Посмотрел обновления доки у протрактора — в настройках protractor-a можно поставить подключение к хром-драйверу напрямую без силениума directConnect: true, а также запускать в режиме без окна
capabilities: { browserName: 'chrome', chromeOptions: { args: [ "--headless", "--disable-gpu", "--window-size=800x600" ] } }
protractor и страницы без ангуляра отлично работает с параметром browser.ignoreSynchronization = true;
Ayzatqa
09.06.2017 00:40+1Всем привет. У нас с ребятами, есть свой чат в Telegram, где мы обсуждаем фичи Nightwatchjs, также делимся фишками, присоединяйтесь https://t.me/nightwatchjs
leorush
Здравствуй SeleniumWebdriver :)