Напишите автотест логина на Playwright. Как сделаете его стабильным и поддерживаемым?
Короткий ответ
- Локаторы по ролям и data-testid, не по XPath с индексами
- Веб-first assertions с ожиданием вместо sleep
- Page Object отделяет логику страницы от теста
- Тестовые данные из фикстур, не хардкод в тесте
- Проверка результата: URL, видимый элемент, состояние сессии
- Негативный кейс с проверкой сообщения об ошибке
Стабильный UI-тест — это надёжные локаторы, автоожидающие проверки, Page Object и изолированные тестовые данные.
Как сказать вслух
пример ответаПишу тест через Page Object: страница логина — отдельный класс с локаторами и методом «войти», тест только вызывает его и проверяет результат. Локаторы беру по ролям или data-testid, чтобы не ломались от вёрстки. Никаких sleep — assertions Playwright сами ждут появления элементов. Данные для входа кладу в фикстуры. Проверяю не только отсутствие ошибки, а положительный признак: URL дашборда и, например, имя пользователя в шапке.
Подробный ответ
Основной ответ
Хороший автотест логина демонстрирует несколько инженерных практик сразу. Локаторы — пользовательские: get_by_role, get_by_label, get_by_test_id; XPath с индексами и CSS-цепочки ломаются от любого изменения вёрстки. Ожидания — только автоожидающие expect-проверки Playwright, никаких time.sleep: это главный источник и флаки, и медленных прогонов. Архитектура — Page Object: класс страницы инкапсулирует локаторы и действия, тест читается как сценарий и не меняется при изменении вёрстки. Данные — в фикстурах pytest или конфигурации окружения, пароли не хардкодятся в коде. Проверки — позитивный признак успеха (URL, элемент дашборда), а не просто отсутствие ошибки. В пару к позитивному тесту пишется негативный: неверный пароль и проверка текста ошибки. Для скорости в реальных проектах сессию логина получают один раз через API или storage_state, а UI-тест логина оставляют единственным, проверяющим саму форму.
Ключевые моменты
- Page Object. Локаторы и действия в классе страницы; изменение вёрстки правится в одном месте.
- Автоожидания вместо sleep. expect(...).to_be_visible() ждёт сам с таймаутом; sleep — запах флаки-теста.
- Позитивный критерий успеха. Проверяется признак залогиненности, а не отсутствие сообщения об ошибке.
- Логин через API для остальных тестов. UI-логин в каждом тесте — медленно; сессия переиспользуется через storage_state.
Практический контекст
Типовое задание на лайвкодинге для middle-автоматизатора: смотрят не на синтаксис по памяти, а на привычки — какие локаторы выберет, появится ли sleep, вынесет ли Page Object, что проверит в конце. Проговаривать решения вслух обязательно: «беру локатор по роли, потому что он переживёт изменение вёрстки» — именно это и оценивается.
Пример кода
from playwright.sync_api import Page, expect
class LoginPage:
def __init__(self, page: Page):
self.page = page
self.email = page.get_by_label("Email")
self.password = page.get_by_label("Пароль")
self.submit = page.get_by_role("button", name="Войти")
self.error = page.get_by_test_id("login-error")
def login(self, email: str, password: str):
self.page.goto("/login")
self.email.fill(email)
self.password.fill(password)
self.submit.click()
def test_login_success(page: Page, user):
LoginPage(page).login(user.email, user.password)
expect(page).to_have_url("/dashboard")
expect(page.get_by_test_id("user-menu")).to_contain_text(user.name)
def test_login_wrong_password(page: Page, user):
LoginPage(page).login(user.email, "WrongPass1!")
expect(LoginPage(page).error).to_have_text("Неверный email или пароль")Частые ошибки
- Используют time.sleep вместо автоожидающих проверок
- Хрупкие локаторы: длинные CSS-цепочки или XPath с индексами
- Проверяют только отсутствие ошибки, а не положительный признак успешного входа