На сайте hh.ru есть около 100 вакансий, где навык составления XPath важен для работодателя, также в интернетах полно материалов, вроде шпаргалок по составлению локаторов или ворк-шопов на ютубе. Как-то у меня спросили на собеседовании про то, какой из языков построения локаторов использовать лучше XPath vs CSS, и я ответил — лучше использовать тестовые аттрибуты, а если мы их используем то и использовать эти языки необязательно. Скорее всего такой ответ не устроил, но я ответил честно, т.к на предыдущем месте мы старались не использовать XPath для решения этой задачи.
Что это за зверь XPath
XPath (XML Path Language) — это язык путей, использующий синтаксис, отличный от XML, для обеспечения адресации различных частей XML-документа. Существует несколько стандартов данного языка, XPath 3.1 — опубликован в 2017 году (с поддержкой карт, массивов и JSON).
Селекторы XPath обычно называются «xpaths», и один xpath указывает пункт назначения от корня до желаемой конечной точки.
Операторы
-
Операторы и
/, //[...] -
Оператор объединения узлов,
| -
Булевы операторы
andиor, и функцияnot() -
Арифметические операторы
+,-,*,divиmod -
Операторы сравнения
=,!=,<,>,<=, >=
Функции
concat(), substring(), contains(), substring-before() и многое другое
Как это используется в тестах
В тестах мы вынуждены взаимодействовать с элементами HTML-страницы, а для этого нам нужны селекторы, чтобы обращаться к кнопкам, формам ввода, и другим элементам веб-интерфейса.
К примеру, у нас есть простой html-документ, и нам нужно обратиться к элементу а, находящемуся внутри div
<head> <title>Xpath & CSS</title> </head> <body> <h1>Hello World</h1> <p>some description text: </p> <div> <a class="link" href="https://helloworld.com">example link</a> </div> </body>
XPath-selector
/html/body/div[1]/p/a
CSS-selector
body > div > a
В тестах можем обращаться к этому локатору так
WebElement passwordByXPath = driver.findElement(By.xpath("/html/body/div[1]/p/a")); //или вот так WebElement passwordByXPath2 = driver.findElement(By.xpath("//a[contains(text(),"example link")]")); WebElement passwordByCSS = driver.findElement(By.css("body > div > a"));
Почему этим пользуемся и почему это не очень
Предположу что есть несколько причин, по которым этот подход еще используется:
-
исторически так сложилось
-
фронтенд не подготовлен для разработки автотестов (разработчики не предусмотрели тестовые локаторы-аттрибуты), выкручиваемся запросами c условиями
Если причиной является отсутствие уникальных тестовых аттрибутов и мы строим локатор, исходя из условий, скорее всего мы создаём нестабильный локатор, в не зависимости от того, насколько правильно он составлен.
Если мы завязались на название класса, то в любой момент он может измениться, например при пересборке веб-пака, а при изменении расположения или при оборачивании в новый tag — изменится путь и локатор будет невалидным.
Для тестов нам нужен стабильный, уникальный локатор, для этого правильным решением будет использовать тестовый аттрибут.
Преимущества использования тестовых аттрибутов
-
повышается стабильность, т.к не используются условия, функции
-
поддержка автоматической нумерации (для множественных объектов одного типа)
Из минусов — упрощается парсинг, если локатор доступен извне.
Поддержка тестовых атрибутов популярными фреймворками
|
фреймворк |
использование |
тестовые аттрибуты |
|
Playwrigth |
page.getByTestId(‘directions’).click(); |
data-pw |
|
Cypress.io |
cy.get(‘[data-cy=»submit»]’).click(); |
data-cy |
|
WebdriverIO |
$(‘button[data-testid=»submit»]’) |
data-testid |
Если внутри компании не принято решение о кастомном названии для тестовых аттрибутов, то можно использовать data-testid, которое поддерживается и рекомендуется большинством фреймворков для использования.
В Selenium из коробки отсутствует поддержка тест-аттрибутов, но можно выкрутиться вот так, а в дальнейшем, можно поддержать тестовое название внутри проекта
driver.findElement(By.css('[data-testid="entry-btn"]')
Как расставить тестовые локаторы
Самое простое решение — создать задачу на доработку фронтенда, и закинуть в беклог, а затем при планировании, взять её в спринт, согласно приоритету. Но, если есть свободное время и желание, можно самостоятельно локально поднять и поковырять фронтенд. Обратить внимание на компонент, если он существует.
Вариант первый (и самый простой) — добавление локатора напрямую
import React, { Component } from 'react'; import { Button } from "@material-ui/core"; function ViewIntro({ onOrder }) { return ( <Button variant=”contained” color=”primary” data-testid=”entry-btn” //просто добавляем аттрибут здесь и проверяем через консполь onClick={onOrder}> Order your ? </Button> ); }
А можно добавить data-testid в сам компонент и при использовании компонента передать значение dataTestId
const Component = ({ variant, color, dataTestId, onOrder }) => ( <Button variant={variant} color={color} data-testid={dataTestId} onClick={onOrder}> Order your ? </Button> );
Итог
-
строить локаторы, используя все возможности XPath/СSS — на основе названий классов, вложенности, и всего, что может в любой момент измениться — плохо
-
для автоматизации желательно использовать уникальные тестовые атрибуты
-
для тестовых атрибутов можно использовать название
data-testid, которое поддерживается несколькими фреймворками -
для обращения к этим тестовым локаторам можно использовать внутренние методы или обращаться через [data-testid=»имя локатора»] используя методы By.CSS/By.Xpath
ссылка на оригинал статьи https://habr.com/ru/articles/742088/
Добавить комментарий