воскресенье, 26 мая 2024 г.

Почему XPath лучше для поиска N-ого элемента, чем nth-child в CSS

В CSS есть псевдокласс :nth-child() — он находит один или более элементов, основываясь на их позиции среди группы соседних элементов. ©

Но у него есть ряд минусов:

  • не срабатывает в firefox (даже когда в хроме всё нормально);
  • срабатывает с оговорками — и поэтому xpath выражение для поиска будет лучше.
Давайте посмотрим на примере.

Создадим такой html-файл (можно сделать текстовый файлик и потом переименовать расширение в «.html»):

<html>
   <body>
          <div attr='1'>Блок 1</div>
  <p>Блок 1</div>
  <div attr='2'>Блок 2</div>
  <div attr='3'>Блок 3</div>
   </body>
</html>

Открываем файлик в хроме (это важно!). 

А теперь попробуем найти второй div. Попробуем через XPath:

//div[2]

Всё работает! Найдет один элемент, второй по счету div:


Теперь попробуем через CSS:


div:nth-child(2)

Увы, ничего не найдено:


Может быть, мы неправильно составили запрос? Хотя он сейчас несложный, это даже не «div[attr]», но проверим, уберем псевдокласс. И да, найдено 3 div элемента, второй тот, что нам и нужен:


То есть само условие верное, вот только псевдокласс почему-то не сработал. А смущает его тот факт, что между div-ами затесался элемент другого типа — <p>. Давайте сделаем html-файлик без этого "лишнего" элемента:

<html>
   <body>
          <div attr='1'>Блок 1</div>
  <div attr='2'>Блок 2</div>
  <div attr='3'>Блок 3</div>
   </body>
</html>

И снова поищем. XPath всё ещё отлично работает:

//div[2]

Элемент найден: 



Пробуем CSS

div:nth-child(2)

Вот, теперь сработало!


Если у вас не сработало, то вы, видимо, использовали другой браузер. Если открыть ту же страничку в Firefox и вставить CSS селектор, он подсветит нам подсказку уже без слова child


А если нажать Enter, активировав поиск — браузер вообще удалит псевдокласс и будет искать по селектору «div», хотя это не то, что нам нужно...


Так, ну с лисой (firefox) всё понятно, но почему в chrome так происходит? Ведь по сути своей селекторы css и xpath должны быть одинаковы, находить второй элемент среди соседей (под одним родителем).

Но хром ищет четко среди соседей. Если между соседями есть другой элемент (<p> в нашем случае) — всё, поиск не срабатывает. Более того, после <p> идет 2 div-элемента, они соседние, но среди них он тоже никого не находит.

А ведь если взглянуть на реальные HTML-страницы, то там целая толпа разных элементов! И далеко не всегда несколько одинаковых элементов будут идти подряд, без "чужеродных" соседей. 

Поэтому, если вам вдруг нужно обратиться к элементу по его номеру, лучше использовать XPath, он в этом плане понадежнее будет. Хотя глобально это плохая практика, особенно в автотестах — завязываться на дерево элементов, слишком уж оно ненадежно. Чуть изменили HTML, и вот уже куча упавших тестов!

Намного лучше привязываться к элементам по их атрибутам, желательно уникальным. Крайне желательно по id, он точно уникален... Но если такой возможности нет, то помните про эти особенности поиска child-ов =)

PS — статья написана в помощь студентам моего курса «CSS и Xpath: инструменты тестировщика».

Комментариев нет:

Отправить комментарий