expectedconditions - selenium wait for page to load c#
El selenio espera hasta que el documento esté listo (24)
¿Alguien puede decirme cómo puedo hacer que el selenio espere hasta que la página se cargue por completo? Quiero algo genérico, sé que puedo configurar WebDriverWait y llamar algo así como ''find'' para hacerlo esperar, pero no voy tan lejos. Solo necesito probar que la página se carga correctamente y pasar a la siguiente página para probar.
Encontré algo en .net pero no pude hacerlo funcionar en Java ...
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"));
¿Alguna idea de alguien?
¿Estás usando Angular? Si lo es, es posible que el controlador de la web no reconozca que las llamadas asíncronas hayan finalizado.
Recomiendo mirar a Paul Hammants ngWebDriver . El método waitForAnularRequestsToFinish () podría ser útil.
Al igual que Rubanov escribió para C #, lo escribo para Java, y es:
public void waitForPageLoaded() {
ExpectedCondition<Boolean> expectation = new
ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return (((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete")&&((Boolean)((JavascriptExecutor)driver).executeScript("return jQuery.active == 0")));
}
};
try {
Thread.sleep(100);
WebDriverWait waitForLoad = new WebDriverWait(driver, 30);
waitForLoad.until(expectation);
} catch (Throwable error) {
Assert.fail("Timeout waiting for Page Load Request to complete.");
}
}
Aquí está mi intento de una solución completamente genérica, 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 en una página, incluido el elemento <html>
nivel superior. Cuando una página se actualiza o se carga, obtiene un nuevo elemento html con una nueva ID.
Por lo tanto, supongamos 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 más ayudante Pythonic, reutilizable y genérico, puedes crear 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 puedes usarlo en prácticamente 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 sobre esto aquí
Aquí hay algo similar, en Ruby:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { @driver.execute_script(''return document.readyState'').eql?(''complete'') }
Eche un vistazo al tapestry web-framework. Puede descargar el código fuente allí.
La idea es señalar que la página está lista por el atributo html del cuerpo. Puede usar esta idea para ignorar casos de sue complicados.
<html>
<head>
</head>
<body data-page-initialized="false">
<p>Write you page here</p>
<script>
$(document).ready(function () {
$(document.body).attr(''data-page-initialized'', ''true'');
});
</script>
</body>
</html>
Y luego crea la extensión de Selenium webdriver (de acuerdo con el marco tapiz)
public static void WaitForPageToLoad(this IWebDriver driver, int timeout = 15000)
{
//wait a bit for the page to start loading
Thread.Sleep(100);
//// In a limited number of cases, a "page" is an container error page or raw HTML content
// that does not include the body element and data-page-initialized element. In those cases,
// there will never be page initialization in the Tapestry sense and we return immediately.
if (!driver.ElementIsDisplayed("/html/body[@data-page-initialized]"))
{
return;
}
Stopwatch stopwatch = Stopwatch.StartNew();
int sleepTime = 20;
while(true)
{
if (driver.ElementIsDisplayed("/html/body[@data-page-initialized=''true'']"))
{
return;
}
if (stopwatch.ElapsedMilliseconds > 30000)
{
throw new Exception("Page did not finish initializing after 30 seconds.");
}
Thread.Sleep(sleepTime);
sleepTime *= 2; // geometric row of sleep time
}
}
Use la extensión ElementIsDisplayed escrita por Alister Scott .
public static bool ElementIsDisplayed(this IWebDriver driver, string xpath)
{
try
{
return driver.FindElement(By.XPath(xpath)).Displayed;
}
catch(NoSuchElementException)
{
return false;
}
}
Y finalmente crear prueba:
driver.Url = this.GetAbsoluteUrl("/Account/Login");
driver.WaitForPageToLoad();
Ejecuté un código de JavaScript para verificar si el documento está listo. Me ahorró mucho tiempo depurando las pruebas de selenio para los sitios que tienen representación del lado del cliente.
public static boolean waitUntilDOMIsReady(WebDriver driver) {
def maxSeconds = DEFAULT_WAIT_SECONDS * 10
for (count in 1..maxSeconds) {
Thread.sleep(100)
def ready = isDOMReady(driver);
if (ready) {
break;
}
}
}
public static boolean isDOMReady(WebDriver driver){
return driver.executeScript("return document.readyState");
}
El siguiente código probablemente debería funcionar:
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.presenceOfAllElementsLocated(By.xpath("//*")));
En Java le gustará a continuación:
private static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
En Nodejs puedes obtenerlo a través de 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 .
Esta es una versión de Java que funciona del ejemplo que usted dio:
void waitForLoad(WebDriver driver) {
new WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd ->
((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
}
Ejemplo para c #:
public static void WaitForLoad(this IWebDriver driver, int timeoutSec = 15)
{
WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec ));
wait.Until(wd => wd.ExecuteScript("return document.readyState") == "complete");
}
Intenté este código y me funciona. Llamo a esta función cada vez que me muevo a otra página
public static void waitForPageToBeReady()
{
JavascriptExecutor js = (JavascriptExecutor)driver;
//This loop will rotate for 100 times to check If page Is ready after every 1 second.
//You can replace your if you wants to Increase or decrease wait time.
for (int i=0; i<400; i++)
{
try
{
Thread.sleep(1000);
}catch (InterruptedException e) {}
//To check page ready state.
if (js.executeScript("return document.readyState").toString().equals("complete"))
{
break;
}
}
}
La espera del evento document.ready no es la solución completa a este problema, porque este código aún está en condición de carrera: a veces este código se activa antes de que se procese el evento click, por lo que esto regresa directamente, ya que el navegador no se ha iniciado cargando la nueva página todavía
Después de buscar, encontré una publicación en Obay the testing cabra , que tiene una solución para este problema. El código c # para esa solución es algo como esto:
IWebElement page = null;
...
public void WaitForPageLoad()
{
if (page != null)
{
var waitForCurrentPageToStale = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
waitForCurrentPageToStale.Until(ExpectedConditions.StalenessOf(page));
}
var waitForDocumentReady = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
waitForDocumentReady.Until((wdriver) => (driver as IJavaScriptExecutor).ExecuteScript("return document.readyState").Equals("complete"));
page = driver.FindElement(By.TagName("html"));
}
`Dispare este método directamente después de que el controlador.navigate.gotourl, de modo que obtenga una referencia de la página tan pronto como sea posible. ¡Diviértete con eso!
La respuesta de Ben Dryer no se compiló en mi máquina ( "The method until(Predicate<WebDriver>) is ambiguous for the type WebDriverWait"
).
Versión de trabajo Java 8:
Predicate<WebDriver> pageLoaded = wd -> ((JavascriptExecutor) wd).executeScript(
"return document.readyState").equals("complete");
new FluentWait<WebDriver>(driver).until(pageLoaded);
Versión de Java 7:
Predicate<WebDriver> pageLoaded = new Predicate<WebDriver>() {
@Override
public boolean apply(WebDriver input) {
return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete");
}
};
new FluentWait<WebDriver>(driver).until(pageLoaded);
La solución sugerida solo espera que DOM readyState
señal complete
. Pero Selenium de forma predeterminada intenta esperar esos (y un poco más) en la carga de la página a través de los driver.get()
y element.click()
. Ya están bloqueando, esperan que la página se cargue por completo y deberían funcionar bien.
El problema, obviamente, son los redireccionamientos a través de solicitudes de AJAX y la ejecución de scripts, los cuales no pueden ser capturados por Selenium, no espera a que terminen. Además, no puede atraparlos de manera confiable a través de readyState
: espera un poco, lo que puede ser útil, pero se señalizará complete
mucho antes de que se descargue todo el contenido de AJAX.
No existe una solución general que funcione en todos lados y para todos, por eso es difícil y todos usan algo un poco diferente.
La regla general es confiar en WebDriver para que haga su parte, luego use esperas implícitas, luego use esperas explícitas para los elementos que desea afirmar en la página, pero hay muchas más técnicas que se pueden hacer. Debe elegir uno (o una combinación de varios) que funcione mejor en su caso, en la página probada.
Vea mis dos respuestas sobre esto para más información:
- Cómo puedo verificar si la página está cargada por completo o no en el controlador web
- Selenium Webdriver: espere a que se cargue la página compleja con javascript
Para C # NUnit, debe convertir WebDriver a JSExecuter y luego ejecutar el script para verificar si el estado de document.ready está completo o no. Verifique el código a continuación para referencia:
public static void WaitForLoad(IWebDriver driver)
{
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
int timeoutSec = 15;
WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
}
Esto esperará hasta que se cumpla la condición o se agote el tiempo de espera.
Para la carga de la página inicial, he notado que "Maximizar" la ventana del navegador prácticamente espera hasta que se complete la carga de la página (incluidas las fuentes)
Reemplazar:
AppDriver.Navigate().GoToUrl(url);
Con:
public void OpenURL(IWebDriver AppDriver, string Url)
{
try
{
AppDriver.Navigate().GoToUrl(Url);
AppDriver.Manage().Window.Maximize();
AppDriver.SwitchTo().ActiveElement();
}
catch (Exception e)
{
Console.WriteLine("ERR: {0}; {1}", e.TargetSite, e.Message);
throw;
}
}
que uso:
OpenURL(myDriver, myUrl);
Esto cargará la página, esperará hasta que se complete, maximizará y se enfocará en ella. No sé por qué es así, pero funciona.
Si desea esperar la carga de la página después de hacer clic en Siguiente o cualquier otra navegación de la página desencadenar otro, entonces "Navegar ()", la respuesta de Ben Dyer (en este hilo) hará el trabajo.
Puede hacer que el hilo duerma hasta que la página se vuelva a cargar. Esta no es la mejor solución, ya que necesita un cálculo de cuánto tarda la página en cargarse.
driver.get(homeUrl);
Thread.sleep(5000);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(userName);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(passWord);
driver.findElement(By.xpath("Your_Xpath_here")).click();
Puedes escribir algo de lógica para manejar esto. He escrito un método que devolverá WebElement
y este método se llamará tres veces o puede aumentar el tiempo y agregar una verificación nula para WebElement
Aquí hay un ejemplo
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get("https://www.crowdanalytix.com/#home");
WebElement webElement = getWebElement(driver, "homekkkkkkkkkkkk");
int i = 1;
while (webElement == null && i < 4) {
webElement = getWebElement(driver, "homessssssssssss");
System.out.println("calling");
i++;
}
System.out.println(webElement.getTagName());
System.out.println("End");
driver.close();
}
public static WebElement getWebElement(WebDriver driver, String id) {
WebElement myDynamicElement = null;
try {
myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(By
.id(id)));
return myDynamicElement;
} catch (TimeoutException ex) {
return null;
}
}
Tuve un problema similar. Necesitaba esperar hasta que mi documento estuviera listo, pero también hasta que todas las llamadas Ajax hubieran terminado. La segunda condición demostró ser difícil de detectar. Al final revisé las llamadas activas de Ajax y funcionó.
Javascript:
return (document.readyState == ''complete'' && jQuery.active == 0)
Método completo de C #:
private void WaitUntilDocumentIsReady(TimeSpan timeout)
{
var javaScriptExecutor = WebDriver as IJavaScriptExecutor;
var wait = new WebDriverWait(WebDriver, timeout);
// Check if document is ready
Func<IWebDriver, bool> readyCondition = webDriver => javaScriptExecutor
.ExecuteScript("return (document.readyState == ''complete'' && jQuery.active == 0)");
wait.Until(readyCondition);
}
normalmente cuando selenio abre una nueva página desde un clic o envía u obtiene métodos, esperará a contar que la página está cargada, pero el problema es cuando la página tiene una llamada xhr (ajax) que nunca esperará a que cargue xhr, por lo que creando un nuevo método para monitorear un xhr y esperar por ellos será lo bueno. (perdón por mi mal inglés: D)
public boolean waitForJSandJQueryToLoad() {
WebDriverWait wait = new WebDriverWait(webDriver, 30);
// wait for jQuery to load
ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driver) {
try {
Long r = (Long)((JavascriptExecutor)driver).executeScript("return $.active");
return r == 0;
} catch (Exception e) {
LOG.info("no jquery present");
return true;
}
}
};
// wait for Javascript to load
ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor)driver).executeScript("return document.readyState")
.toString().equals("complete");
}
};
return wait.until(jQueryLoad) && wait.until(jsLoad);
}
if $ .active == 0 entonces no hay una llamada xhrs activa (que solo funciona con jQuery). para javascript ajax llame debe crear una variable en su proyecto y simularla.
Prueba este código:
driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);
El código anterior esperará hasta 10 segundos para cargar la página. Si la carga de la página excede el tiempo lanzará TimeoutException
. Capturas la excepción y haces tus necesidades. No estoy seguro de si sale de la carga de la página después de la excepción lanzada. No probé este código todavía. ¿Quieres simplemente probarlo?
Esta es una espera implícita. Si configura esto una vez, tendrá el alcance hasta que se destruya la instancia de Web Driver.
Para más info.
WebDriverWait wait = new WebDriverWait(dr, 30);
wait.until(ExpectedConditions.jsReturnsValue("return document.readyState==/"complete/";"));
public boolean waitForElement(String zoneName, String element, int index, int timeout) {
WebDriverWait wait = new WebDriverWait(appiumDriver, timeout/1000);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(element)));
return true;
}
public void waitForPageToLoad()
{
(new WebDriverWait(driver, DEFAULT_WAIT_TIME)).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return (((org.openqa.selenium.JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"));
}
});//Here DEFAULT_WAIT_TIME is a integer correspond to wait time in seconds