What is Base Page Object?

Context:

In the previous section on what is page-object, we talked about how to represent a web page into a page-object, initialize the elements using webdriver and then accessing them in step_definitions.

Since we had only one page-object, we really couldn’t see the issues we might face as code grows. In this section, lets see what is the problem when we define page-objects as we did and the code gets larger and larger. Yes sure, it works as is !

KISS principle:

But we do want to follow KISS (keep it simple stupid) right [Anyways, I have my own qualms about this KISS principle and where it doesn’t apply and how it can be masked into too much of abstraction, but that’s for a later discussion]

The Problem:

Let’s say hypothetically that I had 3 behave scenarios and each scenario would interact with the home page and do further steps. The scenarios from a high level perspective do the following. We will be using automationpractice website.

  1. Go to home page, click sign in, and further steps
  2. Go to home page, verify phone number is correct, then only click sign in
  3. Go to home page, click contact us and further steps

The home page looks as below [The corresponding html locator information is also posted]

element_html_map

Home page-object:

The Login page might look as below

The Contactus Page might look as below

behave Scenarios:

 

Problem 1

We are repeating a lot of code with getters. Can we write a common Base Page, that has methods common to all Page Objects and all Page Objects inherit from that Base Page. That way, any commonality can be defined in the Base Page.

What commonalities?

  • The webdriver handle to the browser
  • Getter methods that can automatically poll the DOM when called and return the WebElement to the calling code (We anyways know that Selenium webdriver does lazy loading i.e. unless we actually need an element, webdriver is NOT going to initialize all elements in the DOM)
  • Can we have some basic checks like “presence of element” and “visibility of element” true before returning the element ?
  • Maybe define default timeout for the driver to poll DOM for elements
  • A generic method for finding element

Solution 1

All of the above can be achieved and below is my base Page Object. It is based on the following assumptions:

  1. There is a locator dict defined in every Page Object, that specifies the locator information for that element
  2. Every Page Object inherits from this Base Page Object
  3. It is also assumed that all attributes of Page Objects are locators i.e. every attribute is defined in the form of a python sequence (By.<X>,'<value’). The reason because we intercept the __get__attr() method when we reference an attribute from the Page Object and use webdriver to find that element and return it. This will greatly reduce the getter methods that we defined previously in every Page Object.
  4. Finally, if there is NOT such an attribute , we defined a method_missing function, that gets called if the attribute is NOT present in the locator dictionary of the Page Object

Base Page Object

Further Improvements ?

Page Factory

I would really like to have the same readability that I had in Ruby blocks (Refer to Page-object pattern framework with Ruby)

However after searching a lot on forums, it seems like we cannot get the exact pattern with Python. Sure we can implement anonymous functions with lambda, but I do NOT want lamba word in the code. Seems like Python had the construct “with <object> as alias:” with Python 1 and 2, but 3 doesn’t seem to work.

Below is what I tried

Calling Code:

 

The above results in an exception as seems like Python 3 doesn’t support this construct. Again not sure, but after struggling for a while, I gave up and moved on because my base page obect implements what I needed to do for now.

I figured I would instantiate the Page Objects inside the step definitions and move on.

If anyone can help me implement the same Ruby construct in Python, please email me and I will return the favor in the form or credits for you on the website.

 

Using Base Page Object:

After applying the page-factory pattern, the step_definitions code would look as below, pretty , clean and KISS right 🙂

But Dude..

What about asynchronous behavior, where html elements detach from DOM and lose their reference with webdriver, that means my page-object that was used a while ago may have stale html elements right ?

Bingo! (You should feel like Neo in Matrix when he asks that question to Oracle…haha)

Right, so you would come across StaleElementReference exceptions in extremely ajax applications. There are strategies to handle this with page-objects and page-factory too. We will talk about some strategies in the closing pages of this section.

Next:

So we talked about page-factory pattern and how it might be useful to us. The next section is where we would take a concrete workflow on an e-commerce website and implement page-object and page-factory patterns.

Just as a reminder, we will be adhering to the Roadmap and Future section, so would request you to read that once again if you did not already.