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

Я видела много статей о том, что это вообще такое, но мне очень не хватало шпаргалки по разным селекторам, причем в разрезе «Вот он в CSS и он же в XPath» для сравнения. 

А мне такое для студентов надо. Поэтому решила сделать сама. Вдохновлялась страничкой «Xpath cheatsheet», но сделала на свой вкус — под автоматизацию, а не XPath вообще. И с комментариями, с ними удобнее. 

Пишите, если где-то накосячила. Хотя я все селекторы проверяла на тестовых страницах, но мало ли… И надеюсь, вам такая шпаргалка тоже пригодится! =)

Содержание

  1. Поиск конкретного элемента

  2. Поиск по атрибутам

  3. Поиск по тексту элемента

  4. Поиск по позиции элемента

  5. Поиск потомков (обход дерева вниз)

  6. Поиск предков (обход дерева вверх)

  7. Поиск соседей

  8. Поиск по комментариям

Поиск конкретного элемента

CSS

XPath

Комментарий

*

//*

Найти любой элемент (используется обычно как часть более сложного запроса)

div

//div

Найти элемент div

div:nth-of-type(2)

//div[2]

Найти 2-ой элемент div под общим родителем (вместо 2 может быть любая цифра) 

В CSS используется псевдокласс, в firefox он не срабатывает, в хроме тоже может глючить. В этом сценарии xpath лучше

Поиск по атрибутам

CSS

XPath

Комментарий

Любой элемент

.form-control

//*[@class="form-control"]

Элемент с классом form-control

#sample_1

//*[@id="sample_1"]

Элемент с атрибутом id = sample_1

[id]

//*[@id]

Элемент с атрибутом id, значение у атрибута любое

Конкретный элемент (в примере это div, но искать можно любой)

div.form-control

//div[@class="form-control"]

Именно div элемент с атрибутом class=form-control

div#sample_1

//div[@id="sample_1"]

Именно div элемент с атрибутом id = sample_1

div[id]

//div[@id]

Именно div элемент с атрибутом id 

div[attr]:nth-child(2)

//div[2][@attr]

2-ой элемент div с атрибутом attr под общим родителем

XPath найдет такой div, даже если между 2-мя div-ами будет что-то ещё. А вот CSS нет (см тут подробнее), только если подряд идут. Поэтому с потомками лучше через XPath

h1:not([id])

//h1[not(@id)]

Элемент h1, у которого нет атрибута id

a:is([name],[href])

//a[@name or @href]

Элемент а, у которого есть или атрибут name, или href, или оба

Сравнения по тексту атрибута (в примере это class, но атрибут может быть любым)

Есть атрибут class, проверяем текст в нем. Допустим, у нас есть такие элементы:

1. class = “test-1 test-3 test-2”

2. class = “test-1”

[class="test-1"]

[class='test-1']

//*[@class="test-1"]

//*[@class='test-1']

Текст четко равен "test-1" (тип кавычек не важен)

Найдет элемент 2, но не найдет элемент 1. 

[class~="test-3"]

//*[contains(@class, 'test-3')]

Текст атрибута состоит из нескольких слов, разделенных пробелами, одно из них — искомое.

В XPath такого нет, поэтому там просто contains — в тексте есть искомое значение

Найдет элемент 1

[class|="test"]

//*[contains(@class, 'test')]

Полное соответствие или атрибут начинается как указано и потом идет "-" (U+002D)

Найдет и элемент 1, и элемент 2

[class^="te"]

//*[starts-with(@class, 'te')]

//*[substring-after(@class, 'te')]

Начинается на …

Найдет и элемент 1, и элемент 2.

В Xpath 2 варианта записи, substring-after ищет текст, который идет после указанного, то есть указанный должен быть.

В CSS запись как в регулярных выражениях

[class$="2"]

//*[substring-before(@class, '2')]

Заканчивается на …

Найдет только элемент 1

В Xpath ещё должно быть выражение «ends-with», но оно не работает ?

[class*="st"]

//*[contains(@class, 'st')]

Содержит искомый текст (хотя бы 1 вхождение, неважно где, начало, конец или середина строки)

Найдет и элемент 1, и элемент 2.

Поиск по тексту элемента

CSS

XPath

Комментарий

-

//a/text()[. ="Ссылка"]

Текст внутри тегов <a> равен «Ссылка»

-

//a[contains(text(),'Ссылка')]

Текст cодержит «Ссылка» (может быть частью слова)

-

//*[starts-with(text(), 'Ссы')]

//*[substring-after(text(), 'Ссы')]

Начинается на …

-

//*[substring-before(text(), 'ка')]

Заканчивается на … (одно из слов, «Ссылка 1» тоже найдет)

-

//a[string-length(text()) > 6]

Длина текста тега <a> больше 6 символов (оператор может быть любым)

Поиск по позиции элемента

CSS

XPath

Комментарий

div:first-child

//*[1][name()="div"]

Первый div

div:last-child

//*[last()][name()="div"]

Последний div

body div:last-child

//body/div[last()]

Последний div внутри body

div:nth-last-of-type(2)

//body/div[last()-1]

Предпоследний div

div:nth-of-type(-3+2)

//body/div[position()<3]

Все div от 1 до 3 (не включительно, оператор может быть любым)

div:nth-of-type(2)

//body/div[position()=2]

Конкретная позиция (2-ая, но цифра может быть любой)

CSS работает с оговорками (см тут подробнее)

div:first-of-type

//div[1]

Первый элемент div

div#id:first-of-type

//div[1][@id]

Первый элемент div с атрибутом id

div[attr]:first-of-type

//div[1][@attr]

Первый элемент div с атрибутом attr

div:last-of-type

//div[last()]

Последний элемент div

Поиск потомков (обход дерева вниз)

CSS

XPath

Комментарий

div h2

//div//h2

h2, дочерний к div (на любом уровне вложенности, div - test - h2 найдет)

div > h2

//div/h2

Прямой потомок (1 уровень вложенности, div - test - h2 уже не найдет)

div > div > h2

//div/div/h2

Спускаемся по дереву, ищем div, внутри ещё div, внутри h2 (прямые потомки везде)

body > *

//body/child::*

Дети (1 уровень вложенности) любые

body > div

//body/child::div

Дети с типом div

body *

//body/descendant::*

Все потомки с типом div (любой уровень вложенности: дети, внуки…)

body div

//body/descendant::div

Только потомки div

-

//body/descendant-or-self::* 

Сам body и все потомки

-

//head/following::*

Все, что после head идет

-

//head/following::a

Все элементы a, которые идут после head

Поиск предков (обход дерева вверх)

CSS не умеет идти по дереву наверх, тут только XPath сработает

CSS

XPath

Комментарий

-

//a/ancestor::*

Все предки ссылки - родитель, дед, прадед, на все уровни вверх смотрим (<a> — это ссылка в HTML)

-

//a/ancestor::div

Только предок div

-

//a/ancestor-or-self::*

Сама ссылка + предки

-

//a/ancestor-or-self::div

Сама ссылка + предки div

-

//a/ancestor-or-self::a

Сама ссылка + предки такого же типа (a)

*:has(> a)

//a/parent::*

Родитель ссылки (строго 1 уровень наверх)

-

//p/preceding::*

Все узлы до текущего, кроме непосредственного родителя (но зато есть те, кто идет до родителя + предки)

-

//p/preceding-sibling::*

Все узлы-соседи до текущего узла (под одним родителем)

Поиск соседей

CSS

XPath

Комментарий

h1 ~ h2 

//h1/following-sibling::h2

Все элементы h2, которые находятся после элемента h1 внутри одного родителя

h1 + h2

//h1/following-sibling::h2[1]

Только первый элемент h2, соседний к h1 справа (находится после)

В XPath можно выбрать не только первый, но и второй, третий, даже last()

h1 ~ h2:last-of-type

//h1/following-sibling::h2[last()]

Последний элемент, который находится после элемента h1 внутри одного родителя

Поиск по комментариям

CSS

XPath

Комментарий

-

//comment()

Все комментарии

-

//comment()[. = 'comment']

Комментарий с конкретным текстом

-

//comment()[. = ' comment ']/parent::*

Родительский элемент комментария

PS — больше полезных статей ищите в моем блоге по метке «полезное». А полезные видео — на моем youtube-канале   

Комментарии (6)


  1. mobi
    28.05.2024 05:14
    +4

    Аналогом //div[2] является div:nth-of-type(2), а не div:nth-child(2). Возможно, поэтому у вас "в хроме тоже может глючить". Да и в Firefox я не припомню проблем с querySelector для селектора с псевдоклассом (кроме бага с использованием псевдоклассов внутри :has), может разве что в совсем ранних версиях что-то такое и было.


    1. mobi
      28.05.2024 05:14
      +1

      Еще замечу пропущенные > при конвертации / из XPath в CSS.

      Плюс, некоторые из "отсутствующих" CSS селекторов на самом деле существуют, например:
      a:is([name],[href])//a[@name or @href]
      body > div:nth-last-of-type(2)//body/div[last()-1]
      body > div:nth-of-type(-n+2)//body/div[position()<3]
      *:has(> a)//a/parent::*
      h1 ~ h2:last-of-type//h1/following-sibling::h2[last()]


      1. Molechka Автор
        28.05.2024 05:14

        Спасибо, добавила!


    1. Molechka Автор
      28.05.2024 05:14

      О, спасибо, исправила. Но в firefox буквально на этой неделе сравнивала разные селекторы и он часть не считывает, которые работают в хроме


  1. BAD-_-BOY
    28.05.2024 05:14

    Отличная статья, спасибо. нашёл несколько ошибок в таблице "Поиск потомков (обход дерева вниз)":

    для xpath "Дети с типом div" написано, "//body/child::*", а должно быть "//body/child::div"

    для "Только потомки div" указано "descendant::a"


    1. Molechka Автор
      28.05.2024 05:14

      Ох, да, спасибо, исправила! А то проверяла я на "a", так и вставила, а в статье див в примерах)