Home > Net >  Want to use Enum file name dynamically to fetch constants
Want to use Enum file name dynamically to fetch constants

Time:02-24

I have a config file with key value pair as language = "IN" and i have multiple page object enum files with name as PageObject_US,PageObject_UK,PageObject_IN

every page object enum file has constants that can be accessed using for example PageObjects_US.String.lable

but what i want to achieve is a way to create something like below

  1. take the parameter from config file store it in a string like String language = "IN"
  2. Then concatenate using "PageObjects_" language to get (PageObjects_IN)
  3. so that the returned value can be used to fetch the constants from PageObjects_IN.String.label.

following is the code block:


if(!ENV.equalsIgnoreCase("development") && VALIDATION.equalsIgnoreCase("yes")) {        
            Elements.ByTitle(webDriver,PageObjects_IN.GREAT.label);
            Elements.ByID(webDriver,  PageObjects_IN.COUNTER.label);
}

In the above i want to use enum file PageObjects_IN at run time as i have many enum files

below is the enum

public enum PageObjects_IN {
    // Text
    GREAT("great"), 
    COUNTER("counter");


    public final String lable;

    PageObjects_IN(final String lable) {
        this.lable = lable;
    }

}

CodePudding user response:

This is possible (using reflection) but strongly not recommended as it eliminates the efficiency of Java language constructs.

Not recommended way

Say you have a package click.webelement.cucumber.po where you store

public enum PO_EN {
    GREAT("great_en"),
    COUNTER("counter_en");

    public final String label;

    PO_EN(String label){
        this.label = label;
    }
}

and

public enum PO_IN {
    GREAT("great_in"),
    COUNTER("counter_in");

    public final String label;

    PO_IN(String label){
        this.label = label;
    }
}

Then to take a value you can do something like this:

String lang = "EN";
// Take class
Class clazz = Class.forName("click.webelement.cucumber.po.PO_"   lang);
// Find an object that represent enum constant
Object val = Arrays
        .stream(clazz.getEnumConstants()).filter(o -> "GREAT".equals(o.toString()))
        .findAny()
        .get();
// Take field value for that object
Field f = clazz.getField("label");
System.out.println(f.get(val));

This is error-prone approach and you would not have benefit from compile phase.

Recommended approach - 1

Instead of having enum use classes.

public abstract class PO {

    public abstract String great();
    public abstract String counter();

}

and

public class PO_EN extends PO{
    @Override
    public String great() {
        return "great_en";
    }

    @Override
    public String counter() {
        return "counter_en";
    }
}

and

public class PO_IN extends PO{
    @Override
    public String great() {
        return "great_in";
    }

    @Override
    public String counter() {
        return "counter_in";
    }
}

so your test would be much simpler

String lang = "EN";
Class clazz = Class.forName("click.webelement.cucumber.po.PO_"   lang);
PO val = (PO) clazz.getDeclaredConstructor().newInstance();
System.out.println(val.great());

Recommended approach - 2

You can utilize PageFactory harness for your page objects and use this lib to parametrize your locators, like (if you use test ng):

@DataProvider(name = "languages")
Object[][] dataProvider(){
    return new Object[][]{
            {"en", "great_en", "counter_en"},
            {"in", "great_in", "counter_in"}
    };
}

@Test(dataProvider = "languages")
public void testPage(String language, String great, String counter){
    DefaultParameterProvider
            .properties
            .set(Map.of("p.great", great, "p.counter", counter));
    MyPage myPage = new MyPage(driver);
    ...
}

Where your page would be like this:

public class MyPage extends PageObjectParameterized {

    @FindByParameterized(xpath = "//button[@name='{wec:p.great}']")
    WebElement great;

    @FindByParameterized(xpath = "//label[text()='{wec:p.counter}']")
    WebElement counter;

    @FindBy(xpath = "//input")
    WebElement input;
    
    public MyPage(SearchContext searchContext) {
        super(searchContext);
    }
}
  • Related