¿Cómo hace que Selenium 2.0 espere a que se cargue la página?
¿Cómo hace que Selenium 2.0 espere a que se cargue la página?
Respuestas:
También puede verificar la página cargada usando el siguiente código
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"));
Utilice la clase WebDriverWait
Ver también aquí
Puede esperar mostrar algún elemento. algo así como en 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"));
Si configura la espera implícita del controlador, luego llama al findElement
método en un elemento que espera que esté en la página cargada, el WebDriver sondeará ese elemento hasta que encuentre el elemento o alcance el valor de tiempo de espera.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
fuente: implícito-espera
En general, con Selenium 2.0, el controlador web solo debe devolver el control al código de llamada una vez que ha determinado que la página se ha cargado. Si no es así, puede llamar waitforelemement
, lo que alterna las llamadas findelement
hasta que se encuentre o se agote el tiempo de espera (se puede configurar el tiempo de espera).
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
, esperando que document.readyState esté "completo". Debido al viaje de ida y vuelta del selenio al navegador, supongo que la condición de carrera se mitiga, y esto "siempre" funciona para mí. Después de "hacer clic ()" cuando espero que se cargue una página, espero explícitamente (usando WebDriverWait) el estado listo. ]
Implementación de Ruby:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
Puedes quitar la System.out
línea. Se agrega con fines de depuración.
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");
}
});
}
Todas estas soluciones están bien para casos específicos, pero sufren al menos uno de los dos posibles problemas:
No son lo suficientemente genéricos: quieren que sepas, de antemano, que se cumplirá alguna condición específica de la página a la que irás (por ejemplo, se mostrará algún elemento)
Están abiertos a una condición de carrera en la que utiliza un elemento que está realmente presente en la página anterior y en la nueva.
Aquí está mi intento de una solución genérica que evite este problema (en Python):
Primero, una función genérica de "espera" (use un WebDriverWait si lo desea, los encuentro feos):
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__))
A continuación, la solución se basa en el hecho de que el selenio registra un número de identificación (interno) para todos los elementos de una página, incluido el nivel superior <html>
elemento de . Cuando una página se actualiza o carga, obtiene un nuevo elemento html con una nueva ID.
Entonces, suponiendo que desea hacer clic en un enlace con el texto "mi enlace", por ejemplo:
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)
Para obtener más ayuda Pythonic, reutilizable, genérica, puede hacer un administrador de contexto:
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)
Y luego puede usarlo en casi cualquier interacción de selenio:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
Creo que es a prueba de balas! ¿Qué piensas?
Más información en una publicación de blog al respecto aquí
También puede usar la clase: ExpectedConditions
para esperar explícitamente a que se muestre un elemento en la página web antes de que pueda realizar cualquier otra acción.
Puede usar la ExpectedConditions
clase para determinar si un elemento es visible:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
Consulte la ExpectedConditions class Javadoc
lista de todas las condiciones que puede verificar.
La respuesta de Imran se volvió a contar para 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");
}
});
Esto parece ser una limitación seria de WebDriver. Obviamente, esperar un elemento no implicará que la página se cargue, en particular, el DOM se puede construir completamente (estado listo) por el cual JS todavía se está ejecutando y CSS y las imágenes aún se están cargando.
Creo que la solución más simple es establecer una variable JS en el evento de carga después de que todo se inicializa y verificar y esperar esta variable JS en Selenium.
Si desea esperar a que se cargue un elemento específico, puede usar el isDisplayed()
método en 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;
}
}
(Ejemplo de la guía de inicio de 5 minutos )
RenderedWebElement
en la API. Sin embargo, el isDisplayed()
método ahora está disponible directamente en WebElement
.
Espera explícitamente o espera condicional en esta espera hasta que se dé esta condición.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
Esto esperará a cada elemento web durante 60 segundos.
Use implícitamente la espera de espera de cada elemento en la página hasta ese momento
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Esto esperará a cada elemento web durante 60 segundos.
Utilice implícitamente esperar a la espera de cada elemento en la página hasta el momento dado.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
esta espera para cada elemento en la página durante 30 segundos.
Otra espera es Esperar explícitamente o esperar condicional en esta espera hasta la condición dada.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
En id, proporcione la identificación del elemento estático que se muestra de forma diferente en la página, tan pronto como se carga la página.
Me sorprende que los predicados no hayan sido la primera opción, ya que normalmente sabes con qué elementos interactuarás en la página que estás esperando para cargar. Mi enfoque siempre ha sido construir predicados / funciones como waitForElementByID(String id)
ywaitForElemetVisibleByClass(String className)
, etc. y luego usarlos y reutilizarlos donde sea que los necesite, ya sea para cargar una página o cambiar el contenido de la página que estoy esperando.
Por ejemplo,
En mi clase de prueba:
driverWait.until(textIsPresent("expectedText");
En mi clase de prueba padre:
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);
}
Aunque esto parece mucho, se encarga de verificar repetidamente para usted y el intervalo de la frecuencia con la que se puede verificar junto con el tiempo de espera final antes de que se agote el tiempo. Además, reutilizará dichos métodos.
En este ejemplo, la clase padre definió e inició el WebDriver driver
y el WebDriverWait driverWait
.
Espero que esto ayude.
La mejor manera de esperar cargas de página cuando se usan los enlaces Java para WebDriver es usar el patrón de diseño de Objeto de página con PageFactory. Esto le permite utilizar el AjaxElementLocatorFactory
que, simplemente, actúa como una espera global para todos sus elementos. Tiene limitaciones en elementos como buzones o transiciones complejas de javascript, pero reducirá drásticamente la cantidad de código necesario y acelerará los tiempos de prueba. Un buen ejemplo se puede encontrar en este blog. Se supone una comprensión básica de Core Java.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
Solución NodeJS:
En Nodejs puedes conseguirlo mediante promesas ...
Si escribe este código, puede estar seguro de que la página está completamente cargada cuando llegue al ...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
Si escribe este código, navegará y el selenio esperará 3 segundos ...
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...
De la documentación de Selenium:
this.get (url) → Thenable
Programa un comando para navegar a la URL dada.
Devuelve una promesa que se resolverá cuando el documento haya terminado de cargarse .
Aquí hay una versión Java 8 de la respuesta más votada actualmente :
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
Donde myDriver
es un WebDriver
objeto (declarado anteriormente).
Nota : Tenga en cuenta que este método ( document.readyState
) solo verifica el DOM.
Llame a continuación a Function en su script, esto esperará hasta que la página no se cargue usando 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;
}
});
}
Puede cambiar del documento a un elemento, en el caso de que solo se cambie parte del documento.
Esta técnica se inspiró en la respuesta de sincebasic.
Selenio Camarero :
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);
}
};
}
}
Y para usarlo :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
Puede usar el siguiente método existente para establecer el tiempo para pageeLoadTimeout en el ejemplo siguiente si la página tarda más de 20 segundos en cargarse, entonces arrojará una excepción de recarga de página
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
Puede esperar explícitamente a que aparezca un elemento en la página web antes de realizar cualquier acción (como 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"));
}});
Esto es lo que usé para un escenario similar y funciona bien.
La mejor manera que he visto es utilizar el stalenessOf
ExpectedCondition, esperar a que la página anterior se vuelva obsoleta.
Ejemplo:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
Esperará diez segundos para que la antigua etiqueta HTML se vuelva obsoleta y luego lanzará una excepción si no sucede.
Uso node + selenium-webdriver (cuya versión es 3.5.0 ahora). lo que hago para esto es:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
Puedes usar esperar. básicamente hay 2 tipos de espera en selenio
- Espera implícita
Esto es muy simple, vea la sintaxis a continuación:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Espera explícita
Espera explícitamente o espera condicional en esta espera hasta que se produzca la condición dada.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Puede usar otras propiedades como visblityOf()
,visblityOfElement()
Si alguien usa seleniuro:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
Más condiciones se pueden encontrar aquí: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
En mi caso, utilicé lo siguiente para conocer el estado de carga de la página. En nuestra aplicación, los gifs de carga están presentes y los escucho de la siguiente manera para eliminar el tiempo de espera no deseado en el script.
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")));
}
Donde el xpath localiza el gif en el DOM HTML. Después de esto, también puede implementar sus métodos de acción Haga clic.
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();
}
Hombre, todas estas respuestas requieren demasiado código. Esto debería ser algo simple, ya que es bastante común.
¿Por qué no simplemente inyectar javascript simple con el controlador web y verificar? Este es el método que uso en mi clase de webscraper. El javascript es bastante básico incluso si no conoce 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
Cómo hacer que Selenium espere la carga de la página después de un clic proporciona el siguiente enfoque interesante:
WebElement
desde la página anterior.WebElement
hasta que StaleElementReferenceException
se lance.Código de muestra:
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))
.