Другие локаторы
CSS-локаторы с расширениями Playwright, XPath, текстовые селекторы, псевдоклассы, позиционные селекторы и низкоуровневые строковые локаторы.
Обзор
Помимо высокоуровневых семантических локаторов (get_by_role, get_by_text и т.д.), Playwright поддерживает традиционные CSS-селекторы, XPath и текстовые селекторы, дополненные собственными мощными расширениями. Эти локаторы удобно использовать как строку в методе page.locator().
Рекомендация: Отдавайте предпочтение семантическим локаторам из раздела Локаторы (get_by_role и т.д.). CSS/XPath используйте, когда семантические методы недостаточно выразительны или когда вы работаете со сложными структурами DOM.
CSS-локаторы со встроенными расширениями Playwright
Playwright расширяет стандартные CSS-селекторы мощными псевдоклассами, которые значительно упрощают поиск элементов.
page.locator() — Базовый CSS-селектор
# Поиск по CSS-классу page.locator(".button-primary").click() # Поиск по ID page.locator("#submit-btn").click() # Поиск по атрибуту page.locator("[data-testid='login']").click() # Вложенные селекторы page.locator("div.container > form .field input").fill("test")
Псевдокласс :visible
Находит только видимые элементы. Исключает элементы с display: none, visibility: hidden, нулевыми размерами и opacity: 0.
# Только видимые кнопки page.locator("button:visible").click() # Видимые поля ввода visible_inputs = page.locator("input:visible").all() # Комбинация с другими селекторами page.locator(".dropdown-item:visible").first.click()
Псевдокласс :has-text()
Находит элементы, чей текст содержит указанную подстроку. Регистр не имеет значения.
# Кнопка, содержащая текст "Submit" page.locator("button:has-text('Submit')").click() # Любой элемент, содержащий "Total:" page.locator(":has-text('Total:')") # Пункт списка, содержащий "Важный" page.locator("li:has-text('Важный')")
Псевдокласс :text()
Находит элементы с точным текстовым содержимым. Поддерживает строки и регулярные выражения.
# Точное совпадение текста (регистр имеет значение) page.locator("button:text('Submit')").click() # Текст с регулярным выражением page.locator("div:text('Цена: \\d+ руб')") # Поиск по тексту с учётом пробелов page.locator("a:text('На главную')") # Элемент с точным текстом "Готово" page.locator("button:text('Готово')")
Псевдоклассы :text-is() и :text-matches()
:text-is() — точное совпадение текста (аналог :text()). :text-matches() — поиск по регулярному выражению.
# Точный текст (полное совпадение всего текстового содержимого) page.locator(":text-is('Полный текст элемента')") # Регулярное выражение (более гибкий синтаксис) page.locator(":text-matches('^Привет, \\w+$')") # Регекс с флагами page.locator(":text-matches('цена', 'i')") # i — ignore case
Псевдокласс :has()
Находит элементы, которые содержат определённых потомков. Аналог CSS-функции :has().
# Строка таблицы, содержащая ячейку с текстом "Активен" page.locator("tr:has(td:text('Активен'))") # Раздел, содержащий кнопку "Удалить" page.locator("div.card:has(button:text('Удалить'))") # Форма, содержащая поле с placeholder "Email" page.locator("form:has(input[placeholder='Email'])")
Псевдокласс :is()
Логическое ИЛИ для селекторов. Позволяет объединить несколько селекторов в один.
# Кнопка ИЛИ ссылка page.locator(":is(button, a[role='button'])") # Заголовки h1, h2, h3 page.locator(":is(h1, h2, h3):text('Введение')") # Поля разных типов page.locator(":is(input[type='email'], input[type='text'])")
Псевдокласс :nth-match()
Выбирает n-ное совпадение среди всех элементов, соответствующих селектору. Отличие от nth-child в том, что :nth-match() считает среди всех совпадений, а не среди siblings.
# Второй элемент с классом .item (среди всех .item на странице) page.locator(":nth-match(.item, 2)").click() # Четвёртая кнопка на странице page.locator(":nth-match(button, 4)") # Первый видимый элемент page.locator(":nth-match(:visible, 1)")
Позиционные псевдоклассы
Playwright предоставляет уникальные псевдоклассы для поиска элементов по их положению относительно других элементов на странице.
:right-of() и :left-of()
# Элемент справа от указанного page.locator("input:right-of(label:text('Имя'))") # Элемент слева от указанного page.locator("label:left-of(input[name='email'])")
:above() и :below()
# Элемент выше указанного page.locator("div:above(button:text('Submit'))") # Элемент ниже указанного page.locator("p:below(h1)")
:near()
# Элемент рядом (в радиусе 50 пикселей по умолчанию) page.locator("input:near(label:text('Email'))") # С кастомным радиусом page.locator("input:near(label:text('Email'), 100)")
Совет: Позиционные селекторы удобны для тестирования форм и макетов, где элементы расположены рядом друг с другом. Однако они могут быть медленнее обычных селекторов, так как Playwright вычисляет позиции всех элементов на странице.
XPath-локаторы
Playwright автоматически определяет XPath, если селектор начинается с // или ... Поддерживается полный синтаксис XPath.
# Базовый XPath (автоопределение по //) page.locator("//button[@id='submit']").click() # XPath с текстом page.locator("//button[text()='Submit']").click() # XPath с contains page.locator("//a[contains(@href, '/dashboard')]").click() # XPath по ancestors page.locator("..//div[@class='card']") # XPath с индексом page.locator("(//input[@type='text'])[2]").fill("test") # XPath с логическими операциями page.locator("//button[@type='submit' and @disabled]") # XPath с осью following-sibling page.locator("//label[text()='Email']/following-sibling::input")
Важно: XPath-селекторы работают во всех браузерах, но они менее устойчивы к изменениям DOM, чем семантические локаторы. Предпочитайте get_by_role или CSS с псевдоклассами Playwright.
Текстовые локаторы с префиксом text=
Playwright поддерживает текстовые селекторы через префикс text=. По умолчанию ищет подстроку.
# Поиск по тексту (подстрока) page.locator("text=Submit").click() # Точное совпадение текста page.locator("text=Submit", exact=True).click() # Поиск по тексту в конкретном элементе page.locator("button:has-text('Submit')").click() # text= с CSS-селектором page.locator("button.text='Нажми меня'")
Локаторы по атрибутам
# По data-testid (как get_by_test_id, но через CSS) page.locator("[data-testid='submit-button']").click() # По id (атрибут id) page.locator("id=submit-btn").click() # По data-test-id page.locator("[data-test-id='header']") # По data-test page.locator("[data-test='login-form']") # По произвольному атрибуту page.locator("[aria-label='Закрыть']").click() # По нескольким атрибутам page.locator("input[type='email'][required]")
nth= — n-ный элемент
# Третий элемент с классом .item (0-based) page.locator(".item >> nth=2").click() # Первый элемент (можно nth=0) page.locator(".item >> nth=0") # Последний элемент page.locator(".item >> nth=-1")
Цепочки селекторов через >> (legacy)
Синтаксис >> позволяет объединять селекторы в цепочку, где каждый последующий селектор ищется в контексте предыдущего. Этот синтаксис считается устаревшим — используйте метод locator.filter() или цепочки вызовов.
# Legacy-цепочка: найти div.card, внутри него кнопку (устаревший синтаксис) page.locator("div.card >> button:text('Подробнее')").click() # Более сложная цепочка page.locator("#sidebar >> .nav-item >> :text('Настройки')") # Современная альтернатива (рекомендуемая) page.locator("#sidebar").locator(".nav-item").filter(has_text="Настройки")
Примечание: Синтаксис >> всё ещё работает, но рекомендуется использовать вложенные локаторы через метод locator() или цепочки методов для лучшей читаемости.
Комбинирование подходов
Playwright позволяет гибко комбинировать разные типы локаторов в одном запросе.
# CSS + текст (псевдокласс :has-text) page.locator(".card:has-text('Регистрация')") # XPath + CSS (через .locator) card = page.locator("//div[@class='card']") card.locator("button.primary").click() # get_by_role + CSS-фильтр page.get_by_role("row").filter( has=page.locator("td.status-active") ) # get_by_test_id + текстовый фильтр page.get_by_test_id("user-list").filter(has_text="Администратор")
Практические примеры
Пример: поиск строки в сложной таблице
def test_table_row(page): page.goto("https://example.com/orders") # CSS + has: найти строку, содержащую определённый статус row = page.locator("tr:has(td:has-text('ORD-0042'))") # Проверить статус заказа status = row.locator("td:nth-child(3)") expect(status).to_have_text("Доставлено") # Кликнуть по кнопке в найденной строке row.locator("button:has-text('Детали')").click()
Пример: сложная форма с XPath
def test_complex_form(page): page.goto("https://example.com/complex-form") # XPath: найти input после label с текстом "Email" page.locator("//label[text()='Email']/following-sibling::input").fill("test@test.com") # Позиционный CSS: поле справа от label "Телефон" page.locator("input:right-of(label:text('Телефон'))").fill("+7-999-123-45-67") # :has() с :visible для поиска активного элемента page.locator("div.field:has(input:visible)").first.locator("input").fill("test")
Пример: фильтрация по видимости
def test_visible_items(page): page.goto("https://example.com/catalog") # Только видимые товары на странице visible_products = page.locator(".product-card:visible").all() # Проверить, что определённый товар видим target = page.locator(".product-card:visible:has-text('Товар #5')") expect(target).to_be_visible() # Кликнуть по первой видимой кнопке "Купить" page.locator("button:visible:has-text('Купить')").first.click()
Сравнение методов поиска элементов
| Метод / Селектор | Пример | Когда использовать |
|---|---|---|
get_by_role() | get_by_role("button", name="Submit") | Всегда в первую очередь |
get_by_text() | get_by_text("Submit") | Поиск по тексту элемента |
get_by_label() | get_by_label("Email") | Поля ввода с label |
get_by_test_id() | get_by_test_id("submit") | Тестовые идентификаторы |
| CSS | locator(".btn") | Сложные DOM-структуры |
| CSS + :has-text | locator("button:has-text('Submit')") | CSS + фильтр по тексту |
| CSS + :visible | locator("button:visible") | Только видимые элементы |
| CSS + :near() | locator("input:near(label)") | Поиск по расположению |
| XPath | locator("//button") | Сложные обходы DOM |
| text= | locator("text=Submit") | Простой поиск по тексту |
Заключение
Playwright предоставляет богатый арсенал низкоуровневых селекторов: от расширенных CSS с уникальными псевдоклассами до полноценного XPath. Используйте их в паре с семантическими локаторами для максимальной гибкости и точности поиска элементов. Помните о приоритете: сначала get_by_role и get_by_text, затем CSS с псевдоклассами, и только потом XPath.