Разделы портала

Онлайн-тренинги

.
Как отказаться от XPath/CSS локаторов в тестах
20.07.2023 00:00

Автор: Куликов Дмитрий 

На сайте 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

Проверить локатор можно через консоль браузера $$(''); для CSS, $x(''); для XPath

Проверить локатор можно через консоль браузера $$(''); для CSS, $x(''); для XPath


В тестах можем обращаться к этому локатору так

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
data-testid

Cypress.io

cy.get('[data-cy="submit"]').click();

data-cy
data-test
data-testid

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, которое поддерживается несколькими фреймворками

  • для обращения к этим тестовым локаторам можно использовать внутренние методы или реализовать свой собственный, а сами локаторы поместить в привычный PageObject класс

Спасибо за прочтение

Обсудить в форуме