Selenium WebDriver在表元素的getText()上生成StaleElementReferenceExep



当前环境:

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

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

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()将刷新缓存。最后,访问元素之前的显式等待应该确保<TD>标记存在。

是什么原因导致getText()方法返回以下异常:

org.openqa.selenium.StaleElementReferenceException:在缓存中找不到元素-也许页面在查找后发生了更改

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

有一个使用Html敏捷包的解决方案。
只有当您想从该页面读取数据时,这才会起作用。

这就像这个

//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。类似于驾驶员。FindElement:文档。选择单个节点
2。类似于驾驶员。FindElements:文档。选择节点
3。类似于驾驶员。文本:文档。InnerText。



有关HtmlNode的更多搜索。

正如我已经提到的那样,事实证明存在竞争条件。由于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);

最新更新