Даний матеріал вперше було опубліковано на сайті 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-дереві.
А після того, як буде натиснути кнопка і пройде 11 секунд з моменту завантаження сторінки вона й DOM-дерево будуть мати такий вигляд:
Можна помітити, що в кінці додалося три раніше згаданих елементи і для того, щоб до них отримати доступ, потрібно використати очікування, оскільки вони додаються на сторінку із затримкою.
Допустимо, що є завдання вивести в консоль текст кожного елементу після того, як всі елемети будуть завантажені на сторінці. Тому для початку спробуємо застосувати такий код:
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 і різницю між ними.