Source code for macaca.webelement

#
# https = //w3c.github.io/webdriver/webdriver-spec.html
# WebDriver Element Implemenation
#

from base64 import b64decode

from retrying import retry

from .asserters import is_displayed
from .command import Command
from .locator import Locator
from .util import add_element_extension_method, value_to_key_strokes, value_to_single_key_strokes, fluent
from .webdriverexception import WebDriverException


[docs]class WebElement(object): """The WebElement Object to implement most part of WebDriver protocol. Attributes: element_id(str): A UDID used to uniquely identify an element. """ def __init__(self, element_id, driver): """Initialize the WebElement Args: element_id(str): The UDID returned by remote servers. driver(WebDriver): The WebDriver Object. """ self.element_id = str(element_id) self._driver = driver def __repr__(self): return '<{0.__name__} (session="{1}", element="{2}")>'.format( type(self), self._driver.session_id, self.element_id) def __eq__(self, el): return hasattr(el, 'element_id') and self.element_id == el.element_id def __ne__(self, el): return not self.__eq__(el) def __hash__(self): return hash(self.element_id) def _execute(self, command, data=None, unpack=True): """Private method to execute command with data. Args: command(Command): The defined command. data(dict): The uri variable and body. Returns: The unwrapped value field in the json response. """ if not data: data = {} data.setdefault('element_id', self.element_id) return self._driver._execute(command, data, unpack) @property def driver(self): """Internal reference to the WebDriver instance.""" return self._driver
[docs] def element(self, using, value): """find an element in the current element. Support: Android iOS Web(WebView) Args: using(str): The element location strategy. value(str): The value of the location strategy. Returns: WebElement Object. Raises: WebDriverException. """ return self._execute(Command.FIND_CHILD_ELEMENT, { 'using': using, 'value': value })
[docs] def element_if_exists(self, using, value): """Check if an element in the current element. Support: Android iOS Web(WebView) Args: using(str): The element location strategy. value(str): The value of the location strategy. Returns: Return True if the element does exists and return False otherwise. Raises: WebDriverException. """ try: self._execute(Command.FIND_CHILD_ELEMENT, { 'using': using, 'value': value }) return True except: return False
[docs] def element_or_none(self, using, value): """Check if an element in the current element. Support: Android iOS Web(WebView) Args: using(str): The element location strategy. value(str): The value of the location strategy. Returns: Return Element if the element does exists and return None otherwise. Raises: WebDriverException. """ try: return self._execute(Command.FIND_CHILD_ELEMENT, { 'using': using, 'value': value }) except: return None
[docs] def elements(self, using, value): """find elements in the current element. Support: Android iOS Web(WebView) Args: using(str): The element location strategy. value(str): The value of the location strategy. Returns: Return a List<Element | None>, if no element matched, the list is empty. Raises: WebDriverException. """ return self._execute(Command.FIND_CHILD_ELEMENTS, { 'using': using, 'value': value })
[docs] def wait_for( self, timeout=10000, interval=1000, asserter=lambda x: x): """Wait for element till given condition Support: Android iOS Web(WebView) Args: timeout(int): How long we should be retrying stuff. interval(int): How long between retries. asserter(callable): The asserter func to determine the result. Returns: Return the Element. Raises: WebDriverException. """ if not callable(asserter): raise TypeError('Asserter must be callable.') @retry( retry_on_exception=lambda ex: isinstance(ex, WebDriverException), stop_max_delay=timeout, wait_fixed=interval ) def _wait_for(el): asserter(el) return el return _wait_for(self)
[docs] def wait_for_element( self, using, value, timeout=10000, interval=1000, asserter=is_displayed): """Wait for element till the given condition Support: Android iOS Web(WebView) Args: using(str): The element location strategy. value(str): The value of the location strategy. timeout(int): How long we should be retrying stuff. interval(int): How long between retries. asserter(callable): The asserter func to determine the result. Returns: Return the Element. Raises: WebDriverException. """ if not callable(asserter): raise TypeError('Asserter must be callable.') @retry( retry_on_exception=lambda ex: isinstance(ex, WebDriverException), stop_max_delay=timeout, wait_fixed=interval ) def _wait_for_element(ctx, using, value): el = ctx.element(using, value) asserter(el) return el return _wait_for_element(self, using, value)
[docs] def wait_for_elements( self, using, value, timeout=10000, interval=1000, asserter=is_displayed): """Wait for elements till the given condition Support: Android iOS Web(WebView) Args: using(str): The element location strategy. value(str): The value of the location strategy. timeout(int): How long we should be retrying stuff. interval(int): How long between retries. asserter(callable): The asserter func to determine the result. Returns: Return the list of Element if any of them satisfy the condition. Raises: WebDriverException. """ if not callable(asserter): raise TypeError('Asserter must be callable.') @retry( retry_on_exception=lambda ex: isinstance(ex, WebDriverException), stop_max_delay=timeout, wait_fixed=interval ) def _wait_for_elements(ctx, using, value): els = ctx.elements(using, value) if not len(els): raise WebDriverException('no such element') else: el = els[0] asserter(el) return els return _wait_for_elements(self, using, value)
[docs] def is_displayed(self): """Whether the element is visible. Support: Android Web(WebView) """ return self._execute(Command.IS_ELEMENT_DISPLAYED)
[docs] def is_selected(self): """Returns whether the element is selected. Support: Web(WebView) """ return self._execute(Command.IS_ELEMENT_SELECTED)
[docs] def is_enabled(self): """Returns whether the element is enabled. Support: Web(WebView) """ return self._execute(Command.IS_ELEMENT_ENABLED)
[docs] def get_property(self, name): """Return the result of getting a property, Support: Android iOS Web(WebView). Support: Support: Android iOS Web(WebView) Args: name(str): Name of the property to retrieve, Android iOS can only get `origin` `size`. Returns: The property of the element. """ return self._execute(Command.GET_ELEMENT_PROPERTY, {'name': name})
[docs] def get_computed_css(self, property_name): """The computed value of the given CSS property of the given web element. Support: Support: Web(WebView) Args: property_name(str): CSS property. Returns: The computed value of parameter property name from element's style declarations if the current browsing context's document type is not "xml", else let it be "" """ return self._execute(Command.GET_ELEMENT_VALUE_OF_CSS_PROPERTY, { 'property_name': property_name})
@property def text(self): """Return the text of the element. This is equivalent to calling element.innerText. Support: Android iOS Web(WebView) """ return self._execute(Command.GET_ELEMENT_TEXT) @property def tag_name(self): """Return the tagName of the element. Support: Web(WebView) """ return self._execute(Command.GET_ELEMENT_TAG_NAME) @property def rect(self): """The dimensions and coordinates of the given web element in pixels. Support: Android iOS Web(WebView) Returns: A dict contains: x(float): X axis position of the top-left corner. y(float): Y axis position of the top-left corner. height(float): Height of the web element's bounding rectangle. width(float): Width of the web element's bounding rectangle. """ return self._execute(Command.GET_ELEMENT_RECT) @property def size(self): """The size of the given web element in pixels. Support: Web(WebView) Returns: A dict contains: height(float): Height of the web element's bounding rectangle. width(float): Width of the web element's bounding rectangle. """ return self._execute(Command.GET_ELEMENT_SIZE)
[docs] @fluent def click(self): """The Element Click command scrolls into view the element and then attempts to click the centre of the visible area of the first element of the DOMRect sequence. In case the element is not displayed, an element not visible error is returned. Support: Android iOS Web(WebView) """ self._execute(Command.CLICK_ELEMENT)
[docs] @fluent def clear(self): """The Element Clear command scrolls into view a submittable element excluding buttons or editable element, and then attempts to clear its value, checkedness, or text content. Support: Android iOS Web(WebView) """ self._execute(Command.CLEAR_ELEMENT)
[docs] @fluent def keys(self, value): """Send a sequence of key strokes to an element. Support: Android iOS Web(WebView) Args: value(str|int|list): value can be a string, int or a list contains defined Keys. """ self._execute(Command.SEND_KEYS_TO_ELEMENT, { 'value': value_to_single_key_strokes(value)})
[docs] @fluent def send_keys(self, value): """Send a sequence of key strokes to an element. Support: Android iOS Web(WebView) Args: value(str|int|list): value can be a string, int or a list contains defined Keys. """ self._execute(Command.SEND_KEYS_TO_ELEMENT, { 'value': value_to_key_strokes(value)})
[docs] @fluent def move_to(self, x=0, y=0): """Deprecated use element.touch('drag', { toX, toY, duration(s) }) instead. Move the mouse by an offset of the specificed element. Support: Android Args: x(float): X offset to move to, relative to the top-left corner of the element. y(float): Y offset to move to, relative to the top-left corner of the element. Returns: WebElement object. """ self._driver.move_to(self, x, y)
[docs] @fluent def flick(self, x, y, speed): """Deprecated use touch('drag', { fromX, fromY, toX, toY, duration(s) }) instead. Flick on the touch screen using finger motion events. This flickcommand starts at a particulat screen location. Support: iOS Args: x(float}: The x offset in pixels to flick by. y(float): The y offset in pixels to flick by. speed(float) The speed in pixels per seconds. Returns: WebElement object. """ self._driver.flick(self, x, y, speed)
[docs] @fluent def tap(self): """Deprecated use touch('tap') instead. Single tap on the touch enabled device. Support: Android iOS Args: element(WebElement): WebElement Object to single tap on. Returns: WebElement object. """ self._driver.tap(self)
[docs] def take_screenshot(self): """Gets the screenshot of the current element as a base64 encoded string. Support: Android iOS Web(WebView) Returns: Base64 encoded string of the screenshot. """ return self._execute(Command.ELEMENT_SCREENSHOT)
[docs] @fluent def save_screenshot(self, filename, quietly = False): """Save the screenshot to local. Support: Android iOS Web(WebView) Args: filename(str): The path to save the image. quietly(bool): If True, omit the IOError when failed to save the image. Returns: WebElement Object. Raises: WebDriverException. IOError. """ imgData = self.take_screenshot() try: with open(filename, "wb") as f: f.write(b64decode(imgData.encode('ascii'))) except IOError as err: if not quietly: raise err
[docs] @fluent def touch(self, name, args=None): """Apply touch actions on devices. Such as, tap/doubleTap/press/pinch/rotate/drag. See more on https://github.com/alibaba/macaca/issues/366. Support: Android iOS Args: name(str): Name of the action args(dict): Arguments of the action Returns: WebDriver Object. Raises: WebDriverException. """ if isinstance(name, list) and not isinstance(name, str): for obj in name: obj['element'] = self.element_id actions = name elif isinstance(name, str): if not args: args = {} args['type'] = name args['element'] = self.element_id actions = [args] else: raise TypeError('Invalid parameters.') self._driver._execute(Command.PERFORM_ACTIONS, { 'actions': actions })
add_element_extension_method(WebElement)