Как заставить 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__))
Далее, решение опирается на тот факт, что селен записывает (внутренний) id-номер для всех элементов на странице, включая <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)
Для большего Pythonic, многоразового, универсального помощника, вы можете сделать контекстный менеджер:
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 для события onload после того, как все будет инициализировано, а также проверить и дождаться этой переменной 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 - это использовать шаблон проектирования Page Object с 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...
Из документации Selenium:
this.get (url) → затем
Планирует команду для перехода к указанному 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;
}
});
}
Вы можете перейти от документа к элементу, если изменяется только часть документа.
Эта техника была вдохновлена ответом frombasic.
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
ExpectedCondition, чтобы дождаться устаревания старой страницы.
Пример:
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 с веб-драйвером и проверить. Это метод, который я использую в своем классе веб-мастеров. 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))
.