6.Page Objects

This chapter is a tutorial introduction to the Page Objects design pattern. Apage object represents an area where the test interacts within the webapplication user interface.

Benefits of using page object pattern:

  • Easy to read test cases

  • Creating reusable code that can share across multiple test cases

  • Reducing the amount of duplicated code

  • If the user interface changes, the fix needs changes in only one place

6.1.Test case

Here is a test case that searches for a word on thepython.org website andensures some results. The following section will introduce thepage modulewhere the page objects will be defined.

importunittestfromseleniumimportwebdriverimportpageclassPythonOrgSearch(unittest.TestCase):"""A sample test class to show how page object works"""defsetUp(self):self.driver=webdriver.Firefox()self.driver.get("http://www.python.org")deftest_search_in_python_org(self):"""Tests python.org search feature. Searches for the word "pycon" then        verified that some results show up.  Note that it does not look for        any particular text in search results page. This test verifies that        the results were not empty."""#Load the main page. In this case the home page of Python.org.main_page=page.MainPage(self.driver)#Checks if the word "Python" is in titleself.assertTrue(main_page.is_title_matches(),"python.org title doesn't match.")#Sets the text of search textbox to "pycon"main_page.search_text_element="pycon"main_page.click_go_button()search_results_page=page.SearchResultsPage(self.driver)#Verifies that the results page is not emptyself.assertTrue(search_results_page.is_results_found(),"No results found.")deftearDown(self):self.driver.close()if__name__=="__main__":unittest.main()

6.2.Page object classes

The page object pattern intends to create an object for each part of a web page.This technique helps build a separation between the test code and the actualcode that interacts with the web page.

Thepage.py will look like this:

fromelementimportBasePageElementfromlocatorsimportMainPageLocatorsclassSearchTextElement(BasePageElement):"""This class gets the search text from the specified locator"""#The locator for search box where search string is enteredlocator='q'classBasePage(object):"""Base class to initialize the base page that will be called from all    pages"""def__init__(self,driver):self.driver=driverclassMainPage(BasePage):"""Home page action methods come here. I.e. Python.org"""#Declares a variable that will contain the retrieved textsearch_text_element=SearchTextElement()defis_title_matches(self):"""Verifies that the hardcoded text "Python" appears in page title"""return"Python"inself.driver.titledefclick_go_button(self):"""Triggers the search"""element=self.driver.find_element(*MainPageLocators.GO_BUTTON)element.click()classSearchResultsPage(BasePage):"""Search results page action methods come here"""defis_results_found(self):# Probably should search for this text in the specific page# element, but as for now it works finereturn"No results found."notinself.driver.page_source

6.3.Page elements

Theelement.py will look like this:

fromselenium.webdriver.common.byimportByfromselenium.webdriver.support.uiimportWebDriverWaitclassBasePageElement(object):"""Base page class that is initialized on every page object class."""def__set__(self,obj,value):"""Sets the text to the value supplied"""driver=obj.driverWebDriverWait(driver,100).until(lambdadriver:driver.find_element(By.NAME,self.locator))driver.find_element(By.NAME,self.locator).clear()driver.find_element(By.NAME,self.locator).send_keys(value)def__get__(self,obj,owner):"""Gets the text of the specified object"""driver=obj.driverWebDriverWait(driver,100).until(lambdadriver:driver.find_element(By.NAME,self.locator))element=driver.find_element(By.NAME,self.locator)returnelement.get_attribute("value")

6.4.Locators

One of the practices is to separate the locator strings from the place wherethey are getting used. In this example, locators of the same page belong to thesame class.

Thelocators.py will look like this:

fromselenium.webdriver.common.byimportByclassMainPageLocators(object):"""A class for main page locators. All main page locators should come here"""GO_BUTTON=(By.ID,'submit')classSearchResultsPageLocators(object):"""A class for search results locators. All search results locators should    come here"""pass