Автор: Ольга Назина (Киселёва)
Для написания автотестов используются 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::* | Родительский элемент комментария |
|