Привет, Хабр! Сегодня хочется поговорить про XPath — мощный и гибкий инструмент для работы с веб-интерфейсами, который при этом почему-то остается не особенно популярным. Статей и мануалов по XPath очень много, и в этом посте я постараюсь рассказать, как мы применяем данный инструмент и почему считаем его более эффективным, чем другие подходы. Если вам знаком термин “селектор”, а тем более — если вы слышали про XPath, добро пожаловать под кат, там много полезного! В нашей команде работает целая группа инженеров-тестировщиков, которые ежедневно пишут автоматические end2end тесты для Selenium, а также создают огромное количество селекторов для них. С одной стороны, эта работа кажется несложной, но на практике к ней добавляются условия:  Писать код надо понятно и однотипно, потому что вы — не единственный инженер; Всегда надо предусматривать возможность оперативно переписать селектор; Для целого множества сайтов и версток необходимо обеспечить единый подход; Важно гарантировать однозначность каждого селектора;  И, наконец, каждый селектор должен быть максимальную информативным.  С учетом всех этих требований, работа инженера-тестировщика становится не такой уж простой, потому что выполнять задачи необходимо с определенным уровнем унификации. И именно поэтому мы полностью отдали предпочтение  XPath (XML Path Language) для написания селекторов.  Существует мнение (и оно довольно распространенное), что XPath это что-то громоздкое, со сложным синтаксисом. А некоторые также ставят под сомнение скорость поиска по XPath. Например, в одном из популярных курсов обучения по автоматизации тестирования с помощью Selenium, вы можете увидеть вот такие мысли:  Но наша практика показывает, что это не совсем так…а может быть даже совсем не так. Мы сделали ставку на XPath, потому что наша команда пишет автоматизированные тесты для заказчиков — фактически тысячи тестов. Чтобы увязать их с внедрением систем комплексного мониторинга, об этом я уже писал в прошлом посте. При таких объемах в условиях командной работы, стандартизация подходов является необходимостью, в том числе и для составления селекторов.  Начнем с минусов — то есть с того, почему XPath не любят.  Минус №1. Холивары о скорости работы селекторов на XPath и, например, CSS действительно не затихают. Мы ввязываться в них не будем и не станем утверждать, что тот или иной подход работает быстрее. Но при этом стоит отметить, что, учитывая общее время выполнения UI теста, разница в скорости работы селектора вообще не существенна. Минус №2. Многие считают селекторы XPath неинформативными. И это мнение обычно формируется после работы с плагинами для браузеров и стандартными средствами браузеров по поиску XPath. Действительно, селектор вида //div[1]/div[2]/ul/li/a не вызывает оптимизма. И мы, кстати, рекомендуем, не пользоваться подобными инструментами. Минус №3. При всей мощности XPath остаются вопросы, которые он не может решить. Например, на XPath не получится сделать селекторы к псевдоклассам, и содержимому Shadow DOM. Но, как говорится, каждому инструменту — своя сфера применения. С плюсами XPath все гораздо проще, ведь они очевидны и лежат на поверхности:  Плюс №1. Возможность поиска по тексту элемента. Первое, что мы встречаем в любом web-приложении — это текст. Текст в том числе располагается на кнопках, ссылках, выпадающих меню. И если свойства таких элементов могут измениться, то текст чаще всего останется прежним. Таким образом, даже изменения верстки никак не повлияют на XPath-селекторы. Как следствие, через XPath можно искать элементы с изменяемым текстом. Например, если нужно выбрать в календаре “позавчера”, можно прописать дату в явном виде в селекторе XPath. Также благодаря этой функции появляется возможность создавать селекторы для сложных таблиц. Например, это будет полезно, если вам необходимо выбрать ячейку в некой строке, причем строку и столбец можно найти только по тексту, так как номера строки и столбца могут меняться.  Плюс №2. Наличие встроенных функций, таких как contains(), starts-with(), sibling,  normalize-space() и прочих в совокупности с логическим операторами and, not , or позволяет создавать гибкие и универсальные локаторы. Все это очень полезно, когда речь заходит о реальной практике. Вот 3 примера, в которых преимущества XPath видны, так сказать, невооруженным взглядом: Пример №1. Селектор авторских постов в блоге Берем первый попавшийся html код. Давайте напишем селектор для  <div class="title second">Ходили купаться</div> Если делать это через CSS, то селектор будет выглядеть так: .second Но обратите внимание, что у post1 и post3, нет классов first и third! Чем руководствуются разработчики подобной верстки и какие у них мотивы — мы не узнаем никогда, но с определенной долей вероятности можем утверждать, что скоро класса second тоже не будет и значит наши тесты упадут. Сохраняя приверженность CSS, можно переписать селектор на: #post2 .title Да, такой селектор будет жить…но вполне возможно, что тоже не долго. Мы видим из кода, что речь идет о постах, авторских статьях или блоге. Но что будет, когда автор добавит очередной текст? Ведь логично, что новый пост должен быть первым, и тогда нумерация сдвинется, наш селектор #post2 .title будет ссылаться на пост с заголовком Как я провел лето. А неправильный селектор ещё хуже, чем нерабочий селектор, потому что узнаем мы о неправильном селекторе не сразу, если вообще узнаем. Тем временем, на XPath селектор может выглядеть следующим образом: //[normalize-space(.)='Ходили купаться' and contains(@class, 'title')] Выглядит громоздко. Но сколько плюсов:  Мы привязали селектор к самому тексту заголовка, который никто не вправе изменять, кроме автора. normalize-space(.) исключает проблему случайных/лишних пробелов. Верстальщик может без последствий добавлять/изменять список применяемых классов —  селектор останется рабочим. И последняя, но очень важная возможность: Представьте, что перед вами задача не написать тест и селекторы, а отредактировать селектор в существующем тесте..., на проде..., срочно, а ещё лучше вчера… Что проще найти и изменить, например в тысяче строк кода? Вариант 1:      Вариант 2: Для нас очевиден Вариант №2. Пример №2. Поиск по DOM-дереву Возможность поиска элементов по DOM-дереву вниз или вверх позволяет использовать XPath, чтобы добраться до самых глубоко спрятанных элементов страницы. Возьмем реальный код Это пример выпадающего меню на странице. Сначала нам надо кликнуть по ссылке (тег <a>), потом заполнить опцию (тег <input>), а затем выбрать ее (тег <li>). Таких меню на странице может быть несколько. Посмотрите как изящно и однозначно выглядят селекторы XPath в таком случае:  Клик по меню:  //select[@name=’field[new_object_assignment_key]’]/..//a Ввод опции:  //select[@name=’field[new_object_assignment_key]’]/..//input Выбор опции: //select[@name='field[new_object_assignment_key]']/..//li[normalize-space(.)='«Тропа» здоровья'] Здесь мы оттолкнулись от существующего поля name, ушли вверх по дереву, а затем вернулись к нужным тегам. Замените значение поля name и название опции на переменные и селекторы будут универсальны для любого из меню на странице. Пример №3. XPath справляется там, где другие не справляются Таблицы довольно часто встречаются на web страницах. При этом нередко речь заходит о множестве таблиц на одной странице, а каждая из них может содержать сотни строк. Ниже мы приводим только часть (упрощенного) кода.  Как сделать селектор к ссылке ячейки “На согласовании”? Классы остались где-то наверху, теги все одинаковые, атрибутов нет от слова “совсем”…XPath тут справляется “на ура”, благодаря своим функциям и полнотекстовому поиску:  //[contains(.,'Сделки')]//td[contains(.,'На согласовании')]//a Такой селектор легко читается, а значит в него легко внести правки, если это необходимо. Кстати, тут XPath демонстрирует дополнительную гибкость. Если в примере выше “На согласовании” будет целое множество “Закупок”, то мы сможем добавить номер закупки как ещё одно условие. Например, вот так:  //*[contains(.,'Сделки')]//tr[contains(.,'Закупка 4')]//td[contains(.,'На согласовании')]//a Фактически XPath похож на язык программирования: хороший XPath-селектор легко читаем, по нему сразу ясно, о каком элементе идет речь.  Такое положение дел добавляет удобства в работе с XPath, увеличивает скорость выполнения типовых задач и, как следствие, сокращает время разработки. К тому же XPath позволяет осуществлять поиск вообще по любому атрибуту элемента. Разработчики зачастую добавляют свои атрибуты ко множеству тегов. Через CSS и стандартными методами фреймворков тестирования их не найти. XPath здесь тоже выручает, например, вот так можно сделать селектор по кастомному атрибуту: //input[@data-input-type='SNILS’] Подводя итог, скажу, что мы выбрали для себя XPath как наиболее удобное средство для создания селекторов и рады поделиться своим опытом как с заказчиками, так и с коллегами “по цеху”. Но не любой селектор, написанный на XPath однозначно хорош. В следующем посте я подробно расскажу о “плохих” и “хороших” практиках использования XPath, которые мы определили, набивая свои собственные шишки. А сейчас прошу всех заинтересованных поучаствовать в нашем опросе. Руководитель отдела внедрения систем мониторинга