Java Selenium fluentWait导致StaleElementReferenceException

Java Selenium fluentWait导致StaleElementReferenceException,java,eclipse,selenium,webdriver,Java,Eclipse,Selenium,Webdriver,我有一个场景,如下面的截图所示: 所以,我已经构建了一些代码,可以让我点击左边的条形图……每次我点击,它都会在右边显示一个关系条形图。如果左侧的条形图特别大,则右侧的关系条形图可能需要一段时间才能显示出来。为了解决这个问题,我构建了一个fluentWait方法,如下所示: public static void fluentWaitOnRelationalBarChartSelector(InternetExplorerDriver driver) { WebEl

我有一个场景,如下面的截图所示:

所以,我已经构建了一些代码,可以让我点击左边的条形图……每次我点击,它都会在右边显示一个关系条形图。如果左侧的条形图特别大,则右侧的关系条形图可能需要一段时间才能显示出来。为了解决这个问题,我构建了一个fluentWait方法,如下所示:

    public static void fluentWaitOnRelationalBarChartSelector(InternetExplorerDriver driver)
    {
        WebElement relationalBarSelect = (new WebDriverWait(driver, 20))
                .until(ExpectedConditions.elementToBeClickable(By.tagName("rect")));
        relationalBarSelect.click();
    }
Exception in thread "main" org.openqa.selenium.StaleElementReferenceException: Element is no longer valid
(WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 33 milliseconds
但是,不总是,但有时,我在控制台中遇到如下错误:

    public static void fluentWaitOnRelationalBarChartSelector(InternetExplorerDriver driver)
    {
        WebElement relationalBarSelect = (new WebDriverWait(driver, 20))
                .until(ExpectedConditions.elementToBeClickable(By.tagName("rect")));
        relationalBarSelect.click();
    }
Exception in thread "main" org.openqa.selenium.StaleElementReferenceException: Element is no longer valid
(WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 33 milliseconds
我不确定的是,当我应用了20秒的等待时,为什么会在33毫秒后发生此超时?有没有一种方法可以满足这个
StaleElementReferenceException


任何帮助都将不胜感激。

StaleElementReferenceException
是一个非常痛苦且非常特定于该元素的问题。这通常意味着该元素无法与selenium交互,因为您的设置中存在很多特定的问题。为了解决这个问题,人们使用了两种不同的机制(至少据我所知)
FluentWait
可能会救你一命。如下所示:

// Waiting 30 seconds for an element to be present on the page, checking
   // for its presence once every 5 seconds.
   Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
       .withTimeout(30, SECONDS)
       .pollingEvery(5, SECONDS)
       .ignoring(NoSuchElementException.class);

   WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
     public WebElement apply(WebDriver driver) {
       return driver.findElement(By.id("foo"));
     }
   });
//等待30秒,让元素出现在页面上,检查
//每5秒检查一次。
等待等待=新建FluentWait(驱动程序)
.带超时(30秒)
.每(5秒)轮询一次
.忽略(NoSuchElementException.class);
WebElement foo=wait.until(新函数(){
公共WebElement应用(WebDriver){
返回驱动程序findElement(By.id(“foo”);
}
});
摘自。值得一提的是,它允许您等待一个元素,同时忽略其他一些异常

如果这不起作用,那么估计一个循环的数量,这可能足以让该元素准备好进行交互。不是我最喜欢的,但很管用

public void StaleElementHandleByID (String elementID){
int count = 0; 
while (count < 4){
    try {
       WebElement yourSlipperyElement= driver.findElement(By.id(elementID));
       yourSlipperyElement.click(); 
     } catch (StaleElementReferenceException e){
       e.toString();
       System.out.println("Trying to recover from a stale element :" + e.getMessage());
       count = count+1;
     }
   count = count+4;
}
public void StaleElementHandleByID(字符串elementID){
整数计数=0;
而(计数<4){
试一试{
WebElement yourSlipperyElement=driver.findElement(By.id(elementID));
您的SlipperyElement.click();
}捕获(StaleElementReferenceException e){
e、 toString();
System.out.println(“试图从过时元素中恢复:+e.getMessage());
计数=计数+1;
}
计数=计数+4;
}

摘自

即使页面上没有任何明显的变化,页面加载后可能会有JavaScript等更改
Web元素
属性的内容。此JavaScript可能由脚本执行的前一个操作触发(例如:单击其他
Web元素

如果在WebElement的属性更改后尝试与WebElement交互(单击、sendkeys等),selenium将抛出一个
StaleElementReferenceException
。在这种情况下,您的代码应该多次重试该操作,而不是在第一次尝试时抛出一个异常,请参见下文

public static Boolean executeElementClick
  (WebDriver driver, WebElement element, int MaxTimeToWait) throws Exception {
    // Local variable declaration
    String sElementString = "";
    String sElementXpath = "";
    Boolean returnValue = false;
    int index = 0;

    // Set browser timeout to 1 second. Will be reset to default later
    driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);

    // Keep trying until 'MaxTimeToWait' is reached 
    for (int loop = 0; loop < MaxTimeToWait; loop++) {
        try {
            // Get element xPath - and find element again
            if (element != null && loop < 1 && sElementXpath.equals("")) {
                sElementString = (element).toString();
                if (sElementString.contains("xpath: ")) {
                    // Retrieve xPath from element, if available
                    index = sElementString.indexOf("xpath: ");
                    sElementXpath = sElementString
                                       .substring(index + 7, sElementString.length());
                }
            }

            // Find Element again
            if (!sElementXpath.equals("") && loop > 0) {
                element = driver.findElement(By.xpath(sElementXpath));
            }

            // Execute the action requested
            element.click();
            returnValue = true;

        } catch (Exception e) {
            Thread.sleep(1000);
            returnValue = false;
        }

        if (returnValue) {
            System.out.println("**** PASSED: Clicked on '" + sElementString + "'");
            break;
        }
    }
    // Reset browser timeout to default
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

    return returnValue;
}
publicstaticbooleaneexecuteelementclick
(WebDriver驱动程序、WebElement元素、int MaxTimeToWait)引发异常{
//局部变量声明
字符串sElementString=“”;
字符串sElementXpath=“”;
布尔返回值=false;
int指数=0;
//将浏览器超时设置为1秒。稍后将重置为默认值
driver.manage().timeouts().implicitlyWait(0,TimeUnit.SECONDS);
//继续尝试,直到达到“MaxTimeToWait”
for(int-loop=0;loop0){
element=driver.findElement(By.xpath(sElementXpath));
}
//执行请求的操作
元素。单击();
returnValue=true;
}捕获(例外e){
睡眠(1000);
returnValue=false;
}
如果(返回值){
System.out.println(“****已通过:单击“+sElementString+””);
打破
}
}
//将浏览器超时重置为默认值
driver.manage().timeouts().implicitlyWait(30,TimeUnit.SECONDS);
返回值;
}

只是一个更正@Andy。
FluentWait
是一类selenium java绑定,其机制与
WebDriverWait
不同,后者是
FluentWait
的一个子类。请参阅感谢提示,Saifur:-)不客气。尽管如此,请告诉我该解决方案是否有效。太棒了,Saifur,谢谢。它工作得很出色真的!