From f870f9c57e1d1cd2cb05c71d173e723d4335815d Mon Sep 17 00:00:00 2001 From: Kevin Ormbrek Date: Tue, 30 Sep 2014 23:24:44 -0500 Subject: [PATCH 1/5] add default prefix and support prefixes with spaces --- CHANGES.rst | 4 +++ src/Selenium2Library/__init__.py | 1 + .../locators/elementfinder.py | 10 +++++--- test/unit/locators/test_elementfinder.py | 25 +++++++++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 5ca645388..f0e7ae657 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -21,6 +21,10 @@ Release Notes - Fixed issue where 'Select Window’ with url strategy fails to locate window [laulaz] +- Allow using key attributes (default strategy) when the locator contains + a '='. Also make locator prefixes space-insensitive. + [ombre42] + 1.5 --- - Copy Desired Capabilities before modifying to prevent affecting future diff --git a/src/Selenium2Library/__init__.py b/src/Selenium2Library/__init__.py index f6316ee35..b97381941 100644 --- a/src/Selenium2Library/__init__.py +++ b/src/Selenium2Library/__init__.py @@ -60,6 +60,7 @@ class Selenium2Library( | jquery | Click Element `|` jquery=div.my_class | Matches by jQuery/sizzle selector | | sizzle | Click Element `|` sizzle=div.my_class | Matches by jQuery/sizzle selector | | tag | Click Element `|` tag=div | Matches by HTML tag name | + | default | Click Link `|` default=page?a=b | Matches key attributes with value after first '=' | Table related keywords, such as `Table Should Contain`, work differently. By default, when a table locator value is provided, it will search for diff --git a/src/Selenium2Library/locators/elementfinder.py b/src/Selenium2Library/locators/elementfinder.py index a63dd2232..a165232a5 100644 --- a/src/Selenium2Library/locators/elementfinder.py +++ b/src/Selenium2Library/locators/elementfinder.py @@ -1,10 +1,12 @@ from Selenium2Library import utils from robot.api import logger +from robot.utils import NormalizedDict + class ElementFinder(object): def __init__(self): - self._strategies = { + strategies = { 'identifier': self._find_by_identifier, 'id': self._find_by_id, 'name': self._find_by_name, @@ -16,14 +18,16 @@ def __init__(self): 'jquery': self._find_by_sizzle_selector, 'sizzle': self._find_by_sizzle_selector, 'tag': self._find_by_tag_name, - None: self._find_by_default + 'default': self._find_by_default } + self._strategies = NormalizedDict(initial=strategies, caseless=True, spaceless=True) def find(self, browser, locator, tag=None): assert browser is not None assert locator is not None and len(locator) > 0 (prefix, criteria) = self._parse_locator(locator) + prefix = 'default' if prefix is None else prefix strategy = self._strategies.get(prefix) if strategy is None: raise ValueError("Element locator with prefix '" + prefix + "' is not supported") @@ -187,7 +191,7 @@ def _parse_locator(self, locator): if not locator.startswith('//'): locator_parts = locator.partition('=') if len(locator_parts[1]) > 0: - prefix = locator_parts[0].strip().lower() + prefix = locator_parts[0] criteria = locator_parts[2].strip() return (prefix, criteria) diff --git a/test/unit/locators/test_elementfinder.py b/test/unit/locators/test_elementfinder.py index b44da3f3e..937aa3bb8 100644 --- a/test/unit/locators/test_elementfinder.py +++ b/test/unit/locators/test_elementfinder.py @@ -12,6 +12,10 @@ def test_find_with_invalid_prefix(self): self.assertRaises(ValueError, finder.find, browser, "something=test1") except ValueError as e: self.assertEqual(e.message, "Element locator with prefix 'something' is not supported") + try: + self.assertRaises(ValueError, finder.find, browser, " by ID =test1") + except ValueError as e: + self.assertEqual(e.message, "Element locator with prefix ' by ID ' is not supported") def test_find_with_null_browser(self): finder = ElementFinder() @@ -36,6 +40,22 @@ def test_find_with_no_tag(self): finder.find(browser, "test1") verify(browser).find_elements_by_xpath("//*[(@id='test1' or @name='test1')]") + def test_find_with_explicit_default_strategy(self): + finder = ElementFinder() + browser = mock() + finder.find(browser, "default=test1") + verify(browser).find_elements_by_xpath("//*[(@id='test1' or @name='test1')]") + + def test_find_with_explicit_default_strategy_and_equals(self): + finder = ElementFinder() + browser = mock() + when(browser).get_current_url().thenReturn("http://localhost/mypage.html") + finder.find(browser, "default=page.do?foo=bar", tag='a') + verify(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 " + + "@href='http://localhost/page.do?foo=bar')]") + def test_find_with_tag(self): finder = ElementFinder() browser = mock() @@ -285,6 +305,7 @@ def test_find_with_sloppy_prefix(self): elements = self._make_mock_elements('div', 'a', 'span', 'a') when(browser).find_elements_by_id("test1").thenReturn(elements) + when(browser).find_elements_by_partial_link_text("test1").thenReturn(elements) result = finder.find(browser, "ID=test1") self.assertEqual(result, elements) @@ -294,6 +315,10 @@ def test_find_with_sloppy_prefix(self): self.assertEqual(result, elements) result = finder.find(browser, " id =test1") self.assertEqual(result, elements) + result = finder.find(browser, " partiallink =test1") + self.assertEqual(result, elements) + result = finder.find(browser, " p art iallin k =test1") + self.assertEqual(result, elements) def test_find_with_sloppy_criteria(self): finder = ElementFinder() From fab080ca225ff58507deabc0eb5ee1421f087fa1 Mon Sep 17 00:00:00 2001 From: Kevin Ormbrek Date: Wed, 1 Oct 2014 20:18:14 -0500 Subject: [PATCH 2/5] fix unit test for bad prefixes --- test/unit/locators/test_elementfinder.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/unit/locators/test_elementfinder.py b/test/unit/locators/test_elementfinder.py index 937aa3bb8..28505f1d1 100644 --- a/test/unit/locators/test_elementfinder.py +++ b/test/unit/locators/test_elementfinder.py @@ -2,20 +2,17 @@ import os from Selenium2Library.locators import ElementFinder from mockito import * +from robot.utils.asserts import assert_raises_with_msg class ElementFinderTests(unittest.TestCase): def test_find_with_invalid_prefix(self): finder = ElementFinder() browser = mock() - try: - self.assertRaises(ValueError, finder.find, browser, "something=test1") - except ValueError as e: - self.assertEqual(e.message, "Element locator with prefix 'something' is not supported") - try: - self.assertRaises(ValueError, finder.find, browser, " by ID =test1") - except ValueError as e: - self.assertEqual(e.message, "Element locator with prefix ' by ID ' is not supported") + assert_raises_with_msg(ValueError, "Element locator with prefix 'something' is not supported", + finder.find, browser, "something=test1") + assert_raises_with_msg(ValueError, "Element locator with prefix ' by ID ' is not supported", + finder.find, browser, " by ID =test1") def test_find_with_null_browser(self): finder = ElementFinder() From cde1d837f46e06d43cdaad58d5c97f6db44af02b Mon Sep 17 00:00:00 2001 From: Kevin Ormbrek Date: Thu, 2 Oct 2014 21:06:50 -0500 Subject: [PATCH 3/5] improve doc for default locator prefix --- src/Selenium2Library/__init__.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Selenium2Library/__init__.py b/src/Selenium2Library/__init__.py index b97381941..44dbe545b 100644 --- a/src/Selenium2Library/__init__.py +++ b/src/Selenium2Library/__init__.py @@ -60,7 +60,14 @@ class Selenium2Library( | jquery | Click Element `|` jquery=div.my_class | Matches by jQuery/sizzle selector | | sizzle | Click Element `|` sizzle=div.my_class | Matches by jQuery/sizzle selector | | tag | Click Element `|` tag=div | Matches by HTML tag name | - | default | Click Link `|` default=page?a=b | Matches key attributes with value after first '=' | + | default* | Click Link `|` default=page?a=b | Matches key attributes with value after first '=' | + * Explicitly specifying the default strategy is only necessary if locating + elements by matching key attributes is desired and an attribute value + contains a '='. The following would fail because it appears as if _page?a_ + is the locator prefix: + | Click Link page?a=b + This can be fixed by changing the locator to: + | Click Link default=page?a=b Table related keywords, such as `Table Should Contain`, work differently. By default, when a table locator value is provided, it will search for From 53ed907bcb313f065b71fcfa2c730b02a5ff2e6a Mon Sep 17 00:00:00 2001 From: Kevin Ormbrek Date: Thu, 2 Oct 2014 21:14:13 -0500 Subject: [PATCH 4/5] fixes #200 Totally unrelated change I know. --- src/Selenium2Library/keywords/_element.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Selenium2Library/keywords/_element.py b/src/Selenium2Library/keywords/_element.py index bc1f405c6..bfe9b0d6b 100644 --- a/src/Selenium2Library/keywords/_element.py +++ b/src/Selenium2Library/keywords/_element.py @@ -436,11 +436,11 @@ def press_key(self, locator, key): """Simulates user pressing key on element identified by `locator`. `key` is either a single character, or a numerical ASCII code of the key - lead by '\\'. + lead by '\\'. In test data, '\\' must be escaped, so use '\\\\'. Examples: | Press Key | text_field | q | - | Press Key | login_button | \\13 | # ASCII code for enter key | + | Press Key | login_button | \\\\13 | # ASCII code for enter key | """ if key.startswith('\\') and len(key) > 1: key = self._map_ascii_key_code_to_key(int(key[1:])) From a7f1d0ddef548dd57f8b8519932e5ea1b08c72c6 Mon Sep 17 00:00:00 2001 From: Kevin Ormbrek Date: Thu, 2 Oct 2014 21:38:49 -0500 Subject: [PATCH 5/5] typo in default strategy doc --- src/Selenium2Library/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Selenium2Library/__init__.py b/src/Selenium2Library/__init__.py index 44dbe545b..2aff8ec88 100644 --- a/src/Selenium2Library/__init__.py +++ b/src/Selenium2Library/__init__.py @@ -64,7 +64,7 @@ class Selenium2Library( * Explicitly specifying the default strategy is only necessary if locating elements by matching key attributes is desired and an attribute value contains a '='. The following would fail because it appears as if _page?a_ - is the locator prefix: + is the specified lookup strategy: | Click Link page?a=b This can be fixed by changing the locator to: | Click Link default=page?a=b