widgetastic.patternfly5 25.2.10.0__py3-none-any.whl → 25.2.17.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {widgetastic.patternfly5-25.2.10.0.dist-info → widgetastic.patternfly5-25.2.17.1.dist-info}/METADATA +9 -12
  2. widgetastic.patternfly5-25.2.17.1.dist-info/RECORD +46 -0
  3. widgetastic_patternfly5/__init__.py +39 -50
  4. widgetastic_patternfly5/charts/alerts_timeline_chart.py +65 -0
  5. widgetastic_patternfly5/charts/bullet_chart.py +3 -5
  6. widgetastic_patternfly5/charts/donut_chart.py +2 -6
  7. widgetastic_patternfly5/charts/line_chart.py +13 -4
  8. widgetastic_patternfly5/components/alert.py +5 -6
  9. widgetastic_patternfly5/components/button.py +7 -8
  10. widgetastic_patternfly5/components/card.py +3 -10
  11. widgetastic_patternfly5/components/chip.py +11 -14
  12. widgetastic_patternfly5/components/clipboard_copy.py +1 -3
  13. widgetastic_patternfly5/components/drawer.py +7 -3
  14. widgetastic_patternfly5/components/dual_list_selector.py +1 -2
  15. widgetastic_patternfly5/components/forms/form_select.py +4 -8
  16. widgetastic_patternfly5/components/forms/radio.py +1 -4
  17. widgetastic_patternfly5/components/menus/context_selector.py +2 -2
  18. widgetastic_patternfly5/components/menus/dropdown.py +38 -13
  19. widgetastic_patternfly5/components/menus/menu.py +19 -18
  20. widgetastic_patternfly5/components/menus/options_menu.py +4 -3
  21. widgetastic_patternfly5/components/menus/select.py +14 -18
  22. widgetastic_patternfly5/components/modal.py +1 -1
  23. widgetastic_patternfly5/components/navigation.py +3 -3
  24. widgetastic_patternfly5/components/pagination.py +3 -8
  25. widgetastic_patternfly5/components/progress.py +2 -3
  26. widgetastic_patternfly5/components/switch.py +8 -7
  27. widgetastic_patternfly5/components/table.py +21 -16
  28. widgetastic_patternfly5/components/tabs.py +7 -4
  29. widgetastic_patternfly5/components/title.py +1 -2
  30. widgetastic_patternfly5/ouia.py +5 -10
  31. widgetastic.patternfly5-25.2.10.0.dist-info/RECORD +0 -45
  32. {widgetastic.patternfly5-25.2.10.0.dist-info → widgetastic.patternfly5-25.2.17.1.dist-info}/WHEEL +0 -0
  33. {widgetastic.patternfly5-25.2.10.0.dist-info → widgetastic.patternfly5-25.2.17.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: widgetastic.patternfly5
3
- Version: 25.2.10.0
3
+ Version: 25.2.17.1
4
4
  Summary: Patternfly5 widget library for Widgetastic.
5
5
  Project-URL: repository, https://github.com/RedHatQE/widgetastic.patternfly5
6
6
  Maintainer-email: Nikhil Dhandre <ndhandre@redhat.com>, Egor Shamardin <eshamard@redhat.com>, Mike Shriver <mshriver@redhat.com>
@@ -21,13 +21,13 @@ License-File: LICENSE
21
21
  Keywords: patternfly,patternfly5,widgetastic
22
22
  Classifier: Programming Language :: Python
23
23
  Classifier: Programming Language :: Python :: 3
24
- Classifier: Programming Language :: Python :: 3.8
25
- Classifier: Programming Language :: Python :: 3.9
26
- Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
27
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
28
  Classifier: Topic :: Software Development :: Quality Assurance
29
29
  Classifier: Topic :: Software Development :: Testing
30
- Requires-Python: >=3.8
30
+ Requires-Python: >=3.11
31
31
  Requires-Dist: widgetastic-core>=1.0.6
32
32
  Provides-Extra: dev
33
33
  Requires-Dist: codecov; extra == 'dev'
@@ -55,15 +55,12 @@ Description-Content-Type: text/markdown
55
55
  <a href="https://github.com/RedHatQE/widgetastic.patternfly5/actions/workflows/tests.yaml">
56
56
  <img alt="github actions" src="https://github.com/RedHatQE/widgetastic.patternfly5/actions/workflows/tests.yaml/badge.svg">
57
57
  </a>
58
- <a href="https://pypi.org/project/black">
59
- <img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg">
60
- </a>
61
58
  <a href="https://results.pre-commit.ci/latest/github/RedHatQE/widgetastic.patternfly5/main">
62
59
  <img alt="pre: black" src="https://results.pre-commit.ci/badge/github/RedHatQE/widgetastic.patternfly5/main.svg">
63
60
  </a>
64
61
  </p>
65
62
 
66
- This library offers Widgetastic Widgets for [PatternFly v5](https://www.patternfly.org/), serving as an extended
63
+ This library offers Widgetastic Widgets for [PatternFly v5/v6](https://www.patternfly.org/), serving as an extended
67
64
  itteration of [widgetastic.patternfly4](https://github.com/RedHatQE/widgetastic.patternfly4).
68
65
 
69
66
 
@@ -111,7 +108,7 @@ itteration of [widgetastic.patternfly4](https://github.com/RedHatQE/widgetastic.
111
108
  - [pie-chart](https://www.patternfly.org/charts/pie-chart)
112
109
 
113
110
  ### Patterns:
114
- - [card-view](https://patternfly-react-main.surge.sh/patterns/card-view)
111
+ - [card-view](https://www.patternfly.org/patterns/card-view)
115
112
 
116
113
 
117
114
  ### Contribution guide
@@ -135,7 +132,7 @@ pre-commit install
135
132
 
136
133
  ### Testing
137
134
 
138
- The library has selenium tests that are performed against [Patternfly React docs](https://patternfly-react-main.surge.sh).
135
+ The library has selenium tests that are performed against [Patternfly v6 docs](https://www.patternfly.org) and [Patternfly v5 docs](https://v5-archive.patternfly.org).
139
136
  It's also configured to run the tests every time when a new version of that page is released.
140
137
 
141
138
  Tests spawn a container from official selenium image - [selenium/standalone-{chrome/firefox}](https://hub.docker.com/u/selenium).
@@ -149,5 +146,5 @@ Use `-n` key to specify a number
149
146
  of workers:
150
147
 
151
148
  ```bash
152
- BROWSER=firefox pytest -v testing -n 4
149
+ pytest --browser-name firefox --pf-version v5 -n 2 -vv
153
150
  ```
@@ -0,0 +1,46 @@
1
+ widgetastic_patternfly5/__init__.py,sha256=Yv3sZRQsi__Wjp5K5odVRZFr6-UQsPLL6lk6g6GWZIg,3822
2
+ widgetastic_patternfly5/ouia.py,sha256=ZAUgIka9odt4yCKQxD2R0fZ30hZKPtOAL-Fjw2xIGS0,4046
3
+ widgetastic_patternfly5/charts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ widgetastic_patternfly5/charts/alerts_timeline_chart.py,sha256=U7hJvxAG1Wgj9WFt5QxAmLh9cJm2qzs2YHs2wfEW0Pk,2377
5
+ widgetastic_patternfly5/charts/boxplot_chart.py,sha256=6Ek6gwbmwNeazy-5o2fVfvkjpd6bhbTyitiPomvLBts,405
6
+ widgetastic_patternfly5/charts/bullet_chart.py,sha256=zfAdvxzPFqeGFzDoqJIUxwkERUlHfPohHOjzPJEjVdw,3680
7
+ widgetastic_patternfly5/charts/donut_chart.py,sha256=RmDKyWjhKnGWQwZ1twPN837LYuvlF1inQlYhIgJgFxU,2570
8
+ widgetastic_patternfly5/charts/legend.py,sha256=fhAg-FhsWpvi91BZ29EztKO3QfANRW-hnfzIkq45q3Y,2983
9
+ widgetastic_patternfly5/charts/line_chart.py,sha256=9gjoUqWopSYTng0iRpvppm-CL-QA8H_HpTvFddg0sB4,3995
10
+ widgetastic_patternfly5/charts/pie_chart.py,sha256=rIxMv6vPERj9FnTp8daejL7MxUTKFCTj9057C1KuuKw,218
11
+ widgetastic_patternfly5/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ widgetastic_patternfly5/components/alert.py,sha256=8wF4348n7Yp6BnOlbDNGw4_fFKyyjzgpQDOe9a96EsI,2579
13
+ widgetastic_patternfly5/components/breadcrumb.py,sha256=_lQ7pqmh2P9FSwMae_quUTteHsfXFlQvYaXE4Z1gK1g,2035
14
+ widgetastic_patternfly5/components/button.py,sha256=dduqxjnTHsHLkPO9TjbWO4HUfpiObMM4yuq3_q8XlA0,3539
15
+ widgetastic_patternfly5/components/card.py,sha256=YScmzLsxO72ITZFz9u3vyxpD2r0QAzP4yaBmJD9FcZE,2677
16
+ widgetastic_patternfly5/components/chip.py,sha256=t5_9oTJ__9ccwrCMzVYllDFY7oyJcMwwWKbr3jiIK0w,11218
17
+ widgetastic_patternfly5/components/clipboard_copy.py,sha256=r9RESokgZ7s5C2_ByOGLqfIjUx15-ZzFi5usSTdb-ac,1292
18
+ widgetastic_patternfly5/components/description_list.py,sha256=sVhKwKnvJguZh9FqyPC1NU2UA_w7uA3ugkY5eoVRlPk,989
19
+ widgetastic_patternfly5/components/drawer.py,sha256=kr2q042x4ghxu6T_C13mlRZZ-gZavGsVvM9a1GVYZZA,1084
20
+ widgetastic_patternfly5/components/dual_list_selector.py,sha256=jL1SOfnR5z_rWniN-KU9a26n-0HxBcL2pJbBcOFT2b8,4839
21
+ widgetastic_patternfly5/components/expandable_section.py,sha256=QCqonn1kiYfL-mGcjwrG6x4TiJBr9RKXZvyDerVTUmQ,1876
22
+ widgetastic_patternfly5/components/modal.py,sha256=uaOsMxWvgCKrF61YX5Dh9z4YCtB0uheQdQTF6cMswxY,2000
23
+ widgetastic_patternfly5/components/navigation.py,sha256=uaAc-FoOdYt0xiH_oPK564KjztQLEusk3LhhHSX4PQ4,5333
24
+ widgetastic_patternfly5/components/pagination.py,sha256=rumYxlMJcO7F0uQtIU24oANwi6JHHzDkD-YMo-eyltA,8707
25
+ widgetastic_patternfly5/components/popover.py,sha256=_XZlM4v8gsmen73DoSpylMXAMeEkdkjRsuBIIKHHhtE,2242
26
+ widgetastic_patternfly5/components/progress.py,sha256=UXNjRgy7aW0YerRWR6cwMF-9AjitI6LO8qlOdz0dYW8,1391
27
+ widgetastic_patternfly5/components/slider.py,sha256=B9gr8mnndLWivSlS9lIRd3SW6W5Iev9ESnQE9b0A55Y,3128
28
+ widgetastic_patternfly5/components/switch.py,sha256=7-ezYAQ3T_cz70GBIW78vTlVaDmRGRhNgi1hWg14Ig8,2226
29
+ widgetastic_patternfly5/components/table.py,sha256=fA5LM7buASXOH3z32t1D5ZkFXyMa3ZZmzFJ6kjF73ZQ,17183
30
+ widgetastic_patternfly5/components/tabs.py,sha256=tSuS6x3_rnc5z8yUW_75ZtkdFOzzWPMmMa48VEEZWQk,2260
31
+ widgetastic_patternfly5/components/title.py,sha256=bIUzFaptG2i84CF4-AMfjbmdVeKYR32wkOBH9P6V3XQ,920
32
+ widgetastic_patternfly5/components/date_and_time/calendar_month.py,sha256=zGIgIsYEWH3VPVNBVIPVaKlnRY61648tM8rGtohmy7s,3307
33
+ widgetastic_patternfly5/components/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ widgetastic_patternfly5/components/forms/form_select.py,sha256=ht_go5lOXhMzq_FyLxS1ny9jaiBkRI6K_5vMv1DASaw,3531
35
+ widgetastic_patternfly5/components/forms/radio.py,sha256=d1fpzoicgSDgoV8K9bHlXFvHEjH3zw59t_WbxTGZyQ8,2009
36
+ widgetastic_patternfly5/components/menus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
+ widgetastic_patternfly5/components/menus/context_selector.py,sha256=Bqj8MrxJypLfjcqrrKQj9jfFWHeSWbHIVcH2aA6sRQ8,1156
38
+ widgetastic_patternfly5/components/menus/dropdown.py,sha256=NUPpKIV-mBzmFVRPjWu0FiCWc9DjcRErK_FOxfag8y0,10471
39
+ widgetastic_patternfly5/components/menus/menu.py,sha256=sRkb46XWMNGueDCkOjs4vyb9Ehjiru71DY3MD2qsorM,8138
40
+ widgetastic_patternfly5/components/menus/menu_toggle.py,sha256=PBwNvg6E2RPdCG6ALBUqyTZxCwThJgk5S-9ghTiZ9hM,1029
41
+ widgetastic_patternfly5/components/menus/options_menu.py,sha256=-7pRukhgxln0rMV77VhNyQ-njLPAE6Wnp2vNAoJUXZk,1474
42
+ widgetastic_patternfly5/components/menus/select.py,sha256=X8DApXg_7tLIOulpmEP-f09bDShYL8jcEb1tYvNHwrE,6482
43
+ widgetastic.patternfly5-25.2.17.1.dist-info/METADATA,sha256=u3xxVUmW53slGMz9XD6BL7XP-TIGG1sH5Khopll1Vw8,6826
44
+ widgetastic.patternfly5-25.2.17.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
45
+ widgetastic.patternfly5-25.2.17.1.dist-info/licenses/LICENSE,sha256=nDhhj8jp0XsTdmvWpTWFpOKVn0LPXPb6ecA9zFF3Exk,576
46
+ widgetastic.patternfly5-25.2.17.1.dist-info/RECORD,,
@@ -1,75 +1,64 @@
1
1
  from .charts.boxplot_chart import BoxPlotChart
2
2
  from .charts.bullet_chart import BulletChart
3
3
  from .charts.donut_chart import DonutChart
4
- from .charts.legend import DataPoint
5
- from .charts.legend import Legend
4
+ from .charts.legend import DataPoint, Legend
6
5
  from .charts.line_chart import LineChart
7
6
  from .charts.pie_chart import PieChart
8
7
  from .components.alert import Alert
9
8
  from .components.breadcrumb import BreadCrumb
10
9
  from .components.button import Button
11
- from .components.card import Card
12
- from .components.card import CardCheckBox
13
- from .components.card import CardForCardGroup
14
- from .components.card import CardGroup
15
- from .components.card import CardWithActions
16
- from .components.chip import CategoryChipGroup
17
- from .components.chip import Chip
18
- from .components.chip import ChipGroup
19
- from .components.chip import ChipGroupToolbar
20
- from .components.chip import ChipGroupToolbarCategory
21
- from .components.chip import ChipReadOnlyError
22
- from .components.chip import StandAloneChipGroup
10
+ from .components.card import Card, CardCheckBox, CardForCardGroup, CardGroup, CardWithActions
11
+ from .components.chip import (
12
+ CategoryChipGroup,
13
+ Chip,
14
+ ChipGroup,
15
+ ChipGroupToolbar,
16
+ ChipGroupToolbarCategory,
17
+ ChipReadOnlyError,
18
+ StandAloneChipGroup,
19
+ )
23
20
  from .components.clipboard_copy import ClipboardCopy
24
21
  from .components.date_and_time.calendar_month import CalendarMonth
25
22
  from .components.description_list import DescriptionList
26
23
  from .components.drawer import Drawer
27
- from .components.dual_list_selector import DualListSelector
28
- from .components.dual_list_selector import SearchDualListSelector
24
+ from .components.dual_list_selector import DualListSelector, SearchDualListSelector
29
25
  from .components.expandable_section import ExpandableSection
30
- from .components.forms.form_select import FormSelect
31
- from .components.forms.form_select import FormSelectDisabled
32
- from .components.forms.form_select import FormSelectOptionDisabled
33
- from .components.forms.form_select import FormSelectOptionNotFound
26
+ from .components.forms.form_select import (
27
+ FormSelect,
28
+ FormSelectDisabled,
29
+ FormSelectOptionDisabled,
30
+ FormSelectOptionNotFound,
31
+ )
34
32
  from .components.forms.radio import Radio
35
33
  from .components.menus.context_selector import ContextSelector
36
- from .components.menus.dropdown import Dropdown
37
- from .components.menus.dropdown import DropdownDisabled
38
- from .components.menus.dropdown import DropdownItemDisabled
39
- from .components.menus.dropdown import DropdownItemNotFound
40
- from .components.menus.dropdown import GroupDropdown
41
- from .components.menus.menu import CheckboxMenu
42
- from .components.menus.menu import Menu
43
- from .components.menus.menu import MenuItemDisabled
44
- from .components.menus.menu import MenuItemNotFound
34
+ from .components.menus.dropdown import (
35
+ Dropdown,
36
+ DropdownDisabled,
37
+ DropdownItemDisabled,
38
+ DropdownItemNotFound,
39
+ GroupDropdown,
40
+ )
41
+ from .components.menus.menu import CheckboxMenu, Menu, MenuItemDisabled, MenuItemNotFound
45
42
  from .components.menus.menu_toggle import SplitButtonDropdown
46
43
  from .components.menus.options_menu import OptionsMenu
47
- from .components.menus.select import CheckboxSelect
48
- from .components.menus.select import Select
49
- from .components.menus.select import SelectItemDisabled
50
- from .components.menus.select import SelectItemNotFound
51
- from .components.modal import Modal
52
- from .components.modal import ModalItemNotFound
53
- from .components.navigation import Navigation
54
- from .components.navigation import NavSelectionNotFound
55
- from .components.pagination import CompactPagination
56
- from .components.pagination import Pagination
57
- from .components.pagination import PaginationNavDisabled
44
+ from .components.menus.select import CheckboxSelect, Select, SelectItemDisabled, SelectItemNotFound
45
+ from .components.modal import Modal, ModalItemNotFound
46
+ from .components.navigation import Navigation, NavSelectionNotFound
47
+ from .components.pagination import CompactPagination, Pagination, PaginationNavDisabled
58
48
  from .components.popover import Popover
59
49
  from .components.progress import Progress
60
- from .components.slider import InputSlider
61
- from .components.slider import Slider
62
- from .components.switch import Switch
63
- from .components.switch import SwitchDisabled
64
- from .components.table import ColumnNotExpandable
65
- from .components.table import CompoundExpandableTable
66
- from .components.table import ExpandableTable
67
- from .components.table import PatternflyTable
68
- from .components.table import RowNotExpandable
50
+ from .components.slider import InputSlider, Slider
51
+ from .components.switch import Switch, SwitchDisabled
52
+ from .components.table import (
53
+ ColumnNotExpandable,
54
+ CompoundExpandableTable,
55
+ ExpandableTable,
56
+ PatternflyTable,
57
+ RowNotExpandable,
58
+ )
69
59
  from .components.tabs import Tab
70
60
  from .components.title import Title
71
61
 
72
-
73
62
  __all__ = [
74
63
  "Alert",
75
64
  "BreadCrumb",
@@ -0,0 +1,65 @@
1
+ from widgetastic_patternfly5.charts.line_chart import LineChart
2
+
3
+
4
+ class AlertsTimelineChart(LineChart):
5
+ """Represents the Patternfly Alerts Timeline.
6
+
7
+ https://v5-archive.patternfly.org/charts/bar-chart/#alerts-timeline
8
+
9
+ Args:
10
+ id: If you want to look the input up by id, use this parameter, pass the id.
11
+ locator: If you have specific locator else it will take pf-chart.
12
+ """
13
+
14
+ Y_AXIS_ROW = "./*[name()='svg']/*[name()='g'][3]/*[name()='g']"
15
+ Y_AXIS_ROW_LINE = "./*[name()='path']"
16
+
17
+ TOOLTIP = "./*[name()='svg']/*[name()='g'][5]"
18
+ TOOLTIP_X_AXIS_LABLE = None
19
+ TOOLTIP_LABLES = None
20
+ TOOLTIP_VALUES = ".//*[name()='text']/*[name()='tspan']"
21
+
22
+ @property
23
+ def _y_axis_labels_map(self):
24
+ """Labels and its webelements in the Y axis
25
+ NOTE: Y labels might not match the number of rows in Y axes.
26
+ """
27
+ return {self.browser.text(el): el for el in self.browser.elements(self.Y_AXIS_LABELS)}
28
+
29
+ @property
30
+ def labels_y_axis(self):
31
+ """Return Y-Axis labels."""
32
+ return list(self._y_axis_labels_map.keys())
33
+
34
+ @property
35
+ def _y_axis_map(self):
36
+ """Dict with Y axis row number as key and the contained lines in each row as values."""
37
+ y_axis_rows_els = self.browser.elements(self.Y_AXIS_ROW)
38
+ y_axis_map = {}
39
+ for row_n, row_el in enumerate(y_axis_rows_els):
40
+ y_axis_map[row_n] = self.browser.elements(self.Y_AXIS_ROW_LINE, parent=row_el)
41
+ return y_axis_map
42
+
43
+ def read(self):
44
+ """Read chart data."""
45
+ _data = []
46
+
47
+ for lines_el in self._y_axis_map.values():
48
+ _row_data = []
49
+ for line_el in lines_el:
50
+ self.browser.move_to_element(line_el)
51
+ self.browser.click(line_el)
52
+ tooltip_el = self.browser.wait_for_element(self.TOOLTIP)
53
+
54
+ label_data = {}
55
+ value_els = self.browser.elements(self.TOOLTIP_VALUES, parent=tooltip_el)
56
+ for value_el in value_els:
57
+ key, value = self.browser.text(value_el).lower().split(": ")
58
+ label_data[key] = value
59
+
60
+ _row_data.append(label_data)
61
+ _data.append(_row_data)
62
+
63
+ # Just move cursor to avoid mismatch of legend and tooltip text.
64
+ self.root_browser.move_to_element(".//body")
65
+ return _data
@@ -1,12 +1,10 @@
1
1
  import re
2
2
 
3
3
  from widgetastic.utils import ParametrizedLocator
4
- from widgetastic.widget import Text
5
- from widgetastic.widget import View
4
+ from widgetastic.widget import Text, View
6
5
  from widgetastic.xpath import quote
7
6
 
8
- from .legend import DataPoint
9
- from .legend import Legend
7
+ from .legend import DataPoint, Legend
10
8
 
11
9
 
12
10
  class BulletChart(View):
@@ -36,7 +34,7 @@ class BulletChart(View):
36
34
  def __init__(self, parent=None, id=None, locator=None, logger=None, *args, **kwargs):
37
35
  View.__init__(self, parent=parent, logger=logger)
38
36
  if id:
39
- self.locator = ".//div[@id={}]".format(quote(id))
37
+ self.locator = f".//div[@id={quote(id)}]"
40
38
  elif locator:
41
39
  self.locator = locator
42
40
  else:
@@ -1,17 +1,13 @@
1
1
  import re
2
2
 
3
- from widgetastic.widget import ClickableMixin
4
- from widgetastic.widget import ParametrizedLocator
5
- from widgetastic.widget import ParametrizedView
6
- from widgetastic.widget import View
7
- from widgetastic.widget import Widget
3
+ from widgetastic.widget import ClickableMixin, ParametrizedLocator, ParametrizedView, View, Widget
8
4
  from widgetastic.xpath import quote
9
5
 
10
6
 
11
7
  class DonutLegendItem(ParametrizedView, ClickableMixin):
12
8
  PARAMETERS = ("label_text",)
13
9
  ROOT = ParametrizedLocator(
14
- ".//*[name()='text']" "/*[name()='tspan' and contains(., '{label_text}')]"
10
+ ".//*[name()='text']/*[name()='tspan' and contains(., '{label_text}')]"
15
11
  )
16
12
  ALL_ITEMS = ".//*[name()='text']/*[name()='tspan']"
17
13
  LEGEND_ITEM_REGEX = re.compile(r"(.*?): ([\d]+)")
@@ -1,5 +1,4 @@
1
- from widgetastic.widget import ParametrizedLocator
2
- from widgetastic.widget import View
1
+ from widgetastic.widget import ParametrizedLocator, View
3
2
  from widgetastic.xpath import quote
4
3
 
5
4
  from .legend import Legend
@@ -37,7 +36,7 @@ class LineChart(View):
37
36
  assert id or locator, "Provide id or locator."
38
37
 
39
38
  if id:
40
- self.locator = ".//div[@id={}]".format(quote(id))
39
+ self.locator = f".//div[@id={quote(id)}]"
41
40
  else:
42
41
  self.locator = locator
43
42
 
@@ -96,7 +95,17 @@ class LineChart(View):
96
95
  self.browser.elements(self.TOOLTIP_LABLES, parent=tooltip_el),
97
96
  self.browser.elements(self.TOOLTIP_VALUES, parent=tooltip_el),
98
97
  ):
99
- label_data[self.browser.text(label_el)] = self.browser.text(value_el)
98
+ # Get the label text and handle empty labels
99
+ label_txt = self.browser.text(label_el)
100
+ if label_txt == "":
101
+ label_txt = "Unknown"
102
+
103
+ # Update label_data with the value
104
+ value_txt = self.browser.text(value_el)
105
+ if label_txt in label_data:
106
+ label_data[label_txt] = f"{label_data[label_txt]}, {value_txt}"
107
+ else:
108
+ label_data[label_txt] = value_txt
100
109
 
101
110
  _data[x_axis_label] = label_data
102
111
 
@@ -57,12 +57,11 @@ class BaseAlert:
57
57
  for class_ in self.browser.classes(self):
58
58
  if class_ in self.TYPE_MAPPING:
59
59
  return self.TYPE_MAPPING[class_]
60
- else:
61
- raise ValueError(
62
- "Could not find a proper alert type."
63
- f"\nAvailable classes: {self.TYPE_MAPPING!r} "
64
- f"\nAlert has: {self.browser.classes(self)!r}"
65
- )
60
+ raise ValueError(
61
+ "Could not find a proper alert type."
62
+ f"\nAvailable classes: {self.TYPE_MAPPING!r} "
63
+ f"\nAlert has: {self.browser.classes(self)!r}"
64
+ )
66
65
 
67
66
  def assert_no_error(self):
68
67
  """Asserts that the warning is not of the error type."""
@@ -1,6 +1,5 @@
1
1
  from widgetastic.utils import ParametrizedLocator
2
- from widgetastic.widget import ClickableMixin
3
- from widgetastic.widget import Widget
2
+ from widgetastic.widget import ClickableMixin, Widget
4
3
  from widgetastic.xpath import quote
5
4
 
6
5
 
@@ -36,7 +35,7 @@ class BaseButton:
36
35
  return check1 or check2 or self.browser.get_attribute("disabled", self) is not None
37
36
 
38
37
  def __repr__(self):
39
- return "{}{}".format(type(self).__name__, self.locator)
38
+ return f"{type(self).__name__}{self.locator}"
40
39
 
41
40
  @property
42
41
  def title(self):
@@ -69,25 +68,25 @@ class Button(BaseButton, Widget, ClickableMixin):
69
68
  if kwargs: # classes should have been the only kwarg combined with text args
70
69
  raise TypeError("If you pass button text then only pass classes in addition")
71
70
  if len(text) == 1:
72
- locator_conditions = "normalize-space(.)={}".format(quote(text[0]))
71
+ locator_conditions = f"normalize-space(.)={quote(text[0])}"
73
72
  elif len(text) == 2 and text[0].lower() == "contains":
74
- locator_conditions = "contains(normalize-space(.), {})".format(quote(text[1]))
73
+ locator_conditions = f"contains(normalize-space(.), {quote(text[1])})"
75
74
  else:
76
75
  raise TypeError("An illegal combination of args/kwargs")
77
76
  else:
78
77
  # Join the kwargs, if any
79
78
  locator_conditions = " and ".join(
80
- "@{}={}".format(attr, quote(value)) for attr, value in kwargs.items()
79
+ f"@{attr}={quote(value)}" for attr, value in kwargs.items()
81
80
  )
82
81
 
83
82
  if classes:
84
83
  if locator_conditions:
85
84
  locator_conditions += " and "
86
85
  locator_conditions += " and ".join(
87
- "contains(@class, {})".format(quote(klass)) for klass in classes
86
+ f"contains(@class, {quote(klass)})" for klass in classes
88
87
  )
89
88
  if locator_conditions:
90
- locator_conditions = "and ({})".format(locator_conditions)
89
+ locator_conditions = f"and ({locator_conditions})"
91
90
 
92
91
  return (
93
92
  ".//*[(self::a or self::button or (self::input and "
@@ -1,8 +1,5 @@
1
1
  from widgetastic.utils import ParametrizedLocator
2
- from widgetastic.widget import Checkbox
3
- from widgetastic.widget import GenericLocatorWidget
4
- from widgetastic.widget import ParametrizedView
5
- from widgetastic.widget import View
2
+ from widgetastic.widget import Checkbox, GenericLocatorWidget, ParametrizedView, View
6
3
 
7
4
  from widgetastic_patternfly5.components.menus.dropdown import Dropdown
8
5
 
@@ -34,9 +31,7 @@ class BaseCard:
34
31
 
35
32
 
36
33
  class Card(BaseCard, GenericLocatorWidget):
37
- DEFAULT_LOCATOR = (
38
- ".//div[@data-ouia-component-type='PF5/Card'] | .//article[contains(@class, '-c-card')]"
39
- )
34
+ DEFAULT_LOCATOR = ".//div[contains(@data-ouia-component-type, '/Card')] | .//article[contains(@class, '-c-card')]"
40
35
 
41
36
  def __init__(self, parent, locator=None, logger=None):
42
37
  locator = locator or self.DEFAULT_LOCATOR
@@ -46,9 +41,7 @@ class Card(BaseCard, GenericLocatorWidget):
46
41
 
47
42
 
48
43
  class CardForCardGroup(BaseCard, ParametrizedView):
49
- DEFAULT_LOCATOR = (
50
- "(.//div[@data-ouia-component-type='PF5/Card'] | .//article[contains(@class, '-c-card')])"
51
- )
44
+ DEFAULT_LOCATOR = "(.//div[contains(@data-ouia-component-type, '/Card')] | .//article[contains(@class, '-c-card')])"
52
45
 
53
46
  def __init__(self, parent, locator=None, logger=None, **kwargs):
54
47
  View.__init__(self, parent, logger=logger, **kwargs)
@@ -1,9 +1,6 @@
1
1
  # TODO: This imported directly form wt.pfy4. I thnk we need to restructure it.
2
2
  from wait_for import wait_for
3
- from widgetastic.widget import ParametrizedLocator
4
- from widgetastic.widget import ParametrizedView
5
- from widgetastic.widget import Text
6
- from widgetastic.widget import View
3
+ from widgetastic.widget import ParametrizedLocator, ParametrizedView, Text, View
7
4
 
8
5
  from .button import Button
9
6
 
@@ -15,18 +12,18 @@ class ChipReadOnlyError(Exception):
15
12
 
16
13
 
17
14
  CHIP_ROOT = (
18
- ".//div[contains(@class, '-c-chip') and not(contains(@class, '-m-overflow')) "
19
- "and not(contains(@class, '-c-chip-group'))]"
15
+ ".//*[contains(@data-ouia-component-type, '/Chip') and not(contains(@class, '-m-overflow')) "
16
+ "and not(contains(@class, '-c-chip-group') or contains(@class, '-c-label-group'))]"
20
17
  )
21
- CHIP_TEXT = ".//span[contains(@class, '-c-chip__text')]"
18
+ CHIP_TEXT = ".//span[contains(@class, '-c-chip__text') or contains(@class, '-c-label__text')]"
22
19
  CHIP_BADGE = ".//span[contains(@class, '-c-badge')]"
23
- GROUP_ROOT = ".//div[contains(@class, '-c-chip-group') and @role='group']"
20
+ GROUP_ROOT = ".//div[(contains(@class, '-c-chip-group') and @role='group') or contains(@class, '-c-label-group')]"
24
21
  CATEGORY_GROUP_ROOT = (
25
- ".//div[contains(@class, '-c-chip-group') and @role='group' "
22
+ ".//div[((contains(@class, '-c-chip-group') and @role='group') or contains(@class, '-c-label-group')) "
26
23
  "and contains(@class, 'pf-m-category')]"
27
24
  )
28
- CATEGORY_LABEL = ".//span[contains(@class, '-c-chip-group__label')]"
29
- CATEGORY_CLOSE = ".//div[contains(@class, '-c-chip-group__close')]/button"
25
+ CATEGORY_LABEL = ".//span[contains(@class, '-group__label')]"
26
+ CATEGORY_CLOSE = ".//div[contains(@class, '-group__close')]/button"
30
27
  # For backwards compatibility
31
28
  OLD_GROUP_ROOT = ".//ul[contains(@class, '-c-chip-group')]"
32
29
  TOOLBAR_GROUP_LABEL = "./li/*[contains(@class, '-c-chip-group__label')]"
@@ -44,7 +41,7 @@ class _BaseChip(View):
44
41
 
45
42
  _text = Text(CHIP_TEXT)
46
43
  _badge = Text(f"{CHIP_TEXT}/{CHIP_BADGE}")
47
- button = Button(**{"aria-label": "close"})
44
+ button = Button()
48
45
 
49
46
  @property
50
47
  def badge(self):
@@ -122,7 +119,7 @@ class OverflowChip(_BaseChip):
122
119
  The 'Show More'/'Show Less' button is essentially a special kind of chip
123
120
  """
124
121
 
125
- ROOT = ".//button[contains(@class, '-c-chip') and contains(@class, 'pf-m-overflow')]"
122
+ ROOT = ".//button[(contains(@class, '-c-chip') or contains(@class, '-c-label')) and contains(@class, 'pf-m-overflow')]"
126
123
 
127
124
  def _show_less_shown(self):
128
125
  return self.text.replace(" ", "").lower() == "showless"
@@ -327,7 +324,7 @@ class ChipGroupToolbar(View):
327
324
  # The parent of the chip group toolbar can be any element type
328
325
  # The locator should be the parent node which holds all the pf-c-chip-group elements
329
326
  TOOLBAR_LOCATOR = (
330
- ".//ul[contains(@class, '-c-chip-group') and " "contains(@class, 'pf-m-toolbar')]/parent::*"
327
+ ".//ul[contains(@class, '-c-chip-group') and contains(@class, 'pf-m-toolbar')]/parent::*"
331
328
  )
332
329
 
333
330
  overflow = OldOverflowChip(
@@ -1,7 +1,5 @@
1
1
  from widgetastic.utils import ParametrizedLocator
2
- from widgetastic.widget import GenericLocatorWidget
3
- from widgetastic.widget import Text
4
- from widgetastic.widget import TextInput
2
+ from widgetastic.widget import GenericLocatorWidget, Text, TextInput
5
3
 
6
4
  from widgetastic_patternfly5 import Button
7
5
 
@@ -1,14 +1,17 @@
1
+ from wait_for import wait_for
1
2
  from widgetastic.utils import ParametrizedLocator
2
3
  from widgetastic.widget import View
3
4
 
5
+ from widgetastic_patternfly5 import Button
6
+
4
7
 
5
8
  class BaseDrawer:
6
- """Represents drawer component for pf5
9
+ """Represents drawer component for pf5/pf6
7
10
 
8
11
  https://www.patternfly.org/components/drawer
9
12
  """
10
13
 
11
- CLOSE = ".//button[@aria-label='Close drawer panel']"
14
+ close_btn = Button(locator=".//div[contains(@class, '-c-drawer__close')]/button")
12
15
 
13
16
  @property
14
17
  def is_open(self):
@@ -18,7 +21,8 @@ class BaseDrawer:
18
21
  def close(self):
19
22
  """Close drawer."""
20
23
  if self.is_open:
21
- self.browser.click(self.browser.element(self.CLOSE))
24
+ self.close_btn.click()
25
+ wait_for(lambda: not self.is_open, num_sec=10)
22
26
 
23
27
 
24
28
  class Drawer(BaseDrawer, View):
@@ -1,5 +1,4 @@
1
- from widgetastic.widget import GenericLocatorWidget
2
- from widgetastic.widget import TextInput
1
+ from widgetastic.widget import GenericLocatorWidget, TextInput
3
2
 
4
3
  from .button import Button
5
4
 
@@ -81,18 +81,14 @@ class BaseFormSelect:
81
81
  FormSelectOptionNotFound: if option not found
82
82
  """
83
83
  if not self.is_enabled:
84
- raise FormSelectDisabled("{} is not enabled".format(repr(self)))
84
+ raise FormSelectDisabled(f"{repr(self)} is not enabled")
85
85
  if value not in self.all_options:
86
86
  raise FormSelectOptionNotFound(
87
- 'Option "{}" not found in {}. Available options: {}'.format(
88
- value, repr(self), self.all_options
89
- )
87
+ f'Option "{value}" not found in {repr(self)}. Available options: {self.all_options}'
90
88
  )
91
89
  elif value not in self.all_enabled_options:
92
90
  raise FormSelectOptionDisabled(
93
- 'Option "{}" is disabled in {}. Enabled options are: {}'.format(
94
- value, repr(self), self.all_enabled_options
95
- )
91
+ f'Option "{value}" is disabled in {repr(self)}. Enabled options are: {self.all_enabled_options}'
96
92
  )
97
93
  self._select_element.select_by_visible_text(value)
98
94
 
@@ -101,7 +97,7 @@ class BaseFormSelect:
101
97
  return self.browser.text(self._select_element.first_selected_option)
102
98
 
103
99
  def __repr__(self):
104
- return "{}({!r})".format(type(self).__name__, self.locator)
100
+ return f"{type(self).__name__}({self.locator!r})"
105
101
 
106
102
 
107
103
  class FormSelect(BaseFormSelect, GenericLocatorWidget):
@@ -1,7 +1,4 @@
1
- from widgetastic.widget import Checkbox
2
- from widgetastic.widget import ParametrizedLocator
3
- from widgetastic.widget import Text
4
- from widgetastic.widget import View
1
+ from widgetastic.widget import Checkbox, ParametrizedLocator, Text, View
5
2
 
6
3
 
7
4
  class BaseRadio:
@@ -3,10 +3,10 @@ from .select import Select
3
3
 
4
4
  class BaseContextSelector:
5
5
  ITEMS_LOCATOR = (
6
- ".//ul[@class='pf-v5-c-menu__list' or @class='pf-c-context-selector__menu-list']/li"
6
+ ".//ul[contains(@class, '-c-menu__list') or @class='pf-c-context-selector__menu-list']/li"
7
7
  )
8
8
  ITEM_LOCATOR = (
9
- ".//*[(contains(@class, 'pf-v5-c-menu__item') or contains(@class, "
9
+ ".//*[(contains(@class, '-c-menu__list-item') or contains(@class, "
10
10
  "'pf-c-context-selector__menu-list-item'))"
11
11
  " and normalize-space(.)={}]"
12
12
  )