扩展 Selenium WebDriver WebElement?

2022-01-16 00:00:00 selenium webdriver java

我正在遵循 Selenium 建议的页面对象模式,但我将如何为页面创建更专业的 WebElement.具体来说,我们的页面上有表格,我编写了一些辅助函数来获取表格的特定行、返回表格的内容等.

I'm following the Page Object pattern suggested by Selenium, but how would I create a more specialized WebElement for a page. Specifically, we have tables on our pages and I have written some helper functions to get specific rows of a table, return the contents of a table, etc.

目前,这是我创建的具有表格的页面对象的片段:

Currently, here is a snippet of a page object I created that has a table:

public class PermissionsPage  {

    @FindBy(id = "studyPermissionsTable")
    private WebElement permissionTable;

    @FindBy(id = "studyPermissionAddPermission")
    private WebElement addPermissionButton;

    ... 

}

所以,我想做的是让 permissionsTable 成为一个更加自定义的 WebElement,它具有我之前提到的一些方法.

So, what I'd like to do is have that permissionsTable to be a more customized WebElement that has some of those methods I mentioned earlier.

例如:

public class TableWebElement extends WebElement {
    WebElement table;
    // a WebDriver needs to come into play here too I think

    public List<Map<String, String>> getTableData() {
        // code to do this
    }

    public int getTableSize() {
        // code to do this
    }

    public WebElement getElementFromTable(String id) {
        // code to do this
    }
}

我希望我试图解释的内容是有意义的.我想我正在寻找的是一种让这个自定义 WebElement 执行一些特定于表的额外内容的方法.将此自定义元素添加到页面,并利用 Selenium 根据注释将 web 元素连接到页面的方式.

I hope that this makes sense what I'm trying to explain. I guess what I'm looking for is a way to have this custom WebElement to do some additional stuff that's table-specific. Add this custom element to a Page and take advantage of the way Selenium wires the webelements to the page based on the annotations.

有可能吗?如果是这样,有谁知道如何做到这一点?

Is it possible? And if so, does anyone know how this can be done?

推荐答案

我创建了一个结合了所有 WebDriver 接口的接口:

I created an interface that combines all of the WebDriver interfaces:

public interface Element extends WebElement, WrapsElement, Locatable {}

它只是用来包装 WebElements 在包装元素时可以做的所有事情.

It's just there to wrap up all of the things WebElements can do when wrapping an element.

然后是一个实现:

public class ElementImpl implements Element {

    private final WebElement element;

    public ElementImpl(final WebElement element) {
        this.element = element;
    }

    @Override
    public void click() {
        element.click();
    }

    @Override
    public void sendKeys(CharSequence... keysToSend) {
        element.sendKeys(keysToSend);
    }

    // And so on, delegates all the way down...

}

然后,例如一个复选框:

Then, for example a check box:

public class CheckBox extends ElementImpl {

    public CheckBox(WebElement element) {
        super(element);
    }

    public void toggle() {
        getWrappedElement().click();
    }

    public void check() {
        if (!isChecked()) {
            toggle();
        }
    }

    public void uncheck() {
        if (isChecked()) {
            toggle();
        }
    }

    public boolean isChecked() {
        return getWrappedElement().isSelected();
    }
}

在我的脚本中使用它时:

When using it in my script:

CheckBox cb = new CheckBox(element);
cb.uncheck();

我还想出了一种包装 Element 类的方法.您必须创建一些工厂来替换内置的 PageFactory,但这是可行的,并且提供了很大的灵活性.

I've also come up with a way of wrapping the Element classes. You have to create a few factories to replace the built-in PageFactory, but it is doable, and it lends a lot of flexibility.

我已经在我的网站上记录了这个过程:

I've documented this process over on my site:

  • 包装 WebElement:第 1 部分
  • 包装 WebElement:第 2 部分

我还有一个名为 selophane 的项目,它的灵感来自这个问题和其他问题:selophane

I've also got a project called selophane that was inspired by this and other questions: selophane

相关文章