Локаторы в 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 даёт встроенные локаторы — их лучше использовать в первую очередь. Рекомендуемый порядок близок к тому, как страницу воспринимают пользователь и скринридеры:

  1. page.getByRole() — роль и доступное имя элемента.
  2. page.getByLabel() — подпись к полю формы.
  3. page.getByPlaceholder() — подсказка в поле (placeholder).
  4. page.getByText() — видимый текст (часто для неинтерактивных блоков).
  5. page.getByAltText() — альтернативный текст у картинок (alt).
  6. page.getByTitle() — атрибут title.
  7. 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, getByPlaceholder
  • getByText (в том числе exact и регулярные выражения)
  • getByAltText, getByTitle, getByTestId
  • при необходимости — page.locator() с CSS или XPath

Подобрать локатор можно в Playwright Codegen, а затем отредактировать его под стандарты проекта.

Хорошие локаторы — это фундамент надёжных тестов. Именно от них зависит, будут ли тесты стабильными или будут ломаться при каждом изменении интерфейса.


Ссылка из видео урока

Демо-страница с примерами локаторов из урока: Playwright Locators Demo.