在我们开始之前,让我说我已经完成了对这个问题的研究,我已经看到了这里发布的解决方案: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。
答案 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
类