Selenium C# WebDriver: espere hasta que el elemento esté presente

Resuelto AyKarsi asked hace 13 años • 30 respuestas

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...

AyKarsi avatar Aug 09 '11 14:08 AyKarsi
Aceptado

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();
Loudenvier avatar Sep 05 '2011 21:09 Loudenvier

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.

Mike Kwan avatar Aug 09 '2011 08:08 Mike Kwan

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

Zain Ali avatar Feb 28 '2013 18:02 Zain Ali

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);
    }
}
Rn222 avatar Apr 04 '2012 18:04 Rn222

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();
aknuds1 avatar Nov 08 '2012 14:11 aknuds1