web-dev-qa-db-fra.com

Selenium c # Webdriver: attendez que l'élément soit présent

Je veux m'assurer qu'un élément est présent avant que le WebDriver commence à faire des choses. 

J'essaie d'obtenir quelque chose comme ça pour fonctionner: 

WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,5));
wait.Until(By.Id("login"));

Je cherche principalement à configurer la fonction anynomous ..

154
AyKarsi

Sinon, vous pouvez utiliser l'attente implicite:

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);

Une attente implicite consiste à demander à WebDriver d'interroger le DOM pour obtenir un certain quantité de temps lorsque vous essayez de trouver un élément ou des éléments s’ils sont pas immédiatement disponible. Le paramètre par défaut est 0. Une fois défini, le fichier une attente implicite est définie pour la vie de l'instance d'objet WebDriver.

135
Mike Kwan

L'utilisation de la solution fournie par Mike Kwan peut avoir un impact sur les performances de test globales, car l'attente implicite sera utilisée dans tous les appels FindElement. Souvent, vous voudrez que FindElement échoue immédiatement lorsqu'un élément n'est pas présent (vous testez une page mal formée, des éléments manquants, etc.). Avec l'attente implicite, ces opérations attendraient l'expiration de tout le délai d'attente avant de lancer l'exception. L'attente implicite par défaut est définie sur 0 seconde.

J'ai écrit une petite méthode d'extension à IWebDriver qui ajoute un paramètre de délai d'attente (en secondes) à la méthode FindElement (). C'est assez explicite:

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);
    }
}

Je n'ai pas mis en cache l'objet WebDriverWait car sa création est très économique, cette extension peut être utilisée simultanément pour différents objets WebDriver et je n'effectue des optimisations qu'en cas de besoin. 

L'utilisation est simple:

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();
245
Loudenvier

Vous pouvez aussi utiliser 

ExpectedConditions.ElementExists

Vous allez donc rechercher une disponibilité d'élément comme celle-ci

new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementExists((By.Id(login))));

La source

79
Zain Ali

Voici une variante de la solution de @ Loudenvier qui fonctionne également pour obtenir plusieurs éléments:

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);
    }
}
27
Rn222

Inspiré par la solution de Loudenvier, voici une méthode d’extension qui fonctionne pour tous les objets ISearchContext, et pas seulement pour IWebDriver, qui est une spécialisation du premier. Cette méthode prend également en charge l’attente jusqu’à ce que l’élément soit affiché.

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;
        });
    }
}

Exemple d'utilisation:

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();
16
aknuds1

J'ai confondu n'importe quelle fonction avec le prédicat. Heres une petite méthode d'assistance:

   WebDriverWait wait;
    private void waitForById(string id) 
    {
        if (wait == null)            
            wait = new WebDriverWait(driver, new TimeSpan(0,0,5));

        //wait.Until(driver);
        wait.Until(d => d.FindElement(By.Id(id)));
    }
9
AyKarsi

Vous pouvez trouver quelque chose comme ça en C #. 

C'est ce que j'ai utilisé dans JUnit - Selenium 

WebDriverWait wait = new WebDriverWait(driver, 100);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));

Importer des paquets liés 

3
Aditi

Python:

from Selenium import webdriver
from Selenium.webdriver.support import expected_conditions as EC
from Selenium.webdriver.support.ui import WebDriverWait
from Selenium.webdriver.common.by import By

driver.find_element_by_id('someId').click()

WebDriverWait(driver, timeout).until(EC.presence_of_element_located((By.ID, 'someAnotherId'))

dans EC, vous pouvez également choisir d’autres conditions Essayez ceci: http://Selenium-python.readthedocs.org/api.html#module-Selenium.webdriver.support.expected_conditions

//wait up to 5 seconds with no minimum for a UI element to be found
WebDriverWait wait = new WebDriverWait(_pagedriver, TimeSpan.FromSeconds(5));
IWebElement title = wait.Until<IWebElement>((d) =>
{
    return d.FindElement(By.ClassName("MainContentHeader"));
});
2
Brian121212

La commande clickAndWait n'est pas convertie lorsque vous choisissez le format Webdriver dans l'EDI Selenium. Voici la solution de contournement. Ajoutez la ligne d'attente ci-dessous. En réalité, le problème était le clic ou l'événement survenu avant cette ligne-1 dans mon code C #. Mais en réalité, assurez-vous d’avoir un WaitForElement avant toute action faisant référence à un objet "By".

Code HTML:

<a href="http://www.google.com">xxxxx</a>

C #/NUnit code:

driver.FindElement(By.LinkText("z")).Click;
driver.WaitForElement(By.LinkText("xxxxx"));
driver.FindElement(By.LinkText("xxxxx")).Click();
2
MacGyver

Étant donné que je sépare les définitions d'éléments de page et les scénarios de test de page en utilisant IWebElement déjà trouvé pour la visibilité, procédez comme suit:

public static void WaitForElementToBecomeVisibleWithinTimeout(IWebDriver driver, IWebElement element, int timeout)
{
    new WebDriverWait(driver, TimeSpan.FromSeconds(timeout)).Until(ElementIsVisible(element));
}

private static Func<IWebDriver, bool> ElementIsVisible(IWebElement element)
{
    return driver => {
        try
        {
            return element.Displayed;              
        }
        catch(Exception)
        {
            // If element is null, stale or if it cannot be located
            return false;
        }
    };
}
1
Angel D

Attente explicite 

public static  WebDriverWait wait = new WebDriverWait(driver, 60);

Exemple:

wait.until(ExpectedConditions.visibilityOfElementLocated(UiprofileCre.UiaddChangeUserLink));
1
Pavan T

Essayez ce code: 

 New WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(Function(d) d.FindElement(By.Id("controlName")).Displayed)
1
Ammar Ben Hadj Amor

Vous ne voulez pas attendre trop longtemps avant que l'élément ne soit modifié. Dans ce code, le pilote Web attend jusqu'à 2 secondes avant de continuer.


 WebDriverWait wait = new WebDriverWait (pilote, TimeSpan.FromMilliseconds (2000)); 
 Wait.Until (ExpectedConditions.VisibilityOfAllElementsLocatedBy (By.Name ("nom_html")); 

1
user3607478
public bool doesWebElementExist(string linkexist)
{
     try
     {
        driver.FindElement(By.XPath(linkexist));
        return true;
     }
     catch (NoSuchElementException e)
     {
        return false;
     }
}
0
Madhu

Je vois plusieurs solutions déjà affichées qui fonctionnent très bien! Cependant, juste au cas où quelqu'un aurait besoin de quelque chose d'autre, j'ai pensé poster deux solutions que j'ai personnellement utilisées dans Selenium C # pour tester la présence d'un élément! J'espère que ça aide, à la vôtre! 

public static class IsPresent
{
    public static bool isPresent(this IWebDriver driver, By bylocator)
    {

        bool variable = false;
        try
        {
            IWebElement element = driver.FindElement(bylocator);
            variable = element != null;
        }
       catch (NoSuchElementException){

       }
        return variable; 
    }

}

Voici la seconde 

    public static class IsPresent2
{
    public static bool isPresent2(this IWebDriver driver, By bylocator)
    {
        bool variable = true; 
        try
        {
            IWebElement element = driver.FindElement(bylocator);

        }
        catch (NoSuchElementException)
        {
            variable = false; 
        }
        return variable; 
    }

}
0
newITguy

A utilisé Rn222 et Aknuds1 pour utiliser un ISearchContext qui renvoie un seul élément ou une liste. Et un nombre minimum d'éléments peut être spécifié:

public static class SearchContextExtensions
{
    /// <summary>
    ///     Method that finds an element based on the search parameters within a specified timeout.
    /// </summary>
    /// <param name="context">The context where this is searched. Required for extension methods</param>
    /// <param name="by">The search parameters that are used to identify the element</param>
    /// <param name="timeOutInSeconds">The time that the tool should wait before throwing an exception</param>
    /// <returns> The first element found that matches the condition specified</returns>
    public static IWebElement FindElement(this ISearchContext context, By by, uint timeOutInSeconds)
    {
        if (timeOutInSeconds > 0)
        {
            var wait = new DefaultWait<ISearchContext>(context);
            wait.Timeout = TimeSpan.FromSeconds(timeOutInSeconds);
            return wait.Until<IWebElement>(ctx => ctx.FindElement(by));
        }
        return context.FindElement(by);
    }
    /// <summary>
    ///     Method that finds a list of elements based on the search parameters within a specified timeout.
    /// </summary>
    /// <param name="context">The context where this is searched. Required for extension methods</param>
    /// <param name="by">The search parameters that are used to identify the element</param>
    /// <param name="timeoutInSeconds">The time that the tool should wait before throwing an exception</param>
    /// <returns>A list of all the web elements that match the condition specified</returns>
    public static IReadOnlyCollection<IWebElement> FindElements(this ISearchContext context, By by, uint timeoutInSeconds)
    {

        if (timeoutInSeconds > 0)
        {
            var wait = new DefaultWait<ISearchContext>(context);
            wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
            return wait.Until<IReadOnlyCollection<IWebElement>>(ctx => ctx.FindElements(by));
        }
        return context.FindElements(by);
    }
    /// <summary>
    ///     Method that finds a list of elements with the minimum amount specified based on the search parameters within a specified timeout.<br/>
    /// </summary>
    /// <param name="context">The context where this is searched. Required for extension methods</param>
    /// <param name="by">The search parameters that are used to identify the element</param>
    /// <param name="timeoutInSeconds">The time that the tool should wait before throwing an exception</param>
    /// <param name="minNumberOfElements">
    ///     The minimum number of elements that should meet the criteria before returning the list <para/>
    ///     If this number is not met, an exception will be thrown and no elements will be returned
    ///     even if some did meet the criteria
    /// </param>
    /// <returns>A list of all the web elements that match the condition specified</returns>
    public static IReadOnlyCollection<IWebElement> FindElements(this ISearchContext context, By by, uint timeoutInSeconds, int minNumberOfElements)
    {
        var wait = new DefaultWait<ISearchContext>(context);
        if (timeoutInSeconds > 0)
        {
            wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
        }

        // Wait until the current context found the minimum number of elements. If not found after timeout, an exception is thrown
        wait.Until<bool>(ctx => ctx.FindElements(by).Count >= minNumberOfElements);

        //If the elements were successfuly found, just return the list
        return context.FindElements(by);
    }

}

Exemple d'utilisation:

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost");
var main = driver.FindElement(By.Id("main"));
// It can be now used to wait when using elements to search
var btn = main.FindElement(By.Id("button"),10);
btn.Click();
//This will wait up to 10 seconds until a button is found
var button = driver.FindElement(By.TagName("button"),10)
//This will wait up to 10 seconds until a button is found, and return all the buttons found
var buttonList = driver.FindElements(By.TagName("button"),10)
//This will wait for 10 seconds until we find at least 5 buttons
var buttonsMin= driver.FindElements(By.TagName("button"), 10, 5);
driver.Close();
0
havan

WebDriverWait ne prendra pas effet.

var driver = new FirefoxDriver(
    new FirefoxOptions().PageLoadStrategy = PageLoadStrategy.Eager
);
driver.Navigate().GoToUrl("xxx");
new WebDriverWait(driver, TimeSpan.FromSeconds(60))
    .Until(d => d.FindElement(By.Id("xxx"))); // a tag that close to the end

Cela lève immédiatement une exception lorsque la page est "interactive". Je ne sais pas pourquoi mais le timeout agit comme s'il n'existait pas.

SeleniumExtras.WaitHelpers fonctionne peut-être mais je n'ai pas essayé. C'est officiel mais il a été divisé en un autre paquet de pépites. Vous pouvez vous référer à C # Selenium 'ExpectedConditions est obsolète' .

Moi-même utilise FindElements et vérifie si Count == 0, si vrai, utilise await Task.Delay. Ce n'est vraiment pas très efficace.

0
imba-tjd

Nous pouvons y arriver comme ceci:

public static IWebElement WaitForObject(IWebDriver DriverObj, By by, int TimeOut = 30)
{
    try
    {
        WebDriverWait Wait1 = new WebDriverWait(DriverObj, TimeSpan.FromSeconds(TimeOut));
        var WaitS = Wait1.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.PresenceOfAllElementsLocatedBy(by));
        return WaitS[0];
    }
    catch (NoSuchElementException)
    {
        Reports.TestStep("Wait for Element(s) with xPath was failed in current context page.");
        throw;
    }
}
0
Krunal

This is the reusable function to wait for an element present in DOM using Explicit Wait. Public void WaitForElement(IWebElement element, int timeout = 2){ WebDriverWait wait = new WebDriverWait(webDriver, TimeSpan.FromMinutes(timeout)); wait.IgnoreExceptionTypes(typeof(NoSuchElementException)); wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException)); wait.Until<bool> (driver => { try { return element.Displayed; } catch(Exception) { return false; } }); }

0
Balakrishna