e2e.pom


Namee2e.pom JSON
Version 0.1.8 PyPI version JSON
download
home_pagehttps://github.com/nickroeker/e2e.pom
SummaryHuman-friendly rich class-based modeling for the Page Object Model pattern
upload_time2023-01-04 20:00:34
maintainer
docs_urlNone
authorNic Kroeker
requires_python>=3.6
licenseApache 2.0
keywords e2e testing framework model selenium webdriver pom page object
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            e2e.pom - Page Object Modelling for End-to-End Testing
======================================================

Use ``e2e.pom`` to easily create reusable Page Object Models that offer
functionality and error scenarios more naturally than Selenium can.

Extend available locators with plugins like ``e2e.pom.extjs`` for
ExtJS/Sencha Locators, or write your own!

Eliminate iframe-handling in your tests — let the model take care of
where your elements reside. In fact, all elements are guaranteed to be
found within their parent model so you can write unique selectors
without specifying a long ancestry within the selector itself!

All actions are logged with human-friendly labels, with human-friendly
exceptions indicating exactly where things went wrong.

Beta Notice
-----------
``e2e.pom`` is still in **beta**, but the API is expected to be stable. The
project is very open to suggestions and feedback at this stage!

This project follows SemVer. It is expected that the first major release (1.x)
will **not** differ in API functionality much from the alpha/beta track
(0.x).

Python 3.6+ is currently required. No support for 2.x is ever planned since
it is soon to be unsupported. Please feel free to file an issue if you need
support for an earlier Python version and simply cannot upgrade.


Modelling Examples
------------------

Pages and their components are easy to model on a class-member basis.
You do not need to pass around a driver, nor do you need to write
properties or methods. There is no need to override ``__init__``
properly either; just author your static model and be done with it!

.. code:: py

   class LoginForm(pom.Region):
       username_field = pom.Element("Username").by_css('.username')
       password_field = pom.Element("Password").by_css('.password')
       login_button = pom.Element("Login btn").by_css('#login-submit')

   class LoginPage(pom.Page):
       login_form = LoginForm("Login form").by_css('.login')

   # ...

   login_pg = LoginPage("https://my-login-service.local:8443", driver)
   login_pg.login_form.wait_for_visible()
   login_pg.login_form.username_field.set_text('Admin1')
   login_pg.login_form.password_field.set_text('Sup3rS3cret!')
   login_pg.login_form.login_button.click()

IFrame Handling
~~~~~~~~~~~~~~~

Handling iframes with Selenium is incredibly annoying. ``e2e.pom``
provides a special component that you can use as a hidden parent so that
test authors do not need to be concerned about the iframe at all.

.. code:: py

   class LoginForm(pom.Region):
       # Same as Example Model above

   class LoginPage(pom.Page):
       # Hide the iframe POM component so the test doesn't need to be aware by
       # overriding the parent of the Form.
       _login_service_iframe = pom.IFrame("LoginService iframe").by_css('iframe#login-service')
       login_form = LoginForm("Login form").by_css('.login', parent=_login_service_iframe)

   # Use exactly as before, like the iframe isn't even there!
   login_pg.login_form.wait_for_visible()

The POM framework will then handle switching to the correct iframes.
Even if a service *becomes* resident within an iframe that was otherwise
inline before, you only need to change the *model* and not the test
code!

In addition, features like ``is_visible()`` are mindful of iframes. That
is, unlike using Selenium directly, if the iframe is not displayed then
``e2e.api`` counts all of its children as invisible.

Hidden Regions
~~~~~~~~~~~~~~

Like the above case for IFrames, you may want to hide a certain part of
the model but otherwise use it as a parent to other components. This is
often useful for ensuring elements are found within a certain part of
the page, but would be too verbose to specify in every test.

.. code:: py

   class ServicePage(pom.Page):
       _nav_bar = pom.Region("Navigation bar").by_css('.upper-nav-container')
       settings_button = pom.Element("Setting btn").by_css('.gear-icon')

   # You can now do this...
   service_pg.settings_button.click()

   # Instead of having to do this
   service_pg.navigation_bar.settings_button.click()

This is especially useful when you have, like in the above example,
multiple elements that use ``.gear-icon`` but are obviously referring to
one particular instance of it. If it is beneficial to the clarity of
your model though, you may want to *not* hide the parent since the
increased verbosity may make your test’s actions more clear to others.

Interacting with Elements
-------------------------

While some available methods are similar to Selenium’s API, they have
differing requirements and behaviours.

For example, the concept of “visibility” is now more user-friendly.
Whether an element is *visible* to the user depends not only on the
display info of the element, but whether the element exists at all. With
Selenium, entirely different code is required to handle that difference!
With ``e2e.pom``, it is *just* the visiblility functions. This allows
product developers to use techniques like DOM caching without needing to
change the test code. This way, ``e2e.pom`` is checking *user intent*
rather than *implementation details*.

.. code:: py

   # Case 1: With Selenium, element not in DOM. Can also assert NoSuchElement was raised.
   assert driver.find_elements_by_xpath(...) == []

   # Case 2: With Selenium, element in DOM
   assert driver.find_elements_by_xpath(...).is_displayed()

   # With happy-path-only POM frameworks (not e2e.pom)
   try:
       assert modelled_element.is_displayed()
   except NoSuchElementException:
       pass

   # With e2e.pom (works for both above cases)
   assert modelled_element.is_visible()

*Nothing* happens until you call a method on an element. This is to give
clarity as to when the finding, attribute checking, and interaction
takes place within a test.

.. code:: py

   # Selenium: All of these do something with the driver, even the properties!
   element = driver.find_element_by_css_selector(...)
   element.text
   element.is_displayed()
   element.click()
   element.clear() and element.send_keys("some text")

   # e2e.pom: Consistent API. Methods == driver actions.
   element.get_text()
   element.is_visible()
   element.click()
   element.set_text("some text")

All user-like interaction methods require visibility of the element. If
the element is not visible, a user cannot interact with it. Exceptions
will be raised with the exact details (e.g. if it was because a parent
could not be located, the exception will state this).

Sets of Elements
----------------

Sometimes you are intentionally referring to a group of similar
elements, like rows of a particular type. You can’t use a
``pom.Element`` for this because they require *uniquely* finding an
element. In this case, you can use ``pom.ElementCollection``.

Rich Visibility
---------------

To-do.

Using Locators Provided by Third-Party Plugins
----------------------------------------------

In certain projects, alternative locator methods may be available that
are more deterministic of exact elements.

A first-party example of this, ``e2e.pom.extjs``, provides locators for
pages built with ExtJS/Sencha.

This extensibility has a few drawbacks to be aware of:

-  The generic ``by(...)`` must be used instead of something like
   ``by_css(...)``
-  Many setups will fail to type-check or auto-complete this correctly.

Using it is very easy though! Just ensure it is installed, then use the
provided ``Locator`` class directly in the ``by()`` construction.

.. code:: py

   from e2e import pom
   from e2e.pom import extjs

   class ServicePage(pom.Page):
       alert_popup = pom.Element("Alert").by(extjs.Locator('panel[title=Alert]'))

Developing Locator Extensions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Please use ``e2e.pom.extjs`` as an implementation guide.

The following are recommended:

-  The extension locator class should be called ``Locator`` where
   possible.
-  ``find_within`` is the only method needing implementation. It will be
   passed *either* a ``WebDriver`` or a ``WebElement``. For the
   ``WebElement``, you *must* assure that anything returned by your
   Locator is within the given ``WebElement``.
-  Don’t forget to register the entrypoint!

Pytest Hooks & Fixtures (BETA)
------------------------------

*Note:* This feature is under development and *will* change. Feedback is
much appreciated!

A information-providing fixture is provided for dumping info useful in
test failure analysis.

You must register the drivers you use with this fixture. We recognize
users will have their own ways of managing drivers, so this is the best
way currently.

.. code:: py

   def test_my_thing(e2e_pom_dumper: pom.fixtures.DumperFixture):
       my_driver = ...  # However you get this
       e2e_pom_dumper.register_driver(my_driver)
       # Now you can use the driver!

After that, the following features are provided:

-  On test failure, two DOMs are dumped to HTML files:

   -  The current frame/iframe at the time of failure (if not the root
      frame)
   -  The root frame

-  A screenshot is taken at the outermost/root frame

Performance Considerations
--------------------------

Certain features like Collections as parents can result in a lot of
Selenium requests being issued. If you test against a busy Selenium
Grid, this can definitely slow things down!

I do not normally recommend the below workarounds (because they bypass
some significant benefits of the framwork), but you may find them
necessary in your case.

1. Avoid a ``pom.Collection`` parent if it represents many elements
   (e.g. rows in a large table). Every found element for the collection
   is searched for the next child.
2. Reduce POM depth where possible. Since each child causes a Selenium
   find request on interaction, reducing the size of that parentage can
   speed things up.

For the first case, this can be easy to work around with a dynamic model
if you are targeting a particular item.

.. code:: py


   class MyTable(pom.Container):

       rows = pom.Collection('Rows').by_css('tr')

       def row_by_title(self, title: str):
           label = f'Row by title [{title}]'
           xpath = f'.//td[text()="{title}]/ancestor::tr"'
           # Do this IF Selenium performance isn't critical to you (most cases)
           return pom.Element(label).by_xpath(xpath, parent=rows)
           # Do this IF and ONLY IF Selenium performance is very important to you
           return pom.Element(label).by_xpath(xpath)

Note how ``rows`` is on the model directly, but also used as a parent
override in the method. However, skipping ``rows`` as a parent means we
can forego some more detailed information on failure while making less
Selenium calls.

Making Richer Models
--------------------

Generic type information can be passed regarding the type of located
elements.

This is especially useful for ``pom.ElementCollection``\ s. For example,
you may want to have an ``icon`` property modelled on each dropdown item
returned from a collection. This is normally modelled by a Findable
component (e.g. ``pom.Container`` or ``pom.Element``), but these cannot
be used for *found* elements (those returned by
``pom.ElementCollection.get()``). Enter, generics.

On construction of *any* findable POM type, you can specify the concrete
type returned by ``findable.get()`` or acted on via operations like
``findable.click()``. By default, this is a
``pom.dom.ElementReference``, but you may extend it to provide more
functionality.

# TODO: assert Reference parents actually work!

.. code:: py

   class Dropdown(pom.Container):

       class IconItem(pom.dom.ElementReference):
           icon = pom.Element("Icon").by_css(".option-icon")

       items = pom.ElementCollection("Dropdown items", IconItem).by_css("option")

   first_item = ...dropdown.items.get()[0]
   assert 'gear-icon' in first_item.icon.get_attribute('class')

The type of ``items`` is now a ``pom.ElementCollection<IconItem>``. If
it was not specified, it would be a
``pom.ElementCollection<dom.ElementReference>``.

This works because while an ElementReference is not “Findable”, it *is*
“Parentable”. That is, it can be a parent, and thus contain other
modelled children.

In the future, a pom.HybridElement may exist that can be used to
represent these items both as a Findable and a Found object to avoid
code duplication.

Basically, a rich interface is what you write.


Changelog for e2e.pom
=====================

0.1.8 (2023-01-04)
------------------

- Remove deprecated _find_within that was causes static analysis issues
- Added wait methods from ElementReferences


0.1.7 (2022-09-20)
------------------

- Allow ElementCollection to be a direct parent


0.1.5 (2022-09-20)
------------------

- Better error reporting for issues while finding
- Added DOM presence wait methods


0.1.4 (2022-09-12)
------------------

- [Issue 2] Fix ElementReference naming and parent chain for logging


0.1.3 (2022-08-24)
------------------

- Fix: Missing import


0.1.2 (2022-08-22)
------------------

- Type-hint fixes at the module-level, and a couple method signature fixes
- New way to wait for page transitions: `pom.Page.expect_transition`


0.1.1 (2022-06-26)
------------------

- Packaging and requirements fixes
- Added some left-behind critical missing functions!
- Fixed typos on exception names


0.1.0 (2022-05-09)
------------------

- Exported modelling core to e2e.common, imported and used here
- Fixed some type-hints based on updated mypy versions
- Fixed some issues mypy had detecting types in the package at all
- Updated tags to support Python 3.9, 3.10


0.0.1 (11-19-2020)
------------------

- Initial release! Elements, Collections, IFrames, and Pages.

Copyright 2019-2022 Nicholas Kroeker

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/nickroeker/e2e.pom",
    "name": "e2e.pom",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "e2e,testing,framework,model,selenium,webdriver,pom,page,object",
    "author": "Nic Kroeker",
    "author_email": "",
    "download_url": "",
    "platform": null,
    "description": "e2e.pom - Page Object Modelling for End-to-End Testing\n======================================================\n\nUse ``e2e.pom`` to easily create reusable Page Object Models that offer\nfunctionality and error scenarios more naturally than Selenium can.\n\nExtend available locators with plugins like ``e2e.pom.extjs`` for\nExtJS/Sencha Locators, or write your own!\n\nEliminate iframe-handling in your tests \u2014 let the model take care of\nwhere your elements reside. In fact, all elements are guaranteed to be\nfound within their parent model so you can write unique selectors\nwithout specifying a long ancestry within the selector itself!\n\nAll actions are logged with human-friendly labels, with human-friendly\nexceptions indicating exactly where things went wrong.\n\nBeta Notice\n-----------\n``e2e.pom`` is still in **beta**, but the API is expected to be stable. The\nproject is very open to suggestions and feedback at this stage!\n\nThis project follows SemVer. It is expected that the first major release (1.x)\nwill **not** differ in API functionality much from the alpha/beta track\n(0.x).\n\nPython 3.6+ is currently required. No support for 2.x is ever planned since\nit is soon to be unsupported. Please feel free to file an issue if you need\nsupport for an earlier Python version and simply cannot upgrade.\n\n\nModelling Examples\n------------------\n\nPages and their components are easy to model on a class-member basis.\nYou do not need to pass around a driver, nor do you need to write\nproperties or methods. There is no need to override ``__init__``\nproperly either; just author your static model and be done with it!\n\n.. code:: py\n\n   class LoginForm(pom.Region):\n       username_field = pom.Element(\"Username\").by_css('.username')\n       password_field = pom.Element(\"Password\").by_css('.password')\n       login_button = pom.Element(\"Login btn\").by_css('#login-submit')\n\n   class LoginPage(pom.Page):\n       login_form = LoginForm(\"Login form\").by_css('.login')\n\n   # ...\n\n   login_pg = LoginPage(\"https://my-login-service.local:8443\", driver)\n   login_pg.login_form.wait_for_visible()\n   login_pg.login_form.username_field.set_text('Admin1')\n   login_pg.login_form.password_field.set_text('Sup3rS3cret!')\n   login_pg.login_form.login_button.click()\n\nIFrame Handling\n~~~~~~~~~~~~~~~\n\nHandling iframes with Selenium is incredibly annoying. ``e2e.pom``\nprovides a special component that you can use as a hidden parent so that\ntest authors do not need to be concerned about the iframe at all.\n\n.. code:: py\n\n   class LoginForm(pom.Region):\n       # Same as Example Model above\n\n   class LoginPage(pom.Page):\n       # Hide the iframe POM component so the test doesn't need to be aware by\n       # overriding the parent of the Form.\n       _login_service_iframe = pom.IFrame(\"LoginService iframe\").by_css('iframe#login-service')\n       login_form = LoginForm(\"Login form\").by_css('.login', parent=_login_service_iframe)\n\n   # Use exactly as before, like the iframe isn't even there!\n   login_pg.login_form.wait_for_visible()\n\nThe POM framework will then handle switching to the correct iframes.\nEven if a service *becomes* resident within an iframe that was otherwise\ninline before, you only need to change the *model* and not the test\ncode!\n\nIn addition, features like ``is_visible()`` are mindful of iframes. That\nis, unlike using Selenium directly, if the iframe is not displayed then\n``e2e.api`` counts all of its children as invisible.\n\nHidden Regions\n~~~~~~~~~~~~~~\n\nLike the above case for IFrames, you may want to hide a certain part of\nthe model but otherwise use it as a parent to other components. This is\noften useful for ensuring elements are found within a certain part of\nthe page, but would be too verbose to specify in every test.\n\n.. code:: py\n\n   class ServicePage(pom.Page):\n       _nav_bar = pom.Region(\"Navigation bar\").by_css('.upper-nav-container')\n       settings_button = pom.Element(\"Setting btn\").by_css('.gear-icon')\n\n   # You can now do this...\n   service_pg.settings_button.click()\n\n   # Instead of having to do this\n   service_pg.navigation_bar.settings_button.click()\n\nThis is especially useful when you have, like in the above example,\nmultiple elements that use ``.gear-icon`` but are obviously referring to\none particular instance of it. If it is beneficial to the clarity of\nyour model though, you may want to *not* hide the parent since the\nincreased verbosity may make your test\u2019s actions more clear to others.\n\nInteracting with Elements\n-------------------------\n\nWhile some available methods are similar to Selenium\u2019s API, they have\ndiffering requirements and behaviours.\n\nFor example, the concept of \u201cvisibility\u201d is now more user-friendly.\nWhether an element is *visible* to the user depends not only on the\ndisplay info of the element, but whether the element exists at all. With\nSelenium, entirely different code is required to handle that difference!\nWith ``e2e.pom``, it is *just* the visiblility functions. This allows\nproduct developers to use techniques like DOM caching without needing to\nchange the test code. This way, ``e2e.pom`` is checking *user intent*\nrather than *implementation details*.\n\n.. code:: py\n\n   # Case 1: With Selenium, element not in DOM. Can also assert NoSuchElement was raised.\n   assert driver.find_elements_by_xpath(...) == []\n\n   # Case 2: With Selenium, element in DOM\n   assert driver.find_elements_by_xpath(...).is_displayed()\n\n   # With happy-path-only POM frameworks (not e2e.pom)\n   try:\n       assert modelled_element.is_displayed()\n   except NoSuchElementException:\n       pass\n\n   # With e2e.pom (works for both above cases)\n   assert modelled_element.is_visible()\n\n*Nothing* happens until you call a method on an element. This is to give\nclarity as to when the finding, attribute checking, and interaction\ntakes place within a test.\n\n.. code:: py\n\n   # Selenium: All of these do something with the driver, even the properties!\n   element = driver.find_element_by_css_selector(...)\n   element.text\n   element.is_displayed()\n   element.click()\n   element.clear() and element.send_keys(\"some text\")\n\n   # e2e.pom: Consistent API. Methods == driver actions.\n   element.get_text()\n   element.is_visible()\n   element.click()\n   element.set_text(\"some text\")\n\nAll user-like interaction methods require visibility of the element. If\nthe element is not visible, a user cannot interact with it. Exceptions\nwill be raised with the exact details (e.g. if it was because a parent\ncould not be located, the exception will state this).\n\nSets of Elements\n----------------\n\nSometimes you are intentionally referring to a group of similar\nelements, like rows of a particular type. You can\u2019t use a\n``pom.Element`` for this because they require *uniquely* finding an\nelement. In this case, you can use ``pom.ElementCollection``.\n\nRich Visibility\n---------------\n\nTo-do.\n\nUsing Locators Provided by Third-Party Plugins\n----------------------------------------------\n\nIn certain projects, alternative locator methods may be available that\nare more deterministic of exact elements.\n\nA first-party example of this, ``e2e.pom.extjs``, provides locators for\npages built with ExtJS/Sencha.\n\nThis extensibility has a few drawbacks to be aware of:\n\n-  The generic ``by(...)`` must be used instead of something like\n   ``by_css(...)``\n-  Many setups will fail to type-check or auto-complete this correctly.\n\nUsing it is very easy though! Just ensure it is installed, then use the\nprovided ``Locator`` class directly in the ``by()`` construction.\n\n.. code:: py\n\n   from e2e import pom\n   from e2e.pom import extjs\n\n   class ServicePage(pom.Page):\n       alert_popup = pom.Element(\"Alert\").by(extjs.Locator('panel[title=Alert]'))\n\nDeveloping Locator Extensions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nPlease use ``e2e.pom.extjs`` as an implementation guide.\n\nThe following are recommended:\n\n-  The extension locator class should be called ``Locator`` where\n   possible.\n-  ``find_within`` is the only method needing implementation. It will be\n   passed *either* a ``WebDriver`` or a ``WebElement``. For the\n   ``WebElement``, you *must* assure that anything returned by your\n   Locator is within the given ``WebElement``.\n-  Don\u2019t forget to register the entrypoint!\n\nPytest Hooks & Fixtures (BETA)\n------------------------------\n\n*Note:* This feature is under development and *will* change. Feedback is\nmuch appreciated!\n\nA information-providing fixture is provided for dumping info useful in\ntest failure analysis.\n\nYou must register the drivers you use with this fixture. We recognize\nusers will have their own ways of managing drivers, so this is the best\nway currently.\n\n.. code:: py\n\n   def test_my_thing(e2e_pom_dumper: pom.fixtures.DumperFixture):\n       my_driver = ...  # However you get this\n       e2e_pom_dumper.register_driver(my_driver)\n       # Now you can use the driver!\n\nAfter that, the following features are provided:\n\n-  On test failure, two DOMs are dumped to HTML files:\n\n   -  The current frame/iframe at the time of failure (if not the root\n      frame)\n   -  The root frame\n\n-  A screenshot is taken at the outermost/root frame\n\nPerformance Considerations\n--------------------------\n\nCertain features like Collections as parents can result in a lot of\nSelenium requests being issued. If you test against a busy Selenium\nGrid, this can definitely slow things down!\n\nI do not normally recommend the below workarounds (because they bypass\nsome significant benefits of the framwork), but you may find them\nnecessary in your case.\n\n1. Avoid a ``pom.Collection`` parent if it represents many elements\n   (e.g. rows in a large table). Every found element for the collection\n   is searched for the next child.\n2. Reduce POM depth where possible. Since each child causes a Selenium\n   find request on interaction, reducing the size of that parentage can\n   speed things up.\n\nFor the first case, this can be easy to work around with a dynamic model\nif you are targeting a particular item.\n\n.. code:: py\n\n\n   class MyTable(pom.Container):\n\n       rows = pom.Collection('Rows').by_css('tr')\n\n       def row_by_title(self, title: str):\n           label = f'Row by title [{title}]'\n           xpath = f'.//td[text()=\"{title}]/ancestor::tr\"'\n           # Do this IF Selenium performance isn't critical to you (most cases)\n           return pom.Element(label).by_xpath(xpath, parent=rows)\n           # Do this IF and ONLY IF Selenium performance is very important to you\n           return pom.Element(label).by_xpath(xpath)\n\nNote how ``rows`` is on the model directly, but also used as a parent\noverride in the method. However, skipping ``rows`` as a parent means we\ncan forego some more detailed information on failure while making less\nSelenium calls.\n\nMaking Richer Models\n--------------------\n\nGeneric type information can be passed regarding the type of located\nelements.\n\nThis is especially useful for ``pom.ElementCollection``\\ s. For example,\nyou may want to have an ``icon`` property modelled on each dropdown item\nreturned from a collection. This is normally modelled by a Findable\ncomponent (e.g. ``pom.Container`` or ``pom.Element``), but these cannot\nbe used for *found* elements (those returned by\n``pom.ElementCollection.get()``). Enter, generics.\n\nOn construction of *any* findable POM type, you can specify the concrete\ntype returned by ``findable.get()`` or acted on via operations like\n``findable.click()``. By default, this is a\n``pom.dom.ElementReference``, but you may extend it to provide more\nfunctionality.\n\n# TODO: assert Reference parents actually work!\n\n.. code:: py\n\n   class Dropdown(pom.Container):\n\n       class IconItem(pom.dom.ElementReference):\n           icon = pom.Element(\"Icon\").by_css(\".option-icon\")\n\n       items = pom.ElementCollection(\"Dropdown items\", IconItem).by_css(\"option\")\n\n   first_item = ...dropdown.items.get()[0]\n   assert 'gear-icon' in first_item.icon.get_attribute('class')\n\nThe type of ``items`` is now a ``pom.ElementCollection<IconItem>``. If\nit was not specified, it would be a\n``pom.ElementCollection<dom.ElementReference>``.\n\nThis works because while an ElementReference is not \u201cFindable\u201d, it *is*\n\u201cParentable\u201d. That is, it can be a parent, and thus contain other\nmodelled children.\n\nIn the future, a pom.HybridElement may exist that can be used to\nrepresent these items both as a Findable and a Found object to avoid\ncode duplication.\n\nBasically, a rich interface is what you write.\n\n\nChangelog for e2e.pom\n=====================\n\n0.1.8 (2023-01-04)\n------------------\n\n- Remove deprecated _find_within that was causes static analysis issues\n- Added wait methods from ElementReferences\n\n\n0.1.7 (2022-09-20)\n------------------\n\n- Allow ElementCollection to be a direct parent\n\n\n0.1.5 (2022-09-20)\n------------------\n\n- Better error reporting for issues while finding\n- Added DOM presence wait methods\n\n\n0.1.4 (2022-09-12)\n------------------\n\n- [Issue 2] Fix ElementReference naming and parent chain for logging\n\n\n0.1.3 (2022-08-24)\n------------------\n\n- Fix: Missing import\n\n\n0.1.2 (2022-08-22)\n------------------\n\n- Type-hint fixes at the module-level, and a couple method signature fixes\n- New way to wait for page transitions: `pom.Page.expect_transition`\n\n\n0.1.1 (2022-06-26)\n------------------\n\n- Packaging and requirements fixes\n- Added some left-behind critical missing functions!\n- Fixed typos on exception names\n\n\n0.1.0 (2022-05-09)\n------------------\n\n- Exported modelling core to e2e.common, imported and used here\n- Fixed some type-hints based on updated mypy versions\n- Fixed some issues mypy had detecting types in the package at all\n- Updated tags to support Python 3.9, 3.10\n\n\n0.0.1 (11-19-2020)\n------------------\n\n- Initial release! Elements, Collections, IFrames, and Pages.\n\nCopyright 2019-2022 Nicholas Kroeker\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n\n",
    "bugtrack_url": null,
    "license": "Apache 2.0",
    "summary": "Human-friendly rich class-based modeling for the Page Object Model pattern",
    "version": "0.1.8",
    "split_keywords": [
        "e2e",
        "testing",
        "framework",
        "model",
        "selenium",
        "webdriver",
        "pom",
        "page",
        "object"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ce7cdfbcbf0a74d020b1dc2235f7c1930284e46648459d3b010de19d295059a2",
                "md5": "623c4517bfca10851d22bd10d3f29bac",
                "sha256": "36d1e0c511aa1460e401d9c4d30e94d3e43e118107f0f15e549630bd19ba8f46"
            },
            "downloads": -1,
            "filename": "e2e.pom-0.1.8-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "623c4517bfca10851d22bd10d3f29bac",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 17027,
            "upload_time": "2023-01-04T20:00:34",
            "upload_time_iso_8601": "2023-01-04T20:00:34.123722Z",
            "url": "https://files.pythonhosted.org/packages/ce/7c/dfbcbf0a74d020b1dc2235f7c1930284e46648459d3b010de19d295059a2/e2e.pom-0.1.8-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-01-04 20:00:34",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "nickroeker",
    "github_project": "e2e.pom",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "tox": true,
    "lcname": "e2e.pom"
}
        
Elapsed time: 0.07831s