web-dev-qa-db-fra.com

Selenium WebDriver: attendre que l'élément soit présent lors de la localisation avec WebDriver.findElement est impossible

Il est pratique d'attendre qu'un WebElement soit présent avec WebDriverWait et ExpectedConditions.

Le problème est, et si WebElement.findElment Était le seul moyen possible de localiser l'élément, car il n'a ni id, ni nom, ni classe unique?

Le constructeur de WebDriverWait n'accepte que WebDriver comme arguments, pas WebElement.

J'ai réglé le temps implicitlyWait, donc il ne semble pas judicieux d'utiliser try{} catch(NoSuchElementException e){}, car je ne veux pas attendre aussi longtemps pour cet élément.

Voici le scénario:

Il existe une page Web avec un formulaire contenant de nombreuses balises input. Chaque balise input a une exigence de format.

Une balise div dynamique serait présente après cette balise input lorsque l'exigence de format n'est pas satisfaite.

Comme il y a tellement de balises input, je crée une méthode générale comme:

public WebElement txtBox(String name) {
    return driver.findElement(By.name(name));
}

au lieu de créer un membre de données pour chaque balise input.

Ensuite, je crée une méthode isValid pour vérifier si les entrées utilisateur dans certains input sont valides. Tout ce que je dois faire dans isValid est de vérifier si une balise div est présente après inputboxToCheck, avec un code comme celui-ci:

public boolean isValid(WebElement inputboxToCheck) {
    WebElementWait wait = new WebElementWait(inputboxToCheck, 1);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("./following-sibling::div")));
        return false;
    } catch (TimeOutException e) {
        return true;
    }    
}

WebElementWait est une classe imaginaire (qui n'existe pas) qui fonctionne de la même manière que WebDriverWait.

11
user2432405

La classe WebElementWait comme mentionné ci-dessus:

package org.openqa.Selenium.support.ui;

import Java.util.concurrent.TimeUnit;

import org.openqa.Selenium.NotFoundException;
import org.openqa.Selenium.WebElement;

public class WebElementWait  extends FluentWait<WebElement>  {
    public final static long DEFAULT_SLEEP_TIMEOUT = 500;

      public WebElementWait(WebElement element, long timeOutInSeconds) {
            this(element, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, DEFAULT_SLEEP_TIMEOUT);
      }

      public WebElementWait(WebElement element, long timeOutInSeconds, long sleepInMillis) {
            this(element, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, sleepInMillis);
      }

      protected WebElementWait(WebElement element, Clock clock, Sleeper sleeper, long timeOutInSeconds,
              long sleepTimeOut) {
            super(element, clock, sleeper);
            withTimeout(timeOutInSeconds, TimeUnit.SECONDS);
            pollingEvery(sleepTimeOut, TimeUnit.MILLISECONDS);
            ignoring(NotFoundException.class);
      }

}

C'est la même chose que WebDriverWait, sauf que l'argument WebDriver est remplacé par WebElement.

Ensuite, la méthode isValid:

//import com.google.common.base.Function;
    //import org.openqa.Selenium.TimeoutException;

public boolean isValid(WebElement e) {
    try {
        WebElementWait wait = new WebElementWait(e, 1);
        //@SuppressWarnings("unused")
        //WebElement icon = 
        wait.until(new Function<WebElement, WebElement>() {
                    public WebElement apply(WebElement d) {
                        return d.findElement(By
                                .xpath("./following-sibling::div[class='invalid-icon']"));
                    }
                });
        return false;
    } catch (TimeoutException exception) {
        return true;
    }
}
10
user2432405

Je ne sais pas si cela vous aide, mais cela permet d'attendre l'élément combien de temps voulez-vous.

public WebElement findDynamicElement(By by, int timeOut) {
    WebDriverWait wait = new WebDriverWait(driver, timeOut);
    WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
    return element;
}

findDynamicElement(By.xpath("//body") , 30);
9

Une variante plus universelle de la solution de user2432405 consisterait à utiliser le type SearchContext plutôt que WebElement:

public class SearchContextWait  extends FluentWait<SearchContext>  {
    ...

Cela permet de faire des attentes sur WebDriver et WebElement de la même manière car l'interface SearchContext est l'ancêtre de WebDriver et WebElement. La méthode isValid doit également être ajustée:

...
        WebElement icon = wait
                .until(new Function<SearchContext, WebElement>() {
                    public WebElement apply(SearchContext d) {
...

Malheureusement, vous perdez toutes les commodités des méthodes ExpectedConditions.xxxx () car elles utilisent l'interface WebDriver en interne.

4
Nik

J'ai trouvé ce blog: Recherche d'un élément - existe?, Visible?, Présent? - https://jkotests.wordpress.com/2012/11/02/checking-for-an-element-exists-visible-present/

Et cela a fait apparaître les différences entre ce qui existe, ce qui est visible et ce qui est présent.

  • existe? - Retourne si cet élément existe réellement.
  • présent? - Retourne vrai si l'élément existe et est visible sur la page
  • visible? - Si un élément parent n'est pas visible, nous ne pouvons pas écrire sur l'élément. Le seul moyen fiable de déterminer cela est d'itérer l'arborescence des éléments DOM en vérifiant chaque élément pour s'assurer qu'il est
    visible.

Exists vous dira si ce que vous recherchez se trouve n'importe où dans le DOM; cependant, WebDriver ne semble pas avoir de méthode intégrée pour vérifier si un élément existe similaire à plain driver.findElement(By.name(name)).

Et, comme expliqué dans le blog, Existe n'est pas la même chose que Présent . Je ne peux donc pas utiliser ExpectedConditions.presenceOfAllElementLocatedBy(By.cssSelector(cssSelector)

Ma solution: (recherche de retours ici :)

public WebElement waitForElementExists(String selector, String timeout) {
    Wait<WebDriver> wait = new WebDriverWait(driver, timeout);

    WebElement element = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver driver) {
            return driver.findElement(By.cssSelector(selector));
        }
    });

    return element;
 }
1
Eric Francis