Представляю вам перевод моей статьи на Medium.com.
Впервые выпущенная более 30 лет назад Microsoft Windows сегодня является неоспоримым лидером среди настольных операционных систем. Это просто нельзя игнорировать при разработке веб-приложений. В этой статье я хотел бы обсудить некоторые особенности использования Selenium под Windows и предложить простое и проверенное в боевых условиях решение, значительно упрощающее жизнь.
Чем Windows отличается от Linux
В своих предыдущих статьях (первая, вторая, третья) я описал подходы и инструменты с открытым кодом, позволяющие организовать масштабируемый кластер Selenium. Мы также поговорили о том, как при помощи тех же инструментов эффективно запускать тесты на машине разработчика. Во всех статьях в качестве операционной системы использовался Linux. Чем же Windows отличается от Linux с точки зрения Selenium?
- Наличие браузеров, не существующих на других платформах. В зависимости от версии, Windows поставляется с предустановленным Internet Explorer (IE) или Microsoft Edge. Единовременно может быть установлена только одна версия каждого браузера. Для обоих браузеров имеются готовые исполняемые файлы web-драйверов (IEDriverServer и EdgeDriver соответственно), которые используют вызовы Windows API для запуска и управления браузером. С этой стороны Windows браузеры архитектурно ничем не отличаются от браузеров на Linux.
- Графический интерфейс встроен в операционную систему. Большинство версий Windows (кроме последних версий Windows Server) имеют встроенный графический интерфейс, который нельзя ни отключить ни заменить другим графическим сервером. Интерфейс автоматически стартует вместе с операционной системой и постоянно потребляет ресурсы. Кроме того графический интерфейс Windows по-умолчанию отображает все открываемые окна (в том числе и окна браузеров) в одном и том же рабочем столе и только одно из этих окон может быть в фокусе в заданный момент времени. Из-за этого попытки запустить несколько IE или Edge параллельно часто приводят к различным проблемам с фокусом окна: отличающиеся CSS-стили (например, при наведении на ссылки), не срабатывающие события DOM и так далее. Эта проблема очень мешает работе.
- Практически полное отсуствие поддержки Docker. Последние версии Windows Server поддерживают большинство функций Docker нативно, но на интересующих нас настольных версиях нет такой поддержки. Поэтому единственный способ запустить Docker на этих версиях — при помощи виртуальной машины с Linux, в которую установлен Docker.
Как видите многие современные подходы при работе с Selenium: использование X сервера без монитора и запуск браузеров в контейнерах не работают в Windows. Но можно ли достичь сходной с Linux производительности и обойти известные ограничения Windows? Да, и это проще, чем вы могли бы подумать! В следующих разделах я расскажу как это сделать.
Создаем порядок из хаоса
Мы будем двигаться к поставленной цели шаг за шагом. Для начала сделаем решение как можно проще. Как известно, обычная схема установки Selenium на Windows выглядит так:
Схема состоит из Selenium сервера, запущенного при помощи виртуальной машины Java (JRE), затем исполняемый файл IEDriverServer или EdgeDriver и, наконец, сам браузер — IE или Edge. В этой цепочке есть как минимум одно слабое звено — Selenium сервер и Java. Все потому, что Selenium здесь выступает в роли простого прокси-сервера, который запускает процесс драйвера на случайном порту и затем отправляет все запросы на этот порт. Проксирование сетевого трафика — простейшая задача в любом языке программирования, потому что основная работа выполняется сетевой подсистемой операционной системы. Именно поэтому установка Java (50 и более Мб) и скачивание Selenium server (20 и более Мб) для простого проксирования выглядит чересчур громоздким решением. Более того Selenium сервер плохо работает под нагрузкой:
- Он потребляет слишком много памяти и иногда даже течет.
- Проксирование выполняется "вручную" — на каждый запрос создается новый экземпляр HTTP клиента и входящий запрос копируется в него. Такой подход очень неэффективен и в некоторых случаях вызывает странные таймауты при проксировании.
Мы можем значительно улучшить ситуацию, просто заменив тяжелый Selenium сервер легковесным Selenoid.
Как заменить Selenium сервер на Selenoid
Selenoid — это легковесная замена Selenium сервера, написанная на языке Go. Selenoid поставляется в виде одного маленького (около 7 Мб) исполняемого файла и не имеет внешних зависимостей. Для начала использования нужно просто скачать и запустить этот файл. В моей предыдущей статье я кратко описал насколько удобным может быть Selenoid для запуска браузеров в Docker контейнерах — основного его назначения. Второй поддерживаемый режим — это запуск исполняемых файлов вместо контейнеров и проксирование сетевого трафика в них — также, как Selenium сервер делает это с IEDriverServer и EdgeDriver. Заменить Selenium сервер на Selenoid очень просто. Для примера, запустим Internet Explorer при помощи Selenoid:
- Скачиваем исполняемый файл Selenoid со страницы релизов. Исполняемый файл обычно называется
selenoid_windows_386.exe
для 32-битной Windows иselenoid_windows_amd64.exe
для Windows 64 bit. Насколько мне известно настольные версии Windows не имеют встроенной консольной программы для скачивания файлов. Но, если у вас установлен Cygwin и curl, то скачать файл можно так:
$ curl -o selenoid.exe https://github.com/aerokube/selenoid/releases/download/1.2.1/selenoid_windows_386.exe
- Скачиваем и распаковываем архив с
IEDriverServer.exe
со страницы загрузок Selenium. К примеру сохранимIEDriverServer.exe
вC:\
. - Настраиваем Internet Explorer как описано в вики.
- Создаем простой файл конфигурации для Selenoid —
browsers.json
:
{ "internet explorer": { "default": "11", "versions": { "11": { "image": ["C:\\IEDriverServer.exe"] } } } }
Запускаем Selenoid вместо Selenium сервера (порт 4444 должен быть свободен) при помощи вот такого файла
selenoid.bat
:
C:\selenoid.exe -conf C:\browsers.json -disable-docker -limit 4 > C:\selenoid.log 2>&1
Здесь мы предполагаем, что все файлы из предыдущих шагов были сохранены в
C:\
. Логи Selenoid будут сохранены вC:\selenoid.log
. Обратите внимание на параметр-limit
— он определяет сколько сессий можно запустить одновременно. Когда указанное количество сессий запущено — новые запросы становятся в очередь точно также, как в Selenium сервере.
- Готово! Можно запускать тесты на тот же самый URL:
http://localhost:4444/wd/hub
- Чтобы оставаться легковесным, Selenoid не имеет встроенного графического интерфейса. Мордочка сделана в виде отдельного исполняемого файла: Selenoid UI. Просто скачайте скомпилированный файл со страницы релизов и запустите его, затем откройте
http://localhost:8080/
в браузере.
Запускаем тесты на нескольких рабочих столах
После замены Selenium сервера на Selenoid вы увидите значительное снижение потребления памяти и CPU. Этот простой шаг может даже позволить вам запускать больше браузеров параллельно. Тем не менее простая замена не лечит проблемы с открытием нескольких окон браузеров одновременно. Окна по-прежнему показывается на одном рабочем столе и продолжают терять фокус. Для того, чтобы обойти это препятствие требуется научиться запускать браузеры в отдельных рабочих столах. Хорошая новость — внутренние API Windows даже в настольных версиях имеют поддержку виртуальных рабочих столов — можно переключаться между рабочими столами и запускать окна в этих рабочих столах независимо друг от друга. Но есть новость получше — не нужно погружаться во внутренности Windows, чтобы получить такое поведение для Selenium — нужная функциональность уже реализована в проекте headless-selenium-for-win. Скачав релиз, вы получите архив с двумя исполняемыми файлами: desktop_utils.exe
и headless_ie_selenium.exe
.
Первый из них — это консольная утилита для ручного переключения между рабочими столами. Команда выглядит примерно так:
C:> desktop_utils.exe -s desktop1
Для работы с Selenium нам потребуется вторая утилита — headless_ie_selenium.exe
. Она является надстройкой к IEDriverServer.exe
, обрабатывающей запросы на сессии и автоматически запускающей IEDriverServer.exe
в новом рабочем столе. headless_ie_selenium.exe
должна лежать в одном каталоге с IEDriverServer.exe
. Для того, чтобы использовать утилиту с Selenoid нужно просто заменить пусть до исполняемого файла в browsers.json
и перезапустить Selenoid:
{
"internet explorer": {
"default": "11",
"versions": {
"11": {
"image": ["C:\\headless_ie_selenium.exe"]
}
}
}
}
Теперь все проблемы с фокусом окон должны уйти.
Немного магии с Selenium capabilities
Простой заменой Selenium на Selenoid и IEDriverServer.exe
на headless_ie_selenium.exe
мы решили наиболее острые проблемы Selenium под Windows. Давайте сделаем из алмаза бриллиант, выставив несколько полезных capabilities в тестах.
По-умолчанию Internet Explorer использует системные настройки HTTP прокси. Это приводит к тому, что настройки прокси, выставленные в одной сессии "пролезают" и в другие сессии. Для того, чтобы исправить это, выставьте:
ie.usePerProcessProxy = true
Ваше веб-приложение может использовать cookies для хранения важной информации. В Windows эти файлы хранятся отдельно для каждого пользователя и поведение по-умолчанию — переиспользовать выставленные куки между параллельными сессиями. Это может приводить к плавающим тестам. Чтобы избежать переиспользование cookie можно стартовать IE в анонимном режиме:
ie.browserCommandLineSwitches = "-private"
Также не забудьте выставить:
ie.ensureCleanSession = true
- Для того, чтобы избежать странных ошибок с фокусом окна, также убедитесь, что указанная нижу capability не выставлена или равна false:
requireWindowFocus = false
Заключение
В этой статье я коротко описал основные проблемы, с которыми вы можете столкнуться при запуске Selenium тестов под Windows и предложил простое решение. Я продолжаю утверждать — тесты в Selenium могут не доставлять боли. Нужно только правильно уметь его готовить.