Source code for nerodia.elements.select

import re

import six

import nerodia
from nerodia.exception import Error, NoValueFoundException, ObjectDisabledException, \
    UnknownObjectException
from nerodia.wait.wait import TimeoutError
from .html_elements import HTMLElement
from ..meta_elements import MetaHTMLElement
from ..wait.wait import Wait

try:
    from re import Pattern
except ImportError:
    from re import _pattern_type as Pattern


[docs]@six.add_metaclass(MetaHTMLElement) class Select(HTMLElement):
[docs] def clear(self): """ Clears all selected options """ if not self.multiple: raise Error('you can only clear multi-selects') for option in self.selected_options: option.click()
[docs] def includes(self, term): """ Returns True if the select list has at least one option where text or label matches the given value :param term: string or regex to match against the option :rtype: bool """ return self.option(text=term).exists or self.option(label=term).exists
[docs] def select(self, *terms): """ Select the option whose text or label matches the given string If this is a multi-select and several options match the value given, all will be selected :param terms: string or regex or list to match against the option :return: The text of the option selected. If multiple options match, returns the first match :rtype: str """ return [self._select_by(t) for t in self._flatten(terms)][0]
[docs] def select_all(self, *terms): """ Select all the options whose text or label matches the given string If this is a multi-select and several options match the value given, all will be selected :param term: string or regex or list to match against the option :return: The text of the first option selected. :rtype: str """ return [self._select_all_by(t) for t in self._flatten(terms)][0]
[docs] def js_select(self, *terms): """ Uses JavaScript to select the option whose text matches the given string. :param term: string or regex or list to match against the option """ return [self._js_select_by(t, 'single') for t in self._flatten(terms)][0]
[docs] def js_select_all(self, *terms): """ Uses JavaScript to select all options whose text matches the given string. :param term: string or regex or list to match against the option """ return [self._js_select_by(t, 'multiple') for t in self._flatten(terms)][0]
[docs] def select_value(self, value): """ Selects the option(s) whose value attribute matches the given string If this is a multi-select and several options match the value given, all will be selected :param value: string or regex to match against the option """ nerodia.logger.deprecate('#select_value', '#select', ids=['select_value']) return self._select_by(value)
[docs] def js_select_value(self, value): """ Uses JavaScript to select the option whose value attribute matches the given string :param value: string or regex to match against the option """ return self._js_select_by(value, 'single')
[docs] def is_selected(self, term): """ Returns True if any of the selected options' text or label matches the given value :param term: string or regex to match against the option :rtype: bool :raises: UnknownObjectException """ by_text = self.options(text=term) if any(option.is_selected for option in by_text): return True by_label = self.options(label=term) if any(option.is_selected for option in by_label): return True if len(by_text) + len(by_label) != 0: return False raise UnknownObjectException('Unable to locate option matching {}'.format(term))
@property def value(self): """ Returns the value of the first selected option in the select list Returns None if no option is selected :rtype: str or None """ selected = self.selected_options return selected[0].value if selected else None @property def text(self): # Returns the text of the first selected option in the select list # Returns nil if no option is selected # :rtype: str or None selected = self.selected_options return selected[0].text if selected else None @property def selected_options(self): """ Returns an array of currently selected options :rtype: list[nerodia.elements.option.Option] """ return self._element_call(lambda: self._execute_js('selectedOptions', self)) # private def _select_by(self, term): found = self._find_options('value', term) if len(found) > 1: nerodia.logger.deprecate('Selecting Multiple Options with #select', '#select_all', ids=['select_by']) return self._select_matching(found) def _js_select_by(self, term, number): if isinstance(term, Pattern): js_rx = term.pattern js_rx = js_rx.replace('\\A', '^', 1) js_rx = js_rx.replace('\\Z', '$', 1) js_rx = js_rx.replace('\\z', '$', 1) js_rx = re.sub(r'\(\?#.+\)', '', js_rx) js_rx = re.sub(r'\(\?-\w+:', '(', js_rx) elif type(term) in [six.text_type, six.binary_type]: js_rx = '^{}$'.format(term) else: raise TypeError('expected String or Regexp, got {}'.format(term)) for way in ['text', 'label', 'value']: self._element_call(lambda: self._execute_js('selectOptions{}'.format(way.capitalize()), self, js_rx, str(number))) if self._is_matching_option(way, term): return self.selected_options[0].text self._raise_no_value_found(term) def _is_matching_option(self, how, what): for opt in self.selected_options: value = getattr(opt, how) if (type(what) in [six.text_type, six.binary_type] and value == what) or \ (type(what) not in [six.text_type, six.binary_type] and re.search(what, value)): if opt.enabled: return True raise ObjectDisabledException('option matching {} by {} on {}' ' is disabled'.format(what, how, self)) def _select_all_by(self, term): if not self.multiple: raise Error('you can only use #select_all on multi-selects') found = self._find_options('text', term) return self._select_matching(found) def _find_options(self, how, term): types = [six.text_type, six.binary_type, int, Pattern] found = [] def func(sel): if type(term) in types: collection = sel.options(value=term) if how == 'value' else [] if not list(collection): collection = sel.options(text=term) if not list(collection): collection = sel.options(label=term) if collection: found.append(collection) return False else: return not found and nerodia.relaxed_locate else: raise TypeError('expected {!r}, got {}:{}'.format(types, term, term.__class__)) try: Wait.until_not(func, object=self) if found: return found[0] self._raise_no_value_found(term) except TimeoutError: self._raise_no_value_found(term) def _raise_no_value_found(self, term): raise NoValueFoundException('{} not found in {}'.format(term, self)) def _select_matching(self, elements): if not self.multiple: elements = elements[:1] for element in elements: if not element.is_selected: element.click() return '' if elements[0].stale else elements[0].text