Selenium WebDriver 显式等待

3

我正在编写一些使用selenium chrome driver的自动化测试。我试图编写一个可重用的方法,该方法将显式等待元素出现,然后在其他类中调用此方法。看起来很简单,但它没有做我想要的事情。这是我拥有的方法。

public String waitForElement(String item) {
    WebDriverWait wait = new WebDriverWait(driver,30);
    WebElement element = wait.until(
                        ExpectedConditions.elementToBeClickable(By.id(item)));
    return item;
}

然后我调用这个方法,并像这样传递一个参数:

waitForElement("new-message-button");

那似乎不起作用,有人能提供一些见解吗?

你确定要返回“item”吗?当我写这样的代码时,我想要的是你代码中命名为“element”的东西。 - Louis
你确定在DOM中只有一个该ID的元素吗?另外,如果你调试代码,element是否被找到了? - anotherdave
你怎么知道它不等待?你设置了断点并调试过吗?代码看起来没问题,我真的不相信它“不等待”而“不工作”。它是否抛出超时异常?如果是,什么时候?多久之后?为什么要返回你传入的相同字符串?这毫无意义。 - Arran
@Arran,我更新了代码以返回元素。我已经调试了代码,并且它确实将ID传递到方法中,只是没有应用等待。它不会超时,但如果失败,则会返回此错误org.openqa.selenium.WebDriverException:未知错误:元素在点(573,181)处不可点击。 - vslat
@vslat 稍等,你的方法是在调用时抛出异常,还是在尝试单击结果元素时抛出异常?如果是后者,WebDriver肯定正在等待该元素。在预期条件的上下文中,“可单击”意味着“它是否可见和启用”。除了元素不可见或未启用(主要涉及无法将元素滚动到视口之外),可能还有其他原因导致元素无法单击。 - JimEvans
显示剩余4条评论
7个回答

1

您可以使用显式等待或流畅等待

显式等待的示例 -

WebDriverWait wait = new WebDriverWait(WebDriverRefrence,20);
WebElement aboutMe;
aboutMe= wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("about_me")));
流畅等待的示例 -
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)                            
.withTimeout(20, TimeUnit.SECONDS)          
.pollingEvery(5, TimeUnit.SECONDS)          
.ignoring(NoSuchElementException.class);    

  WebElement aboutMe= wait.until(new Function<WebDriver, WebElement>() {       
public WebElement apply(WebDriver driver) { 
return driver.findElement(By.id("about_me"));     
 }  
});

检查这个TUTORIAL以获取更多细节。

请查看以下网址以获得有关隐式等待和显式等待的详细解释:http://elementalselenium.com/tips/47-waitinghttp://elementalselenium.com/tips/23-dynamic-pages - vikramvi

1
public static void clickOn(WebDriver driver, WebElement locator, int timeout)
 {
        new WebDriverWait(driver,timeout).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(locator));
        locator.click();

    }

在主方法中调用上述方法,然后我们将获得显式等待功能。

0

你的问题在于你将字符串传递给了方法参数:

public String waitForElement(String item) {

你需要传递你的WebElement,类似这样:

public boolean visibilityOfElementWait(WebElement webElement) {
    if (webElement != null) {
        try {
            WebDriverWait wait = new WebDriverWait(Driver.getCurrentDriver(), 20);
            wait.until(ExpectedConditions.visibilityOf(wrappedElement));
            highlightElement(webElement);
            return true;
        } catch (Exception e) {
            return false;
        }
    } else
        Logger.logError("PageElement " + webElement.getText() + " not exist");
    return false;
}

public void highlightElement(WebElement element) {
    if (!Config.getProperty(Config.BROWSER).equalsIgnoreCase("ANDROIDHYBRID")) {

        String bg = element.getCssValue("backgroundColor");

        for (int i = 0; i < 4; i++) {
            Driver.getDefault()
                    .executeScript("arguments[0].style.backgroundColor = 'red'", element);
            Driver.getDefault()
                    .executeScript("arguments[0].style.backgroundColor = '" + bg + "'", element);
        }

   //            String highlightElementScript = "arguments[0].style.backgroundColor = 'red';";
   //            Driver.getDefault().executeScript(highlightElementScript, element);
    }
}

0
我们可以自己开发隐式等待。
使用这段代码,它应该和隐式等待的功能一样。
//=== Start of Implicit Wait Statement ===

public void implicit_Wait_ID(String str) throws Exception{

        for(int i=0;i<60;i++){
            try{
                driver.findElement(By.id(str)).isDisplayed();
                break;
            }catch(Exception e){Thread.sleep(2000);

            }   
        }
}
//=== End of Implicit Wait Statement ===    

通过传递ID值使用此方法:

public void loginGmail() throws Exception
{
        driver.findElement(By.id("Email")).sendKeys("Mail ID");
        driver.findElement(By.id("next")).click();
        implicit_Wait_ID("Passwd");
        driver.findElement(By.id("Passwd")).sendKeys("Pwd value");
        driver.findElement(By.id("signIn")).click();
}

如果是Xpath或LinkText,只需为所有定位器类型创建上述方法之一,并在脚本中重复使用n次。

0
我以以下方式为我的Selenium测试编写了一个显式等待:
我使用@ FindBy注释声明要查找的WebElement,并引用Id,如下所示:
@FindBy(how = How.ID, using = "home")
private WebElement home;

那么,我等待元素加载的方法如下所示:

public WebElement isElementLoaded(WebElement elementToBeLoaded) {
    WebDriverWait wait = new WebDriverWait(driver, 15);
    WebElement element = wait.until(ExpectedConditions.visibilityOf(elementToBeLoaded));
    return element;
}

这使我能够通过名称引用任何我已经使用find by注释标记的元素,而不管使用的@FindBy方法是什么。


1
更正一下,这是一个显式等待的例子,而不是隐式等待。很好的例子。 - mrfreester

0

只需使用这个方法。我希望它能完美地工作。

public void waitForElement(String item) {
    WebDriverWait wait = new WebDriverWait(driver,30);
    WebElement element =  wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("item")));
}

然后调用该方法:

waitForElement("new-message-button");

-1

我使用Selenium构建了一个包,等待是我遇到的最大问题之一。最终,如上所述的方法不起作用。我不得不采取一种简单的隐式等待方式来等待任何动态元素,如下所述:

隐式等待是告诉WebDriver在尝试查找元素或元素时,在DOM中轮询一定时间,如果它们不立即可用。默认设置为0。一旦设置,隐式等待将设置为WebDriver对象实例的生命周期。

代码:

WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = driver.findElement(By.id("myDynamicElement"));

src

希望这有所帮助。

我尝试使用它,但不清楚如何根据特定元素ID使Web驱动程序等待。例如,您可以将其编写为方法吗? - vslat
如上所述,隐式等待持续整个驱动程序元素的生命周期。如果您在方法开始时设置driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);则驱动程序将等待该方法中尝试查找的每个元素10秒钟。 - drunkel
明白了,我也试过了,但不起作用。还是谢谢你的帮助。 - vslat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接