Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

Получение элементов по XPath в зависимости от их видимости

xpath
webdriver
java
Теги: #<Tag:0x00007f7b641aea00> #<Tag:0x00007f7b641ae870> #<Tag:0x00007f7b641ae6b8>

(Maksim Smolyakov) #1

Привет!
В работе внезапно застрял на одной головоломке. Помогите, пожалуйста, с поиском решения.

На странице есть блок для выбора категории. Пример DOM:

<div class="values">
    <ul class="topValues">
        <li>Категория 2</li>
        <li>Категория 4</li>
    </ul>
    <ul class="allValues g-hidden">
        <li>Категория 1</li>
        <li>Категория 2</li>
        <li>Категория 3</li>
        <li>Категория 4</li>
        <li>Категория 5</li>
    </ul>
    <a href="javascript:void(0)">Показать все</a>
</div>

По умолчанию при открытии страницы отображается список самых популярных категорий (первый ul), а второй ul список скрыт (классом g-hidden задается стиль display:none;). Если нажать на кнопку “Показать все”, то модель меняет вид:

<div class="values">
    <ul class="topValues" style="display:none;">
        <li>Категория 2</li>
        <li>Категория 4</li>
    </ul>
    <ul class="allValues g-hidden" style="display:block;">
        <li>Категория 1</li>
        <li>Категория 2</li>
        <li>Категория 3</li>
        <li>Категория 4</li>
        <li>Категория 5</li>
    </ul>
    <a href="javascript:void(0)">Скрыть</a>
</div>

Здесь с помощью атрибута style скрыт первый список ul и стал отображаться второй ul. Если теперь нажать кнопку “Скрыть”, то модель становится такой:

<div class="values">
    <ul class="topValues" style="display:block;">
        <li>Категория 2</li>
        <li>Категория 4</li>
    </ul>
    <ul class="allValues g-hidden" style="display:none;">
        <li>Категория 1</li>
        <li>Категория 2</li>
        <li>Категория 3</li>
        <li>Категория 4</li>
        <li>Категория 5</li>
    </ul>
    <a href="javascript:void(0)">Показать все</a>
</div>

Здесь атрибуты style у списков не исчезают, а лишь меняется их значение с none на block и наоборот.

Собственно, задача: XPath должен возвращать список элементов li всегда только того списка ul, который отображается в данный момент.

Как пытаюсь делать я, и какая возникла проблема:

List<WebElement> categoryList = driver.findElements(By.xpath("(//div[@class = 'values']/ul[not(contains(@style, 'none'))])[1]/li"));

Я опирался на то, что в начальном состоянии страницы у списков нет атрибута style, и решил, что с помощью not(contains()) будут выбраны оба ul, а [1] отберет только первый из них.
Также я полагал, что во втором случае not(contains()) исключит из выборки первый ul, а [1] не испортит выборку, т.к. всё равно будет отобран только один ul.
И, наконец, в третьем случае not(contains()) исключил бы второй ul, а [1] отберет оставшийся первый ul.

Но во всех трех случаях XPath возвращает только первый ul.

Вопрос: подскажите, что я делаю не так?


(Максим Малунов) #2

Xpath поддерживает перечисление локаторов емнип толе через | толи через ,


(Maksim Smolyakov) #3

Xpath поддерживает перечисление локаторов емнип толе через | толи через ,

Да, их можно перечислять, но как это поможет в данном случае?


(Максим Малунов) #4

А уберите плиз [1]


(vmaximv) #5

Вы что-то недоговариваете. С вашим html+xpath в ff+firepath во втором случае корректно выбирает второй блок.


(Maksim Smolyakov) #6

Вы что-то недоговариваете. С вашим html+xpath в ff+firepath во втором случае корректно выбирает второй блок.

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