Source code for aamras.driver.element

"""Element wrapper/decorator."""

from typing import cast, List, Optional

from selenium.webdriver.remote.webelement import WebElement

from ..util import LoggerMixin
from .traverser import Traverser, Traversable

class ElementTraverserMixin:
    _traverser: Traverser
    dom_root: Traversable

    @property
    def traverser(self) -> Traverser:
        if not hasattr(self, "_traverser") or not self._traverser:
            self._traverser = Traverser(self.dom_root)

        return self._traverser

    def elements(
            self,
            id_: Optional[str] = None,
            name: Optional[str] = None,
            class_: Optional[str] = None,
            tag: Optional[str] = None) -> "List[Element]":
        """Search DOM for elements matching provided criteria.

        See :meth:`Traverser.elements` for more documentation.

        :returns: List of Elements matching criteria
        """
        return list(map(
            Element,
            self.traverser.elements(id_, name, class_, tag)))

    def element(
            self,
            id_: Optional[str] = None,
            name: Optional[str] = None,
            class_: Optional[str] = None,
            tag: Optional[str] = None) -> "Element":
        """Search DOM for single element matching provided criteria.

        See :meth:`Traverser.element` for more documentation.

        :returns: Element matching criteria"""
        return Element(self.traverser.element(id_, name, class_, tag))

[docs]class Element(LoggerMixin, ElementTraverserMixin): """Wrapper for selenium WebElement.""" _element: WebElement def __init__(self, element: WebElement): self._element = element @property def dom_root(self): return self._element @property def tag(self) -> str: return cast(str, self._element.tag_name) @property def id(self) -> Optional[str]: return cast(Optional[str], self._element.get_attribute("id")) @property def class_(self) -> Optional[str]: return cast(Optional[str], self._element.get_attribute("class")) @property def name(self) -> Optional[str]: return cast(Optional[str], self._element.get_attribute("name")) @property def text(self) -> Optional[str]: return cast(Optional[str], self._element.text) @property def selected(self) -> bool: return bool(self._element.is_selected()) @property def enabled(self) -> bool: return bool(self._element.is_enabled()) @property def displayed(self) -> bool: return bool(self._element.is_displayed()) @property def description(self) -> str: params = { "id": self.id, "name": self.name, "class": self.class_ } attributes = " ".join( [f"{k}=\"{v}\"" for (k, v) in params.items() if v]) return f"<{self.tag}{attributes and ' '}{attributes}>" def __repr__(self): return self.description def __str__(self): return self.description def _log_basic_action(self, action: str) -> None: self.log.info(f"{action} element {self}")
[docs] def attribute(self, name: str) -> Optional[str]: return cast(Optional[str], self._element.get_attribute(name))
[docs] def clear(self) -> None: """Clear element's text, if present.""" self._log_basic_action("clear") self._element.clear()
[docs] def click(self) -> None: """Click the element.""" self._log_basic_action("click") self._element.click()
[docs] def submit(self) -> None: """Submit the element.""" self._log_basic_action("submit") self._element.submit()
[docs] def type(self, text: Optional[str]) -> None: """Send text input to the element.""" self.log.info(f"type '{text}' to element {self}") self._element.send_keys(text)
[docs] def screenshot(self, file_path: str) -> None: """Save screenshot of element. :param file_path: path of file to save screenshot to """ self.log.info( f"save screenshot of element {self} to {file_path}") self._element.screenshot(file_path)