需要帮助处理StaleElementReferenceException

时间:2017-09-06 21:05:06

标签: selenium selenium-webdriver groovy geb

在我们开始之前,让我说我已经完成了对这个问题的研究,我已经看到了这里发布的解决方案:stale element solution one,我甚至想出了我自己的解决方案:My temporary solution我的解决方案的问题在于它并不适用于所有情况(特别是在处理.children()的长链时

我遇到的问题"过时的元素解决方案1"是它根本不是一个非常强大的解决方案。它只适用于你可以将你的Navigator元素实例化放在try catch中,但是如果你没有那个实例化,那么这个解决方案没有用。让我举一个我的意思的例子。

假设我有一个看起来像这样的Page类:

package interfaces

import geb.Page
import geb.navigator.Navigator
import org.openqa.selenium.By

class TabledPage extends Page {

    static content ={
        table {$(By.xpath("//tbody"))}
        headers {$(By.xpath("//thead"))}
    }

    Navigator getAllRows(){
        return table.children()
    }

    Navigator getRow(int index){
        return table.children()[index]
    }

    Navigator getRow(String name){
        return table.children().find{it.text().matches(~/.*\b${name}\b.*/)}
    }

    Navigator getColumn(Navigator row, int column){
        return row.children()[column]
    }


}

假设我的脚本中有一个方法可以执行“#st; stale element solution one"做(或多或少)。看起来像这样:

def staleWraper(Closure c, args = null, attempts = 5){
    def working = false
    def trys = 0
    while(!working){
        try{
            if(args){
                return c(args)
            }
            else{
                return c()
            }
        }
        catch(StaleElementReferenceException se){
            println("I caught me a stale element this many times: ${trys}")
            if(trys>attempts){
                working = true
                throw se
            }
            else{
                trys++
            }
        }
    }
}

您调用上述方法的方式是这样的(使用TabledPage作为示例:staleWrapper(TabledPage.&getRow, 5) //grabs the 4th row of the table

,这很正常,这很重要,getRow方法引用静态内容中的元素。引用静态内容元素时,将在运行时重新定义导航器。这就是为什么这个解决方案适用于getRow方法。 (表在try catch中重新实例化)

我的问题和抱怨"陈旧的元素解决方案之一"是这种类型的实现不适用于像getColumn这样的方法,这是因为getColumn不引用静态内容本身。我正在测试的Tabled页面上运行了javascript,每秒多次刷新DOM。因此,即使我使用staleWraper方法,无论尝试了多少次,它都会抛出一个陈旧的元素。

对此的一个解决方案是将列添加为页面的静态内容,但我想避免这种情况,因为它不会像我整个项目设置那样流动(我有很多Page对象,以与TabledPage类似的方式实现方法如果由我决定,有一种方法可以抑制staleElelementExcpetions,但这也不是一个选项。

我想知道是否有人在这里有一个创造性的解决方案Robustly(关键词在这里)处理StaleElementException,因为我认为循环尝试catch已经有点hacky。

2 个答案:

答案 0 :(得分:0)

好吧,我不确定我的解决方案是否能解决您的目的。在我的例子中,我使用Page Pattern来设计测试,因此Page class的每个方法都使用PageFactory来返回Page类的实例。例如,

public class GoogleSearchPage {
    // The element is now looked up using the name attribute
    @FindBy(how = How.NAME, using = "q")
    private WebElement searchBox;

    public SearchResultPage searchFor(String text) {
        // We continue using the element just as before
        searchBox.sendKeys(text);
        searchBox.submit();

        // Return page instance of SearchResultPage class
        return PageFactory.initElements(driver, SearchResultPage.class);
    }

    public GoogleSearchPage lookForAutoSuggestions(String text) {
    // Do something
    // Return page instance of itself as this method does not change the page
    return PageFactory.initElements(driver, GoogleSearchPage.class);
    } 
}

lookForAutoSuggestions可能抛出StaleElementException,返回页面实例时会这样做。因此,如果您正在使用页面类,那么理想情况下,每个页面方法都应该返回一个用户应该登陆的页面实例。

答案 1 :(得分:0)

我最终实现了类似于这个人给出的第三个选项":Look at the answer (option 3)

我需要对它进行更多测试但是我还没有得到过时的元素,因为我以这种方式实现它(关键是创建我自己的WebElement类然后覆盖Navigator类但使用NeverStaleWebElement对象而不是WebElement