Skip to content

Commit

Permalink
Merge pull request #16 from dedie/master
Browse files Browse the repository at this point in the history
Changes to pageobjectlibrary
  • Loading branch information
boakley authored Aug 21, 2018
2 parents cc242ed + 2bc7e89 commit 0dbaa01
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 53 deletions.
20 changes: 11 additions & 9 deletions PageObjectLibrary/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from __future__ import absolute_import, unicode_literals

from .keywords import PageObjectLibraryKeywords
from .pageobject import PageObject
from .version import __version__


class PageObjectLibrary(PageObjectLibraryKeywords):

"""This project is hosted on github in the repository
Expand All @@ -11,9 +13,9 @@ class PageObjectLibrary(PageObjectLibraryKeywords):
*PageObjectLibrary* is a lightweight library which supports using
the page object pattern with
[http://robotframework.org/Selenium2Library/doc/Selenium2Library.html|Selenium2Library].
This library does not replace Selenium2Library; rather, it
provides a framework around which to use Selenium2Library and the
[http://robotframework.org/SeleniumLibrary/doc/SeleniumLibrary.html|SeleniumLibrary].
This library does not replace SeleniumLibrary; rather, it
provides a framework around which to use SeleniumLibrary and the
lower-level [http://selenium-python.readthedocs.org/|Python
bindings to Selenium]
Expand All @@ -30,16 +32,16 @@ class your keywords have access to the following pre-defined
attributes and methods:
| =Attribute/method= | =Description= |
| ``self.se2lib`` | A reference to the Selenium2Library instance |
| ``self.se2lib`` | A reference to the SeleniumLibrary instance |
| ``self.browser`` | A reference to the currently open browser |
| ``self.locator`` | A wrapper around the ``_locators`` dictionary |
| ``self.logger`` | A reference to the ``robot.api.logger`` instance |
| ``self._wait_for_page_refresh()`` | a context manager for doing work that causes a page refresh |
= Using Selenium2Library Keywords =
= Using SeleniumLibrary Keywords =
Within your keywords you have access to the full power of
Selenium2Library. You can use ``self.se2lib`` to access the
SeleniumLibrary. You can use ``self.se2lib`` to access the
library keywords. The following example shows how to call the
``Capture Page Screenshot`` keyword:
Expand Down Expand Up @@ -126,7 +128,7 @@ class your keywords have access to the following pre-defined
Robot can import it, just like with any other keyword
library. When you use the keyword `Go to page`, the keyword will
automatically load the keyword library and put it at the front of
the Robot Framework library search order (see
the Robot Framework library search order (see
[http://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Set%20Library%20Search%20Order|Set Library Search Order])
In the following example it is assumed there is a second page
Expand All @@ -135,14 +137,14 @@ class your keywords have access to the following pre-defined
| ``*** Settings ***``
| Library PageObjectLibrary
| Library Selenium2Library
| Library SeleniumLibrary
| Suite Setup Open browser http://www.example.com
| Suite Teardown Close all browsers
|
| ``*** Test Cases ***``
| Log in to the application
| Go to page LoginPage
| Log in as a normal user
| Log in as a normal user
| The current page should be DashboardPage
"""
Expand Down
19 changes: 11 additions & 8 deletions PageObjectLibrary/keywords.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
"""PageObjectLibrary
A library to support the creation of page objects using
selenium and Seleniuim2Library.
selenium and SeleniuimLibrary.
"""

from __future__ import print_function, absolute_import, unicode_literals
import six

import robot.api
from robot.libraries.BuiltIn import BuiltIn

import six

from .pageobject import PageObject
try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse


class PageObjectLibraryKeywords(object):

ROBOT_LIBRARY_SCOPE = "TEST SUITE"
Expand All @@ -30,11 +34,11 @@ def se2lib(self):
# can be imported outside the context of a running
# suite (ie: by libdoc, robotframework-hub, etc)
try:
se2 = self.builtin.get_library_instance("Selenium2Library")
se2 = self.builtin.get_library_instance("SeleniumLibrary")

except RuntimeError:
self.builtin.import_library("Selenium2Library")
se2 = self.builtin.get_library_instance("Selenium2Library")
self.builtin.import_library("SeleniumLibrary")
se2 = self.builtin.get_library_instance("SeleniumLibrary")

return se2

Expand Down Expand Up @@ -69,7 +73,7 @@ def the_current_page_should_be(self, page_name):
# If we get here, we're not on the page we think we're on
raise Exception("Expected page to be %s but it was not" % page_name)

def go_to_page(self, page_name, page_root = None):
def go_to_page(self, page_name, page_root=None):
"""Go to the url for the given page object.
Unless explicitly provided, the URL root will be based on the
Expand All @@ -90,7 +94,7 @@ def go_to_page(self, page_name, page_root = None):
The effect is the same as if you had called the following three
keywords:
| Selenium2Library.Go To http://www.example.com/login
| SeleniumLibrary.Go To http://www.example.com/login
| Import Library ExampleLoginPage
| Set Library Search Order ExampleLoginPage
Expand Down Expand Up @@ -125,4 +129,3 @@ def _get_page_object(self, page_name):
page = self.builtin.get_library_instance(page_name)

return page

2 changes: 2 additions & 0 deletions PageObjectLibrary/locatormap.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import absolute_import, unicode_literals

import six


class LocatorMap(dict):
"""LocatorMap - a dict-like object that supports dot notation
Expand Down
24 changes: 14 additions & 10 deletions PageObjectLibrary/pageobject.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
from __future__ import absolute_import, unicode_literals

from abc import ABCMeta
from contextlib import contextmanager

import robot.api
from robot.libraries.BuiltIn import BuiltIn
from contextlib import contextmanager
from selenium.webdriver.support.ui import WebDriverWait

from selenium.webdriver.support.expected_conditions import staleness_of
from abc import ABCMeta
from selenium.webdriver.support.ui import WebDriverWait

import six

from .locatormap import LocatorMap


class PageObject(six.with_metaclass(ABCMeta, object)):
"""Base class for page objects
Classes that inherit from this class need to define the
following class variables:
PAGE_TITLE the title of the page; used by the default
PAGE_TITLE the title of the page; used by the default
implementation of _is_current_page
PAGE_URL this should be the URL of the page, minus
the hostname and port (eg: /loginpage.html)
Expand All @@ -25,18 +30,18 @@ class PageObject(six.with_metaclass(ABCMeta, object)):
provided by this class. It compares the current page title to the
class variable PAGE_TITLE. A class can override this method if the
page title is not unique or is indeterminate.
Classes that inherit from this class have access to the
following properties:
* se2lib a reference to an instance of Selenium2Library
* se2lib a reference to an instance of SeleniumLibrary
* browser a reference to the current webdriver instance
* logger a reference to robot.api.logger
* locator a wrapper around the page object's ``_locators`` dictionary
* locator a wrapper around the page object's ``_locators`` dictionary
This class implements the following context managers:
* _wait_for_page_refresh
* _wait_for_page_refresh
This context manager is designed to be used in page objects when a
keyword should wait to return until the html element has been
Expand All @@ -56,7 +61,7 @@ def __init__(self):
# test (eg: by libdoc, robotframework-hub, etc)
@property
def se2lib(self):
return BuiltIn().get_library_instance("Selenium2Library")
return BuiltIn().get_library_instance("SeleniumLibrary")

@property
def browser(self):
Expand Down Expand Up @@ -110,4 +115,3 @@ def _is_current_page(self):
self.logger.info(" actual title: '%s'" % actual_title)
raise Exception("expected title to be '%s' but it was '%s'" % (expected_title, actual_title))
return False

2 changes: 1 addition & 1 deletion demo/resources/HomePage.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from PageObjectLibrary import PageObject


class HomePage(PageObject):
"""Keywords for the Home page of the demo app
Expand All @@ -16,4 +17,3 @@ class HomePage(PageObject):
# (eg: self.locator.username, etc)
_locators = {
}

4 changes: 3 additions & 1 deletion demo/resources/LoginPage.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from PageObjectLibrary import PageObject

from robot.libraries.BuiltIn import BuiltIn


class LoginPage(PageObject):
PAGE_TITLE = "Login - PageObjectLibrary Demo"
PAGE_URL = "/login.html"
Expand All @@ -24,7 +26,7 @@ def enter_username(self, username):
"""Enter the given string into the username field"""
self.se2lib.input_text(self.locator.username, username)

def enter_password(self,password):
def enter_password(self, password):
"""Enter the given string into the password field"""
self.se2lib.input_text(self.locator.password, password)

Expand Down
12 changes: 7 additions & 5 deletions demo/resources/config.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import os
import sys


class Config(object):
"""Configuration variables for this test suite
"""Configuration variables for this test suite
This creates a variable named CONFIG (${CONFIG} when included
in a test as a variable file.
in a test as a variable file.
Example:
Expand All @@ -28,11 +29,12 @@ def __init__(self):
self.demo_root = os.path.abspath(os.path.join(_here, ".."))
self.port = 8000
self.root_url = "http://localhost:%s" % self.port
self.username="test user"
self.password="password"
self.username = "test user"
self.password = "password"

def __str__(self):
return "<Config: %s>" % str(self.__dict__)



# This creates a variable that robot can see
CONFIG = Config()
2 changes: 1 addition & 1 deletion demo/tests/demo.robot
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
| Variables | ../resources/config.py
|
| Library | PageObjectLibrary
| Library | Selenium2Library
| Library | SeleniumLibrary
| Library | Process
|
| Suite Setup | Start webapp and open browser
Expand Down
8 changes: 6 additions & 2 deletions demo/webapp/demoserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import SocketServer as socketserver
from urlparse import urlparse


def main():
parser = argparse.ArgumentParser(description="demo web server")
parser.add_argument("-p", "--port", type=int, default=8000, help="port number for the server (default 8000)")
Expand All @@ -27,11 +28,12 @@ def main():
try:
httpd = DemoServer(("", args.port), DemoHandler)
print("serving %s on port %s" % (docroot, 8000))
print ("^C, or visit http://localhost:%s/admin/shutdown to stop" % args.port)
print("^C, or visit http://localhost:%s/admin/shutdown to stop" % args.port)
httpd.serve_forever()
except KeyboardInterrupt:
pass


class DemoHandler(SimpleHTTPRequestHandler):

def redirect(self, uri):
Expand All @@ -50,7 +52,7 @@ def do_POST(self):
def do_GET(self):
url = urlparse(self.path)
print("url: '%s' url.path: '%s'" % (url, url.path))
if url.path == "" or url.path == "/" :
if url.path == "" or url.path == "/":
self.redirect("/login.html")

if url.path == "/authenticate":
Expand Down Expand Up @@ -79,10 +81,12 @@ def get_form_data(self):
})
return form


class DemoServer(socketserver.TCPServer):
def server_bind(self):
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)


if __name__ == "__main__":
main()
34 changes: 18 additions & 16 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
# N.B. to push a new version to PyPi, update the version number
# in rfhub/version.py and then run 'python setup.py sdist upload'
from io import open

from setuptools import setup

execfile('PageObjectLibrary/version.py')
exec(open('PageObjectLibrary/version.py').read())

setup(
name = 'robotframework-pageobjectlibrary',
version = __version__,
author = 'Bryan Oakley',
author_email = 'bryan.oakley@gmail.com',
url = 'https://github.com/boakley/robotframework-pageobjectlibrary/',
keywords = 'robotframework',
license = 'Apache License 2.0',
description = 'RobotFramework library that implements the Page Object pattern',
long_description = open('README.md').read(),
zip_safe = True,
include_package_data = True,
install_requires = ['robotframework', 'robotframework-selenium2library', 'selenium', 'six'],
classifiers = [
name='robotframework-pageobjectlibrary',
version=__version__,
author='Bryan Oakley',
author_email='bryan.oakley@gmail.com',
url='https://github.com/boakley/robotframework-pageobjectlibrary/',
keywords='robotframework',
license='Apache License 2.0',
description='RobotFramework library that implements the Page Object pattern',
long_description=open('README.md', encoding='latin-1').read(),
zip_safe=True,
include_package_data=True,
install_requires=['robotframework', 'robotframework-seleniumlibrary', 'selenium', 'six'],
classifiers=[
"Development Status :: 4 - Beta",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
Expand All @@ -27,8 +29,8 @@
"Topic :: Software Development :: Quality Assurance",
"Intended Audience :: Developers",
],
packages =[
packages=[
'PageObjectLibrary',
],
scripts =[],
scripts=[],
)

0 comments on commit 0dbaa01

Please sign in to comment.