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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@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:
1
2
3
4
5
6
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:
1
2
3
4
5
6
7
8
9
10
11
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.