Leveling up POM - BasePage
At this point, you have a base project that includes pages and tests, following the Page Object Model pattern. However, we can make certain adjustments to level up our project and make it better in terms of the pattern's usage and make our life easier.
Pre-conditions:
You should have completed this tutorial where the base project is structured for POM.
Certain methods are used repetitively for all the pages, for example, finding elements, clicking on buttons, entering a text, and so on. Those shared methods are better to be located on a single page. We will do this by creating a BasePage, which will be the parent of all pages, therefore we'll inherit all those methods.
a. Under the pages folder, create a base_page.py file. b. Add the code below to create the class stub, add the constructor, and add the methods for:
- Finding element and elements
- Clicking on an element
- Typing on a text element
class BasePage:
# Constructor that will receive the browser parameter.
def __init__(self, browser):
self.browser = browser
# This method will be reused by all the methods that require interact with an element.
def get_element(self, element):
return self.browser.find_element(*element)
# This method will be return a list of elements.
def get_elements(self, element):
return self.browser.find_elements(*element)
# A method to click on any element, using the local method to find element.
def click_on_element(self, element):
self.get_element(element).click()
# This method will get the element with the local method, then clear the text and insert the new text.
def type_on_element(self, element, value):
elem = self.get_element(element)
elem.clear()
elem.send_keys(value)
c. Let's go to the Search page first and update it so that it inherits from the Base page and then update the selenium methods to use our custom methods from the Base page.
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from pages.base_page import BasePage
class DuckDuckGoSearchPage(BasePage):
URL = "https://www.duckduckgo.com"
SEARCH_INPUT = (By.ID, "search_form_input_homepage")
def __init__(self, browser):
super().__init__(browser)
def load(self):
self.browser.get(self.URL)
def search(self, phrase):
self.type_on_element(self.SEARCH_INPUT, phrase + Keys.RETURN)
d. Let's do the same thing on the Results page.
from selenium.webdriver.common.by import By
from pages.base_page import BasePage
class DuckDuckGoResultPage(BasePage):
LINK_DIVS = (By.CSS_SELECTOR, "#links > div")
SEARCH_INPUT = (By.ID, "search_form_input")
@classmethod
def PHRASE_RESULTS(cls, phrase):
xpath = f"//div[@id='links']//*[contains(text(), '{phrase}')]"
return (By.XPATH, xpath)
def __init__(self, browser):
super().__init__(browser)
def link_div_count(self):
return len(self.get_elements(self.LINK_DIVS))
def phrase_result_count(self, phrase):
return len(self.get_elements(self.PHRASE_RESULTS(phrase)))
def search_input_value(self):
search_input = self.get_element(self.SEARCH_INPUT)
return search_input.get_attribute("value")
That's it! You have successfully upgraded your POM to a more adequate architecture. That's only the tip of the iceberg, few other useful methods can be added to the Base page, and also, we could add a Util class for other generic methods.
Additional resource: Handling Race Conditions