Playwright Python — справочник На главный сайт

Обзор

Помимо высокоуровневых семантических локаторов (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")Тестовые идентификаторы
CSSlocator(".btn")Сложные DOM-структуры
CSS + :has-textlocator("button:has-text('Submit')")CSS + фильтр по тексту
CSS + :visiblelocator("button:visible")Только видимые элементы
CSS + :near()locator("input:near(label)")Поиск по расположению
XPathlocator("//button")Сложные обходы DOM
text=locator("text=Submit")Простой поиск по тексту

Заключение

Playwright предоставляет богатый арсенал низкоуровневых селекторов: от расширенных CSS с уникальными псевдоклассами до полноценного XPath. Используйте их в паре с семантическими локаторами для максимальной гибкости и точности поиска элементов. Помните о приоритете: сначала get_by_role и get_by_text, затем CSS с псевдоклассами, и только потом XPath.