Repository: robotframework/SeleniumLibrary
Pull request #884 (2017-09-02 22:04:26)

Cleanup
1. Little import cleanup
2. Fix registering keyword to run on failure (#176)
3. Make public attributes actually public (#882)

This PR contains somewhat unrelated fixes, but commits ought to mainly contain only a single fix.


Patch:
diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py
index 9f5e0a90..07e658c1 100644
--- a/src/SeleniumLibrary/__init__.py
+++ b/src/SeleniumLibrary/__init__.py
@@ -16,21 +16,24 @@
 
 import warnings
 
-from .base import DynamicCore
-from .keywords import AlertKeywords
-from .keywords import BrowserManagementKeywords
-from .keywords import CookieKeywords
-from .keywords import ElementKeywords
-from .keywords import FormElementKeywords
-from .keywords import JavaScriptKeywords
-from .keywords import RunOnFailureKeywords
-from .keywords import ScreenshotKeywords
-from .keywords import SelectElementKeywords
-from .keywords import TableElementKeywords
-from .keywords import WaitingKeywords
-from .locators import ElementFinder
-from .utils import BrowserCache
-from .utils import LibraryListener
+from robot.api import logger
+from robot.libraries.BuiltIn import BuiltIn
+
+from SeleniumLibrary.base import DynamicCore
+from SeleniumLibrary.keywords import (AlertKeywords,
+                                      BrowserManagementKeywords,
+                                      CookieKeywords,
+                                      ElementKeywords,
+                                      FormElementKeywords,
+                                      JavaScriptKeywords,
+                                      RunOnFailureKeywords,
+                                      ScreenshotKeywords,
+                                      SelectElementKeywords,
+                                      TableElementKeywords,
+                                      WaitingKeywords)
+from SeleniumLibrary.locators import ElementFinder
+from SeleniumLibrary.utils import (BrowserCache, Deprecated, LibraryListener,
+                                   timestr_to_secs)
 
 
 __version__ = '3.0.0b1'
@@ -194,7 +197,6 @@ class SeleniumLibrary(DynamicCore):
     Note that prior to SeleniumLibrary 3.0, all non-empty strings, including
     ``false``, ``no`` and ``none``, were considered true.
     """
-
     ROBOT_LIBRARY_SCOPE = 'GLOBAL'
     ROBOT_LIBRARY_VERSION = __version__
 
@@ -234,11 +236,13 @@ class SeleniumLibrary(DynamicCore):
         | Library `|` SeleniumLibrary `|` implicit_wait=5 `|` run_on_failure=Log Source | # Sets default implicit_wait to 5 seconds and runs `Log Source` on failure |
         | Library `|` SeleniumLibrary `|` timeout=10      `|` run_on_failure=Nothing    | # Sets default timeout to 10 seconds and does nothing on failure           |
         """
-        self._run_on_failure_keyword = None
-        self._running_on_failure_routine = False
-        self._speed_in_secs = 0.0
-        self._timeout_in_secs = 5.0
-        self._implicit_wait_in_secs = 5.0
+        self.timeout = timestr_to_secs(timeout)
+        self.implicit_wait = timestr_to_secs(implicit_wait)
+        self.speed = 0.0
+        self.run_on_failure_keyword \
+            = RunOnFailureKeywords.resolve_keyword(run_on_failure)
+        self._running_on_failure_keyword = False
+        self.screenshot_root_directory = screenshot_root_directory
         libraries = [
             AlertKeywords(self),
             BrowserManagementKeywords(self),
@@ -254,35 +258,46 @@ class SeleniumLibrary(DynamicCore):
         ]
         self._browsers = BrowserCache()
         DynamicCore.__init__(self, libraries)
-        self.screenshot_root_directory = screenshot_root_directory
-        self.set_selenium_timeout(timeout)
-        self.set_selenium_implicit_wait(implicit_wait)
-        self.register_keyword_to_run_on_failure(run_on_failure)
         self.ROBOT_LIBRARY_LISTENER = LibraryListener()
         self.element_finder = ElementFinder(self)
 
+    _speed_in_secs = Deprecated('_speed_in_secs', 'speed')
+    _timeout_in_secs = Deprecated('_timeout_in_secs', 'timeout')
+    _implicit_wait_in_secs = Deprecated('_implicit_wait_in_secs',
+                                        'implicit_wait')
+    _run_on_failure_keyword = Deprecated('_run_on_failure_keyword',
+                                         'run_on_failure_keyword')
+
     def run_keyword(self, name, args, kwargs):
         try:
             return DynamicCore.run_keyword(self, name, args, kwargs)
         except Exception:
-            self.run_on_failure()
+            self.failure_occurred()
             raise
 
     def register_browser(self, browser, alias):
         return self._browsers.register(browser, alias)
 
-    def run_on_failure(self):
-        """Executes the registered run on failure keyword.
+    def failure_occurred(self):
+        """Method that is executed when a SeleniumLibrary keyword fails.
 
-        This is designed as an API when writing library which extends the
-        SeleniumLibrary with new functionality. If that new functionality
-        does not (always) relay on SeleniumLibrary keyword methods, then the
-        new functionality can use this method to execute the run on failure
-        functionality in SeleniumLibrary"""
-        RunOnFailureKeywords(self).run_on_failure()
+        By default executes the registered run-on-failure keyword.
+        Libraries extending SeleniumLibrary can overwrite this hook
+        method if they want to provide custom functionality instead.
+        """
+        if self._running_on_failure_keyword or not self.run_on_failure_keyword:
+            return
+        try:
+            self._running_on_failure_keyword = True
+            BuiltIn().run_keyword(self.run_on_failure_keyword)
+        except Exception as err:
+            logger.warn("Keyword '%s' could not be run on failure: %s"
+                        % (self.run_on_failure_keyword, err))
+        finally:
+            self._running_on_failure_keyword = False
 
     @property
-    def _browser(self):
+    def browser(self):
         """Current active browser"""
         if not self._browsers.current:
             raise RuntimeError('No browser is open')
@@ -296,12 +311,12 @@ class SeleniumLibrary(DynamicCore):
 
     def _current_browser(self):
         warnings.warn('"SeleniumLibrary._current_browser" is deprecated, '
-                      'use "SeleniumLibrary._browser" instead.',
+                      'use "SeleniumLibrary.browser" instead.',
                       DeprecationWarning)
-        return self._browser
+        return self.browser
 
     def _run_on_failure(self):
         warnings.warn('"SeleniumLibrary._run_on_failure" is deprecated, '
-                      'use "SeleniumLibrary.run_on_failure" instead.',
+                      'use "SeleniumLibrary.failure_occurred" instead.',
                       DeprecationWarning)
-        self.run_on_failure()
+        self.failure_occurred()
diff --git a/src/SeleniumLibrary/base/context.py b/src/SeleniumLibrary/base/context.py
index b0c3d832..0dc3ebc8 100644
--- a/src/SeleniumLibrary/base/context.py
+++ b/src/SeleniumLibrary/base/context.py
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+
 class ContextAware(object):
 
     def __init__(self, ctx):
@@ -21,7 +22,7 @@ class ContextAware(object):
 
     @property
     def browser(self):
-        return self.ctx._browser
+        return self.ctx.browser
 
     @property
     def browsers(self):
diff --git a/src/SeleniumLibrary/keywords/browsermanagement.py b/src/SeleniumLibrary/keywords/browsermanagement.py
index f21df473..ddf55a0b 100644
--- a/src/SeleniumLibrary/keywords/browsermanagement.py
+++ b/src/SeleniumLibrary/keywords/browsermanagement.py
@@ -19,13 +19,13 @@ import time
 import types
 
 from robot.errors import DataError
-from robot.utils import secs_to_timestr, timestr_to_secs
 from selenium import webdriver
 from selenium.common.exceptions import NoSuchWindowException
 
 from SeleniumLibrary.base import LibraryComponent, keyword
 from SeleniumLibrary.locators.windowmanager import WindowManager
-from SeleniumLibrary.utils import is_truthy, is_falsy
+from SeleniumLibrary.utils import (is_truthy, is_falsy,
+                                   secs_to_timestr, timestr_to_secs)
 
 
 ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
@@ -363,19 +363,18 @@ class BrowserManagementKeywords(LibraryComponent):
             pass
         finally:
             self._window_manager.select(self.browser, locator)
-    
-    @keyword      
+
+    @keyword
     def get_log(self, log_type):
         """Get the log for a given selenium log type
 
         The `log_type` argument defines which logs to get. Possible values are:
         `browser`, `driver`, `client` or `server`
-        
-        New in SeleniumLibrary 3.0
+
+        New in SeleniumLibrary 3.0.0
         """
         return self.browser.get_log(log_type)
 
-
     @keyword
     def list_windows(self):
         """Return all current window handles as a list"""
@@ -480,22 +479,25 @@ class BrowserManagementKeywords(LibraryComponent):
     def get_selenium_speed(self):
         """Gets the delay in seconds that is waited after each Selenium command.
 
-        See `Set Selenium Speed` for an explanation."""
-        return secs_to_timestr(self.ctx._speed_in_secs)
+        See `Set Selenium Speed` for an explanation.
+        """
+        return secs_to_timestr(self.ctx.speed)
 
     @keyword
     def get_selenium_timeout(self):
         """Gets the timeout in seconds that is used by various keywords.
 
-        See `Set Selenium Timeout` for an explanation."""
-        return secs_to_timestr(self.ctx._timeout_in_secs)
+        See `Set Selenium Timeout` for an explanation.
+        """
+        return secs_to_timestr(self.ctx.timeout)
 
     @keyword
     def get_selenium_implicit_wait(self):
         """Gets the wait in seconds that is waited by Selenium.
 
-        See `Set Selenium Implicit Wait` for an explanation."""
-        return secs_to_timestr(self.ctx._implicit_wait_in_secs)
+        See `Set Selenium Implicit Wait` for an explanation.
+        """
+        return secs_to_timestr(self.ctx.implicit_wait)
 
     @keyword
     def set_selenium_speed(self, seconds):
@@ -515,10 +517,10 @@ class BrowserManagementKeywords(LibraryComponent):
         Example:
         | Set Selenium Speed | .5 seconds |
         """
-        old_speed = self.ctx._speed_in_secs
-        self.ctx._speed_in_secs = timestr_to_secs(seconds)
+        old_speed = self.ctx.speed
+        self.ctx.speed = timestr_to_secs(seconds)
         for browser in self.browsers.browsers:
-            browser._speed = self.ctx._speed_in_secs
+            browser._speed = self.ctx.speed
             self._monkey_patch_speed(browser)
         return old_speed
 
@@ -541,9 +543,9 @@ class BrowserManagementKeywords(LibraryComponent):
         | Set Selenium Timeout | ${orig timeout} |
         """
         old_timeout = self.get_selenium_timeout()
-        self.ctx._timeout_in_secs = timestr_to_secs(seconds)
+        self.ctx.timeout = timestr_to_secs(seconds)
         for browser in self.browsers.get_open_browsers():
-            browser.set_script_timeout(self.ctx._timeout_in_secs)
+            browser.set_script_timeout(self.ctx.timeout)
         return old_timeout
 
     @keyword
@@ -561,9 +563,9 @@ class BrowserManagementKeywords(LibraryComponent):
         | Set Selenium Implicit Wait | ${orig wait} |
         """
         old_wait = self.get_selenium_implicit_wait()
-        self.ctx._implicit_wait_in_secs = timestr_to_secs(seconds)
+        self.ctx.implicit_wait = timestr_to_secs(seconds)
         for browser in self.browsers.get_open_browsers():
-            browser.implicitly_wait(self.ctx._implicit_wait_in_secs)
+            browser.implicitly_wait(self.ctx.implicit_wait)
         return old_wait
 
     @keyword
@@ -579,8 +581,7 @@ class BrowserManagementKeywords(LibraryComponent):
 
         See also `Set Selenium Implicit Wait`.
         """
-        implicit_wait_in_secs = timestr_to_secs(seconds)
-        self.browser.implicitly_wait(implicit_wait_in_secs)
+        self.browser.implicitly_wait(timestr_to_secs(seconds))
 
     def _get_browser_creation_function(self, browser_name):
         func_name = BROWSER_NAMES.get(browser_name.lower().replace(' ', ''))
@@ -594,8 +595,8 @@ class BrowserManagementKeywords(LibraryComponent):
             raise ValueError(browser_name + " is not a supported browser.")
 
         browser = creation_func(remote, desired_capabilities, profile_dir)
-        browser.set_script_timeout(self.ctx._timeout_in_secs)
-        browser.implicitly_wait(self.ctx._implicit_wait_in_secs)
+        browser.set_script_timeout(self.ctx.timeout)
+        browser.implicitly_wait(self.ctx.implicit_wait)
 
         return browser
 
diff --git a/src/SeleniumLibrary/keywords/element.py b/src/SeleniumLibrary/keywords/element.py
index 429d417e..aa2b9ffe 100644
--- a/src/SeleniumLibrary/keywords/element.py
+++ b/src/SeleniumLibrary/keywords/element.py
@@ -19,8 +19,7 @@ from selenium.webdriver.common.keys import Keys
 
 from SeleniumLibrary.base import LibraryComponent, keyword
 from SeleniumLibrary.keywords.formelement import FormElementKeywords
-from SeleniumLibrary.utils import escape_xpath_value
-from SeleniumLibrary.utils import is_truthy, is_falsy
+from SeleniumLibrary.utils import escape_xpath_value, is_falsy, is_truthy
 
 
 class ElementKeywords(LibraryComponent):
diff --git a/src/SeleniumLibrary/keywords/runonfailure.py b/src/SeleniumLibrary/keywords/runonfailure.py
index f968255d..cd5a7f1e 100644
--- a/src/SeleniumLibrary/keywords/runonfailure.py
+++ b/src/SeleniumLibrary/keywords/runonfailure.py
@@ -14,9 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from robot.libraries.BuiltIn import BuiltIn
-
 from SeleniumLibrary.base import LibraryComponent, keyword
+from SeleniumLibrary.utils import is_falsy, is_string
 
 
 class RunOnFailureKeywords(LibraryComponent):
@@ -25,53 +24,45 @@ class RunOnFailureKeywords(LibraryComponent):
     def register_keyword_to_run_on_failure(self, keyword):
         """Sets the keyword to execute when a SeleniumLibrary keyword fails.
 
-        `keyword_name` is the name of a keyword (from any available
-        libraries) that  will be executed if a SeleniumLibrary keyword fails.
-        It is not possible to use a keyword that requires arguments.
-        Using the value "Nothing" will disable this feature altogether.
+        `keyword` is the name of a keyword that will be executed if a
+        SeleniumLibrary keyword fails. It is possible to use any available
+        keyword, including user keywords or keywords from other libraries,
+        but the keyword must not take any arguments.
 
         The initial keyword to use is set in `importing`, and the
         keyword that is used by default is `Capture Page Screenshot`.
         Taking a screenshot when something failed is a very useful
         feature, but notice that it can slow down the execution.
 
+        It is possible to use string "Nothing" or "None", case-insensitively,
+        as well as any value considered false in Python to disable this
+        feature altogether.
+
         This keyword returns the name of the previously registered
-        failure keyword. It can be used to restore the original
-        value later.
+        failure keyword or Python ``None`` if this functionality was
+        previously disabled. The return value can be always used to
+        restore the original value later.
 
         Example:
         | Register Keyword To Run On Failure  | Log Source | # Run `Log Source` on failure. |
         | ${previous kw}= | Register Keyword To Run On Failure  | Nothing    | # Disables run-on-failure functionality and stores the previous kw name in a variable. |
         | Register Keyword To Run On Failure  | ${previous kw} | # Restore to the previous keyword. |
-        """
-        old_keyword = self.ctx._run_on_failure_keyword
-        old_keyword_text = old_keyword if old_keyword else "No keyword"
-
-        new_keyword = keyword if keyword.strip().lower() != "nothing" else None
-        new_keyword_text = new_keyword if new_keyword else "No keyword"
 
-        self.ctx._run_on_failure_keyword = new_keyword
-        self.info('%s will be run on failure.' % new_keyword_text)
-
-        return old_keyword_text
-
-    def run_on_failure(self):
-        if not self.ctx._run_on_failure_keyword:
-            return
-        if self.ctx._running_on_failure_routine:
-            return
-        self.ctx._running_on_failure_routine = True
-        try:
-            BuiltIn().run_keyword(self.ctx._run_on_failure_keyword)
-        except Exception as err:
-            self.run_on_failure_error(err)
-        finally:
-            self.ctx._running_on_failure_routine = False
+        Changes in version 3.0.0:
+        - Possible to use string "NONE" or any falsy value to disable the
+          feature.
+        - Return Python ``None`` when the functionality was disabled earlier.
+          In previous versions special value "No Keyword" was returned and
+          it could not be used to restore the original state.
+        """
+        old_keyword = self.ctx.run_on_failure_keyword
+        keyword = self.resolve_keyword(keyword)
+        self.ctx.run_on_failure_keyword = keyword
+        self.info('%s will be run on failure.' % (keyword or 'No keyword'))
+        return old_keyword
 
-    def run_on_failure_error(self, err):
-        err = ("Keyword '%s' could not be run on failure: %s"
-               % (self.ctx._run_on_failure_keyword, err))
-        if hasattr(self, 'warn'):
-            self.warn(err)
-            return
-        raise Exception(err)
+    @staticmethod
+    def resolve_keyword(name):
+        if is_falsy(name) or is_string(name) and name.upper() == 'NOTHING':
+            return None
+        return name
diff --git a/src/SeleniumLibrary/keywords/screenshot.py b/src/SeleniumLibrary/keywords/screenshot.py
index 9ce8ea51..27dcb083 100644
--- a/src/SeleniumLibrary/keywords/screenshot.py
+++ b/src/SeleniumLibrary/keywords/screenshot.py
@@ -18,13 +18,11 @@ import errno
 import os
 import re
 
-from robot.libraries.BuiltIn import BuiltIn
-from robot.libraries.BuiltIn import RobotNotRunningError
+from robot.libraries.BuiltIn import BuiltIn, RobotNotRunningError
 from robot.utils import get_link_path
 
 from SeleniumLibrary.base import LibraryComponent, keyword
-from SeleniumLibrary.utils import events
-from SeleniumLibrary.utils import is_falsy
+from SeleniumLibrary.utils import events, is_falsy
 
 
 class ScreenshotKeywords(LibraryComponent):
diff --git a/src/SeleniumLibrary/keywords/waiting.py b/src/SeleniumLibrary/keywords/waiting.py
index 42ac2f60..38d6a5a0 100644
--- a/src/SeleniumLibrary/keywords/waiting.py
+++ b/src/SeleniumLibrary/keywords/waiting.py
@@ -16,11 +16,10 @@
 
 import time
 
-from robot.utils import secs_to_timestr, timestr_to_secs
-
 from SeleniumLibrary.base import LibraryComponent, keyword
 from SeleniumLibrary.keywords.element import ElementKeywords
-from SeleniumLibrary.utils import is_truthy, is_falsy
+from SeleniumLibrary.utils import (is_truthy, is_falsy,
+                                   secs_to_timestr, timestr_to_secs)
 
 
 class WaitingKeywords(LibraryComponent):
@@ -264,7 +263,7 @@ class WaitingKeywords(LibraryComponent):
         self._wait_until_no_error(timeout, wait_func)
 
     def _wait_until_no_error(self, timeout, wait_func, *args):
-        timeout = timestr_to_secs(timeout) if is_truthy(timeout) else self.ctx._timeout_in_secs
+        timeout = timestr_to_secs(timeout) if is_truthy(timeout) else self.ctx.timeout
         maxtime = time.time() + timeout
         while True:
             timeout_error = wait_func(*args)
@@ -275,5 +274,5 @@ class WaitingKeywords(LibraryComponent):
             time.sleep(0.2)
 
     def _format_timeout(self, timeout):
-        timeout = timestr_to_secs(timeout) if is_truthy(timeout) else self.ctx._timeout_in_secs
+        timeout = timestr_to_secs(timeout) if is_truthy(timeout) else self.ctx.timeout
         return secs_to_timestr(timeout)
diff --git a/src/SeleniumLibrary/locators/elementfinder.py b/src/SeleniumLibrary/locators/elementfinder.py
index eabe30b9..1b37c8cb 100644
--- a/src/SeleniumLibrary/locators/elementfinder.py
+++ b/src/SeleniumLibrary/locators/elementfinder.py
@@ -18,10 +18,10 @@ from robot.api import logger
 from robot.utils import NormalizedDict
 from selenium.webdriver.remote.webelement import WebElement
 
-from .customlocator import CustomLocator
 from SeleniumLibrary.base import ContextAware
-from SeleniumLibrary.utils import escape_xpath_value, events
-from SeleniumLibrary.utils import is_falsy
+from SeleniumLibrary.utils import escape_xpath_value, events, is_falsy
+
+from .customlocator import CustomLocator
 
 
 class ElementFinder(ContextAware):
diff --git a/src/SeleniumLibrary/utils/__init__.py b/src/SeleniumLibrary/utils/__init__.py
index 117feec1..48f23b9f 100644
--- a/src/SeleniumLibrary/utils/__init__.py
+++ b/src/SeleniumLibrary/utils/__init__.py
@@ -14,7 +14,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from robot.utils import secs_to_timestr, timestr_to_secs
+
 from .browsercache import BrowserCache
+from .deprecated import Deprecated
 from .librarylistener import LibraryListener
 from .types import is_string, is_truthy, is_falsy
 
diff --git a/src/SeleniumLibrary/utils/deprecated.py b/src/SeleniumLibrary/utils/deprecated.py
new file mode 100644
index 00000000..57a4d1a5
--- /dev/null
+++ b/src/SeleniumLibrary/utils/deprecated.py
@@ -0,0 +1,38 @@
+# Copyright 2008-2011 Nokia Networks
+# Copyright 2011-2016 Ryan Tomac, Ed Manlove and contributors
+# Copyright 2016-     Robot Framework Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import warnings
+
+
+class Deprecated(object):
+
+    def __init__(self, old_name, new_name):
+        self.old_name = old_name
+        self.new_name = new_name
+
+    def __get__(self, instance, owner):
+        self._warn()
+        return getattr(instance, self.new_name)
+
+    def __set__(self, instance, value):
+        self._warn()
+        setattr(instance, self.new_name, value)
+
+    def _warn(self):
+        warnings.warn('"SeleniumLibrary.%s" is deprecated, use '
+                      '"SeleniumLibrary.%s" instead.'
+                      % (self.old_name, self.new_name),
+                      DeprecationWarning)
diff --git a/src/SeleniumLibrary/utils/types.py b/src/SeleniumLibrary/utils/types.py
index 5650a8a0..86e1890f 100644
--- a/src/SeleniumLibrary/utils/types.py
+++ b/src/SeleniumLibrary/utils/types.py
@@ -18,12 +18,11 @@
 # Can be removed when library minimum required Robot Framework version is
 # greater than 3.0.2. Then Robot Framework is_truthy should also support
 # string NONE as Python False.
-import sys
 
+import sys
 
-PY2 = sys.version_info[0] == 2
 
-if PY2:
+if sys.version_info[0] == 2:
     def is_string(item):
         return isinstance(item, (str, unicode))
 else:


Test patch:
diff --git a/test/acceptance/keywords/run_on_failure.robot b/test/acceptance/keywords/run_on_failure.robot
index 698d8047..656e93a8 100644
--- a/test/acceptance/keywords/run_on_failure.robot
+++ b/test/acceptance/keywords/run_on_failure.robot
@@ -28,19 +28,28 @@ Log Title On Failure
     ...    needle    loglevel=None
 
 Disable Run on Failure
-    [Documentation]    LOG 1 No keyword will be run on failure. LOG 2.1:2 NONE
+    [Documentation]
+    ...    LOG 1 No keyword will be run on failure.
+    ...    LOG 2.1:2 NONE
+    ...    LOG 3 No keyword will be run on failure.
+    ...    LOG 4.1:2 NONE
     Register Keyword to Run On Failure    Nothing
     Run Keyword And Expect Error    ${FAILURE MESSAGE}    Page Should Not Contain
     ...    needle    loglevel=None
+    Register Keyword to Run On Failure    ${NONE}
+    Run Keyword And Expect Error    ${FAILURE MESSAGE}    Page Should Not Contain
+    ...    needle    loglevel=None
 
 Run on Failure Returns Previous Value
-    [Documentation]    Run on Failure Returns Previous Value
+    [Documentation]    Also tests that previous value always works as input.
     ${old}=    Register Keyword to Run on Failure    Log Title
-    Should Be Equal    ${old}    No keyword
-    ${old}=    Register Keyword to Run on Failure    Log Source
+    Should Be Equal    ${old}    ${NONE}
+    ${old}=    Register Keyword to Run on Failure    ${old}
     Should Be Equal    ${old}    Log Title
     ${old}=    Register Keyword to Run on Failure    ${old}
-    Should Be Equal    ${old}    Log Source
+    Should Be Equal    ${old}    ${NONE}
+    ${old}=    Register Keyword to Run on Failure    ${old}
+    Should Be Equal    ${old}    Log Title
 
 Run On Failure also fails
     Register Keyword to Run on Failure    Failure During Run On failure
diff --git a/test/unit/keywords/test_browsermanagement.py b/test/unit/keywords/test_browsermanagement.py
index 43460657..3f577007 100644
--- a/test/unit/keywords/test_browsermanagement.py
+++ b/test/unit/keywords/test_browsermanagement.py
@@ -96,7 +96,7 @@ class BrowserManagementTests(unittest.TestCase):
 
     def test_set_selenium_timeout_only_affects_open_browsers(self):
         ctx = mock()
-        ctx._timeout_in_secs = 5.0
+        ctx.timeout = 5.0
         _browsers = mock()
         ctx._browsers = _browsers
         first_browser, second_browser = mock(), mock()
diff --git a/test/unit/keywords/test_keyword_arguments_cookie.py b/test/unit/keywords/test_keyword_arguments_cookie.py
index 7decbefe..af07cd09 100644
--- a/test/unit/keywords/test_keyword_arguments_cookie.py
+++ b/test/unit/keywords/test_keyword_arguments_cookie.py
@@ -8,10 +8,9 @@ from SeleniumLibrary.keywords import CookieKeywords
 class KeywordArgumentsCookieTest(unittest.TestCase):
 
     def setUp(self):
-        ctx = mock()
-        ctx._browser = mock()
-        self.cookie = CookieKeywords(ctx)
-        self.ctx = ctx
+        self.ctx = mock()
+        self.ctx.browser = self.browser = mock()
+        self.cookie = CookieKeywords(self.ctx)
         self.default_cookie = {'name': 'name', 'value': 'value'}
 
     def tearDown(self):
@@ -19,40 +18,40 @@ class KeywordArgumentsCookieTest(unittest.TestCase):
 
     def test_add_cookie_default(self):
         self.cookie.add_cookie('name', 'value')
-        verify(self.ctx._browser).add_cookie(self.default_cookie)
+        verify(self.browser).add_cookie(self.default_cookie)
 
     def test_add_cookie_secure_true(self):
         self.cookie.add_cookie('name', 'value', path='None', domain='None',
                                secure='True')
         cookie = self.default_cookie
         cookie['secure'] = 'True'
-        verify(self.ctx._browser).add_cookie(cookie)
+        verify(self.browser).add_cookie(cookie)
 
     def test_add_cookie_secure_false(self):
         self.cookie.add_cookie('name', 'value', path='None', domain='None',
                                secure='None')
-        verify(self.ctx._browser).add_cookie(self.default_cookie)
+        verify(self.browser).add_cookie(self.default_cookie)
 
     def test_add_cookie_domain_true(self):
         self.cookie.add_cookie('name', 'value', path='None', domain='MyDomain',
                                secure=None)
         cookie = self.default_cookie
         cookie['domain'] = 'MyDomain'
-        verify(self.ctx._browser).add_cookie(cookie)
+        verify(self.browser).add_cookie(cookie)
 
     def test_add_cookie_domain_false(self):
         self.cookie.add_cookie('name', 'value', path='None', domain='False',
                                secure=None)
-        verify(self.ctx._browser).add_cookie(self.default_cookie)
+        verify(self.browser).add_cookie(self.default_cookie)
 
     def test_add_cookie_path_true(self):
         self.cookie.add_cookie('name', 'value', path='/foo/bar', domain=None,
                                secure=None)
         cookie = self.default_cookie
         cookie['path'] = '/foo/bar'
-        verify(self.ctx._browser).add_cookie(cookie)
+        verify(self.browser).add_cookie(cookie)
 
     def test_add_cookie_path_false(self):
         self.cookie.add_cookie('name', 'value', path='None', domain=None,
                                secure=None)
-        verify(self.ctx._browser).add_cookie(self.default_cookie)
+        verify(self.browser).add_cookie(self.default_cookie)
diff --git a/test/unit/keywords/test_keyword_arguments_waiting.py b/test/unit/keywords/test_keyword_arguments_waiting.py
index 0aaf089d..6e307fff 100644
--- a/test/unit/keywords/test_keyword_arguments_waiting.py
+++ b/test/unit/keywords/test_keyword_arguments_waiting.py
@@ -1,7 +1,6 @@
 import unittest
 
 from mockito import mock, unstub, when
-from mockito.matchers import ANY
 
 from SeleniumLibrary.keywords import WaitingKeywords
 
@@ -9,11 +8,10 @@ from SeleniumLibrary.keywords import WaitingKeywords
 class KeywordArgumentsWaitingKeywordsTest(unittest.TestCase):
 
     def setUp(self):
-        ctx = mock()
-        ctx._browser = mock()
-        ctx._timeout_in_secs = 0.01
-        self.waiting = WaitingKeywords(ctx)
-        self.ctx = ctx
+        self.ctx = mock()
+        self.ctx.browser = mock()
+        self.ctx.timeout = 0.01
+        self.waiting = WaitingKeywords(self.ctx)
 
     def tearDown(self):
         unstub()
diff --git a/test/unit/keywords/test_runonfailure_from_lib.py b/test/unit/keywords/test_runonfailure_from_lib.py
index a375066e..07e667d7 100644
--- a/test/unit/keywords/test_runonfailure_from_lib.py
+++ b/test/unit/keywords/test_runonfailure_from_lib.py
@@ -11,14 +11,14 @@ class SeleniumLibraryRunOnFailureTest(unittest.TestCase):
     def tearDown(self):
         unstub()
 
-    def test_run_on_failure(self):
-        when(RunOnFailureKeywords).run_on_failure().thenReturn(True)
+    def test_failure_occurred(self):
+        when(SeleniumLibrary).failure_occurred().thenReturn(True)
         sl = SeleniumLibrary()
-        sl.run_on_failure()
-        verify(RunOnFailureKeywords, times=1).run_on_failure()
+        sl.failure_occurred()
+        verify(SeleniumLibrary, times=1).failure_occurred()
 
-    def test_underscore_run_on_failure(self):
-        when(RunOnFailureKeywords).run_on_failure().thenReturn(True)
+    def test_deprecated_run_on_failure(self):
+        when(SeleniumLibrary).failure_occurred().thenReturn(True)
         sl = SeleniumLibrary()
         sl._run_on_failure()
-        verify(RunOnFailureKeywords, times=1).run_on_failure()
+        verify(SeleniumLibrary, times=1).failure_occurred()
diff --git a/test/unit/locators/test_elementfinder.py b/test/unit/locators/test_elementfinder.py
index a22b6b01..43754bfd 100644
--- a/test/unit/locators/test_elementfinder.py
+++ b/test/unit/locators/test_elementfinder.py
@@ -8,11 +8,9 @@ from SeleniumLibrary.locators.elementfinder import ElementFinder
 class ElementFinderTests(unittest.TestCase):
 
     def setUp(self):
-        ctx = mock()
-        _browser = mock()
-        ctx._browser = _browser
-        self.finder = ElementFinder(ctx)
-        self.ctx = ctx
+        self.ctx = mock()
+        self.ctx.browser = self.browser = mock()
+        self.finder = ElementFinder(self.ctx)
 
     def tearDown(self):
         unstub()
@@ -36,18 +34,18 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_with_no_tag(self):
         self.finder.find("test1", required=False)
-        verify(self.ctx._browser).find_elements_by_xpath("//*[(@id='test1' or "
+        verify(self.browser).find_elements_by_xpath("//*[(@id='test1' or "
                                                          "@name='test1')]")
 
     def test_find_with_explicit_default_strategy(self):
         self.finder.find("default=test1", required=False)
-        verify(self.ctx._browser).find_elements_by_xpath("//*[(@id='test1' or "
+        verify(self.browser).find_elements_by_xpath("//*[(@id='test1' or "
                                                          "@name='test1')]")
 
     def test_find_with_explicit_default_strategy_and_equals(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("default=page.do?foo=bar", tag='a', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//a[(@id='page.do?foo=bar' or @name='page.do?foo=bar' or "
             "@href='page.do?foo=bar' or "
             "normalize-space(descendant-or-self::text())='page.do?foo=bar' or "
@@ -55,90 +53,90 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_with_tag(self):
         self.finder.find("test1", tag='div', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//div[(@id='test1' or @name='test1')]")
 
     def test_find_with_locator_with_apos(self):
         self.finder.find("test '1'", required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//*[(@id=\"test '1'\" or @name=\"test '1'\")]")
 
     def test_find_with_locator_with_quote(self):
         self.finder.find("test \"1\"", required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//*[(@id='test \"1\"' or @name='test \"1\"')]")
 
     def test_find_with_locator_with_quote_and_apos(self):
         self.finder.find("test \"1\" and '2'", required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//*[(@id=concat('test \"1\" and ', \"'\", '2', \"'\", '') "
             "or @name=concat('test \"1\" and ', \"'\", '2', \"'\", ''))]")
 
     def test_find_with_a(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("test1", tag='a', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//a[(@id='test1' or @name='test1' or @href='test1' or "
             "normalize-space(descendant-or-self::text())='test1' or "
             "@href='http://localhost/test1')]")
 
     def test_find_with_link_synonym(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("test1", tag='link', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//a[(@id='test1' or @name='test1' or @href='test1' or "
             "normalize-space(descendant-or-self::text())='test1' or "
             "@href='http://localhost/test1')]")
 
     def test_find_with_img(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("test1", tag='img', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//img[(@id='test1' or @name='test1' or @src='test1' or "
             "@alt='test1' or @src='http://localhost/test1')]")
 
     def test_find_with_image_synonym(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("test1", tag='image', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//img[(@id='test1' or @name='test1' or @src='test1' or "
             "@alt='test1' or @src='http://localhost/test1')]")
 
     def test_find_with_input(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("test1", tag='input', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//input[(@id='test1' or @name='test1' or @value='test1' or "
             "@src='test1' or @src='http://localhost/test1')]")
 
     def test_find_with_radio_button_synonym(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("test1", tag='radio button', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//input[@type='radio' and (@id='test1' or @name='test1' or "
             "@value='test1' or @src='test1' or "
             "@src='http://localhost/test1')]")
 
     def test_find_with_checkbox_synonym(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("test1", tag='checkbox', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//input[@type='checkbox' and (@id='test1' or @name='test1' or "
             "@value='test1' or @src='test1' or "
             "@src='http://localhost/test1')]")
 
     def test_find_with_file_upload_synonym(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("test1", tag='file upload', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//input[@type='file' and (@id='test1' or @name='test1' or "
             "@value='test1' or @src='test1' or "
             "@src='http://localhost/test1')]")
 
     def test_find_with_text_field_synonym(self):
-        self.ctx._browser.current_url = "http://localhost/mypage.html"
+        self.browser.current_url = "http://localhost/mypage.html"
         self.finder.find("test1", tag='text field', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//input[@type[. = 'date' or . = 'datetime-local' or . = 'email' or "
             ". = 'month' or . = 'number' or . = 'password' or . = 'search' or "
             ". = 'tel' or . = 'text' or . = 'time' or . = 'url' or . = 'week'] and "
@@ -147,23 +145,23 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_with_button(self):
         self.finder.find("test1", tag='button', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//button[(@id='test1' or @name='test1' or @value='test1' or "
             "normalize-space(descendant-or-self::text())='test1')]")
 
     def test_find_with_select(self):
         self.finder.find("test1", tag='select', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//select[(@id='test1' or @name='test1')]")
 
     def test_find_with_list_synonym(self):
         self.finder.find("test1", tag='list', required=False)
-        verify(self.ctx._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//select[(@id='test1' or @name='test1')]")
 
     def test_find_with_implicit_xpath(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_xpath(
+        when(self.browser).find_elements_by_xpath(
             "//*[(@test='1')]").thenReturn(elements)
         result = self.finder.find("//*[(@test='1')]", first_only=False)
         self.assertEqual(result, elements)
@@ -174,9 +172,9 @@ class ElementFinderTests(unittest.TestCase):
     def test_find_by_identifier(self):
         id_elements = self._make_mock_elements('div', 'a')
         name_elements = self._make_mock_elements('span', 'a')
-        when(self.ctx._browser).find_elements_by_id("test1").thenReturn(
+        when(self.browser).find_elements_by_id("test1").thenReturn(
             list(id_elements)).thenReturn(list(id_elements))
-        when(self.ctx._browser).find_elements_by_name("test1").thenReturn(
+        when(self.browser).find_elements_by_name("test1").thenReturn(
             list(name_elements)).thenReturn(list(name_elements))
         all_elements = list(id_elements)
         all_elements.extend(name_elements)
@@ -188,7 +186,7 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_by_id(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_id("test1").thenReturn(
+        when(self.browser).find_elements_by_id("test1").thenReturn(
             elements)
         result = self.finder.find("id=test1", first_only=False)
         self.assertEqual(result, elements)
@@ -197,7 +195,7 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_by_name(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_name("test1").thenReturn(
+        when(self.browser).find_elements_by_name("test1").thenReturn(
             elements)
         result = self.finder.find("name=test1", first_only=False)
         self.assertEqual(result, elements)
@@ -206,7 +204,7 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_by_xpath(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_xpath(
+        when(self.browser).find_elements_by_xpath(
             "//*[(@test='1')]").thenReturn(elements)
         result = self.finder.find("xpath=//*[(@test='1')]", first_only=False)
         self.assertEqual(result, elements)
@@ -217,7 +215,7 @@ class ElementFinderTests(unittest.TestCase):
     def test_find_by_dom(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
         elems = [elements[1], elements[3]]
-        when(self.ctx._browser).execute_script(
+        when(self.browser).execute_script(
             "return document.getElementsByTagName('a');").thenReturn(elems)
         result = self.finder.find("dom=document.getElementsByTagName('a')",
                                   first_only=False)
@@ -225,7 +223,7 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_by_link_text(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_link_text(
+        when(self.browser).find_elements_by_link_text(
             "my link").thenReturn(elements)
         result = self.finder.find("link=my link", first_only=False)
         self.assertEqual(result, elements)
@@ -234,7 +232,7 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_by_partial_link_text(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_partial_link_text(
+        when(self.browser).find_elements_by_partial_link_text(
             "my link").thenReturn(elements)
         result = self.finder.find("partial link=my link", first_only=False)
         self.assertEqual(result, elements)
@@ -244,7 +242,7 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_by_css_selector(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "#test1").thenReturn(elements)
         result = self.finder.find("css=#test1", first_only=False)
         self.assertEqual(result, elements)
@@ -253,7 +251,7 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_by_class_names(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_class_name(
+        when(self.browser).find_elements_by_class_name(
             "test1").thenReturn(elements)
         result = self.finder.find("class=test1", first_only=False)
         self.assertEqual(result, elements)
@@ -262,7 +260,7 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_by_tag_name(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_tag_name(
+        when(self.browser).find_elements_by_tag_name(
             "div").thenReturn(elements)
         result = self.finder.find("tag=div", first_only=False)
         self.assertEqual(result, elements)
@@ -271,9 +269,9 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_with_sloppy_prefix(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_id("test1").thenReturn(
+        when(self.browser).find_elements_by_id("test1").thenReturn(
             elements)
-        when(self.ctx._browser).find_elements_by_partial_link_text(
+        when(self.browser).find_elements_by_partial_link_text(
             "test1").thenReturn(elements)
         result = self.finder.find("ID=test1", first_only=False)
         self.assertEqual(result, elements)
@@ -290,7 +288,7 @@ class ElementFinderTests(unittest.TestCase):
 
     def test_find_with_sloppy_criteria(self):
         elements = self._make_mock_elements('div', 'a', 'span', 'a')
-        when(self.ctx._browser).find_elements_by_id("test1  ").thenReturn(
+        when(self.browser).find_elements_by_id("test1  ").thenReturn(
             elements)
         result = self.finder.find("id= test1  ", first_only=False)
         self.assertEqual(result, elements)
@@ -304,7 +302,7 @@ class ElementFinderTests(unittest.TestCase):
         elements[5].set_attribute('type', 'text')
         elements[7].set_attribute('type', 'file')
         elements[8].set_attribute('type', 'email')
-        when(self.ctx._browser).find_elements_by_id("test1").thenReturn(
+        when(self.browser).find_elements_by_id("test1").thenReturn(
             elements)
         result = self.finder.find("id=test1", first_only=False)
         self.assertEqual(result, elements)
@@ -331,7 +329,7 @@ class ElementFinderTests(unittest.TestCase):
                     'find_elements_by_tag_name')
         for bad_value in (None, {'': None}):
             for func_name in locators:
-                when_find_func = getattr(when(self.ctx._browser), func_name)
+                when_find_func = getattr(when(self.browser), func_name)
                 when_find_func(any()).thenReturn(bad_value)
             for locator in ("identifier=it", "id=it", "name=it", "xpath=//div",
                             "link=it", "css=div.it", "tag=div", "default"):
diff --git a/test/unit/locators/test_tableelementfinder.py b/test/unit/locators/test_tableelementfinder.py
index e92f1d4b..823e365e 100644
--- a/test/unit/locators/test_tableelementfinder.py
+++ b/test/unit/locators/test_tableelementfinder.py
@@ -9,128 +9,127 @@ class ElementFinderTests(unittest.TestCase):
 
     def setUp(self):
         self.ctx = mock()
-        self._browser = mock()
-        self.ctx._browser = self._browser
+        self.ctx.browser = self.browser = mock()
         self.finder = TableElementFinder(self.ctx)
 
     def tearDown(self):
         unstub()
 
     def test_find_with_implicit_css_locator(self):
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1").thenReturn([])
         self.finder.find("test1")
-        verify(self._browser).find_elements_by_css_selector("table#test1")
+        verify(self.browser).find_elements_by_css_selector("table#test1")
 
     def test_find_with_css_selector(self):
         elements = self._make_mock_elements('table', 'table', 'table')
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1").thenReturn(elements)
         self.assertEqual(
             self.finder.find("css=table#test1"),
             elements[0])
-        verify(self._browser).find_elements_by_css_selector("table#test1")
+        verify(self.browser).find_elements_by_css_selector("table#test1")
 
     def test_find_with_xpath_selector(self):
         elements = self._make_mock_elements('table', 'table', 'table')
-        when(self._browser).find_elements_by_xpath(
+        when(self.browser).find_elements_by_xpath(
             "//table[@id='test1']").thenReturn(elements)
         self.assertEqual(
             self.finder.find("xpath=//table[@id='test1']"),
             elements[0])
-        verify(self._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//table[@id='test1']")
 
     def test_find_with_content_constraint(self):
         elements = self._make_mock_elements('td', 'td', 'td')
         elements[1].text = 'hi'
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1").thenReturn(elements)
         self.assertEqual(
             self.finder.find_by_content("test1", 'hi'),
             elements[1])
-        verify(self._browser).find_elements_by_css_selector("table#test1")
+        verify(self.browser).find_elements_by_css_selector("table#test1")
 
     def test_find_with_null_content_constraint(self):
         elements = self._make_mock_elements('td', 'td', 'td')
         elements[1].text = 'hi'
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1").thenReturn(elements)
         self.assertEqual(
             self.finder.find_by_content("test1", None),
             elements[0])
-        verify(self._browser).find_elements_by_css_selector("table#test1")
+        verify(self.browser).find_elements_by_css_selector("table#test1")
 
     def test_find_by_content_with_css_locator(self):
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1").thenReturn([])
         self.finder.find_by_content("css=table#test1", 'hi')
-        verify(self._browser).find_elements_by_css_selector("table#test1")
+        verify(self.browser).find_elements_by_css_selector("table#test1")
 
     def test_find_by_content_with_xpath_locator(self):
-        when(self._browser).find_elements_by_xpath(
+        when(self.browser).find_elements_by_xpath(
             "//table[@id='test1']//*").thenReturn([])
         self.finder.find_by_content("xpath=//table[@id='test1']", 'hi')
-        verify(self._browser).find_elements_by_xpath("//table[@id='test1']//*")
+        verify(self.browser).find_elements_by_xpath("//table[@id='test1']//*")
 
     def test_find_by_header_with_css_locator(self):
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1 th").thenReturn([])
         self.finder.find_by_header("css=table#test1", 'hi')
-        verify(self._browser).find_elements_by_css_selector("table#test1 th")
+        verify(self.browser).find_elements_by_css_selector("table#test1 th")
 
     def test_find_by_header_with_xpath_locator(self):
-        when(self._browser).find_elements_by_xpath(
+        when(self.browser).find_elements_by_xpath(
             "//table[@id='test1']//th").thenReturn([])
         self.finder.find_by_header("xpath=//table[@id='test1']", 'hi')
-        verify(self._browser).find_elements_by_xpath(
+        verify(self.browser).find_elements_by_xpath(
             "//table[@id='test1']//th")
 
     def test_find_by_footer_with_css_locator(self):
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1 tfoot td").thenReturn([])
         self.finder.find_by_footer("css=table#test1", 'hi')
-        verify(self._browser).find_elements_by_css_selector(
+        verify(self.browser).find_elements_by_css_selector(
             "table#test1 tfoot td")
 
     def test_find_by_footer_with_xpath_locator(self):
-        when(self._browser).find_elements_by_xpath(
+        when(self.browser).find_elements_by_xpath(
             "//table[@id='test1']//tfoot//td").thenReturn([])
         self.finder.find_by_footer("xpath=//table[@id='test1']", 'hi')
-        verify(self._browser).find_elements_by_xpath("//table[@id='test1']"
+        verify(self.browser).find_elements_by_xpath("//table[@id='test1']"
                                                      "//tfoot//td")
 
     def test_find_by_row_with_css_locator(self):
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1 tr:nth-child(2)").thenReturn([])
         self.finder.find_by_row("css=table#test1", 2, 'hi')
-        verify(self._browser).find_elements_by_css_selector("table#test1 "
+        verify(self.browser).find_elements_by_css_selector("table#test1 "
                                                             "tr:nth-child(2)")
 
     def test_find_by_row_with_xpath_locator(self):
-        when(self._browser).find_elements_by_xpath(
+        when(self.browser).find_elements_by_xpath(
             "//table[@id='test1']//tr[2]//*").thenReturn([])
         self.finder.find_by_row("xpath=//table[@id='test1']", 2, 'hi')
-        verify(self._browser).find_elements_by_xpath("//table[@id='test1']"
+        verify(self.browser).find_elements_by_xpath("//table[@id='test1']"
                                                      "//tr[2]//*")
 
     def test_find_by_col_with_css_locator(self):
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1 tr td:nth-child(2)").thenReturn([])
-        when(self._browser).find_elements_by_css_selector(
+        when(self.browser).find_elements_by_css_selector(
             "table#test1 tr th:nth-child(2)").thenReturn([])
         self.finder.find_by_col("css=table#test1", 2, 'hi')
-        verify(self._browser).find_elements_by_css_selector(
+        verify(self.browser).find_elements_by_css_selector(
             "table#test1 tr td:nth-child(2)")
-        verify(self._browser).find_elements_by_css_selector(
+        verify(self.browser).find_elements_by_css_selector(
             "table#test1 tr th:nth-child(2)")
 
     def test_find_by_col_with_xpath_locator(self):
-        when(self._browser).find_elements_by_xpath("//table[@id='test1']//tr//"
+        when(self.browser).find_elements_by_xpath("//table[@id='test1']//tr//"
                                                    "*[self::td or self"
                                                    "::th][2]").thenReturn([])
         self.finder.find_by_col("xpath=//table[@id='test1']", 2, 'hi')
-        verify(self._browser).find_elements_by_xpath("//table[@id='test1']"
+        verify(self.browser).find_elements_by_xpath("//table[@id='test1']"
                                                      "//tr//*[self::td or self"
                                                      "::th][2]")