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

I don't know how in a better way to check that my List<WebElement> has more then one item in a loop (counting by time is not prefer)

java
Теги: #<Tag:0x00007f7b61f706c8>

(Oleksii Ihnatiuk) #1

У меня реализовано ожидание List по presenceOfAllElementsLocatedBy условию. Метод реализован в BaseClass и выглядит:

protected List<WebElement> waitForElements(By locator, WaitConditionForWebElements condition) {

       return  elements = wait.until(condition.getType().apply(locator));
}

Я столкнулся с проблемой, что при переходе на новую страницу нужный мне массив не успевает подгрузиться весь: после перехода в этом массиве лишь один элемент, когда проходит пару секунд, то все находится корректно. Я преобразовал этот метод добавив проверку на размер массива и счетчик (который странный как по мне, но рабочий). Метод срабатывает корректно, но я знаю :slight_smile: , что можно сделать явно легче/лучше. Привязывать счетчит жестко к времени sleep не хотелось бы. Идеально как я считаю, была бы реализация как в дефолтном ожидании (условие, общее время ожидания) .Мой метод сейчас выглядит так:

protected List<WebElement> waitForElements(By locator, WaitConditionForWebElements condition){

    List<WebElement> elements;
    int counter = 1;
    do {
         elements = wait.until(condition.getType().apply(locator));
         //System.out.println(elements.size());
        counter++;
    } while ((elements.size() == 1) && (counter < 30));
    return elements;
}

Буду рад любому совету. Спасибо


(Yaroslav Pernerovskyy) #2

А что вы пытаетесь вытащить в массив? Учитывая, что вы переходите на новую страницу, это явно не вебелементы, скорее всего какие то данные? Если так, то это лучше делать с помощью джаваскрипта. Надежнее и быстрее.

Попробуйте например так, как в статье:


(Oleksii Ihnatiuk) #3

Хм, у меня указан дженерик тип в методе, это <WebElement>. Давайте я немного проясню флоу.
Я делаю поиск по CSS. Поиск находит n-ое количество элементов, за это и отвечает метод waitForElements. В дальнейшем я фильтрую этот массив элементво и нахожу тот, который мне нужен.


(Maxim Zaitsev) #4

Ага, а по количеству циклов самое-то! Не тож самое в итоге получается?

По сути, нужна готовая ожидалка по условию. Наверняка, в java должна быть.
Схема такая:

function wait(condition, timeout) { …}

wait( elements.size() > 1, timeout)

Требования к ожидалке:

  1. проверяет переданное условие на True в течение времени заданного timeout.
  2. Частоту проверок можно настроить
  3. Выбрасывает исключение по истечению таймаута.

(Сергей Кузьмин) #5

Oleksii Ihnatiuk - посмотрите на упражнения в проекте
https://github.com/sergueik/selenium_java/blob/master/java8/src/test/java/com/mycompany/app/SuvianTest.java


(Oleksii Ihnatiuk) #6

По кол-ву циклов не самое-то, но и не тоже самое. То, что в java есть нужная имплементация я уверен :slight_smile: . Спасибо, что попробовали помочь.


(Oleksii Ihnatiuk) #7

Обязательно сегодня гляну и отпишусь, большое спасибо за помощь.


(Сергей Кузьмин) #8

like it => star it


(Oleksii Ihnatiuk) #9

2186 строк кода…
в коде есть достаточно много мест, которые мне не нравятся. Пока я честно посмотрел четверть и не нашел того что мне нужно.


(Сергей Кузьмин) #10

так это ж упражнение ( недотянул до 3000 - будет исправлено! )- если можно сформулируйте на псевдокоде что надо получить и напишем нужный ExpectedCondition


(Sergey Korol) #11

Метод until принимает Function / Predicate на вход. Т.е. технически вы можете подсунуть туда абсолютно любую кастомную ожидалку. Пример можно подсмотреть в самом ExpectedConditions.

Применительно к вашему коду, вот так можно ждать, пока в списке не появится хотя бы 1 элемент.

isNotEmpty(locator -> driver -> ofNullable(driver)
                          .map(d -> d.findElements(locator))
                          .filter(list -> !list.isEmpty())
                          .orElse(null));
...
elements = waitFor(locator, isNotEmpty);

(Oleksii Ihnatiuk) #12

Дело в том, что:

  1. Мне нужно ожидать, чтобы в списке Больше чем один элемент
  2. Это ожидание должно оборачивать предыдущее ожидание по поиску элементов по состоянию (я делаю ожидание по presenceOfAllElementsLocatedBy ).
    То есть мне хочется сделать это таким образом:
    у меня есть поиск List<WebElements> по состоянию:

elements = wait.until(condition.getType().apply(locator));

в моем случае это будет presenceOfAllElementsLocatedBy (это я реализовал по вашему примеру с конференции).
А потом я хочу чтобы было ожидание

wait.until(elements == 1)

То есть:
Сначала ищем массив по состоянию, потом проверяем что он больше 1. Если у массива только один элемент, то повторяем процедуру.
Заранее прошу прощение за запутаный ответ :slight_smile:


(Oleksii Ihnatiuk) #13

Пробовал и так и этак. Пока не озарила мысль глянуть повнимательней на родной метод ExpectedCondition<List<WebElement>> presenceOfAllElementsLocatedBy. По факту нужно было заменить одну цифру с 0 на 1. Создал отдельный класс и:

public class CustomExpectedCondition {

public static ExpectedCondition<List<WebElement>> moreThanOne(
        final By locator) {
    return driver -> {
        List<WebElement> elements = getDriver().findElements(locator);
        return elements.size() > 1 ? elements : null;
    };
}

}
Дальше обернул это в функцию и подставил в wait.until(). Все работает. Спасибо всем за помощь.
Реализовать вейтер в вейтере я почти понял как, но мне показалось что в вейтере обертке инициализировать WebDriverWait wait это не очень хорошо, поправьте если я не прав.
Еще раз спасибо всем за обсуждение.


(Sergey Korol) #14

В примере выше достаточно было заменить фильтр на .filter(list -> list.size() > 1), и вы добились бы того же результата.


(Oleksii Ihnatiuk) #15

Я не понял куда мне вставить вашу конструкцию:

moreThanOne(locator -> driver -> ofNullable(driver)
.map(d -> d.findElements(locator))
.filter(list -> list.size() > 1)
.orElse(null));

Буду признателен если напишете более развернуто.
Я же правильно понимаю, что мы делаем Предикату, которая принимает locator и возвращает булевое значение?


(Sergey Korol) #16

Ну вы ведь взяли пример с конференции. ExtendedWaitCondition же…

Это свернутый пример того анонимного класса, который представлен в официальных ExpectedConditions.


(Oleksii Ihnatiuk) #17

Спасибо, подставил, работает. Не смог только сделать отдельным методом ваш пример, чтобы так же передвать по :: . Как я понимаю наши способы делают то же самое, но вы это смогли реализовать через stream.