Локаторы в Playwright

Locator — один из ключевых концептов в Playwright. Он представляет собой способ поиска элементов на странице.

В этой главе представлены рекомендуемые в Playwright методы поиска: поиск элементов по роли, тексту, метке и placeholder.


Что такое Locator

Locator — это абстрактный объект, который Playwright использует для поиска элементов на странице.

В отличие от традиционныхdocument.querySelector()способами, Locator в Playwright обладаетавтоматическим ожиданием и автоматическими повторными попыткамивозможностями.

Когда содержимое страницы динамически меняется, Locator будет постоянно заново находить элементы, пока не найдёт подходящий элемент или не истечёт время ожидания.

Пример

// Создать Locator (поиск элемента не выполняется сразу)
const button = page.getByRole('button', { name: 'Submit' });

// При выполнении действия Playwright автоматически ждёт, пока кнопка появится и станет доступной для действий
await button.click();

Как работают Locator

Когда вы создаёте Locator, Playwright только записывает правило поиска.

Когда вы вызываете.click()、.fill()действия илиexpect(locator)утверждения, Locator фактически начинает искать элементы.

Если элемент не удаётся найти, Locator будет повторять попытки до истечения времени ожидания операции.


Поиск по роли: getByRole()

getByRole()является наиболее рекомендуемым методом поиска в Playwright.

Он используетроль доступности элемента (ARIA Role)для поиска элементов, что наиболее близко к тому, как их воспринимают пользователи.

Базовое использование

Пример

// Найти кнопку — по роли "button"
const submitBtn = page.getByRole('button', { name: 'Submit' });
await submitBtn.click();

// Найти ссылку — по роли "link"
const homeLink = page.getByRole('link', { name: 'Главная' });
await homeLink.click();

// Найти заголовок — по роли "heading"
const mainTitle = page.getByRole('heading', { name: 'Добро пожаловать в EXAMPLE' });

// Найти текстовое поле — по роли "textbox"
const searchBox = page.getByRole('textbox', { name: 'Поиск' });
await searchBox.fill('Playwright');

Распространённые роли ARIA

РольСоответствующие элементы HTMLПример использования
'button'<button>、role="button"getByRole('button', { name: '登录' })
'link'<a>getByRole('link', { name: '了解更多' })
'heading'<h1>~<h6>getByRole('heading', { name: 'EXAMPLE 教程' })
'textbox'<input type="text">、<textarea>getByRole('textbox', { name: '用户名' })
'checkbox'<input type="checkbox">getByRole('checkbox', { name: '记住我' })
'radio'<input type="radio">getByRole('radio', { name: '男' })
'combobox'<select>getByRole('combobox', { name: '城市' })
'img'<img>getByRole('img', { name: 'Logo' })
'list'<ul>、<ol>getByRole('list')
'listitem'<li>getByRole('listitem')
'navigation'<nav>getByRole('navigation')
'table'<table>getByRole('table')

Опция name

nameОпция используетдоступное имяэлемента, чтобы сузить область поиска.

Источники доступного имени включают: текстовое содержимое элемента,aria-labelатрибуты, связанные<label>и т. д.

Пример

// Сопоставление по тексту кнопки
page.getByRole('button', { name: 'Login' });

// Сопоставление по aria-label
page.getByRole('button', { name: 'Close dialog' });

// Сопоставление с помощью регулярного выражения
page.getByRole('link', { name: /EXAMPLE|rookie/ });

Параметры состояния

Кроме того,name,getByRoleон также поддерживает несколько параметров состояния:

Пример

// Найти отмеченный чекбокс
page.getByRole('checkbox', { checked: true });

// Найти неактивную кнопку
page.getByRole('button', { disabled: true });

// Найти раскрытое выпадающее меню
page.getByRole('button', { expanded: true });

// Найти выбранную опцию
page.getByRole('option', { selected: true });

// Объединить несколько состояний
page.getByRole('checkbox', { name: 'Agree to the terms', checked: false });

Поиск по тексту: getByText()

getByText()Потекстовому содержимому элементадля поиска.

Пример

// Точное совпадение текста
page.getByText('Welcome to EXAMPLE');

// Частичное совпадение (по умолчанию)
page.getByText('EXAMPLE');

// Принудительное точное совпадение
page.getByText('EXAMPLE', { exact: true });

// Совпадение по регулярному выражению
page.getByText(/EXAMPLE|rookie tutorial/);

getByTextОно сопоставляет полное текстовое содержимое элемента, поэтомуgetByText('EXAMPLE', { exact: true })оно будет сопоставлять только элементы, текстовое содержимое которых в точности равно "EXAMPLE".

По умолчанию, когда точное совпадение не используется, достаточно совпадения подстроки (например,getByText('EXAMPLE')оно сопоставит "Welcome to EXAMPLE").


Поиск по метке: getByLabel()

getByLabel()Используется для поиска<label>связанных элементов управления формы.

Пример

// Структура HTML:
// <label for="username">Username</label>
// <input id="username" type="text" />

// Найти поле ввода по тексту метки
await page.getByLabel('Username').fill('example_user');

// Структура HTML:
// <label>Password <input type="password" /></label>

// Вложенные метки также допустимы
await page.getByLabel('Password').fill('password123');

Он также поддерживает{ exact: true }опции точного совпадения.


Поиск по плейсхолдеру: getByPlaceholder()

getByPlaceholder()С помощьюplaceholderатрибут placeholder для поиска полей ввода.

Пример

// Структура HTML: <input placeholder="Please enter a search keyword" />
await page.getByPlaceholder('Please enter a search keyword').fill('Playwright');

// Структура HTML: <textarea placeholder="Tell us what you think..."></textarea>
await page.getByPlaceholder('Tell us what you think...').fill('The EXAMPLE tutorial is great!');

Выбор между getByLabel и getByPlaceholder

МетодСценарий примененияПриоритет
getByLabel()Когда есть элемент <label>Сначала используйте его
getByPlaceholder()Когда нет label, но есть placeholderВторой вариант

getByRole— самый рекомендуемый метод локализации в Playwright, потому что он имитирует, как пользователи определяют элементы по роли. Следующий —getByLabelиgetByPlaceholder. Рассматривайте его использование только когда нет семантических элементовgetByTestIdили CSS-селекторы.


getByAltText() для поиска изображений

getByAltText()С помощьюaltатрибута alt изображения для поиска<img>элемента <img>.

Пример

// HTML:<img src="logo.png" alt="EXAMPLE Logo" />
await expect(page.getByAltText('EXAMPLE Logo')).toBeVisible();

// Совпадение по регулярному выражению
await expect(page.getByAltText(/logo/i)).toBeVisible();

getByTitle() для поиска по атрибуту title

getByTitle()С помощьюtitleатрибута title элемента для поиска.

Пример

// HTML: <button title="Close current page">X</button>
await page.getByTitle('Close current page').click();

getByAltTextиgetByTitleИспользуется реже; только когда у элемента есть явный атрибут alt или title и его нельзя найти другими способами.


getByTestId() для поиска по Test ID

getByTestId()ДаРезервный вариант, черезdata-testidатрибут для поиска элемента.

Пример

// HTML: <button data-testid="submit-btn">Submit</button>
await page.getByTestId('submit-btn').click();

// Может содержать несколько совпадений (например, элементы списка)
const items = page.getByTestId('todo-item');
await expect(items).toHaveCount(3);

Настройка атрибута testId

Если в вашем проекте не используетсяdata-testid, вы можетеplaywright.config.tsнастройте имя атрибута в:

Пример

// Путь к файлу: playwright.config.ts
export default defineConfig({
  использовать: {
    // Используйте data-cy вместо data-testid (для миграции с Cypress)
    testIdAttribute: 'data-cy',
    // Или используйте id как testId
    // testIdAttribute: 'id',
  },
});

page.locator(): поиск по CSS и XPath

page.locator()Поддерживает CSS-селекторы и XPath, выступая в роли более гибкого запасного варианта.

Селекторы CSS

Пример

// По имени CSS-класса
await page.locator('.submit-btn').click();

// По ID
await page.locator('#username').fill('example_user');

// По атрибуту
await page.locator('[data-type="primary"]').click();

// По комбинации тега + класса
await page.locator('button.primary').click();

// По связи родитель — потомок
await page.locator('nav a').first().click();

// CSS-селектор, содержащий определённый текст
await page.locator('button:has-text("Submit")').click();

Поиск по XPath

Пример

// Поиск с помощью XPath
await page.locator('xpath=//button[@type="submit"]').click();

// Поиск по тексту
await page.locator('xpath=//h1[contains(text(), "EXAMPLE")]').click();

CSS-селекторы и XPath — крайняя мера; отдавайте предпочтение использованиюgetByRole、getByTextсемантические методы локализации. CSS-селекторы склонны к поломке из-за рефакторинга стилей, а XPath обладает плохой читаемостью и более низкой производительностью.


Цепочка Locator

Locator в Playwright поддерживает цепочки, позволяя дополнительно фильтровать текущие результаты сопоставления.

.first()、.last()、.nth()

Пример

// Получить первый соответствующий элемент списка
const firstItem = page.getByRole('listitem').first();

// Получить последний
const lastItem = page.getByRole('listitem').last();

// Получить второй (индекс начинается с 0)
const secondItem = page.getByRole('listitem').nth(1);

.filter() Фильтрация

Пример

// Фильтровать кнопки, содержащие определённый текст
page.getByRole('button').filter({ hasText: 'Сохранить' });

// Отфильтровать те, которые не содержат указанный текст
page.getByRole('listitem').filter({ hasNotText: 'Удалено' });

// Отфильтровать те, которые содержат указанный дочерний элемент
page.getByRole('listitem').filter({ has: page.getByRole('button') });

// Отфильтровать те, которые не содержат указанный дочерний элемент
page.getByRole('listitem').filter({ hasNot: page.getByTestId('badge') });

.locator() для поиска дочернего элемента

Пример

// Сначала найдите контейнер списка, затем найдите кнопки внутри него
const list = page.getByTestId('todo-list');
const deleteBtn = list.locator('button.delete');
await deleteBtn.click();

// Многоуровневая вложенность
page
  .getByRole('dialog')
  .locator('div.content')
  .locator('button')
  .filter({ hasText: 'Confirm' })
  .click();

.and() и .or() Логические комбинации (1.63+)

Пример

// Удовлетворить оба условия одновременно
const btn = page.getByRole('button')
  .и(page.getByText('Submit'));

// Удовлетворить любое из условий
const target = page.getByText('EXAMPLE')
  .или(page.getByTitle('EXAMPLE'));

Сводка по приоритету стратегий локаторов

Упорядочено от наиболее рекомендуемых к наименее рекомендуемым:

ПриоритетМетодУсловие использования
1 (Наиболее рекомендуемый)getByRole()Элемент имеет явную ARIA-роль
2getByLabel()У элемента формы есть связанная метка
3getByPlaceholder()Поле ввода имеет заполнитель
4getByText()Элемент имеет четкое текстовое содержимое
5getByAltText()У изображения есть атрибут alt
6getByTitle()У элемента есть атрибут title
7 (Резервный вариант)getByTestId()Когда не удаётся найти с помощью вышеуказанных методов
8 (последнее средство)locator()CSS-селекторы / XPath
Другие расширения