【问题标题】:How to fix 'stale element reference exception' while trying to pick date from date-picker?尝试从日期选择器中选择日期时如何修复“陈旧元素引用异常”?
【发布时间】:2015-04-11 17:57:35
【问题描述】:

我正在尝试从 Datepicker 中选择日期。以下是代码

WebDriver d=new FirefoxDriver();
Actions a=new Actions(d);
String date="14";
d.get("http://www.eyecon.ro/bootstrap-datepicker/");
d.findElement(By.cssSelector("div#dp3>span")).click();
List<WebElement> trs=d.findElements(By.cssSelector("div.datepicker-days>table>tbody>tr"));
       for(WebElement tr:trs) {
            List<WebElement> tds=tr.findElements(By.tagName("td"));
            for(WebElement td:tds) {
                if(date.equals(td.getText())) {
                    a.moveToElement(td).click().build().perform();

                }
            }

}

使用上面的代码,我在这行代码中遇到了过时的元素引用异常

"if(date.equals(td.getText())) {"

所以我把代码改成了这个

for(WebElement td:tds) {
                while(i<4) {
                    try {
                        if(date.equals(td.getText())) {
                            a.moveToElement(td).click().build().perform();

                        }
                        break;
                    }catch(Exception ex) {

                    }
                    System.out.println(i);
                    i++;
                }
            }

现在我可以选择日期了。但是脚本仍然抛出过时的元素引用异常。脚本现在在这一行显示错误

List<WebElement> tds=tr.findElements(By.tagName("td"));

过去 3 天我一直在处理这个问题。关于如何解决这个问题的任何建议。 提前致谢

【问题讨论】:

标签: selenium selenium-webdriver webdriver


【解决方案1】:

在您的第一个代码中,单击元素后,DOM 发生了变化,因为 Date 变成了 "14",并且由于两个 for 循环仍在迭代,因此它抛出了 StaleElementReferenceException

同样,在第二个代码中,您确实打破了迭代 td 元素的 “inside for-loop”,但是您没有破坏 "outside" 一个,它继续迭代 tr 元素,因此它抛出 StaleElementReferenceException又一次。

解决方案:-您应该在单击元素后使用 break 退出两个 for 循环,因此 在此过程中避免 StaleElementReferenceException。

下面的代码展示了如何毫无例外地跳出两个 for 循环:

    WebDriver d=new FirefoxDriver();
    d.manage().window().maximize(); //Maximizing window
    d.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS); //Implicit wait for 20 seconds

    Actions a=new Actions(d);
    String date="14";
    int flag=0;

    d.get("http://www.eyecon.ro/bootstrap-datepicker/");
    d.findElement(By.cssSelector("div#dp3>span")).click();
    List<WebElement> trs=d.findElements(By.cssSelector("div.datepicker-days>table>tbody>tr"));
    for(WebElement tr:trs) {
        List<WebElement> tds=tr.findElements(By.tagName("td"));
        for(WebElement td:tds) {
            if(date.equals(td.getText())) {
                a.moveToElement(td).click().build().perform();
                flag=1; // Set to 1 when the required element was found and clicked.
                break; //To come out of the first for-loop
            }
        }
        if(flag==1)
            break; //Since the element was found, come out of the second for-loop.
    }

注意:-我已经添加了最大化窗口和提供隐式等待的代码,这实际上是在您编写 selenium 脚本时建议的。

【讨论】:

  • 非常感谢。你帮了我大忙,解决了这个问题。它奏效了
【解决方案2】:

您应该使用WebDriverWaitExpectedConditions 来解决元素的过时问题。下面是我测试过的修改后的代码块。

 driver.findElement(By.cssSelector("div#dp3>span")).click();
 WebDriverWait wait = new WebDriverWait(driver, 30);
 List<WebElement> trs = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector("div.datepicker-days>table>tbody>tr")));
 datePicker:
 {
    for (WebElement tr : trs) {
       List<WebElement> tds = tr.findElements(By.tagName("td"));
       for (WebElement td : tds) {
                 wait.until(ExpectedConditions.not(ExpectedConditions.stalenessOf(td)));
                 if (date.equals(td.getText())) {
                        td.click();
                        break datePicker;
                 }
        }
     }
 }

更多信息请查看WebDriverWaitExpectedConditions这里

【讨论】:

  • 感谢您的建议
  • Np。我无耻地说我仍然相信我的解决方案比接受的解决方案优雅:)
  • 这很优雅。但是在我接受的答案中,他对问题给出了明确的解释。所以这就是我接受其他答案的原因
  • @RachelD'cruz 我认为这很公平。我确实错过了,我认为命名的 for 块使解释很明显。
【解决方案3】:

找到了一种更简单的方法来解决我的过时元素引用异常。

在 Java 中使用 Selenium2 试试下面的代码:

 public WebElement cleanAndRebuildElement(final WebElement ee) {
        WebElement e2;
        try {
            e2=ee;
            e2.isDisplayed();
            logger.info("Element is cleaned : Not Stale Anymore !");
        } catch (StaleElementReferenceException e) {
              e2=null;

          
        } catch(NoSuchElementException nse) {
nse.printstacktrace(); 
          }
        return e2;
    }
}

【讨论】:

  • 这解决了我们得到陈旧元素引用异常的原因。使用 Page Factory web 元素的人发现很难破坏和重建元素,以便刷新。页面工厂在调用时总是重新获取元素。通过重新分配引用,我们强制 Page Factory 再次获取元素。此方法存在递归,请使用一些超时来打破循环。毕竟我们不希望出现无限循环的情况。
  • 这种方式确保元素的清理和重建可以通过通用功能进行,因此可以无缝实现。
【解决方案4】:

根据我的理解,当您在 for loop DOM 重新加载中执行 element.click() 时,这就是它显示陈旧元素异常的原因。 使用以下css选择器[它将仅从预期的日期选择器中选择元素,使用它,因为页面上有多个日期选择器]并在匹配日期上应用中断循环,如下所示。它将选择日期14并中断循环,无一例外 -

String date="14";
d.get("http://www.eyecon.ro/bootstrap-datepicker/");
d.findElement(By.cssSelector("div#dp3>span")).click();
List<WebElement> trs=d.findElements(By.cssSelector(".datepicker.dropdown-menu:nth-of-type(4)>div.datepicker-days>table>tbody>tr>td"));
     for(WebElement td:trs) {
         if(date.equals(td.getText())) {
            td.click();
            break;
         }
     }

【讨论】:

  • 感谢您的建议
猜你喜欢
  • 2019-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-09
  • 2020-02-05
相关资源
最近更新 更多