From 91f8ddc0af6441f1b1fe239360a42e661fa81b5d Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Wed, 3 Jan 2018 23:24:31 +0200 Subject: [PATCH 1/6] Initial commit for extending SL --- docs/extending/EXTENDING_SELENIUMLIBRARY.rst | 96 +++++++++++++++++++ .../GetSeleniumLibraryInstance.py | 14 +++ .../examples/get_instance/instance.robot | 10 ++ .../inheritance/InheritSeleniumLibrary.py | 18 ++++ .../examples/inheritance/inheritance.robot | 9 ++ 5 files changed, 147 insertions(+) create mode 100644 docs/extending/EXTENDING_SELENIUMLIBRARY.rst create mode 100644 docs/extending/examples/get_instance/GetSeleniumLibraryInstance.py create mode 100644 docs/extending/examples/get_instance/instance.robot create mode 100644 docs/extending/examples/inheritance/InheritSeleniumLibrary.py create mode 100644 docs/extending/examples/inheritance/inheritance.robot diff --git a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst new file mode 100644 index 000000000..02d1197c4 --- /dev/null +++ b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst @@ -0,0 +1,96 @@ +Extending SeleniumLibrary +========================= + +.. contents:: + +Introduction +------------ +Starting from SeleniumLibrary 3.0, the library has moved to use Robot Framework +`dynamic library API`_. To ease the usage of the dynamic library API, the SeleniumLibrary uses +a `PythonLibCore`_ project to handle the keyword keyword discovery, running the keywords and +other things to related to the dynamic library API. For more details please read the Robot +Framework `dynamic library API`_ documentation. + +Public API methods +------------------ +All the methods, which are exposed as keywords, are available in the library public API. Generally +keywords are converted to lover case and spaces are converted to underscores. Example `Open Browser`_ +is available as ``open_browser``. Please note that method name can be overwritten with the ``@keyword`` +decorator, but in the SeleniumLibrary 3.0.0 release does not contain keywords where the keyword +name would differ from the method name (other than the keywords name case). + +Methods and attributes which are not keywords in the public API methods +----------------------------------------------------------------------- +The SeleniumLibrary instance also contains methods and attributes which are not keywords but are +useful when extending the SeleniumLibrary. The available methods are: + +================ ============================================================= + Method Description +================ ============================================================= +find_element Finds first element matching ``locator``. +find_elements Find all elements matching ``locator``. +register_driver Add's a ``driver`` to the library WebDriverCache. +run_keyword Responsible for executing keywords. +failure_occurred Method that is executed when a SeleniumLibrary keyword fails. +================ ============================================================= + +Also there are the following public attributes available: + +========================= ================================================================ + Attribute Description +========================= ================================================================ +driver Current active driver. +timeout Default value for ``timeouts`` used with ``Wait ...`` keywords. +implicit_wait Default value for ``implicit wait`` used when locating elements. +run_on_failure_keyword Default action for the `run-on-failure functionality`. +screenshot_root_directory Location where possible screenshots are created +========================= ================================================================ + +For more details about the methods, please read the individual method documentation and many +of the attributes are explained in the library `keyword documentation`_. + +Extending SeleniumLibrary by pull requests +------------------------------------------ +Before making your own extension, private or public, please consider would the extension be +generally useful in the SeleniumLibrary. If the extension would be useful for others, then please +create an issue and a pull request. For more details how SeleniumLibrary project handles the +enhancement requests can be read from the `CONTRIBUTING.rst Enhancement requests`_ chapter. + +General prinsibles for extending SeleniumLibrary +------------------------------------------------ +The prinsibles described in the Robot Framework User Guide, `Extending existing test libraries`_ +chapter also apply when extending the SeleniumLibrary. But because the SeleniumLibrary uses the +`PythonLibCore`_ and the `dynamic library API`_, there are some extra steps which needs to be taken +in account when SeleniumLibrary is extended by using with `inheritace`_ or `dynamically`_. + +All methods which should be published as keywords must be decorated with ``@keyword`` decorator. +The ``@keyword`` decorator can be imported in following ways:: + + from from SeleniumLibrary.base import keyword + +Creating a new library by using inheritance +------------------------------------------- +Perhaps the easiest way to extend the SeleniumLibrary is to inherit the SeleniumLibrary and add +new keywords methods to a new library. The `inheritance example`_ shows how to declare new keyword +`Get Browser Desired Capabilities` and how to overwrite existing `Open Browser` keyword. + +The + +Creating a new library by getting active library instance +--------------------------------------------------------- +* Creating a new library by getting active library instance from Robot Framework. + +Extending the SeleniumLibrary dynamically +----------------------------------------- +TO BE DEIFNED + + +.. _dynamic library API: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api +.. _PythonLibCore: https://github.com/robotframework/PythonLibCore +.. _Open Browser: http://robotframework.org/SeleniumLibrary/SeleniumLibrary.html#Open%20Browser +.. _keyword documentation: https://github.com/robotframework/SeleniumLibrary#keyword-documentation +.. _CONTRIBUTING.rst Enhancement requests: https://github.com/robotframework/SeleniumLibrary/blob/master/CONTRIBUTING.rst#enhancement-requests +.. _Extending existing test libraries: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extending-existing-test-libraries +.. _inheritace: https://github.com/robotframework/SeleniumLibrary#TO_BE_DEDFINE +.. _dynamically: https://github.com/robotframework/SeleniumLibrary#TO_BE_DEDFINE_2 +.. _inheritance example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/inheritance/InheritSeleniumLibrary.py \ No newline at end of file diff --git a/docs/extending/examples/get_instance/GetSeleniumLibraryInstance.py b/docs/extending/examples/get_instance/GetSeleniumLibraryInstance.py new file mode 100644 index 000000000..c734a12ab --- /dev/null +++ b/docs/extending/examples/get_instance/GetSeleniumLibraryInstance.py @@ -0,0 +1,14 @@ +from robot.api import logger +from robot.libraries.BuiltIn import BuiltIn + + +def open_browser(host): + url = 'http://{}.com/'.format(host) + sl = BuiltIn().get_library_instance('SeleniumLibrary') + sl.open_browser(url, 'chrome') + + +def get_browser_desired_capabilities(): + logger.info('Getting currently open browser desired capabilities') + sl = BuiltIn().get_library_instance('SeleniumLibrary') + return sl.driver.desired_capabilities diff --git a/docs/extending/examples/get_instance/instance.robot b/docs/extending/examples/get_instance/instance.robot new file mode 100644 index 000000000..716d6bbcd --- /dev/null +++ b/docs/extending/examples/get_instance/instance.robot @@ -0,0 +1,10 @@ +*** Settings *** +Library SeleniumLibrary +Library ./GetSeleniumLibraryInstance.py + +*** Test Cases *** +Use InheritSeleniumLibrary Open Browser Keyword + GetSeleniumLibraryInstance.Open Browser google + ${capabilities} = GetSeleniumLibraryInstance.Get Browser Desired Capabilities + Log ${capabilities} + [Teardown] Close Browser \ No newline at end of file diff --git a/docs/extending/examples/inheritance/InheritSeleniumLibrary.py b/docs/extending/examples/inheritance/InheritSeleniumLibrary.py new file mode 100644 index 000000000..20e2ed3df --- /dev/null +++ b/docs/extending/examples/inheritance/InheritSeleniumLibrary.py @@ -0,0 +1,18 @@ +from robot.api import logger +from SeleniumLibrary import SeleniumLibrary +from SeleniumLibrary.base import keyword +from SeleniumLibrary.keywords import BrowserManagementKeywords + + +class InheritSeleniumLibrary(SeleniumLibrary): + + @keyword + def open_browser(self, host): + url = 'http://{}.com/'.format(host) + browser_management = BrowserManagementKeywords(self) + browser_management.open_browser(url, 'chrome') + + @keyword + def get_browser_desired_capabilities(self): + logger.info('Getting currently open browser desired capabilities') + return self.driver.desired_capabilities diff --git a/docs/extending/examples/inheritance/inheritance.robot b/docs/extending/examples/inheritance/inheritance.robot new file mode 100644 index 000000000..83a6522dd --- /dev/null +++ b/docs/extending/examples/inheritance/inheritance.robot @@ -0,0 +1,9 @@ +*** Settings *** +Library ./InheritSeleniumLibrary.py + +*** Test Cases *** +Use InheritSeleniumLibrary Open Browser Keyword + Open Browser google + ${capabilities} = Get Browser Desired Capabilities + Log ${capabilities} + [Teardown] Close Browser \ No newline at end of file From ef1cef4653ef644601e4ad2eab97756b22119d3b Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Mon, 8 Jan 2018 23:37:30 +0200 Subject: [PATCH 2/6] Added example about decomposition The decomposition example shows usage of the ctx object and LibraryComponent class. --- docs/extending/EXTENDING_SELENIUMLIBRARY.rst | 50 +++++++++++++++---- .../examples/decomposition/Decomposition.py | 38 ++++++++++++++ .../decomposition/decomposition.robot | 9 ++++ .../inheritance/InheritSeleniumLibrary.py | 8 +++ 4 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 docs/extending/examples/decomposition/Decomposition.py create mode 100644 docs/extending/examples/decomposition/decomposition.robot diff --git a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst index 02d1197c4..433f7166e 100644 --- a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst +++ b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst @@ -59,22 +59,52 @@ enhancement requests can be read from the `CONTRIBUTING.rst Enhancement requests General prinsibles for extending SeleniumLibrary ------------------------------------------------ The prinsibles described in the Robot Framework User Guide, `Extending existing test libraries`_ -chapter also apply when extending the SeleniumLibrary. But because the SeleniumLibrary uses the -`PythonLibCore`_ and the `dynamic library API`_, there are some extra steps which needs to be taken -in account when SeleniumLibrary is extended by using with `inheritace`_ or `dynamically`_. +chapter also apply when extending the SeleniumLibrary. There are two different ways to +extend the SeleniumLibrary. +1) Create a library which also the existing SeleniumLibrary keywords, example by using `inheritace`_. +2) Create library which contains only new keywords. -All methods which should be published as keywords must be decorated with ``@keyword`` decorator. -The ``@keyword`` decorator can be imported in following ways:: +When creating a library, which also includes the existing SeleniumLibrary keywords, there are +extra steps which needs to be taken account because SeleniunLibrary uses `PythonLibCore`_ +and the `dynamic library API`_. All methods which should be published as keywords must be +decorated with ``@keyword`` decorator. The ``@keyword`` decorator can be imported in following way:: from from SeleniumLibrary.base import keyword +Keywords should be inside of a ``class`` and the ``add_library_components`` method +must be called to add keywords. The ``add_library_components`` method is inherited from the +`PythonLibCore`_ project and the project provides easy way to write libraries with +dynamic or hybrid library API. + Creating a new library by using inheritance ------------------------------------------- Perhaps the easiest way to extend the SeleniumLibrary is to inherit the SeleniumLibrary and add -new keywords methods to a new library. The `inheritance example`_ shows how to declare new keyword -`Get Browser Desired Capabilities` and how to overwrite existing `Open Browser` keyword. +new or replace existing keywords methods to a new library. The `inheritance example`_ shows how +to declare new keyword ``Get Browser Desired Capabilities`` and how to overwrite existing +``Open Browser`` keyword. + +Because the ``InheritSeleniumLibrary`` class foes not overwrite the SeleniumLibrary init method, the +``add_library_components`` is called automatically. Then the ``InheritSeleniumLibrary`` class methods +which are decorated with ``@keyword`` decorator are added to the ``InheritSeleniumLibrary`` +library keywords. Also existing keywords from SeleniumLibrary are added as library keywords. + +Creating a new library from multiple classes +-------------------------------------------- +Decomposition is a good way to split library to smaller name spaces and it usually eases the +library testing. The `decomposition example`_ shows how the ``Get Browser Desired Capabilities`` +and ``Open Browser`` keywords can divided to own classes. + +The example also shows the usage of the ``context`` object and the `LibraryComponent`_ class. +The ``context`` object is a instance of the SeleniunLibrary which provides access the the +SeleniumLibrary methods, example to the Selenium WebDriver instance. Without the ``context`` object, +the ``BrowserKeywords`` and ``DesiredCapabilitiesKeywords`` classes would not have access to the +SeleniunLibrary methods and objects. + +The ``LibraryComponent`` wrapper class, which provides easier shortcuts the ``context`` object methods +and example provides general logging methods. Example the Selenium WebDriver instance in the context in: +``self.ctx.driver``, but the ``LibraryComponent`` provides a shortcut and it can be accessed with +``self.driver`` -The Creating a new library by getting active library instance --------------------------------------------------------- @@ -93,4 +123,6 @@ TO BE DEIFNED .. _Extending existing test libraries: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extending-existing-test-libraries .. _inheritace: https://github.com/robotframework/SeleniumLibrary#TO_BE_DEDFINE .. _dynamically: https://github.com/robotframework/SeleniumLibrary#TO_BE_DEDFINE_2 -.. _inheritance example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/inheritance/InheritSeleniumLibrary.py \ No newline at end of file +.. _inheritance example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/inheritance/InheritSeleniumLibrary.py +.. _decomposition example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/decomposition/Decomposition.py +.. _LibraryComponent: https://github.com/robotframework/SeleniumLibrary/blob/master/src/SeleniumLibrary/base/librarycomponent.py \ No newline at end of file diff --git a/docs/extending/examples/decomposition/Decomposition.py b/docs/extending/examples/decomposition/Decomposition.py new file mode 100644 index 000000000..6be35969a --- /dev/null +++ b/docs/extending/examples/decomposition/Decomposition.py @@ -0,0 +1,38 @@ +from SeleniumLibrary import SeleniumLibrary +from SeleniumLibrary.base import keyword, LibraryComponent +from SeleniumLibrary.keywords import BrowserManagementKeywords + + +class BrowserKeywords(LibraryComponent): + + def __init__(self, ctx): + LibraryComponent.__init__(self, ctx) + + @keyword + def open_browser(self, host): + url = 'http://{}.com/'.format(host) + browser_management = BrowserManagementKeywords(self.ctx) + browser_management.open_browser(url, 'chrome') + + +class DesiredCapabilitiesKeywords(LibraryComponent): + + def __init__(self, ctx): + LibraryComponent.__init__(self, ctx) + + @keyword + def get_browser_desired_capabilities(self): + self.info('Getting currently open browser desired capabilities') + return self.driver.desired_capabilities + + +class Decomposition(SeleniumLibrary): + + def __init__(self, timeout=5.0, implicit_wait=0.0, + run_on_failure='Capture Page Screenshot', + screenshot_root_directory=None): + SeleniumLibrary.__init__(self, timeout=timeout, implicit_wait=implicit_wait, + run_on_failure=run_on_failure, + screenshot_root_directory=screenshot_root_directory) + self.add_library_components([BrowserKeywords(self), + DesiredCapabilitiesKeywords(self)]) diff --git a/docs/extending/examples/decomposition/decomposition.robot b/docs/extending/examples/decomposition/decomposition.robot new file mode 100644 index 000000000..e62c78e46 --- /dev/null +++ b/docs/extending/examples/decomposition/decomposition.robot @@ -0,0 +1,9 @@ +*** Settings *** +Library ./Decomposition.py + +*** Test Cases *** +Decomposition Example + Open Browser google + ${capabilities} = Get Browser Desired Capabilities + Log ${capabilities} + [Teardown] Close Browser diff --git a/docs/extending/examples/inheritance/InheritSeleniumLibrary.py b/docs/extending/examples/inheritance/InheritSeleniumLibrary.py index 20e2ed3df..634b4ce79 100644 --- a/docs/extending/examples/inheritance/InheritSeleniumLibrary.py +++ b/docs/extending/examples/inheritance/InheritSeleniumLibrary.py @@ -16,3 +16,11 @@ def open_browser(self, host): def get_browser_desired_capabilities(self): logger.info('Getting currently open browser desired capabilities') return self.driver.desired_capabilities + + def not_keywords_but_public_methods(self): + logger.info('Python public method not a keyword, because it is not ' + 'decorated with @keyword decorator') + + def _private_method_are_not_keywords(self): + logger.info('Python private method is not a keyword, because it is not ' + 'decorated with @keyword decorator') From d05f066b3217820325a2c63ccb8b6d9b406e8e63 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Tue, 9 Jan 2018 21:15:47 +0200 Subject: [PATCH 3/6] Fixing inheritance example documentation --- docs/extending/EXTENDING_SELENIUMLIBRARY.rst | 26 ++++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst index 433f7166e..c10941f6a 100644 --- a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst +++ b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst @@ -19,8 +19,8 @@ is available as ``open_browser``. Please note that method name can be overwritte decorator, but in the SeleniumLibrary 3.0.0 release does not contain keywords where the keyword name would differ from the method name (other than the keywords name case). -Methods and attributes which are not keywords in the public API methods ------------------------------------------------------------------------ +Methods or attributes which are not keywords but are available in the public API +-------------------------------------------------------------------------------- The SeleniumLibrary instance also contains methods and attributes which are not keywords but are useful when extending the SeleniumLibrary. The available methods are: @@ -65,11 +65,11 @@ extend the SeleniumLibrary. 2) Create library which contains only new keywords. When creating a library, which also includes the existing SeleniumLibrary keywords, there are -extra steps which needs to be taken account because SeleniunLibrary uses `PythonLibCore`_ +extra steps which needs to be taken account, because SeleniunLibrary uses `PythonLibCore`_ and the `dynamic library API`_. All methods which should be published as keywords must be decorated with ``@keyword`` decorator. The ``@keyword`` decorator can be imported in following way:: - from from SeleniumLibrary.base import keyword + from SeleniumLibrary.base import keyword Keywords should be inside of a ``class`` and the ``add_library_components`` method must be called to add keywords. The ``add_library_components`` method is inherited from the @@ -79,15 +79,25 @@ dynamic or hybrid library API. Creating a new library by using inheritance ------------------------------------------- Perhaps the easiest way to extend the SeleniumLibrary is to inherit the SeleniumLibrary and add -new or replace existing keywords methods to a new library. The `inheritance example`_ shows how -to declare new keyword ``Get Browser Desired Capabilities`` and how to overwrite existing -``Open Browser`` keyword. +new keywords methods to a new library. The `inheritance example`_ shows how to declare new +keyword ``Get Browser Desired Capabilities`` and how to overwrite existing ``Open Browser`` keyword. Because the ``InheritSeleniumLibrary`` class foes not overwrite the SeleniumLibrary init method, the ``add_library_components`` is called automatically. Then the ``InheritSeleniumLibrary`` class methods which are decorated with ``@keyword`` decorator are added to the ``InheritSeleniumLibrary`` library keywords. Also existing keywords from SeleniumLibrary are added as library keywords. +Because the methods are not anymore directly available in the SeleniumLibrary class, it not +anymore possible to call the original method like this:: + + super(ClassName, self).open_browser(url, browser, alias, remote_url, + desired_capabilities, ff_profile_dir) + +Instead user must call the method from the class which implements the keyword, example:: + + browser_management = BrowserManagementKeywords(self) + browser_management.open_browser(url, 'chrome') + Creating a new library from multiple classes -------------------------------------------- Decomposition is a good way to split library to smaller name spaces and it usually eases the @@ -98,7 +108,7 @@ The example also shows the usage of the ``context`` object and the `LibraryCompo The ``context`` object is a instance of the SeleniunLibrary which provides access the the SeleniumLibrary methods, example to the Selenium WebDriver instance. Without the ``context`` object, the ``BrowserKeywords`` and ``DesiredCapabilitiesKeywords`` classes would not have access to the -SeleniunLibrary methods and objects. +SeleniunLibrary common methods and objects. The ``LibraryComponent`` wrapper class, which provides easier shortcuts the ``context`` object methods and example provides general logging methods. Example the Selenium WebDriver instance in the context in: From b6df81bb26743adf039a3bb408c400769cbf65f7 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Tue, 9 Jan 2018 22:25:53 +0200 Subject: [PATCH 4/6] Adds example how the extend using the active instance --- docs/extending/EXTENDING_SELENIUMLIBRARY.rst | 43 ++++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst index c10941f6a..3555fe55b 100644 --- a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst +++ b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst @@ -15,9 +15,9 @@ Public API methods ------------------ All the methods, which are exposed as keywords, are available in the library public API. Generally keywords are converted to lover case and spaces are converted to underscores. Example `Open Browser`_ -is available as ``open_browser``. Please note that method name can be overwritten with the ``@keyword`` -decorator, but in the SeleniumLibrary 3.0.0 release does not contain keywords where the keyword -name would differ from the method name (other than the keywords name case). +keyword is available as ``open_browser`` method. Please note that method name can be overwritten +with the ``@keyword`` decorator, but in the SeleniumLibrary 3.0.0 release does not contain keywords +where the keyword name would differ from the method name (other than the keywords name case). Methods or attributes which are not keywords but are available in the public API -------------------------------------------------------------------------------- @@ -53,15 +53,16 @@ Extending SeleniumLibrary by pull requests ------------------------------------------ Before making your own extension, private or public, please consider would the extension be generally useful in the SeleniumLibrary. If the extension would be useful for others, then please -create an issue and a pull request. For more details how SeleniumLibrary project handles the -enhancement requests can be read from the `CONTRIBUTING.rst Enhancement requests`_ chapter. +create an issue and a pull request. More details how SeleniumLibrary project handles the +enhancement requests can be read from the CONTRIBUTING.rst `Enhancement requests`_ chapter. General prinsibles for extending SeleniumLibrary ------------------------------------------------ The prinsibles described in the Robot Framework User Guide, `Extending existing test libraries`_ chapter also apply when extending the SeleniumLibrary. There are two different ways to extend the SeleniumLibrary. -1) Create a library which also the existing SeleniumLibrary keywords, example by using `inheritace`_. + +1) Create a library which also the contains existing SeleniumLibrary keywords, example by using `inheritace`_. 2) Create library which contains only new keywords. When creating a library, which also includes the existing SeleniumLibrary keywords, there are @@ -93,7 +94,7 @@ anymore possible to call the original method like this:: super(ClassName, self).open_browser(url, browser, alias, remote_url, desired_capabilities, ff_profile_dir) -Instead user must call the method from the class which implements the keyword, example:: +Instead user must call the method from the class instance which implements the keyword, example:: browser_management = BrowserManagementKeywords(self) browser_management.open_browser(url, 'chrome') @@ -106,19 +107,24 @@ and ``Open Browser`` keywords can divided to own classes. The example also shows the usage of the ``context`` object and the `LibraryComponent`_ class. The ``context`` object is a instance of the SeleniunLibrary which provides access the the -SeleniumLibrary methods, example to the Selenium WebDriver instance. Without the ``context`` object, -the ``BrowserKeywords`` and ``DesiredCapabilitiesKeywords`` classes would not have access to the -SeleniunLibrary common methods and objects. +SeleniumLibrary methods from the ``BrowserKeywords`` and ``DesiredCapabilitiesKeywords`` classes. +Example ``context`` object provides access to the Selenium WebDriver instance. -The ``LibraryComponent`` wrapper class, which provides easier shortcuts the ``context`` object methods -and example provides general logging methods. Example the Selenium WebDriver instance in the context in: -``self.ctx.driver``, but the ``LibraryComponent`` provides a shortcut and it can be accessed with -``self.driver`` +The ``LibraryComponent`` is a wrapper class, which provides easier shortcuts the ``context`` object +methods and example provides general logging methods. Example the Selenium WebDriver instance in +the context: ``self.ctx.driver``, but the ``LibraryComponent`` provides a shortcut and it can be +accessed with: ``self.driver`` Creating a new library by getting active library instance --------------------------------------------------------- -* Creating a new library by getting active library instance from Robot Framework. +Getting the active library instance provides way to create a new library that it does not +automatically contain keywords from the SeleniumLibrary. This eases the name space +handling and if only new keywords are created, user does not have to prefix the keywords with the +library name. This way also allows user to freely choose the Robot Framework `library API`_. +The `instance example`_ shows a way how the active SeleniumLibrary is get from the Robot Framework. +The example shows how to declare ``Get Browser Desired Capabilities`` and ``Open Browser`` keywords +to the new library and the example uses the `static keyword API`_. Extending the SeleniumLibrary dynamically ----------------------------------------- @@ -129,10 +135,13 @@ TO BE DEIFNED .. _PythonLibCore: https://github.com/robotframework/PythonLibCore .. _Open Browser: http://robotframework.org/SeleniumLibrary/SeleniumLibrary.html#Open%20Browser .. _keyword documentation: https://github.com/robotframework/SeleniumLibrary#keyword-documentation -.. _CONTRIBUTING.rst Enhancement requests: https://github.com/robotframework/SeleniumLibrary/blob/master/CONTRIBUTING.rst#enhancement-requests +.. _Enhancement requests: https://github.com/robotframework/SeleniumLibrary/blob/master/CONTRIBUTING.rst#enhancement-requests .. _Extending existing test libraries: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extending-existing-test-libraries .. _inheritace: https://github.com/robotframework/SeleniumLibrary#TO_BE_DEDFINE .. _dynamically: https://github.com/robotframework/SeleniumLibrary#TO_BE_DEDFINE_2 .. _inheritance example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/inheritance/InheritSeleniumLibrary.py .. _decomposition example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/decomposition/Decomposition.py -.. _LibraryComponent: https://github.com/robotframework/SeleniumLibrary/blob/master/src/SeleniumLibrary/base/librarycomponent.py \ No newline at end of file +.. _instance example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/get_instance/GetSeleniumLibraryInstance.py +.. _LibraryComponent: https://github.com/robotframework/SeleniumLibrary/blob/master/src/SeleniumLibrary/base/librarycomponent.py +.. _library API: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-test-library-apis +.. _static keyword API: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-static-keywords From 61cd603166019230a6c3ad98747969bf45504479 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Thu, 11 Jan 2018 23:11:28 +0200 Subject: [PATCH 5/6] Add example about extending SeleniumLibrary directly. --- docs/extending/EXTENDING_SELENIUMLIBRARY.rst | 30 ++++++++++----- .../modify_seleniumlibrary/NewKeywords.py | 37 +++++++++++++++++++ .../modify_seleniumlibrary/modify_sl.robot | 10 +++++ 3 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 docs/extending/examples/modify_seleniumlibrary/NewKeywords.py create mode 100644 docs/extending/examples/modify_seleniumlibrary/modify_sl.robot diff --git a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst index 3555fe55b..efe5172b7 100644 --- a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst +++ b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst @@ -74,8 +74,8 @@ decorated with ``@keyword`` decorator. The ``@keyword`` decorator can be importe Keywords should be inside of a ``class`` and the ``add_library_components`` method must be called to add keywords. The ``add_library_components`` method is inherited from the -`PythonLibCore`_ project and the project provides easy way to write libraries with -dynamic or hybrid library API. +`PythonLibCore`_ project and the method must contains list of classes which contains the +new keywords. Creating a new library by using inheritance ------------------------------------------- @@ -83,13 +83,13 @@ Perhaps the easiest way to extend the SeleniumLibrary is to inherit the Selenium new keywords methods to a new library. The `inheritance example`_ shows how to declare new keyword ``Get Browser Desired Capabilities`` and how to overwrite existing ``Open Browser`` keyword. -Because the ``InheritSeleniumLibrary`` class foes not overwrite the SeleniumLibrary init method, the -``add_library_components`` is called automatically. Then the ``InheritSeleniumLibrary`` class methods +Because the ``InheritSeleniumLibrary`` class foes not overwrite the SeleniumLibrary ``init`` method, +the ``add_library_components`` is called automatically. Then the ``InheritSeleniumLibrary`` class methods which are decorated with ``@keyword`` decorator are added to the ``InheritSeleniumLibrary`` library keywords. Also existing keywords from SeleniumLibrary are added as library keywords. Because the methods are not anymore directly available in the SeleniumLibrary class, it not -anymore possible to call the original method like this:: +anymore possible to call the original method example like this:: super(ClassName, self).open_browser(url, browser, alias, remote_url, desired_capabilities, ff_profile_dir) @@ -124,24 +124,34 @@ handling and if only new keywords are created, user does not have to prefix the library name. This way also allows user to freely choose the Robot Framework `library API`_. The `instance example`_ shows a way how the active SeleniumLibrary is get from the Robot Framework. The example shows how to declare ``Get Browser Desired Capabilities`` and ``Open Browser`` keywords -to the new library and the example uses the `static keyword API`_. +to the new library and the `instance example`_ uses the `static keyword API`_ to declare new +keywords. Extending the SeleniumLibrary dynamically ----------------------------------------- -TO BE DEIFNED +It is possible to modify keywords directly in the SeleniumLibrary. This can be done calling +``add_library_components`` method from the SeleniumLibrary instance and then using the +``BuiltIn().reload_library()`` method to reload the SeleniumLibrary. +The `modify SeleniumLibrary`_ example uses the Robot Framework `Listener API`_ to extend the +SeleniumLibrary with a keywords in the ``KeywordClass``. The ``NewKeywords``class is library +which is also a listener and it uses the ``start_suite`` method to trigger the modifications +to the SeleniumLibrary. The example gets the active library instance from the Robot Framework +and uses the ``add_library_components`` method to add the ``KeywordClass`` keywords in to +the SeleniumLibrary directly. .. _dynamic library API: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api .. _PythonLibCore: https://github.com/robotframework/PythonLibCore .. _Open Browser: http://robotframework.org/SeleniumLibrary/SeleniumLibrary.html#Open%20Browser -.. _keyword documentation: https://github.com/robotframework/SeleniumLibrary#keyword-documentation +.. _keyword documentation: http://robotframework.org/SeleniumLibrary/SeleniumLibrary.html .. _Enhancement requests: https://github.com/robotframework/SeleniumLibrary/blob/master/CONTRIBUTING.rst#enhancement-requests .. _Extending existing test libraries: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extending-existing-test-libraries -.. _inheritace: https://github.com/robotframework/SeleniumLibrary#TO_BE_DEDFINE -.. _dynamically: https://github.com/robotframework/SeleniumLibrary#TO_BE_DEDFINE_2 +.. _inheritace: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/inheritance/InheritSeleniumLibrary.py .. _inheritance example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/inheritance/InheritSeleniumLibrary.py .. _decomposition example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/decomposition/Decomposition.py .. _instance example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/get_instance/GetSeleniumLibraryInstance.py .. _LibraryComponent: https://github.com/robotframework/SeleniumLibrary/blob/master/src/SeleniumLibrary/base/librarycomponent.py .. _library API: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-test-library-apis .. _static keyword API: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-static-keywords +.. _modify SeleniumLibrary: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/modify_seleniumlibrary/NewKeywords.py +.. _Listener API: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface diff --git a/docs/extending/examples/modify_seleniumlibrary/NewKeywords.py b/docs/extending/examples/modify_seleniumlibrary/NewKeywords.py new file mode 100644 index 000000000..78965834f --- /dev/null +++ b/docs/extending/examples/modify_seleniumlibrary/NewKeywords.py @@ -0,0 +1,37 @@ +from robot.api import logger +from robot.libraries.BuiltIn import BuiltIn +from SeleniumLibrary.base import keyword +from SeleniumLibrary.base import LibraryComponent +from SeleniumLibrary.keywords import BrowserManagementKeywords + + +class KeywordClass(LibraryComponent): + + def __init__(self, ctx): + LibraryComponent.__init__(self, ctx) + + @keyword + def open_browser(self, host): + logger.info('This is keyword from KeywordClass') + url = 'http://{}.com/'.format(host) + browser_management = BrowserManagementKeywords(self.ctx) + browser_management.open_browser(url, 'chrome') + + @keyword + def get_browser_desired_capabilities(self): + logger.info('Getting currently open browser desired capabilities') + return self.driver.desired_capabilities + + +class NewKeywords(object): + + ROBOT_LISTENER_API_VERSION = 2 + + def __init__(self): + self.ROBOT_LIBRARY_LISTENER = self + + def start_suite(self, name, attributes): + sl = BuiltIn().get_library_instance('SeleniumLibrary') + sl.add_library_components([KeywordClass(sl)]) + BuiltIn().reload_library('SeleniumLibrary') + self.added = True diff --git a/docs/extending/examples/modify_seleniumlibrary/modify_sl.robot b/docs/extending/examples/modify_seleniumlibrary/modify_sl.robot new file mode 100644 index 000000000..7916ec47a --- /dev/null +++ b/docs/extending/examples/modify_seleniumlibrary/modify_sl.robot @@ -0,0 +1,10 @@ +*** Settings *** +Library SeleniumLibrary +Library ./NewKeywords.py + +*** Test Cases *** +Use New Keywords From SeleniumLibrary + SeleniumLibrary.Open Browser google + ${capabilities} = SeleniumLibrary.Get Browser Desired Capabilities + Log ${capabilities} + [Teardown] Close Browser From 115b5f35989d7deb89c9e142002e88d41a3a2fb4 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Tue, 16 Jan 2018 22:13:23 +0200 Subject: [PATCH 6/6] Fine tuning documentation --- docs/extending/EXTENDING_SELENIUMLIBRARY.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst index efe5172b7..f47b55ce9 100644 --- a/docs/extending/EXTENDING_SELENIUMLIBRARY.rst +++ b/docs/extending/EXTENDING_SELENIUMLIBRARY.rst @@ -62,7 +62,7 @@ The prinsibles described in the Robot Framework User Guide, `Extending existing chapter also apply when extending the SeleniumLibrary. There are two different ways to extend the SeleniumLibrary. -1) Create a library which also the contains existing SeleniumLibrary keywords, example by using `inheritace`_. +1) Create a library which also the contains existing SeleniumLibrary keywords, example by using `inheritance`_. 2) Create library which contains only new keywords. When creating a library, which also includes the existing SeleniumLibrary keywords, there are @@ -106,8 +106,8 @@ library testing. The `decomposition example`_ shows how the ``Get Browser Desire and ``Open Browser`` keywords can divided to own classes. The example also shows the usage of the ``context`` object and the `LibraryComponent`_ class. -The ``context`` object is a instance of the SeleniunLibrary which provides access the the -SeleniumLibrary methods from the ``BrowserKeywords`` and ``DesiredCapabilitiesKeywords`` classes. +The ``context`` object is a instance of the SeleniunLibrary which provides access to the +SeleniumLibrary methods for the ``BrowserKeywords`` and ``DesiredCapabilitiesKeywords`` classes. Example ``context`` object provides access to the Selenium WebDriver instance. The ``LibraryComponent`` is a wrapper class, which provides easier shortcuts the ``context`` object @@ -146,7 +146,7 @@ the SeleniumLibrary directly. .. _keyword documentation: http://robotframework.org/SeleniumLibrary/SeleniumLibrary.html .. _Enhancement requests: https://github.com/robotframework/SeleniumLibrary/blob/master/CONTRIBUTING.rst#enhancement-requests .. _Extending existing test libraries: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extending-existing-test-libraries -.. _inheritace: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/inheritance/InheritSeleniumLibrary.py +.. _inheritance: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/inheritance/InheritSeleniumLibrary.py .. _inheritance example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/inheritance/InheritSeleniumLibrary.py .. _decomposition example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/decomposition/Decomposition.py .. _instance example: https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/examples/get_instance/GetSeleniumLibraryInstance.py