处理多个框架时如何创建静态页面内容?

时间:2018-10-12 20:42:28

标签: selenium geb

我刚开始测试新应用程序,并且已经开始为所述应用程序建模页面对象。

我发现此应用程序使用“框架”,因为DOM中包含2个或更多HTML元素标签。默认情况下,GEB看起来看不到在嵌套HTML元素下找到的元素。

我检查了GEB的书,发现可以使用withFrame方法来指定元素属于哪个框架。当我这样做时,GEB确实确实看到了有问题的元素。

我遇到的问题是,我不想让编写脚本(使用页面对象)的人不必担心特定元素来自哪个框架。我想知道是否有一种方法可以从静态内容中指定元素所属的框架。否则,脚本编写者不仅需要知道某个元素不在框架内,而且还必须检查并查看所讨论的元素属于哪个框架。

以下是到目前为止我尝试过的一些事情:

SomePage extends Page{
    static content=  {
        myNavigator {withFrame("header", {$(By.xpath("my xpath"))})}
    }
}

如果我尝试使用myNavigator,则会收到过时的元素引用异常(也许我所做的一切正确,并且还有其他原因吗?)

我也尝试过这也会导致过时的元素:

SomePage extends Page{
    static content=  {
        myNavigator {$(By.xpath("my xpath"))}
    }

    Navigator getMyNavigator(){
        return withFrame("header", {myNavigator})
    }
}

我有点理解为什么会发生这种情况,在执行withFrame colusre之后,我假设该闭包内部引用的任何元素都已失效。

基本上我想要它,以便脚本编写者需要做的只是说些类似的话:

at MyPage
waitFor {myNavigator}.click()

我想避免这样做:

at MyPage
withFrame("header", {waitFor {myNavigator}.click()}

如何在“页面对象”侧进行设置以获得所需的结果? (可以选择模块吗?)

编辑:我也尝试用稍微不同的语法定义静态内容,但是仍然获得相同的陈旧元素引用:

myNavigator{ withFrame("header") { $(By.xpath("//td/a"))} } 

Edit2:我也曾尝试实现类似于本文的内容:https://groups.google.com/forum/#!topic/geb-user/uxgcgWgmGYE

我的静态内容现在看起来像这样:

static content = {
    bannerMod {withFrame("banner") {module BannerModule}}
    mainViewMod {withFrame("FrameworkMain") {module MainViewModule}}
    sideMenuMod {withFrame("contents") {module SideMenuModule}}
}

我将所有元素都移到了它们各自的模块中,但是现在当我尝试引用它们时,仍然会得到一个过时的元素引用异常。例如,它被抛出以下代码行:

if(!mainViewMod.table.displayed){

声明stale element reference: element is not attached to the page document

1 个答案:

答案 0 :(得分:3)

正如您已经注意到的,您得到StaleElementExcpetions的原因是,在切换到根文档的上下文之后,当您尝试访问在框架上下文中获得引用的元素时,即您正在尝试在withFrame()调用之外访问这些元素。

我可以看到两种解决您问题的方法。

第一个是不使用withFrame(),而是通过driver.switchTo().frame(..)调用手动管理帧上下文。不幸的是,这将意味着您将无法达到使用页面对象时不必知道哪些元素来自哪些帧的目的。

另一种方法是在页面中编写一个方法,该方法将关闭并处理切换到正确的框架。像这样:

class PageWithFrames extends Page {
    public <T> T mainView(@DelegatesTo(value = MainViewPage, strategy = Closure.DELEGATE_FIRST) Closure<T> mainViewAction) {
        withFrame('FrameworkMain', MainViewPage, mainViewAction)
    }
}

class MainViewPage extends Page {
    static content = {
        table { ... }
    }
}

然后可以像这样使用它:

at PageWithFrames
if (mainView { table.displayed }) {
    ....
}

请注意,由于有了@DelegatesTo批注,IntelliJ会知道您在MainViewPage调用中位于mainView {},并且您将获得自动补全功能。请记住,无论您做什么,都不应从mainView {}调用中返回页面元素,因为您将开始获得StaleElementException s。

您可能还会发现"Switching pages and frames at once"手册部分很有趣。