Package: seleniumpm
Selenium-PageModelThis project helpsTest Engineersby abstracting out the implementation – in this case Selenium – from the actual set ofActionsnecessary to perform a singleTest Scenario. TheSelenium-PageModellibrary does this by defining a set of well definedPageModelconstructs thatTest Engineerscan extend/implement to describe a Website. ThesePageModelconstructs includes the following:WebPageButtonCheckboxDropdownLinkTableTextElementTextFieldWidgetUsing these constructs, you can describe aWebPageas having the following web-elements:A HeaderWidgetcontaining:A HomeLinkA LoginLinkA RegisterLinkA formWidgetcontaining:A userNameTextFieldA passwordTextFieldA submitButtonButtonA potential Error messageTextElement(in the event of a login failure)Once aPageModelis defined, alogin testfor an imaginary website may look like this:homePage.open();
loginPage.waitForPageLoad().validate();
loginPage.userName.type("myuser");
loginPage.password.type("mypassword");
loginPage.submitButton.click();
homePage.waitForPageLoad().isLoggedIn();Please see the project’s Homepage for more information:Selenium-PageModelInstallationThe library can be installed via:pip install seleniumpmOr if you want to install from src:pip install git+https://github.com/gradeawarrior/python-seleniumpm.gitUsageHere is the ever so popular Google example usingseleniumpm:from selenium import webdriver
from seleniumpm.examples.google_page import GooglePage

"""
Setup for Remote execution against a local standalone-selenium-server
and using the PhantomJS driver. This can be changed of course to using
the driver of your choice (e.g. Chrome or Firefox)
"""
driver = webdriver.Remote(command_executor="http://localhost:4444/wd/hub", desired_capabilities=webdriver.DesiredCapabilities.PHANTOMJS)

# Instantiate Google Page
google = GooglePage(driver, url="https://www.google.com")

# Open + wait for page load + validate Google
google.open().wait_for_page_load().validate()

# Print the page title
print google.get_title()

# Search for 'Cheese!'
search_str = "Cheese!"
google.search_field.type(search_str)
google.search_field.submit()

# Ensure that the page is refreshed from your search
print google.wait_for_title(search_str).get_title()Creating your PageObject’sThe GooglePage used in the above example looks like the following:from selenium.webdriver.common.by import By
from seleniumpm.webpage import Webpage
from seleniumpm.webelements.textfield import TextField
from seleniumpm.locator import Locator

class GooglePage(Webpage):
    def __init__(self, driver, url=None):
        super(GooglePage, self).__init__(driver, url)
        self.search_field = TextField(driver, Locator.by_name('q'))

    def get_result_links(self):
        links = []
        elements = self.driver.find_elements(By.XPATH, "//h3[contains(@class, 'r')]/a")
        for element in elements:
            links.append(element.get_attribute("href"))
        return linksYou should notice that most of the operations except for get_result_links() are not visible on the GooglePage class. That is because the basic behaviors are either part of the Webpage or the TextField (aka an Element) type.For more information about writing your PageObject’s in SeleniumPM, please direct your attention toCreating-your-PageObject-with-SeleniumPMLanguage SupportThe Selenium PageModel implementation is not limited to just one language. Here are other language implementations:Java-Java-SeleniumPMRuby- In consideration depending on needs and popularity.Contributing to SeleniumPMCheck out the latest master to make sure the feature hasn’t been implemented or the bug hasn’t been fixed yet.Check out the issue tracker to make sure someone already hasn’t requested it and/or contributed it.Fork the project.Start a feature/bugfix branch.Commit and push until you are happy with your contribution.Make sure to add tests for it. This is important so I don’t break it in a future version unintentionally.Please try not to mess with the version or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so that I can cherry-pick around it.ReferencesA huge shoutout to Peter Downs for his very easy-to-follow instructions for submitting a Python package to the community. Seefirst time with pypifor his instructions.Also see the following:selenium-server-runner- If you’re running on a Mac, this project helps you setup and run thestandalone-selenium-serveron your laptopJava-SeleniumPM- The Java version ofSeleniumPMrequestests- An API testing libraryPackage Dependencies:seleniumpminstalls the following upstream packages as of the latest release:selenium~=2.53.6CopyrightCopyright (c) 2017 Peter Salas. See LICENSE for
further details.Release HistoryFUTURE (UN-RELEASED)New Features:Added highlight() feature to all Element typesSupport defining locators as tuplesAdding utility for scanning a path and generating json output of all the PageObject structures in the projectAdded get_webelement_by_text() to Element typesFixed:Moving upload of wheel to use twine instead of setup.py. See the following link for why:https://packaging.python.org/distributing/#wheelsFixed issue with validating a Widget with locator = None on a Webpage2.13.0 (2017-05-18)New Features:Removed snapshot featureFixed:2.12.2 (2017-05-09)New Features:Implementing await_for_page_load(Default: False) on Webpageopen(),refresh(), andreload()operationsFixed:Webpage.refresh() and Webpage.reload() did not return self2.12.1 (2017-05-08)New Features:Fixed:Turning off snapshot feature during is_page() and is_widget_loaded() operations. These operations often time trigger TimeoutException but it should not trigger a snapshot to be taken.2.12.0 (2017-05-07)New Features:Implementing to_json() and to_json_pp() for Element, Widget, Locator, and Webpage typesAdding additional wait_for_widget_load() timer to calculate load time of a widgetAdding more logging across seleniumpm. Most are WARNING levels, so this will need to be set accordinglyImplemented a is_widget_loaded() for all Widget types. This also includes both Panel and IFrame typesAdded ability to enumerate over all elements defined on a webpage and/or widget, and then return all elements that failed their checks for presence and visibility. The ability is built directly intowait_for_page_load(),validate(), andwait_for_widget_load(). This check is controlled via parameter and global selenium configfailfast_check_element(Default: True). This is set to True by default for old behavior of throwing exception on the first element that is not present/visible. Setting this to False will enable this feature and will check each element before raising the expected TimeoutException with a message containing all the elements that failed.NOTE: Depending on the timeout, this could potentially be a compounded amount of time before the method returns, hence why this feature is disabled by default.Fixed:Element.dict() had an issue if the locator was NoneWidget.validate() force_check_visibility was accidentally set to True when expected to be False. This ended up causing unexpected conditions in a test where some elements were marked as invisible, but validate() was still checking for visibility2.11.8 (2017-05-05)New Features:For validate() and wait_for_page_load() operations, adding the meta-data for the Class and attribute name of the element that is being checked. This is so that if there is a TimeoutException, we can also report where we can find this element to fix in the codeAdd Logger for better debugging capability for testing purposes.Fixed:2.11.7 (2017-05-02)New Features:Fixed:Moving click_index() from Clickable to Element type.2.11.6 (2017-05-02)New Features:Fixed:Adding Clickable.click_index() and Element.get_index_of_text() to indirectly address StaleElementReferenceException. Unfortunately, the problem may still arise and some experts say that StaleElementReferenceException is by design and should generally be “fixed” on a case-by-case basis and should not be fixed in a wrapper framework like seleniumpm nor will it be addressed in the Selenium core library.2.11.5 (2017-05-01)New Features:Adding the following ‘wait_for’ methods to Element: wait_for_webelements(), wait_for_text(), and wait_for_texts()Fixed:Element.wait_for_present_and_visible() did not have a return selfAdding mark_check() and mark_visible() to complement the existing mark_do_not_check() and mark_invisible()2.11.4 (2017-04-26)New Features:Adding unselect() to Checkbox and select() to both RadioButton and Checkbox types.Adding a new Label type. Right now, this is effectively the same as a TextElement or an ElementFixed:2.11.3 (2017-04-20)New Features:Fixed:Fixing a missed-case configuringdisable_check_for_selenium_webdriver(Default: False) on a Webpage2.11.2 (2017-04-20)New Features:Adding new configdisable_check_for_selenium_webdriver(Default: False) which now makes is possible to disable this check on an Element. Apparently, there are situations where a developer may pass in a non-webdriver object that overrides __getattr__() to returns driver.__getattribute__(item)Fixed:2.11.1 (2017-04-18)New Features:Adding a check_myself flag (Default: True) on a Widget/Panel/IFrame type. This is to support certain scenarios where a developer may want to validate the collection of elements found in an Widget/Panel/IFrame, but not actually validate itself. Again, this is because Widget/Panel/IFrame is of type Element and thus has a locator.Fixed:2.11.0 (2017-04-18)New Features:Adding a get_html() capability to return back either an entire page or the inner-html of a specific element. This is implemented on a Webpage, an IFrame, and Element types.Adding a wait_for_iframe_load() to IFrame typeAdded stop-watch capabilities (e.g. start, stop, split) to a Webpage and Element types. In addition, a basic page load timer has been implemented. Basically, every wait_for_page_load() and wait_for_iframe_load() will calculate a duration time automatically.Removed requirement that a Widget/Panel/IFrame type must define a Locator. This is to support situations where a developer doesn’t want to validate the location of the Widget, but instead just wants to validate the objects that are within a Widget. This is similar to a Webpage validation.Fixed:Fixed scenario for __getattr__ where a developer could decorate a method with @property, and thus could execute code that results in an Error/Exception.Added try/finally block to the validate() operation on an IFrame. This is to handle the situation when a sub-webpage (a.k.a. an iFrame) fails a validation; in this situation, we want to make sure that we allow going back to the top-level-webpage in the event of a Error.2.10.0 (2017-04-07)New Features:Added a get_attribute_contains() and a get_attribute_is() on Element type. The intention is to implement an all-in-one solution for both retrieving an attribute and validating whether something contains or is something. This operation is useful for dynamic elements that use css classes for changing the state of a page (e.g. <div class=’svgOverviewView-status-icon fa fa-exclamation-triangle svg-status-warning’>); One could define a generic reference to this element, and then use get_attribute_contains() to check if it now contains ‘fa-exclamation-triangle’ css class.Implementation of seleniumpm.config module. This module can be imported viaimport seleniumpm.config as seleniumconfig; and variables can be changed like so:seleniumconfig.page_timeout_in_sec = 60Added a globalelement_timeout_in_msandpage_timeout_in_msto seleniumpm.config module. Defaults are still 10s for element timeout and 30s for page timeout.Added a globaldebug_logging_functionto selenium.config moduleAdded a refresh() operation on a Webpage (a.k.a. a page refresh). This of course is simply a driver.refresh() operation on an opened page.Added a get_current_url() operation on a WebpageAdded get_number(), get_numbers(), get_int(), and get_float() to an Element. This is so that you can quickly and easily get numbers from element(s) text that represent numbersAdded an “access element” abstraction layer so that you can retrieve any element defined any levels deep (e.g. A button defined within a Panel that is under an IFrame). The idea is simple: If I want to click a button 2-levels-deep, this can be done either by (1) page.iframe.panel1.login_button.click(), or (2) directly from the top-level page as if it was a local attribute via page.login_button.click()Added take_screenshot() feature to both a Webpage and Element types.Added a take_screenshot_on_test_error annotation for annotating tests. The screenshot capability for a test is controlled byseleniumpm.config.test_screenshot_enabledand is set to True by default.Added pretty-print way of visualizing all attributes and methods for a Webpage. This is useful for documentation as well as for debuggingFixed:Fixing issue with get_attribute() on Element. This method did not have an expected return statement2.9.1 (2017-03-27)New Features:Fixed:Fixing missing implementation to do proper validation of an IFrame that is embedded on a Webpage2.9.0 (2017-03-27)New Features:Implement a get_texts() which returns back all the text (in a List) given a locator. This is available for all Element typesImplement hover_over() capability to ElementFixed:Fixed several critical issues related to get_element_attr(), validate(), and wait_for_page_load() operations on both a Webpage and Widget typesAdd more unittests for IFrameFix wait_for_present_and_visible() timeout for the check for visibility. There are scenarios in which an element may be present, but not immediately visible2.8.0 (2017-03-24)New Features:Adding click() operations to a Widget. This is to support the fact that sometimes an entire section of a page can be “clickable”Adding new IFrame typeFixed:Fixing issue with get_element_attr() method on both a Widget and a Webpage. The problem was that if you marked Widget type as do_not_check, then it should respect both the Widget and all of its embedded elements. The issue was that it would respect that the Widget was marked as do_not_check, but would still enumerate over all of its sub-elements.Fixing another issue with get_element_attr() method on both a Widget and a Webpage. The problem was related to Widget’s that are marked “invisible”. Similar to do_not_check, sub-elements should not be checked if the top-level Widget is already “invisible”.2.7.2 (2017-03-20)New Features:Fixed:Both Webpage and Widget validate() methods should return selfFixing force_check_visibility parameter in Webpage.wait_for_page_load(). The default was set to True instead of False2.7.1 (2017-03-20)New Features:Fixed:Fixed HISTORY.rst and README.rst files that are malformed sometime after 2.5.1 releaseHopefully fixing other issues with 2.7.0 not being installable2.7.0 (2017-03-20)New Features:Adding a new ability to mark an Element type as ‘invisible’ so that validations on a Widget or Webpage can be done simply on presenceAdding a new ability to mark an Element type as ‘do not check’ so that you could potentially define an Element that you simply don’t validate using the default validation() operation defined on a Widget or a Webpage. This feature should be used sparingly as there are better design patterns to handlemostcases that you may think that you need to avoid validating the presence of specific Element types.Fixed:2.6.0 (2017-03-17)New Features:Adding get_tuple() to Locator object. This is to make passing between SeleniumPM and the Selenium libraries eaiserAdding simpler way of defining Locators. Locators can now be created via Locator.by_xpath(path) or Locator.by_css_selector(path). The following types are supported:by_xpath(path)by_css_selector(path)by_name(path)by_class_name(path)by_id(path)by_link_text(path)by_partial_link_text(path)by_tag_name(path)Adding wait_for_selected() to ElementAdding wait_for_clickable() and click_invisible() to ClickableAdding send_keys_delayed() and type_delayed() to TextFieldAdding new Panel type that simply extends Widget. Conceptually they’re exactly the same, but Panel appears to be a more generally acceptable term for a section of a pageFixed:- Simplifying README for more of a project overview. Details should be located on the wiki2.5.2 (2017-03-07)New Features:Fixed:Fixing issue with setup.py throwing error missing HISTORY.rst from package data2.5.1 (2017-03-07) - BROKENNew Features:Fixed:Fixing issue with set_focus() or scroll_into_view(). They were apparently not included in 2.5.0 release2.5.0 (2017-03-07) - BROKENNew Features:Addition of RadioButton typeAddition of Dropdown typeAddition of Image typeAdd new method get_element_attr() to Webpage and Widget type. This will give developers access to all define
Element attributes on a Webpage or within a Widget. This method all supports retrieving a specific Element type
(e.g. Button, Link, Checkbox)Changing default wait_for_page_load() and validate() methods to use the above mentioned get_element_attr(). This can
still be overridden, and does not affect previous implementations.Adding new seleniumpm.examples.widgets packageElement class now implements a get_action_chains() method to return back an ActionChains type.Element class now implements a set_focus() or scroll_into_view() functionality, for those pesky webelements that are
need to be visible, but are corrently scrolled off page somehow.Fixed:Adding type-checking to constructor of the Element, Widget, and Webpage types. These classes will now throw an
AttributeError if not passed in a legitimate RemoteWebdriver, URL, or Locator type as parameters.2.4.2 (2017-02-13)New Features:Fixed:Fixing issue appending two .rst files together to generate the long_descriptionUsing setuptools for setup.py.2.4.1 (2017-02-13)New Features:Fixed:Using disutils.core instead of setuptools for setup.py. Hoping this fixes pretty-print of rst files on PyPi2.4.0 (2017-02-13)New Features:Better support for Table type and interacting with them on a page. This includes support for ‘search’ operations and
enumerating over rows and columnsAdditional methods to Locator object to assist in managing themimplemented get_webelement() and get_webelements() for all Elements. This will return the Selenium WebElement
object(s).Implementation of object equality for all Selenium Page Model classesUnitTests are now using PhantomJS (Headless) targetRemoval of requestest dependency to keep the project simpleFixed:The Widget type was missing in 2.3.0 releaseExpanding of the UnitTest coverage to ensure libraries are working correctlyFixing issue with get_text() in Python Selenium. Apparently, this call in Python (versus Java) is simply called ‘text’Conversion of README and HISTORY files to rst. This is so that they are rendered correctly on PyPi server2.3.0 (2017-02-06)New Features:Provides a full implementation of the current Java v2.3 of Selenium PageModel2.0.0 (2017-01-10)New Features:First release of seleniumpm for the worldContains minimum proof-of-concept for testing search on Google