Немного про Selenoid

Если вы читаете эту статью, то наверняка слышали о Selenoid. Это мощное решение написанное на Go от компании aerokube для управления Docker-контейнерами, в которых «завёрнуты» все необходимые программы и драйверы для тестирования в браузерах или на Android-эмуляторах. Как утверждают производители Selenoid, их решение потребляет намного меньше ресурсов, чем, например тот же Selenium. В то время, как первый имеет удобный веб интерфейс (в документации к Selenium нет никаких упоминаний про UI) и также возможность параллельного запуска тестов. У Selenoid также есть отличная поддержка, большое коммьюнити и достаточно хорошая документация .

Отмечу, что Selenoid работает только на Linux. За исключением, когда вам нужно запустить Selenoid без Docker. Но это уже совсем другая история.

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

Установка и настройка Selenoid

Чтобы начать установку и настройку Selenoid, нужно сперва установить Docker. Для этого идём на официальный сайт, выбираем свою ОС и устанавливаем программу.

Чтобы удобно было управлять Selenoid, сразу устанавливаем docker-compose. Это решение, которое позволяет описать настройки для нескольких Docker контейнеров в одном yaml файле и упралять ими.

Для этого нужно перейти на сайт и скачать в директорию /usr/local/bin последний доступный релиз.

cd /usr/local/bin/
sudo wget https://github.com/docker/compose/releases/download/v2.21.0/docker-compose-linux-x86_64

Переименовываем файл.

sudo mv docker-compose-linux-x86_64 docker-compose

И даём права на запуск.

sudo chmod +x docker-compose

Теперь нам нужно создать docker-compose.yml файл для docker-compose. У нас он получился вот таким.

version: "3"
services:
  selenoid:
    image: aerokube/selenoid:latest-release
    container_name: selenoid
    network_mode: bridge
    ports:
      - "4444:4444"
    environment:
      - "OVERRIDE_VIDEO_OUTPUT_DIR=$PWD/video"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "/etc/selenoid:/etc/selenoid"
      - "./video:/opt/selenoid/video"
      - "/opt/selenoid/logs:/opt/selenoid/logs"
    command: ["-conf", "/etc/selenoid/browsers.json", "-limit", "20", "-retry-count", "1000", "-video-output-dir", "/opt/selenoid/video", "-log-output-dir", "/opt/selenoid/logs", "-max-timeout", "20m0s", "-session-attempt-timeout", "15m", "-timeout", "10m",  "-service-startup-timeout", "10m"]
  selenoid-ui:
    image: aerokube/selenoid-ui:latest-release
    container_name: selenoid-ui
    network_mode: bridge
    ports:
      - "8080:8080"
    links:
      - selenoid
    command: -selenoid-uri 'http://selenoid:4444'
    depends_on:
      - selenoid

Здесь важно понимать, что без yaml файла docker-compose работать не будет.

Далее нам нужно создать и настроить конфигурационный файл /etc/selenoid/browsers.json.

{
  "android": {
    "default": "10.0",
        "versions": {
            "10.0": {
                "image": "selenoid/android:10.0",
                "port": "4444",
                "path": "/wd/hub",
                "env": [
                  "VERBOSE=true",
                  "APPIUM_ARGS=--log-level debug"
                ],
                "selenoid:options": {
                  "enableVNC": "true",
                  "enableLog": "true",
                  "enableVideo": "true"
                }
            }
        }
    }
}

После всей подготовки запускаем Selenoid. Для этого переходим в директорию, где у вас лежит подготовленный ранее файл docker-compose.yml и выполняем команду

docker-compose up -d

После этого скачаются образы selenoid и selenoid-ui и запустятся контейнеры.

Снимок экрана 2023-10-27 в 21.07.23

Проверяем, что selenoid и его ui запущен

docker-compose ps -a
Снимок экрана 2023-10-27 в 21.28.53

Up <time> говорит о том, что контейнеры запущены и работают

Теперь идем в браузер и открываем ui selenoid, чтобы точно убедиться, что все заработало. http://<hostname>:8080.

Снимок экрана 2023-10-27 в 21.32.15
Снимок экрана 2023-10-27 в 21.32.15

Две зеленые надписи CONNECTED говорят о том, что все хорошо. Но тесты запускать пока рано. Переходим на сайт с образами для Android и скачиваем образ с Android 10.

docker pull selenoid/android:10.0

Запуск тестов и пара проблем

Мы установили Selenoid, скачали образ с Android 10, теперь можно приступать к тестированию.

Мы используем стек:

  • Gradle.

  • Java.

  • JUnit5.

  • Appium.

С разбегу запустить тесты на Selenoid не получилось. При первом запуске получили вот такую ошибку.

photo_2023-10-27 21.57.49

Этот лог нам ничего не сказал. Лезем в логи контейнера с Android-эмулятором.

photo_2023-10-27 18.32.28

Здесь уже поинтересней. Оказалось, что на ПК выключена виртуализация.

Заходим в BIOS и включаем виртуализацию. У каждого производителя виртуализация включается по разному.

456f3080-681e-4e58-82a9-860c6ecf2dbd
144155fd-24a1-4c1c-b32b-73ca56e5a108

Далее столкнулись с другой проблемой. При запуске тестов с таким capability...

final DesiredCapabilities device = new DesiredCapabilities();
device.setCapability("deviceName", "android");
device.setCapability("version", "10.0");
device.setCapability("appPackage", "ru.app.mobile.android");
device.setCapability("appActivity", "ru.app.mobile.android.splash.presentation.activity.SplashActivity");
device.setCapability("enableVNC", true);
device.setCapability("enableLog", true);
device.setCapability("enableVideo", true); // Uncomment this to record video

driver = new AppiumDriver<>(new URL(
        "http://<selenoid>:4444/wd/hub" //Replace with correct host and port
), device);

 ...получали такую ошибку.

.
java
org.openqa.selenium.SessionNotCreatedException: Unable to create a new remote session. Please check the server log for more details. Original error: All non-standard capabilities should have a vendor prefix. The following capabilities did not have one: enableLog,enableVNC,enableVideo,version
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
System info: host: 'MacBook-Pro-Pavel.local', ip: 'fe80:0:0:0:14d7:d36:4180:ab86%en0', os.name: 'Mac OS X', os.arch: 'aarch64', os.version: '13.5.1', java.version: '11.0.20'
Driver info: driver.version: AppiumDriver
remote stacktrace: InvalidArgumentError: All non-standard capabilities should have a vendor prefix. The following capabilities did not have one: enableLog,enableVNC,enableVideo,version

После общения в чате поддержки, оказалось, что capability должен выглядеть примерно вот так.

DesiredCapabilities device = new DesiredCapabilities();
device.setCapability("appium:deviceName", "android");
device.setCapability("appium:version", "10.0");
device.setCapability("appium:app", "ru.app.mobile.android"); 
device.setCapability("appium:appPackage", "ru.app.mobile.android.feature");
device.setCapability("appium:sessionTimeout", "15m");
device.setCapability("appium:enableVNC", true);
device.setCapability("appium:enableLog", true);
device.setCapability("appium:enableVideo", true); // Uncomment this to record video
device.setCapability(NEW_COMMAND_TIMEOUT, "3000");

AppiumDriver<RemoteWebElement> driver = new AndroidDriver<>(new URL(
        "http://<selenoid>:4444/wd/hub" //Replace with correct host and port
), device);

Но при таком capability в selenoid-ui были видны только логи appium, без VNC.

photo_2023-10-27 22.18.52

Оказалось, что enableVNC нужно запускать по другому.

Map<String, Object> selenoidOptions = Map.of("enableVNC", true,
        "enableLog", true,
        "enableVideo", true);

DesiredCapabilities device = new DesiredCapabilities();
device.setCapability("appium:deviceName", BrowserType.ANDROID);
device.setCapability("appium:platform", Platform.ANDROID);
device.setCapability("appium:version", "10.0");
device.setCapability("appium:app", "ru.app.mobile.android.feature");
device.setCapability("appium:appPackage", "ru.alfabank.mobile.android.feature");
device.setCapability("appium:appActivity", "ru.alfabank.mobile.android.splash.presentation.activity.SplashActivity");
device.setCapability("appium:sessionTimeout", "15m");
device.setCapability("selenoid:options", selenoidOptions);
device.setCapability(NEW_COMMAND_TIMEOUT, "3000");

AppiumDriver<RemoteWebElement> driver = new AndroidDriver<>(new URL(
        "http://<selenoid>:4444/wd/hub" //Replace with correct host and port
), device);
driver.manage().timeouts().implicitlyWait(launchPropertyProvider.getImplicitWaitDuration(), TimeUnit.SECONDS);
return driver;
photo_2023-10-27 22.40.50
photo_2023-10-27 22.40.50

Вот теперь можно запускать тесты или приступать к сборке собственного образа с Android эмулятором.

Сборка собственного образа с Android эмулятором

Клонируем репозиторий.

git clone https://github.com/aerokube/images

Переходим в директорию selenium и запускаем скрипт automate_android.sh.

cd selenium
./automate_android.sh

Вводим последнею стабильную версию appium, либо оставляем версию по умолчанию.

Specify Appium version: [2.0.1] 2.1.3

Далее выбираем какой тип Android будем использовать: выбираем с Google сервисами (google_apis_playstore) или без (google_apis).

Specify Android image type (possible values: "default", "google_apis", "google_apis_playstore", "android-tv", "android-wear"): [default] google_apis_playstore

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

Specify Application Binary Interface (possible values: "armeabi-v7a", "arm64-v8a", "x86", "x86_64"): [x86] x86_64

Далее выбираем версию Android — доступны версии с 4 по 14. В примере ниже выбрал версию 12.0.

Specify Android version: [8.1] 12.0

Идем в Android Studio, смотрим список доступных эмуляторов...

Снимок экрана 2023-09-26 в 12.58.27

...и вводим нужное название эмулятора...

Specify device preset name if needed (e.g. "Nexus 4"): Pixel 6a

...или оставляем значение по умолчанию.

Далее выбираем объем SD карты для эмулятора, оставляем по умолчанию 500 Mb или указываем свое значение.

Specify SD card size, Mb: [500]

Следующим шагом указываем объем памяти для эмулятора, оставляем значение по умолчанию или указываем свое значение.

Specify userdata.img size, Mb: [500]

Следующим шагом указываем нужно ли устанавливать Chrome для web тестирования на Android, оставляем значение по умолчанию.

Are you building a Chrome Mobile image (for mobile web testing): [n]

Указываем версию Chromedriver. Оставляем значение по умолчанию.

Specify Chromedriver version if needed (required for Chrome Mobile):

Как будет называться наш docker образ? Оставляем по умолчанию или задаем свое имя.

Specify image tag: [selenoid/android:12.0]

И, наконец, нас спрашивают «Добавить ли снимок быстрой загрузки». Оставляем значение по умолчанию.

Add Android quick boot snapshot? [y]

После начнется сборка образа с заданными параметрами.

Снимок экрана 2023-09-26 в 12.46.34

Когда сборка закончится, проверяем, наш новый образ.

Снимок экрана 2023-09-26 в 12.51.32
Снимок экрана 2023-09-26 в 12.51.32

Теперь нам нужно добавить образ в конфигурацию selenoid. Для этого открываем и правим файл /etc/selenoid/browsers.json.

{
  "android": {
    "default": "12.0",
        "versions": {
            "10.0": {
                "image": "selenoid/android:10.0",
                "port": "4444",
                "path": "/wd/hub",
                "env": [
                  "VERBOSE=true",
                  "APPIUM_ARGS=--log-level debug"
                ],
                "selenoid:options": {
                  "enableVNC": "true",
                  "enableLog": "true",
                  "enableVideo": "true"
                }
            },
            "12.0": {
                "image": "selenoid/android:12.0",
                "port": "4444",
                "path": "/wd/hub",
                "env": [
                  "VERBOSE=true",
                  "APPIUM_ARGS=--log-level debug"
                ],
                "selenoid:options": {
                  "enableVNC": "true",
                  "enableLog": "true",
                  "enableVideo": "true"
                }
            }
        }
    }
}

Перезапускам Selenoid, чтобы изменения подхватились.

docker-compose down && docker-compose up -d

Итог

Изначально я планировал разместить этот материал только для внутреннего использования в Confluence, чтобы делиться материалом по теме. Но по мере написания статьи, все больше понимал, что мой опыт может помочь не только мне и моим коллегам, но и остальным. Поэтому я искренне надеюсь, что здесь вы найдете решение основных проблем, с которыми я столкнулся. А сэкономленное время вы сможете потратить на погружение в прекрасный мир тестирования или другие приятные вещи. Желаю, чтобы у вас все получилось!

Selenoid хороший инструмент. Например, нам он дал нам следующее:

  • возможность сразу запускать тесты, без необходимости настраивать тестовую среду локально;

  • паралелльный запуск тестов, без необходимости дополнительной настройки тестовой среды;

  • тестирование на всех версиях Android и всех доступных эмуляторах;

  • удобный web интерфейс и мониторинг процесса тестирования;

  • запись видео тестирования.

Также в планах есть интеграция Appium Inspector с Selenoid, чтобы коллегам было еще удобнее писать тесты, без необходимости поднимать и настраивать локально тестовую среду.

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


  1. pbezpal Автор
    15.11.2023 08:28

    @Pecnikas если вы захотите использовать ещё одну машинку, то для этого вам нужно будет расспаралелливать при помощи ggr от этих же ребят, вот дока https://aerokube.com/ggr/latest/

    По поводу использования эмуляторов на отдельной машинке не подскажу, потому что мы это решение не прорабатывали. Но вы можете спросить в поддержке https://t.me/aerokube


  1. Pecnikas
    15.11.2023 08:28
    +1

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