image

Предисловие


Привет, Хабр! Данная задача возникла у меня с проблемой, которая заключалась в создании робота для авторизации в Instagram, который бы делал за меня лайки. Всю задачу не напишу, напишу только часть реализации в виде настройки необходимого инструментария на удаленном сервере.

WEB — тестирование — это объемная и неоднозначная сфера, которая может заключаться в решении задач не только в плане тестирования WEB — приложений, но и, к примеру, в плане построения парсеров, роботов IoT и ботов работы с социальными сетями и все это используя только JavaScript!

Возможно, что вам не нравится словосочетание «тестирование», возможно, отчасти, из-за того, что это словосочетание заключает в себе более интересные вещи, которые, к примеру, позволят нам написать бота, способного авторизироваться в Instagram, Facebook и совершать там ряд действий от нашего лица и в одно и то же время нудно заниматься наблюдением, как выполняется наш фронтенд, но тестирование имеет смысл и уже стандартизировано сообществом W3C и продолжает развиваться.

Описание задачи в двух словах


Какую задачу мы ставим, чтобы решить при помощи тестирования? Всего-то нужно, чтобы какая-то программа открывала браузер и там автоматически кликала ссылки, вбивала тексты и показывала, что получится или возвращала параметр результата, который нам нужен. И все это нужно сделать на Linux — дистрибутиве Ubuntu 16.04, у которого нет GUI, т.е. у нас только консоль и запустить привычный браузер, как на полноценном компьютере не получится.

Что нужно для решения тестирования без GUI?


Все, что нужно для современного, «монопольного» тестирования на JavaScript:

  1. Headless Chromium Browser v 59 (chromium-browser) — безголовый браузер в консоли;
  2. Node.js (nodejs) — сервер JavaScript;
  3. WebDriver (chromedriver) — драйвер для обработки тестов на JavaScript и работы с chromium-browser посредством Node.js;
  4. Nightwatch.js (nightwatch) — известная библиотека для написания и запуска автотестов посредством Node.js от LinkedIn.

Установка на сервер


Напишем шаги для последовательной установки всех компонентов для тестирования.

image

1). Установка cromium-browser. Перед установкой chromium-browser надо будет установить все необходимые для него зависимости, поэтому надо будет выполнить ряд действий.
Устанавливаем зависимости:

sudo apt-get -f install

Если у нас были первые попытки установки, но помещали отсутствие зависимостей, то будет хорошо, если удалить загруженные файлы в /var/cache/apt/archives запуском команды:

sudo rm /var/cache/apt/archives/chromium*

Теперь устанавливаем сам cromium-browser:

sudo apt-get install chromium-browser

image

2). Установка nodejs. Как установить Node.js и все методы установки подробно описано тут.

Один из самых простых методов установки:
Есть вероятность, что данным методом установится старая стабильная версия v4.2.6 из репозитория Ubuntu, под которым этот пример тестирования не проверен. Для стабильной работы оптимально, если установить версию 7 или выше методом PPA или NVM

sudo apt-get update
sudo apt-get install nodejs

Также потребуется и менеджер пакетов, посредством которого надо будет установить chromedriver и nightwatch :

sudo apt-get install npm

Они нужны будут нам обработать тесты на JavaScript из Node.js.

image

3). Установка chromedriver. Этот драйвер выполняет роль WebDriver’а, предоставляющего API, к примеру, чтобы иметь возможность кликать на ссылки и вбивать тексты в текстовые поля и формы, для этого мы и будем использовать Chromedriver. Для установки chromedriver выполняем команду:

npm install chromedriver

image

4). Установка nightwatch. Nightwatch.js — это библиотека для написания и запуска автотестов на JavaScript:

npm install nightwatch

Схема работы тестирования


Коротко вся схема выглядит таким образом, что тесты на Nightwatch.js отправляют запросы на Chromedriver, а Chromedriver обращается к Chrome Browser для исполнения тестов(заполнение полей форм и нажатие на ссылки):

image

Настройка и запуск первого теста


Конфигурационный файл Nightwatch.js умолчанию находится в папке node_modules/nightwatch/bin и настройки берутся по умолчанию оттуда и для того, чтобы задать наши пользовательские настройки для Nightwatch.js нужно создать файл nightwatch.json в корне проекта и прописать туда всё необходимое, чтобы Chromedriver использовался напрямую (без Selenium и других сторонних вещей) и Chromium запускался в «headless» режиме:

{
  "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 стартовал перед запуском всех тестов и прибивался в конце:

const chromedriver = require('chromedriver');

module.exports = {
  before: function(done) {
    chromedriver.start();

    done();
  },

  after: function(done) {
    chromedriver.stop();

    done();
  }
};

Теперь необходимо написать любой тест для проверки работоспособности системы тестирования. К примеру, нужно открыть google.com, поискать что-нибудь и проверить результаты поиска. Конечно, Nightwatch.js API предоставляет ещё кучу всяких методов для всевозможных проверок, но для начала нам хватит:

module.exports = {
  'Test google.com': function(browser) {
    const firstResultSelector = '#rso cite._Rm';

    browser
      .url('http://google.com', () => {
        console.log('Loading google.com...');
      })
      .waitForElementVisible('#lst-ib', 5000)
      .execute(function() {
        document.getElementById('lst-ib').value = 'Блог WebSofter!';
      })
      .submitForm('form')
      .waitForElementVisible(firstResultSelector, 5000)
      .getText(firstResultSelector, result => {
        browser.assert.equal(result.value, 'blog.websofter.ru/');
      })
      .end();
      
  }
};

Запускаем через консоль по команде:

nightwatch --test google.js


Замечание. Во первых, если Node.js установлен через nvm, то надо активировать сессию через команду:

nvm ~/.profile

во вторых, для запуска теста необходимо создать в корне проекта package.json с данными проекта, а в виде запускаемого фала надо указать google.js через команду:

npm init

Далее уже выполняем команду запуска нашего теста:

nightwatch --test google.js

Результатом выше изложенного кода в файлах будет результат в консоли:

image

Т.е., мы заходим на главную сайта Google, вбиваем в поиск словосочетание «Блог WebSofter!» и в итоге сравнивается адрес нашего блога на наличие в определенных тегах на странице результата поиска.

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

Заключение


Первоначально Nightwatch.js был ориентирован на работу с Selenium. Но сегодня она умеет работать с chromedriver напрямую и необходимость в Selenium тем более в PhantomJS отпадает, хотя есть возможность с ними интегрировать.

Осторожно! Безголовый режим Chrome доступен на Mac и Linux в v59. Поддержка Windows входит в Chrome v60. Чтобы проверить, какая версия Chrome у вас есть, откройте

chrome://version

Безголовый Chrome поставляется в версии Chrome 59. Это способ запуска браузера Chrome в безголовой среде, т.е. в консоли без GUI. Подобным образом работал PhantomJS. Chrome привносит в командную строку все современные функции веб-платформы, предоставляемые Chromium и движком Blink.

Почему это полезно?

Безголовый браузер — отличный инструмент для автоматического тестирования и серверных сред, где вам не нужна видимая оболочка пользовательского интерфейса. Например, вы можете выполнить некоторые тесты на реальной веб-странице, создать PDF-файл или просто проверить, как браузер отображает URL-адрес. Дополнительно можно узнать по ссылке

Ссылки по теме


Комментарии (8)


  1. prefrontalCortex
    29.11.2017 23:48

    Спасибо за статью!


    Скрытый текст
    Устанавливаем зависимости:
    sudo apt-get -f install

    Боюсь, вы только что случайно бутылку колы.


  1. suratovvlad
    30.11.2017 10:17

    Мне кажется, что, наверняка, для этого уже есть Docker образ на хабе :)


  1. ihost
    30.11.2017 10:48

    Конечно, Nightwatch в целом неплох, но имеет свои недостатки: устаревший синтаксис с callback-цепочками вместо Promises и async/await, и требования наличия webdriver-а к браузеру — как тестировать на смартфоне или смарт-ТВ? Если Вы занимаетесь функциональным тестированием web-сфере и следите за развитием технологий, рекоммендую ознакомиться с этой статьей, и в частности, присмотреться к решениям от TestCafe — тоже на Node.js, но поудобнее и решающий вопрос с любыми девайсами. Можно вообще SauseLabs прикрутить, чтобы тестировать на всевозможных устройствах скопом.


    1. EvilsInterrupt
      30.11.2017 11:55

      Да, TestCafe выглядит не плохим. Но! Присмотритесь по-внимательнее:

      «TestCafe uses a URL-rewriting proxy which allows it to work without the WebDriver. This proxy injects the driver script that emulates user actions into the tested page.». © FAQ I have heard that TestCafe does not use Selenium. How does it operate?

      Меня, если честно, очень коробит, когда тест.программа лезет в тестируемый объект. Да, бывают случаи, когда без модификации тест.объекта нет возможности проверить ту или иную функциональность, но когда есть зачем это надо делать? Я к тому что Selenium-based решения сейчас более выигрышные!


      1. ihost
        30.11.2017 12:03

        Безусловно, у всех решений свои плюсы и минусы. В принципе, в современном web-е код модифицируется и так немало раз — babel для async/await и генераторов, bundle-ирование в webpack-е, polyfills и так далее — так что в принципе в еще одном преобразовании особо ничего страшного нет.
        Сам hammerhead выглядит довольно надежным — мне удалось найти, как выйти из песочницы, но маловероятно, что в обычном web-приложении такое бывает. Зато пользователи SmartTV и прочих необычных браузеров счастливы :)


        1. EvilsInterrupt
          30.11.2017 13:31

          В принципе, в современном web-е код модифицируется и так немало раз — babel для async/await и генераторов, bundle-ирование в webpack-е, polyfills и так далее — так что в принципе в еще одном преобразовании особо ничего страшного нет.

          Не спорю! Но. Все эти преобразования дают итоговый продукт. Вот именно итоговый продукт и есть тест. объект, который желательно не трогать и проверять таким какой он есть. Иначе может получиться ситуация, что у разработчика одна ситуация, а пользователя совсем другая. Я сейчас про конечного продукта, т.е. по принципу черного ящика, а не серо или бело ящичные виды тестирования


    1. vados665
      01.12.2017 22:16

      Спасибо большое! Как раз искал что то в этом духе)


  1. AlexPTS
    02.12.2017 09:24

    Исследовал множество инструментов для тестирования на nodejs и выбрал nightwatchjs. Много лет применял nightwatchjs в работе в разных компаниях, но на текущий день его сложно рекомендовать новым людям из-за отсутствия поддержки async/await из коробки, которые помогают писать тест как «синхронный» код, делая тесты лаконичнее в синтаксисе и проще для восприятия и понимания.

    В эпоху ES6 стоит 2 раза подумать об этом, прежде чем делать свой выбор в пользу того или иного инструмента.