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.