根据“Book of Geb”,我开始绘制门户网站的网页。我更喜欢使用静态内容闭包块中定义的变量,然后在页面方法中访问它们:
static content = {
buttonSend { $("input", type: "submit", nicetitle: "Senden") }
}
def sendLetter() {
waitFor { buttonSend.isDisplayed() }
buttonSend.click()
}
不幸的是,有时候我会得到Geb等待超时异常(60秒后),甚至更糟糕的是我收到了众所周知的“StaleElementReferenceException”。
使用“isEnabled”代替“isDisplayed”时可以避免等待超时,但对于“StaleElementReferenceException”,我只能应用以下解决方案:
def sendLetter() {
waitFor { buttonSend.isEnabled() }
try {
buttonSend.click()
} catch (StaleElementReferenceException e) {
log.info(e.getMessage())
buttonSend.click()
}
}
我想,这个解决方案并不是很好,但我无法应用另一篇文章中描述的明确等待。因此,我有一些一般性的问题:
我希望每一个有助于理解或解决这个问题的提示。最好的方法是拥有一个简单的代码示例,因为我还是初学者。谢谢!
除了twinj的答案,我还想指出一些其他的解决方法,以防你遇到StaleElementReferenceException。
static content = {
dropdown { $("#parentDiv").find("ul") }
}
void clickDesiredElement(String elementName) {
dropdown.click()
def desiredElement = dropdown.find("li", text:elementName)
waitFor { desiredElement.displayed }
desiredElement.click()
}
如果这不起作用,请尝试完全删除内容,并手动写出选择器...
void clickDesiredElement(String elementName) {
$("#parentDiv").find("ul").click()
def desiredElement = $("#parentDiv").find("ul").find("li", text:elementName)
waitFor { desiredElement.displayed }
desiredElement.click()
}
在非常讨厌的情况下,您可能必须使用this answer中指出的手动计时器,并且您的代码可能看起来像这样......
void clickDesiredElement(String elementName) {
$("#parentDiv").find("ul").click()
sleepForNSeconds(2)
def desiredElement = $("#parentDiv").find("ul").find("li", text:elementName)
waitFor { desiredElement.displayed }
desiredElement.click()
}
请记住这是一个解决方法:)def rows = $("#table1").find("tr").collect {
[
name: it.find("td",0),
email: it.find("td",1)
]
}
有时我发现自己必须迭代地执行此操作,并在每次迭代之间使用waitFor {}以避免StaleElementReferentException。它可能看起来像这样......
def rows = []
int numRows = $("#table1").find("tr").size()
int i
for(i=0; i < numRows; i++) {
waitFor {
def row = $("#table1").find("tr",i)
rows << [
name: row.find("td",0),
email: row.find("td",1)
]
}
}
如果您在页面类中定义了一个检查页面,则页面将首先验证该条件并等待前n秒。这是在您的gebConfig文件中分配的。默认值为30秒。
static at = {
waitFor { buttonSend.isDisplayed() }
}
因此,一旦您通过测试将您的页面调用到'方法或者您正在使用的任何方法,页面将等待然后执行页面操作。
to MyPage
buttonSend.click()
当页面是动态的时候,我应该避免使用静态内容定义吗?
实际上,静态定义是封闭的。所以实际发生的是每次使用Pages静态组件时,你调用的是一个在当前页面上动态运行的闭包(webElements集合)。了解这一点是使用Geb并发现您将遇到的问题的关键。
在什么时间或事件Geb刷新它的DOM?如何触发DOM刷新?
当您调用:to,go,at,click,withFrame(frame,page),withWindow和浏览器驱动方法时,它将刷新当前的WebElements集。 Geb有很好的收集,可以在页面之间切换,轻松等待页面操作。注意:Geb实际上是建立在WebDriver WebElements上的。
为什么在使用CSS选择器时仍然会出现“StaleElementReferenceException”?
页面可能尚未完成加载,已使用ajax调用进行操作或已以其他方式刷新。有时'at'PAGE方法调用可以解决这些问题。在使用框架时,它们对我来说最常见,因为Geb似乎在页面和框架之间变得混乱。有解决方法。
简而言之,如果您使用页面模式,您可以使用您使用以下内容静态内容,at和url闭包定义的Page类轻松切换预期页面:
我认为这是动态加载时丢失的导航器。我通过以下代码重新启动页面或模块来解决本地问题:
void waitForDynamically(Double timeout = 20, Closure closure) {
closure.resolveStrategy = Closure.DELEGATE_FIRST
switch (this) {
case Module:
init(browser, browser.navigatorFactory)
break
case Page:
init(browser)
break
default:
throw new UnsupportedOperationException()
}
waitFor {
closure()
}
}