7

I'm trying to use Page Object pattern in Java and having some trouble with @FindBy/XPath.

Earlier, I used the following construction in Groovy:

driver.findElement(By.xpath("//td[contains(text(),'$SystemName')]")).click()

Here, SystemName is a parameter that can be different. 

Now, I want to do the same thing but in accordance with Page Object paradigm in Java:

public class ManagedSystems {

    private WebDriver driver;

    @FindBy(id="menu_NewSystem")
    private WebElement menuNewSystem;

    @FindBy (xpath = "//td[contains(text(),'$SystemName')]")  // ??? How to use SystemName from deleteSystem method (below)?
    private WebElement plantSystemName;

    ....

    public SystemHomePage deleteSystem (String systemName) {

        plantSystemName.click();

    }

}

In my test, I call deleteSystem:

SystemHomePage.deleteSystem("Firestone");

Question: How to link @FindBy notation for PlantSystemName and SystemName specified for deleteSystem?

Thanks, Racoon

Racoon
  • 951
  • 3
  • 14
  • 32

4 Answers4

7

I used another workaround for this which will allow us to use dynamic xpath even with page factory.

Solution: Add the xpath of any parent element that is static and reference child element with dynamic path. In your case, //td[contains(text(),'$SystemName'), parent element of td might be 'tr' or 'table'. If table is static, use below code:

@FindBy(xpath = "<..table xpath>")
public WebElement parentElement; 

public WebElement getDynamicEmement(String SystemName){
  parentElement.findElement(By.xpath("//tr/td[contains(text(),'"+SystemName+"')]"))
}

Now in your script, access table first(so that its reference is loaded in memory) and then call the getDynamicElement method.

waitForElement(parentElement)
getDynamicElement("System-A")
Aftaab Siddiki
  • 241
  • 3
  • 4
  • 1
    parentElement.findElement(By.xpath(String.format("//tr/td[contains(text(),'%s')]", SystemName))) - a bit simplier – Alex Aug 08 '19 at 13:44
3

You can't do that, Annotations are constant values stored in the class file. You can't compute them at runtime.

See Can the annotation variables be determined at runtime?

Community
  • 1
  • 1
Ardesco
  • 7,281
  • 26
  • 49
  • Ardesco, thanks! The link you specified doesn't contain any workaround. So how do people cope with this limitation? – Racoon Jan 21 '14 at 16:24
  • That's because there isn't one, it's the way annotations work in Java. People cope with this by not trying to do what you are trying to do. – Ardesco Jan 21 '14 at 23:16
  • Ardesco, thanks. So do I understand right that there are two options: 1) use only static XPath. But that's not always possible; 2) Don't use PageFactory & annotations at all. Implement Page Objects on my own. In this case, are there any best practicies? – Racoon Jan 22 '14 at 10:57
  • You can mix and match, you can use PageFactory and annotations and you can define some By's in your page object that use dynamically created XPath's. – Ardesco Jan 22 '14 at 23:03
  • Ardesco, thanks! I published the solution based on your suggestion. It works. Any remarks on how to do it better are appreciated. – Racoon Jan 23 '14 at 13:44
3

Thanks to Ardesco and Robbie, I came up with the following solution:

private String RequiredSystemNameXpath = "//td[contains(text(),'xxxxx')]";

private WebElement prepareWebElementWithDynamicXpath (String xpathValue, String substitutionValue ) {

        return driver.findElement(By.xpath(xpathValue.replace("xxxxx", substitutionValue)));
}

public void deleteSystem (String systemName) {


    WebElement RequiredSystemName = prepareWebElementWithDynamicXpath(RequiredSystemNameXpath, systemName);

    RequiredSystemName.click();

}
Racoon
  • 951
  • 3
  • 14
  • 32
1

You are using a page object factory rather than just following the page object pattern.

You can create page objects as simple classes with identifiers stored as private variables, and methods exposing the elements using those variables, and you are still following the page object pattern.

check out this; http://relevantcodes.com/pageobjects-and-pagefactory-design-patterns-in-selenium/

If your identifiers are just variables, then you can use any manipulation you want

Robbie Wareham
  • 3,380
  • 1
  • 20
  • 38
  • Robbie, first of all, thank you for the answer. Truth be told, I didn't quite understand what you meant. Do you mean it makes sense to forget about PageFactory/PageObject built into Selenium WebDriver and just follow the pattern itself, not its built-in implementation? I.e. creating my own classes with my own functionality? – Racoon Jan 21 '14 at 18:37
  • I was trying to say that yo don't have to use the Page Factory to follow the Page Object pattern. I find it limits me too much for reasons such as you have found. – Robbie Wareham Jan 21 '14 at 21:37
  • Robbie, thanks. OK, let's forget about PageFactory. How would you implement a WebElement with dynamic XPath? – Racoon Jan 22 '14 at 06:41