An opinionated framework for writing page objects for selenium tests/scripts


Keywords
selenium, page-object, testing, automation, test, tests, python, python27, python3, selenium-webdriver, test-automation, testing-tools
License
MIT
Install
pip install vom==2.0.0

Documentation

Build Status PyPI version

vom

vom (View Object Model) is an opinionated framework for writing page objects for selenium tests/scripts

Installation

Tested on Python 2.7.x & 3.6.x

$ pip install vom

Usage

Defining view objects is as easy as extending View:

from vom import View

class LoginForm(View):
    @property
    def username(self):
        return self.find_element_by_id("username")
    
    @property
    def password(self):
        return self.find_element_by_id("password")
    
    @property
    def submit_button(self):
        return self.find_element_by_css_selector("input[type='submit']")

Lets initialize the view object:

login = LoginForm(lambda: driver.find_element_by_id("login-form"))

The view object is initialized by passing a Callable[[], WebElement]. The WebDriver instance is object from the WebElement. Its a Callable because we need to be able to get a fresh reference to the WebElement at any time. See StaleElementReferenceException

Passing a lambda can be cumbersome. The ViewDriver utility class can streamline this.

Root WebElement

The WebElement returned from the Callable[[], WebElement] will serve as the root for the view object.

Method Calls

View will proxy all undefined methods to its WebElement allowing you to treat them as a super powered WebElement.

Querying

Querying for a view object's elements can be done with the same methods you use on WebElement. All of the results from these calls are then wrapped in a View. Custom view object implementations can be passed for advanced logic.

from vom import View

class OptionComponent(View):
    @property
    def switch(self):
        self.find_element_by_id("switch")
    
    def toggle(self):
        self.switch.click()

class SearchForm(View):
    @property
    def some_search_option(self):
        self.find_element_by_id("some-search-option-id", OptionComponent)

search = SearchForm(lambda: driver.find_element_by_id("search-form"))
search.some_search_option.toggle()

Utility Methods

There are a number of utility methods to supplement the WebElement methods.

Find Element/s by Text

Similar to find_element/s_by_link_text & find_element/s_by_partial_link_text but across all tags. They also allow for a custom selector.

  • find_elements_by_text(value, selector="*")
  • find_element_by_text(value, selector="*")
  • find_elements_by_partial_text(value, selector="*")
  • find_element_by_partial_text(value, selector="*")

Find Input/s

  • find_inputs_by_placeholder(value)
  • find_input_by_placeholder(value)

Properties

  • title Return the WebElement title property
  • has_class(value) Returns if WebElement has css class

Content

  • inner_html Returns the innerHTML of the WebElement
  • outer_html Returns the outerHTML of the WebElement
  • inner_text Returns the innerText of the WebElement

Waiting

  • wait_until_displayed(timeout=10)
  • wait_until_not_displayed(timeout=10)

Actions

  • focus() Focus the WebElement
  • blur() Blur the WebElement

Execute Script

Similar to driver.execute_script but arguments[0] is a reference to the root element of the View.

  • execute_script(script, *args)
  • execute_async_script(script, *args)

Transform

  • as_select Return the WebElement wrapped in a Select

ViewDriver

ViewDriver is a utility class which wraps WebDriver. It provides similar find_element/s methods that View does.

from selenium import webdriver
from vom import ViewDriver

if __name__ == '__main__':
    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    driver = ViewDriver(webdriver.Chrome(chrome_options=options))

    driver.get("http://example.com")

    login = driver.find_element_by_id("login-form", LoginForm)
    login.username.send_keys("")
    login.password.send_keys("")
    login.submit_buttom.click()