Python selenium page object example

Tutorial¶

Throughout this tutorial, we’ll use the following simple web page with a form to demonstrate the page objects pattern.

   Login Page   type="POST" action="/login">  type="text" name="username" id="user-input">  type="password" name="password">  type="submit">Submit    

Let’s assume also that this page is hosted on the url http://example.com/login

A simple Page Object¶

Here’s a simple page object that models this page.

>>> from page_objects import PageObject, PageElement >>> >>> class LoginPage(PageObject): username = PageElement(id_='user-input') password = PageElement(name='password') login = PageElement(css='input[type="submit"]') form = PageElement(tag_name='form') 

What is a Page Object?¶

It is a class that, when instantiated, models a single page on your website. It has attributes on it that model elements on the page. Accessing the attributes on the Page Object instance accesses the live elements on the page, thus removing the need for your test code to worry about how to go about finding them.

In our example, the LoginPage class is how the test will access the login page HTML, it has three attributes of type PageElement that refer to the three input elements, and one for the form.

Page Elements and locators¶

Page Elements allow you to specify in exactly one place how to find a particular element on your page. They are implemented using the Descriptor protocol which you can read more about here: https://docs.python.org/3.4/howto/descriptor.html. When constructing a Page Element, you specify the locator for the element, which can be any from the following table:

Keyword Arg Description
id_ Element ID attribute
css CSS Selector
name Element name attribute
class_name Element class name
tag_name Element HTML tag name
link_text Anchor Element text content
partial_link_text Anchor Element partial text content
xpath XPath

These map directly to Selenium Webdriver’s element accessor API which is documented here: http://selenium-python.readthedocs.org/en/latest/locating-elements.html

Using Page Objects¶

Page Objects are constructed with an instantiated webdriver instance, and optinally a root URI:

>>> from selenium import webdriver >>> driver = webdriver.PhantomJS() >>> page = LoginPage(driver, root_uri="http://example.com") 

Here I’ve used the PhantomJS webdriver which is a convenient way to test your site without needing a full browser stack installed. The root URI is purely to provide a base for the Page Object’s one and only method, get() :

This call above instructs the browser to load the url http://example.com/login.

Accessing Page Elements¶

To access elements on the page we get attributes on the page object. This will return a Selenium WebElement instance for the selector that was specified in the PageElement’s constructor. If the element is not found, it will return None .

For example, to check that the form above was using POST instead of GET, we would do the following.

>>> page.form >>> assert page.form.get_attribute('type') == 'POST' 

Here, accessing page.form gets the form element off of the page, allowing us to run the WebElement.get_attribute function to return its form type.

Interacting with Page Elements¶

We can interact with page elements in our tests as well. To type in text inputs, we can set attributes on the Page Object. This sends the text that we set on the attribute to the Selenium WebElement using its send_keys method.

For example, to fill in the form above, and then click the login button we would do the following:

>>> page.username = 'secret' >>> page.password = 'squirrel' >>> page.login.click() 

Multi Page Elements¶

Sometimes we we want to access lists of elements from the page. To do this there is a MultiPageElement class which is constructed exactly the same as PageElement .

>>> from page_objects import PageObject, MultiPageElement >>> >>> class LoginPage(PageObject): inputs = MultiPageElement(tag_name='input') 

When accessed, they return a list of the matching elements, or an empty list if there was nothing found.

You can send text to them all as well:

Elements with context¶

By default, when the PageElement objects are searching on the page for their matching selector, they are searching from the root of the DOM. Or to put it another way, they are searching across the whole page. Sometimes, it might be better to search within the context of another element if you have many similar items on the page.

Take this example where there are more than one login form on the page:

   id="login-1" type="POST" action="/login-1">  type="text" name="username">  type="password" name="password">  type="submit">Submit   id="login-2" type="POST" action="/login-2">  type="text" name="username">  type="password" name="password">  type="submit">Submit    

You could have separate page elements for each form input, like this:

>>> class LoginPage(PageObject): submit_1 = PageElement(css='#form-1 input[type="submit"]') submit_2 = PageElement(css='#form-2 input[type="submit"]') 

However, you can also construct the page elements with the context flag set like this:

>>> class LoginPage(PageObject): form1 = PageElement(id_='form-1') form2 = PageElement(id_='form-1') submit = PageElement(css='input[type="submit"]', context=True) 

This allows you to access the submit element within a form element, by calling the submit element like you would a method:

In this way, Page Elements with context are like ‘saved searches’.

Accessing the Webdriver directly¶

You can always access the webdriver that the Page Object was constructed with direcly, using the w attribute.

>>> page.w >> page.w.current_url 'http://example.com/login' 

© Copyright 2014, Edward Easton.

Versions latest stable Downloads pdf htmlzip epub On Read the Docs Project Home Builds Free document hosting provided by Read the Docs.

Источник

6. Page Objects¶

This chapter is a tutorial introduction to the Page Objects design pattern. A page object represents an area where the test interacts within the web application 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 the python.org website and ensures some results. The following section will introduce the page module where the page objects will be defined.

import unittest from selenium import webdriver import page class PythonOrgSearch(unittest.TestCase): """A sample test class to show how page object works""" def setUp(self): self.driver = webdriver.Firefox() self.driver.get("http://www.python.org") def test_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 title self.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 empty self.assertTrue(search_results_page.is_results_found(), "No results found.") def tearDown(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 actual code that interacts with the web page.

The page.py will look like this:

from element import BasePageElement from locators import MainPageLocators class SearchTextElement(BasePageElement): """This class gets the search text from the specified locator""" #The locator for search box where search string is entered locator = 'q' class BasePage(object): """Base class to initialize the base page that will be called from all pages""" def __init__(self, driver): self.driver = driver class MainPage(BasePage): """Home page action methods come here. I.e. Python.org""" #Declares a variable that will contain the retrieved text search_text_element = SearchTextElement() def is_title_matches(self): """Verifies that the hardcoded text "Python" appears in page title""" return "Python" in self.driver.title def click_go_button(self): """Triggers the search""" element = self.driver.find_element(*MainPageLocators.GO_BUTTON) element.click() class SearchResultsPage(BasePage): """Search results page action methods come here""" def is_results_found(self): # Probably should search for this text in the specific page # element, but as for now it works fine return "No results found." not in self.driver.page_source 

6.3. Page elements¶

The element.py will look like this:

from selenium.webdriver.support.ui import WebDriverWait class BasePageElement(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.driver WebDriverWait(driver, 100).until( lambda driver: 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.driver WebDriverWait(driver, 100).until( lambda driver: driver.find_element_by_name(self.locator)) element = driver.find_element_by_name(self.locator) return element.get_attribute("value") 

6.4. Locators¶

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

The locators.py will look like this:

from selenium.webdriver.common.by import By class MainPageLocators(object): """A class for main page locators. All main page locators should come here""" GO_BUTTON = (By.ID, 'submit') class SearchResultsPageLocators(object): """A class for search results locators. All search results locators should come here""" pass 

Источник

Читайте также:  Почему python не любят
Оцените статью