Скилл для UI-автотестов: от 800 строк до автопилота

Скилл для UI-автотестов: от 800 строк до автопилота

TechTalk — это наши внутренние встречи, на которых команды OneTwoTrip делятся техническими решениями, экспериментами и результатами. На этот раз говорили о скилле для UI-автотестов iOS: как он вырос из одного файла на 800 строк в систему с маршрутами, сабагентами, общей памятью и журналом успешных решений.

Как устроен скилл

Его первая версия была устроена просто: вся логика была собрана в одном файле примерно на 800 строк. Там находились сценарии, инструкции по управлению, диагностике и запуску. В результате агент на каждой задаче получал много контекста, который ему мог вообще не понадобиться.

Сейчас skill.md занимает всего 68 строк и фактически работает маршрутизатором: определяет задачу и подключает нужный сценарий. Остальные знания разнесены по 29 инструкциям и 18 скриптам. Всего есть семь маршрутов — например, для добавления и исправления тестов, диагностики, ревью, автопилота и обучения.

Так исторически сложилось что для работы с Jira и TestOps используется корпоративный MCP, а скилл только определяет, что и в какой последовательности делать.

Не показывать агенту всё сразу

Ещё один принцип — выдавать диагностические данные по мере необходимости. Сначала агент получает самые дешёвые артефакты: дерево UI и логи. Если их недостаточно — скриншот и код. Видео подключается в последнюю очередь: отдельный скрипт достаёт из него кадры и связывает их с конкретными действиями теста.

Источниками истины при этом остаются TestOps, код проекта и артефакты запуска. Предусловия, шаги и ожидаемый результат из TestOps сопоставляются с кодом в начале и в конце работы. Это важно, чтобы агент не «починил» тест самым простым способом — например, выбросив проблемный шаг ради зелёного прогона.

Пробовали и проверять гипотезы без полной пересборки приложения через XcodeBuildMCP. Но замеры дали неожиданный результат: общий цикл стал примерно на 15% медленнее. Около 80% тестов агент и так исправлял с первой попытки. Поэтому такой сценарий оставили только для случаев, когда первый фикс не сработал.

Один координатор и несколько исполнителей

Для сложных падений используется оркестрация сабагентов. Координатор распределяет работу и собирает итоговый отчёт, а владелец теста отвечает за него до зелёного статуса или подтверждённого блокера.

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

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

Как дать агентам общую память

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

Если один агент уже попробовал определённый способ и выяснил, что он не работает, следующий увидит это в состоянии и не станет повторять тот же путь. Файл можно передать другому агенту и продолжить работу с того же места.

Записывать данные напрямую нельзя: состояние меняется только через CLI-команды. Так формат остаётся единым, логика работы с ним покрывается тестами, а правила не зависят от конкретной модели.

Решения, которые не приходится искать заново

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

Когда появляется новое падение, система формирует его сигнатуру, ищет похожие случаи и выбирает подходящий рецепт. После применения результат снова попадает в журнал. Получается накопительная память: опыт одного запуска может пригодиться в следующих. Причём журнал можно наполнять не только новыми кейсами. Отдельный сценарий обучения по pull request возвращает проект в состояние до исправления, воспроизводит падение, затем применяет изменения и проверяет результат. Так можно перенести в систему знания, которые разработчики и QA накопили ещё до появления самого журнала.

От скилла к автопилоту

У агента заранее определены права: что он может читать и какие действия выполнять — например, создать ветку, сделать коммит, открыть pull request или оставить комментарий. Всё, на что разрешения нет, он пропускает.

Это позволяет запускать ночной сценарий с чистым контекстом. Скилл забирает артефакты последнего прогона, разбирает падения и работает с ними до исправления или блокера. В конце он может создать задачу в Jira, ветку и pull request, а человеку оставить один итоговый артефакт — отчёт.

В отчёте видно, сколько тестов прошло, где остались проблемы и какие случаи требуют ручной проверки. Для каждого сценария сохраняются причина падения, исправление, дифф и видео успешного прогона. Поверх видео накладываются действия теста — нажатия, свайпы и проверки элементов, — поэтому QA может проверить результат, не погружаясь в код и логи.

Следующий шаг — связать этот процесс с генерацией тест-кейсов: получать их из описания задачи, документации, макетов и кода, а затем использовать как контракт для написания автотестов. Правда, пока это только концепция. Мы в OneTwoTrip решили начать именно с тестов: прежде чем отдавать AI исправление продуктовых багов, нужно научиться доверять системе, которая проверяет результат.