Локаторы в Playwright
Урок: Локаторы в Playwright
Введение
Представь, что ты пришёл в большой супермаркет и тебе нужно найти конкретный товар. Если ты скажешь: «дай мне что-то с полки», это будет слишком размыто. Но если ты скажешь: «мне нужна бутылка воды с надписью “Evian”», найти её станет гораздо проще.
В тестировании происходит то же самое. Когда ты работаешь со страницей, тебе нужно находить элементы: кнопки, поля, тексты. И от того, насколько точно ты их находишь, зависит стабильность теста.
Если ты выбираешь элемент «примерно», тесты начинают ломаться. Если точно — они работают стабильно.
В Playwright для этого используются локаторы.
Локаторы — это способ найти элемент на странице и взаимодействовать с ним. Но важно не просто «найти», а сделать это правильно.
Полный справочник по встроенным локаторам — в документации: Locators | Playwright.
Что такое локатор
Локатор — это объект, который указывает на элемент (или группу элементов) на странице.
Пример:
const button = page.getByText('Войти');
await button.click();
Разберём:
page.getByText('Войти')— находит элемент по тексту;- результат — это локатор;
click()— действие над этим элементом.
Важно: локатор — это не сам элемент, а способ его найти.
Playwright будет искать элемент в момент выполнения действия, а не заранее.
Почему локаторы лучше обычных селекторов
Можно работать и так:
await page.click('.btn');
Но это плохая практика.
Почему:
- класс может измениться;
- дизайнер поменяет верстку;
- тест сломается.
Локаторы в Playwright более «умные»:
await page.getByRole('button', { name: 'Войти' }).click();
Здесь:
- мы ищем кнопку;
- с текстом «Войти»;
- это ближе к реальному поведению пользователя.
Основные типы локаторов
Playwright даёт встроенные локаторы — их лучше использовать в первую очередь. Рекомендуемый порядок близок к тому, как страницу воспринимают пользователь и скринридеры:
page.getByRole()— роль и доступное имя элемента.page.getByLabel()— подпись к полю формы.page.getByPlaceholder()— подсказка в поле (placeholder).page.getByText()— видимый текст (часто для неинтерактивных блоков).page.getByAltText()— альтернативный текст у картинок (alt).page.getByTitle()— атрибутtitle.page.getByTestId()— явный контракт для тестов (data-testidили свой атрибут).
Если ни один из вариантов не подходит, остаётся page.locator() с CSS или XPath — это запасной путь, он сильнее привязан к вёрстке.
По роли (getByRole)
await page.getByRole('button', { name: 'Войти' }).click();
Здесь используется доступность (ARIA): роль элемента и его доступное имя (текст кнопки, связанный label и т.д.).
Частые роли: button, link, textbox, checkbox, heading, list, listitem, table, row, cell и другие — они соответствуют спецификации ARIA.
Имя можно задавать регулярным выражением (например, без учёта регистра):
await page.getByRole('button', { name: /войти/i }).click();
await expect(page.getByRole('heading', { name: 'Регистрация' })).toBeVisible();
await page.getByRole('checkbox', { name: 'Подписаться на рассылку' }).check();
Для интерактивных элементов (кнопка, ссылка, поле ввода) сначала пробуй getByRole, а не «голый» текст или CSS.
По подписи поля (getByLabel)
await page.getByLabel('Пароль').fill('1234');
Используется, когда у контрола есть связанный <label> или aria-label — как в настоящей форме.
По placeholder (getByPlaceholder)
await page.getByPlaceholder('Email').fill('test@mail.com');
Удобно, если у поля нет нормальной подписи, но есть placeholder.
По тексту (getByText)
await page.getByText('Успешно').click();
Точное совпадение строки:
await expect(page.getByText('Привет, Анна', { exact: true })).toBeVisible();
По регулярному выражению:
await expect(page.getByText(/привет, [а-яё]+/i)).toBeVisible();
Playwright нормализует пробелы (лишние пробелы и переносы строк сводит к одному пробелу), даже при exact: true.
Для неинтерактивных узлов (div, span, p) текст часто уместен. Для кнопок и полей предпочтительнее роль (getByRole).
По alt-тексту (getByAltText)
Для изображений и областей с атрибутом alt:
<img alt="Логотип компании" src="/logo.svg" />
await page.getByAltText('Логотип компании').click();
По атрибуту title (getByTitle)
<span title="Количество задач">25 задач</span>
await expect(page.getByTitle('Количество задач')).toHaveText('25 задач');
По test id (getByTestId)
await page.getByTestId('login-button').click();
В разметке обычно так:
<button data-testid="login-button">Войти</button>
Плюсы: стабильность, не зависит от текста и дизайна. Минус: это не то, что видит пользователь — для проверки UX лучше по возможности комбинировать с ролью или текстом.
По умолчанию ищется атрибут data-testid. Другой атрибут задаётся в конфиге, например data-pw:
// playwright.config.ts — фрагмент use
use: {
testIdAttribute: 'data-pw',
},
или через selectors.setTestIdAttribute() — см. документацию.
CSS и XPath (page.locator)
await page.locator('button.submit').click();
await page.locator('xpath=//button[@type="submit"]').click();
Префиксы css= и xpath= можно указывать явно; часто Playwright сам определяет тип селектора.
Длинные цепочки вроде #app > div > div:nth-child(3) > … ломаются от любой правки вёрстки. Используй такой подход только когда встроенных локаторов недостаточно.
Shadow DOM: большинство локаторов Playwright по умолчанию «проникают» в открытый shadow root так же, как в обычный DOM. Ограничения: поиск по XPath через shadow root не проходит; у closed shadow root доступ из теста недоступен. Подробнее — Locate in Shadow DOM.
Как работает локатор внутри
Когда ты пишешь:
await page.getByText('Войти').click();
Playwright:
- не сохраняет элемент сразу;
- ждёт, пока он появится;
- проверяет, что он доступен;
- выполняет действие.
Это называется «ленивое выполнение».
Поэтому локаторы:
- автоматически ждут элемент;
- уменьшают количество ошибок.
Комбинирование локаторов
Иногда нужно уточнить поиск.
await page.locator('.form').getByText('Войти').click();
Здесь:
- сначала ищем блок
.form; - внутри него ищем текст.
Это делает поиск точнее.
Те же методы (getByRole, getByLabel и др.) можно вызывать у уже найденного локатора и у page.frameLocator('#my-iframe') — чтобы искать внутри iframe, не смешивая контекст с основной страницей.
Фильтрация (filter)
Когда подходят несколько одинаковых элементов, сузь список по тексту или по вложенному локатору:
await page
.getByRole('listitem')
.filter({ hasText: 'Товар 2' })
.getByRole('button', { name: 'В корзину' })
.click();
С регулярным выражением: filter({ hasText: /Товар 2/ }).
Исключить по тексту: filter({ hasNotText: 'Нет в наличии' }).
Через опцию has: filter({ has: page.getByRole('heading', { name: 'Товар 2' }) }) — останутся только элементы, внутри которых есть такой заголовок (или другой вложенный локатор).
Подробнее — в том же разделе Filtering locators документации.
Работа с несколькими элементами
Если элементов несколько:
const items = page.getByRole('listitem');
Можно выбрать конкретный:
await items.nth(0).click();
Или перебрать:
const count = await items.count();
for (let i = 0; i < count; i++) {
console.log(await items.nth(i).textContent());
}
Локаторы позволяют удобно работать со списками.
Проверки через локаторы
Локаторы используются не только для действий, но и для проверок:
await expect(page.getByText('Успешно')).toBeVisible();
Playwright:
- ждёт появления текста;
- проверяет его наличие.
Это делает тесты стабильнее.
Частые ошибки при работе с локаторами
Ошибка 1 — слишком общий селектор:
await page.click('button');
Если кнопок несколько — тест станет нестабильным.
Ошибка 2 — зависимость от верстки:
await page.click('.container > div:nth-child(2)');
Малейшее изменение сломает тест.
Ошибка 3 — отсутствие уточнения:
await page.getByText('Отправить');
Если таких кнопок несколько — нужно уточнить.
Где это используется на практике
Локаторы — это основа всех тестов в Playwright.
Они используются:
- для кликов;
- для ввода данных;
- для проверок;
- для навигации по странице.
Если локаторы выбраны плохо — тесты ломаются. Если хорошо — тесты становятся стабильными и надёжными.
Итоговое понимание
Локаторы — это способ находить элементы на странице и взаимодействовать с ними.
Ключевая идея в том, что важно не просто «найти элемент», а сделать это:
- точно;
- стабильно;
- понятно.
Playwright даёт удобные и мощные инструменты для этого:
getByRole,getByLabel,getByPlaceholdergetByText(в том числеexactи регулярные выражения)getByAltText,getByTitle,getByTestId- при необходимости —
page.locator()с CSS или XPath
Подобрать локатор можно в Playwright Codegen, а затем отредактировать его под стандарты проекта.
Хорошие локаторы — это фундамент надёжных тестов. Именно от них зависит, будут ли тесты стабильными или будут ломаться при каждом изменении интерфейса.
Ссылка из видео урока
Демо-страница с примерами локаторов из урока: Playwright Locators Demo.