Reflection for hybrid testing framework with cucumber

After a couple of time I manage to create a Selenium hybrid testing framework base on java reflection functional.

In this post I will explain the base principles of this framework and all pluses and minuses. Let’s begin in our journey.

Based on my experience a good testing framework base on UI functional testing an using Selenium Web Driver have a module with POJO elements witch represents web pages of the testing project, usually this POJO contains and implementation of some basic functional, like insert data to input or click a button. But not in my case I used this time POJO just to declare Web Elements of the page. So a simple page of the project will look like below:

public class HomePage1 extends AbstractPageObject {
    public HomePage1(WebDriver driver) {
        super(driver);
    }

    @FindBy(xpath = "//*[@id=\"page-wrapper\"]/main/section[1]/div/h1")
    private WebElement pageTitle;

    @FindBy(xpath = "//*[@id=\"main-nav\"]/div/ul/li[4]/ul/li[1]/a")
    private WebElement partnerCollegesNavButton;

    @Override
    public boolean isInitialized() {
        boolean value = false;
        try {
            value = pageTitle.isDisplayed();
        } catch (Exception e) {
            System.out.println("Page is not initialized");
        }
        return value;
    }
}

 

So I have the page name and the name of web elements, in this case I think to use java reflection for re-usability  of the code. Created two generic methods:

  • getWebElementByObjectAndName – return a web element from Object, Object in our case is representation of web page in framework,
  • getPageObjectByPageName – return page representation name.

 

public WebElement getWebElementByObjectAndName(Object object, String fieldName) {
    WebElement webElement = null;
    Class<?> validationClass = object.getClass();
    Field[] fields = validationClass.getDeclaredFields();
    for (Field field : fields) {
        if (field.getType() == WebElement.class) {
            field.setAccessible(true);
            if (field.getName().equals(fieldName)) {
                try {
                    webElement = (WebElement) field.get(object);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }

        }
    }
    return webElement;
}

public AbstractPageObject getPageObjectByPageName(PageNames pageNames, WebDriver driver) throws Exception {
    Class<?> c = Class.forName("com.pages.pageObjects." + pageNames.name());
    Constructor<?> cons = c.getConstructor(WebDriver.class);
    return (AbstractPageObject) cons.newInstance(driver);
}

 

And use this methods in steps then click or insert data in a web element, we will have two methods with will be used a lot of time. Implementation is below!

@When("^user clicks on '(.*)' from current page$")
public void userClicksOnSimpleFileDownloadFromCurrentPage(String webElement) {
    AbstractPageObject currentPage = (AbstractPageObject) scenarioContext.getData(PageKeys.CURRENT_PAGE);
    WebElement foundElement = getWebElementByObjectAndName(currentPage, webElement);
    foundElement.click();
    makeScreenshot((String) scenarioContext.getData(PageKeys.SCENARIO_NAME), (WebDriver) scenarioContext.getData(PageKeys.OPEN_DRIVER));
    scenarioContext.save(PageKeys.LAST_CLICKED, foundElement);
}

@When("^user inserts following data in current page$")
public void userInsertsFollowingDataInCurrentPage(List<ItemList> dataTableValues) {
    WebDriver webDriver = (WebDriver) scenarioContext.getData(PageKeys.OPEN_DRIVER);
    AbstractPage currentPage = (AbstractPage) scenarioContext.getData(PageKeys.CURRENT_PAGE);
    for (ItemList itemList : dataTableValues) {
        WebElement webElement = getWebElementByObjectAndName(currentPage, itemList.getFieldName());
        webElement.clear();
        if (itemList.getFieldValue().contains("%s")) {
            String userTestEmail = String.format(itemList.getFieldValue(), LocalDateTime.now().toLocalTime().toSecondOfDay());
            scenarioContext.save(PageKeys.TEST_EMAIL, userTestEmail);
            webElement.sendKeys(userTestEmail);
            highLighterMethod(webDriver, webElement);
            makeScreenshot((String) scenarioContext.getData(PageKeys.SCENARIO_NAME), webDriver);
        } else {
            webElement.sendKeys(itemList.getFieldValue());
            highLighterMethod(webDriver, webElement);
            makeScreenshot((String) scenarioContext.getData(PageKeys.SCENARIO_NAME), webDriver);
        }
    }
}

And example of cucumber scenarios look like this:

And page 'HomePage' is displayed
  And user inserts following data in current page
    | fieldName | fieldValue      |
    | email     | Ivan@Cazlov.com |
    | password  | Ivan1234@       |
  And user clicks on 'continueButton' from current page

And important step is to save the current page to have corresponding object of page to return our web element.Code below:

Cucumber: And page 'HomePage' is displayed

Java:
@Then("^page '(.*)' is displayed$")
public void pageIsDisplayed(PageNames pageNames) throws Exception {
    WebDriver driver = (WebDriver) scenarioContext.getData(PageKeys.OPEN_DRIVER);
    AbstractPageObject object = getPageObjectByPageName(pageNames, driver);
    await().atMost(DEFAULT_TIMEOUT, SECONDS).until(() -> object.isInitialized());
    assertTrue("Page object " + pageNames.name() + " is displayed", object.isInitialized());
    scenarioContext.save(PageKeys.CURRENT_PAGE, object);
}

Hope this will help you to re use your code and to implement this type of framework in your experience.

I case of some question don't hesitate to write a comment, I will answer all the questions.