Selenium WebDriver StaleElementReferenceException

运行我的测试时出现此错误:org.openqa.selenium.StaleElementReferenceException:元素不再附加到DOM

关于如何解决上述exception的任何想法? 这发生在我的网格中,它有一个动态的ref Xpath表达式

我遇到了同样的问题,找不到任何解决方案。 提出一个解决方案,并将其发布在这里,希望这可以帮助有同样问题的人。 我创建了一个类来处理陈旧元素,具体取决于它们的类型,cssselector,id等,并简单地调用它,就像我任何其他页面对象一样。

public void StaleElementHandleByID (String elementID){ int count = 0; boolean clicked = false; while (count < 4 || !clicked){ try { WebElement yourSlipperyElement= driver.findElement(By.id(elementID)); yourSlipperyElement.click(); clicked = true; } catch (StaleElementReferenceException e){ e.toString(); System.out.println("Trying to recover from a stale element :" + e.getMessage()); count = count+1; } } 

我建议只在你知道导致WebDriver出现问题的元素上使用它。

我们通过做一些名为WebdriverWrapper和WebElementWrapper的事来解决这个问题。

这些包装器所做的是处理其中的StaleElementException,然后使用定位器重新评估并获取新的WebElement对象。 这样,您需要在代码库中传播处理exception的代码,并将其本地化为一个类。

我将很快研究这几个类的开源,如果你有兴趣,我会在这里添加一个链接。

当您尝试使用页面上不再存在的WebElement方法时,将引发该exception。 如果您的网格是动态加载数据并刷新网格,那么对该网格上元素的任何引用都将是“陈旧的”。 仔细检查您尝试引用的元素是否在测试的页面上,您可能需要重新实例化该对象。

它也遇到了这个问题,看起来非常明显的是模态面板加载处于竞争状态并一直等到超时。

我已经尝试了很多次,并且发现解决方案是保持模态面板加载,直到webDriver可以完全找到并同时保持刷新webDriver实例,然后尝试在模态面板中找到WebElements。

所以解决方案如下:例如MyModalPanel是你的ModalPanel Id,然后执行以下操作

 page.openModalPanel(); Assert.assertTrue(page.waitTillDisplay( "MyModalPanelContentDiv"), Wait.MODAL_PANEL)); page.fillInFormInModalpanel(formObj); 

并且可以在WebDriver网站上找到waitTillDisplay代码,我将在此处粘贴我的代码供您参考:

 public Boolean waitTillDisplay(final String id, int waitSeconds){ WebDriverWait wait = new WebDriverWait(driver, waitSeconds); Boolean displayed = wait.until(new ExpectedCondition() { public Boolean apply(WebDriver driver) { return driver.findElement(By.id(id)).isDisplayed(); } }); return displayed; 

}

单击元素后,您可能尝试获取任何元素属性。

我遇到了同样的问题,我点击了按钮后试图获取按钮的文本()。 在我的例子中,一旦点击按钮,就会出现新窗口。

我使用了FluentWait和ExpectedCondition应用覆盖: https ://gist.github.com/djangofan/5112655。 这个处理最终块内的exception,不像其他人回答这个问题,并允许连续的尝试包含在该块中。 我觉得这更优雅。

 public static void clickByLocator( final By locator ) { final long startTime = System.currentTimeMillis(); driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS ); Wait wait = new FluentWait( driver ) .withTimeout(90000, TimeUnit.MILLISECONDS) .pollingEvery(5500, TimeUnit.MILLISECONDS); //.ignoring( StaleElementReferenceException.class ); wait.until( new ExpectedCondition() { @Override public Boolean apply( WebDriver webDriver ) { try { webDriver.findElement( locator ).click(); return true; } catch ( StaleElementReferenceException e ) { // try again return false; } } } ); driver.manage().timeouts().implicitlyWait( DEFAULT_IMPLICIT_WAIT, TimeUnit.SECONDS ); long endTime = System.currentTimeMillis(); long totalTime = endTime - startTime; log("Finished click after waiting for " + totalTime + " milliseconds."); } 
 public static Boolean executeElementSendKeys (WebDriver driver, WebElement element, String sInputParameters) throws Exception { return (Boolean) executeElementMaster (driver, element, "sendKeys", sInputParameters, 30, true); } public static Boolean executeElementClear (WebDriver driver, WebElement element) throws Exception { return (Boolean) executeElementMaster (driver, element, "clear", "", 30, true); } public static String executeElementGetText (WebDriver driver, WebElement element) throws Exception { return (String) executeElementMaster (driver, element, "getText", "", 30, true); } public static Boolean executeElementClick (WebDriver driver, WebElement element) throws Exception { return (Boolean) executeElementMaster (driver, element, "click", "", 30, true); } public static boolean executeElementIsDisplayed (WebDriver driver, WebElement element) throws Exception { return (Boolean) executeElementMaster (driver, element, "isDisplayed", "", 30, true); } public static String executeElementGetAttribute (WebDriver driver, WebElement element, String sInputParameters) throws Exception { return (String) executeElementMaster (driver, element, "getAttribute", sInputParameters, 30, true); } 

//以下是处理StaleElementReferenceException和其他exception的主方法。

//在catch部分中,如果希望此方法仅StaleElementReferenceException而不是其他exception重试操作(如click,sendkeys等),则将(Exception e)替换为(StaleElementReferenceException e)

 private static Object executeElementMaster(WebDriver driver, WebElement element, String sExecuteAction, String sInputParametersOptional, int MaxTimeToWait, boolean bExpectedElementState) throws Exception { try { // Local variable declaration String sElementString = ""; String sElementXpath = ""; Object ReturnValue = ""; int Index = 0; boolean bCurrentElementState = true; boolean bWebDriverWaitUntilElementClickableFlag = false; System.out.println("**** Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Expected : '" + bExpectedElementState + "'"); System.out.println("**** MaxTimeToWait ='" + MaxTimeToWait + "' seconds"); // Set browser timeout to 1 second. Will be reset to default later driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS); // Keep trying until 'MaxTimeToWait' is reached for (int i = 0; i < MaxTimeToWait; i++) { try { // Get element xPath - and find element again if (element != null && i < 2 && sElementString == "") { 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 != "" && i > 0) { element = driver.findElement(By.xpath(sElementXpath)); } // Execute the action requested switch (sExecuteAction) { case ("isDisplayed"): // Check if element is displayed and save in bCurrentElementState variable ReturnValue = element.isDisplayed(); bCurrentElementState = (Boolean) ReturnValue; bWebDriverWaitUntilElementClickableFlag = true; break; case ("getText"): ReturnValue = element.getText(); bCurrentElementState = true; bWebDriverWaitUntilElementClickableFlag = false; break; case ("sendKeys"): // Scroll element into view before performing any action element.sendKeys(sInputParametersOptional); ReturnValue = true; bCurrentElementState = true; bWebDriverWaitUntilElementClickableFlag = false; break; case ("clear"): // Scroll element into view before performing any action element.clear(); ReturnValue = true; bCurrentElementState = true; bWebDriverWaitUntilElementClickableFlag = false; break; case ("click"): // Scroll element into view before performing any action element.click(); ReturnValue = true; bCurrentElementState = true; bWebDriverWaitUntilElementClickableFlag = false; break; default: ReturnValue = element.getAttribute(sInputParametersOptional); bCurrentElementState = true; break; } } catch (Exception e) { Thread.sleep(500); bCurrentElementState = false; ReturnValue = false; } if (bCurrentElementState == bExpectedElementState) { // If element's actual and expected states match, log result and return value System.out.println("**** PASSED: Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Returned '" + ReturnValue + "' **** \n" + "Actual element status: '" + bCurrentElementState + "' Expected element status: '" + bExpectedElementState + "'"); break; } else { // If element's actual and expected states do NOT match, loop until they match or timeout is reached Thread.sleep(500); } } // Reset browser timeout to default driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS); // Return value before exiting if (bCurrentElementState != bExpectedElementState) { // If element's actual and expected states do NOT match, log result and return value System.out.println("**** FAILED: Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Returned '" + ReturnValue + "' **** \n" + "Actual element status: '" + bCurrentElementState + "' Expected element status: '" + bExpectedElementState + "'"); if (sExecuteAction.equalsIgnoreCase("findElement")) { ReturnValue = null; } } return ReturnValue; } catch (Exception e) { System.out.println("Exception in executeElementMaster - " + e.getMessage()); throw (e); } } 

我做了一些更改以更灵活:

  delegate void StaleFunction(IWebElement elt); private static void StaleElementHandleByID(By by, StaleFunction func ) { int count = 0; while (count < 4) { try { IWebElement yourSlipperyElement = Driver.FindElement(by); func(yourSlipperyElement); count = count + 4; } catch (StaleElementReferenceException e) { count = count + 1; } } } 

  StaleElementHandleByID(By.Id("identDdl"), delegate(IWebElement elt) { SelectElement select = new SelectElement(elt); select.SelectByText(tosave.ItemEquipamentoCem.CodigoCne.ToString()); }); 

在这种情况下,测试正在查找尚未加载或已刷新的元素。 结果,StaleElementException。 一个简单的解决方案是添加一个fluentWait。

快速而肮脏的解决方案:

 el.click() time.sleep(1) 

然后继续以迭代方式解析