Automated-Test/common/pageObject.py

133 lines
4.6 KiB
Python

from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
# Map PageElement constructor arguments to webdriver locator enums
_LOCATOR_MAP = {'css': By.CSS_SELECTOR,
'id': By.ID,
'name': By.NAME,
'xpath': By.XPATH,
'link_text': By.LINK_TEXT,
'partial_link_text': By.PARTIAL_LINK_TEXT,
'tag_name': By.TAG_NAME,
'class_name': By.CLASS_NAME,
}
class PageObject(object):
"""Page Object pattern.
:param webdriver: `selenium.webdriver.WebDriver`
Selenium webdriver instance
:param root_uri: `str`
Root URI to base any calls to the ``PageObject.get`` method. If not defined
in the constructor it will try and look it from the webdriver object.
"""
def __init__(self, webdriver, root_uri=None):
self.w = webdriver
self.root_uri = root_uri if root_uri else getattr(self.w, 'root_uri', None)
def get(self, uri):
"""
:param uri: URI to GET, based off of the root_uri attribute.
uri can be None
"""
root_uri = self.root_uri or ''
self.w.get(root_uri + uri)
class PageElement(object):
"""Page Element descriptor.
:param css: `str`
Use this css locator
:param id_: `str`
Use this element ID locator
:param name: `str`
Use this element name locator
:param xpath: `str`
Use this xpath locator
:param link_text: `str`
Use this link text locator
:param partial_link_text: `str`
Use this partial link text locator
:param tag_name: `str`
Use this tag name locator
:param class_name: `str`
Use this class locator
:param context: `bool`
This element is expected to be called with context
Page Elements are used to access elements on a page. The are constructed
using this factory method to specify the locator for the element.
# >>> from page_objects import PageObject, PageElement
# >>> class MyPage(PageObject):
elem1 = PageElement(css='div.myclass')
elem2 = PageElement(id_='foo')
elem_with_context = PageElement(name='bar', context=True)
Page Elements act as property descriptors for their Page Object, you can get
and set them as normal attributes.
"""
def __init__(self, context=False, **kwargs):
if not kwargs:
raise ValueError("Please specify a locator")
if len(kwargs) > 1:
raise ValueError("Please specify only one locator")
k, v = next(iter(kwargs.items()))
self.locator = (_LOCATOR_MAP[k], v)
self.has_context = bool(context)
def find(self, context):
try:
return context.find_element(*self.locator)
except NoSuchElementException:
return None
def __get__(self, instance, owner, context=None):
if not instance:
return None
if not context and self.has_context:
return lambda ctx: self.__get__(instance, owner, context=ctx)
if not context:
context = instance.w
return self.find(context)
def __set__(self, instance, value):
if self.has_context:
raise ValueError("Sorry, the set descriptor doesn't support elements with context.")
elem = self.__get__(instance, instance.__class__)
if not elem:
raise ValueError("Can't set value, element not found")
elem.clear()
elem.send_keys(value)
class MultiPageElement(PageElement):
""" Like `PageElement` but returns multiple results.
# >>> from page_objects import PageObject, MultiPageElement
# >>> class MyPage(PageObject):
all_table_rows = MultiPageElement(tag='tr')
elem2 = PageElement(id_='foo')
elem_with_context = PageElement(tag='tr', context=True)
"""
def find(self, context):
try:
return context.find_elements(*self.locator)
except NoSuchElementException:
return []
def __set__(self, instance, value):
if self.has_context:
raise ValueError("Sorry, the set descriptor doesn't support elements with context.")
elems = self.__get__(instance, instance.__class__)
if not elems:
raise ValueError("Can't set value, no elements found")
[elem.send_keys(value) for elem in elems]
# Backwards compatibility with previous versions that used factory methods
page_element = PageElement
multi_page_element = MultiPageElement