diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py index 9f5e0a90f..07e658c12 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 @@ def __init__(self, | 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 @@ def __init__(self, ] 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 @@ def _cache(self): 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 b0c3d8326..0dc3ebc81 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 @@ def __init__(self, ctx): @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 f21df473d..c87d874d7 100644 --- a/src/SeleniumLibrary/keywords/browsermanagement.py +++ b/src/SeleniumLibrary/keywords/browsermanagement.py @@ -19,13 +19,13 @@ 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__), "..")) @@ -480,22 +480,25 @@ def reload_page(self): 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 +518,10 @@ def set_selenium_speed(self, seconds): 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 +544,9 @@ def set_selenium_timeout(self, seconds): | 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 +564,9 @@ def set_selenium_implicit_wait(self, seconds): | 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 +582,7 @@ def set_browser_implicit_wait(self, seconds): 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 +596,8 @@ def _make_browser(self, browser_name, desired_capabilities=None, 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 429d417e5..aa2b9ffe5 100644 --- a/src/SeleniumLibrary/keywords/element.py +++ b/src/SeleniumLibrary/keywords/element.py @@ -19,8 +19,7 @@ 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 f968255d2..cd5a7f1eb 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 9ce8ea51a..27dcb0833 100644 --- a/src/SeleniumLibrary/keywords/screenshot.py +++ b/src/SeleniumLibrary/keywords/screenshot.py @@ -18,13 +18,11 @@ 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 42ac2f602..38d6a5a09 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 @@ def wait_func(): 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 @@ def _wait_until_no_error(self, timeout, wait_func, *args): 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 eabe30b9a..1b37c8cb7 100644 --- a/src/SeleniumLibrary/locators/elementfinder.py +++ b/src/SeleniumLibrary/locators/elementfinder.py @@ -18,10 +18,10 @@ 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 117feec14..48f23b9fa 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 000000000..57a4d1a5a --- /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 5650a8a06..86e1890fd 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: diff --git a/test/acceptance/keywords/run_on_failure.robot b/test/acceptance/keywords/run_on_failure.robot index 698d80472..656e93a89 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 43460657e..3f5770078 100644 --- a/test/unit/keywords/test_browsermanagement.py +++ b/test/unit/keywords/test_browsermanagement.py @@ -96,7 +96,7 @@ def test_capabilities_attribute_not_modified(self): 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 7decbefed..af07cd09d 100644 --- a/test/unit/keywords/test_keyword_arguments_cookie.py +++ b/test/unit/keywords/test_keyword_arguments_cookie.py @@ -8,10 +8,9 @@ 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 @@ def tearDown(self): 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 0aaf089d3..6e307fff6 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 @@ 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 a375066e9..07e667d74 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 a22b6b017..43754bfd9 100644 --- a/test/unit/locators/test_elementfinder.py +++ b/test/unit/locators/test_elementfinder.py @@ -8,11 +8,9 @@ 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 @@ def test_find_with_null_browser(self): 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 @@ def test_find_with_explicit_default_strategy_and_equals(self): 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 @@ def test_find_with_text_field_synonym(self): 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 @@ def test_find_with_implicit_xpath(self): 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 @@ def test_find_by_identifier(self): 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 @@ def test_find_by_id(self): 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 @@ def test_find_by_name(self): 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 @@ def test_find_by_xpath(self): 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 @@ def test_find_by_dom(self): 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 @@ def test_find_by_link_text(self): 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 @@ def test_find_by_partial_link_text(self): 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 @@ def test_find_by_css_selector(self): 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 @@ def test_find_by_class_names(self): 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 @@ def test_find_by_tag_name(self): 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 @@ def test_find_with_sloppy_prefix(self): 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 @@ def test_find_by_id_with_synonym_and_constraints(self): 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 @@ def test_find_returns_bad_values(self): '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 e92f1d4ba..823e365ee 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]")