【问题标题】:Selenium WebDriver generates StaleElementReferenceExeption on getText() on table elementsSelenium WebDriver 在表元素的 getText() 上生成 StaleElementReferenceExeption
【发布时间】:2013-12-17 23:31:10
【问题描述】:

当前环境:

  • Selenium 服务器版本 2.37.0
  • 在 Firefox 上运行的 RemoteWebDriver
  • 没有 Ajax / 异步加载的内容

我的测试试图验证 HTML 表格的每个单元格的内容。在访问任何表格元素之前,显式等待会验证

元素是否存在
ExpectedCondition<WebElement> recruitTableIsPresent = ExpectedConditions.presenceOfElementLocated(By.id("newRecruitFieldAgentWidget:newRecruitDataTable_data"));
new WebDriverWait(driver, 5).until(recruitTableIsPresent);

一旦验证表存在,就按行列拉取数据

private Stats[] parseStats() {
    String xpath = "//tbody[@id='regionalFieldAgentWidget:regionalDataTable_data']/tr[%d]/td[%d]";
    Stats[] stats = new Stats[3];
    for (int i = 0; i < stats.length; i++) {
        String inProgresOrders = cellContent(xpath, i, 1);
        String maxCapacity = cellContent(xpath, i, 2);
        String allocationRatio = cellContent(xpath, i, 3);
        Stats[i] = new Stats(inProgressORders, maxCapacity, allocationRatio);
    }
    return stats;
}

private String cellContent(String xpathTemplate, int row, int cell) {
    String xpath = String.format(xpathTemplate, row + 1, cell + 1);
    new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(By.xpath(xpath)));
    WebElement elementByXPath = driver.findElementByXPath(xpath);
    return elementByXPath.getText();
}

我没有看到任何竞争条件,因为表格内容是由页面填充的,而不是在异步调用中。此外,我还看到其他建议通过驱动程序实例调用 findElement() 的答案将刷新缓存。最后,访问元素之前的显式等待应该确保

标签存在。

可能导致 getText() 方法返回以下异常的原因:

org.openqa.selenium.StaleElementReferenceException: 缓存中未找到元素 - 页面可能在查找后已更改

值得注意的是,故障是间歇性的。一些执行失败,而其他执行通过相同的代码传递。导致失败的表格单元格也不一致。

【问题讨论】:

  • 如果真的是竞态问题,请尝试使用 Thread.sleep(1000) 进行调试,否则唯一的问题可能与刷新元素缓存有关!
  • 我之前添加了一个 5 秒的显式等待,没有 until() 条件没有成功。我宁愿避免让线程休眠,但我会尝试一下
  • 原来有一个我一开始没有注意到的异步回发,这大大简化了问题。正如在类似问题中提到的那样,以下 sn-p 就像一个等待主动异步请求完成的魅力: (Long) jsContext.executeScript("return (window.jQuery || { active : 0 }).active");
  • 很好,您可以将其发布为答案并将其标记为已采取的解决方案!

标签: selenium selenium-webdriver


【解决方案1】:

有一个使用 Html-Agility-Pack 的解决方案。
这仅在您想从该页面读取数据时才有效。

这样就好了

//Convert the pageContent into documentNode.

void _getHtmlNode(IWebDriver driver){
    var htmlDocument = new HtmlDocument();
    htmlDocument.LoadHtml(driver.PageSource);
    return htmlDocument.DocumentNode;
}

private Stats[] parseStats(){
    String xpath = "//tbody[@id='regionalFieldAgentWidget:regionalDataTable_data']/tr[%d]/td[%d]";
    Stats[] stats = new Stats[3];
    for (int i = 0; i &lt; stats.Length; i++) {
        String inProgresOrders = cellContent(xpath, i, 1);
        String maxCapacity = cellContent(xpath, i, 2);
        String allocationRatio = cellContent(xpath, i, 3);
        Stats[i] = new Stats(inProgressORders, maxCapacity, allocationRatio);
    }
    return stats;
}

private String cellContent(String xpathTemplate, int row, int cell) {
    String xpath = String.format(xpathTemplate, row + 1, cell + 1);
    new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(By.xpath(xpath)));
    var documentNode = _getHtmlNode(driver);
    var elementByXPath = documentNode.SelectSingleNode(xpath);
    return elementByXPath.InnerText;
}

现在读取任何数据。

使用 htmlNode 的一些技巧。
1。类似于 driver.FindElement: document.SelectSingleNode
2。类似于 driver.FindElements: document.SelectNodes
3。类似于 driver.Text: document.InnerText.



更多关于 HtmlNode 的搜索。

【讨论】:

    【解决方案2】:

    事实证明,正如我已经提到的那样,存在竞争条件。由于 jQuery 可通过 PrimeFaces 获得,因此在其他几篇文章中提到了一个非常方便的解决方案。我实现了以下方法,在解析页面元素之前等待任何异步请求返回

    public static void waitForPageLoad(JavascriptExecutor jsContext) {
        while (getActiveConnections(jsContext) > 0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
    
    private static long getActiveConnections(JavascriptExecutor jsContext) {
        return (Long) jsContext.executeScript("return (window.jQuery || { active : 0 }).active");
    }
    

    每个内置驱动实现都实现了JavascriptExecutor接口,所以调用代码非常简单:

    WebDriver driver = new FirefoxDriver();
    waitForPageLoad((JavascriptExecutor) driver);
    

    【讨论】:

      猜你喜欢
      • 2011-12-21
      • 1970-01-01
      • 2013-07-26
      • 2018-10-23
      • 2014-09-08
      • 2017-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多