Page Object Model in Selenium Python | POM in Selenium Python

Selenium Python – Page Object Model

Selenium is an open-source test automation tool. Like other commercial tools in the market, it doesn’t come up with an inbuilt feature to manage object information which we use in creating test scripts. So we need to take the help of design patterns like POM to manage these artifacts. In this chapter, we will understand how to create them and what benefits they bring to the table.

Structure

  • Page Object Model (POM)
  • Implementing the POM • Example of login logout scenario

Objective

This chapter will help us understand the concept of a design pattern called Page Object Model (POM), and how to implement it to make our scripts more robust.

Page Object Model (POM)

Page Object Model (POM) is a design pattern that helps us to separate the object information from the business logic of a page from the application. The idea behind this is, if the object information changes from one build release to another, the business logic is not impacted at the code level, and we only make changes at the object information level. To achieve this we need to implement a POM design pattern at our code level.

Creating Selenium test cases can result in an unmaintainable project. One of the reasons is that too much-duplicated code is used. Duplicated code could be caused by duplicated functionality and this will result in duplicated usage of locator information to identify the objects on a page. The disadvantage of duplicated code is that the project is less maintainable. If some locator will change, you have to walk through the whole test code to adjust locators where necessary.

Implementing the POM

By using the POM we can make non-brittle test code and reduce or eliminate duplicate test code. Besides, it improves readability and allows us to create interactive documentation. Last but not least, we can create tests with fewer keystrokes.
The concept of POM says that when we look at a page, we should see if it has got two components:

  • Objects
  • Business logic

So the page has a business logic, and to achieve that business objective there are objects available on the page. We need to segregate these two entities. The reason for this is, that over a period of time as an application undergoes changes the object information can get changed more frequently, making the maintenance of the code a humongous effort. Let us take an example of the My Account Page here from our application: http://practice.bpbonline.com/catalog/login.php
The business logic of the page says:

  • If there exists a new user, allow them to create a new account.
  • If there is a registered user with valid credentials allows them to log in.
  • If there is a registered user, but who has forgotten credentials, allow them to fetch the password.
  • Not allow a user with invalid credentials to log in.

To achieve these business functions, the page is designed with the following objects:

  • Username textbox
  • Password textbox
  • Sign-in button
  • Continue button

Please find the following screenshot explaining the preceding bullet points:

Selenium Python - Page Object Model chapter 11 img 1

By keeping object information separate from business logic, we are able to manage and achieve modularity and robustness at the code level. As we find during build release cycles, the object information may change over a period of time, so only the files where object information is stored need to be changed, whereas the test logic which is consuming these objects will not get affected by it.

In this chapter, we will see how we will implement POM for the login logout scenario of our application.

from selenium.webdriver.common.by import By

# for maintainbility We can seperate web objects by page name

class mainpageLocators(object):
MYACCOUT    = (By.LINK_TEXT, 'My Account')

class LoginpageLocators(object):
Email       = (By.NAME,   'email_address')
PASSWORD    = (By.NAME,   'password')
SIGNIN      = (By.ID,   'tab1')


class LogoutpageLocators(object):
LOGOFF     = (By.LINK_TEXT, 'log off')
continue   = (By.LINK_TEXT, 'continue')

So, if the object information in any of the upcoming builds changes, we can come to this file, and change the information associated with that object. In another file, called as pages. py we call the action associated with each object:

class Mainpage(page):
    def click_myaccount(self):
        self.find_element(*mainpageLocators.MYACCOUNT).click( )
        return self.driver

class Loginpage(page):
     def enter_email(self, email):
        self.find_element(*LoginpageLocators.EMAIL).send_keys(email)

def enter_password (self,pwd):
    self.find_element(*LoginpageLocators.PASSWORD).send_keys(pwd)

def click_login_button(self):
    self.find_element(*LoginpageLocators.SIGNIN).click( )

def login(self, email,pwd):
    self.enter_email(email)
    self.enter_password(pwd)
    self.click_login_button( )
    return self.driver


class Logoutpage(page):
   def click_logoff(self):
       self.find_element(*LogoutpageLocators.LOGOFF).click()

def click_continue(self):
     self.find_element(*LogoutpageLocators.CONTINUE).click( )

def logout(self):
    self.click_logoff( )
    self.click_continue( )

Now, we will create the test scenarios:

def test_sign_in_with_valid_user(self):
mainpage = mainpage(self . driver)
mainpage . Click_myaccount( )
loginpage=loginpage(self.driver)
loginpage . login("bpb@bpb.com","bpb@123")
logoutpage=logoutpage(self.driver)
logoutpage . logout ( )

As we can see, our actual test scenario looks clean, easy to read. Since object information is now hidden in the other files, the test can concentrate on actual test logic.

Conclusion

In this chapter, we learned the importance and need for POM to manage and maintain object information in the form of page objects. This is necessary as Selenium by default doesn’t come with any feature like object repository to manage and maintain object information. POM helps us create modular and robust code.
In our next chapter, we will discuss the concept of Selenium Grid, which as a component, allows us to execute scenarios in parallel.

Related Articles: