Буэнос приветос!
Отвлекитесь на секундочку от футбола и зацените, какой у нас тут релиз подъехал:
Selenide 7.17.0!
Наконец-то завезли локатор byRole!
- Локатор
byRole— поиск элемента по ARIA-роли - Ещё MCP-тулзов для вашего ИИ-раба!
- Скачивание нескольких файлов разом
- Типа типы SelenideAppiumElement
Selenide.cookies()— новый API для печенекelement()/elements()для котлин-разработчиков в Appium- Обновили Selenium с 4.44.0 на 4.46.0
Локатор 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
