Рекомендация

Как задавать шаги автотеста без ложных падений

Как задавать шаги автотеста без ложных падений

Рекомендация для авторов шагов Playwright в ComplexQA: как собрать импорт, COMMON, URL и Target так, чтобы запуск падал только на реальном расхождении с экраном.

Зачем

Воркер выполняет шаги буквально. Относительный goto всегда берёт стартовый домен запуска, а не текущую вкладку. waitForURL и toHaveURL разбирают Value по-разному. Импорт JSON принимает узкий набор полей. Из-за этого отчёт показывает FAILED на шаге, хотя нужный экран уже открыт, или наоборот: toHaveURL зелёный при странице 404.

Как устроить работу

  1. Повторяемый вход оформите автотестом вида COMMON. Проверяемый экран - отдельный CASE. На карточке CASE укажите предшественника и привяжите тестовый аккаунт. У COMMON аккаунта нет: шаги TEST_ACCOUNT читают аккаунт этого CASE. Порядок: Когда использовать COMMON и CASE.
  2. После импорта JSON смените вид на COMMON вручную. Импорт не принимает pre_autotest_case_ids и вид. COMMON в очередь запуска не ставьте.
  3. Экраны на том же хосте, что стартовый домен, храните в репозитории объектов относительным путём (/web/ru/user/auth/login). Экраны на поддомене команды - полным URL https://{slug}.хост/…. Подтверждённый корень покрывает свои поддомены. На шаге goto выберите страницу каталога; Value оставьте пустым.
  4. Для waitForURL задавайте Playwright glob (**/web/ru). Для toHaveURL задавайте /pattern/flags (исполнитель собирает регулярное выражение) или glob без хвоста ** сразу после последнего сегмента пути.
  5. Target должен находить один узел. Если ROLE с одним именем даёт два heading, смените kind на CSS.
  6. Проверяйте то, что видно после предыдущего шага, а не экран, который был вчера. Скриншот - опция запуска, не action_name.

Инструкции действий: goto, waitForURL, toHaveURL, toBeVisible.

Чего избегать

Каждый подраздел - одно ложное падение: что видно в отчёте, почему так, что поставить в шаге.

Импорт отклоняет value_source_type

В отчёте импорта. Unknown field value_source_type / value_source_field. Кнопка создания пропускает только валидные элементы массива.

Почему. Контракт импорта автотестов принимает у кейса autotest_case_title, autotest_case_description, autotest_case_status, autotest_steps. У шага: sort_order, action_name, target, value_text, timeout_ms. Поля карточки шага (value_source_type, value_source_field, object_repository_page_id, test_account_id, pre_autotest_case_ids) в JSON импорта не входят.

Как. Импортируйте fill с value_text (для синтаксиса). На карточке шага выставьте источник Value TEST_ACCOUNT и поле login / password. Пароль в JSON не кладите. Тестовый аккаунт привязывайте к CASE.

Вход повторён в каждом CASE

В отчёте. Одинаковые goto + fill + click на входе в десятке результатов. Смена формы входа ломает все кейсы.

Почему. Вид CASE без предшественника сам открывает сессию. Импорт не умеет выставить вид COMMON и список предшественников.

Как. Один COMMON «вход». После импорта смените вид на COMMON, статус READY. На каждом CASE в блоке Предшествующие автотесты укажите этот COMMON. CASE, который снимает форму входа, к этому COMMON не привязывайте: иначе снимок будет уже после входа.

waitForURL с /pattern/flags

В отчёте. page.waitForURL: Timeout … waiting for navigation to "/\/web\/ru\/(?!user\/auth)/" при уже открытом https://хост/web/ru.

Почему. Исполнитель передаёт Value waitForURL в Playwright строкой. Строка /…/ не компилируется в регулярное выражение. Символ ? в glob - один любой символ, lookahead не работает. Навигацию лог показывает, совпадения нет.

Как. Glob, как в инструкции waitForURL: **/web/ru. Регулярное выражение /pattern/flags используйте в toHaveURL.

Glob waitForURL со слэшем, которого нет в адресе

В отчёте. Ожидание **/web/ru/ или шаблона с \/web\/ru\/, получен https://хост/web/ru без слэша после ru.

Почему. Playwright сравнивает с фактическим href. Лишний слэш в шаблоне не совпадает с путём без завершающего слэша.

Как. Пишите glob так, как адрес выглядит в браузере: **/web/ru, не **/web/ru/, если слэша в конце нет.

toHaveURL с glob и хвостом **

В отчёте. expect(page).toHaveURL Expected: "**/web/ru/project/listing**" Received: https://{slug}.хост/web/ru/project/listing. Экран верный, шаг красный.

Почему. У toHaveURL исполнитель прогоняет Value через разбор /pattern/flags. Иначе строка уходит в Playwright как glob. Хвост ** сразу после последнего сегмента (listing**) не совпадает с URL, который на этом сегменте заканчивается.

Как. Для toHaveURL задайте регулярное выражение:

text
/\/web\/ru\/project\/listing/

Либо glob без хвоста: **/web/ru/project/listing. Не копируйте в toHaveURL тот же приём «обернуть путь в **…**», который сработал у waitForURL.

toHaveURL смотрит /web/ru/, страница каталога ведёт на /web/en/

В отчёте. Expected: **/web/ru**. Received: https://{slug}.хост/web/en/project/listing. Меню на английском.

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

Как. В карточке страницы каталога держите тот сегмент локали, который нужен сценарию (/web/ru/… или /web/en/…). Value toHaveURL повторяет тот же сегмент.

ROLE heading: strict mode, два узла

В отчёте. strict mode violation: getByRole('heading', { name: '…' }) resolved to 2 elements - например h5 шапки и h2 карточки с одним текстом.

Почему. Playwright в строгом режиме запрещает действие, если локатор находит больше одного узла. Kind ROLE + одно имя не различает два heading.

Как. Kind CSS с селектором одного узла (например h2.team-listing__title). Если шаг только подтверждает экран, а следующий клик однозначен, лишний toBeVisible по неуникальному heading уберите.

Относительный goto после смены хоста в COMMON

В отчёте. goto зелёный, на снимке страница 404 «Не найдено». Адрес вида https://webapp.пример/web/ru/project/listing без поддомена команды.

Почему. Относительный путь в goto склеивается со стартовым доменом запуска, не с хостом, на котором закончился COMMON. Клик по команде мог открыть {slug}.хост, следующий goto /web/ru/project/listing возвращает на корень. На корне этого экрана нет.

Как. Не увеличивайте число стартовых доменов. Заведите страницу каталога с полным URL https://{slug}.хост/web/ru/project/listing и выберите её на шаге goto. Подтверждённый корень покрывает поддомен. Подробнее: Страница репозитория и goto.

toHaveURL зелёный при 404

В отчёте. toHaveURL за путь /web/ru/project/listing - PASSED. Следующий toBeVisible по пункту меню - FAILED. Снимок: 404.

Почему. Проверка по пути не видит хост. Тот же путь на корне и на поддомене команды даёт разный экран.

Как. Для toHaveURL включайте хост или поддомен в шаблон (/\/{slug}\..*\/web\/ru\/project\/listing/ или glob **://{slug}.хост/web/ru/project/listing). Рядом держите toBeVisible по уникальному тексту рабочего экрана: 404 эту проверку не пройдёт.

Проверка экрана, которого после входа уже нет

В отчёте. toBeVisible по h2.team-listing__title («Выберите команду») при снимке списка проектов команды.

Почему. После входа на поддомене команды стартовая страница - рабочая область (listing проектов), не выбор команды. Шаг, написанный под picker, ищет узел с другого экрана.

Как. Стройте COMMON по фактическому снимку шага после click входа. Если picker исчез, удалите клик по команде и проверку заголовка выбора. Проверяйте то, что открылось: карточка проекта, пункт Проекты.

Скриншот как action_name

В отчёте. Импорт или проверка синтаксиса отвергает действие screenshot, либо шага нет в каталоге карточки.

Почему. Снимок экрана - опция запуска («Скриншот при ошибке», «Скриншот результата»), не действие шага. Каталог: Шаг автотеста.

Как. Включите нужную опцию в форме создания запуска автотестов. В шагах оставьте навигацию и проверки.

Локаль по атрибуту lang у html

В отчёте. URL содержит /web/ru/, в логе Playwright узел <html lang="en">. Автор меняет шаги, думая, что открыта английская локаль маршрута.

Почему. Сегмент пути /web/ru/ и атрибут lang на корневом html - разные поля. Проверка URL смотрит href. Подписи меню смотрите на снимке шага.

Как. Сегмент локали в пути страницы каталога и в toHaveURL держите одинаковыми. Для TEXT берите подпись, которая видна на снимке (пункт меню или название демо-проекта), не значение html lang.

Версия 1.0.0 · Последнее изменение 2026-09-14

Страница не помогла?