manen.page_object_model#
This module provides an implementation of the Page Object design pattern
described in Selenium documentation. By combining the classes
Page
and Region
with the Element
object (and all its subclasses),
you can easily describe any web pages and access all the DOM elements in a simple
way through a Python class.
Let’s say that you want, given a query, to get all the packages information from
the website PyPi (e.g.: “selenium”). The first step to
work with manen.page_object_model
is to define the Python classes which
will describe the web pages you are working on. Here we will define all the
classes in an external file called pypi_pom.py
.
from manen.page_object_model import (Page, Regions, InputElement,
TextElement, LinkElement,
IntegerElement)
class HomePage(Page):
query = InputElement("input[id='search']")
class SearchResultPage(Page):
class ResultRegions(Regions):
name = TextElement("h3 span.package-snippet__name")
version = TextElement("h3 span.package-snippet__version")
link = LinkElement("a.package-snippet")
description = TextElement("p.package-snippet__description")
n_results = IntegerElement("//*[@id='content']//form/div[1]/div[1]/p/strong")
results = ResultRegions("ul[aria-label='Search results'] li")
Once you have defined all the classes describing the web pages, you can start
interacting by instanciating the Page
subclass
with an instance of WebDriver
. Here
we will suppose that you have an instance of
WebDriver
stored in the variable
browser
.
>>> from pypi_pom import HomePage, SearchResultPage
>>> home_page = HomePage(browser)
>>> home_page.query = "selenium"
>>> home_page.query = Action("submit")
# This will direct you to a search result page of PyPi.
>>> browser.current_url
"https://pypi.org/search/?q=selenium"
>>> page = SearchResultPage(browser)
>>> page.n_results
1600
>>> len(page.results)
20
>>> page.results[0]
<pypi_pom.ResultRegions>
>>> page.results[0].name
"selenium"
>>> page.results[0].version
"3.141.0"
>>> page.results[0].link
"https://pypi.org/project/selenium/"
This is a glitch of what you can do with manen.page_object_model
. See the
documentation of each objects to check all the features provided by the module.
- class manen.page_object_model.Action(method: str, *args, **kwargs)[source]#
Bases:
object
Enable to interact with an input by calling a method of the WebElement. This is intended to be used by a subtype of
Element
which can be set.Example:
>>> page.query = "python manen" >>> page.query = Action("submit")
- __dict__ = mappingproxy({'__module__': 'manen.page_object_model', '__doc__': 'Enable to interact with an input by calling a method of the WebElement. This is\n intended to be used by a subtype of :py:class:`~manen.page_object_model.Element`\n which can be set.\n\n Example::\n\n >>> page.query = "python manen"\n >>> page.query = Action("submit")\n ', '__init__': <function Action.__init__>, '__dict__': <attribute '__dict__' of 'Action' objects>, '__weakref__': <attribute '__weakref__' of 'Action' objects>, '__annotations__': {}})#
- __init__(method: str, *args, **kwargs)[source]#
- Parameters:
method (str) – name of the method to call. This should be a method ones of a method of
selenium.webdriver.remote.webelement.WebElement
*args (Any) – positional arguments called with the method
**kwargs – keyword arguments called with the method
- __module__ = 'manen.page_object_model'#
- __weakref__#
list of weak references to the object (if defined)
- class manen.page_object_model.CheckboxElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
Get the status of a checkbox element directly as a boolan. Setting a boolean value to a checkbox element will directly change the value of the DOM element.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.DOMAccessor(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
object
Main interface of a DOM element.
- __annotations__ = {'_post_processing': typing.List[ForwardRef('PostProcessingFunction')]}#
- __dict__ = mappingproxy({'__module__': 'manen.page_object_model', '__annotations__': {'_post_processing': typing.List[ForwardRef('PostProcessingFunction')], '_name': 'str', '_path': 'Tuple[str, ...]'}, '__doc__': 'Main interface of a DOM element.', '_post_processing': [], '_many': False, '__init_subclass__': <classmethod(<function DOMAccessor.__init_subclass__>)>, '__init__': <function DOMAccessor.__init__>, '__set_name__': <function DOMAccessor.__set_name__>, '_apply_post_processing': <function DOMAccessor._apply_post_processing>, '_get_from': <function DOMAccessor._get_from>, '_build_elements': <function DOMAccessor._build_elements>, '__dict__': <attribute '__dict__' of 'DOMAccessor' objects>, '__weakref__': <attribute '__weakref__' of 'DOMAccessor' objects>})#
- __init__(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Main interface with a DOM element.
- Parameters:
selectors (Union[str, List[str]]) – Selector or sets of selectors used to identify the DOM element(s). Each selector must be in form of {selection_method}:{selector} where {selection_method} is in …. Note that if no selection method is specified, it will be inferred from the selector (but only the CSS and XPath method can be inferred).
default (Any, optional) – Default value to returned if no element matching the selector(s) is found. Defaults to NotImplemented.
wait (int, optional) – Time to wait before throwing an error. Defaults to 0.
post_processing (Callable[[Any], Any]) – Callable called after getting the element from the DOM. Defaults to None.
- classmethod __init_subclass__(many: bool | None = None, post_processing: List[PostProcessingFunction] | None = None)[source]#
This method is called when a class is subclassed.
The default implementation does nothing. It may be overridden to extend subclasses.
- __module__ = 'manen.page_object_model'#
- __weakref__#
list of weak references to the object (if defined)
- _many = False#
- class manen.page_object_model.DateTimeElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
TextElement
Extract a datetime from a text element matching a set of selectors.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>, <function parse>]#
- class manen.page_object_model.DateTimeElements(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
DateTimeElement
Pluralized version of
DateTimeElement
.- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = True#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>, <function parse>]#
- class manen.page_object_model.Element(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
DOMAccessor
Based on one or several selectors, extract a
selenium.webdriver.remote.webelement.WebElement
from a region or page.An element should be used to initialize a class attribute of a subclass of
Page
,Region
orFrame
(or any subtypes ofWebArea
)- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = []#
- class manen.page_object_model.Elements(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
Pluralized version of
Element
.- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = True#
- _post_processing: List['PostProcessingFunction'] = []#
- class manen.page_object_model.Frame(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
DOMAccessor
Enable to work with <iframe> element.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = []#
- class manen.page_object_model.IgnorePageObjectLoader(*args, **kwargs)[source]#
Bases:
Loader
Loader used to build page from a YAML file. This loader automatically registers all classes in the current module having a method
_yaml_loader
.- __module__ = 'manen.page_object_model'#
- ignore(loader: Loader, node: Node) Any [source]#
Prevent loading a YAML file with special classes when a tag is specified. This is useful when you want to a Manen YAML page without loading the element but only a regular Python object.
- Parameters:
loader (yaml.Loader) – instance of YAML Loader which describe how to build an element.
node (yaml.Node) – node to construct
- Raises:
TypeError – Raised if the special tag is set on something different from a SequenceNode or a MappingNode
- Returns:
- Python object as it should be loaded with a regular YAML
Loader
- Return type:
Any
- class manen.page_object_model.ImageSourceElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
Extract the source URL of an image.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.ImageSourceElements(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
ImageSourceElement
Pluralized version of
ImageSourceElement
.- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = True#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.InnerHtmlElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
Extract the inner HTML from an element.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.InnerHtmlElements(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
InnerHtmlElement
Pluralized version of
manen.page_object_model.InnerHtmlElement
.- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = True#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.InputElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
Interface with an <input> element of a DOM. Setting the variable of the InputElement will also set the value of the DOM.
Example:
>>> from manen.page_object_model import Page, InputElement >>> class LoginPage(Page): ... email = InputElement("input[type='email']") ... password = InputElement("input[type='password']") >>> from manen.page_object_model import Action >>> login_page = LoginPage(browser) >>> login_page.email = "username@manen.co" >>> login_page.password = "dummypassword" >>> login_page.password = Action("submit")
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.IntegerElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
TextElement
Extract the integer from a text element matching a selector or set of selectors.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>, <function extract_integer>]#
- class manen.page_object_model.IntegerElements(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
IntegerElement
Get elements from a HTML page matching a set of selectors and extract a integer from each text element. Pluralized version of
IntegerElement
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = True#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>, <function extract_integer>]#
- class manen.page_object_model.LinkElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
Extract the link from an element matching one or several selectors.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.LinkElements(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
LinkElement
Pluralized version of
LinkElement
.- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = True#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.OuterHtmlElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
Extract the outer HTML of an element.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.OuterHtmlElements(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
OuterHtmlElement
Pluralized version of
OuterHtmlElement
.- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = True#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.Page(container: SeleniumElement, _context: str = 'PAGE')[source]#
Bases:
WebArea
Modelize a HTML page in the Page Object Model design pattern. The attributes of
Page
should be an instance ofElement
(or any subclass) or an instance ofRegion
.Example:
>>> class QueryPage(Page): ... main_title = TextElement("h1") ... search = InputElement("input[name='query']") ... button_validate = Element("button#validate") >>> page = QueryPage(browser) >>> page.search = "python manen" >>> button_validate.click()
- __module__ = 'manen.page_object_model'#
- classmethod from_object(page_objects: Dict[str, Element], bases: Tuple = (), name: str = 'Page')[source]#
Build a Page class from a dictionary.
- class manen.page_object_model.PageObjectLoader(*args, **kwargs)[source]#
Bases:
Loader
Loader used to build page from a YAML file. This loader automatically registers all classes in the current module having a method
_yaml_loader
.- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- class manen.page_object_model.RadioButtonElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
Mapper to a set of choices controlled by a radio element in the page. Setting the value of the radio button element will directly update the DOM element with the specified value.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = []#
- class manen.page_object_model.Region(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
DOMAccessor
Modelize a region of a webpage. A region is a set of elements contained in the same container.
Note
Contrary to
Page
, this class should not be instanciated with an instance of WebDriver. This class is closer to anElement
than aElement
.Example:
>>> from manen.page_object_model import Page, Region, InputElement, Action >>> class LoginPage(Page): ... class FormRegion(Region): ... email = InputElement("input#email") ... password = InputElement("input#password") ... form_region = FormRegion("div#form-container") >>> page = LoginPage(browser) >>> page.form_region.email = "hello@manen.com" >>> page.form_region.password = "strong_password" >>> page.form_region.password = Action("submit")
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = []#
- class manen.page_object_model.Regions(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Region
Pluralized version of
Region
.- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = True#
- _post_processing: List['PostProcessingFunction'] = []#
- class manen.page_object_model.SelectElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
A shortcut to get an instance of
Select
for a select element. See guide to work withSelect
element from official documentation. # pylint: disable=line-too-long- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = []#
- class manen.page_object_model.TextElement(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
Element
Extract text from an element matching one or several selectors.
- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = False#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.TextElements(selectors: str | List[str] | None = None, *, default: Any = NotImplemented, wait: int = 0, post_processing: PostProcessingFunction | None = None)[source]#
Bases:
TextElement
Pluralized version of
TextElement
.- __annotations__ = {}#
- __module__ = 'manen.page_object_model'#
- _many = True#
- _post_processing: List['PostProcessingFunction'] = [<function <lambda>>]#
- class manen.page_object_model.WebArea(container: SeleniumElement, _context: str = 'PAGE')[source]#
Bases:
object
Wrapper around a Selenium element which works together with an
Element
(and its subclasses). Any class attribute instanciated withElement
will be accessible as an instance attribute; it will, when accessed, evaluate the selector to retrieve the element.Example:
>>> class Area(WebArea): ... body = Element("css:body") ... first_div = Element("css:div") ... links = Elements("css:a") >>> area = Area(browser) >>> area.body <selenium.webdriver.remote.webelement.WebElement id="abcdef-1234"> >>> div_area = Area(area.first_div) >>> div_area.links # Find all the links in the first div element of the body
Note
This class is mainly used internally to build the classes
Page
,Region
andFrame
. You shouldn’t need to use this class to create basic page objects (see the documentation of each object to see how to efficiently used page object modelling).- class Meta[source]#
Bases:
object
Metadata for a webarea.
- __annotations__ = {'selectors': typing.Dict[str, typing.Any], 'selectors_path': <class 'str'>, 'url': typing.Optional[str]}#
- __dict__ = mappingproxy({'__module__': 'manen.page_object_model', '__annotations__': {'selectors_path': <class 'str'>, 'selectors': typing.Dict[str, typing.Any], 'url': typing.Optional[str]}, '__doc__': 'Metadata for a webarea.', 'selectors_path': '', 'selectors': {}, 'url': None, '__dict__': <attribute '__dict__' of 'Meta' objects>, '__weakref__': <attribute '__weakref__' of 'Meta' objects>})#
- __module__ = 'manen.page_object_model'#
- __weakref__#
list of weak references to the object (if defined)
- __annotations__ = {}#
- __dict__ = mappingproxy({'__module__': 'manen.page_object_model', '__doc__': 'Wrapper around a Selenium element which works together with an\n :py:class:`~manen.page_object_model.Element` (and its subclasses). Any class\n attribute instanciated with :py:class:`~manen.page_object_model.Element`\n will be accessible as an instance attribute; it will, when accessed, evaluate\n the selector to retrieve the element.\n\n Example::\n\n >>> class Area(WebArea):\n ... body = Element("css:body")\n ... first_div = Element("css:div")\n ... links = Elements("css:a")\n >>> area = Area(browser)\n >>> area.body\n <selenium.webdriver.remote.webelement.WebElement id="abcdef-1234">\n >>> div_area = Area(area.first_div)\n >>> div_area.links # Find all the links in the first div element of the body\n\n .. note:: This class is mainly used internally to build the classes\n :py:class:`~manen.page_object_model.Page`,\n :py:class:`~manen.page_object_model.Region` and\n :py:class:`~manen.page_object_model.Frame`. You shouldn\'t need to use this\n class to create basic page objects (see the documentation of each object to\n see how to efficiently used page object modelling).\n ', 'Meta': <class 'manen.page_object_model.WebArea.Meta'>, '__init__': <function WebArea.__init__>, 'container': <property object>, 'switch_container': <function WebArea.switch_container>, '_selectors_from_meta': <classmethod(<function WebArea._selectors_from_meta>)>, '__dict__': <attribute '__dict__' of 'WebArea' objects>, '__weakref__': <attribute '__weakref__' of 'WebArea' objects>, '__annotations__': {}})#
- __init__(container: SeleniumElement, _context: str = 'PAGE')[source]#
- Parameters:
container ("SeleniumElement") – Parent element in which all the elements will be searched.
- __module__ = 'manen.page_object_model'#
- __weakref__#
list of weak references to the object (if defined)
- property container: SeleniumElement#
Selenium element where to perform the query in order to retrieve some elements with selectors.
Warning
Prefer using the context manager switch_container() rather than this property.
- switch_container()[source]#
Context manager which returns the container where to perform the query. In most cases, it is the container used to instanciate WebArea but some additional computing may be needed in some cases (for example, when working with frame element). The additional computation will occur based on the value of the attribute _context, entered at instanciation.
- Yields:
container (
selenium.webdriver.remote.webelement.WebElement
) – Selenium element where to evaluate a selector