Selenium/PageFactory: Find child elements using pa

2019-05-31 08:45发布

I'm trying to convert my selenium tests to use the Page Object Model (and, by extension, @FindBy). I have several object definitions like this:

public WebElement objectParent() {
    return driver.findElement(By.name("parent-id")) ;
}

public WebElement objectChild() {
    WebElement elem = objectParent();
    return elem.findElement(By.name("child-id")) ;
}

Converting the parent object to using @FindBy is easy:

@FindBy(name = "parent-id")
WebElement parentObj;

Basically, I want to do something like this, if possible (I know this isn't real code, this is just a pseudo example:

@FindBy(name = "parent-id")
WebElement parentObj;

@FindBy(parentObj.name = "child-id")
WebElement childObj;

But is there a way too target the child element within the parent element using @FindBy?. I need to do it this way because I am targeting specific elements on the page that may share the same name or class name with other elements on the page. Thanks!

3条回答
太酷不给撩
2楼-- · 2019-05-31 09:26

What you are trying to do is not easily achievable without writing custom ElementLocatorFactory.

Firstly I would really recommend using XPath. This would make it easy lot to grab the:
3rd <table> just like this: @FindBy(xpath = "\\table[3]") and...
2nd <li> in the 3rd table just like this: @FindBy(xpath = "\\table[3]\li[2]").

But if you really want to do it with shorter @FindBy annotations, you can go for ElementLocatorFactory.

public class FindByContextModifier implements ElementLocatorFactory {

    private final SearchContext context;

    public FindByContextModifier(final SearchContext context) {
        this.context = context;
    }

    public ElementLocator createLocator(final Field field) {
        return new DefaultElementLocator(context, field);
    }
}

Class with an element that will provide you with the context:

public class Parent {
    @FindBy(name = "myTable")
    WebElement table;

    public WebElement getTable() {
      return this.table;
    }
}

Its child:

public class Child {
    @FindBy(name = "particular")
    WebElement specialTableListElement;
}

Usage:

Parent parent = PageFactory.initElements(driver, Parent.class);
FindByContextModifier parentContext = new FindByContextModifier(parent.getTable());
Child child = new Child();
// This will look for the name "particular" inside the element with "myTable" name
PageFactory.initElements(parentContext, child);
查看更多
Root(大扎)
3楼-- · 2019-05-31 09:45

You do not need to write a custom ElemLocatorFactory, just use org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory instead:

Parent parent = PageFactory.initElements(driver, Parent.class);
DefaultElementLocatorFactory parentContext = new DefaultElementLocatorFactory(parent.getTable());
Child child = new Child();
PageFactory.initElements(parentContext, child);
查看更多
干净又极端
4楼-- · 2019-05-31 09:47

The approach mentioned above works, but if you're using xpath, make sure that your 'child' element has a .// in front to make it relative.

查看更多
登录 后发表回答