Как настроить простую систему автотестов без Java и Selenium

    Представьте: вы работник стартапа, сварганили по-быстрому прототип и постепенно начинаете его развивать. И вот вам уже хочется, чтобы во время очередного спешного релиза не приходилось перепроверять все разделы сайта вручную (руками директора по продукту). Конечно, можно нанять отдельного тестировщика, но на это в вашем 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('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
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 37
    • +2
      прощайте тесты на Python'е, прощай Selenium.

      Здравствуй SeleniumWebdriver :)
      • +1
        Так что прощай Java, прощайте тесты на Python'е, прощай Selenium.

        Привет JS, привет непонятная либа, привет стремный мир javascript разработки?


        Как-то шило на мыло получилось :)


        Никогда не понимал в чем проблема писать тесты на Python. Язык то вроде простой как два пальца.

        • +1

          Совсем недавно занимался переносом автотестов с Ruby+Capybara на Javascript+webdriver.io.


          Дело не в том, простой язык или нет, а дело в том, что он инородный для команды JS-разработчиков в целом. Ruby (ну или Python, Java, whatever) будет сложно интегрировать с основным флоу сборки, построенном на каком-нибудь Gulp.

          • 0
            проблем никаких, но зачем?)

            плюс, это позволяет избежать смешения кода из разных языков — если потребовалось выполнить какой-то яваскрипт в браузере в процессе теста (вызов функции execute в примере)

            вообще основной поинт статьи был в том, чтобы показать как можно максимально быстро начать использовать автотесты человеку без опыта в этой сфере — фронтендеру, например)
            • 0
              если потребовалось выполнить какой-то яваскрипт в браузере в процессе теста

              На этом месте я бы уже задумался о качестве тестов.

              как можно максимально быстро начать использовать автотесты человеку без опыта в этой сфере

              «Скругляем инструмент согласно изгибу рук пользователя...»
            • 0
              Да и Java с точки зрения написания тестов не очень то и сложна. Ну по опыту коллег, которые как раз автотесты пишут.
              • 0
                image

                всегда актуально ;)
            • 0

              Вот что мне не понятно, так это что мешало раньше использовать все то же самое с chrome в "обычном" режиме, если так не хотелось использовать Java+Selenium? Разъясните, пожалуйста.

              • 0
                смысл в том, что эту систему можно развернуть на сервере без иксов! (на самом деле, раньше тоже можно было через xvfb, но, поверьте, это более сложный путь)
                • 0
                  Да ладно)))) Не знаю, как на JS, на Java минут 5 все в общем сложности. А с приходом докера вообще сущией пустики
                  • 0

                    С этим не спорю. Сюда же дополнительный профит в виде отсутствия затрат на отрисовку страниц.


                    Так что прощай Java, прощайте тесты на Python'е, прощай Selenium.

                    Однако автор, по моему скромному мнению, ощутимо более существенным выделяет тезис именно против Selenium и "скачков" из рабочего окружения (js) в тестировочное (java и т.д.), а главное событие — появление headless browser — как-то скралось на его фоне...


                    Странно, что вообще gui-free-режимы в браузерах стали появляться только сейчас. Автотесты вроде бы уже давно практикуются. И если разработчики тех же firefox и opera подключатся к тренду (в чем я немного сомневаюсь, во всяком случае в плане сроков ожидания данной фичи), то будет великое счастье уже всем тестировщикам и всем тем, кто так или иначе связан с написанием и развертыванием этих тестов.

                • +4
                  Хорошая альтернатива Nightshift, раз уж ноду используете.
                  http://codecept.io/
                  • 0
                    так сразу непонятно может ли он webgl рендерить
                    • +1

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


                      И вообще, мы же все снисходительны к себе и результатам своего труда. Свой код тестировать не так эффективно, как чужой. А ещё у разработчика и тестировщика разные образы мышления — не так-то просто переключаться между ними.


                      лучше давайте купим наконец-то кофе-машину

                      У вас там либо очень дешевые тестировщики, либо очень дорогие кофе-машины.

                      • 0

                        Мне любопытно, ведь с помощью хедлесс хрома можно сделать следущую конструкцию:


                        1. Сайт написаный плохо.
                        2. Хром
                        3. chromedriver, который перегоняет новости в rss
                        4. Rss ридер
                        5. Профит.

                        Профит в том, что большинство современных сайтов написаны настолько плохо, что пользоваться на телефоне невозможно, а на ультрабуке — затруднительно. Но контент на них может быть хорошим.

                        • 0

                          А я запускаю с Селениумом в докер-контейнерах, без иксов. И не парюсь. Если хочется подебажить глазами: гашу контейнер с селениумом, запускаю селениум локально, и любуюсь в иксах.
                          Под селениум все уже написано до нас, и ничего сложного нет в том, чтобы под любой язык настроить решение. Может не пол часа, но зная свой стек и приложение, пусть час. Основная сложность автотестов не в том чтобы программно запускать браузер.


                          Не разделяю эйфории автора от описанного велосипеда.

                          • +1
                            На правах рекламы. Путь с xvfb пройден нами полностью. Готовое решение для запуска браузеров в Docker под запрос выложено на Github: http://github.com/aerokube/selenoid Это если вам нужно не только Хром 59+, а любые версии браузеров и желательно, чтобы не загаживать ими систему. Ставится за 5 минут, также не требует Java. В контейнерах Xvfb, но можно смотреть на браузер во время выполнения сессии через мордочку.
                            • 0
                              Как это легко сделать описано в статье:

                              https://habrahabr.ru/post/327184/
                            • 0
                              взяли готовую либу, готовый Chromedriver и готовый Headless Chrome. по каким признакам велосипед-то?)

                              а ваш комментарий звучит как «я пользуюсь тем, чем пользуюсь и знать не хочу ничего нового» :)

                              … по поводу того, что «основная сложность автотестов не в этом» — в принципе, согласен. всё веселье начинается, когда, например, хром внезапно начинает просто зависать на каких-то страницах и начинаешь гадать, что могло послужить причиной) и всё же стереотип по поводу того, что «автотесты — это только для энтерпрайза, а мы пока не доросли» — существует, согласитесь.
                              • 0
                                Аналогия с велосипедом, чисто субъективная, не хотел обидеть.
                                Навеяна тем что есть готовое решение без иксов, java, но со скриншотами: докерезированный selenium.
                                А либы предоставляющие биндинг с API selenium есть практически для любого языка.
                                Т.о. не вижу конкурентных преимуществ Вашего решения. Единственно, если проект на js и команда тоже, а docker не используется. Тогда да, м.б. быстрее.

                                У меня такого стереотипа нет. Бывал как в интерпрайзе без тестов, так и в стартапах с тестами. Реально внедрить и там и тут, если менеджмент не мешает.
                                • 0
                                  готовое решение без иксов, java, но со скриншотами


                                  в том-то и дело, что тут тоже со скриншотами)

                                  либы предоставляющие биндинг с API selenium есть практически для любого языка


                                  да, Nightwatch.js — это по сути и есть такая либа для JS'а

                                  мне просто персонально нравится делать то, что можно делать без докера — без докера)

                                  … но в целом понял вашу точку зрения, спасибо за комментарии!
                            • +1

                              С основным тезисом статьи про миграцию тестов на JS и headless Chrome, я согласен, но Nightwatch я бы не выбрал.


                              Дело в том, что этот инструмент является сразу и инструментом для общения с браузером, и тестовым фреймворком, и библиотекой ассертов. Такой комбайн будет трудно сочетать, например, с остальными тестами, написанными на Mocha или Jasmine.


                              Гораздо лучше взять отдельные специализированные инструменты для каждой задачи. Я для этого обычно использую такую связку: Mocha, webdriver.io и Allure. Каждый инструмент делает здесь только одну задачу, а значит, делает её хорошо.

                              • +1

                                Отдельные выражения в адрес Джавы и Питона, скажем, не совсем нейтральны, как будто это что-то плохое. Лучше следовало бы объяснить доступным языком, что если раньше на протяжении долгого времени у разработчика не было выбора, на чем писать тесты, то теперь, с появлением стандарта WebDriver, можно автоматизировать браузер с помощью любого языка.


                                WebDriver — это веб-сервер на локальном хосте, прокладка между разработчиком и сокет-сервером самого браузера. Это значит, что для написания либы потребуется только HTTP-клиент и парсинг джейсона. Например, клик по ссылке — это запрос вида POST /session/{session id}/element/{element id}/click. Управлять браузером становится технически легко (но остается много тонкостей под капотом).


                                Что касается nightwatch, ты мы использовали эту либу в проекте. У меня сложилось впечатление, что она жульничает. Например, кликает по элементам нулевой толщины. Я полагаю, что под капотом она делает это (а так же другие операции) через Джаваскрипт, что есть читерство. После замены nightwatch на чистый WebDriver-протокол, при использовании тех же селекторов полезли ошибки, что по ним кликать нельзя.


                                Пользуясь случаем, попиарю свою библиотеку для Кложи — Etaoin. На ней сейчас гоняются наши тесты, полет нормальный.

                                • 0

                                  И вот что: Headless Chrome не умеет делать скриншоты. Возвращает картинку сплошь залитую серым. Я рекомендую вам использовать обычный Хром. На CircleCI настроен X Display, тесты проходят без проблем.

                                  • 0
                                    вот тут неправда ваша, умеет, проверенно
                                • 0

                                  Есть шикарный selenium-grid в докере. Вообще ничего делать не надо, просто работать с ремоутным селениумом.

                                  • 0
                                    Все это давно делалось с использованием 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 режиме
                                    • 0
                                      я почему-то думал, что protractor — это что-то из мира Angular'a…

                                      но тут у вас опять нужен Selenium Server, т.е. нужна Java)
                                      • +1
                                        Посмотрел обновления доки у протрактора — в настройках protractor-a можно поставить подключение к хром-драйверу напрямую без силениума directConnect: true, а также запускать в режиме без окна
                                        capabilities: {
                                          browserName: 'chrome',
                                          chromeOptions: {
                                             args: [ "--headless", "--disable-gpu", "--window-size=800x600" ]
                                           }
                                        }
                                        

                                        protractor и страницы без ангуляра отлично работает с параметром browser.ignoreSynchronization = true;
                                    • 0
                                      Не знаю как тесты, но для парсеров будет полезно
                                      • +1
                                        Всем привет. У нас с ребятами, есть свой чат в Telegram, где мы обсуждаем фичи Nightwatchjs, также делимся фишками, присоединяйтесь https://t.me/nightwatchjs
                                        • 0
                                          Почему прощай Selenium, ведь NightwatchJS — это одна из его оберток. То есть там, где будут проблемы у Selenium с WebDriver ровно там будут проблемы и у NighwatchJS. Ну плюс еще и свои собственные.
                                        • +1

                                          Посмотрите mocha-headless-chrome, там нет Silenium от слова "совсем".

                                          • 0

                                            Зато и поддерживается один только Chrome.


                                            С остальными браузерами что делать?

                                            • 0
                                              Если нужны разные браузеры, то нужен Silenium. Если нужен один браузер, без зависимостей, который можно запустить в консоли, то Headless Chrome хорошо подойдет.

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.