You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/guidelines.rst
+9-9Lines changed: 9 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -50,19 +50,19 @@ Anyone using this library should consult these guidelines whether one is not vio
50
50
51
51
- et cetera
52
52
53
-
- ``__locator__`` MUST NOT return ``WebElement`` instances to prevent ``StaleElementReferenceException``
53
+
- ``__locator__`` MUST NOT return ``ElementHandle`` instances to prevent stale element issues
54
54
55
55
- If you use a ``ROOT`` class attribute, especially in combination with ``ParametrizedLocator``, a ``__locator__`` is generated automatically for you.
56
56
57
-
- Widgets should keep its internal state in reasonable size. Ideally none, but eg. caching header names of tables is perfectly acceptable. Saving ``WebElement`` instances in the widget instance is not recommended.
57
+
- Widgets should keep its internal state in reasonable size. Ideally none, but eg. caching header names of tables is perfectly acceptable. Saving ``ElementHandle`` instances in the widget instance is not recommended.
58
58
59
59
- Think about what to cache and when to invalidate
60
60
61
-
- Never store ``WebElement`` objects.
61
+
- Never store ``ElementHandle`` objects.
62
62
63
-
- Try to shorten the lifetime of any single ``WebElement`` as much as possible
63
+
- Try to shorten the lifetime of any single ``ElementHandle`` as much as possible
64
64
65
-
- This will help against ``StaleElementReferenceException``
65
+
- This will help against stale element issues
66
66
67
67
- Widgets shall log using ``self.logger``. That ensures the log message is prefixed with the widget name and location and gives more insight about what is happening.
68
68
@@ -96,17 +96,17 @@ Anyone using this library should consult these guidelines whether one is not vio
96
96
97
97
- When using ``Browser`` (also applies when writing Widgets)
98
98
99
-
- Ensure you don't invoke methods or attributes on the ``WebElement`` instances returned by ``element()`` or ``elements()``
99
+
- Ensure you use the widgetastic Browser methods rather than direct Playwright Locator methods where possible
100
100
101
-
- Eg. instead of ``element.text`` use ``browser.text(element)`` (applies for all such circumstances). These calls usually do not invoke more than their original counterparts. They only invoke some workarounds if some know issue arises. Check what the ``Browser`` (sub)class offers and if you miss something, create a PR
101
+
- Eg. instead of ``locator.text_content()`` use ``browser.text(locator)`` (applies for all such circumstances). These calls usually do not invoke more than their original counterparts. They only invoke some workarounds if some known issue arises. Check what the ``Browser`` (sub)class offers and if you miss something, create a PR
102
102
103
103
- You don't necessarily have to specify ``self.browser.element(..., parent=self)`` when you are writing a query inside a widget implementation as widgetastic figures this out and does it automatically.
104
104
105
105
- Most of the methods that implement the getters, that would normally be on the element object, take an argument or two for themselves and the rest of ``*args`` and ``**kwargs`` is shoved inside ``element()`` method for resolution, so constructs like ``self.browser.get_attribute('id', self.browser.element('locator', parent=foo))`` are not needed. Just write ``self.browser.get_attribute('id', 'locator', parent=foo)``. Check the method definitions on the ``Browser`` class to see that.
106
106
107
-
- ``element()`` method tries to apply a rudimentary intelligence on the element it resolves. If a locator resolves to a single element, it returns it. If the locator resolves to multiple elements, it tries to filter out the invisible elements and return the first visible one. If none of them is visible, it just returns the first one. Under normal circumstances, standard selenium resolution always returns the first of the resolved elements.
107
+
- ``element()`` method tries to apply a rudimentary intelligence on the element it resolves. If a locator resolves to a single element, it returns it. If the locator resolves to multiple elements, it tries to filter out the invisible elements and return the first visible one. If none of them is visible, it just returns the first one. Under normal circumstances, standard Playwright resolution returns all matching elements.
108
108
109
-
- DO NOT use ``element.find_elements_by_<method>('locator')``, use ``self.browser.element('locator', parent=element)``. It is about as same long and safer.
109
+
- DO NOT use nested locator calls, use ``self.browser.element('locator', parent=element)``. This approach is safer and more consistent with the framework architecture.
110
110
111
111
- Eventually I might wrap the elements as well but I decided to not complicate things for now.
Copy file name to clipboardExpand all lines: docs/internals.rst
+9-12Lines changed: 9 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,15 +3,15 @@ Internal structure of Widgetastic
3
3
4
4
Widgetastic consists of 2 main parts:
5
5
6
-
* `Selenium browser wrapper`_
6
+
* `Playwright browser wrapper`_
7
7
* `Widget system`_
8
8
9
-
.. `Selenium browser wrapper`:
9
+
.. `Playwright browser wrapper`:
10
10
11
-
Selenium browser wrapper
12
-
========================
11
+
Playwright browser wrapper
12
+
===========================
13
13
14
-
This part of the framework serves the purpose of simplifying the interactions with Selenium and also handling some of the quirks we have discovered during development of our testing framework. It also supports "nesting" of the browsers in relation to specific widgets, so it is then easier in the widget layer to implement the lookup fencing. Majority of this functionality is implemented in :py:class:`widgetastic.browser.Browser`.
14
+
This part of the framework serves the purpose of simplifying the interactions with Playwright and also handling some of the quirks we have discovered during development of our testing framework. It also supports "nesting" of the browsers in relation to specific widgets, so it is then easier in the widget layer to implement the lookup fencing. Majority of this functionality is implemented in :py:class:`widgetastic.browser.Browser`.
15
15
16
16
Lookup fencing is a technique that enables the programmer to write locators that are relative to its hosting object. When such locator gets resolved, the parent element is resolved first (and it continues recursively until you hit an "unwrapped" browser that is just a browser). This behaviour is not visible to the outside under normal circumstances and it is achieved by :py:class:`widgetastic.browser.BrowserParentWrapper`.
17
17
@@ -29,20 +29,17 @@ the pattern of `tagname#id.class1.class2` where the tag is optional and at least
29
29
is present, it considers it a CSS locator.
30
30
31
31
If you want to use a complex CSS locator or a different lookup type, you can use
32
-
`selenium-smart-locator <https://pypi.python.org/pypi/selenium-smart-locator>`_ library that is used
33
-
underneath to process all the locators. You can consult the documentation and pass instances of
34
-
``Locator`` instead of a string.
35
-
36
-
This library is already in the requirements, so it is not necessary to install it.
32
+
the built-in ``SmartLocator`` functionality that processes all the locators. You can pass instances of
33
+
``SmartLocator`` or raw locator strings, and the system will automatically handle the conversion.
37
34
38
35
.. `Automatic visibility precedence selection`:
39
36
40
37
Automatic visibility precedence selection
41
38
-----------------------------------------
42
39
43
-
Under normal circumstances, Selenium's ``find_element`` always returns the first element from the query result. But what if there are multiple elements matching the query, the first one being for some reason invisible, and the second one displayed?
40
+
Under normal circumstances, Playwright's ``locator.all()`` returns all elements from the query result. But what if there are multiple elements matching the query, the first one being for some reason invisible, and the second one displayed?
44
41
45
-
Widgetastic's :py:meth:`widgetastic.browser.Browser.element`, :py:meth:`widgetastic.browser.Browser.elements`, and :py:meth:`widgetastic.browser.Browser.wait_for_element` browser methods allow for visibility checking in this case. If the keyword argument ``check_visiblity=True`` is passed to ``elements``, if ``visible=True`` is passed to ``wait_for_elements``, or if the locator object (e.g., a :py:class:`widgetastic.widget.Widget` object) passed to ``element`` contains a ``__locator__`` method as well as a ``CHECK_VISIBILITY=True`` attribute, then the method will return only the visible matching element(s).
42
+
Widgetastic's :py:meth:`widgetastic.browser.Browser.element`, :py:meth:`widgetastic.browser.Browser.elements`, and :py:meth:`widgetastic.browser.Browser.wait_for_element` browser methods allow for visibility checking in this case. If the keyword argument ``check_visiblity=True`` is passed to ``elements``, if ``visible=True`` is passed to ``wait_for_element``, or if the locator object (e.g., a :py:class:`widgetastic.widget.Widget` object) passed to ``element`` contains a ``__locator__`` method as well as a ``CHECK_VISIBILITY=True`` attribute, then the method will return only the visible matching element(s).
0 commit comments