Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions src/SeleniumLibrary/locators/elementfinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,7 @@ def find(self, locator, tag=None, first_only=True, required=True):
if isinstance(locator, WebElement):
return locator
prefix, criteria = self._parse_locator(locator)
if prefix not in self._strategies:
raise ValueError("Element locator with prefix '%s' "
"is not supported." % prefix)
strategy = self._strategies.get(prefix)
strategy = self._strategies[prefix]
tag, constraints = self._get_tag_and_constraints(tag)
elements = strategy(criteria, tag, constraints)
if required and not elements:
Expand Down Expand Up @@ -124,9 +121,6 @@ def unregister(self, strategy_name):
else:
del self._strategies[strategy_name]

def has_strategy(self, strategy_name):
return strategy_name in self.strategies

def _find_by_identifier(self, criteria, tag, constraints):
elements = self._normalize_result(
self.browser.find_elements_by_id(criteria))
Expand Down Expand Up @@ -257,10 +251,19 @@ def _get_tag_and_constraints(self, tag):
def _parse_locator(self, locator):
if locator.startswith(('//', '(//')):
return 'xpath', locator
index = self._get_locator_separator_index(locator)
if index != -1:
prefix = locator[:index].strip()
if prefix in self._strategies:
return prefix, locator[index+1:].lstrip()
return 'default', locator

def _get_locator_separator_index(self, locator):
if '=' not in locator:
return 'default', locator
prefix, criteria = locator.split('=', 1)
return prefix.strip(), criteria.lstrip()
return locator.find(':')
if ':' not in locator:
return locator.find('=')
return min(locator.find('='), locator.find(':'))

def _element_matches(self, element, tag, constraints):
if not element.tag_name.lower() == tag:
Expand Down
37 changes: 37 additions & 0 deletions test/acceptance/locators/locator_parsing.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
*** Settings ***
Documentation Tests different supported xpath strategies
Test Setup Go To Page "links.html"
Resource ../resource.robot

*** Test Cases ***
xpath with prefix should work
Page Should Contain Element xpath=//div[@id="div_id"]/a
Page Should Contain Element xpath://div[@id="div_id"]/a

xpath with // and without prefix should work
Page Should Contain Element //div[@id="div_id"]/a

xpath with (// and without prefix should work
Page Should Contain Element (//div[@id="div_id"]/a)[1]

Locator without prefix
Page Should Contain Element div_id

Locator with prefix
Page Should Contain Element id:div_id
Page Should Contain Element id=div_id
Page Should Contain Element id:foo:bar
Page Should Contain Element id=foo:bar
Page Should Contain Element id:bar=foo
Page Should Contain Element id=bar=foo

Locator with separator but without matching prefix is not special
Page Should Contain Element foo:bar
Page Should Contain Element bar=foo

Locator with separator and with matchign prefix cannot be used as-is
Page Should Contain Element id:id:problematic
Page Should Contain Element id=id:problematic
Run Keyword And Expect Error
... Page should have contained element 'id:problematic' but did not
... Page Should Contain Element id:problematic
14 changes: 0 additions & 14 deletions test/acceptance/locators/xpath.robot

This file was deleted.

12 changes: 6 additions & 6 deletions test/resources/html/links.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
<a href="index.html">Link with asterisk * and another *</a><br/>
<a href="index.html">Link with Unicode äöüÄÖÜß</a>
</div>
<div>
<a href="target/second.html">
Link with whitespace
<div id="foo:bar">
<a id="bar=foo" href="target/second.html">
Link with whitespace
</a><br/>
<a href="target/third.html">
Link with
whitespace within
<a id="id:problematic" href="target/third.html">
Link with
whitespace within
</a><br/>
<a href="target/first.html" id="bold_id"><b>Link with bolded text</b></a>
</div>
Expand Down
52 changes: 52 additions & 0 deletions test/unit/locators/test_elementfinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,58 @@
from SeleniumLibrary.locators.elementfinder import ElementFinder


class ParseLocatorTests(unittest.TestCase):

def setUp(self):
self.finder = ElementFinder(None)

def test_implicit_xpath(self):
self._verify_parse_locator('//foo', 'xpath', '//foo')
self._verify_parse_locator('(//foo)', 'xpath', '(//foo)')
self._verify_parse_locator('//id=bar', 'xpath', '//id=bar')

def test_no_separator(self):
self._verify_parse_locator('foo', 'default', 'foo')
self._verify_parse_locator('', 'default', '')

def test_equal_sign_as_separator(self):
self._verify_parse_locator('class=foo', 'class', 'foo')
self._verify_parse_locator('id=foo=bar', 'id', 'foo=bar')

def test_colon_as_separator(self):
self._verify_parse_locator('class:foo', 'class', 'foo')
self._verify_parse_locator('id:foo:bar', 'id', 'foo:bar')

def test_use_first_separator_when_both_are_used(self):
self._verify_parse_locator('id:foo=bar', 'id', 'foo=bar')
self._verify_parse_locator('id=foo:bar', 'id', 'foo:bar')

def test_preserve_trailing_whitespace(self):
self._verify_parse_locator('//foo/bar ', 'xpath', '//foo/bar ')
self._verify_parse_locator('class=foo ', 'class', 'foo ')

def test_remove_whitespace_around_prefix_and_separator(self):
self._verify_parse_locator('class = foo', 'class', 'foo')
self._verify_parse_locator('class : foo', 'class', 'foo')
self._verify_parse_locator(' id = foo = bar ', 'id', 'foo = bar ')
self._verify_parse_locator(' id : foo : bar ', 'id', 'foo : bar ')

def test_separator_without_matching_prefix_is_ignored(self):
self._verify_parse_locator('no=match', 'default', 'no=match')
self._verify_parse_locator('no:match', 'default', 'no:match')

def test_registered_strategy_can_be_used_as_prefix(self):
self._verify_parse_locator('registered=no', 'default', 'registered=no')
self._verify_parse_locator('registered:no', 'default', 'registered:no')
self.finder.register('registered', lambda *args: None, persist=True)
self._verify_parse_locator('registered=yes!!', 'registered', 'yes!!')
self._verify_parse_locator('registered:yes!!', 'registered', 'yes!!')

def _verify_parse_locator(self, locator, prefix, criteria):
parse_locator = self.finder._parse_locator
self.assertEqual(parse_locator(locator), (prefix, criteria))


class ElementFinderTests(unittest.TestCase):

def setUp(self):
Expand Down
79 changes: 0 additions & 79 deletions test/unit/locators/test_locator_parser.py

This file was deleted.