Source code for capybara.node.simple
import re
from xpath import dsl as x
from xpath.renderer import to_xpath
from capybara.compat import bytes_, str_
from capybara.node.document_matchers import DocumentMatchersMixin
from capybara.node.finders import FindersMixin
from capybara.node.matchers import MatchersMixin
from capybara.utils import decode_bytes, inner_content
[docs]class Simple(FindersMixin, MatchersMixin, DocumentMatchersMixin, object):
"""
A :class:`Simple` is a simpler version of :class:`Base` which includes only
:class:`FindersMixin` and :class:`MatchersMixin` and does not include :class:`ActionsMixin`.
This type of node is returned when using :func:`capybara.string`.
It is useful in that it does not require a session, an application, or a driver, but can still
use Capybara's finders and matchers on any string that contains HTML.
"""
def __init__(self, native):
if isinstance(native, (bytes_, str_)):
from lxml import etree
native = decode_bytes(native)
native = etree.HTML(native)
self.native = native
def __getitem__(self, name):
"""
Return the given attribute. ::
element["title"] # => HTML title attribute
Args:
name (str): The attribute name to retrieve.
Returns:
str: The value of the attribute.
"""
return self.native.get(name)
@property
def tag_name(self):
""" str: The tag name of the element. """
return self.native.tag
@property
def path(self):
""" str: An XPath expression describing where on the page the element can be found. """
return self.native.getroottree().getpath(self.native)
@property
def text(self):
""" str: The text of the element. """
return self.native.text
@property
def value(self):
""" str: The value of the form element. """
if self.tag_name == "textarea":
return inner_content(self.native)
elif self.tag_name == "select":
if self["multiple"] == "multiple":
selected_options = self._find_xpath(".//option[@selected='selected']")
return [_get_option_value(option) for option in selected_options]
else:
options = (
self._find_xpath(".//option[@selected='selected']") +
self._find_xpath(".//option"))
return _get_option_value(options[0]) if options else None
elif self.tag_name == "input" and self["type"] in ["checkbox", "radio"]:
return self["value"] or "on"
else:
return self["value"]
@property
def visible(self):
""" bool: Whether or not the element is visible. """
return self._visible()
@property
def checked(self):
""" bool: Whether or not the element is checked. """
return "checked" in self.native.attrib
@property
def disabled(self):
""" bool: Whether or not the element is disabled. """
return "disabled" in self.native.attrib
@property
def readonly(self):
""" bool: Whether or not the element is readonly. """
return "readonly" in self.native.attrib
@property
def multiple(self):
""" bool: Whether or not the select supports multiple values. """
return "multiple" in self.native.attrib
@property
def selected(self):
""" bool: Whether or not the element is selected. """
return "selected" in self.native.attrib
@property
def allow_reload(self):
return False
@allow_reload.setter
def allow_reload(self, value):
pass
@property
def title(self):
""" str: The current page title. """
elements = self.native.xpath("/html/head/title | /html/title")
return elements[0].text if elements else None
[docs] def synchronize(self, func=None, **kwargs):
# Simple nodes don't need to wait.
return func if func else lambda func: func
def _visible(self, check_ancestor_visibility=True):
if self.tag_name == "input" and self.native.get("type") == "hidden":
return False
if check_ancestor_visibility:
return not self.native.xpath(
"./ancestor-or-self::*["
"contains(@style, 'display:none') or "
"contains(@style, 'display: none') or "
"@hidden or "
"name()='script' or "
"name()='head'"
"]")
if "hidden" in self.native.attrib:
return False
if re.compile(r"display:\s?none").search(self.native.get("style", "")):
return False
if self.tag_name in ["script", "head"]:
return False
return True
def _find_xpath(self, xpath):
return self.native.xpath(xpath)
def _find_css(self, css):
xpath = to_xpath(x.css(css))
return self._find_xpath(xpath)
def _get_option_value(option):
return option.get("value") or inner_content(option)