Fluent wait або впевнене очікування та як його їсти

Цього разу буду розглядату впевнене очікування, хоча його називають ще інколи плаваючим, вільним або ще якось, втім називати в рамках цієї статті буду його впевненим. На жаль в більшості статей про очікування даний тип згадується досить коротко, що особисто мені не дуже подобається тому вважаю, що оминути його існування все-таки було б неправильно, хоча б з таких причи: воно існує, воно досить потужне, воно є базою для явного очікування, а також його можна використати, коли інші очікування не підходять.

Почну з можливостей, які дає цей тип очікуваня:

  • Керування часом очікування

  • Керування інтервалом між опитуваннями

  • Ігнорування винятків (NoSuchElementExceptions, ElementNotInteractableException і т.д.)

А ось і приклад такого очікування:

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
  .withTimeout(Duration.ofSeconds(30)) //Встановлює час очікування 30 секунд
  .pollingEvery(Duration.ofSeconds(5)) //Встановлює інтервал опитування 5 секунд
  .ignoring(NoSuchElementException.class); //Визначає тип винятку, який буде ігноруватися

WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
  @Override
  public WebElement apply(WebDriver driver) {
    return driver.findElement(By.id("foo"));
  }
});

Умовно можемо розділити його на дві частини:

  1. Налаштування очікування ( Wait<Webdriver> wait = ... )

  2. Виконання самого очікування (wait.until(... ).

З назв методів можна зрозуміти, що вони виконують, а якщо ні, то пан автор додав там коментарі. А ось друга частина буде трішки цікавішою. Що ж, аргументом до методу until є функція, яка й буде виконувати очікування. Варто пам’ятати, що опис логіки потрібно робити в тілі функції apply. А от те, як працює все це під капотом — є тим, що потребує опису в окремому пості, а в цьому хочеться описати загалом, що це таке і як його з’їсти. Також варто додати, що запис другої частини може мати дещо інший вигляд, якщо використовувати лямбди:

WebElement foo = wait.until(driver -> driver.findElement(By.id("foo")));

Може здатися, що щоразу писати стіну коду, коли потрібно якесь очікування з різними налаштуваннями не надто зручно, втім можна зробити метод, який буде викликатися, замість постійного повтору коду:

private WebElement fluentWaitMethod(Duration timeout, By by) {
  return new FluentWait<WebDriver>(driver)
      .withTimeout(timeout)
      .ignoring(NoSuchElementException.class)
      .until(innerDriver -> innerDriver.findElement(by));
}

Можна помітити, що опущено налаштування інтервалу між опитуваннями і це не викличе помилки, оскільки воно має значення за замовчуванням, яке дорівнює 500мс, як і значення за замовчуванням для часу очікування.

Теорія — це, звісно, добре, а тепер варто перейти до практичного застосування і для цього використаю код з попередньої статті про неявне очікування:

/*
* Старий варіант
*/
WebElement h1 = driver.findElement(By.tagName("h1"));
System.out.println("Header text: " + h1.getText()); //Header text: Implicit Wait Example

WebElement firstParagraph = driver.findElement(By.tagName("p"));
System.out.println("First paragraph text: " + firstParagraph.getText()); //First paragraph text: This loads with page

WebElement clickMe = driver.findElement(By.id("addNewContent"));
System.out.println("Button text: " + clickMe.getText()); //Button text: ClickMe

driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
WebElement secondParagraph = driver.findElement(By.id("postponedForFiveSeconds"));
System.out.println("Second paragraph text: " + secondParagraph.getText());//Second paragraph text: Loaded after 5 seconds.

driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(11));
WebElement thirdParagraph = driver.findElement(By.id("postponedForElevenSeconds"));
System.out.println("Third paragraph text: " + thirdParagraph.getText());//Third paragraph text: Loaded after 11 seconds.

clickMe.click();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
WebElement fourthParagraph = driver.findElement(By.id("dynamicElement"));
System.out.println("Fourth paragraph text: " + fourthParagraph.getText());//Fourth paragraph text: Created at: 3:30:01 AM

driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(0));//Вимикає неявні очікування

А тепер перепишу його з використанням впевненого очікування:

/*
* З використанням fluent wait
*/

WebElement h1 = driver.findElement(By.tagName("h1"));

System.out.println("Header text: " + h1.getText()); //Header text: Implicit Wait Example

WebElement firstParagraph = driver.findElement(By.tagName("p"));
System.out.println("First paragraph text: " + firstParagraph.getText()); //First paragraph text: This loads with page

WebElement clickMe = driver.findElement(By.id("addNewContent"));
System.out.println("Button text: " + clickMe.getText()); //Button text: ClickMe

WebElement secondParagraph = fluentWaitMethod(Duration.ofSeconds(5), By.id("postponedForFiveSeconds"));
System.out.println("Second paragraph text: " + secondParagraph.getText());//Second paragraph text: Loaded after 5 seconds.

WebElement thirdParagraph = fluentWaitMethod(Duration.ofSeconds(11), By.id("postponedForElevenSeconds"));
System.out.println("Third paragraph text: " + thirdParagraph.getText());//Third paragraph text: Loaded after 11 seconds.

clickMe.click();
WebElement fourthParagraph = fluentWaitMethod(Duration.ofSeconds(5), By.id("dynamicElement"));
System.out.println("Fourth paragraph text: " + fourthParagraph.getText());//Fourth paragraph text: Created at: 3:30:01 AM

Отже, можна побачити, що в такому варіанті ми позбавилися постійних маніпуляцій із неявним очікуванням (driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));), а з використанням написаного методу fluentWaitMethod і зменшується загальна кількість коду через відсутність його повторювання, що одночасно покращує читабельність коду.

До речі, якщо розглянути умовну другу часнину очікування:

WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
  @Override
  public WebElement apply(WebDriver driver) {
    return driver.findElement(By.id("foo"));
  }
});

, то можна зрозуміти чому поєднання неявного очікування з іншими — не бажане, оскільки воно буде впливати на логіку, яку було описано в коді, збільшуючи час очікування описаного в тілі методу apply.

Тако ж було б добре навести приклад використання не тільки пошуку елементів, але й якоїсь взаємодії. Отже допустимо, що потрібно натиснути кнопку, яка перші 2 секунди перекривається якимось іншим елементом. Якщо спробувати одразу це зробити, то ймовірно буде викинутий виняток ElementClickInterceptedException, тому можна створити таке очікування:

Wait<WebDriver> wait =
    new FluentWait<WebDriver>(driver)
        .withTimeout(Duration.ofSeconds(3))
        .ignoring(ElementClickInterceptedException.class, NoSuchElementException.class);

wait.until(
    new Function<WebDriver, Boolean>() {
      public Boolean apply(WebDriver driver) {
        driver.findElement(by).click();
        return Boolean.TRUE;
      }
    });

В даному випадку повертати щось з функції при успішному кліку є обов’язково, оскільки метод until очікує, що з функції в тілі метода apply повернеться щось типу Boolean, якщо по-простому, адже детальний механізм роботи цього заслуговою більш детального розгляду в окремому пості, як пан автор казав раніше.

І на завершення хотів би зробити такі висноски про впевнене очікування(fluent wait):

  • Дозволяє налаштовувати такі параметри:

    • Час очікування

    • Інтервал між пошуком елементів

    • Типи винятків, що ігноруюються

  • Дозволяє описувати власну логіку очікування

  • Дозволяє налаштовувати очікування для кожного елементу окремо

  • Достатньо потужний інструмент для використання в тих місцях, де інші типи очікування не підходять

Сподіваюся мені вдалося розкрити дану тему детальніше, аніж це роблять інші та й взагалі маю надію, що даний матеріал був корисним та цікавим для прочитання. Коментарі, критика і т.д. — вітаються.

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Василь Побережник
Василь Побережник@VasylPoberezhnyk

AQA | Фотограф-ентузіаст

527Прочитань
0Автори
4Читачі
На Друкарні з 29 серпня

Більше від автора

  • Explicit wait: явне очікування або fluent wait швидкого приготування

    Що ж, в попередніх постах було описано imlicit wait(неявне очікування) та fluent wait(впевнене очікування, хоча такий переклад — це радше відсебеньки), а це означає, що настав час для останнього з трьох — явного очікування.

    Теми цього довгочиту:

    Qa
  • Implicit wait або неявне очікування та пошук елементів findElement

    Неявне очікування (implicit wait) та пошук елементів (findElelement) є, мабуть, першим поняттями із якими стикаються, коли починають розбиратися із Selenium WebDriver. Тож тут написано про них і як їх можна поєднати між собою.

    Теми цього довгочиту:

    Selenium
  • Що таке Selenium?

    Selenium — це інструмент для автоматизації тестування веб-додатків. Він дозволяє розробникам і тестувальникам автоматизувати взаємодію з веб-браузером, тобто виконувати різні дії на веб-сторінках, такі як клікання на кнопки, введення тексту, перевірка наявності елементів і т.д.

    Теми цього довгочиту:

    Selenium

Вам також сподобається

Коментарі (0)

Підтримайте автора першим.
Напишіть коментар!

Вам також сподобається