Як змусити Selenium 2.0 чекати завантаження сторінки?
Як змусити Selenium 2.0 чекати завантаження сторінки?
Відповіді:
Ви також можете перевірити завантаження сторінки за допомогою наступного коду
IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
Використовуйте клас WebDriverWait
Також дивіться тут
Ви можете розраховувати на показ якогось елемента. щось на кшталт C #:
WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));
_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement"));
Якщо встановити неявне очікування драйвера, а потім викликати findElement
метод на елементі, який, як ви очікуєте, буде розміщено на завантаженій сторінці, WebDriver буде опитувати цей елемент, поки він не знайде елемент або не досягне значення тайм-ауту.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
джерело: неявно-чекає
Взагалі, із Selenium 2.0 веб-драйвер повинен повертати керуючий код виклику лише після того, як він встановить, що сторінка завантажена. Якщо цього не відбувається, ви можете зателефонувати waitforelemement
, який здійснює циклічний цикл виклику, findelement
поки не буде знайдено або вичерпано час (може встановити тайм-аут).
If click() causes a new page to be loaded via an event or is done by sending a native event (which is a common case on Firefox, IE on Windows) then the method will not wait for it to be loaded and the caller should verify that a new page has been loaded.
JavascriptExecutor
, чекаючи, коли document.readyState буде "завершеним". Зважаючи на те, що в обидва кінці від селену до браузера, стан гонки, напевно, погіршується, і це "завжди" працює для мене. Після "click ()", коли очікую завантаження сторінки, я явно чекаю (використовуючи WebDriverWait) готового стану. ]
Реалізація Ruby:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
Ви можете видалити System.out
рядок. Він додається для налагодження.
WebDriver driver_;
public void waitForPageLoad() {
Wait<WebDriver> wait = new WebDriverWait(driver_, 30);
wait.until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
System.out.println("Current Window State : "
+ String.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState")));
return String
.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState"))
.equals("complete");
}
});
}
Усі ці рішення добре для конкретних випадків, але вони страждають хоча б однією з пари можливих проблем:
Вони недостатньо загальні - вони хочуть, щоб ви заздалегідь знали, що певна умова стосується сторінки, на якій ви переходите (наприклад, якийсь елемент відображатиметься)
Вони відкриті для перегонових умов, коли ви використовуєте елемент, який фактично присутній на старій сторінці, а також на новій сторінці.
Ось моя спроба загального рішення, яке дозволяє уникнути цієї проблеми (в Python):
По-перше, загальна функція "чекати" (використовуйте WebDriverWait, якщо вам подобається, я вважаю їх некрасивими):
def wait_for(condition_function):
start_time = time.time()
while time.time() < start_time + 3:
if condition_function():
return True
else:
time.sleep(0.1)
raise Exception('Timeout waiting for {}'.format(condition_function.__name__))
Далі, рішення покладається на те, що селен записує (внутрішній) ідентифікаційний номер для всіх елементів на сторінці, включаючи верхній рівень <html>
елемент . Коли сторінка оновлюється або завантажується, вона отримує новий html-елемент з новим ідентифікатором.
Отже, якщо припустити, що ви хочете натиснути на посилання з текстом "моє посилання", наприклад:
old_page = browser.find_element_by_tag_name('html')
browser.find_element_by_link_text('my link').click()
def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
wait_for(page_has_loaded)
Щоб отримати більше пітонічних, багаторазових помічників, ви можете створити контекстний менеджер:
from contextlib import contextmanager
@contextmanager
def wait_for_page_load(browser):
old_page = browser.find_element_by_tag_name('html')
yield
def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
wait_for(page_has_loaded)
І тоді ви можете використовувати його майже на будь-якій взаємодії з селеном:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
Я вважаю, що це куленепробивна! Що ти думаєш?
Більше інформації в публікації блогу тут
Ви також можете використовувати клас: ExpectedConditions
явно чекати, коли елемент з’явиться на веб-сторінці, перш ніж вжити будь-яких дій, подальших дій
Ви можете використовувати ExpectedConditions
клас, щоб визначити, чи видно елемент:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
Перегляньте ExpectedConditions class Javadoc
список усіх умов, які ви можете перевірити.
Відповідь Ірана переглянуто для Java 7:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wdriver) {
return ((JavascriptExecutor) driver).executeScript(
"return document.readyState"
).equals("complete");
}
});
Це здається серйозним обмеженням WebDriver. Очевидно, що очікування на елемент не означатиме завантаження сторінки, зокрема DOM може бути повністю складений (вже готовий стан), коли JS ще виконується, а CSS та зображення все ще завантажуються.
Я вважаю, що найпростішим рішенням є встановлення змінної JS після події завантаження після того, як все ініціалізується, і перевірити та дочекатися цієї змінної JS у Selenium.
Якщо ви хочете зачекати, коли певний елемент завантажиться, ви можете використовувати isDisplayed()
метод на RenderedWebElement
:
// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
// Browsers which render content (such as Firefox and IE) return "RenderedWebElements"
RenderedWebElement resultsDiv = (RenderedWebElement) driver.findElement(By.className("gac_m"));
// If results have been returned, the results are displayed in a drop down.
if (resultsDiv.isDisplayed()) {
break;
}
}
(Приклад із 5-хвилинної інструкції з початку роботи )
RenderedWebElement
в API немає. Однак isDisplayed()
метод тепер доступний безпосередньо на WebElement
.
Явно чекати або умовно чекати в цьому очікуванні, поки не буде дано цю умову.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
Це буде чекати кожного веб-елемента протягом 60 секунд.
Використовуйте неявно очікування очікування кожного елемента на сторінці до цього часу.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Це буде чекати кожного веб-елемента протягом 60 секунд.
Використовуйте неявно очікування очікування кожного елемента на сторінці до заданого часу.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
це чекає кожного елемента на сторінці протягом 30 сек.
Ще одне очікування - явно чекати або умовне очікування в цьому очікуванні, поки не буде задано умову.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
У id введіть статичний ідентифікатор елемента, який важко відображається на сторінці, як тільки сторінка завантажується.
Я здивований, що предикати були не першим вибором, оскільки ти зазвичай знаєш, з якими елементами ти будеш наступним чином взаємодіяти на сторінці, яку ти очікуєш завантажити. Мій підхід завжди полягав у формуванні предикатів / функцій, таких як waitForElementByID(String id)
іwaitForElemetVisibleByClass(String className)
т. Д., А потім використовувати та використовувати їх там, де мені потрібно, будь то для завантаження сторінки або зміни вмісту сторінки, на яку я чекаю.
Наприклад,
У моєму тестовому класі:
driverWait.until(textIsPresent("expectedText");
У моєму батьківському тестовому класі:
protected Predicate<WebDriver> textIsPresent(String text){
final String t = text;
return new Predicate<WebDriver>(){
public boolean apply(WebDriver driver){
return isTextPresent(t);
}
};
}
protected boolean isTextPresent(String text){
return driver.getPageSource().contains(text);
}
Хоча це здається чималим, воно вимагає багаторазової перевірки для вас, і інтервал того, як часто перевіряти, можна встановити разом з кінцевим часом очікування перед тимчасовим вичерпанням. Також ви повторно використовуєте такі методи.
У цьому прикладі батьківський клас визначив і ініціював WebDriver driver
іWebDriverWait driverWait
.
Я сподіваюся, що це допомагає.
Найкращий спосіб зачекати завантаження сторінок під час використання прив'язок Java для WebDriver - це використовувати шаблон дизайну Об'єкт сторінки разом із PageFactory. Це дозволяє вам використовувати те, AjaxElementLocatorFactory
що, якщо говорити, просто виступає як глобальне очікування всіх ваших елементів. У нього є обмеження щодо таких елементів, як спадні скриньки або складні переходи JavaScript, але це різко зменшить кількість необхідного коду та пришвидшить тестові часи. Хороший приклад можна знайти в цьому пості. Передбачається базове розуміння Core Java.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
Рішення NodeJS:
У Nodejs ви можете отримати це за допомогою обіцянок ...
Якщо ви пишете цей код, ви можете бути впевнені, що сторінка повністю завантажена, коли ви дістанетесь до тогочасного ...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
Якщо ви напишете цей код, ви перейдете, а селен чекатиме 3 секунди ...
driver.get('www.sidanmor.com');
driver.sleep(3000);
// you can't be sure that the page is fully loaded!!!
// do your stuff... hope it will be OK...
З документації Селен:
this.get (url) → Thenable
Запланує команду для переходу до вказаної URL-адреси.
Повертає обіцянку , що буде вирішена , коли документ має закінчену навантаження .
Ось версія Java 8 з найбільш актуальної на даний момент відповіді :
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
Де myDriver
знаходиться WebDriver
об’єкт (заявлено раніше).
Примітка . Майте на увазі, що цей метод ( document.readyState
) перевіряє лише DOM.
Дзвінок нижче Функція у вашому сценарії, це буде чекати, поки сторінка не буде завантажена за допомогою JavaScript
public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
/**
* Call this method before an event that will change the page.
*/
private void beforePageLoad() {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.mpPageReloaded='notYet';");
}
/**
* Call this method after an event that will change the page.
*
* @see #beforePageLoad
*
* Waits for the previous page to disappear.
*/
private void afterPageLoad() throws Exception {
(new WebDriverWait(driver, 10)).until(new Predicate<WebDriver>() {
@Override
public boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
Object obj = js.executeScript("return document.mpPageReloaded;");
if (obj == null) {
return true;
}
String str = (String) obj;
if (!str.equals("notYet")) {
return true;
}
return false;
}
});
}
Ви можете перейти з документа на елемент, якщо змінюється лише частина документа.
Цей прийом був натхненний відповіддю з тих пір.
SeleniumWaiter :
import com.google.common.base.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
public class SeleniumWaiter {
private WebDriver driver;
public SeleniumWaiter(WebDriver driver) {
this.driver = driver;
}
public WebElement waitForMe(By locatorname, int timeout){
WebDriverWait wait = new WebDriverWait(driver, timeout);
return wait.until(SeleniumWaiter.presenceOfElementLocated(locatorname));
}
public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
// TODO Auto-generated method stub
return new Function<WebDriver, WebElement>() {
@Override
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
}
І вам ви користуєтесь цим :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
Ви можете скористатися наявним нижче методом, щоб встановити час для pageeLoadTimeout у наведеному нижче прикладі, якщо на завантаження сторінки потрібно більше 20 секунд, це призведе до виключення перезавантаження сторінки
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
Ви можете явно чекати, коли елемент з’явиться на веб-сторінці, перш ніж вжити будь-яких дій (наприклад, element.click ())
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}});
Це те, що я використовував для аналогічного сценарію, і це прекрасно працює.
Найкращий спосіб, який я бачив, - це використовувати stalenessOf
очікуваний стан, щоб дочекатися, коли стара сторінка стане черствою.
Приклад:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
Він зачекає десять секунд, коли старий тег HTML стане несвіжим, а потім викине виняток, якщо цього не відбудеться.
Я використовую node + selenium-webdriver (версія якої зараз є 3.5.0). що я для цього роблю:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
Ви можете використовувати зачекати. в основному є 2 типи чекання в селені
- Неочікуване зачекання
Це дуже просто, будь ласка, дивіться синтаксис нижче:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Явне очікування
Явно чекати або умовно чекати в цьому очікуванні, поки не відбудеться задана умова
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Ви можете використовувати інші властивості, наприклад visblityOf()
,visblityOfElement()
Якщо хтось використовує селенід:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
Більше умов можна знайти тут: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
У моєму випадку я використовував наступне, щоб знати стан завантаження сторінки. У нашому додатку gif-файли для завантаження присутні, і я слухаю їх так, щоб усунути небажаний час очікування в сценарії.
public static void processing(){
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
}
Де xpath знаходить gif у HTML DOM. Після цього ви також можете застосувати свої дії. Клацніть.
public static void click(WebElement elementToBeClicked){
WebDriverWait wait = new WebDriverWait(driver, 45);
wait.until(ExpectedConditions.visibilityOf(element));
wait.until(ExpectedConditions.elementToBeClickable(element));
wait.ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class); elementToBeClicked.click();
}
Людина на всі ці відповіді вимагає занадто багато коду. Це має бути проста річ, оскільки її досить поширене.
Чому б просто не ввести якийсь простий javascript з webdriver і перевірити. Це метод, який я використовую в своєму класі веб-шрифтів. Javascript є досить базовим, навіть якщо ви не знаєте js.
def js_get_page_state(self):
"""
Javascript for getting document.readyState
:return: Pages state.
More Info: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
"""
ready_state = self.driver.execute_script('return document.readyState')
if ready_state == 'loading':
self.logger.info("Loading Page...")
elif ready_state == 'interactive':
self.logger.info("Page is interactive")
elif ready_state == 'complete':
self.logger.info("The page is fully loaded!")
return ready_state
Як змусити Selenium дочекатися завантаження сторінки після клацання забезпечує наступний цікавий підхід:
WebElement
стару сторінку.WebElement
поки не StaleElementReferenceException
буде кинуто.Приклад коду:
WebElement link = ...;
link.click();
new WebDriverWait(webDriver, timeout).until((org.openqa.selenium.WebDriver input) ->
{
try
{
link.isDisplayed();
return false;
}
catch (StaleElementReferenceException unused)
{
return true;
}
});
new WebDriverWait(driver, 10).until(ExpectedConditions.stalenessOf(element))
.