robo_appian 0.0.12__tar.gz → 0.0.14__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.14/PKG-INFO +66 -0
- robo_appian-0.0.14/README.md +47 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/pyproject.toml +1 -1
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/ButtonUtils.py +37 -1
- robo_appian-0.0.14/robo_appian/utils/ComponentUtils.py +188 -0
- robo_appian-0.0.12/PKG-INFO +0 -140
- robo_appian-0.0.12/README.md +0 -122
- robo_appian-0.0.12/robo_appian/utils/ComponentUtils.py +0 -229
- {robo_appian-0.0.12 → robo_appian-0.0.14}/LICENSE +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/__init__.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/DateUtils.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/DropdownUtils.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/InputUtils.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/LabelUtils.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/LinkUtils.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/SearchDropdownUtils.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/SearchInputUtils.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/TabUtils.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/TableUtils.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/components/__init__.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/controllers/ComponentDriver.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/controllers/__init__.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/exceptions/MyCustomError.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/exceptions/__init__.py +0 -0
- {robo_appian-0.0.12 → robo_appian-0.0.14}/robo_appian/utils/__init__.py +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: robo_appian
|
|
3
|
+
Version: 0.0.14
|
|
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
|
+
|
|
57
|
+
## Contributing
|
|
58
|
+
Contributions are welcome! Please see the [contributing guidelines](CONTRIBUTING.md) or open an issue to get started.
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
For questions or support, contact [Dinil Mithra](mailto:dinilmithra.mailme@gmail.com) or connect on [LinkedIn](https://www.linkedin.com/in/dinilmithra).
|
|
66
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
|
|
39
|
+
## Contributing
|
|
40
|
+
Contributions are welcome! Please see the [contributing guidelines](CONTRIBUTING.md) or open an issue to get started.
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
For questions or support, contact [Dinil Mithra](mailto:dinilmithra.mailme@gmail.com) or connect on [LinkedIn](https://www.linkedin.com/in/dinilmithra).
|
|
@@ -13,7 +13,7 @@ class ButtonUtils:
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
@staticmethod
|
|
16
|
-
def
|
|
16
|
+
def __findByPartialLabelText(wait: WebDriverWait, label: str):
|
|
17
17
|
"""
|
|
18
18
|
Finds a button by its label.
|
|
19
19
|
|
|
@@ -35,6 +35,42 @@ class ButtonUtils:
|
|
|
35
35
|
raise RuntimeError(f"Button with label '{label}' not found or not clickable.") from e
|
|
36
36
|
return component
|
|
37
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
|
+
|
|
38
74
|
@staticmethod
|
|
39
75
|
def clickByLabelText(wait: WebDriverWait, label: str):
|
|
40
76
|
"""Finds a button by its label and clicks it.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
from selenium.common.exceptions import NoSuchElementException
|
|
2
|
+
from selenium.webdriver import ActionChains
|
|
3
|
+
from selenium.webdriver.common.by import By
|
|
4
|
+
from selenium.webdriver.common.keys import Keys
|
|
5
|
+
from selenium.webdriver.support import expected_conditions as EC
|
|
6
|
+
from selenium.webdriver.remote.webdriver import WebDriver
|
|
7
|
+
from selenium.webdriver.remote.webelement import WebElement
|
|
8
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ComponentUtils:
|
|
12
|
+
@staticmethod
|
|
13
|
+
def today():
|
|
14
|
+
"""
|
|
15
|
+
Returns today's date formatted as MM/DD/YYYY.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from datetime import date
|
|
19
|
+
|
|
20
|
+
today = date.today()
|
|
21
|
+
yesterday_formatted = today.strftime("%m/%d/%Y")
|
|
22
|
+
return yesterday_formatted
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def yesterday():
|
|
26
|
+
"""
|
|
27
|
+
Returns yesterday's date formatted as MM/DD/YYYY.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from datetime import date, timedelta
|
|
31
|
+
|
|
32
|
+
yesterday = date.today() - timedelta(days=1)
|
|
33
|
+
yesterday_formatted = yesterday.strftime("%m/%d/%Y")
|
|
34
|
+
return yesterday_formatted
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def findChildComponent(wait: WebDriverWait, component: WebElement, xpath: str):
|
|
38
|
+
"""Finds a child component using the given XPath within a parent component.
|
|
39
|
+
|
|
40
|
+
:param wait: WebDriverWait instance to wait for elements
|
|
41
|
+
:param component: Parent WebElement to search within
|
|
42
|
+
:param xpath: XPath string to locate the child component
|
|
43
|
+
:return: WebElement if found, raises NoSuchElementException otherwise
|
|
44
|
+
Example usage:
|
|
45
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
46
|
+
from selenium import webdriver
|
|
47
|
+
|
|
48
|
+
driver = webdriver.Chrome()
|
|
49
|
+
wait = WebDriverWait(driver, 10)
|
|
50
|
+
parent_component = driver.find_element(By.ID, "parent")
|
|
51
|
+
xpath = ".//button[@class='child']"
|
|
52
|
+
child_component = ComponentUtils.findChildComponent(wait, parent_component, xpath)
|
|
53
|
+
"""
|
|
54
|
+
return component.find_element(By.XPATH, xpath)
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def findComponentUsingXpathAndClick(wait: WebDriverWait, xpath: str):
|
|
58
|
+
"""Finds a component using the given XPath and clicks it.
|
|
59
|
+
|
|
60
|
+
:param wait: WebDriverWait instance to wait for elements
|
|
61
|
+
:param xpath: XPath string to locate the component
|
|
62
|
+
:return: None
|
|
63
|
+
Example usage:
|
|
64
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
65
|
+
from selenium import webdriver
|
|
66
|
+
|
|
67
|
+
driver = webdriver.Chrome()
|
|
68
|
+
wait = WebDriverWait(driver, 10)
|
|
69
|
+
xpath = "//button[@id='submit']"
|
|
70
|
+
ComponentUtils.findComponentUsingXpathAndClick(wait, xpath)
|
|
71
|
+
"""
|
|
72
|
+
component = ComponentUtils.findComponentUsingXpath(wait, xpath)
|
|
73
|
+
component.click()
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def findComponentUsingXpath(wait: WebDriverWait, xpath: str):
|
|
77
|
+
"""Finds a component using the given XPath in the current WebDriver instance.
|
|
78
|
+
|
|
79
|
+
:param wait: WebDriverWait instance to wait for elements
|
|
80
|
+
:param xpath: XPath string to locate the component
|
|
81
|
+
:return: WebElement if found, raises NoSuchElementException otherwise
|
|
82
|
+
Example usage:
|
|
83
|
+
component = ComponentUtils.findComponentUsingXpath(wait, "//button[@id='submit']")
|
|
84
|
+
component.click()
|
|
85
|
+
"""
|
|
86
|
+
component = wait.until(EC.presence_of_element_located((By.XPATH, xpath)))
|
|
87
|
+
return component
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def checkComponentExistsByXpath(wait: WebDriverWait, xpath: str):
|
|
91
|
+
"""Checks if a component with the given XPath exists in the current WebDriver instance."""
|
|
92
|
+
status = False
|
|
93
|
+
try:
|
|
94
|
+
ComponentUtils.findComponentUsingXpath(wait, xpath)
|
|
95
|
+
status = True
|
|
96
|
+
except NoSuchElementException:
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
return status
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def checkComponentExistsById(driver: WebDriver, id: str):
|
|
103
|
+
"""Checks if a component with the given ID exists in the current WebDriver instance.
|
|
104
|
+
|
|
105
|
+
:param driver: WebDriver instance to check for the component
|
|
106
|
+
:param id: ID of the component to check
|
|
107
|
+
:return: True if the component exists, False otherwise
|
|
108
|
+
Example usage:
|
|
109
|
+
exists = ComponentUtils.checkComponentExistsById(driver, "submit-button")
|
|
110
|
+
print(f"Component exists: {exists}")
|
|
111
|
+
"""
|
|
112
|
+
status = False
|
|
113
|
+
try:
|
|
114
|
+
driver.find_element(By.ID, id)
|
|
115
|
+
status = True
|
|
116
|
+
except NoSuchElementException:
|
|
117
|
+
pass
|
|
118
|
+
|
|
119
|
+
return status
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
def findCount(wait: WebDriverWait, xpath: str):
|
|
123
|
+
"""Finds the count of components matching the given XPath.
|
|
124
|
+
|
|
125
|
+
:param wait: WebDriverWait instance to wait for elements
|
|
126
|
+
:param xpath: XPath string to locate components
|
|
127
|
+
:return: Count of components matching the XPath
|
|
128
|
+
Example usage:
|
|
129
|
+
count = ComponentUtils.findCount(wait, "//div[@class='item']")
|
|
130
|
+
print(f"Number of items found: {count}")
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
length = 0
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
component = wait.until(EC.presence_of_all_elements_located((By.XPATH, xpath)))
|
|
137
|
+
length = len(component)
|
|
138
|
+
except NoSuchElementException:
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
return length
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def tab(wait: WebDriverWait):
|
|
145
|
+
"""Simulates a tab key press in the current WebDriver instance.
|
|
146
|
+
|
|
147
|
+
:param wait: WebDriverWait instance to wait for elements
|
|
148
|
+
:return: None
|
|
149
|
+
Example usage:
|
|
150
|
+
ComponentUtils.tab(wait)
|
|
151
|
+
"""
|
|
152
|
+
driver = wait._driver
|
|
153
|
+
actions = ActionChains(driver)
|
|
154
|
+
actions.send_keys(Keys.TAB).perform()
|
|
155
|
+
|
|
156
|
+
@staticmethod
|
|
157
|
+
def findComponentsByXPath(wait: WebDriverWait, xpath: str):
|
|
158
|
+
"""Finds all components matching the given XPath and returns a list of valid components
|
|
159
|
+
that are clickable and displayed.
|
|
160
|
+
|
|
161
|
+
:param wait: WebDriverWait instance to wait for elements
|
|
162
|
+
:param xpath: XPath string to locate components
|
|
163
|
+
:return: List of valid WebElement components
|
|
164
|
+
Example usage:
|
|
165
|
+
components = ComponentUtils.findComponentsByXPath(wait, "//button[@class='submit']")
|
|
166
|
+
for component in components:
|
|
167
|
+
component.click()
|
|
168
|
+
"""
|
|
169
|
+
# Wait for the presence of elements matching the XPath
|
|
170
|
+
wait.until(EC.presence_of_element_located((By.XPATH, xpath)))
|
|
171
|
+
|
|
172
|
+
# Find all matching elements
|
|
173
|
+
driver = wait._driver
|
|
174
|
+
components = driver.find_elements(By.XPATH, xpath)
|
|
175
|
+
|
|
176
|
+
# Filter for clickable and displayed components
|
|
177
|
+
valid_components = []
|
|
178
|
+
for component in components:
|
|
179
|
+
try:
|
|
180
|
+
if component.is_displayed() and component.is_enabled():
|
|
181
|
+
valid_components.append(component)
|
|
182
|
+
except Exception:
|
|
183
|
+
continue
|
|
184
|
+
|
|
185
|
+
if len(valid_components) > 0:
|
|
186
|
+
return valid_components
|
|
187
|
+
|
|
188
|
+
raise Exception(f"No valid components found for XPath: {xpath}")
|
robo_appian-0.0.12/PKG-INFO
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: robo_appian
|
|
3
|
-
Version: 0.0.12
|
|
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
|
-
**Automate your Appian code testing with Python. Boost quality, save time.**
|
|
22
|
-
|
|
23
|
-
[](https://badge.fury.io/py/robo-appian)
|
|
24
|
-
[](https://www.python.org/downloads/)
|
|
25
|
-
[](https://dinilmithra.github.io/robo_appian/)
|
|
26
|
-
|
|
27
|
-
## 🚀 Quick Start
|
|
28
|
-
|
|
29
|
-
### Installation
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
pip install robo-appian
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Basic Usage
|
|
36
|
-
|
|
37
|
-
```python
|
|
38
|
-
from selenium import webdriver
|
|
39
|
-
from selenium.webdriver.support.ui import WebDriverWait
|
|
40
|
-
from robo_appian import ButtonUtils, InputUtils, TableUtils
|
|
41
|
-
|
|
42
|
-
# Setup your driver
|
|
43
|
-
driver = webdriver.Chrome()
|
|
44
|
-
wait = WebDriverWait(driver, 10)
|
|
45
|
-
|
|
46
|
-
# Interact with Appian components
|
|
47
|
-
ButtonUtils.click(wait, "Submit")
|
|
48
|
-
InputUtils.set_text(wait, "Username", "john.doe")
|
|
49
|
-
TableUtils.click_cell_link(wait, "Actions", 1, "Edit")
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## 📚 Features
|
|
53
|
-
|
|
54
|
-
### Components
|
|
55
|
-
- **ButtonUtils**: Find and click buttons
|
|
56
|
-
- **DateUtils**: Interact with date fields and date pickers
|
|
57
|
-
- **DropdownUtils**: Interact with dropdown/select components
|
|
58
|
-
- **InputUtils**: Interact with input fields and text areas
|
|
59
|
-
- **LabelUtils**: Find and interact with labels
|
|
60
|
-
- **LinkUtils**: Click links and navigate
|
|
61
|
-
- **TableUtils**: Interact with tables and grids
|
|
62
|
-
- **TabUtils**: Switch between tabs
|
|
63
|
-
- **ComponentUtils**: General component utilities
|
|
64
|
-
|
|
65
|
-
### Controllers
|
|
66
|
-
- **ComponentDriver**: High-level interface for component interaction
|
|
67
|
-
|
|
68
|
-
### Exceptions
|
|
69
|
-
- **MyCustomError**: Custom exceptions for better error handling
|
|
70
|
-
|
|
71
|
-
## 📖 Documentation
|
|
72
|
-
|
|
73
|
-
Visit our [full documentation](https://dinilmithra.github.io/robo_appian/) for:
|
|
74
|
-
- Detailed API reference
|
|
75
|
-
- Complete examples and tutorials
|
|
76
|
-
- Installation guide
|
|
77
|
-
- Best practices
|
|
78
|
-
|
|
79
|
-
## 🛠️ Requirements
|
|
80
|
-
|
|
81
|
-
- Python 3.12+
|
|
82
|
-
- Selenium WebDriver 4.34.0+
|
|
83
|
-
- Compatible web browser (Chrome, Firefox, etc.)
|
|
84
|
-
|
|
85
|
-
## 🤝 Contributing
|
|
86
|
-
|
|
87
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
88
|
-
|
|
89
|
-
## 📄 License
|
|
90
|
-
|
|
91
|
-
This project is licensed under the MIT License.
|
|
92
|
-
|
|
93
|
-
## 🔗 Links
|
|
94
|
-
|
|
95
|
-
- [Documentation](https://dinilmithra.github.io/robo_appian/)
|
|
96
|
-
- [PyPI Package](https://pypi.org/project/robo-appian/)
|
|
97
|
-
- [GitHub Repository](https://github.com/dinilmithra/robo_appian)
|
|
98
|
-
ButtonUtils, ComponentUtils, DateUtils, DropdownUtils, InputUtils,
|
|
99
|
-
LabelUtils, LinkUtils, TableUtils, TabUtils
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
# Example: Set a Date Value
|
|
103
|
-
DateUtils.set_date_value("date_field_id", "2023-10-01")
|
|
104
|
-
|
|
105
|
-
# Example: Click a Button
|
|
106
|
-
ButtonUtils.click_button("submit_button_id")
|
|
107
|
-
|
|
108
|
-
# Example: Select a Dropdown Value
|
|
109
|
-
DropdownUtils.select_value("dropdown_id", "Option 1")
|
|
110
|
-
|
|
111
|
-
# Example: Enter Text in an Input Field
|
|
112
|
-
InputUtils.enter_text("input_field_id", "Sample Text")
|
|
113
|
-
|
|
114
|
-
# Example: Click a Link
|
|
115
|
-
LinkUtils.click_link("link_id")
|
|
116
|
-
|
|
117
|
-
# Example: Click a Tab
|
|
118
|
-
TabUtils.click_tab("tab_id")
|
|
119
|
-
|
|
120
|
-
# Example: Get a Table Cell Value
|
|
121
|
-
TableUtils.get_cell_value("table_id", 1, 2) # Row 1, Column 2
|
|
122
|
-
|
|
123
|
-
# Example: Get a Label Value
|
|
124
|
-
LabelUtils.get_label_value("label_id")
|
|
125
|
-
|
|
126
|
-
# Example: Get a Component Value
|
|
127
|
-
ComponentUtils.get_component_value("component_id")
|
|
128
|
-
|
|
129
|
-
# Example: Use the Component Driver
|
|
130
|
-
from robo_appian.utils.controllers.ComponentDriver import ComponentDriver
|
|
131
|
-
ComponentDriver.execute(wait, "Button", "Click", "Submit", None)
|
|
132
|
-
|
|
133
|
-
## Dependencies
|
|
134
|
-
|
|
135
|
-
Python >= 3.8
|
|
136
|
-
Uses selenium
|
|
137
|
-
|
|
138
|
-
## License
|
|
139
|
-
|
|
140
|
-
MIT License. See LICENSE.
|
robo_appian-0.0.12/README.md
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# Robo Appian
|
|
2
|
-
|
|
3
|
-
**Automate your Appian code testing with Python. Boost quality, save time.**
|
|
4
|
-
|
|
5
|
-
[](https://badge.fury.io/py/robo-appian)
|
|
6
|
-
[](https://www.python.org/downloads/)
|
|
7
|
-
[](https://dinilmithra.github.io/robo_appian/)
|
|
8
|
-
|
|
9
|
-
## 🚀 Quick Start
|
|
10
|
-
|
|
11
|
-
### Installation
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
pip install robo-appian
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
### Basic Usage
|
|
18
|
-
|
|
19
|
-
```python
|
|
20
|
-
from selenium import webdriver
|
|
21
|
-
from selenium.webdriver.support.ui import WebDriverWait
|
|
22
|
-
from robo_appian import ButtonUtils, InputUtils, TableUtils
|
|
23
|
-
|
|
24
|
-
# Setup your driver
|
|
25
|
-
driver = webdriver.Chrome()
|
|
26
|
-
wait = WebDriverWait(driver, 10)
|
|
27
|
-
|
|
28
|
-
# Interact with Appian components
|
|
29
|
-
ButtonUtils.click(wait, "Submit")
|
|
30
|
-
InputUtils.set_text(wait, "Username", "john.doe")
|
|
31
|
-
TableUtils.click_cell_link(wait, "Actions", 1, "Edit")
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## 📚 Features
|
|
35
|
-
|
|
36
|
-
### Components
|
|
37
|
-
- **ButtonUtils**: Find and click buttons
|
|
38
|
-
- **DateUtils**: Interact with date fields and date pickers
|
|
39
|
-
- **DropdownUtils**: Interact with dropdown/select components
|
|
40
|
-
- **InputUtils**: Interact with input fields and text areas
|
|
41
|
-
- **LabelUtils**: Find and interact with labels
|
|
42
|
-
- **LinkUtils**: Click links and navigate
|
|
43
|
-
- **TableUtils**: Interact with tables and grids
|
|
44
|
-
- **TabUtils**: Switch between tabs
|
|
45
|
-
- **ComponentUtils**: General component utilities
|
|
46
|
-
|
|
47
|
-
### Controllers
|
|
48
|
-
- **ComponentDriver**: High-level interface for component interaction
|
|
49
|
-
|
|
50
|
-
### Exceptions
|
|
51
|
-
- **MyCustomError**: Custom exceptions for better error handling
|
|
52
|
-
|
|
53
|
-
## 📖 Documentation
|
|
54
|
-
|
|
55
|
-
Visit our [full documentation](https://dinilmithra.github.io/robo_appian/) for:
|
|
56
|
-
- Detailed API reference
|
|
57
|
-
- Complete examples and tutorials
|
|
58
|
-
- Installation guide
|
|
59
|
-
- Best practices
|
|
60
|
-
|
|
61
|
-
## 🛠️ Requirements
|
|
62
|
-
|
|
63
|
-
- Python 3.12+
|
|
64
|
-
- Selenium WebDriver 4.34.0+
|
|
65
|
-
- Compatible web browser (Chrome, Firefox, etc.)
|
|
66
|
-
|
|
67
|
-
## 🤝 Contributing
|
|
68
|
-
|
|
69
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
70
|
-
|
|
71
|
-
## 📄 License
|
|
72
|
-
|
|
73
|
-
This project is licensed under the MIT License.
|
|
74
|
-
|
|
75
|
-
## 🔗 Links
|
|
76
|
-
|
|
77
|
-
- [Documentation](https://dinilmithra.github.io/robo_appian/)
|
|
78
|
-
- [PyPI Package](https://pypi.org/project/robo-appian/)
|
|
79
|
-
- [GitHub Repository](https://github.com/dinilmithra/robo_appian)
|
|
80
|
-
ButtonUtils, ComponentUtils, DateUtils, DropdownUtils, InputUtils,
|
|
81
|
-
LabelUtils, LinkUtils, TableUtils, TabUtils
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
# Example: Set a Date Value
|
|
85
|
-
DateUtils.set_date_value("date_field_id", "2023-10-01")
|
|
86
|
-
|
|
87
|
-
# Example: Click a Button
|
|
88
|
-
ButtonUtils.click_button("submit_button_id")
|
|
89
|
-
|
|
90
|
-
# Example: Select a Dropdown Value
|
|
91
|
-
DropdownUtils.select_value("dropdown_id", "Option 1")
|
|
92
|
-
|
|
93
|
-
# Example: Enter Text in an Input Field
|
|
94
|
-
InputUtils.enter_text("input_field_id", "Sample Text")
|
|
95
|
-
|
|
96
|
-
# Example: Click a Link
|
|
97
|
-
LinkUtils.click_link("link_id")
|
|
98
|
-
|
|
99
|
-
# Example: Click a Tab
|
|
100
|
-
TabUtils.click_tab("tab_id")
|
|
101
|
-
|
|
102
|
-
# Example: Get a Table Cell Value
|
|
103
|
-
TableUtils.get_cell_value("table_id", 1, 2) # Row 1, Column 2
|
|
104
|
-
|
|
105
|
-
# Example: Get a Label Value
|
|
106
|
-
LabelUtils.get_label_value("label_id")
|
|
107
|
-
|
|
108
|
-
# Example: Get a Component Value
|
|
109
|
-
ComponentUtils.get_component_value("component_id")
|
|
110
|
-
|
|
111
|
-
# Example: Use the Component Driver
|
|
112
|
-
from robo_appian.utils.controllers.ComponentDriver import ComponentDriver
|
|
113
|
-
ComponentDriver.execute(wait, "Button", "Click", "Submit", None)
|
|
114
|
-
|
|
115
|
-
## Dependencies
|
|
116
|
-
|
|
117
|
-
Python >= 3.8
|
|
118
|
-
Uses selenium
|
|
119
|
-
|
|
120
|
-
## License
|
|
121
|
-
|
|
122
|
-
MIT License. See LICENSE.
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
from selenium.common.exceptions import NoSuchElementException
|
|
2
|
-
from selenium.webdriver import ActionChains
|
|
3
|
-
from selenium.webdriver.common.by import By
|
|
4
|
-
from selenium.webdriver.common.keys import Keys
|
|
5
|
-
from selenium.webdriver.support import expected_conditions as EC
|
|
6
|
-
from selenium.webdriver.remote.webdriver import WebDriver
|
|
7
|
-
from selenium.webdriver.remote.webelement import WebElement
|
|
8
|
-
from selenium.webdriver.support.ui import WebDriverWait
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class ComponentUtils:
|
|
12
|
-
"""
|
|
13
|
-
Utility class for interacting with various components in Appian UI.
|
|
14
|
-
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
@staticmethod
|
|
18
|
-
def today():
|
|
19
|
-
"""
|
|
20
|
-
Returns today's date formatted as MM/DD/YYYY.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
from datetime import date
|
|
24
|
-
|
|
25
|
-
today = date.today()
|
|
26
|
-
yesterday_formatted = today.strftime("%m/%d/%Y")
|
|
27
|
-
return yesterday_formatted
|
|
28
|
-
|
|
29
|
-
@staticmethod
|
|
30
|
-
def yesterday():
|
|
31
|
-
"""
|
|
32
|
-
Returns yesterday's date formatted as MM/DD/YYYY.
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
from datetime import date, timedelta
|
|
36
|
-
|
|
37
|
-
yesterday = date.today() - timedelta(days=1)
|
|
38
|
-
yesterday_formatted = yesterday.strftime("%m/%d/%Y")
|
|
39
|
-
return yesterday_formatted
|
|
40
|
-
|
|
41
|
-
@staticmethod
|
|
42
|
-
def findChildComponent(wait: WebDriverWait, component: WebElement, xpath: str):
|
|
43
|
-
return component.find_element(By.XPATH, xpath)
|
|
44
|
-
|
|
45
|
-
@staticmethod
|
|
46
|
-
def findSuccessMessage(wait: WebDriverWait, message: str):
|
|
47
|
-
"""
|
|
48
|
-
Finds a success message in the UI by its text.
|
|
49
|
-
Parameters:
|
|
50
|
-
wait: Selenium WebDriverWait instance.
|
|
51
|
-
message: The text of the success message to find.
|
|
52
|
-
Returns:
|
|
53
|
-
The Selenium WebElement for the success message.
|
|
54
|
-
Example:
|
|
55
|
-
ComponentUtils.findSuccessMessage(wait, "Operation completed successfully")
|
|
56
|
-
"""
|
|
57
|
-
# This method locates a success message that contains a strong tag with the specified text.
|
|
58
|
-
# The message is normalized to handle any extra spaces.
|
|
59
|
-
# It uses the presence_of_element_located condition to ensure the element is present in the DOM.
|
|
60
|
-
|
|
61
|
-
xpath = f'.//div/div/p/span/strong[normalize-space(text())="{message}"]'
|
|
62
|
-
component = wait.until(EC.presence_of_element_located((By.XPATH, xpath)))
|
|
63
|
-
return component
|
|
64
|
-
|
|
65
|
-
@staticmethod
|
|
66
|
-
def findComponentUsingXpathAndClick(wait: WebDriverWait, xpath: str):
|
|
67
|
-
"""
|
|
68
|
-
Finds a component using its XPath and clicks it.
|
|
69
|
-
Parameters:
|
|
70
|
-
wait: Selenium WebDriverWait instance.
|
|
71
|
-
xpath: The XPath of the component to find and click.
|
|
72
|
-
Example:
|
|
73
|
-
ComponentUtils.findComponentUsingXpathAndClick(wait, "//button[@id='submit']")
|
|
74
|
-
|
|
75
|
-
"""
|
|
76
|
-
# This method locates a component using the provided XPath and clicks it.
|
|
77
|
-
# It uses the presence_of_element_located condition to ensure the element is present in the DOM.
|
|
78
|
-
# After locating the component, it clicks it to perform the action.
|
|
79
|
-
component = ComponentUtils.findComponentUsingXpath(wait, xpath)
|
|
80
|
-
component.click()
|
|
81
|
-
|
|
82
|
-
@staticmethod
|
|
83
|
-
def findComponentUsingXpath(wait: WebDriverWait, xpath: str):
|
|
84
|
-
"""
|
|
85
|
-
Finds a component using its XPath.
|
|
86
|
-
Parameters:
|
|
87
|
-
wait: Selenium WebDriverWait instance.
|
|
88
|
-
xpath: The XPath of the component to find.
|
|
89
|
-
Returns:
|
|
90
|
-
The Selenium WebElement for the component.
|
|
91
|
-
Example:
|
|
92
|
-
ComponentUtils.findComponentUsingXpath(wait, "//button[@id='submit']")
|
|
93
|
-
"""
|
|
94
|
-
# This method locates a component using the provided XPath.
|
|
95
|
-
# It uses the presence_of_element_located condition to ensure the element is present in the DOM.
|
|
96
|
-
# The method returns the WebElement for further interaction.
|
|
97
|
-
component = wait.until(EC.presence_of_element_located((By.XPATH, xpath)))
|
|
98
|
-
return component
|
|
99
|
-
|
|
100
|
-
@staticmethod
|
|
101
|
-
def checkComponentExistsByXpath(wait: WebDriverWait, xpath: str):
|
|
102
|
-
"""
|
|
103
|
-
Checks if a component exists using its XPath.
|
|
104
|
-
Parameters:
|
|
105
|
-
wait: Selenium WebDriverWait instance.
|
|
106
|
-
xpath: The XPath of the component to check.
|
|
107
|
-
Returns:
|
|
108
|
-
True if the component exists, False otherwise.
|
|
109
|
-
Example:
|
|
110
|
-
ComponentUtils.checkComponentExistsByXpath(wait, "//button[@id='submit']")
|
|
111
|
-
"""
|
|
112
|
-
# This method checks if a component exists by attempting to find it using the provided XPath.
|
|
113
|
-
# If the component is found, it returns True; otherwise, it catches the NoSuchElementException and returns False.
|
|
114
|
-
# It uses the presence_of_element_located condition to ensure the element is present in the DOM.
|
|
115
|
-
|
|
116
|
-
status = False
|
|
117
|
-
try:
|
|
118
|
-
ComponentUtils.findComponentUsingXpath(wait, xpath)
|
|
119
|
-
status = True
|
|
120
|
-
except NoSuchElementException:
|
|
121
|
-
pass
|
|
122
|
-
|
|
123
|
-
return status
|
|
124
|
-
|
|
125
|
-
@staticmethod
|
|
126
|
-
def checkComponentExistsById(driver: WebDriver, id: str):
|
|
127
|
-
"""
|
|
128
|
-
Checks if a component exists using its ID.
|
|
129
|
-
Parameters:
|
|
130
|
-
driver: Selenium WebDriver instance.
|
|
131
|
-
id: The ID of the component to check.
|
|
132
|
-
Returns:
|
|
133
|
-
True if the component exists, False otherwise.
|
|
134
|
-
Example:
|
|
135
|
-
ComponentUtils.checkComponentExistsById(driver, "submit-button")
|
|
136
|
-
"""
|
|
137
|
-
# This method checks if a component exists by attempting to find it using the provided ID.
|
|
138
|
-
# If the component is found, it returns True; otherwise, it catches the NoSuchElementException and returns False.
|
|
139
|
-
# It uses the find_element method to locate the element by its ID.
|
|
140
|
-
|
|
141
|
-
status = False
|
|
142
|
-
try:
|
|
143
|
-
driver.find_element(By.ID, id)
|
|
144
|
-
status = True
|
|
145
|
-
except NoSuchElementException:
|
|
146
|
-
pass
|
|
147
|
-
|
|
148
|
-
return status
|
|
149
|
-
|
|
150
|
-
@staticmethod
|
|
151
|
-
def findCount(wait: WebDriverWait, xpath: str):
|
|
152
|
-
"""
|
|
153
|
-
Finds the count of components matching the given XPath.
|
|
154
|
-
Parameters:
|
|
155
|
-
wait: Selenium WebDriverWait instance.
|
|
156
|
-
xpath: The XPath of the components to count.
|
|
157
|
-
Returns:
|
|
158
|
-
The count of components matching the XPath.
|
|
159
|
-
Example:
|
|
160
|
-
count = ComponentUtils.findCount(wait, "//div[@class='item']")
|
|
161
|
-
"""
|
|
162
|
-
# This method locates all components matching the provided XPath and returns their count.
|
|
163
|
-
# It uses the presence_of_all_elements_located condition to ensure all elements are present in the DOM.
|
|
164
|
-
# If no elements are found, it catches the NoSuchElementException and returns 0.
|
|
165
|
-
|
|
166
|
-
length = 0
|
|
167
|
-
|
|
168
|
-
try:
|
|
169
|
-
component = wait.until(EC.presence_of_all_elements_located((By.XPATH, xpath)))
|
|
170
|
-
length = len(component)
|
|
171
|
-
except NoSuchElementException:
|
|
172
|
-
pass
|
|
173
|
-
|
|
174
|
-
return length
|
|
175
|
-
|
|
176
|
-
@staticmethod
|
|
177
|
-
def tab(driver: WebDriver):
|
|
178
|
-
"""
|
|
179
|
-
Simulates a TAB key press in the browser.
|
|
180
|
-
|
|
181
|
-
Parameters:
|
|
182
|
-
driver: Selenium WebDriver instance.
|
|
183
|
-
Example:
|
|
184
|
-
ComponentUtils.tab(driver)
|
|
185
|
-
"""
|
|
186
|
-
# This method simulates a TAB key press in the browser using ActionChains.
|
|
187
|
-
# It creates an ActionChains instance, sends the TAB key, and performs the action.
|
|
188
|
-
# This is useful for navigating through form fields or components in the UI.
|
|
189
|
-
# It uses the ActionChains class to perform the key press action.
|
|
190
|
-
|
|
191
|
-
actions = ActionChains(driver)
|
|
192
|
-
actions.send_keys(Keys.TAB).perform()
|
|
193
|
-
|
|
194
|
-
@staticmethod
|
|
195
|
-
def findComponentsByXPath(wait: WebDriverWait, xpath: str):
|
|
196
|
-
"""
|
|
197
|
-
Finds multiple components that match the same XPath.
|
|
198
|
-
|
|
199
|
-
Parameters:
|
|
200
|
-
wait: Selenium WebDriverWait instance.
|
|
201
|
-
xpath: The XPath expression to find components.
|
|
202
|
-
|
|
203
|
-
Returns:
|
|
204
|
-
List of WebElement objects that match the XPath.
|
|
205
|
-
|
|
206
|
-
Raises:
|
|
207
|
-
Exception: If no components are found.
|
|
208
|
-
"""
|
|
209
|
-
|
|
210
|
-
# Wait for at least one element to be present
|
|
211
|
-
wait.until(EC.presence_of_element_located((By.XPATH, xpath)))
|
|
212
|
-
|
|
213
|
-
# Find all matching elements
|
|
214
|
-
driver = wait._driver
|
|
215
|
-
components = driver.find_elements(By.XPATH, xpath)
|
|
216
|
-
|
|
217
|
-
# Filter for clickable and displayed components
|
|
218
|
-
valid_components = []
|
|
219
|
-
for component in components:
|
|
220
|
-
try:
|
|
221
|
-
if component.is_displayed() and component.is_enabled():
|
|
222
|
-
valid_components.append(component)
|
|
223
|
-
except Exception:
|
|
224
|
-
continue
|
|
225
|
-
|
|
226
|
-
if len(valid_components) > 0:
|
|
227
|
-
return valid_components
|
|
228
|
-
|
|
229
|
-
raise Exception(f"No valid components found for XPath: {xpath}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|