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

WebDriverWait, PageObject и Lambda выражения


(heartwilltell) #1

Есть 2 вопроса:

  1. Есть ли возможность юзать WebDriverWait не указывая ему локатор элемента через By класс, а просто давая ему элемент который обьявляется в пейдж обджекте анотацией @FindBy

Как-то так:

public void waitForElementApear(WebElement element) {
        WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until(new ExpectedCondition<WebElement>() {
            @Override
            public WebElement apply(WebDriver webDriver) {
                return element;
            }
        });
    }
  1. Сейчас конструкцию типа:

    public void waitFor() {
    WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until(new ExpectedCondition() {
    @Override
    public WebElement apply(WebDriver input) {
    return input.findElement(By.cssSelector(“somelocator”));
    }
    });
    }

IDE предлагает мне заменить лямбдой на такую:

public void waitFor() {
        WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until((WebDriver input) -> input.findElement(By.cssSelector("somelocator")));
    }

Сам в лямбды еще особо не вникал, но то что советует IDE работает. Есть ли в них профит или это просто синтакс шугар?

Сразу отвечу - фреймворк с тестами на флешке с собой не ношу и разворачивать это все на ноутбуке мамы где стоит джава ниже 1.8 - точно не буду :slight_smile:


(Mitallast) #2

По сути, это синтаксический сахар, появился с Java 8. Профит имеется некоторый, т.к. для реализации лямбд допилили jvm для более быстрой реализации и использования. Пример - можно в некоторых ситуациях не использовать модификатор final, если в коде сохраняется promise отсутствия модификации используемых в лямбде переменных.


(Taras) #3

А в ExpectedCondition вообще подставлять елементи с FindBy получаеться ? Exception-и не вибрасивает ?


(Sergey Korol) #4

В ExpectedConditions есть API для работы с WebElement. Просто кейсов для возможного применения будет поменьше, нежели в случае с By. Ведь если элемент уже найден, то проверять его, к примеру, на presence - бессмысленно.

Касательно лямд: как уже сказали выше, в данном случае это лишь сахар. Более реальные примеры с лямбдами были освещены в недавней статье.


(Taras) #5

ну если все елементи которрие описани на пейдж обджекте описани через Find by , то как то не християски смотриться потом xpath в коде какой то Expected condion-e типа. Лучше что б он те сами елементи юзал что Find By описани били


(heartwilltell) #6

Вот! Вот по этому я и спрашиваю собственно. Мне аж дрожь бросает от того что приходится дублировать локатор элемента в качестве аргумента методу, когда он уже определен на выше через FindBy.


(Sergey Korol) #7

Возможно там задумка была в поиске вложенных локаторов внутри уже найденных. Не могу сказать точно, т.к. не использую FindBy.


(heartwilltell) #8

Наверное достойно другой темы и возможно уже обсуждалось - но почему не используете?


(Sergey Korol) #9

У нас очень непростое приложение, где UI полностью отделен от backend. Сплошные асинхронные запросы. Нужно постоянно чего-то ждать. И не просто появления элемента, а к примеру, текста внутри него. Либо проверять кликабелен он или нет до непосредственного взаимодействия. Любая часть страницы может в любой момент измениться в зависимости от состояния другой. У нас идет постоянное двустороннее общение UI с backend. Помимо этого, у нас много динамических компонентов, которые надо формировать на лету. Тут статические локаторы не помогут. Посему мне проще было переопределить findElement, настроив его на работу с WebDriverWait, нежели отдавать управление фабрикам, которые ровным счетом мало чем мне помогут.


(Taras) #10

я сделал так

public <V> V forCondition(Function<? super T, V> function) {
		return fluentWait.until(function);
	}

где

fluentWait = getDefaultFluentWait();
	/**
	 * @return a new instance
	 */
	private FluentWait<T> getDefaultFluentWait() {
		return new FluentWait<T>(searchContext)
				.withTimeout(timeout, TimeUnit.SECONDS)
				.pollingEvery(1, TimeUnit.SECONDS)
				.ignoring(NoSuchElementException.class);
	}

и туда просто тикаю Expected condition-и разние.
По сути все кондишини принимают параметром By - нам нужно засунуть WebElement вместо By.

Давайте подумаем вместе как ето сделать …


(Sergey Korol) #11

А зачем вы зовете FluentWait, если WebDriverWait уже его расширяет?


(Taras) #12

тут прочитал


(Taras) #13

ну типа в Fluent Wait можна больше всего наконфиговать что я чуток и доделал там…ексепишини итд итп


(heartwilltell) #14

Что-то аватар индуса заставляет меня поразмыслить над качеством его решения :smiley:


(Taras) #15

ахахахахахах


(Sergey Korol) #16

По-моему, тот парень не совсем понимает значения слова “наследование”. Если WebDriverWait расширяет FluentWait, ему автоматически доступно все то, что есть во FluentWait.

Я могу использовать такую же конструкцию, как у вас, но у же с WebDriverWait:

wait.withTimeout(timeout, TimeUnit.SECONDS)
    .pollingEvery(1, TimeUnit.SECONDS)
    .ignoring(NoSuchElementException.class);

Касательно вопроса, как засунуть WebElement через функциональный интерфейс в ExpectedCondition: я недавно постил статью о Java 8 фичах, в том числе с примером использования WebDriverWait.

Если чуть модифицировать тот пример, можно получить следующее:

.
    public WebElement findElement(final WebElement element, 
              final Function<WebElement, ExpectedCondition<WebElement>> condition,
              final Integer timeout) {
        final WebElement subElement = wait.withTimeout(
                Optional.ofNullable(timeout)
                        .filter(value -> value >= 0)
                        .orElse(DEFAULT_TIMEOUT), TimeUnit.SECONDS)
                .until(condition.apply(element));

        wait.withTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        return subElement;
    }

Ну и вызов останется таким же:

findElement(element, ExpectedConditions::elementToBeClickable, 5);

Только в этом случае будет срабатывать метод, принимающий WebElement на вход, вместо By.

Но опять-таки, использование таких конструкций наверное сможет себя окупить лишь в случае взаимодействия с саб-элементами найденного родителя.


(Taras) #17

у меня 7 Java - нужно такое переписать для 7 Java как то - я использую Guava, но я еще не совсем в нее вьехал