Selenium C# WebDriver: espere hasta que el elemento esté presente
Quiero asegurarme de que haya un elemento presente antes de que el controlador web comience a hacer cosas.
Estoy intentando que algo como esto funcione:
WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, 5));
wait.Until(By.Id("login"));
Principalmente estoy luchando con cómo configurar la función anónima...
El uso de la solución proporcionada por Mike Kwan puede tener un impacto en el rendimiento general de las pruebas, ya que la espera implícita se utilizará en todas las llamadas a FindElement.
Muchas veces querrás que FindElement falle de inmediato cuando un elemento no esté presente (estás probando una página con formato incorrecto, elementos faltantes, etc.). Con la espera implícita, estas operaciones esperarían a que expire todo el tiempo de espera antes de generar la excepción. La espera implícita predeterminada se establece en 0 segundos.
Escribí un pequeño método de extensión para IWebDriver que agrega un parámetro de tiempo de espera (en segundos) al FindElement()
método. Se explica por sí mismo:
public static class WebDriverExtensions
{
public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
{
if (timeoutInSeconds > 0)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
return wait.Until(drv => drv.FindElement(by));
}
return driver.FindElement(by);
}
}
No almacené en caché el objeto WebDriverWait porque su creación es muy económica, esta extensión se puede usar simultáneamente para diferentes objetos WebDriver y solo hago optimizaciones cuando finalmente es necesario.
El uso es sencillo:
var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost/mypage");
var btn = driver.FindElement(By.CssSelector("#login_button"));
btn.Click();
var employeeLabel = driver.FindElement(By.CssSelector("#VCC_VSL"), 10);
Assert.AreEqual("Employee", employeeLabel.Text);
driver.Close();
Alternativamente puedes usar una espera implícita:
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
Una espera implícita es decirle a WebDriver que sondee el DOM durante un cierto período de tiempo cuando intenta encontrar un elemento o elementos si no están disponibles de inmediato. La configuración predeterminada es 0. Una vez establecida, la espera implícita se establece durante la vida de la instancia del objeto WebDriver.
También puedes usar
Condiciones esperadas.ElementExists
Entonces buscarás la disponibilidad de un elemento como ese.
new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementExists((By.Id(login))));
Fuente
Aquí hay una variación de la solución de Loudenvier que también funciona para obtener múltiples elementos:
public static class WebDriverExtensions
{
public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
{
if (timeoutInSeconds > 0)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
return wait.Until(drv => drv.FindElement(by));
}
return driver.FindElement(by);
}
public static ReadOnlyCollection<IWebElement> FindElements(this IWebDriver driver, By by, int timeoutInSeconds)
{
if (timeoutInSeconds > 0)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
return wait.Until(drv => (drv.FindElements(by).Count > 0) ? drv.FindElements(by) : null);
}
return driver.FindElements(by);
}
}
Inspirado en la solución de Loudenvier , aquí hay un método de extensión que funciona para todos los objetos ISearchContext, no solo para IWebDriver, que es una especialización del primero. Este método también admite esperar hasta que se muestre el elemento.
static class WebDriverExtensions
{
/// <summary>
/// Find an element, waiting until a timeout is reached if necessary.
/// </summary>
/// <param name="context">The search context.</param>
/// <param name="by">Method to find elements.</param>
/// <param name="timeout">How many seconds to wait.</param>
/// <param name="displayed">Require the element to be displayed?</param>
/// <returns>The found element.</returns>
public static IWebElement FindElement(this ISearchContext context, By by, uint timeout, bool displayed=false)
{
var wait = new DefaultWait<ISearchContext>(context);
wait.Timeout = TimeSpan.FromSeconds(timeout);
wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
return wait.Until(ctx => {
var elem = ctx.FindElement(by);
if (displayed && !elem.Displayed)
return null;
return elem;
});
}
}
Uso de ejemplo:
var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost");
var main = driver.FindElement(By.Id("main"));
var btn = main.FindElement(By.Id("button"));
btn.Click();
var dialog = main.FindElement(By.Id("dialog"), 5, displayed: true);
Assert.AreEqual("My Dialog", dialog.Text);
driver.Close();