diff --git a/splinter/driver/__init__.py b/splinter/driver/__init__.py index 4ca3622df..5cbab0a37 100644 --- a/splinter/driver/__init__.py +++ b/splinter/driver/__init__.py @@ -252,6 +252,32 @@ def find_option_by_text(self, text: str) -> ElementList: "%s doesn't support finding options by text." % self.driver_name, ) + def set_find_strategy(self, strategy): + """Change the strategy used by browser.find(). + + Arguments: + strategy (str): The strategy used for finding elements. Can be one of either: + 'css', 'name', 'xpath' + + Returns: + Browser: The current browser instance + """ + raise NotImplementedError(f"{self.driver_name} doesn't support set_find_strategy()") + + def find(self, locator): + """Find an element. + + The default strategy used is 'name'. To change the strategy, see: + browser.set_find_strategy() + + Arguments: + locator (str): The string used to locate an element. + + Returns: + The found element + """ + raise NotImplementedError(f"{self.driver_name} doesn't support find()") + def is_text_present(self, text: str, wait_time: Optional[int] = None) -> bool: """Check if a piece of text is on the page. diff --git a/splinter/driver/lxmldriver.py b/splinter/driver/lxmldriver.py index 4d42578e7..d642beb5b 100644 --- a/splinter/driver/lxmldriver.py +++ b/splinter/driver/lxmldriver.py @@ -3,6 +3,7 @@ # license that can be found in the LICENSE file. import re import time +import warnings from typing import Optional from urllib import parse @@ -40,6 +41,14 @@ def __init__( self.config = config or Config(user_agent=user_agent) + self._finder_methods = { + "name": self.find_by_name, + "xpath": self.find_by_xpath, + "css": self.find_by_css, + } + + self._finder_method = "name" + def __enter__(self): return self @@ -240,8 +249,25 @@ def find_by_name(self, name): query=query, ) + def set_find_strategy(self, strategy): + valid = self._finder_methods.get(strategy) + + if not valid: + raise ValueError(f"{strategy} is not a valid strategy.") + + self._finder_method = strategy + + return self + + def find(self, locator): + return self._finder_methods[self._finder_method](locator) + def fill(self, name, value): - self.find_by_name(name=name).first.fill(value) + warnings.warn( + f"browser.fill({name}, {value}) is deprecated. Use browser.find({name}).fill({value}) instead.", + FutureWarning, + ) + self.find(name).fill(value) def fill_form(self, field_values, form_id=None, name=None, ignore_missing=False): form = None @@ -283,12 +309,18 @@ def choose(self, name, value): self.find_by_name(name).first._control.value = value def check(self, name): - control = self.find_by_name(name).first._control - control.value = ["checked"] + warnings.warn( + f"browser.check({name}) is deprecated. Use browser.find({name}).check() instead.", + FutureWarning, + ) + self.find(name).first.check() def uncheck(self, name): - control = self.find_by_name(name).first._control - control.value = [] + warnings.warn( + f"browser.uncheck({name}) is deprecated. Use browser.find({name}).uncheck() instead.", + FutureWarning, + ) + self.find(name).first.uncheck() def attach_file(self, name, file_path): control = self.find_by_name(name).first._control @@ -462,6 +494,12 @@ def _get_parent_form(self): parent_form = next(self._control.iterancestors("form")) return self.parent._forms.setdefault(parent_form._name(), parent_form) + def check(self): + self._control.value = ["checked"] + + def uncheck(self): + self._control.value = [] + class LxmlOptionElement(LxmlElement): def __init__(self, control, parent): diff --git a/splinter/driver/webdriver/__init__.py b/splinter/driver/webdriver/__init__.py index 02edbd26c..f316f5d2f 100644 --- a/splinter/driver/webdriver/__init__.py +++ b/splinter/driver/webdriver/__init__.py @@ -5,6 +5,7 @@ import re import tempfile import time +import warnings from contextlib import contextmanager from typing import Optional @@ -292,6 +293,14 @@ def __init__(self, driver=None, wait_time=2): self._cookie_manager = CookieManager(self.driver) + self._finder_methods = { + "name": self.find_by_name, + "xpath": self.find_by_xpath, + "css": self.find_by_css, + } + + self._finder_method = "name" + def __enter__(self): return self @@ -526,9 +535,25 @@ def find_by_id(self, id, wait_time=None): # NOQA: A002 wait_time=wait_time, ) + def set_find_strategy(self, strategy): + valid = self._finder_methods.get(strategy) + + if not valid: + raise ValueError(f"{strategy} is not a valid strategy.") + + self._finder_method = strategy + + return self + + def find(self, locator): + return self._finder_methods[self._finder_method](locator) + def fill(self, name, value): - field = self.find_by_name(name).first - field.value = value + warnings.warn( + f"browser.fill({name}, {value}) is deprecated. Use browser.find({name}).fill({value}) instead.", + FutureWarning, + ) + self.find(name).fill(value) attach_file = fill @@ -567,11 +592,11 @@ def fill_form(self, field_values, form_id=None, name=None, ignore_missing=False) raise ElementDoesNotExist(e) def type(self, name, value, slowly=False): # NOQA: A003 - element = self.find_by_name(name).first._element - if slowly: - return TypeIterator(element, value) - element.send_keys(value) - return value + warnings.warn( + f"browser.type({name}, {value}) is deprecated. Use browser.find({name}).type({value}) instead.", + FutureWarning, + ) + return self.find(name).type(value, slowly) def choose(self, name, value): fields = self.find_by_name(name) @@ -580,10 +605,18 @@ def choose(self, name, value): field.click() def check(self, name): - self.find_by_name(name).first.check() + warnings.warn( + f"browser.check({name}) is deprecated. Use browser.find({name}).check() instead.", + FutureWarning, + ) + self.find(name).first.check() def uncheck(self, name): - self.find_by_name(name).first.uncheck() + warnings.warn( + f"browser.uncheck({name}) is deprecated. Use browser.find({name}).uncheck() instead.", + FutureWarning, + ) + self.find(name).first.uncheck() def screenshot(self, name="", suffix=".png", full=False, unique_file=True): filename = f"{name}{suffix}" diff --git a/splinter/driver/zopetestbrowser.py b/splinter/driver/zopetestbrowser.py index 0fee93c7b..f19c9b420 100644 --- a/splinter/driver/zopetestbrowser.py +++ b/splinter/driver/zopetestbrowser.py @@ -4,6 +4,7 @@ import mimetypes import re import time +import warnings from typing import Optional import lxml.html @@ -73,6 +74,14 @@ def __init__(self, wait_time=2, config: Optional[Config] = None): self.links = FindLinks(self) + self._finder_methods = { + "name": self.find_by_name, + "xpath": self.find_by_xpath, + "css": self.find_by_css, + } + + self._finder_method = "name" + def __enter__(self): return self @@ -215,8 +224,25 @@ def find_by_name(self, name): query=name, ) + def set_find_strategy(self, strategy): + valid = self._finder_methods.get(strategy) + + if not valid: + raise ValueError(f"{strategy} is not a valid strategy.") + + self._finder_method = strategy + + return self + + def find(self, locator): + return self._finder_methods[self._finder_method](locator) + def fill(self, name, value): - self.find_by_name(name=name).first._control.value = value + warnings.warn( + f"browser.fill({name}, {value}) is deprecated. Use browser.find({name}).fill({value}) instead.", + FutureWarning, + ) + self.find(name).fill(value) def fill_form(self, field_values, form_id=None, name=None, ignore_missing=False): form = self._browser @@ -247,12 +273,18 @@ def choose(self, name, value): control.value = [option for option in control.options if option == value] def check(self, name): - control = self._browser.getControl(name=name) - control.value = control.options + warnings.warn( + f"browser.check({name}) is deprecated. Use browser.find({name}).check() instead.", + FutureWarning, + ) + self.find(name).first.check() def uncheck(self, name): - control = self._browser.getControl(name=name) - control.value = [] + warnings.warn( + f"browser.uncheck({name}) is deprecated. Use browser.find({name}).uncheck() instead.", + FutureWarning, + ) + self.find(name).first.uncheck() def attach_file(self, name, file_path): filename = file_path.split("/")[-1] @@ -415,6 +447,12 @@ def fill(self, value): def select(self, value): self._control.value = [value] + def check(self): + self._control.value = self._control.options + + def uncheck(self): + self._control.value = [] + class ZopeTestBrowserOptionElement(ZopeTestBrowserElement): def __init__(self, control, parent):