From 25e35bc329a0fd250bc042d209adc5bbf59d5c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pekka=20Kl=C3=A4rck?= Date: Sat, 2 Sep 2017 18:13:20 +0300 Subject: [PATCH 1/6] Little import cleanups. - Merge imports from same module into single import. - Expose some often used robot.utils via our utils. --- src/SeleniumLibrary/__init__.py | 25 +++++++++---------- .../keywords/browsermanagement.py | 4 +-- src/SeleniumLibrary/keywords/waiting.py | 5 ++-- src/SeleniumLibrary/utils/__init__.py | 2 ++ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py index 9f5e0a90f..76fe65537 100644 --- a/src/SeleniumLibrary/__init__.py +++ b/src/SeleniumLibrary/__init__.py @@ -17,20 +17,19 @@ 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 .keywords import (AlertKeywords, + BrowserManagementKeywords, + CookieKeywords, + ElementKeywords, + FormElementKeywords, + JavaScriptKeywords, + RunOnFailureKeywords, + ScreenshotKeywords, + SelectElementKeywords, + TableElementKeywords, + WaitingKeywords) from .locators import ElementFinder -from .utils import BrowserCache -from .utils import LibraryListener +from .utils import BrowserCache, LibraryListener __version__ = '3.0.0b1' diff --git a/src/SeleniumLibrary/keywords/browsermanagement.py b/src/SeleniumLibrary/keywords/browsermanagement.py index f21df473d..b0411b151 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__), "..")) diff --git a/src/SeleniumLibrary/keywords/waiting.py b/src/SeleniumLibrary/keywords/waiting.py index 42ac2f602..6400569ce 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): diff --git a/src/SeleniumLibrary/utils/__init__.py b/src/SeleniumLibrary/utils/__init__.py index 117feec14..632270320 100644 --- a/src/SeleniumLibrary/utils/__init__.py +++ b/src/SeleniumLibrary/utils/__init__.py @@ -14,6 +14,8 @@ # 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 .librarylistener import LibraryListener from .types import is_string, is_truthy, is_falsy From 8e8101bb85541af6acb361916516dd850e2641db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pekka=20Kl=C3=A4rck?= Date: Sat, 2 Sep 2017 23:21:10 +0300 Subject: [PATCH 2/6] Fixes and cleanup to running keyword on failure. 1. Return value from `Register keyword to run on failure` can now always be used as an argument to the keyword. In practice the keyword nowadays returns `None` if the functionality was disabled and `None` (as well as `'NONE'`) can be used to disable the functionality. Fixes #176. 2. Moved the hook method to run when a keyword fails to the core. This simplifies implementation. The hook method was also renamed from `run_on_failure` to `failure_occurred`. --- src/SeleniumLibrary/__init__.py | 36 +++++++---- src/SeleniumLibrary/keywords/runonfailure.py | 63 ++++++++----------- test/acceptance/keywords/run_on_failure.robot | 19 ++++-- .../keywords/test_runonfailure_from_lib.py | 14 ++--- 4 files changed, 69 insertions(+), 63 deletions(-) diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py index 76fe65537..d5063428d 100644 --- a/src/SeleniumLibrary/__init__.py +++ b/src/SeleniumLibrary/__init__.py @@ -16,6 +16,9 @@ import warnings +from robot.api import logger +from robot.libraries.BuiltIn import BuiltIn + from .base import DynamicCore from .keywords import (AlertKeywords, BrowserManagementKeywords, @@ -193,7 +196,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,7 +236,7 @@ def __init__(self, | 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._running_on_failure_keyword = False self._speed_in_secs = 0.0 self._timeout_in_secs = 5.0 self._implicit_wait_in_secs = 5.0 @@ -264,21 +266,29 @@ 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): @@ -301,6 +311,6 @@ def _current_browser(self): 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/keywords/runonfailure.py b/src/SeleniumLibrary/keywords/runonfailure.py index f968255d2..417d976b8 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,41 @@ 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. | + + 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 - 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 - - 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) + if is_falsy(keyword) \ + or is_string(keyword) and keyword.upper() == 'NOTHING': + keyword = None + self.ctx._run_on_failure_keyword = keyword + self.info('%s will be run on failure.' % (keyword or 'No keyword')) + return old_keyword 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_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() From cec9ff013abd7327eb94f68206677ceaf598dfd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pekka=20Kl=C3=A4rck?= Date: Sat, 2 Sep 2017 23:34:09 +0300 Subject: [PATCH 3/6] More import cleanup --- src/SeleniumLibrary/__init__.py | 28 +++++++++---------- src/SeleniumLibrary/base/context.py | 1 + src/SeleniumLibrary/keywords/element.py | 3 +- src/SeleniumLibrary/keywords/screenshot.py | 6 ++-- src/SeleniumLibrary/locators/elementfinder.py | 6 ++-- src/SeleniumLibrary/utils/types.py | 5 ++-- 6 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py index d5063428d..c12f169fb 100644 --- a/src/SeleniumLibrary/__init__.py +++ b/src/SeleniumLibrary/__init__.py @@ -19,20 +19,20 @@ from robot.api import logger from robot.libraries.BuiltIn import BuiltIn -from .base import DynamicCore -from .keywords import (AlertKeywords, - BrowserManagementKeywords, - CookieKeywords, - ElementKeywords, - FormElementKeywords, - JavaScriptKeywords, - RunOnFailureKeywords, - ScreenshotKeywords, - SelectElementKeywords, - TableElementKeywords, - WaitingKeywords) -from .locators import ElementFinder -from .utils import BrowserCache, LibraryListener +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, LibraryListener __version__ = '3.0.0b1' diff --git a/src/SeleniumLibrary/base/context.py b/src/SeleniumLibrary/base/context.py index b0c3d8326..89d048371 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): 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/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/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/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: From 14bbd1462231c19ed83921b9f5815dae2e1bc674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pekka=20Kl=C3=A4rck?= Date: Sun, 3 Sep 2017 00:08:44 +0300 Subject: [PATCH 4/6] Make public API public. #882 Renamed these: _run_on_failure_keyword _speed_in_secs _timeout_in_secs _implicit_wait_in_secs to these: run_on_failure_keyword speed timeout implicit_wait Original attributes still work but are deprecated. Deprecation isn't currently tested but unit tests could be added. --- src/SeleniumLibrary/__init__.py | 30 +++++++++------ .../keywords/browsermanagement.py | 36 +++++++++--------- src/SeleniumLibrary/keywords/runonfailure.py | 14 ++++--- src/SeleniumLibrary/keywords/waiting.py | 4 +- src/SeleniumLibrary/utils/__init__.py | 1 + src/SeleniumLibrary/utils/deprecated.py | 38 +++++++++++++++++++ test/unit/keywords/test_browsermanagement.py | 2 +- .../test_keyword_arguments_waiting.py | 3 +- 8 files changed, 89 insertions(+), 39 deletions(-) create mode 100644 src/SeleniumLibrary/utils/deprecated.py diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py index c12f169fb..25ac96073 100644 --- a/src/SeleniumLibrary/__init__.py +++ b/src/SeleniumLibrary/__init__.py @@ -32,7 +32,8 @@ TableElementKeywords, WaitingKeywords) from SeleniumLibrary.locators import ElementFinder -from SeleniumLibrary.utils import BrowserCache, LibraryListener +from SeleniumLibrary.utils import (BrowserCache, Deprecated, LibraryListener, + timestr_to_secs) __version__ = '3.0.0b1' @@ -235,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.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._speed_in_secs = 0.0 - self._timeout_in_secs = 5.0 - self._implicit_wait_in_secs = 5.0 + self.screenshot_root_directory = screenshot_root_directory libraries = [ AlertKeywords(self), BrowserManagementKeywords(self), @@ -255,13 +258,16 @@ 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) @@ -279,14 +285,14 @@ def failure_occurred(self): 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: + 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) + 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)) + % (self.run_on_failure_keyword, err)) finally: self._running_on_failure_keyword = False diff --git a/src/SeleniumLibrary/keywords/browsermanagement.py b/src/SeleniumLibrary/keywords/browsermanagement.py index b0411b151..e4c7ab2af 100644 --- a/src/SeleniumLibrary/keywords/browsermanagement.py +++ b/src/SeleniumLibrary/keywords/browsermanagement.py @@ -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. + q""" + 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/runonfailure.py b/src/SeleniumLibrary/keywords/runonfailure.py index 417d976b8..cd5a7f1eb 100644 --- a/src/SeleniumLibrary/keywords/runonfailure.py +++ b/src/SeleniumLibrary/keywords/runonfailure.py @@ -55,10 +55,14 @@ def register_keyword_to_run_on_failure(self, keyword): 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 - if is_falsy(keyword) \ - or is_string(keyword) and keyword.upper() == 'NOTHING': - keyword = None - self.ctx._run_on_failure_keyword = keyword + 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 + + @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/waiting.py b/src/SeleniumLibrary/keywords/waiting.py index 6400569ce..38d6a5a09 100644 --- a/src/SeleniumLibrary/keywords/waiting.py +++ b/src/SeleniumLibrary/keywords/waiting.py @@ -263,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) @@ -274,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/utils/__init__.py b/src/SeleniumLibrary/utils/__init__.py index 632270320..48f23b9fa 100644 --- a/src/SeleniumLibrary/utils/__init__.py +++ b/src/SeleniumLibrary/utils/__init__.py @@ -17,6 +17,7 @@ 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/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_waiting.py b/test/unit/keywords/test_keyword_arguments_waiting.py index 0aaf089d3..f1693b8b4 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 @@ -11,7 +10,7 @@ class KeywordArgumentsWaitingKeywordsTest(unittest.TestCase): def setUp(self): ctx = mock() ctx._browser = mock() - ctx._timeout_in_secs = 0.01 + ctx.timeout = 0.01 self.waiting = WaitingKeywords(ctx) self.ctx = ctx From d3cddd8f6673afc1afe656174966511e234e8aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pekka=20Kl=C3=A4rck?= Date: Sun, 3 Sep 2017 01:00:08 +0300 Subject: [PATCH 5/6] _browser -> browser #882 --- src/SeleniumLibrary/__init__.py | 6 +- src/SeleniumLibrary/base/context.py | 2 +- .../keywords/test_keyword_arguments_cookie.py | 21 ++-- .../test_keyword_arguments_waiting.py | 9 +- test/unit/locators/test_elementfinder.py | 100 +++++++++--------- test/unit/locators/test_tableelementfinder.py | 67 ++++++------ 6 files changed, 100 insertions(+), 105 deletions(-) diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py index 25ac96073..07e658c12 100644 --- a/src/SeleniumLibrary/__init__.py +++ b/src/SeleniumLibrary/__init__.py @@ -297,7 +297,7 @@ def failure_occurred(self): 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') @@ -311,9 +311,9 @@ 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, ' diff --git a/src/SeleniumLibrary/base/context.py b/src/SeleniumLibrary/base/context.py index 89d048371..0dc3ebc81 100644 --- a/src/SeleniumLibrary/base/context.py +++ b/src/SeleniumLibrary/base/context.py @@ -22,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/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 f1693b8b4..6e307fff6 100644 --- a/test/unit/keywords/test_keyword_arguments_waiting.py +++ b/test/unit/keywords/test_keyword_arguments_waiting.py @@ -8,11 +8,10 @@ class KeywordArgumentsWaitingKeywordsTest(unittest.TestCase): def setUp(self): - ctx = mock() - ctx._browser = mock() - ctx.timeout = 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/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]") From 5759dfb319430c10a7a2a2976c0d2d5b665d0083 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Mon, 4 Sep 2017 23:19:21 +0300 Subject: [PATCH 6/6] Removed the not required q character from doc The line 492 contained not needed q character. --- src/SeleniumLibrary/keywords/browsermanagement.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SeleniumLibrary/keywords/browsermanagement.py b/src/SeleniumLibrary/keywords/browsermanagement.py index e4c7ab2af..c87d874d7 100644 --- a/src/SeleniumLibrary/keywords/browsermanagement.py +++ b/src/SeleniumLibrary/keywords/browsermanagement.py @@ -489,7 +489,7 @@ def get_selenium_timeout(self): """Gets the timeout in seconds that is used by various keywords. See `Set Selenium Timeout` for an explanation. - q""" + """ return secs_to_timestr(self.ctx.timeout) @keyword