Java Selenium WebDriver StaleElementReferenceException

Java Selenium WebDriver StaleElementReferenceException,java,testing,selenium,webdriver,Java,Testing,Selenium,Webdriver,我在运行测试时遇到此错误: org.openqa.selenium.StaleElementReferenceException:元素不再附加到DOM 关于如何解决上述异常有什么想法吗? 这发生在我的网格中 它有一个ref Xpath表达式,它是动态的,当您尝试使用页面上不再存在的WebElement方法时,会引发该异常。如果您的网格正在动态加载数据,并且您刷新了网格,那么对该网格上元素的任何引用都将是“过时的”。仔细检查您试图引用的元素是否在测试页面上,您可能需要重新实例化该对象。我们通过执行

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

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

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

我们通过执行称为WebDriverRapper和WebElementWrapper的操作来解决此问题

这些包装器所做的是在中处理StaleElementException,然后使用定位器重新计算并获取新的WebElement对象。这样,您需要将处理异常的代码分散到整个代码库中,并将其本地化到一个类中


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

我遇到了同样的问题,但找不到任何解决方案。提出了一个解决方案并发布在这里,希望这能帮助有同样问题的人。我创建了一个类来根据过时元素的类型、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;
        }
    }
}
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;
}
}
}

我建议只在您知道会导致WebDriver出现问题的元素上使用此选项。

它也遇到了此问题,很明显,模态面板加载陷入竞争状态,并一直等待到超时

我已经尝试了很多次,发现解决方案是保持模态面板加载,直到webDriver能够准确地找到它,同时保持刷新webDriver实例,然后尝试在模态面板中查找WebElements

因此,解决方案如下所示: e、 g.MyModalPanel是您的ModalPanel Id,然后执行以下操作

page.openModalPanel();
Assert.assertTrue(page.waitTillDisplay( "MyModalPanelContentDiv"), Wait.MODAL_PANEL));
page.fillInFormInModalpanel(formObj);
而waitTillDisplay代码可以在WebDriver网站上找到,我会将我的代码粘贴到这里供您参考:

public Boolean waitTillDisplay(final String id, int waitSeconds){

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

        });
        return displayed;
public Boolean waitTillDisplay(最终字符串id,int waitSeconds){
WebDriverWait wait=新的WebDriverWait(驱动程序,等待秒);
显示布尔值=等待.until(新的ExpectedCondition(){
公共布尔应用(WebDriver驱动程序){
返回driver.findElement(By.id(id)).isDisplayed();
}
});
返回显示;

}

为了更灵活,我做了一些更改:

   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;
                }

            }
        }

快速而肮脏的解决方案:

el.click()

time.sleep(1)

然后继续以迭代的方式进行解析

单击某个元素后,您可能试图获取任何元素属性


我也有同样的问题,我试图在点击按钮后获取按钮的text()。在我的例子中,一旦单击按钮,新窗口就会出现。

我使用了FluentWait和ExpectedCondition应用覆盖:。与其他人回答此问题的方式不同,此方法在最终确定的块内处理异常,并允许在该块中包装连续的尝试。我觉得这个更优雅

public static void clickByLocator( final By locator ) {
  final long startTime = System.currentTimeMillis();
  driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
  Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
        .withTimeout(90000, TimeUnit.MILLISECONDS)
        .pollingEvery(5500, TimeUnit.MILLISECONDS);
        //.ignoring( StaleElementReferenceException.class );        
  wait.until( new ExpectedCondition<Boolean>() { 
    @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 void clickByLocator(最终由定位器确定){
最终长启动时间=System.currentTimeMillis();
driver.manage().timeouts().implicitlyWait(5,TimeUnit.SECONDS);
等待等待=新建FluentWait(驱动程序)
.withTimeout(90000,时间单位为毫秒)
.pollingEvery(5500,时间单位为毫秒);
//.忽略(StaleElementReferenceException.class);
等待.until(新的ExpectedCondition(){
@凌驾
公共布尔应用(WebDriver WebDriver){
试一试{
webDriver.findElement(定位器)。单击();
返回true;
}捕获(StaleElementReferenceException e){//重试
返回false;
}     
} 
} );      
driver.manage().timeouts().implicitlyWait(默认值\u IMPLICIT\u WAIT,TimeUnit.SECONDS);
long-endTime=System.currentTimeMillis();
长总时间=结束时间-开始时间;
日志(“等待“+totalTime+”毫秒后完成单击”);
}

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

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
和其他异常的主方法

//在catch部分,如果希望此方法仅对
StaleElementReferenceException
而不是其他异常重试操作(如单击、发送键等),请将
(异常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);
    }
}
私有静态对象executeElementMaster(WebDriver驱动程序、WebElement元素、String SexecutAction、String sInputParametersOptional、int MaxTimeToWait、,
布尔值beExpectedElementState)引发异常{
试一试{
//局部变量声明
字符串sElementString=“”;
字符串sElementXpath=“”;
对象返回值=”;
int指数=0;
布尔bCurrentElementState=true;
布尔值bWebDriverWituntileLementClickableFlag=false;
System.out.println(“**Execute method””+sexecutAction+“'on”“+sElementString+”)-应为“+beExpectedElementState+””;
系统
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);
    }
}
 //.. (first page asserts)
 //...
 element.Click();   
 Thread.Sleep(200);
 //.. (second page asserts)
 //...