To implement the Page Object model in tests, we need to create a Page Object class for each page that is being tested. For example, to test the BMI Calculator application, a BMI Calculator page class will be defined, which will expose the internals of the BMI Calculator page to the test, as shown in following diagram. This is done by using the PageFactory
class of Selenium WebDriver API:
Before exposing the elements of a page, we need to do the following:
Let's implement a Page Object test for the BMI Calculator page using the PageFactory
class with the following steps:
seleniumcookbook.tests.pageobjects
is created to define all the page objects.BmiCalcPage
. This is a single page application. The Java class file will have the following code:package com.secookbook.examples.chapter08.pageobjects; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class BmiCalcPage { }
BmiCalcPage
class created in step 1. Use the name
or id
attributes to name these variables, as follows:private WebElement heightCMS; private WebElement weightKg; private WebElement Calculate; private WebElement bmi; @FindBy(id = "bmi_category") private WebElement bmiCategory; private WebDriver driver;
BmiCalcPage
class, which will call the PageFactory.initElements()
method to initialize the elements in the class. In other words, map the elements to the variables in the BmiCalcPage
class, as follows:public BmiCalcPage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); }
public void setHeight(String height) { heightCMS.sendKeys(height); } public void setWeight(String weight) { weightKg.sendKeys(weight); } public void calculateBmi() { Calculate.click(); }
Bmi
and Bmi
Category fields, as shown in the following code:public String getBmi() { return bmi.getAttribute("value"); } public String getBmiCategory() { return bmiCategory.getAttribute("value"); }
BmiCalcPage
class to test the BMI Calculator page, as follows:package com.secookbook.examples.chapter08.tests; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import static org.junit.Assert.*; import com.secookbook.examples.chapter08.pageobjects.BmiCalcPage; public class BmiCalculatorTests { private WebDriver driver; @Before public void setUp() { driver = new ChromeDriver(); driver.get("http://cookbook.seleniumacademy.com/bmicalculator.html"); } @Test public void testBmiCalculation() { // Create an instance of Bmi Calculator Page class // and provide the driver CopyOfBmiCalcPage bmiCalcPage = new CopyOfBmiCalcPage(driver); // Set Height bmiCalcPage.setHeight("181"); // Set Weight bmiCalcPage.setWeight("80"); // Click on Calculate button bmiCalcPage.calculateBmi(); // Verify Bmi & Bmi Category values assertEquals("24.4", bmiCalcPage.getBmi()); assertEquals("Normal", bmiCalcPage.getBmiCategory()); } @After public void tearDown() { driver.quit(); }
Using the Page Object model and the PageFactory
class, the BMI Calculator page's elements are exposed through the BmiCalcPage
class to the test instead of the test directly accessing the internals of the page.
When we initialize the page's object using the PageFactory
class in the BmiCalcPage
class, the PageFactory
class searches for the elements on the page with the name
or id
attributes matching the name of the WebElement
object declared in the BmiCalcPage
class, as follows:
public BmiCalcPage(WebDriver driver) { PageFactory.initElements(driver, this); }
The initElements()
method takes the driver object created in the test and initializes the elements declared in the BmiCalcPage
class. We can then directly call the methods on these elements, as follows:
// Set Height bmiCalcPage.setHeight("181"); // Set Weight bmiCalcPage.setWeight("80"); // Click on Calculate button bmiCalcPage.calculateBmi();
Finding elements using the name
or id
attributes may not always work and we might need to use advanced locator strategies such as XPath or CSS selectors. Using the FindBy
annotation, we can locate the elements within the PageFactory
class, as follows:
@FindBy(id = "heightCMS") public WebElement heightField;
We declared a public member for the height element and used the @FindBy
annotation, specifying the id
as a locator for finding this element on the page.
One downside to using the @FindBy
annotation is that every time we call a method on the WebElement
object, the driver will go and find it on the current page again. This is useful in applications where elements are dynamically loaded, or AJAX-heavy applications.
However, in applications where we know that the element is always going to be there and stay the same without any change, it would be handy if we could cache the element once we find it. In order to do this, we use the @CacheLookUp
annotation along with the @FindBy
annotation, as follows:
@FindBy(id = "heightCMS") @CacheLookup public WebElement heightField;
This tells the PageFactory.initElements()
method to cache the element once it's located. Tests work faster with cached elements when these elements are used repeatedly.
3.149.236.27