UI Automation Page Objects design pattern.
Project description
huskyPO
Copyright
- Developer: Johnny Chou
Overview
- huskyPO stands for husky Page Object, named 'husky' due to the author's fondness.
- Constructed using Python's data descriptors, it's a UI Page Object package.
- Enables developers to build Python Selenium/Appium UI automation scripts more easily and elegantly.
Features
- Significantly simplifies and beautifully constructs Page objects and test scripts.
- Encapsulates and integrates commonly used methods of Selenium and Appium, with optimizations in certain functions.
- Uses explicit waiting as the core driving mechanism, and extends some official explicit waiting methods.
Usage
- Build page objects simply and elegantly using the
Page
andElement(s)
classes. - Write test scripts simply and elegantly using the constructed Page objects.
Example Code
- First, construct a Page object in any Python file, each page recommended to be a separate Page class.
- For example, in the my_page.py file:
from huskypo import Page, Element, Elements
from huskypo import By
from huskypo import dynamic
class MyPage(Page):
# Static elements, equivalent to the normal setup of page objects.
# Similar to constructing Python instance objects.
search_field = Element(By.NAME, 'q', remark='Search input box')
search_results = Elements(By.TAG_NAME, 'h3', remark='All search results')
search_result1 = Element(By.XPATH, '//h3[1]', remark='First search result')
# Dynamic elements, suitable for special test scenarios
# where element locator info is decided at runtime during the test case.
# Typically, dynamic elements make up a very small proportion;
# if the test environment is robust and stable,
# it's advisable to mostly use static elements.
# Dynamic elements need to be written as instance methods of the Page class,
# and must be decorated with @dynamic to function properly.
@dynamic
def search_result(self, order: int = 1):
return Element(By.XPATH, f'//h3[{order}]', remark=f'Search result no.{order}')
@dynamic
def keyword_results(self, keyword: str):
return Elements(By.XPATH, f'//*[contains(text(), "{keyword}")]')
# If you must set dynamic elements as properties, follow this order:
@property
@dynamic
def keyword_results(self):
return Elements(By.XPATH, f'//*[contains(text(), "{Keyword.text1}")]')
# If you want to record information about dynamic elements and reuse it,
# it is recommended to revert to the official standard data descriptor dynamic assignment method.
# 1. You must first create an object of a data descriptor, such as static_element.
# 2. Create a function corresponding to static_element and assign a value to static_element,
# This assignment method utilizes the "__set__" method of the data descriptor.
# The parameters given is the same as the way of initializing the "Element".
# 3. When executing the testcase, first call dynamic_element.
# If the subsequent elements no longer change, you can directly use static_element for operations.
static_element = Element()
def dynamic_element(self, par) -> Element:
# __set__ will get the tuple and assign it to Element to initialize static_element.
# The logic of tuple is exactly the same as the method of placing parameters in an Element,
# such as (by, value, index, timeout, remark).
# It also includes other configuration methods mentioned in the Element documentation,
# such as (by, value, remark), and so on.
self.static_element = (By.XPATH, f'//*[contains(text(), "{par}")]', f'This is {par}')
return self.static_element
def dynamic_element(self, par) -> Element:
# If you want to clearly specify parameter names, you can also use a dictionary.
self.static_element = {
'by': By.XPATH,
'value': f'//*[contains(text(), "{par}")]',
'remark': f'This is {par}'}
return self.static_element
- After constructing the Page object in my_page.py, you can begin writing test cases.
- For example, the content of the test_my_page.py file:
from selenium import webdriver
from my_page import MyPage
class TestMyPage:
driver = webdriver.Chrome()
my_page = MyPage(driver)
my_page.get("https://google.com")
my_page.search_field.wait_present()
my_page.save_screenshot("my/file/path/image.png")
search_keyword = 'automation'
my_page.search_field.send_keys(keyword, Keys.ENTER)
my_page.search_results.wait_any_visible()
my_page.save_screenshot("my/file/path/image.png")
assert my_page.keyword_results(search_keyword).quantity > 1
assert search_keyword in my_page.search_result1.text
my_page.search_result1.click()
...
driver.close()
-
By using the simple examples above, you can see how we can construct Page objects and write scripts intuitively and beautifully with Page, Element(s) classes, and using page.element.method() style.
-
All the element finding processes rely on explicit waiting methods, the core mainly being the official WebDriverWait and expected_conditions, this package extends the commonly used conditions of present, visible, clickable, selected in the Element(s) class and the driver methods and other page-related operations are encapsulated in the Page class.
TODO
- Continuously monitor new features in Selenium 4.0 and Appium 2.0.
- Other optimizations.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
huskypo-1.3.0.tar.gz
(52.8 kB
view hashes)
Built Distribution
huskypo-1.3.0-py3-none-any.whl
(55.0 kB
view hashes)