Source code for webdriverwrapper.forms
# pylint: disable=unused-argument
from selenium.common.exceptions import WebDriverException, NoSuchElementException
from selenium.webdriver.common.keys import Keys
from webdriverwrapper.wrapper import _WebElementWrapper
from webdriverwrapper.exceptions import _create_exception_msg
__all__ = ('Form',)
[docs]class Form(_WebElementWrapper):
[docs] def fill_out_and_submit(self, data, prefix='', skip_reset=False):
"""
Calls :py:meth:`~.Form.fill_out` and then :py:meth:`.submit`.
"""
self.fill_out(data, prefix, skip_reset)
self.submit()
[docs] def fill_out(self, data, prefix='', skip_reset=False):
"""
Fill out ``data`` by dictionary (key is name attribute of inputs). You
can pass normal Pythonic data and don't have to care about how to use
API of WebDriver.
By ``prefix`` you can specify prefix of all name attributes. For example
you can have inputs called ``client.name`` and ``client.surname`` -
then you will pass to ``prefix`` string ``"client."`` and in dictionary
just ``"name"``.
Option ``skip_reset`` is for skipping reset, so it can go faster. For
example for multiple selects it calls ``deselect_all`` first, but it need
to for every option check if it is selected and it is very slow for
really big multiple selects. If you know that it is not filled, you can
skip it and safe in some cases up to one minute! Also same with text
inputs, but first is called ``clear``.
Example:
.. code-block:: python
driver.get_elm('formid').fill_out({
'name': 'Michael',
'surname': 'Horejsek',
'age': 24,
'enabled': True,
'multibox': ['value1', 'value2']
}, prefix='user_')
.. versionchanged:: 2.2
``turbo`` renamed to ``skip_reset`` and used also for common elements
like text inputs or textareas.
"""
for elm_name, value in data.items():
FormElement(self, prefix + elm_name).fill_out(value, skip_reset)
[docs] def submit(self):
"""
Try to find element with ID "[FORM_ID]_submit" and click on it. If no
element doesn't exists it will call default behaviour - submiting of
form by pressing enter.
"""
elm_name = '%s_submit' % self.get_attribute('id')
try:
self.click(elm_name)
except NoSuchElementException:
super(Form, self).submit()
[docs] def reset(self):
"""
Try to find element with ID "[FORM_ID]_reset" and click on it.
You should use it for forms where you have cleaning/reseting of data.
"""
elm_name = '%s_reset' % self.get_attribute('id')
self.click(elm_name)
class FormElement:
def __init__(self, form_elm, elm_name):
self.form_elm = form_elm
self.elm_name = elm_name
def convert_value(self, value):
if not isinstance(value, (list, tuple)):
return self._convert_value_to_string(value)
values = []
for item in value:
values.append(self._convert_value_to_string(item))
return values
# pylint: disable=no-self-use
def _convert_value_to_string(self, value):
if isinstance(value, bool):
value = int(value)
elif value is None:
value = ''
return str(value)
def fill_out(self, value, skip_reset):
tag_name, elm_type = self.analyze_element()
method_name = ('fill_%s_%s' % (tag_name, elm_type)).replace('-', '')
getattr(self, method_name, self.fill_common)(value, skip_reset)
def analyze_element(self):
elms = self.form_elm.get_elms(name=self.elm_name)
for elm in elms:
elm_type = elm.get_attribute('type')
if elm_type == 'hidden':
continue
return elm.tag_name, elm_type
raise NoSuchElementException(_create_exception_msg(name=self.elm_name))
def fill_input_checkbox(self, value, skip_reset=False):
if isinstance(value, (list, tuple)):
self.fill_input_checkbox_multiple(value)
self.fill_input_checkbox_single(value)
def fill_input_checkbox_single(self, value, skip_reset=False):
elm = self.form_elm.get_elm(xpath='//input[@type="checkbox"][@name="%s"]' % self.elm_name)
if bool(value) != elm.is_selected():
self._click_on_elm_or_his_ancestor(elm)
def fill_input_checkbox_multiple(self, value, skip_reset=False):
for item in value:
elm = self.form_elm.get_elm(xpath='//input[@type="checkbox"][@name="%s"][@value="%s"]' % (
self.elm_name,
self.convert_value(item),
))
self._click_on_elm_or_his_ancestor(elm)
def fill_input_radio(self, value, skip_reset=False):
elm = self.form_elm.get_elm(xpath='//input[@type="radio"][@name="%s"][@value="%s"]' % (
self.elm_name,
self.convert_value(value),
))
self._click_on_elm_or_his_ancestor(elm)
def fill_input_file(self, value, skip_reset=False):
elm = self.form_elm.get_elm(name=self.elm_name)
elm.send_keys(self.convert_value(value))
def fill_select_selectone(self, value, skip_reset=False):
select = self.form_elm.get_elm(name=self.elm_name)
select.select_by_value(self.convert_value(value))
def fill_select_selectmultiple(self, value, skip_reset=False):
if not isinstance(value, (list, tuple)):
value = [value]
select = self.form_elm.get_elm(name=self.elm_name)
if not skip_reset:
select.deselect_all()
for item in self.convert_value(value):
select.select_by_value(item)
def fill_common(self, value, skip_reset=False):
elm = self.form_elm.get_elm(name=self.elm_name)
if not skip_reset:
elm.clear()
elm.send_keys(self.convert_value(value))
elm.send_keys(Keys.TAB) # Send TAB for losing focus. (Trigger change events.)
@classmethod
def _click_on_elm_or_his_ancestor(cls, elm):
"""
For example Bootstrap wraps chboxes or radio button into label and hide
that element, so Selenium can't click on it.
"""
try:
elm.click()
except WebDriverException:
elm.click(xpath='ancestor::label')