Skip to main content

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 and Element(s) classes.
  • Write test scripts simply and elegantly using the constructed Page objects.

Example Code

  1. First, construct a Page object in any Python file, each page recommended to be a separate Page class.
  2. 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
  1. After constructing the Page object in my_page.py, you can begin writing test cases.
  2. 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()
  1. 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.

  2. 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


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 details)

Uploaded Source

Built Distribution

huskypo-1.3.0-py3-none-any.whl (55.0 kB view details)

Uploaded Python 3

File details

Details for the file huskypo-1.3.0.tar.gz.

File metadata

  • Download URL: huskypo-1.3.0.tar.gz
  • Upload date:
  • Size: 52.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.11.3

File hashes

Hashes for huskypo-1.3.0.tar.gz
Algorithm Hash digest
SHA256 3fcfa27673d99dc9b4b975efb662e48b87daa7ac3e36d2b2f990a84900dc3d7b
MD5 4daeca0bbe43fae124d06bff08072285
BLAKE2b-256 a47876b8e8517e2c120276435cc9a60f78eb3931fe03cd5066bda41e7eb2d470

See more details on using hashes here.

File details

Details for the file huskypo-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: huskypo-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 55.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.11.3

File hashes

Hashes for huskypo-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c7d8c0022cae5882b5ba1bf0d132a2c5fcb9823199c91c98fe75fa8ecab6c4a5
MD5 f7fa82d197bd34f0a95ff8136af133cd
BLAKE2b-256 1931b4dd9987a1ed9c34b2180660b32433477202c3cc5b0f16bf13cc02d08f70

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page