В мире автоматизированного тестирования давно существует правило — избегать использования произвольных ожиданий или задержек. Многолетняя практика диктует, что фиксированные паузы в тестах не только замедляют выполнение сценариев, но и скрывают настоящие проблемы, создавая иллюзию стабильности там, где на самом деле имеется непойманный баг. Однако, сталкиваясь с реальными задачами и ограничениями в разработке, мы в Octomind пересмотрели этот принцип. В этом материале расскажем, что подтолкнуло нас к изменению подхода, какие сложности были на пути и как грамотное и осознанное внедрение ожиданий помогло повысить качество и предсказуемость автоматизированных тестов.Долгое время в нашем сообществе разработчиков и тестировщиков вырабатывалась твердая установка — не использовать произвольные задержки в тестах.
Такой подход формировался из понимания, что фиксированные паузы изначально являются костылями, маскирующими настоящие проблемы с синхронизацией или неполнотой загрузки страницы. В идеальном мире тесты должны срабатывать по событию, состояние элементов должно гарантировано быть готовым, и весь поток должен строиться исключительно на детектировании развития событий в приложении. Этот идеал позволял экономить существенное время в прогоне, делать тесты более быстрыми и поддерживаемыми, избавлял от неопределенности и случайных отставаний.Однако практика оказалась куда сложнее. На стыке современных фреймворков, оптимизации скорости загрузок и новых методик рендеринга появились сценарии, в которых классическая методика ожидания событий переставала быть адекватной.
Один из ярких примеров — реакция на события в приложениях с отложенной гидрацией пользовательского интерфейса. Такие веб-приложения сначала загружают статическую разметку, а необходимые JavaScript-слушатели подключают уже после, что экономит ресурсы и улучшает показатели аналитических сервисов, таких как Lighthouse. При этом вид с точки зрения DOM давно кажется завершенным и «готовым» — но на самом деле взаимодействие с элементами остается неактивным. Для обычного пользователя такая задержка незаметна: он просто повторит клик, когда элемент станет доступен. Для автоматизации же, которая кликает один раз и ждет результата, это становится источником постоянных ошибок и нестабильности.
Обнаружить и понять природу таких «фантомных» багов было непросто. Мы получили запросы от нескольких клиентов, которые столкнулись с тем, что тесты ломались именно на этом этапе — при попытке взаимодействия с элементами после первого рендера страниц. Клиенты замечали, что баги не проявлялись при живом использовании, а лишь портили статистику тестов. После глубокого исследования оказалось, что фича задержки гидрации — nuxt-delay-hydration — встроена в Nuxt.js приложение и служит для повышения производительности.
Тем не менее, она создает временное состояние, когда элементы выглядят полностью готовыми, но еще не получены обработчики событий. Результат — клики в этом промежутке «падают», тесты становятся нестабильными, а сбои воспринимаются как флаттеринг.Конечно, правильным было бы либо ускорить процесс гидрации страницы, либо заблокировать взаимодействие пользователя до полной готовности интерфейса. Но этим оказалось сложно заниматься сразу: разработчики имеют свои приоритеты, и критические улучшения часто откладываются на потом. В таких условиях нашу команду заинтересовало использование функционала самого плагина, который возвращал промис завершения гидрации — window.
_$delayHydration. Благодаря этому появилась возможность использовать детерминированное ожидание. Вместо произвольного ожидания по таймауту, мы добились ситуации, когда тест ждал именно сигнала о том, что интерфейс готов для взаимодействия. Это значительно уменьшило количество ложных срабатываний и улучшило стабильность тестов без задержек, уменьшая общее время прогона.Добавление в тестовый фреймворк шага «ожидания гидрации» улучшило понимание процесса, дало визуальный и программный контроль состояния страницы и позволило нашим пользователям запускать тесты с высокой степенью предсказуемости.
Для нас это стало важным уроком баланса между идеальностью и практичностью. Иногда идеальный вариант в виде исправления кода невозможен — а бизнесу требуются стабильные тесты сейчас. Приходится принимать компромиссы в виде детерминированных ожиданий, которые являют собой не просто «зависание по времени», а осознанную точку ожидания.Другим случаем стало тестирование классической схемы входа по одноразовой ссылке. Пользователь вводит электронную почту, получает письмо с кодом, вводит его в форму и получает доступ в приложение.
Это, казалось бы, простейший сценарий, который в жизни работает безотказно. Но при попытках автоматизации на Playwright 70% прогонов заканчивались ошибкой «некорректный одноразовый код». Разбор ошибок показал, что до отправки запроса с кодом поле было заполнено как будто верно, но в реальности в сетевом запросе передавался пустой или null-код. Причина — гонка состояний, при которой перед вводом кода в поле требовалась небольшая пауза, чтобы клиентское приложение гарантированно подготовилось к работе. Опять же, проблема была признана багом и должна быть исправлена в приложении, но сроки затягивались, а тесты нужны были уже сегодня.
В этой ситуации мы приняли решение об использовании фиксированного ожидания в три секунды перед вводом кода. Да, строго говоря, это артефакт и временный костыль, но он позволил разблокировать клиентов и поддерживать стабильность конвейера CI. Мы тщательно следим за дальнейшим поведением такого решения и планируем удалять эти паузы, как только появится возможность корректных исправлений в коде.Выводы, которые мы сделали после этих кейсов, помогают нам формировать эффективный подход к автоматизации в условиях реальной работы с продукцией и клиентами. Внутри собственной компании и на собственных проектах, где есть быстрый доступ к коду и ресурсам разработки, мы стремимся избегать произвольных timeout-ов.
Каждую такую проблему стараемся выстраивать в цепочку исправлений кода, чтобы тесты отражали реальность, а не маскировали ее.Но при поставке платформы для широкого круга пользователей ситуация иная. Многие команды не имеют возможности напрямую влиять на баги, либо не могут оперативно их решить из-за бизнес-приоритетов. В таких условиях идеализм необходимости заменять ожидания на реальные проверки сталкивается с жесткой реальностью. Чтобы обеспечить жизнеспособность автоматизации и уменьшить фреймобильность тестов, иногда приходится прибегать к «хирургическим» паузам — целенаправленным и детерминированным задержкам.
Они не служат целью скрывать баги, а являются временной мерой, обеспечивающей непрерывность процессов и возможность быстро реагировать на бизнес-задачи.Представляя автоматизацию как часть общего цикла разработки продуктов, мы понимаем важность такого баланса между желанием идеального и требованиями бизнеса. Безусловно, каждый такой вызов — повод по-новому взглянуть на архитектуру приложений, процессы коммуникации команд, особенности фронтенда и тестов. Возможность применять осмысленные ожидания дает нам дополнительный уровень защиты от флаттеринга и нестабильности, не превращая тесты в бездумное скриптование с многочисленными паузами.Подводя итог, можно сказать, что наш опыт показывает необходимость видеть за правилом не догму, а удобный инструмент.
 
     
    