Selenium, Playwright и «плавающие» тесты

Даже если вы не автоматизатор, от middle-кандидата ждут понимания, как устроены UI-тесты и почему они «плавают».

Flaky-тест — тест, который на одном и том же коде то падает, то проходит. Он опаснее отсутствующего теста: команда перестаёт доверять всему набору.

Вопрос 1: «Чем Playwright отличается от Selenium?»

Что на самом деле проверяет интервьюер

Ориентируетесь ли вы в инструментах и понимаете ли, что разница не в «моде», а в архитектуре.

Развёрнутый ответ

КритерийSelenium WebDriverPlaywright
Управление браузеромпо протоколу WebDriver, через драйвернапрямую по протоколу браузера (CDP и аналоги)
Ожиданияявные и неявные, настраиваются вручнуюавто-ожидание готовности элемента встроено
Экосистемаочень зрелая, любой язык, стандарт W3Cмоложе, но «из коробки» трассировка, видео, скриншоты, перехват сети
Параллельностьчерез Selenium Gridвстроенные контексты браузера, изоляция сессий
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# явное ожидание вместо time.sleep
button = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, "[data-testid='pay-button']"))
)
button.click()
// Playwright: ожидание встроено в действие
await page.getByTestId('pay-button').click();
await expect(page.getByText('Заказ оплачен')).toBeVisible();

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

Вопрос 2: «Какие локаторы выбирать и что такое Page Object?»

Развёрнутый ответ

Порядок предпочтения локаторов от лучшего к худшему:

  1. Специальный атрибут для тестовdata-testid. Не меняется при редизайне, потому что существует только ради тестов.
  2. Доступные роли и тексты — «кнопка с названием Оплатить». Заодно проверяет доступность интерфейса.
  3. Стабильный id, если он действительно стабилен, а не сгенерирован фреймворком.
  4. CSS-селектор по осмысленным классам.
  5. XPath по структуре вроде /div[2]/div[3]/span — худший вариант: ломается от любой правки вёрстки.

Page Object — паттерн, при котором страница описывается классом: локаторы и действия внутри, тест — снаружи. Смысл в том, что при изменении вёрстки правится один класс, а не пятьдесят тестов. Тест при этом читается как сценарий на человеческом языке, а не как набор селекторов.

Вопрос 3: «Тест падает через раз. Что делать?»

Что на самом деле проверяет интервьюер

Не предложите ли вы «перезапустить и забыть» — самый вредный ответ в этом блоке.

Развёрнутый ответ

Типовые причины нестабильности и лечение:

  • Гонки и ожидания: time.sleep(2) вместо ожидания условия. Лечится явными ожиданиями конкретного состояния элемента.
  • Зависимость от данных: тест рассчитывает на пользователя, которого удалил другой тест. Лечится генерацией своих данных и очисткой после прогона.
  • Зависимость от порядка: тест 5 работает только после теста 4. Тесты должны быть независимыми.
  • Внешние сервисы: реальный платёжный шлюз отвечает нестабильно. Лечится моками и sandbox-окружением.
  • Общее состояние и параллельность: два теста меняют одну и ту же запись. Лечится изоляцией — свой аккаунт на тест.
  • Время и локаль: тест падает после полуночи или на другом часовом поясе. Лечится фиксацией времени и локали.

Организационная часть ответа не менее важна: flaky-тест нужно пометить и завести на него задачу, а не глушить перезапуском. Автоматический retry маскирует настоящие плавающие дефекты продукта — а они, между прочим, точно так же «плавают» у пользователей.

Типичные ошибки кандидатов

  • Предлагают лечить нестабильность увеличением sleep — это замедляет прогон и не устраняет причину.
  • Ставят автоматический retry по умолчанию и считают проблему решённой.
  • Используют XPath по структуре и жалуются, что тесты ломаются от любой правки вёрстки.
  • Пишут тесты, зависящие друг от друга и от порядка выполнения.
  • Считают Playwright «заменой Selenium во всём» — выбор зависит от стека команды, языка и требований к поддержке браузеров.

Как ответить кратко

Selenium управляет браузером по стандарту WebDriver, у него огромная экосистема и поддержка любых языков, но ожидания нужно писать руками. Playwright работает по протоколу браузера напрямую, авто-ожидания и трассировка встроены, параллельность — через изолированные контексты. Локаторы выбираю в порядке устойчивости: data-testid, затем роль и текст, затем стабильный id и CSS; XPath по структуре — последний вариант. Страницы описываю паттерном Page Object, чтобы при редизайне править один класс, а не все тесты. Flaky-тесты не глушу перезапусками: ищу причину — sleep вместо ожидания условия, зависимость от данных или порядка, внешние сервисы, общее состояние при параллельном прогоне, привязка ко времени и локали — и завожу на нестабильный тест отдельную задачу.

Проверьте себя
1. Какой локатор наиболее устойчив к изменениям вёрстки?
AXPath по структуре: /div[2]/div[3]/span
BCSS-селектор по классу оформления .btn-primary-2024
CСпециальный атрибут data-testid, добавленный для тестов
DПозиция элемента на странице в пикселях
2. UI-тест падает примерно в одном прогоне из четырёх. Какое решение правильное?
AВключить автоматический retry и не тратить время
BУвеличить time.sleep до 10 секунд
CНайти причину нестабильности — ожидания, данные, порядок, внешние сервисы — и завести на неё задачу
DУдалить тест из набора
3. Зачем нужен паттерн Page Object?
AЧтобы тесты выполнялись быстрее
BЧтобы локаторы и действия страницы жили в одном классе и при изменении вёрстки правился он, а не десятки тестов
CЧтобы обойтись без ожиданий в тестах
DЧтобы запускать тесты параллельно