Вышла Selenide 7.17.0

Вышла Selenide 7.17.0

Ролевые игры
12.07.26

Буэнос приветос!

Отвлекитесь на секундочку от футбола и зацените, какой у нас тут релиз подъехал:
Selenide 7.17.0!


Наконец-то завезли локатор byRole!


Локатор byRole — поиск элемента по ARIA-роли

В последнее время стали модными “accessibility locators”.

Мне доставляет мысль о том, что изначально их придумали, чтобы помочь слепым, слабовидяшим людям и т.д. А тестировщики такие: зашибись, пофиг на слепых, мы в тестах это заюзаем, чтобы айдишки не искать!

Зачастую в тестах удобно искать элементы по ролям. Типа, “найди кнопку” - без детализации, как эта кнопка внутри реализована.

Теперь метод byRole позволяет найти элемент по роли, либо по роли и тексту.

$(byRole("button")).click();
$(byRole("button", "Начать заправку")).click();
  • Причём роль ищется не только по явному атрибуту role="button", но и по неявной роли тэга — если у вас честный <button> или <a href="...">, Selenide тоже его найдёт. Список поддерживаемых ролей приличный: button, link, heading, checkbox, radio, textbox, searchbox, combobox, listbox, option, img, list, listitem, table, row, cell, navigation, dialog, form и ещё десяток.

  • А текст (т.е. accessibleName - “доступное имя элемента”) вычисляется в определённом порядке: сначала aria-labelledby, потом aria-label, потом связанный <label>, потом alt, потом текст внутри, и в конце — title.


ЭлементЛокатор
<button>Заправиться</button>$(byRole("button")).click();
<h1>Топлива нет<h2>,
<h6>АЗС не работает</h6>
$$(byRole("heading"))
<div role="alert">АИ-95 нет!</div>$(byRole("alert"))
<button aria-label="В канистры не заправляем">×</button>$(byRole("button", "В канистры не заправляем"))
<label>Жалоба
<input type="text"></label>
$(byRole("textbox", "Жалоба"))
<img src="qr.png"
alt="QR код для заправки"/>
$(byRole("img", "QR код для заправки"))


Поиск по тексту можно уточнить: “полный текст” или “подстрока”, “учитываем регистр” или “не учитываем”; “Пофиг на пробелы” или “учитываем пробелы” - так же, как в byPlaceholder, byTitle, byAltText:

import static com.codeborne.selenide.TextMatchOptions.*;
import static com.codeborne.selenide.Selectors.byRole;

$(byRole("img", "QR код", partialText()));
$(byRole("img", "qr код для ЗАПРАВКИ", fullText().caseInsensitive()));
$(byRole("img", "QR     код    для    заправки", partialText().ignoreWhitespaces()));

Это пока ещё не полная реализация W3C AccName-алгоритма (рекурсивный обход поддерева и скрытые элементы пока не завезли), но для 95% реальных страниц этого за глаза хватит.

См. issue 3359 и PR 3336.


Ещё MCP-тулзов для вашего ИИ-раба!

Помните, недавно мы завезли Selenide MCP server? Для начала там был ограниченный набор инструментов - попробовать-поиграться. Теперь навайбкодили ему ещё девять тулзов:

  • управление вкладками — browser_tab_list, browser_tab_select, browser_tab_new, browser_tab_close
  • browser_resize — ресайз окна браузера
  • browser_fill_form — заполнить сразу пачку полей одним вызовом
  • browser_wait_for — подождать текст, исчезновение текста, состояние элемента или просто время
  • browser_network_requests / browser_network_request — посмотреть, что там браузер вообще у бекенда просил (требует --proxy-enabled при старте)

Теперь ваш ИИ видит все вкладки на поле, отслеживает сетевые запросы и может даже заполнять формы одним пинком, не тыкая в каждое поле по отдельности.

> claude
> /mcp enable selenide

> Дорогой агент,
> ресайзни окно под мобилку и поищи, на каких заправках сегодня есть 95ый.
> Каждую заправку открывай в отдельной вкладке.
> Из всех респонсов выцепи куки с сессией и пробуй заново каждые 5 минут.
> Не отчаивайся!

См. PR 3335.


Скачивание нескольких файлов разом

В селениде давно уже есть метод $.download с кучей разных опций, чтобы тыкнуть по кнопке и скачать файл.

Да вот беда: иногда тык вызывает скачивание сразу нескольких файлов, и тест хочет проверить их все. И иногда скачать их по одному не вариант: например, если ссылка одноразовая.

Теперь есть метод $.downloadFiles, который тыкнет и вернёт сразу несколько файлов:

List<File> reports = $("#reports").downloadFiles(
    files(5).withExtension("zip")
);
assertThat(reports).hasSizeGreaterThanOrEqualTo(5);

Удобно, если один клик в интерфейсе триггерит скачивание сразу пачки файлов (отчётов, архивов, чего угодно), а вам надо проверить, что все они долетели и нужного формата.

См. issue 3261 и PR 3334.


SelenideAppiumElement теперь честно возвращает SelenideAppiumElement

Старая заноза в мобильных тестах, которой скоро уже два года: если вызвать find()/$()/$x() у SelenideAppiumElement, он раньше подсовывал вам обычный SelenideElement — и все специфичные мобильные методы становились недоступны. Как будто нападающего вызвали в сборную, а на поле выпустили полузащитника.

SelenideAppiumElement parent = SelenideAppium.$(By.xpath("//android.view.ViewGroup"));
SelenideAppiumElement child = SelenideAppium.$(By.xpath("//android.widget.TextView"));

  // Compilation error: child is `SelenideElement`, not `SelenideAppiumElement`.

Теперь find(), $(), $x(), findAll(), $$(), $$x() у SelenideAppiumElement возвращают именно Appium-элементы — по всей цепочке вызовов, а не только на первом уровне.

Спасибо Stanislav Vasenkov за то, что начал разгребать эту тему в PR 3362.

См. issue 2761 и PR 3373.


Selenide.cookies() — новый API для печенек

У Selenide давно есть красивый симметричный API для хранилищ:

sessionStorage().clear();
localStorage().clear();

А вот для печенек такой красоты не было — только старые корявые Selenide.clearBrowserCookies() и проверки через webdriver().shouldHave(cookie("name")).

Непорядок исправили — теперь куки живут в той же линейке:

cookies().clear();
cookies().add("mouse", "Jerry");

cookies().shouldHave(cookie("cat"));
cookies().shouldHave(cookie("mouse", "Jerry"));

Заодно объявили deprecated старые методы clearBrowserLocalStorage() и clearBrowserCookies() — пользуйтесь

  • localStorage().clear(),
  • sessionStorage().clear() и
  • cookies().clear().

Спасибо Stanislav Vasenkov за PR 3361.

См. PR 3375 и issue 3357.


element()/elements() для котлин-разработчиков в Appium

Если вы пишете Appium-тесты на Kotlin, то наверняка уже прокляли метод $ — в Kotlin его приходится экранировать бэктиками, и выглядит это как заклинание, а не как код:

Чтобы охладить полыхание котлиножёп, мы добавили алиасы element()/elements() - как в Selenide.

// было
private val button = SelenideAppium.`$`(CombinedBy.android(...).ios(...))

// стало
private val button = SelenideAppium.element(CombinedBy.android(...).ios(...))

Спасибо Gabriel Baldez за PR!

См. issue 3348 и PR 3350.


Обновили Selenium с 4.44.0 на 4.46.0

И подняли версию CDP с v148 до v150.

Заметные изменения для нас:

  • debug logs in Grid when downloading files - теперь при скачивании файла из Selenium Grid грид пишет дебаг-логи: какие файлы и где нашлись. Поможет тем бедолагам, у которых файлы из грида почему-то не скачиваются.
  • ElectronDriver - нативная поддержка приложенек на Electron!
  • publish selenium-devtools-latest artifact Теперь вместо того, чтобы везде в импортах прописывать версию CDP:
import org.openqa.selenium.devtools.v148.browser.Browser;

и вечно её обновлять по всем тестам, можно просто прописать “latest” и забыть навсегда:

import org.openqa.selenium.devtools.latest.browser.Browser;

См. PR 3347, PR 3374 и ченджлог селениума.


Не откладывайте,

обновляйтесь!

Скоро мы ещё больше навайбкодим…



Андрей Солнцев

ru.selenide.org

12.07.26