Перейти к содержанию
Публикация AiManual

E2E-тесты с Claude Code: как находить баги до пользователей

E2E-тест с агентом кликает по приложению как пользователь и падает там, где Claude Code ошибся. Разбираем промпт со сценарием и ролями, доступ к браузеру через

Коротко

Что будет в материале

  1. 01

    Что такое E2E-тесты и почему они важны при разработке с кодинг-агентами

  2. 02

    Как изменились E2E-тесты: от ручных скриптов к агенту с планом действий

  3. 03

    Как описать E2E-тест промптом: сценарий, роли и ожидаемый результат

  4. 04

    Как запускать агентные E2E-тесты в CI/CD

Что такое E2E-тесты и почему они важны при разработке с кодинг-агентами

E2E-тест (end-to-end) проверяет приложение так, как его видит человек: агент с доступом к браузеру открывает страницу, кликает по кнопке, переходит на следующий экран и сообщает, если после действия возникла ошибка, ничего не произошло или ожидаемый результат не наступил. Тест смотрит на экран, решает, куда нажать, и проверяет, что оказалось дальше.

При разработке с кодинг-агентами вроде Claude Code или Codex такой тест закрывает конкретный разрыв. Агенты пишут код быстро и в основном правильно, но ошибаются неизбежно: упускают часть информации или выдают запутанную конструкцию с неожиданными побочными эффектами. Синтаксис при этом чистый, сборка проходит, а пользователь на третьем клике получает пустой экран и уходит. Разбор подхода к тестированию приложений, собранных с Claude Code описывает именно эту логику: агент проверяет поведение, а не внутреннюю реализацию.

Ключевое отличие E2E от остальных проверок: тест не зависит от того, какой код вы запустили или собрали. Он работает с самим приложением, с конечным продуктом, который видит пользователь. Отсюда и главная польза: проблемы обнаруживаются в той форме, в какой их переживают люди, и появляется время исправить их до того, как пользователи найдут их первыми.

Чем E2E-тест отличается от юнит-тестов и проверок кода

Разница проходит по уровню, на котором тест работает. Юнит-тест дергает отдельную функцию и сравнивает результат с ожидаемым значением. E2E запускает приложение целиком и проходит пользовательский путь: вход, заполнение формы, сохранение, проверка, что данные появились в списке.

УровеньЧто проверяетКогда гоняютЧто пропускает
Юнит-тестОтдельную функцию или модуль в изоляцииНа каждый коммит, секундыКак части собираются вместе и как ведёт себя интерфейс
Интеграционный тестСвязку модулей, API и базы данныхПри изменении контрактовРеальный путь пользователя через экраны
E2E-тестСквозной сценарий в запущенном приложенииПеред мержем и по расписанию, минутыНе локализует причину сбоя, дороже в поддержке

Вывод из таблицы простой: E2E дороже и медленнее юнит-тестов, поэтому им не заменяют нижние уровни, а дополняют. Юнит-тест скажет, что сломалась функция расчёта скидки. E2E скажет, что после применения скидки из корзины исчез самовывоз. Для кодинг-агента ценнее второй сигнал: он проверяет результат работы агента, а не его намерения.

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

Почему кодинг-агенты хорошо пишут код, но всё равно ошибаются

Ошибки агентов редко выглядят как грубый синтаксис. Чаще это пропущенная деталь: не обработан пустой ответ API, не учтён пользователь без прав, кнопка отрисовывается, но обработчик не привязан. Такие дефекты не видны в диффе и почти не ловятся линтером, потому что формально код корректен.

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

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

Как изменились E2E-тесты: от ручных скриптов к агенту с планом действий

Раньше E2E-тесты собирались руками. Нужно было пройти каждую страницу, найти ID кнопки, которую тест должен нажать, и записать ожидаемый результат действия на этой странице. Работа механическая, но объёмная: на десяток экранов уходил день, и это только первый проход.

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

С кодинг-агентами картина изменилась: тесты стали быстрее собирать и проще поддерживать. Современный E2E-тест по сути представляет собой агента с доступом к компьютеру или браузеру и планом того, что он должен сделать. Ему задают сценарий: добраться до страницы A, выполнить действие B, получить результат C.

Почему агентные тесты устойчивее к изменениям дизайна

Агента не нужно обновлять при изменениях дизайна страницы, пока нужная кнопка остаётся на ней. Он ищет кнопку по смыслу и тексту, а не по жёстко зашитому селектору. Ручной тест с ID элемента ломается от смены вёрстки, агентный проходит тот же путь на новом макете. Эта устойчивость и её границы разобраны в первоисточнике.

Границы важны. Если кнопка исчезла с экрана, переехала в скрытое меню или сценарий изменился по смыслу (раньше оплата шла в один клик, теперь через подтверждение), промпт придётся править. Поддержка не исчезла полностью, она сместилась: вы поддерживаете описание сценария, а не селекторы и ожидаемые строки.

Что агентные E2E-тесты находят лучше узких скриптов

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

  • Ошибка после нажатия: появился экран 500, упал запрос, вылетело сообщение об исключении.
  • Отсутствие реакции: клик прошёл, но ничего не изменилось и запрос не ушёл.
  • Невыполнение ожидаемого действия: форма отправилась, а запись не создалась или создалась с пустыми полями.
  • Побочный дефект: сценарий формально завершился, но на экране остались чужие данные или неверный статус.

Пример из практики поддержки больших наборов: в разборе аудита 2600 автотестов перед миграцией с Java на .NET видно, сколько мусора накапливается в наборе E2E-тестов без регулярной ревизии: около 450 неактуальных скриншотных тестов и удалённые дубли. Сценарии на естественном языке читать и ревизовать дешевле, чем код с селекторами.

Как описать E2E-тест промптом: сценарий, роли и ожидаемый результат

Промпт для E2E-теста состоит из четырёх частей: стартовая точка, последовательность действий, ожидаемый результат и критерий провала. Четвёртая часть самая недооценённая. Без неё агент может решить, что сценарий прошёл, хотя приложение вело себя не так, как задумано.

Доступ к браузеру дают через MCP-сервер, например Playwright MCP: он отдаёт агенту инструменты вроде открытия страницы, клика, ввода текста, чтения DOM и снятия скриншота. Конкретный транспорт вторичен, важен принцип: агент получает возможность управлять браузером и видеть результат. Первоисточник описывает подход в общем виде, без привязки к конкретному MCP-серверу, поэтому связку «агент + Playwright MCP» считайте практическим дополнением, а не цитатой.

Полезно сразу договориться, что агент делает при сбое: останавливается, фиксирует шаг, прикладывает скриншот и текст ошибки. Тогда результат прогона читается за минуту, а не превращается в расследование.

Как задавать роли: обычный пользователь и админ

Роль задаётся прямо в промпте как часть сценария: под каким пользователем стартуем, что ему доступно, что должно быть недоступно. Тест только от администратора маскирует баги прав доступа, потому что админ видит всё и не воспроизводит ограничения обычного аккаунта.

Рабочая структура описания роли:

  1. Кто именно действует: гость, обычный пользователь, администратор.
  2. С какого экрана стартует и в каком состоянии аккаунт (пустой профиль, есть заказы, активная подписка).
  3. Что роль может сделать и что должно быть заблокировано.
  4. Какое поведение системы считается правильным при попытке запрещённого действия: редирект, сообщение, скрытая кнопка.

Один сценарий удобно прогонять дважды, от обычного пользователя и от админа. Расхождения в поведении часто и оказываются багом: пользователь видит кнопку удаления, которая должна быть только у администратора, или админ получает отказ по правам.

Пример промпта для E2E-сценария

Шаблон ниже иллюстративный. Он показывает структуру, а не проверенный на конкретном проекте набор инструкций.

Цель: проверить сценарий оформления заказа.
Роль: обычный пользователь, тестовый аккаунт <email>, пароль <пароль>.
Старт: <URL стенда>, страница каталога.
Шаги:
1. Открыть карточку первого товара в списке.
2. Нажать «Добавить в корзину».
3. Перейти в корзину и нажать «Оформить заказ».
4. Заполнить обязательные поля и подтвердить заказ.
Ожидаемый результат: появился экран подтверждения с номером заказа,
заказ виден в разделе «Мои заказы» со статусом «Оплачен».
Считать провалом: ошибка после клика, отсутствие реакции на клик,
отсутствие заказа в списке, неверный статус, пустые поля в заказе.
При сбое: остановись, укажи номер шага, что ожидал и что увидел,
приложи скриншот.
Не делай: не удаляй заказы, не меняй пароль и настройки аккаунта.

Последний блок («не делай») экономит нервы. Агент без ограничений иногда «чинит» окружение по пути: удаляет мешающую запись или меняет настройки, чтобы сценарий прошёл. Запрет на разрушающие действия стоит в промпте по умолчанию.

Как запускать агентные E2E-тесты в CI/CD

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

Первый режим: блокирующий прогон перед мержем. Второй: регулярный прогон по расписанию на dev и production. Они ловят разные классы проблем, поэтому нужны оба.

Прогон перед мержем: что блокировать

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

В GitHub Actions прогон выглядит привычно: джоб поднимает приложение и базу, запускает агента с промптом, складывает в artifacts скриншоты, видео и лог шагов. Артефакты важнее статуса: по ним видно, на каком шаге тест сломался и что именно было на экране.

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

Прогон по расписанию в dev и production

Расписание ловит то, что не воспроизводится в чистом CI: миграции на реальных данных, истёкшие токены, изменившиеся ответы внешних API, проблемы окружения. На dev такие прогоны дешевле и безопаснее, туда можно включить больше сценариев.

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

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

Где запускать тесты: облачный сервер, GitHub Actions runner или отдельная машина

Агент с браузером требователен к окружению: нужен запущенный Chromium, стабильная сеть, доступ к стенду и достаточно памяти. Выбор площадки влияет на стабильность и на стоимость одного прогона.

ВариантПлюсыМинусыКогда подходит
GitHub Actions runnerНулевая настройка, интеграция с PR, артефакты из коробкиЛимиты по времени и окружению, доступ во внутреннюю сеть требует self-hosted агентаСтарт проекта, публичные стенды, короткие блокирующие прогоны
Облачный сервер (VM)Полный контроль над образом, воспроизводимость, можно держать браузер и проксиНужно администрировать, платить за простой, следить за обновлениямиРегулярные прогоны по расписанию, доступ к приватным стендам
Отдельная машинаМаксимум контроля, свои секреты и сеть, удобная отладкаНет масштабирования, одна точка отказа, зависимость от чужого питания и сетиНебольшая команда, один-два сценария, закрытый контур

Рамка выбора простая. Если прогонов мало и они короткие, хватит hosted runner. Если тесты идут по расписанию и нужен доступ в приватную сеть, берите VM или self-hosted runner. Если проект небольшой и всё упирается в закрытый контур, отдельная машина переживёт и это, но перестанет работать, как только понадобится параллельность.

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

Ограничения и подводные камни агентных E2E-тестов

Подход не бесплатный и не самоподдерживающийся. Прямые минусы, с которыми придётся жить:

  • Недетерминированность. Один и тот же промпт может дать разное поведение: сегодня агент пошёл по одному пути, завтра по другому. Часть ложных срабатываний идёт отсюда.
  • Стоимость. Каждый прогон расходует токены и время, а отладка сбоя иногда занимает больше, чем написание сценария.
  • Флейки. Сеть, тайминги анимаций и медленные ответы API дают падения, не связанные с багами. Без изоляции такие тесты перестают замечать.
  • Ложный зелёный. Агент может пройти сценарий другим путём и не увидеть проблему, которую искали. Спасают точные критерии провала в промпте.
  • Поддержка по смыслу. Дизайн меняется, и тест выживает, а бизнес-логика меняется, и промпт нужно переписать.

Агентные E2E-тесты не заменяют юнит-тесты и код-ревью. Они закрывают верхний уровень: проверяют, что приложение работает для человека целиком. При этом проверка результата вообще стала дороже генерации кода, и это отдельная проблема, разобранная в статье про разработку с ИИ-агентами. Автотест в браузере сокращает эту нагрузку, но не отменяет её.

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

С чего начать: минимальный план запуска

Старт с одного сценария дешевле, чем попытка покрыть всё приложение сразу. Порядок шагов:

  1. Выберите один критичный путь, без которого продукт не работает. Не самый сложный, а самый важный.
  2. Подключите агенту доступ к браузеру через Playwright MCP или аналогичный сервер и убедитесь, что он открывает ваш стенд.
  3. Опишите сценарий промптом: роль, стартовая страница, шаги, ожидаемый результат, критерии провала, запрет на разрушающие действия.
  4. Прогоните вручную несколько раз. Если агент каждый раз идёт по-разному, уточните формулировки: неоднозначность в промпте превращается в флейк.
  5. Встройте прогон в CI перед мержем как блокирующий для этого одного сценария.
  6. Добавьте расписание: сначала на dev, затем на production с безопасным набором действий.
  7. Расширяйте набор только после того, как первый сценарий перестал падать без причины.

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

Подписаться на канал