diff --git a/src/Selenium2Library/keywords/element.py b/src/Selenium2Library/keywords/element.py index b1f92c031..95aa5c646 100644 --- a/src/Selenium2Library/keywords/element.py +++ b/src/Selenium2Library/keywords/element.py @@ -3,7 +3,6 @@ from Selenium2Library.base import LibraryComponent, keyword from Selenium2Library.keywords.formelement import FormElementKeywords -from Selenium2Library.locators.customlocator import CustomLocator from Selenium2Library.utils import escape_xpath_value @@ -716,16 +715,18 @@ def xpath_should_match_x_times(self, xpath, expected_xpath_count, message='', lo @keyword def add_location_strategy(self, strategy_name, strategy_keyword, persist=False): - """Adds a custom location strategy based on a user keyword. Location strategies are - automatically removed after leaving the current scope by default. Setting `persist` - to any non-empty string will cause the location strategy to stay registered throughout - the life of the test. + """Adds a custom location strategy based on a keyword. - Trying to add a custom location strategy with the same name as one that already exists will - cause the keyword to fail. + Location strategies are automatically removed after leaving the current + scope by default. Setting `persist` to Python True will cause the + location strategy to stay registered throughout the life of the test. + + Trying to add a custom location strategy with the same name as one that + already exists will cause the keyword to fail. Custom locator keyword example: - | Custom Locator Strategy | [Arguments] | ${browser} | ${criteria} | ${tag} | ${constraints} | + | Custom Locator Strategy | + | | [Arguments] | ${browser} | ${criteria} | ${tag} | ${constraints} | | | ${retVal}= | Execute Javascript | return window.document.getElementById('${criteria}'); | | | [Return] | ${retVal} | @@ -733,14 +734,15 @@ def add_location_strategy(self, strategy_name, strategy_keyword, persist=False): | Add Location Strategy | custom | Custom Locator Strategy | | Page Should Contain Element | custom=my_id | - See `Remove Location Strategy` for details about removing a custom location strategy. + See `Remove Location Strategy` for details about removing a custom + location strategy. """ - strategy = CustomLocator(strategy_name, strategy_keyword) - self.element_finder.register(strategy, persist) + self.element_finder.register(strategy_name, strategy_keyword, persist) @keyword def remove_location_strategy(self, strategy_name): """Removes a previously added custom location strategy. + Will fail if a default strategy is specified. See `Add Location Strategy` for details about adding a custom location strategy. diff --git a/src/Selenium2Library/locators/customlocator.py b/src/Selenium2Library/locators/customlocator.py index fdf2c716e..6b5cd5b20 100644 --- a/src/Selenium2Library/locators/customlocator.py +++ b/src/Selenium2Library/locators/customlocator.py @@ -1,5 +1,7 @@ from robot.libraries.BuiltIn import BuiltIn +from Selenium2Library.base import ContextAware + try: basestring @@ -7,23 +9,26 @@ basestring = str -class CustomLocator(object): +class CustomLocator(ContextAware): - def __init__(self, name, finder): + def __init__(self, ctx, name, finder): + ContextAware.__init__(self, ctx) self.name = name self.finder = finder - def find(self, *args): + def find(self, criteria, tag, constraints): # Allow custom locators to be keywords or normal methods if isinstance(self.finder, basestring): - element = BuiltIn().run_keyword(self.finder, *args) + element = BuiltIn().run_keyword(self.finder, self.browser, + criteria, tag, constraints) elif hasattr(self.finder, '__call__'): - element = self.finder(*args) + element = self.finder(self.browser, criteria, tag, constraints) else: - raise AttributeError('Invalid type provided for Custom Locator %s' % self.name) + raise AttributeError('Invalid type provided for Custom Locator %s' + % self.name) # Always return an array - if hasattr(element, '__len__') and (not isinstance(element, basestring)): + if hasattr(element, '__len__') and not isinstance(element, basestring): return element else: return [element] diff --git a/src/Selenium2Library/locators/elementfinder.py b/src/Selenium2Library/locators/elementfinder.py index 94639e783..4413265c9 100644 --- a/src/Selenium2Library/locators/elementfinder.py +++ b/src/Selenium2Library/locators/elementfinder.py @@ -3,6 +3,7 @@ from selenium.webdriver.remote.webelement import WebElement from Selenium2Library.base import ContextAware +from Selenium2Library.locators.customlocator import CustomLocator from Selenium2Library.utils import escape_xpath_value, events @@ -89,13 +90,13 @@ def get_value(self, locator, tag=None): element = self.find(locator, tag, required=False) return element.get_attribute('value') if element else None - def register(self, strategy, persist): + def register(self, strategy_name, strategy_keyword, persist=False): + strategy = CustomLocator(self.ctx, strategy_name, strategy_keyword) if strategy.name in self._strategies: raise RuntimeError("The custom locator '%s' cannot be registered. " "A locator of that name already exists." % strategy.name) self._strategies[strategy.name] = strategy.find - if not persist: # Unregister after current scope ends events.on('scope_end', 'current', self.unregister, strategy.name) diff --git a/src/Selenium2Library/utils/events/scope_event.py b/src/Selenium2Library/utils/events/scope_event.py index 3746d0c40..2352ff995 100644 --- a/src/Selenium2Library/utils/events/scope_event.py +++ b/src/Selenium2Library/utils/events/scope_event.py @@ -13,7 +13,7 @@ def __init__(self, scope, action, *args, **kwargs): if scope == 'current': suite = BuiltIn().get_variable_value('${SUITE NAME}') - test = BuiltIn().get_variable_value('${TEST NAME}', '') + test = BuiltIn().get_variable_value('${TEST NAME}', '') self.scope = suite + '.' + test if test != '' else suite def trigger(self, *args, **kwargs): diff --git a/test/acceptance/locators/custom.robot b/test/acceptance/locators/custom.robot index 4e65b3a4d..350a5c415 100644 --- a/test/acceptance/locators/custom.robot +++ b/test/acceptance/locators/custom.robot @@ -5,7 +5,6 @@ Resource ../resource.robot *** Test Cases *** Test Custom Locator - [Documentation] Test Custom Locator [Setup] Setup Custom Locator Page Should Contain Element custom=some_id Page Should Not Contain Element custom=invalid_id @@ -17,22 +16,18 @@ Ensure Locator Auto Unregisters Setup Custom Locator Ensure Attempting to Unregister a Default Locator Fails - [Documentation] Ensure Attempting to Unregister a Default Locator Fails Run Keyword And Expect Error * Remove Location Strategy id Ensure Unregistering a Non-Existent Locator Does Not Fail - [Documentation] Ensure Unregistering a Non-Existent Locator Does Not Fail Teardown Custom Locator Ensure a Custom Locator can be Unregistered - [Documentation] Ensure a Custom Locator can be Unregistered Setup Custom Locator persist Teardown Custom Locator # Test step is used for the next test. It sets up a persistant locator. Setup Custom Locator persist Ensure Locators Can Persist - [Documentation] Ensure Locators Can Persist Page Should Contain Element custom=some_id Run Keyword And Expect Error * Setup Custom Locator [Teardown] Teardown Custom Locator @@ -40,15 +35,12 @@ Ensure Locators Can Persist *** Keywords *** Setup Custom Locator [Arguments] ${persist}=${EMPTY} - [Documentation] Setup Custom Locator Add Location Strategy custom Custom Locator Strategy persist=${persist} Teardown Custom Locator - [Documentation] Teardown Custom Locator Remove Location Strategy custom Custom Locator Strategy - [Arguments] ${criteria} ${tag} ${constraints} - [Documentation] Custom Locator Strategy - ${retVal}= Execute Javascript return window.document.getElementById('${criteria}') || []; - [Return] ${retVal} + [Arguments] ${browser} ${locator} ${tag} ${constraints} + ${element}= Execute Javascript return window.document.getElementById('${locator}') || []; + [Return] ${element}