In a previous article I described a set of best practices for designing automated tests. So as I said, in this post I would like to expand our toolbox of two design patterns, that work great with selenium tests. In this post we will dig into Page Object pattern and combine it with Page Factory. As always, whole code for project is available on my github.
Pattern Page Object is a concept that helps to reduce the number of duplicated code, and helps with test maintenance, resulting from changes in the structure and functionality of the web application. The main idea behind page object is to place the code relating to the functionality of subpages in separate classes. In a very simplified way, if your web application includes pages:
We should create three separate page object classes:
Each class should contain only those methods that support functionality for the corresponding subpage, and define selectors only for this subpage. We should also remember, that public methods in page object class are only those, that represents user’s workflow.
One important point is that each public method in page object class should return object of page that user is on. For example, if a button on the page does not gets you to different subpage, this method should return this. Moreover, if a button is a link to another page, the method should return page object class of this subpage. Here is a code snippet of this approach using an example from previous article, where we wrote tests for Facebook login:
In above example, methods enterUserLogin() and enterUserPassword() don’t transfer user to another subpage, but perform activities on the login page, so return type is object of LoginPage class (this). On the other hand, submitLoginCredentials() method moves user to home page (or to the page informing about the login failure), so it returns home page class object. In real life example, in HomePage.class we would have had methods that perform actions on the home page, but since it’s only an example code demonstrating pattern usage, we have only checkIfLoginSucceed() method here:
…and test looks as follows:
Page Factory pattern
The main idea behind this pattern is to support page object classes, and to allow better page selectors management. Page Factory provide us with a set of annotations, which work great with selectors and enhance code readability. To understand this, let’s look at a standard initialization webelement through the selector:
private static By email = By.id(“email”);
WebElement emailBox = driver.findElement(email);
Unfortunately, the readability leaves much to be desired. The problem is also that variable with selector and web element object require a separate initialization. Along with Page Factory, this is greatly simplified:
private WebElement email;
That’s all! Page Factory search page source code for element with id=”email” by default and assigns it to declared webelement. Of course, this minimalism can introduce some confusion, and therefore I recommend the use of @FindBy annotation:
@FindBy(id = “email”) private WebElement userEmailLoginInput;
We can also search selectors by other attributes, such as xpath, name, className, etc. Everything we have to do to use this pattern, is to initialize PageFactory in the page object class constructor:
Our LoginPage.class with page factory pattern will look like this:
Important thing to notice is that every time we call a method on web element, page factory search for our element all over again through page sources. If page isn’t AJAX-based, we can use page factory cache to search an element only with page factory initialization, and then retrieve it from cache:
@FindBy(id = “email”)
If you want to continue reading and expand your knowledge in area of Docker and Selenium Grid, I recommend you these books:
- Selenium WebDriver Practical Guide – there’re not many materials about Selenium Grid, but this books is a great read if you want to master not only Grid, but Selenium in general
As in every aspect of software development, design patterns in test automations help us to develop tests faster and more efficient. Page Object and Page Factory are two simple patterns, that significantly improve maintenance and readability of selenium tests. For complete sources of examples in this article please visit my github. If you have any questions, feel free to leave a comment!