Избыточный XPath (Excessive XPath)

Для поиска элементов используются сложные XPath-выражения: абсолютные пути, позиционные индексы, конкатенация с contains() и normalize-space(), — там, где достаточно простого CSS-селектора.

Симптомы

  • Абсолютный XPath: /html/body/div[1]/div[2]/main/section/div[3]/input
  • Позиционные индексы: //ul/li[3]/div[2]/span
  • Сложные предикаты: //button[contains(@class,'btn') and normalize-space(text())='Сохранить']
  • XPath длиннее 80 символов
  • Локаторы скопированы из «Copy XPath» в DevTools без изменений

Причины возникновения

  • «Copy XPath» в браузере — самый простой способ получить локатор прямо сейчас
  • Нет атрибутов data-testid в вёрстке, поэтому выбирают XPath как «единственный вариант»
  • Непонимание возможностей CSS-селекторов (:nth-child, [attr^=val], ~, +)
  • Убеждение, что XPath мощнее и поэтому лучше

Почему это проблема

  • Хрупкость: любое изменение структуры DOM — добавление <div> обёртки — ломает абсолютный XPath
  • Медленная выборка: браузерный движок обрабатывает XPath медленнее CSS в 2–5 раз
  • Нечитаемость: /html/body/div[1]/div[3]/main/... невозможно понять без открытия DevTools
  • Ошибки при копировании: автоматически скопированный XPath почти всегда абсолютный и сразу устаревает

Решение

CSS-селектор по стабильному атрибуту, XPath — только там, где CSS не справляется:

// ❌
By.xpath("/html/body/div[1]/div[2]/main/section/div[3]/input")
By.xpath("//button[normalize-space(text())='Сохранить']")

// ✅
By.cssSelector("[data-testid='email-input']")
By.cssSelector("[data-testid='save-btn']")

// XPath уместен только для поиска по тексту без атрибутов
By.xpath("//label[text()='Обязательное поле']")