Correct and incorrect ways of creating page object classes

Let’s say that you want to automate test scenarios for the login page of a web site.

The login page has 3 elements:

– username textbox

– password textbox

– sign in button

 

login

 

Some of the test cases to be automated for this page are

  1. user can sign in with correct username and password
  2. user cannot sign in if username or password are incorrect
  3. password is masked
  4. user can create a new account

 

In this article, we will focus on the first test case only.

Since the test cases uses 2 pages (login page and the page the user sees after a successful sign in), we will need 2 page object classes:

  1. LoginPage class
  2. MainPage class

One way of implementing the LoginPage.java class is

public class LoginPage {

private WebDriver driver;

private WebDriverWait wait;

private By userNameLocator = By.id("userNameId");

private By passwordLocator = By.id("passwordId");

private By signInLocator   = By.id("signInId");

 

public LoginPage(WebDriver driver) {

   this.driver = driver;

   this.wait = new WebDriverWait(driver, 30);

}

public void clickUserName() {

   WebElement userName = findElement(userNameLocator);

   userName.click();

}

public void clickPassword() {

   WebElement password = findElement(passwordLocator);

   password.click();

}

public void clickSignIn() {

   WebElement signIn = findElement(signInLocator);

   signIn.click();

}

public void typeUserName(String value) {

   WebElement userName = findElement(userNameLocator);

   userName.sendKeys(value);

}

public void typePassword(String value) {

   WebElement password = findElement(passwordLocator);

   password.sendKeys(value);

}

private WebElement findElement(By locator) {

  return

  wait.until(visibilityOfElementLocated(locator));

}

 

The LoginPage class has multiple methods for clicking elements and typing text into them.

Using this LoginPage class, we can now build a test script (JUNIT):

@Test

public void testSuccessfullLogin() {

  LoginPage loginPage = new LoginPage(driver);

  loginPage.clickUserName();

  loginPage.typeUserName("admin");

  loginPage.clickPassword();

  loginPage.typePassword("abcdef");

  loginPage.clickSignIn();

  MainPage mainPage = new MainPage(driver);

  assertTrue(mainPage.isDisplayed() == true);

}

 

Building a page object class like this is not correct.

It is not correct because what we do is creating an API that interacts with HTML elements.

For a page that has only 3 elements, we have 5 methods.

Imagine how many methods you will need for a page with 100 elements.

 

The correct approach for page object classes is explained in the following link:

https://martinfowler.com/bliki/PageObject.html

We should not create page object classes and APIs that interact with HTML elements.

Instead, we should create page classes and APIs that interacts with the site similar with how a user does it.

 

 

pageobject

 

See below the LoginPage class changed to interact with the site:

public class LoginPage {

private WebDriver driver;

private WebDriverWait wait;

private By userNameLocator = By.id("userNameId");

private By passwordLocator = By.id("passwordId");

private By signInLocator = By.id("signInId");

 

public LoginPage(WebDriver driver) {

 this.driver = driver;

 this.wait = new WebDriverWait(driver, 30);

}

public void signInWith(String userName, String password) {

 WebElement userName = findElement(userNameLocator);

 userName.click();

 userName.sendKeys(value);

 WebElement password = findElement(passwordLocator);

 password.click();

 password.sendKeys(value);

 WebElement signIn = findElement(signInLocator);

 signIn.click();

}

private WebElement findElement(By locator) {

  return

  wait.until(visibilityOfElementLocated(locator));

}

}

The class has now 1 method only instead of 5.

This method is about interacting with the site like a user by signing in.

Using the LoginPage class, the test script becomes

@Test

public void testSuccessfullLogin() {

  LoginPage loginPage = new LoginPage(driver);

  loginPage.signInWith("admin", "abcdef");

  MainPage mainPage = new MainPage(driver); 

  assertTrue(mainPage.isDisplayed() == true);

}

 

The test script is significantly shorter now.

It also looks like English and is similar to a test case.

We should always aim to

  1.  making the test scripts as short as possible
  2.  moving code from the test script to the page object class
  3.  not using any webdriver object or method in the test scripts
  4.  use only page objects and page methods in the test scripts
  5.  not creating any methods that interact with an element in the page object classes
  6.  keep page object classes short (less than 250 lines of code)
  7.  do not create methods that include in their names the following words: click, type, getText, etc as these are most probably interacting with single elements
Advertisement

2 Comments

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s