chrome selenium webdriver

chrome - Selenium WebDriver: la espera fluida funciona como se esperaba, pero la espera implícita no



selenium webdriver python (9)

A continuación se muestra el código de código equivalente para la espera de fluient en c # .Net usando DefaultWait.

IWait<IWebDriver> wait = new DefaultWait<IWebDriver>(driver); wait.Timeout = TimeSpan.FromSeconds(10); wait.PollingInterval = TimeSpan.FromMilliseconds(100); IWebElement elementt = wait.Until<IWebElement>(ExpectedConditions.ElementIsVisible(By.Id("selectedfirstlast1"))); SelectElement se = new SelectElement(driver.FindElement(By.Id("selectedfirstlast1"))); element = se.SelectedOption; if (element.Text.Contains("Mumbai") && element.Selected) driver.FindElement(By.XPath("//table/tbody/tr[2]/td[7]/a")).Click();

Soy nuevo en Selenium WebDriver y trato de entender la forma correcta de ''esperar'' a que los elementos estén presentes.

Estoy probando una página con un montón de preguntas que tienen respuestas de botón de opción. A medida que selecciona las respuestas, Javascript puede activar / desactivar algunas de las preguntas en la página.

El problema parece ser que Selenium está ''haciendo clic demasiado rápido'' y no esperando a que el Javascript termine. Intenté resolver este problema de dos maneras: las esperas explícitas resolvieron el problema. Específicamente, esto funciona y resuelve mi problema:

private static WebElement findElement(final WebDriver driver, final By locator, final int timeoutSeconds) { FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver) .withTimeout(timeoutSeconds, TimeUnit.SECONDS) .pollingEvery(500, TimeUnit.MILLISECONDS) .ignoring(NoSuchElementException.class); return wait.until(new Function<WebDriver, WebElement>() { public WebElement apply(WebDriver webDriver) { return driver.findElement(locator); } }); }

Sin embargo, preferiría usar una espera implícita en lugar de esto. Tengo mi controlador web configurado de esta manera:

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Esto no resuelve el problema y recibo una NoSuchElementException. Además, no noto una pausa de 10 segundos; simplemente se produce un error de inmediato. He verificado que esta línea en el código está siendo golpeada con un depurador. ¿Qué estoy haciendo mal? ¿Por qué implícitamente no espera a que aparezca el elemento, pero FluentWait sí?

Nota: Como mencioné, ya tengo un trabajo alternativo, realmente solo quiero saber por qué la espera implícita no resuelve mi problema. Gracias.


De Seleniumhq.com:

Una espera implícita es decirle a WebDriver que sondee el DOM durante un cierto período de tiempo cuando intente encontrar un elemento o elementos si no están disponibles de inmediato. La configuración predeterminada es 0. Una vez configurado, la espera implícita se establece para la vida de la instancia del objeto WebDriver.

Si publica su código de prueba lo que realmente desea hacer, puedo brindarle más información.


Escribí un pequeño método en C # usando la clase WebDriverWait. Funciona muy bien para mi

public static void WaitForAjaxElement(IWebDriver driver, By byElement, double timeoutSeconds) { WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutSeconds)); wait.Until(x => x.FindElement(byElement)); }

Utilizando:

WaitForAjaxElement(driver, By.ClassName("ui-menu-item"), 10);

Espero eso ayude.


Recuerde que hay una diferencia entre varios escenarios:

  • Un elemento que no está presente en absoluto en el DOM.
  • Un elemento presente en el DOM pero no visible.
  • Un elemento está presente en el DOM pero no está habilitado. (es decir, clicable)

Supongo que si parte de la página se muestra con javascript, los elementos ya están presentes en el navegador DOM, pero no son visibles. La espera implícita solo espera a que aparezca un elemento en el DOM, por lo que regresa inmediatamente, pero cuando intentas interactuar con el elemento obtienes una excepción NoSuchElementException. Puede probar esta hipótesis escribiendo un método auxiliar que explicita espera a que un elemento sea visible o se pueda hacer clic.

Algunos ejemplos (en Java):

public WebElement getWhenVisible(By locator, int timeout) { WebElement element = null; WebDriverWait wait = new WebDriverWait(driver, timeout); element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); return element; } public void clickWhenReady(By locator, int timeout) { WebDriverWait wait = new WebDriverWait(driver, timeout); WebElement element = wait.until(ExpectedConditions.elementToBeClickable(locator)); element.click(); }


Tengo otra solución para resolver este problema (solo para IE, nunca pruebo otro navegador):

1) después de crear la instancia del controlador Selenium, puede obtener su instancia ie COM

Add-Type -Path ./SePSX.NET35/WebDriver.dll $ieDriver = New-Object "OpenQA.Selenium.IE.InternetExplorerDriver" $ieShell = $null $shell_apps = (New-Object -ComObject Shell.Application).Windows() foreach($app in $shell_apps) { if ($app.LocationURL -eq $ieDriver.URL) { $ieShell = $app break } } if ($ieShell -eq $null) { throw "Can''t get WebDriver IE Instance" }

2) después de cada llamada GotoURL o haga clic en la acción, marque el estado $ ieShell.Busy, esperará hasta que se cargue la página.

$ieDriver.Navigate().GotoUrl("www.google.com") while ($ieShell.Busy -eq $true) {sleep 1} then call Selenium driver to get element id and do the further action $ieDriver.FindElementById ...

use de esta manera, no necesita configurar la carga de la página y findElement timeout para Selenium


Una versión de kotlin de la respuesta:

clickWhenReady("#suggest",10,driver)

vía

fun clickWhenReady(selector: String,timeout: Long, webdriver: WebDriver?) { val wait = WebDriverWait(webdriver, timeout); val element = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector(selector))); element.click(); }


la idea básica está en lo siguiente:

Espera explícita

WebDriverWait.until(condition-that-finds-the-element);

Espera implícita

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

En otras palabras, explícito se asocia con alguna condición que se mantendrá, mientras que está implícito con algo de tiempo para esperar algo. ver este enlace

Para hacer que el trabajo sea fluido, espere de manera adecuada, intente esto:

public WebElement fluentWait(final By locator){ Wait<WebDriver> wait = new FluentWait<WebDriver>(driver) .withTimeout(Duration.ofSeconds(30)) .pollingEvery(Duration.ofMillis(100)) .ignoring(NoSuchElementException.class); WebElement foo = wait.until( new Function<WebDriver, WebElement>() { public WebElement apply(WebDriver driver) { return driver.findElement(locator); } } ); return foo; };

Espero que esto ayude)


Palabra de advertencia por un error común:

Una vez que establezca la espera implícita, no podrá usar espera explícita o fluida hasta que restablezca nuevamente la espera implícita. Esto significa que ExpectedConditions , que contiene llamadas driver.findElement no funcionará como se espera con espera implícita. A menudo encontrará casos en los que desea verificar un elemento o su inexistencia al instante, pero tampoco puede hacer eso.

Después de ~ 2 años de experiencia y problemas con esto, recomiendo enfáticamente que no se use la espera implícita.


import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.FluentWait; import org.openqa.selenium.support.ui.Wait; FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver); wait.pollingEvery(250, TimeUnit.MILLISECONDS); wait.withTimeout(20, TimeUnit.SECONDS); wait.ignoring(NoSuchElementException.class); Predicate<WebDriver> predicate = new Predicate <WebDriver>() { public boolean apply(WebDriver arg0) { WebElement element = arg0.findElement(By.id("colorVar")); String color = element.getAttribute("color"); System.out.println("The color if the button is " + color); if(color.equals("blue")) { return true; } return false; } }; wait.until(predicate);