Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Локаторы и взаимодействие с элементами
locators

Локаторы и взаимодействие с элементами

Стратегии поиска элементов, встроенные локаторы, цепочки, работа с текстом и атрибутами

Локаторы и взаимодействие с элементами

Локатор — это способ описать, какой элемент на странице вы хотите найти. Правильный локатор — основа стабильного теста. Хрупкий локатор — главная причина падающих тестов.

#1. Приоритет локаторов

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

ПриоритМетодКогда использовать
1get_by_role()Кнопки, ссылки, заголовки — любой элемент с ARIA-ролью
2get_by_text()Поиск по видимому тексту на странице
3get_by_label()Поля форм, связанные с <label>
4get_by_placeholder()Поля с атрибутом placeholder
5get_by_test_id()Кастомные элементы без семантики
6get_by_alt_text()Изображения с alt
7get_by_title()Элементы с атрибутом title
8locator()CSS-селекторы или XPath как крайний случай

Главное правило: используйте тот же способ, которым пользователь нашёл бы элемент на странице. Пользователь видит кнопку «Сохранить» — используйте get_by_role('button', name='Сохранить'), а не CSS-селектор .btn-primary.

#2. get_by_role — основной инструмент

get_by_role() ищет элементы по их ARIA-роли. Это самый устойчивый и семантичный способ.

# Кнопка с текстом await page.get_by_role('button', name='Сохранить').click() # Ссылка await page.get_by_role('link', name='Профиль').click() # Заголовок heading = page.get_by_role('heading', name='Настройки') # Чекбокс await page.get_by_role('checkbox', name='Запомнить меня').check()

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

# Точное совпадение page.get_by_role('button', name='Отправить') # Подстрока page.get_by_role('button', name='Отпр') # Регулярное выражение page.get_by_role('button', name=re.compile(r'отпр', re.IGNORECASE))

Важно: роль элемента определяется его HTML-тегом. <button> имеет роль button, <a href> — роль link, <h1> — роль heading. Если элементу задана role="..." явно — используется она.

#3. Strict Mode — защита от случайностей

Все локаторы в Playwright строгие. Если локатор находит более одного элемента, действие выбросит ошибку:

# На странице 5 кнопок 'Удалить' await page.get_by_role('button', name='Удалить').click() # Error: strict mode violation: locator resolved to 5 elements >

Это не баг — это защита. Тест не должен случайно кликнуть не туда.

Как исправить:

# 1. Сузить контекст card = page.locator('.product-card').first await card.get_by_role('button', name='Удалить').click() # 2. Использовать .first / .last await page.get_by_role('button', name='Удалить').first.click() # 3. Использовать .nth() await page.get_by_role('button', name='Удалить').nth(2).click() # 4. Добавить фильтрацию await page.get_by_role('button', name='Удалить').filter( has_text='Комментарий' ).click()

Рекомендация: используйте .first только если уверены, что порядок элементов стабилен. Лучше сузить контекст через родительский локатор.

#4. Цепочки локаторов

Локаторы можно комбинировать. Вызовите get_by_* или locator() на другом локаторе — поиск будет внутри найденного элемента:

# Найти карточку товара, внутри неё — кнопку card = page.locator('.product-card', has_text='Playwright в действии') await card.get_by_role('button', name='В корзину').click() # Найти таблицу, внутри неё — строку table = page.get_by_role('table') row = table.locator('tr', has_text='admin@example.com') await row.get_by_role('button', name='Редактировать').click()

Параметр has в locator() позволяет найти элемент, содержащий другой элемент:

# Найти article, который содержит кнопку 'Delete' article = page.locator('article', has=page.get_by_role('button', name='Delete'))

#5. get_by_text и get_by_label

get_by_text() ищет по видимому тексту:

# Найти элемент с текстом await page.get_by_text('Добро пожаловать!').click() # Регистр важен page.get_by_text('save') # не найдёт 'Save' # Регулярное выражение для нечувствительного поиска page.get_by_text(re.compile(r'save', re.IGNORECASE))

get_by_label() — для полей форм, связанных с <label>:

<label for="email">Email</label> <input id="email" type="email" />
await page.get_by_label('Email').fill('user@example.com')

#6. Универсальный locator()

page.locator() принимает CSS-селектор или XPath:

# CSS-селектор await page.locator('.btn.btn-primary').click() await page.locator('#main-nav > li').click() # XPath (когда CSS недостаточен) await page.locator('xpath=//div[contains(@class, "card")]').click()

CSS быстрее и читаемее XPath. Используйте XPath только когда нужна навигация по дереву:

# Найти родительский элемент parent = page.locator('xpath=//button[contains(., "Delete")]/ancestor::div') # Найти соседний элемент sibling = page.locator('xpath=//td[text()="Price"]/following-sibling::td')

#7. data-testid — стабильный, но без семантики

# Установка атрибута в HTML # <button data-testid="submit-btn">Отправить</button> # В Playwright await page.get_by_test_id('submit-btn').click()

data-testid не зависит от текста, CSS-классов и ARIA-ролей. Но он не отражает пользовательский опыт — реальный пользователь не видит этот атрибут.

Когда использовать data-testid:

  • Кастомные компоненты без ARIA-ролей
  • Динамический или локализованный текст
  • Элементы без уникальных атрибутов

Когда НЕ использовать:

  • Есть семантическая роль — используйте get_by_role()
  • Есть видимый текст — используйте get_by_text()

#8. Проверка состояния элементов

Playwright предоставляет встроенные assertion'ы через expect:

from playwright.sync_api import expect # Видимость expect(page.locator('#success-msg')).to_be_visible() # Текст expect(page.locator('h1')).to_have_text('Добро пожаловать!') # Атрибут expect(page.locator('input')).to_have_value('user@email.com') # CSS-класс expect(page.locator('.alert')).to_have_class('alert alert-success') # Количество элементов expect(page.locator('.item')).to_have_count(5) # Отрицание expect(page.locator('.error')).not_to_be_visible()

Каждый assertion автоматически ждёт выполнения условия до таймаута (по умолчанию 5 секунд). Не нужно time.sleep().

#9. Типичные ошибки

❌ Использование XPath для всего. XPath медленнее CSS и менее читаем. Используйте его только для навигации по дереву (родители, соседи).

❌ Игнорирование strict mode. .first — это быстрый фикс, но не решение. Сузьте контекст через родительский элемент.

❌ Локаторы по CSS-классам стилей. Класс .btn-primary может измениться при редизайне. Роль button не изменится.

✅ Правильный подход: get_by_role() → get_by_text() → get_by_label() → get_by_test_id() → locator().


#Упражнения

  1. Откройте https://demo.playwright.dev/todomvc/ через Codegen. Посмотрите, какие локаторы генерирует Playwright для добавления задачи.
  2. Напишите тест, который находит все чекбоксы на странице и проверяет, что ни один не отмечен.
  3. Используйте locator(..., has=...) для нахождения карточки, содержащей определённый текст, и кликните кнопку внутри неё.
  4. Попробуйте вызвать strict mode violation намеренно — найдите элемент, которого несколько на странице, и попытайтесь кликнуть.

#Что дальше?

Перейдите к работе с формами, чтобы освоить заполнение полей, чекбоксов, выпадающих списков и отправку форм.

Далее: Работа с формами