Для написания автотестов используются XPath и CSS-селекторы. Они помогают найти элемент на странице, чтобы потом с ним как-то взаимодействовать (кликнуть, ввести текст, или что-то другое).
Я видела много статей о том, что это вообще такое, но мне очень не хватало шпаргалки по разным селекторам, причем в разрезе «Вот он в CSS и он же в XPath» для сравнения.
А мне такое для студентов надо. Поэтому решила сделать сама. Вдохновлялась страничкой «Xpath cheatsheet», но сделала на свой вкус — под автоматизацию, а не XPath вообще. И с комментариями, с ними удобнее.
Пишите, если где-то накосячила. Хотя я все селекторы проверяла на тестовых страницах, но мало ли… И надеюсь, вам такая шпаргалка тоже пригодится! =)
Содержание
Поиск конкретного элемента
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)
BAD-_-BOY
28.05.2024 05:14Отличная статья, спасибо. нашёл несколько ошибок в таблице "Поиск потомков (обход дерева вниз)":
для xpath "Дети с типом div" написано, "//body/child::*", а должно быть "//body/child::div"
для "Только потомки div" указано "descendant::a"
Molechka Автор
28.05.2024 05:14Ох, да, спасибо, исправила! А то проверяла я на "a", так и вставила, а в статье див в примерах)
mobi
Аналогом
//div[2]
являетсяdiv:nth-of-type(2)
, а неdiv:nth-child(2)
. Возможно, поэтому у вас "в хроме тоже может глючить". Да и в Firefox я не припомню проблем сquerySelector
для селектора с псевдоклассом (кроме бага с использованием псевдоклассов внутри:has
), может разве что в совсем ранних версиях что-то такое и было.mobi
Еще замечу пропущенные
>
при конвертации/
из 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()]
Molechka Автор
Спасибо, добавила!
Molechka Автор
О, спасибо, исправила. Но в firefox буквально на этой неделе сравнивала разные селекторы и он часть не считывает, которые работают в хроме