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

Даний матеріал вперше було опубліковано на сайті automation-qa.in.ua, втім з певних причин я вирішив не продовжувати його підтримку.

Implicit wait або неявне очікування є, мабуть, найпростішим типом очікування в Selenium Webdriver й однією з його властивостей є те, що період очікування встановлюється один раз для всіх наступних викликів й буде діяти допоки його не змінять або до завершення сесії. За замовчуванням його значення дорівнює нулю, тобто можна вважати, що таке очікування вимкнене, а щоб його змінити можна використати такий код мовою Java (приклади для інших мов, що підтримуються у Selenium WebDriver):

//Встановлення неявного очікування 5 секунд
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

В інших статтях також можна зустріти такий код, однак він вже буде застарілим і його використання у нових проектах є небажаним:

//Застарілий варіант
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Також варто додати, що використовуючи об’єкт timeouts очікування можна встановити не тільки для пошуку якогось елементу на сторнці ( findElement() ), а ще для часу очікування завантаження сторінки( pageLoadTimeout() ), та виконання асинхронного коду( scriptTimeout() ).

//Встановлює неявне очікування в 5 секунд для виконання асинхронного скрипта
driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(5)); 

//Встановлює неявне очікування в 5 секунд для завантаження сторінки
driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(5));

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

Згідно з https://w3c.github.io/webdriver/#element-retrieval час завершення пошуку елемента для findElement та findElements буде тоді, коли настане час виклику команди плюс час неявного очікування, тобто якщо умовний пошук елементу почнеться о 00:00:00 і неявне очікування матиме значення 10 секунд, то після 00:00:10 буде вкинуте NoSuchElementException, якщо елемент не знайдеться до цього.

Загалом, неявне очікування повідомляє веб-драйверу, що він має почекати певну кількість часу, перед тим як повернути NoSuchElementException, якщо такого елементу незнайдеться в період очікування. Тепер, коли розібралися із неявним очікування, можна перейти до самого пошуку елементів з його використанням. Розглянемо це на прикладі сторінки, яка симулює сторінку із контентом, який може завантажуватися із затримками або динамічно.

Приклад сторінки

Ця сторінка має такі елементи:

  • Заголовок, який завантажується із сторінкою

  • Один параграф, який завантажується також із сторінкою

  • Кнопку “ClickMe”, яка завантажується із сторінкою та при натисканні додасть ще один параграф через випадкову кількість часу в проміжку від 0 до 5 секунд

  • Один параграф, який додасться через 5 секунд після завантаження сторінки

  • Один параграф, який додасться через 11 секунд після завантаження сторінки

Отже, до перших трьох елементів можна отримати доступ одразу, без використання будь-яких очікувань, оскільки вони завантажаться разом із сторінкою та на момент їхнього пошуку будуть присутні в DOM-дереві.

Початкове DOM-дерево

А після того, як буде натиснути кнопка і пройде 11 секунд з моменту завантаження сторінки вона й DOM-дерево будуть мати такий вигляд:

DOM-дерево після появи всіх елементів через 11 секунд

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

Допустимо, що є завдання вивести в консоль текст кожного елементу після того, як всі елемети будуть завантажені на сторінці. Тому для початку спробуємо застосувати такий код:

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 = driver.findElement(By.id("postponedForFiveSeconds"));//NoSuchElementException
System.out.println("Second paragraph text: " + secondParagraph.getText());

WebElement thirdParagraph = driver.findElement(By.id("postponedForElevenSeconds"));
System.out.println("Forth paragraph text: " + thirdParagraph.getText());

WebElement fourthParagraph = driver.findElement(By.id("dynamicElement"));
System.out.println("Fourth paragraph text: " + fourthParagraph.getText());

Очікувано, що на 10 рядку виконання перерветься через NoSuchElementException, оскільки в цьому місці є намагання отримати елемент, якого ще немає в DOM-дереві. Тому перед тим, як спробувати отримати доступ до цього елементу, потрібно встановити очікування, а точніше неявне очікування протягом 5 секунд.

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

//
// Додано неявне очікування 5 секунд перед пошуком елементу
//
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

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

WebElement thirdParagraph = driver.findElement(By.id("postponedForElevenSeconds"));//NoSuchElementException
System.out.println("Third paragraph text: " + thirdParagraph.getText());

clickMe.click();
WebElement fourthParagraph = driver.findElement(By.id("dynamicElement"));
System.out.println("Fourth paragraph text: " + fourthParagraph.getText());

Що ж, якщо з другим параграфом все зрозуміло і помилка виправлена, то з третім все трішки складніше, оскільки він завантажиться тільки після 11 секунди, а очікування зараз дорівнює 5 секунд, тому знову потрібно маніпулювати часом очікування, тобто збільшити його до 11 секунд. Зважаючи на те, що останній параграф завантажиться через 5 секунд після натискання на кнопку, то потім його знову потрібно буде зменшити до 5, оскільки елемент має завантажитися через 5 секунд і не пізніше. Тому фінальний варіант коду буде мати такий вигляд:

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

// Встановлено неявне очікування 5 секунд перед пошуком елементу
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.


// Встановлено неявне очікування 11 секунд перед пошуком елементу
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();


// Встаглвлено неявне очікування 5 секунд перед пошуком елементу
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));//Вимикає неявні очікування

Також варто додати те, що методи findElement та findElements очікують на появу елемента в DOM-дереві, не зважаючи на інші його властивості, а неявне очікування не варто поєднувати з іншими типами очікуваннь, оскільки це може викликати небажані наслідки та неявно збільшити інтервал в інших типах очікувань(fluent та explicit).

Підсумовуючи написане можна виокремити наступне про неявне очікування:

  • Вимкнуте за замовчуванням

  • Встановлюється один раз та діє протягом всієї сесії або до його зміни

  • Може впливати на інші типи очікувань, тому їхнє поєднання — не рекомендоване

  • findElement та findElements лише шукають елемент в DOM-дереві ігноруючи його властивості

В наступних постах розгляну fluent wait та explicit wait і різницю між ними.

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

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

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

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

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

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

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

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

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

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

    It
  • Що таке Selenium?

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

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

    Selenium

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

  • Damn Small Linux - диструбитив який повертає життя старим комп’ютерам

    DSL 2024 відродився як компактний дистрибутив Linux, спеціально призначений для комп'ютерів з низькими характеристиками x86. Він вміщує багато програм у маленький пакет. Усі програми вибрані за їх функціональність, невеликий розмір та низькі вимоги до залежностей.

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

    Linux
  • 16 слів, які допоможуть вам зрозуміти свій психологічний стан

    Апатія, роздратованість, вигорання, зміни настрою — у цього є причина. І вона одна. Як її знайти і повернутися до ресурсного стану? Як знайти справжню причину своєї психічної нестабільності?

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

    Ментальне Здоров'я
  • Чому __name__ == "__main__"?

    "name == "main"" - ключова фраза в Python. Визначає, чи є файл головним скриптом чи модулем. Це допомагає створювати зручні модулі, уникати ненавмисного виконання при імпорті та оптимізувати продуктивність.

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

    Python

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

Досі дивуюся з того що хтось використовує застралій selenium(

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

  • Damn Small Linux - диструбитив який повертає життя старим комп’ютерам

    DSL 2024 відродився як компактний дистрибутив Linux, спеціально призначений для комп'ютерів з низькими характеристиками x86. Він вміщує багато програм у маленький пакет. Усі програми вибрані за їх функціональність, невеликий розмір та низькі вимоги до залежностей.

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

    Linux
  • 16 слів, які допоможуть вам зрозуміти свій психологічний стан

    Апатія, роздратованість, вигорання, зміни настрою — у цього є причина. І вона одна. Як її знайти і повернутися до ресурсного стану? Як знайти справжню причину своєї психічної нестабільності?

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

    Ментальне Здоров'я
  • Чому __name__ == "__main__"?

    "name == "main"" - ключова фраза в Python. Визначає, чи є файл головним скриптом чи модулем. Це допомагає створювати зручні модулі, уникати ненавмисного виконання при імпорті та оптимізувати продуктивність.

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

    Python