Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add small extensions #30

Merged
merged 4 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ Below is the code that opens ``PyPI.org``, searches for packages by name and pri
packages to the terminal. The script contains all base classes contained in ``pomcorn``: **Page**,
**ComponentWithBaseLocator**, **ListComponent** and **Element**.

.. /* yaspeller ignore:start */

.. code-block:: python

from typing import Self
Expand All @@ -105,11 +103,11 @@ packages to the terminal. The script contains all base classes contained in ``po
APP_ROOT = "https://pypi.org"

def check_page_is_loaded(self) -> bool:
return self.init_element(locator=locators.TagNameLocator("main")).is_displayed
return self.init_element(locators.TagNameLocator("main")).is_displayed

@property
def search(self) -> Element[locators.XPathLocator]:
return self.init_element(locator=locators.IdLocator("search"))
return self.init_element(locators.IdLocator("search"))


# Prepare components
Expand Down Expand Up @@ -159,8 +157,6 @@ packages to the terminal. The script contains all base classes contained in ``po
search_page = SearchPage.open(webdriver=Chrome())
print(search_page.find("saritasa").names)

.. /* yaspeller ignore:end */

For more information about package classes, you can read in `Object Hierarchy <https://pomcorn.readthedocs.io/en/latest/objects_hierarchy.html>`_
and `Developer Interface <https://pomcorn.readthedocs.io/en/latest/developer_interface.html>`_.

Expand Down
3 changes: 3 additions & 0 deletions demo/pages/base/base_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ def __init__(
# The Logo will be on all the pages of the application so we initialize
# it in base page class.
self.logo = self.init_element(
# The ``locator=`` keyword is optional here, but we recommend using
# it to be consistent with the method of the same name in
# ``ComponentWithBaseLocator``. Same with ``init_elements``.
locator=locators.ClassLocator("site-header__logo"),
)

Expand Down
9 changes: 9 additions & 0 deletions docs/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ Version history

We follow `Semantic Versions <https://semver.org/>`_.

0.4.0
*******************************************************************************

- Add ``|`` (or) operator for XPathLocators
- Add ``Page.click_on_page`` method
- Add recommendation for use keyword when specifying the ``locator`` argument
in ``init_element`` and ``init_elements`` methods whenever possible to be
consistent with the method of the same name in ``ComponentWithBaseLocator``

0.3.1
*******************************************************************************

Expand Down
15 changes: 15 additions & 0 deletions pomcorn/locators/base_locators.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,21 @@ def __floordiv__(self, other: XPathLocator) -> XPathLocator:
"""Override `//` operator to implement nested XPath locators."""
return XPathLocator(query=f"{self.query}//{other.related_query}")

def __or__(self, other: XPathLocator) -> XPathLocator:
r"""Override `|` operator to implement variant XPath locators.

Example:
span = XPathLocator("//span")
div = XPathLocator("//div")
img = XPathLocator("//img")

(span | div) // img == XPathLocator("(//span | //div)//img")

span | div // img == XPathLocator("(//span | //div//img)")

"""
return XPathLocator(query=f"({self.query} | {other.query})")

def extend_query(self, extra_query: str) -> XPathLocator:
"""Return new XPathLocator with extended query."""
return XPathLocator(query=self.query + extra_query)
10 changes: 10 additions & 0 deletions pomcorn/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.remote.webdriver import WebDriver

from . import locators
from .exceptions import PageDidNotLoadedError
from .web_view import WebView

Expand Down Expand Up @@ -145,6 +146,15 @@ def navigate_relative(self, relative_url: str = "/") -> None:
self._get_full_relative_url(self.app_root, relative_url),
)

def click_on_page(self):
"""Click on page `html` tag.

Allows you to move focus away from an element, for example, if it
is currently unavailable for interaction.

"""
self.init_element(locator=locators.TagNameLocator("html")).click()

@staticmethod
def _get_full_relative_url(app_root: str, relative_url: str) -> str:
"""Add relative URL to application root URL.
Expand Down
13 changes: 11 additions & 2 deletions pomcorn/web_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ def __init__(
def init_element(self, locator: TInitLocator) -> Element[TInitLocator]:
"""Shortcut for initializing Element instances.

Note: To be consistent with the method of the same name in
``ComponentWithBaseLocator``, try to use keyword when specifying
the ``locator`` argument whenever possible.

Args:
locator: Instance of a class to locate the element in the browser.

Expand All @@ -61,6 +65,10 @@ def init_elements(

Note: Only supports Xpath locators.

Note: To be consistent with the method of the same name in
``ComponentWithBaseLocator``, try to use keyword when specifying the
``locator`` argument whenever possible.

Args:
locator: Instance of a class to locate the element in the browser.

Expand Down Expand Up @@ -88,9 +96,10 @@ def iter_locators(

For example, there are multiple elements on the page that matches
`XPathLocator("//a")`.

This method return the set of locators like:
* `XPathLocator("//a[1]")`
* `XPathLocator("//a[2]")`
* `XPathLocator("(//a)[1]")`
* `XPathLocator("(//a)[2]")`

Args:
locator: Instance of a class to locate the element in the browser.
Expand Down