Блог
Автотесты/Playwright

Локаторы в Playwright подробно: все способы найти элемент

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

getByRole — приоритетный способ

await page.getByRole('button', { name: 'Отправить' }).click();
await page.getByRole('link', { name: 'На главную' }).click();
await page.getByRole('checkbox', { name: 'Согласен с условиями' }).check();
await page.getByRole('heading', { name: 'Добро пожаловать', level: 1 });

getByRole ищет элемент по его роли в дереве доступности (accessibility tree) — той же модели, которой пользуются скринридеры для незрячих пользователей. Это делает getByRole устойчивым к изменениям CSS-классов, порядка атрибутов и внутренней структуры HTML: пока элемент остаётся кнопкой с текстом «Отправить», локатор будет находить его независимо от того, как именно вёрстка реализована внутри.

getByText, getByLabel, getByPlaceholder

await page.getByText('Заказ оформлен').isVisible();
await page.getByLabel('Email').fill('user@example.com');
await page.getByPlaceholder('Введите пароль').fill('secret123');

getByText ищет по видимому тексту элемента — удобно для проверки сообщений, уведомлений, статусов. getByLabel находит поле формы по связанной с ним подписи (<label>) — предпочтительный способ для полей ввода, потому что отражает то, как пользователь реально ориентируется в форме. getByPlaceholder — по подсказке внутри пустого поля, полезно, когда у поля нет явного <label>.

getByTestId — запасной вариант

await page.getByTestId('submit-button').click();

getByTestId ищет элемент по специальному атрибуту (по умолчанию data-testid), который разработчики добавляют в разметку специально для тестов. Это надёжный, но не самый «естественный» способ — он требует, чтобы фронтенд-разработчики заранее проставили такие атрибуты. Используется, когда у элемента нет подходящей роли, текста или подписи, по которым его можно было бы найти иначе.

Фильтрация и уточнение локаторов

Если по одному запросу находится несколько элементов, локатор можно сузить:
// первый элемент из нескольких подходящих
await page.getByRole('button', { name: 'Удалить' }).first().click();

// элемент по индексу
await page.getByRole('listitem').nth(2).click();

// фильтрация по вложенному тексту
await page.getByRole('listitem').filter({ hasText: 'Молоко' }).click();

// комбинация: локатор внутри локатора
const row = page.getByRole('row', { name: 'Заказ №105' });
await row.getByRole('button', { name: 'Отменить' }).click();

Вложенные локаторы (row.getByRole(...)) — частый и полезный паттерн: сначала находится контейнер (строка таблицы, карточка товара), а затем внутри него ищется конкретный элемент. Это точнее, чем искать кнопку «Отменить» по всей странице, если таких кнопок несколько в разных строках.

Почему CSS-селекторы и XPath — не первый выбор

// Работает, но хрупко: привязан к структуре и классам вёрстки
await page.locator('.btn.btn-primary.submit-form > span').click();

Такой локатор сломается при любом изменении CSS-классов или структуры вложенности, даже если сама кнопка на странице никуда не делась и выглядит так же. getByRole, getByText, getByLabel устойчивее, потому что опираются на то, что видит и понимает пользователь, а не на детали реализации вёрстки. CSS-локаторы остаются рабочим инструментом, но как последний вариант, когда более «человеческие» локаторы не подходят.

Частые вопросы про локаторы в Playwright

Какой локатор использовать в первую очередь? getByRole — он рекомендован официальной документацией Playwright как приоритетный способ, потому что устойчив к изменениям вёрстки и отражает то, как реально взаимодействует с элементом пользователь.
Когда стоит использовать getByTestId? Когда у элемента нет подходящей роли, текста или подписи для поиска другим способом — например, у декоративного элемента без видимого текста. Требует, чтобы атрибут data-testid был заранее добавлен в разметку.
Что делать, если локатор находит несколько элементов? Сузить его: через .first(), .nth(index), фильтрацию по тексту (.filter({ hasText: '...' })) или через поиск внутри более конкретного родительского локатора.
Почему не стоит использовать CSS-селекторы по умолчанию? CSS-классы и структура HTML часто меняются при рефакторинге вёрстки, даже если поведение элемента остаётся прежним — из-за этого CSS-локаторы чаще ломаются и требуют переписывания, чем локаторы по роли или тексту.

Закрепить локаторы на практике

Разница между .filter(), .first() и вложенными локаторами лучше укладывается в голове на реальных задачах. Бесплатный тренажёр Playwright Arena от Quality Academy — 30 задач без оплаты и ограничения попыток.

-------

Полезные ссылки школы

Сайт Quality Academy:
/main
Telegram-канал:
https://t.me/quality_academy
YouTube-канал:
https://www.youtube.com/@quality_academy
ВКонтакте:
https://vk.com/quality_academy
Канал отзывов учеников (58+ отзывов):
https://t.me/quality_academy_reviews
Задать вопрос менеджеру:
https://t.me/quality_academy_bot
Тест «Подойдёт ли вам тестирование»:
https://quiz.quality-academy.ru
5000+ вопросов с собесов тестировщика — бот-тренажёр:
https://t.me/quality_academy_interview_bot
3 практические задачи и дорожная карта:
https://t.me/quality_academy_tasks_bot
Бесплатные тренажёры — SQL Arena, Playwright Arena, Python Arena:
SQL Arena · Playwright Arena · Python Arena