2010-11-06 3 views
9

Parfois, lors de l'exécution de tests sur WebDriver avec Javascript désactivé, WebDriver se bloque en raison d'une erreur ElementNotFound lorsqu'il trouve un élément et tente de cliquer dessus.API WebDriver Selenium: ElementNotFoundErrorException lorsque Element est clairement là!

Cependant, l'élément est clairement là!

Après avoir lu ceci: http://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_My_XPath_finds_elements_in_one_browser,_but_not_in_others._Wh

Je suis venu à la conclusion que WebDriver ne doit pas être en attente jusqu'à ce que la page Web a terminé chargé. Comment utiliser la classe Webdriver Wait? Quelqu'un peut-il donner un exemple?

Répondre

18

Cet exemple was posted on Google Groups. Selon les développeurs de Google:

1 Utilisez les attentes implicites. Dans ce cas, le chauffeur attend jusqu'à la fin de la temporisation jusqu'à ce que l'élément soit trouvé. Assurez-vous de lire le javadoc pour les mises en garde . Utilisation:

driver.get("http://www.google.com"); 
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); 
WebElement element = driver.findElement(By.name("q")); 
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); 
// continue with test... 

2 Utilisez la classe org.openqa.selenium.support.ui.WebDriverWait. Cela va interroger jusqu'à ce que la condition attendue soit vraie, retournant le résultat de cette condition (s'il recherche un élément). Ceci est beaucoup plus flexible que les attentes implicites , car vous pouvez définir n'importe quel comportement personnalisé. Utilisation:

Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) { 
    return new Function<WebDriver, WebElement>() { 
    public WebElement apply(WebDriver driver) { 
     return driver.findElement(locator); 
    } 
    }; 
} 

// ... 
driver.get("http://www.google.com"); 
WebDriverWait wait = new WebDriverWait(driver, /*seconds=*/3); 
WebElement element = wait.until(presenceOfElementLocated(By.name("q")); 
+1

Pouvez-vous expliquer "Function"? Il n'y a pas un tel objet appelé "Fonction" et se demandait si vous pouviez mieux le mettre en contexte? – djangofan

3

Prendre la réponse de Nilesh une étape supplémentaire, vous pouvez également permettre des recherches à l'écoute plus fines (par exemple, dans le cadre d'un WebElement) en utilisant l'interface SearchContext:

Function<SearchContext, WebElement> elementLocated(final By by) { 
    return new Function<SearchContext, WebElement>() { 
     public WebElement apply(SearchContext context) { 
      return context.findElement(by); 
     } 
    }; 
} 

L'exécution est effectuée par un FluentWait <SearchContext> instance (au lieu de WebDriverWait). Offrez-vous une interface de programmation agréable en enveloppant son exécution et la gestion des exceptions nécessaires dans une méthode utilitaire (la racine de votre hiérarchie de type PageObject est un bon endroit):

/** 
* @return The element if found before timeout, otherwise null 
*/ 
protected WebElement findElement(SearchContext context, By by, 
     long timeoutSeconds, long sleepMilliseconds) { 
    @SuppressWarnings("unchecked") 
    FluentWait<SearchContext> wait = new FluentWait<SearchContext>(context) 
      .withTimeout(timeoutSeconds, TimeUnit.SECONDS) 
      .pollingEvery(sleepMilliseconds, TimeUnit.MILLISECONDS) 
      .ignoring(NotFoundException.class); 
    WebElement element = null; 
    try { 
     element = wait.until(elementLocated(by)); 
    } 
    catch (TimeoutException te) { 
     element = null; 
    } 
    return element; 
} 

/** 
* overloaded with defaults for convenience 
*/ 
protected WebElement findElement(SearchContext context, By by) { 
    return findElement(context, by, DEFAULT_TIMEOUT, DEFAULT_POLL_SLEEP); 
} 

static long DEFAULT_TIMEOUT = 3;  // seconds 
static long DEFAULT_POLL_SLEEP = 500; // milliseconds 

Exemple d'utilisation:

WebElement div = this.findElement(driver, By.id("resultsContainer")); 
if (div != null) { 
    asyncSubmit.click(); 
    WebElement results = this.findElement(div, By.id("results"), 30, 500); 
    if (results == null) { 
     // handle timeout 
    } 
} 
+0

Votre exemple n'explique pas ce qu'est "elementLocated". – djangofan

+0

Oui, c'est le cas. C'est une méthode (définie dans mon premier bloc de code) qui renvoie une fonction, appelée à plusieurs reprises par FluentWait jusqu'à ce qu'un objet soit retourné, expiré ou qu'une exception non-ignorée soit levée (selon la première éventualité). –

0

Fluent Wait - Meilleure approche car elle est la plus flexible et la plus configurable à la volée (option ignore les exceptions, interrogation toutes les fois, timeout):

public Wait<WebDriver> getFluentWait() { 
    return new FluentWait<>(this.driver) 
      .withTimeout(driverTimeoutSeconds, TimeUnit.SECONDS) 
      .pollingEvery(500, TimeUnit.MILLISECONDS) 
      .ignoring(StaleElementReferenceException.class) 
      .ignoring(NoSuchElementException.class) 
      .ignoring(ElementNotVisibleException.class) 
} 

Utilisation comme ceci:

WebElement webElement = getFluentWait().until(x -> { return driver.findElement(elementBy); }); 

explicite Attendez - Eh bien, il est le même que FluentWait mais avec préconfiguré pollingEvery et le type d'attente par exemple FluentWait<WebDriver> (plus rapide à utiliser):

WebDriverWait wait = new WebDriverWait(driver, 30000); 
WebElement item = wait.until(ExpectedConditions.visibilityOfElementLocated(yourBy)); 

ImplicitWait - Non recommandé car il est configuré une fois pour toutes votre session. Ceci est également utilisé pour chaque élément de recherche et attend la présence seulement (pas ExpectedConditions etc ...):

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