robo_appian 0.0.11__tar.gz → 0.0.13__tar.gz
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.
Potentially problematic release.
This version of robo_appian might be problematic. Click here for more details.
- robo_appian-0.0.13/PKG-INFO +67 -0
- robo_appian-0.0.13/README.md +48 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/pyproject.toml +1 -1
- robo_appian-0.0.13/robo_appian/components/ButtonUtils.py +105 -0
- robo_appian-0.0.13/robo_appian/components/DateUtils.py +77 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/components/DropdownUtils.py +117 -5
- robo_appian-0.0.13/robo_appian/components/InputUtils.py +165 -0
- robo_appian-0.0.13/robo_appian/components/LabelUtils.py +46 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/components/LinkUtils.py +9 -9
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/components/SearchDropdownUtils.py +1 -1
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/components/SearchInputUtils.py +23 -28
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/components/TabUtils.py +24 -29
- robo_appian-0.0.13/robo_appian/components/TableUtils.py +122 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/controllers/ComponentDriver.py +4 -4
- robo_appian-0.0.13/robo_appian/utils/ComponentUtils.py +188 -0
- robo_appian-0.0.11/PKG-INFO +0 -140
- robo_appian-0.0.11/README.md +0 -122
- robo_appian-0.0.11/robo_appian/components/ButtonUtils.py +0 -51
- robo_appian-0.0.11/robo_appian/components/DateUtils.py +0 -145
- robo_appian-0.0.11/robo_appian/components/InputUtils.py +0 -129
- robo_appian-0.0.11/robo_appian/components/LabelUtils.py +0 -54
- robo_appian-0.0.11/robo_appian/components/TableUtils.py +0 -157
- robo_appian-0.0.11/robo_appian/utils/ComponentUtils.py +0 -229
- {robo_appian-0.0.11 → robo_appian-0.0.13}/LICENSE +0 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/__init__.py +0 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/components/__init__.py +0 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/controllers/__init__.py +0 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/exceptions/MyCustomError.py +0 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/exceptions/__init__.py +0 -0
- {robo_appian-0.0.11 → robo_appian-0.0.13}/robo_appian/utils/__init__.py +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: robo_appian
|
|
3
|
+
Version: 0.0.13
|
|
4
|
+
Summary: Automate your Appian code testing with Python. Boost quality, save time.
|
|
5
|
+
Author: Dinil Mithra
|
|
6
|
+
Author-email: dinilmithra@mailme@gmail.com
|
|
7
|
+
Requires-Python: >=3.12,<4.0
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Requires-Dist: numpy
|
|
13
|
+
Requires-Dist: requests (>=2.25.1,<3.0.0)
|
|
14
|
+
Requires-Dist: selenium (>=4.34.0)
|
|
15
|
+
Project-URL: Homepage, https://github.com/dinilmithra/robo_appian
|
|
16
|
+
Project-URL: Repository, https://github.com/dinilmithra/robo_appian.git
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# Robo Appian
|
|
20
|
+
|
|
21
|
+
Robo Appian is a Python library for automated UI testing of Appian applications. It provides user-friendly utilities and best practices to help you write robust, maintainable, and business-focused test automation.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
- Simple, readable API for Appian UI automation
|
|
25
|
+
- Utilities for buttons, inputs, dropdowns, tables, tabs, and more
|
|
26
|
+
- Data-driven and workflow testing support
|
|
27
|
+
- Error handling and debugging helpers
|
|
28
|
+
- Designed for both technical and business users
|
|
29
|
+
|
|
30
|
+
## Documentation
|
|
31
|
+
Full documentation, guides, and API reference are available at:
|
|
32
|
+
|
|
33
|
+
➡️ [Robo Appian Documentation](https://dinilmithra.github.io/robo_appian/)
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
1. Install Robo Appian:
|
|
37
|
+
```bash
|
|
38
|
+
pip install robo_appian
|
|
39
|
+
```
|
|
40
|
+
2. See the [Getting Started Guide](docs/getting-started/installation.md) for setup and your first test.
|
|
41
|
+
|
|
42
|
+
## Example Usage
|
|
43
|
+
```python
|
|
44
|
+
from robo_appian.components import InputUtils, ButtonUtils
|
|
45
|
+
|
|
46
|
+
# Set value in a text field by label
|
|
47
|
+
InputUtils.setValueByLabelText(wait, "Username", "testuser")
|
|
48
|
+
|
|
49
|
+
# Click a button by label
|
|
50
|
+
ButtonUtils.clickByLabelText(wait, "Sign In")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Project Structure
|
|
54
|
+
- `robo_appian/` - Library source code
|
|
55
|
+
- `docs/` - Documentation and guides
|
|
56
|
+
- `examples/` - Example test scripts
|
|
57
|
+
|
|
58
|
+
## Contributing
|
|
59
|
+
Contributions are welcome! Please see the [contributing guidelines](CONTRIBUTING.md) or open an issue to get started.
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
For questions or support, contact [Dinil Mithra](mailto:dinilmithra.mailme@gmail.com) or connect on [LinkedIn](https://www.linkedin.com/in/dinilmithra).
|
|
67
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Robo Appian
|
|
2
|
+
|
|
3
|
+
Robo Appian is a Python library for automated UI testing of Appian applications. It provides user-friendly utilities and best practices to help you write robust, maintainable, and business-focused test automation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
- Simple, readable API for Appian UI automation
|
|
7
|
+
- Utilities for buttons, inputs, dropdowns, tables, tabs, and more
|
|
8
|
+
- Data-driven and workflow testing support
|
|
9
|
+
- Error handling and debugging helpers
|
|
10
|
+
- Designed for both technical and business users
|
|
11
|
+
|
|
12
|
+
## Documentation
|
|
13
|
+
Full documentation, guides, and API reference are available at:
|
|
14
|
+
|
|
15
|
+
➡️ [Robo Appian Documentation](https://dinilmithra.github.io/robo_appian/)
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
1. Install Robo Appian:
|
|
19
|
+
```bash
|
|
20
|
+
pip install robo_appian
|
|
21
|
+
```
|
|
22
|
+
2. See the [Getting Started Guide](docs/getting-started/installation.md) for setup and your first test.
|
|
23
|
+
|
|
24
|
+
## Example Usage
|
|
25
|
+
```python
|
|
26
|
+
from robo_appian.components import InputUtils, ButtonUtils
|
|
27
|
+
|
|
28
|
+
# Set value in a text field by label
|
|
29
|
+
InputUtils.setValueByLabelText(wait, "Username", "testuser")
|
|
30
|
+
|
|
31
|
+
# Click a button by label
|
|
32
|
+
ButtonUtils.clickByLabelText(wait, "Sign In")
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Project Structure
|
|
36
|
+
- `robo_appian/` - Library source code
|
|
37
|
+
- `docs/` - Documentation and guides
|
|
38
|
+
- `examples/` - Example test scripts
|
|
39
|
+
|
|
40
|
+
## Contributing
|
|
41
|
+
Contributions are welcome! Please see the [contributing guidelines](CONTRIBUTING.md) or open an issue to get started.
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
For questions or support, contact [Dinil Mithra](mailto:dinilmithra.mailme@gmail.com) or connect on [LinkedIn](https://www.linkedin.com/in/dinilmithra).
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from selenium.webdriver.common.by import By
|
|
2
|
+
from selenium.webdriver.support import expected_conditions as EC
|
|
3
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ButtonUtils:
|
|
7
|
+
"""
|
|
8
|
+
Utility class for interacting with button components in Appian UI.
|
|
9
|
+
Usage Example:
|
|
10
|
+
# Click a button by its label
|
|
11
|
+
from robo_appian.components.ButtonUtils import ButtonUtils
|
|
12
|
+
ButtonUtils.clickByLabelText(wait, "Submit")
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def __findByPartialLabelText(wait: WebDriverWait, label: str):
|
|
17
|
+
"""
|
|
18
|
+
Finds a button by its label.
|
|
19
|
+
|
|
20
|
+
Parameters:
|
|
21
|
+
wait: Selenium WebDriverWait instance.
|
|
22
|
+
label: The label of the button to find.
|
|
23
|
+
label: The label of the button to find.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
WebElement representing the button.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
component = ButtonUtils.__findByLabelText(wait, "Submit")
|
|
30
|
+
"""
|
|
31
|
+
xpath = f".//button[./span[contains(translate(normalize-space(.), '\u00a0', ' '), '{label}')]]"
|
|
32
|
+
try:
|
|
33
|
+
component = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
|
|
34
|
+
except Exception as e:
|
|
35
|
+
raise RuntimeError(f"Button with label '{label}' not found or not clickable.") from e
|
|
36
|
+
return component
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def __findByLabelText(wait: WebDriverWait, label: str):
|
|
40
|
+
"""
|
|
41
|
+
Finds a button by its label.
|
|
42
|
+
|
|
43
|
+
Parameters:
|
|
44
|
+
wait: Selenium WebDriverWait instance.
|
|
45
|
+
label: The label of the button to find.
|
|
46
|
+
label: The label of the button to find.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
WebElement representing the button.
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
component = ButtonUtils.__findByLabelText(wait, "Submit")
|
|
53
|
+
"""
|
|
54
|
+
xpath = f".//button[./span[normalize-space(text())='{label}']]"
|
|
55
|
+
try:
|
|
56
|
+
component = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
|
|
57
|
+
except Exception as e:
|
|
58
|
+
raise RuntimeError(f"Button with label '{label}' not found or not clickable.") from e
|
|
59
|
+
return component
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def clickByPartialLabelText(wait: WebDriverWait, label: str):
|
|
63
|
+
"""Finds a button by its partial label and clicks it.
|
|
64
|
+
|
|
65
|
+
Parameters:
|
|
66
|
+
wait: Selenium WebDriverWait instance.
|
|
67
|
+
label: The partial label of the button to click.
|
|
68
|
+
Example:
|
|
69
|
+
ButtonUtils.clickByPartialLabelText(wait, "Button Label")
|
|
70
|
+
"""
|
|
71
|
+
component = ButtonUtils.__findByPartialLabelText(wait, label)
|
|
72
|
+
component.click()
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def clickByLabelText(wait: WebDriverWait, label: str):
|
|
76
|
+
"""Finds a button by its label and clicks it.
|
|
77
|
+
|
|
78
|
+
Parameters:
|
|
79
|
+
wait: Selenium WebDriverWait instance.
|
|
80
|
+
label: The label of the button to click.
|
|
81
|
+
Example:
|
|
82
|
+
ButtonUtils.clickByLabelText(wait, "Button Label")
|
|
83
|
+
"""
|
|
84
|
+
component = ButtonUtils.__findByLabelText(wait, label)
|
|
85
|
+
component.click()
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def clickById(wait: WebDriverWait, id: str):
|
|
89
|
+
"""
|
|
90
|
+
Finds and clicks an input button by its HTML id attribute.
|
|
91
|
+
|
|
92
|
+
Parameters:
|
|
93
|
+
wait: Selenium WebDriverWait instance.
|
|
94
|
+
id: The HTML id of the input button.
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
ButtonUtils.clickById(wait, "button_id")
|
|
98
|
+
|
|
99
|
+
"""
|
|
100
|
+
try:
|
|
101
|
+
component = wait.until(EC.element_to_be_clickable((By.ID, id)))
|
|
102
|
+
except Exception as e:
|
|
103
|
+
raise RuntimeError(f"Input button with id '{id}' not found or not clickable.") from e
|
|
104
|
+
|
|
105
|
+
component.click()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from selenium.webdriver.common.by import By
|
|
2
|
+
from selenium.webdriver.support import expected_conditions as EC
|
|
3
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
4
|
+
|
|
5
|
+
from robo_appian.components.InputUtils import InputUtils
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DateUtils:
|
|
9
|
+
"""
|
|
10
|
+
Utility class for interacting with date components in Appian UI.
|
|
11
|
+
Usage Example:
|
|
12
|
+
# Set a date value in a date component
|
|
13
|
+
from robo_appian.components.DateUtils import DateUtils
|
|
14
|
+
DateUtils.setValueByLabelText(wait, "Start Date", "2023-10-01")
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def __findComponent(wait: WebDriverWait, label: str):
|
|
19
|
+
"""
|
|
20
|
+
Finds a date component by its label.
|
|
21
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
22
|
+
:param label: The label of the date component.
|
|
23
|
+
:return: The WebElement representing the date component.
|
|
24
|
+
Example:
|
|
25
|
+
DateUtils.__findComponent(wait, "Start Date")
|
|
26
|
+
"""
|
|
27
|
+
# xpath = f".//div/label[text()='{label}']"
|
|
28
|
+
# try:
|
|
29
|
+
# component: WebElement = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
|
|
30
|
+
# except Exception as e:
|
|
31
|
+
# raise Exception(f"Could not find clickable date component with label '{label}': {e}")
|
|
32
|
+
|
|
33
|
+
# attribute: str = "for"
|
|
34
|
+
# component_id = component.get_attribute(attribute) # type: ignore[reportUnknownMemberType]
|
|
35
|
+
# if component_id is None:
|
|
36
|
+
# raise ValueError(f"Could not find component using {attribute} attribute for label '{label}'.")
|
|
37
|
+
|
|
38
|
+
# try:
|
|
39
|
+
# component = wait.until(EC.element_to_be_clickable((By.ID, component_id)))
|
|
40
|
+
# except Exception as e:
|
|
41
|
+
# raise Exception(f"Could not find clickable date input with id '{component_id}': {e}")
|
|
42
|
+
|
|
43
|
+
xpath = f'.//div[./div/label[text()="{label}"]]/div/div/div/input'
|
|
44
|
+
try:
|
|
45
|
+
component = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
|
|
46
|
+
except Exception as e:
|
|
47
|
+
raise Exception(f"Could not find clickable date component with label '{label}': {e}")
|
|
48
|
+
return component
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def setValueByLabelText(wait: WebDriverWait, label: str, value: str):
|
|
52
|
+
"""
|
|
53
|
+
Sets the value of a date component.
|
|
54
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
55
|
+
:param label: The label of the date component.
|
|
56
|
+
:param value: The value to set in the date component.
|
|
57
|
+
:return: The WebElement representing the date component.
|
|
58
|
+
Example:
|
|
59
|
+
DateUtils.setValueByLabelText(wait, "Start Date", "2023-10-01")
|
|
60
|
+
"""
|
|
61
|
+
component = DateUtils.__findComponent(wait, label)
|
|
62
|
+
InputUtils._setValueByComponent(component, value)
|
|
63
|
+
return component
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def clickByLabelText(wait: WebDriverWait, label: str):
|
|
67
|
+
"""
|
|
68
|
+
Clicks on the date component to open the date picker.
|
|
69
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
70
|
+
:param label: The label of the date component.
|
|
71
|
+
:return: The WebElement representing the date component.
|
|
72
|
+
Example:
|
|
73
|
+
DateUtils.clickByLabelText(wait, "Start Date")
|
|
74
|
+
"""
|
|
75
|
+
component = DateUtils.__findComponent(wait, label)
|
|
76
|
+
component.click()
|
|
77
|
+
return component
|
|
@@ -16,7 +16,16 @@ class DropdownUtils:
|
|
|
16
16
|
|
|
17
17
|
@staticmethod
|
|
18
18
|
def __findComboboxByPartialLabelText(wait: WebDriverWait, label: str):
|
|
19
|
-
|
|
19
|
+
"""
|
|
20
|
+
Finds a combobox by its partial label text.
|
|
21
|
+
|
|
22
|
+
:param wait: Selenium WebDriverWait instance.
|
|
23
|
+
:param label: The partial label of the combobox to find.
|
|
24
|
+
:return: WebElement representing the combobox.
|
|
25
|
+
Example:
|
|
26
|
+
component = DropdownUtils.__findComboboxByPartialLabelText(wait, "Dropdown Label")
|
|
27
|
+
"""
|
|
28
|
+
xpath = f'.//div[./div/span[contains(normalize-space(text()), "{label}")]]/div/div/div/div[@role="combobox" and not(@aria-disabled="true")]' # noqa: E501
|
|
20
29
|
try:
|
|
21
30
|
component = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
|
|
22
31
|
except Exception as e:
|
|
@@ -26,7 +35,16 @@ class DropdownUtils:
|
|
|
26
35
|
|
|
27
36
|
@staticmethod
|
|
28
37
|
def __findComboboxByLabelText(wait: WebDriverWait, label: str):
|
|
29
|
-
|
|
38
|
+
"""
|
|
39
|
+
Finds a combobox by its label text.
|
|
40
|
+
|
|
41
|
+
:param wait: Selenium WebDriverWait instance.
|
|
42
|
+
:param label: The label of the combobox to find.
|
|
43
|
+
:return: WebElement representing the combobox.
|
|
44
|
+
Example:
|
|
45
|
+
component = DropdownUtils.__findComboboxByLabelText(wait, "Dropdown Label")
|
|
46
|
+
"""
|
|
47
|
+
xpath = f'.//div[./div/span[normalize-space(text())="{label}"]]/div/div/div/div[@role="combobox" and not(@aria-disabled="true")]' # noqa: E501
|
|
30
48
|
try:
|
|
31
49
|
component = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
|
|
32
50
|
except Exception as e:
|
|
@@ -36,10 +54,27 @@ class DropdownUtils:
|
|
|
36
54
|
|
|
37
55
|
@staticmethod
|
|
38
56
|
def __clickCombobox(wait: WebDriverWait, combobox: WebElement):
|
|
57
|
+
"""
|
|
58
|
+
Clicks the combobox to open the dropdown options.
|
|
59
|
+
|
|
60
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
61
|
+
:param combobox: The combobox WebElement.
|
|
62
|
+
Example:
|
|
63
|
+
DropdownUtils.__clickCombobox(wait, combobox)
|
|
64
|
+
"""
|
|
39
65
|
combobox.click()
|
|
40
66
|
|
|
41
67
|
@staticmethod
|
|
42
68
|
def __findDropdownOptionId(wait: WebDriverWait, combobox: WebElement):
|
|
69
|
+
"""
|
|
70
|
+
Finds the dropdown option id from the combobox.
|
|
71
|
+
|
|
72
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
73
|
+
:param combobox: The combobox WebElement.
|
|
74
|
+
:return: The id of the dropdown options list.
|
|
75
|
+
Example:
|
|
76
|
+
dropdown_option_id = DropdownUtils.__findDropdownOptionId(wait, combobox)
|
|
77
|
+
"""
|
|
43
78
|
dropdown_option_id = combobox.get_attribute("aria-controls")
|
|
44
79
|
if dropdown_option_id is None:
|
|
45
80
|
raise Exception('Dropdown component does not have a valid "aria-controls" attribute.')
|
|
@@ -47,9 +82,23 @@ class DropdownUtils:
|
|
|
47
82
|
|
|
48
83
|
@staticmethod
|
|
49
84
|
def __checkDropdownOptionValueExistsByDropdownOptionId(wait: WebDriverWait, dropdown_option_id: str, value: str):
|
|
50
|
-
|
|
85
|
+
"""
|
|
86
|
+
Checks if a dropdown option value exists by its option id and value.
|
|
87
|
+
|
|
88
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
89
|
+
:param dropdown_option_id: The id of the dropdown options list.
|
|
90
|
+
:param value: The value to check in the dropdown.
|
|
91
|
+
Example:
|
|
92
|
+
exists = DropdownUtils.checkDropdownOptionValueExistsByDropdownOptionId(wait, "dropdown_option_id", "Option Value")
|
|
93
|
+
if exists:
|
|
94
|
+
print("The value exists in the dropdown.")
|
|
95
|
+
else:
|
|
96
|
+
print("The value does not exist in the dropdown.")
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
xpath = f'.//div/ul[@id="{dropdown_option_id}"]/li[./div[normalize-space(text())="{value}"]]'
|
|
51
100
|
try:
|
|
52
|
-
wait.until(EC.element_to_be_clickable((By.XPATH,
|
|
101
|
+
wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
|
|
53
102
|
return True
|
|
54
103
|
except NoSuchElementException:
|
|
55
104
|
return False
|
|
@@ -58,6 +107,15 @@ class DropdownUtils:
|
|
|
58
107
|
|
|
59
108
|
@staticmethod
|
|
60
109
|
def __selectDropdownValueByDropdownOptionId(wait: WebDriverWait, dropdown_option_id: str, value: str):
|
|
110
|
+
"""
|
|
111
|
+
Selects a value from a dropdown by its option id and value.
|
|
112
|
+
|
|
113
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
114
|
+
:param dropdown_option_id: The id of the dropdown options list.
|
|
115
|
+
:param value: The value to select from the dropdown.
|
|
116
|
+
Example:
|
|
117
|
+
DropdownUtils.selectDropdownValueByDropdownOptionId(wait, "dropdown_option_id", "Option Value")
|
|
118
|
+
"""
|
|
61
119
|
option_xpath = f'.//div/ul[@id="{dropdown_option_id}"]/li[./div[normalize-space(text())="{value}"]]'
|
|
62
120
|
try:
|
|
63
121
|
try:
|
|
@@ -65,7 +123,7 @@ class DropdownUtils:
|
|
|
65
123
|
component = wait.until(EC.element_to_be_clickable((By.XPATH, option_xpath)))
|
|
66
124
|
except Exception as e:
|
|
67
125
|
raise Exception(
|
|
68
|
-
f'Could not locate or click dropdown option "{value}" with dropdown option id "{dropdown_option_id}": {str(e)}'
|
|
126
|
+
f'Could not locate or click dropdown option "{value}" with dropdown option id "{dropdown_option_id}": {str(e)}' # noqa: E501
|
|
69
127
|
)
|
|
70
128
|
except Exception as e:
|
|
71
129
|
raise Exception(f'Could not find or click dropdown option "{value}" with xpath "{option_xpath}": {str(e)}')
|
|
@@ -101,6 +159,19 @@ class DropdownUtils:
|
|
|
101
159
|
|
|
102
160
|
@staticmethod
|
|
103
161
|
def checkReadOnlyStatusByLabelText(wait: WebDriverWait, label: str):
|
|
162
|
+
"""
|
|
163
|
+
Checks if a dropdown is read-only by its label text.
|
|
164
|
+
|
|
165
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
166
|
+
:param label: The label of the dropdown.
|
|
167
|
+
:return: True if the dropdown is read-only, False otherwise.
|
|
168
|
+
Example:
|
|
169
|
+
is_read_only = DropdownUtils.checkReadOnlyStatusByLabelText(wait, "Dropdown Label")
|
|
170
|
+
if is_read_only:
|
|
171
|
+
print("The dropdown is read-only.")
|
|
172
|
+
else:
|
|
173
|
+
print("The dropdown is editable.")
|
|
174
|
+
"""
|
|
104
175
|
xpath = f'.//div[./div/span[normalize-space(text())="{label}"]]/div/div/p[text()]'
|
|
105
176
|
try:
|
|
106
177
|
wait._driver.find_element(By.XPATH, xpath)
|
|
@@ -112,20 +183,61 @@ class DropdownUtils:
|
|
|
112
183
|
|
|
113
184
|
@staticmethod
|
|
114
185
|
def selectDropdownValueByComboboxComponent(wait: WebDriverWait, combobox: WebElement, value: str):
|
|
186
|
+
"""
|
|
187
|
+
Selects a value from a dropdown using the combobox component.
|
|
188
|
+
|
|
189
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
190
|
+
:param combobox: The combobox WebElement.
|
|
191
|
+
:param value: The value to select from the dropdown.
|
|
192
|
+
Example:
|
|
193
|
+
DropdownUtils.selectDropdownValueByComboboxComponent(wait, combobox, "Option Value")
|
|
194
|
+
"""
|
|
115
195
|
dropdown_option_id = DropdownUtils.__findDropdownOptionId(wait, combobox)
|
|
116
196
|
DropdownUtils.__clickCombobox(wait, combobox)
|
|
117
197
|
DropdownUtils.__selectDropdownValueByDropdownOptionId(wait, dropdown_option_id, value)
|
|
118
198
|
|
|
119
199
|
@staticmethod
|
|
120
200
|
def selectDropdownValueByLabelText(wait: WebDriverWait, dropdown_label: str, value: str):
|
|
201
|
+
"""
|
|
202
|
+
Selects a value from a dropdown by its label text.
|
|
203
|
+
|
|
204
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
205
|
+
:param dropdown_label: The label of the dropdown.
|
|
206
|
+
:param value: The value to select from the dropdown.
|
|
207
|
+
Example:
|
|
208
|
+
DropdownUtils.selectDropdownValueByLabelText(wait, "Dropdown Label", "Option Value")
|
|
209
|
+
"""
|
|
121
210
|
DropdownUtils.__selectDropdownValueByLabelText(wait, dropdown_label, value)
|
|
122
211
|
|
|
123
212
|
@staticmethod
|
|
124
213
|
def selectDropdownValueByPartialLabelText(wait: WebDriverWait, dropdown_label: str, value: str):
|
|
214
|
+
"""
|
|
215
|
+
Selects a value from a dropdown by its partial label text.
|
|
216
|
+
|
|
217
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
218
|
+
:param dropdown_label: The partial label of the dropdown.
|
|
219
|
+
:param value: The value to select from the dropdown.
|
|
220
|
+
Example:
|
|
221
|
+
DropdownUtils.selectDropdownValueByPartialLabelText(wait, "Dropdown Label", "Option Value")
|
|
222
|
+
"""
|
|
125
223
|
DropdownUtils.__selectDropdownValueByPartialLabelText(wait, dropdown_label, value)
|
|
126
224
|
|
|
127
225
|
@staticmethod
|
|
128
226
|
def checkDropdownOptionValueExists(wait: WebDriverWait, dropdown_label: str, value: str):
|
|
227
|
+
"""
|
|
228
|
+
Checks if a dropdown option value exists by its label text.
|
|
229
|
+
|
|
230
|
+
:param wait: WebDriverWait instance to wait for elements.
|
|
231
|
+
:param dropdown_label: The label of the dropdown.
|
|
232
|
+
:param value: The value to check in the dropdown.
|
|
233
|
+
:return: True if the value exists, False otherwise.
|
|
234
|
+
Example:
|
|
235
|
+
exists = DropdownUtils.checkDropdownOptionValueExists(wait, "Dropdown Label", "Option Value")
|
|
236
|
+
if exists:
|
|
237
|
+
print("The value exists in the dropdown.")
|
|
238
|
+
else:
|
|
239
|
+
print("The value does not exist in the dropdown.")
|
|
240
|
+
"""
|
|
129
241
|
combobox = DropdownUtils.__findComboboxByLabelText(wait, dropdown_label)
|
|
130
242
|
DropdownUtils.__clickCombobox(wait, combobox)
|
|
131
243
|
dropdown_option_id = DropdownUtils.__findDropdownOptionId(wait, combobox)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
from robo_appian.utils.ComponentUtils import ComponentUtils
|
|
2
|
+
from selenium.webdriver.common.by import By
|
|
3
|
+
from selenium.webdriver.support import expected_conditions as EC
|
|
4
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
5
|
+
from selenium.webdriver.remote.webelement import WebElement
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class InputUtils:
|
|
9
|
+
"""
|
|
10
|
+
Utility class for interacting with input components in Appian UI.
|
|
11
|
+
Usage Example:
|
|
12
|
+
from robo_appian.components.InputUtils import InputUtils
|
|
13
|
+
|
|
14
|
+
# Set a value in an input component by its label
|
|
15
|
+
InputUtils.setValueByLabelText(wait, "Username", "test_user")
|
|
16
|
+
|
|
17
|
+
# Set a value in an input component by its ID
|
|
18
|
+
InputUtils.setValueById(wait, "inputComponentId", "test_value")
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
def __findInputComponentsByXpath(wait: WebDriverWait, xpath: str):
|
|
23
|
+
"""
|
|
24
|
+
Finds input components by their XPath.
|
|
25
|
+
|
|
26
|
+
Parameters:
|
|
27
|
+
wait: Selenium WebDriverWait instance.
|
|
28
|
+
xpath: The XPath expression to locate the input components.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
A list of Selenium WebElement representing the input components.
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
InputUtils.__findInputComponentsByXpath(wait, './/div/label[normalize-space(text())="Username"]')
|
|
35
|
+
"""
|
|
36
|
+
label_components = ComponentUtils.findComponentsByXPath(wait, xpath)
|
|
37
|
+
input_components = []
|
|
38
|
+
for label_component in label_components:
|
|
39
|
+
attribute: str = "for"
|
|
40
|
+
component_id = label_component.get_attribute(attribute) # type: ignore[reportUnknownMemberType]
|
|
41
|
+
if component_id:
|
|
42
|
+
try:
|
|
43
|
+
component = wait.until(EC.element_to_be_clickable((By.ID, component_id)))
|
|
44
|
+
input_components.append(component)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
raise Exception(f"Could not find clickable input component with id '{component_id}': {e}")
|
|
47
|
+
else:
|
|
48
|
+
raise ValueError(f"Input component with label '{label_component.text}' does not have 'for' attribute.")
|
|
49
|
+
return input_components
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def __findInputComponentsByPartialLabel(wait: WebDriverWait, label: str):
|
|
53
|
+
"""Finds input components by their label text, allowing for partial matches.
|
|
54
|
+
|
|
55
|
+
Parameters:
|
|
56
|
+
wait: Selenium WebDriverWait instance.
|
|
57
|
+
label: The visible text label of the input component, allowing for partial matches.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
A list of Selenium WebElement representing the input components.
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
InputUtils.__findInputComponentsByPartialLabel(wait, "Username")
|
|
64
|
+
"""
|
|
65
|
+
xpath = f'.//div/label[contains(normalize-space(text()), "{label}")]'
|
|
66
|
+
components = InputUtils.__findInputComponentsByXpath(wait, xpath)
|
|
67
|
+
return components
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def __findComponentsByLabel(wait: WebDriverWait, label: str):
|
|
71
|
+
"""Finds input components by their label text.
|
|
72
|
+
|
|
73
|
+
Parameters:
|
|
74
|
+
wait: Selenium WebDriverWait instance.
|
|
75
|
+
label: The visible text label of the input component.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
A list of Selenium WebElement representing the input components.
|
|
79
|
+
|
|
80
|
+
Example:
|
|
81
|
+
InputUtils.__findComponentsByLabel(wait, "Username")
|
|
82
|
+
"""
|
|
83
|
+
xpath = f'.//div/label[normalize-space(text())="{label}"]'
|
|
84
|
+
components = InputUtils.__findInputComponentsByXpath(wait, xpath)
|
|
85
|
+
return components
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def _setValueByComponent(component: WebElement, value: str):
|
|
89
|
+
"""
|
|
90
|
+
Sets a value in an input component.
|
|
91
|
+
Parameters:
|
|
92
|
+
component: The Selenium WebElement for the input component.
|
|
93
|
+
value: The value to set in the input field.
|
|
94
|
+
Returns:
|
|
95
|
+
The Selenium WebElement for the input component after setting the value.
|
|
96
|
+
Example:
|
|
97
|
+
InputUtils._setValueByComponent(component, "test_value")
|
|
98
|
+
"""
|
|
99
|
+
component.clear()
|
|
100
|
+
component.send_keys(value)
|
|
101
|
+
return component
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def __setValueByComponents(wait: WebDriverWait, input_components, value: str):
|
|
105
|
+
"""
|
|
106
|
+
Sets a value in an input component identified by its label text.
|
|
107
|
+
Parameters:
|
|
108
|
+
wait: Selenium WebDriverWait instance.
|
|
109
|
+
label: The visible text label of the input component.
|
|
110
|
+
value: The value to set in the input field.
|
|
111
|
+
Returns:
|
|
112
|
+
None
|
|
113
|
+
Example:
|
|
114
|
+
InputUtils.setValueByLabelText(wait, "Username", "test_user")
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
for component in input_components:
|
|
118
|
+
InputUtils._setValueByComponent(component, value)
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def setValueByPartialLabelText(wait: WebDriverWait, label: str, value: str):
|
|
122
|
+
input_components = InputUtils.__findInputComponentsByPartialLabel(wait, label)
|
|
123
|
+
InputUtils.__setValueByComponents(wait, input_components, value)
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def setValueByLabelText(wait: WebDriverWait, label: str, value: str):
|
|
127
|
+
"""
|
|
128
|
+
Sets a value in an input component identified by its label text.
|
|
129
|
+
|
|
130
|
+
Parameters:
|
|
131
|
+
wait: Selenium WebDriverWait instance.
|
|
132
|
+
label: The visible text label of the input component.
|
|
133
|
+
value: The value to set in the input field.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
None
|
|
137
|
+
|
|
138
|
+
Example:
|
|
139
|
+
InputUtils.setValueByLabelText(wait, "Username", "test_user")
|
|
140
|
+
"""
|
|
141
|
+
input_components = InputUtils.__findComponentsByLabel(wait, label)
|
|
142
|
+
InputUtils.__setValueByComponents(wait, input_components, value)
|
|
143
|
+
|
|
144
|
+
@staticmethod
|
|
145
|
+
def setValueById(wait: WebDriverWait, component_id: str, value: str):
|
|
146
|
+
"""
|
|
147
|
+
Sets a value in an input component identified by its ID.
|
|
148
|
+
|
|
149
|
+
Parameters:
|
|
150
|
+
wait: Selenium WebDriverWait instance.
|
|
151
|
+
component_id: The ID of the input component.
|
|
152
|
+
value: The value to set in the input field.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
The Selenium WebElement for the input component after setting the value.
|
|
156
|
+
|
|
157
|
+
Example:
|
|
158
|
+
InputUtils.setValueById(wait, "inputComponentId", "test_value")
|
|
159
|
+
"""
|
|
160
|
+
try:
|
|
161
|
+
component = wait.until(EC.element_to_be_clickable((By.ID, component_id)))
|
|
162
|
+
except Exception as e:
|
|
163
|
+
raise Exception(f"Timeout or error finding input component with id '{component_id}': {e}")
|
|
164
|
+
InputUtils._setValueByComponent(component, value)
|
|
165
|
+
return component
|