by.xpath()

by.xpath() — это один из локаторов в Protractor, позволяющий находить элементы на веб-странице с помощью XPath-выражений. XPath предоставляет гибкий и мощный способ навигации по DOM, особенно когда стандартные локаторы (by.id, by.css, by.className) не подходят.

Основы использования

Синтаксис вызова:

element(by.xpath('XPath выражение'));

Пример поиска кнопки с текстом «Войти»:

let loginButton = element(by.xpath("//button[text()='Войти']"));
  • //button — выбирает все элементы <button> в документе.
  • [text()='Войти'] — фильтрует элементы по точному тексту.

Для поиска элементов внутри контейнера:

let firstInputInForm = element(by.xpath("//form[@id='loginForm']//input[1]"));
  • //form[@id='loginForm'] — находит форму с атрибутом id="loginForm".
  • //input[1] — выбирает первый <input> внутри формы.

Относительные и абсолютные XPath

  • Абсолютный XPath начинается с / и описывает путь от корня документа:
element(by.xpath("/html/body/div[2]/form/input[1]"));
  • Относительный XPath начинается с // и ищет элементы в любом месте документа:
element(by.xpath("//input[@name='username']"));

Относительные XPath предпочтительнее, так как они менее хрупкие при изменении структуры страницы.

Использование условий

XPath позволяет строить сложные условия через логические операторы:

  • and — объединяет условия
  • or — одно из условий
  • contains() — проверяет наличие подстроки
  • starts-with() — проверяет начало строки

Примеры:

// Поиск элемента с классом 'btn' и текстом 'Отправить'
element(by.xpath("//button[contains(@class,'btn') and text()='Отправить']"));

// Поиск ссылки, начинающейся с 'https://'
element(by.xpath("//a[starts-with(@href,'https://')]"));

Поиск по индексам и позициям

XPath позволяет выбирать элементы по порядковому номеру:

// Третий элемент списка
element(by.xpath("(//ul[@id='menu']/li)[3]"));

Скобки важны: они ограничивают область действия индекса, иначе он применяется к последнему шагу XPath.

Работа с дочерними и соседними элементами

  • Дочерние элементы:
element(by.xpath("//div[@class='container']/child::span"));
  • Следующий сосед (following-sibling):
element(by.xpath("//label[text()='Email']/following-sibling::input"));
  • Предыдущий сосед (preceding-sibling):
element(by.xpath("//input[@name='email']/preceding-sibling::label"));
  • Родительский элемент (parent):
element(by.xpath("//input[@name='email']/parent::div"));

Массовый поиск элементов

Для получения списка элементов используется element.all(by.xpath()):

let menuItems = element.all(by.xpath("//ul[@id='menu']/li"));
menuItems.count().then(count => console.log(count));

Элементы можно фильтровать и применять итерации:

menuItems.each(item => {
    item.getText().then(text => console.log(text));
});

Советы по эффективному использованию

  1. Стараться избегать абсолютных путей. Изменения в DOM ломают тесты.
  2. Использовать contains() и starts-with(), чтобы делать XPath гибким к изменениям текста и атрибутов.
  3. При возможности комбинировать XPath с CSS локаторами, чтобы повысить читаемость и стабильность.
  4. Логические операторы позволяют объединять условия вместо создания множества локаторов.
  5. Использовать скобки при индексации, чтобы выборка элементов была точной.

Примеры практического применения

  • Нахождение кнопки по частичному тексту:
element(by.xpath("//button[contains(text(),'Продолжить')]"));
  • Поиск всех активных элементов меню:
element.all(by.xpath("//ul[@id='menu']/li[contains(@class,'active')]"));
  • Получение значения поля ввода рядом с лейблом:
element(by.xpath("//label[text()='Пароль']/following-sibling::input")).getAttribute('value');
  • Проверка наличия элемента с несколькими условиями:
element(by.xpath("//div[@class='alert' and contains(text(),'Ошибка')]")).isDisplayed();

by.xpath() в Protractor — универсальный инструмент для нахождения элементов на странице, особенно когда структура сложная или стандартные локаторы не подходят. Он позволяет строить гибкие и точные селекторы с учетом текста, атрибутов, позиции и иерархии элементов.