
Привет! Я Павел Лобач из команды инфраструктуры тестирования Т-Банка. Расскажу, как у нас организована инфраструктура для запуска E2E браузерных тестов, как она развивалась и как в итоге вылилась в открытый проект Selebrow.
Будет много технических подробностей и ни слова про ИИ!
E2E-тесты и как их запускают
E2E-тесты (end-to-end, или сквозные, тесты) занимают вершину пирамиды тестирования. E2E — наиболее комплексные и ресурсоемкие тесты, которые проверяют всю систему от начала до конца, включая взаимодействие всех компонентов и пользовательский интерфейс.
Суть E2E-тестов в том, чтобы взаимодействовать с тестируемым приложением так, как это делал бы пользователь, и оценивать результат. А пользователь взаимодействует с веб-сервисами, используя браузер, поэтому идея запустить из кода тестов браузер и как-то его заставить автоматически взаимодействовать со страницей кажется здравой.
Как делали деды. Исторически для автоматизации браузерных тестов использовался фреймворк Selenium, а для мира Node.js есть Webdriver.IO.
Selenium общается с браузером, используя протокол Webdriver, который почти стал стандартом W3C, но так и остался вечным черновиком. Вот только браузеры не понимают Webdriver, и поэтому нужна прокладка, называемая драйвером: для Chrome — chromedriver, для Firefox — geckodriver, для Safari — safaridriver.
Тестовый фреймворк запускает процесс-драйвер и взаимодействует с ним по протоколу Webdriver. Драйвер запускает браузер и управляет им, используя свой внутренний протокол.

Минусы использования такого подхода:
Необходим промежуточный процесс, который выполняет трансляцию и так медленного stateful Webdriver-протокола.
Проблемы масштабирования: браузеры запускаются рядом с тестами и мешают друг другу, особенно если хочется запускать тесты в несколько потоков.
Нужно как-то доставлять драйвер и браузер нужной версии перед запуском тестов. Это неудобно для запуска тестов на CI, так как добавляет задержки на скачивание бинарников и лишнюю зависимость от внешних интернет-ресурсов.
Есть проблема повторяемости тестов локально и на CI: разные OS, шрифты, настройки сглаживания. Это важно для скриншотного тестирования.
Docker to the rescue. Совместив перечень недостатков со списком хайповых в 2017 году технологий, появилась идея запускать браузеры в Docker-контейнерах из готовых имиджей. Это поможет решить проблемы с повторяемостью тестов и доставкой браузера и драйвера новой версии: просто используем одни и те же имиджи для запуска тестов локально и в CI!
Нужно написать какой-нибудь оркестратор. Так в свое время появился проект selenoid, который принимает подключение по протоколу Webdriver и запускает Docker-контейнеры, внутри которых уже все есть: и драйвер, и браузер нужных версий. Вот только мы все еще ограничены одним хостом, на котором запущен selenoid и Docker-демон.
Каждому браузеру нужно выделить примерно 1 ядро CPU и 2 ГБ RAM, что ограничивает нас запуском одновременно 64 браузеров на 64-ядерной машине (а такую еще добыть нужно). Увы, этого может быть недостаточно. Что, если у нас есть пара десятков дешевых 8-ядерных виртуалок — как распределять контейнеры с браузерами между ними? Для решения этой задачи авторы проекта selenoid создали балансер ggr, который распределяет запросы между selenoid-хостами — получается браузерная ферма.

Начало браузерной фермы
Когда в 2020 году я пришел в Т-Банк, у нас была браузерная ферма, основанная на доработанных версиях selenoid и ggr. Мы добавили возможность задавать квоты на ферме для команд (чтобы кто-то один не занял все ресурсы), а это потребовало прикрутить аутентификацию.
После решения некоторых технических проблем и добавления метрик проект заработал стабильно и не требовал внимания.
У сетапа ggr+selenoid было несколько недостатков:
Необходим еще один промежуточный процесс, который выполняет трансляцию stateful Webdriver-протокола. А в случае ggr+selenoid получается очень длинная цепочка взаимодействия.
Есть часы низкой нагрузки, когда мощности фермы простаивают.
Нет возможности запускать тесты на Safari, так как Safari для linux никогда не существовал, как и сборок Webkit-браузеров, пригодных для использования с selenoid.
Можно было бы этим пренебречь, если бы мир вокруг был неизменным, но реальность заставила нас все переделать.
Революция первая: новая инфраструктура сборки. До 2021 года наш CI был довольно типичным: GitLab CI + шареные Docker-ранеры. Сверившись со списком хайповых технологий 2021 года, мы решили построить новый CI с Kubernetes и клаудами.

Старая инфраструктура CI не позволяла нам масштабироваться и эффективно утилизировать выделенное железо: есть часы пониженной нагрузки, когда простаивали тысячи ядер CPU.
А при чем тут браузерная ферма? Да вроде была ни при чем, но через некоторое время пользователи стали робко спрашивать запросили фичу, чтобы ходить браузерами из фермы на сервисы, запущенные внутри CI.
В новой инфраструктуре сборки мы дали пользователям инструмент для запуска временных изолированных интеграционных окружений прямо внутри CI. Проект называется Kuber-API. Так как CI-кластеры не содержат ingress-контроллеров, попасть на поды, запущенные внутри CI, из старой браузерной фермы не представлялось возможным.
Рассмотрев разные возможности — туннели и прочие решения, усложняющие схему взаимодействия, — мы решили... избавиться от фермы совсем. Новая идея состояла в том, чтобы каждой CI-джобе дать свою мини-ферму. Эта мини-ферма будет работать в том же кластере Kubernetes, запускать браузеры внутри k8s-подов вместо Docker-контейнеров и умирать после завершения сборки.
Для реализации нового плана за пару недель и почти без перекуров мы написали проект, который назвали Selebrow. Получился GitLab-сервис, который можно подключить в своем CI.
test-job:
services:
- selebrow/selebrow:latest
Тесты подключаются к localhost:4444, как будто у нас запущен обычный selenoid.
Новым подходом мы решили ряд вопросов:
Браузеры теперь запускаются в одном Kubernetes-кластере с CI-сборками и интеграционными окружениями, поэтому возможны любые варианты взаимодействия: браузер → CI job, браузер → сервис из временного окружения.
Проблема масштабирования полностью решилась: каждый может запустить себе столько браузеров, сколько хочет — в пределах выделенной квоты. CI-кластер автоматически растет под нагрузкой и, наоборот, сжимается при падении нагрузки. Вот для чего нужны эти ваши клауды!
Аутентификация пользователей больше не нужна, так как внутри CI мы и так знаем, кто это.

Из недостатков нового решения стоит отметить более медленный старт пода с браузером, но проблема нивелировалась добавлением возможности переиспользования уже запущенных подов браузеров в рамках тестовой сессии.
Революция вторая: Playwright. Вроде на этом можно было бы выдохнуть и заняться другими делами. Но тут на сцену врывается новый тестовый фреймворк Playwright, и он получает просто взрывной адопшен.
Отставив в сторону удобство написания тестов (а там все очень хорошо), Playwright предлагает более технологичный метод взаимодействия с браузером: вместо промежуточного драйвера фреймворк использует родной протокол общения. Например, для Chrome это CDP. Схема взаимодействия тестов с браузером максимально упрощается, и это объективно сильно ускоряет тесты.

А еще Playwright из коробки предоставляет сборку мини-браузера на основе Webkit, позволяя запускать тесты «почти на Safari» на платформах, отличных от macOS, и возможность удаленного запуска браузеров тоже в наличии.
Звезды сложились так, что Playwright признали перспективным и предпочтительным фреймворком для написания E2E-тестов внутри нашей компании и появилась необходимость реализовать его поддержку в браузерной ферме. Внезапно оказалось, что изначальная реализация Selebrow получилась настолько легко расширяемой, что задача была сделана практически «еще вчера». Для подключения браузерной фермы в конфигурации Playwright-проекта нужно всего лишь указать параметр connectOptions.
export default defineConfig({
projects: [
{
name: 'chrome',
use: {
...devices['Desktop Chrome'],
connectOptions: {
wsEndpoint: 'ws://localhost:4444/pw/chrome/1.49.0'
}
}
}
...
Прощай selenoid
На этом наша «история успеха» не заканчивается: до сих пор мы не принимали во внимание технологии, которые пользователи применяют для запуска тестов локально. Общей фермы-то больше нет, а запустить тесты «как в CI» может быть необходимо. Например, для скриншотных тестов.
До всей истории с Playwright в качестве локального решения мы предлагали использовать старый добрый selenoid с нашими имиджами. Но selenoid не умеет в Playwright, а просто запускать Playwirght тесты локально — почти гарантированно получить расхождения в скриншотах из-за зоопарка пользовательских устройств (Windows, macOS). Кроме того, проект selenoid был заархивирован и больше не развивается с конца 2024 года.

Мы решили написать замену selenoid и в уже существующий сервис добавили поддержку Docker-бэкенда. Конфигурацию браузеров в CI опубликовали на внутреннем общем ресурсе, и теперь она автоматически применяется при запуске бинарника браузерной фермы локально.
Замена почившего selenoid может быть потенциально интересна более широкой аудитории, поэтому мы открыли большую часть кода нашего сервиса. Получившийся проект назвали Selebrow.
Сейчас наш внутренний проект на 99% собирается из кода Selebrow и мы планируем публиковать все доработки в open source.
Итоги
Параллельно с развитием проекта росло количество клиентов-пользователей, и общее количество ежедневно запускаемых браузеров достигло тех самых 100k+, обещанных в заголовке.

Если вы хотите за��устить нечто подобное у себя или уже используете Selenoid/Selenum Grid, предлагаем попробовать Selebrow. Пишите issue, если есть какие-то вопросы по запуску или настройке, — всем постараемся ответить. Если чего-то не хватает, тоже пишите: у нас уже сложился некоторый бэклог по Selebrow — возможно, там это уже есть.
Полезные ссылки
Стандарт протокола Webdriver (draft)
Комментарии (5)

muhachev
17.10.2025 15:08А чем Puppeteer вам не подошёл?

Hamletghost Автор
17.10.2025 15:08Привет спасибо за вопрос, я действительно про него не упомянул в статье, хотя изначально в черновиках было.
Если коротко: Puppeter так и не взлетел (не получил широкого применения) и сейчас скорее мертв чем жив. Из главных для нас недостатков это то что он chrome only и JS only - тесты пишут не только на ноде так то )
Команда его разработчиков собственно ушла в Microsoft и сделала там на его основе (хотя там наверное уже ничего общего не осталось) Playwright. В 2025 году выбор между Playwright и Puppeter даже не стоит рассматривать на мой взгляд.

PCB_Destroyer
17.10.2025 15:08С включёнными 100к+ браузерами врд ли поспишь)

Hamletghost Автор
17.10.2025 15:08В это наверное трудно поверить, но в поддержке этот сервис один из самых беспроблемных.
Во-первых: все эти сотни тысяч браузеров (в пике сейчас бывает до полу миллиона в день на самом деле) запускаются не одновременно, а в течение дня, иначе в моменте потребовались бы сотни тысяч ядер CPU для их запуска (наш облачный провайдер был бы очень рад такому клиенту).
Во-вторых у нас есть многоуровневая система лимитов:
Лимит на команду/проект как раз на количество одновременно запущенных браузеров
Общий лимит подов браузеров на неймспейс в кластере
Лимит для автомасштабирования нод кластера, чтобы он не рос бесконечно
В конце концов лимиты, установленные в настройках облака, чтобы не потратить все деньги мира.
В-третьих у нас собирается подробная статистика по всему, что происходит в этом сервисе и на основе нее отливаются метрики, по которым настроен мониторинг и алертинг. Всю картину происходящего можно легко увидеть на дашборде.
По факту вся поддержка в основном пользовательская: ответы на вопросы «как сделать», «что я делаю не так» и т.п.
apcs660
когда то в дремучем 2004 (или 2005? не помню) был проект для Toyota Canada. Нужно было из браузера делать обход сайтов и тд, собирать информацию (ну не было тогда автоматизированных API для B2B). По разному пробовали, в итоге получилось решение на VMWare сервере, с IEHost для IE на С# с управлением от Java (изначально было решение на Java). Удаленно создавалась честная VM (управление VMWare из java по веб сервису), в ней плодились в необходимом количестве IE браузеры, ходили куда нужно, кликали что требовалось (доступ к DOM), сайты его воспринимали нормально, js работал тоже нормально, что не проходило с разными "обрезанными" версиями html браузеров или java библиотек с html клиентами (js код к примеру не выполнялся). Тяжеловестно, дубово но работало. 20 лет назад, на коленке.