Modern QA2026Стратегии локаторов
Join

Course13 Browser Automation with Playwright

Foundations · Chapter 13

Стратегии локаторов

Updated Jul 2026

Выбор правильной стратегии локаторов — одно из наиболее влиятельных решений в автоматизации тестирования. Хрупкие локаторы — главная причина бремени поддержки тестов. Playwright предоставляет пользователе-ориентированные локаторы, которые отражают то, как реальные пользователи находят элементы — и они значительно стабильнее CSS/XPath-селекторов, используемых в Selenium.

Иерархия локаторов

Playwright рекомендует локаторы в следующем порядке приоритета:

Приоритет Локатор Пример Почему
1 Роль getByRole('button', { name: 'Отправить' }) Отражает дерево доступности; устойчив к изменениям разметки
2 Текст getByText('Войти') Видимый пользователю; ломается только при изменении текста
3 Test ID getByTestId('login-form') Явный контракт между разработчиком и тестировщиком
4 Метка getByLabel('Электронная почта') Поля форм через связанный label
5 Placeholder getByPlaceholder('Введите email') Поля ввода без видимых меток
6 CSS/XPath page.locator('.btn-primary') Последний вариант для сложного обхода DOM

Ролевые локаторы (предпочтительные)

Ролевые локаторы используют дерево доступности, а не структуру DOM. Они находят элементы так, как это делает программа чтения с экрана — что означает устойчивость к рефакторингу HTML.

// Находит <button>, <input type="submit"> или любой элемент с role="button"
await page.getByRole('button', { name: 'Отправить' }).click();

// Находит элементы <a> или элементы с role="link"
await page.getByRole('link', { name: 'Регистрация' }).click();

// Находит <h1>–<h6> или элементы с role="heading"
await expect(page.getByRole('heading', { name: 'Панель управления' })).toBeVisible();

// Чекбоксы и радиокнопки
await page.getByRole('checkbox', { name: 'Запомнить меня' }).check();

Текстовые локаторы

// Точный текст
await page.getByText('С возвращением', { exact: true }).click();

// Частичное совпадение (по умолчанию)
await page.getByText('С возвращением').click();

// Регулярное выражение
await page.getByText(/добро пожаловать/i).click();

Локаторы Test ID

Когда ролевые и текстовые локаторы неприменимы (например, элементы без значимого текста или несколько идентичных элементов), test ID обеспечивают стабильный контракт.

// В приложении: <div data-testid="user-profile">...</div>
await page.getByTestId('user-profile').click();

// Настройка имени атрибута в playwright.config.ts:
// use: { testIdAttribute: 'data-qa' }

Локаторы по метке и placeholder

// Поиск input по связанному <label>
await page.getByLabel('Электронная почта').fill('user@example.com');

// Поиск input по тексту placeholder
await page.getByPlaceholder('Поиск товаров').fill('ноутбук');

CSS и XPath: когда они нужны

Playwright поддерживает CSS и XPath для случаев, когда семантические локаторы недостаточны:

// CSS-селектор
await page.locator('.product-card >> .price').textContent();

// XPath (с префиксом //)
await page.locator('//div[@class="sidebar"]//a').click();

Когда CSS/XPath допустимы

  • Сторонние виджеты без доступных ролей или test ID
  • Сложный обход DOM (родитель → потомок → сосед)
  • Унаследованные приложения, где добавление test ID невозможно

Когда избегать CSS/XPath

  • Позиционные селекторы вроде div:nth-child(3) — ломаются при изменении порядка разметки
  • Глубокая вложенность вроде #app > div > main > section > form > button — ломается при любом рефакторинге
  • Селекторы по классам, нацеленные на стилизацию (.btn-primary), а не на назначение

Сравнение стратегий локаторов

Стратегия Стабильность Читаемость Поддержка Лучше всего для
getByRole() Высокая Высокая Низкая Кнопки, ссылки, заголовки, элементы форм
getByText() Средняя Высокая Низкая Статический контент, метки
getByTestId() Высокая Средняя Низкая Динамический контент, сложные компоненты
getByLabel() Высокая Высокая Низкая Поля ввода форм
CSS-селектор Низкая–Средняя Низкая Высокая Сторонние виджеты, устаревшие приложения
XPath Низкая Низкая Высокая Сложный обход, поиск по тексту

Практический пример: форма входа

// ЛУЧШЕ ВСЕГО: ролевые локаторы
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Password').fill('secret');
await page.getByRole('button', { name: 'Sign in' }).click();

// ХОРОШО: test ID локаторы
await page.getByTestId('email-input').fill('user@example.com');
await page.getByTestId('password-input').fill('secret');
await page.getByTestId('login-button').click();

// ИЗБЕГАЙТЕ: CSS-селекторы, привязанные к реализации
await page.locator('input[type="email"]').fill('user@example.com');
await page.locator('input[type="password"]').fill('secret');
await page.locator('form.login-form button.btn-primary').click();

Ключевые выводы

  • Предпочитайте ролевые локаторы (getByRole) — они отражают поведение пользователя и выживают при рефакторинге
  • Используйте getByTestId, когда семантические локаторы недоступны — это создаёт стабильный тестовый контракт
  • Оставляйте CSS/XPath для сторонних виджетов и устаревших приложений
  • Избегайте позиционных селекторов, глубокой вложенности и селекторов по классам стилизации
  • Хорошая стратегия локаторов сокращает поддержку тестов на 60–80% по сравнению с тестами, насыщенными CSS/XPath