robo_appian 0.0.27__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.
@@ -0,0 +1,29 @@
1
+ from robo_appian.components.ButtonUtils import ButtonUtils
2
+ from robo_appian.utils.ComponentUtils import ComponentUtils
3
+ from robo_appian.components.DateUtils import DateUtils
4
+ from robo_appian.components.DropdownUtils import DropdownUtils
5
+ from robo_appian.components.InputUtils import InputUtils
6
+ from robo_appian.components.LabelUtils import LabelUtils
7
+ from robo_appian.components.LinkUtils import LinkUtils
8
+ from robo_appian.components.SearchDropdownUtils import SearchDropdownUtils
9
+ from robo_appian.components.TableUtils import TableUtils
10
+ from robo_appian.components.TabUtils import TabUtils
11
+ from robo_appian.utils.BrowserUtils import BrowserUtils
12
+ from robo_appian.components.SearchInputUtils import SearchInputUtils
13
+
14
+ __version__ = ComponentUtils.get_version()
15
+
16
+ __all__ = [
17
+ "ButtonUtils",
18
+ "ComponentUtils",
19
+ "DateUtils",
20
+ "DropdownUtils",
21
+ "InputUtils",
22
+ "LabelUtils",
23
+ "LinkUtils",
24
+ "SearchDropdownUtils",
25
+ "TableUtils",
26
+ "TabUtils",
27
+ "BrowserUtils",
28
+ "SearchInputUtils"
29
+ ]
@@ -0,0 +1,137 @@
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
+ from selenium.webdriver.remote.webelement import WebElement
5
+ from robo_appian.utils.ComponentUtils import ComponentUtils
6
+
7
+
8
+ class ButtonUtils:
9
+ """
10
+ Utility class for interacting with button components in Appian UI.
11
+ Usage Example:
12
+ # Click a button by its label
13
+ from robo_appian.components.ButtonUtils import ButtonUtils
14
+ ButtonUtils.clickByLabelText(wait, "Submit")
15
+ """
16
+
17
+ @staticmethod
18
+ def __click(wait: WebDriverWait, component: WebElement):
19
+ wait.until(EC.element_to_be_clickable(component))
20
+ component.click()
21
+
22
+ @staticmethod
23
+ def _findByPartialLabelText(wait: WebDriverWait, label: str):
24
+ """
25
+ Finds a button by its label.
26
+
27
+ Parameters:
28
+ wait: Selenium WebDriverWait instance.
29
+ label: The label of the button to find.
30
+ label: The label of the button to find.
31
+
32
+ Returns:
33
+ WebElement representing the button.
34
+
35
+ Example:
36
+ component = ButtonUtils._findByPartialLabelText(wait, "Submit")
37
+ """
38
+ xpath = f"//button[./span[contains(translate(normalize-space(.), '\u00a0', ' '), '{label}')]]"
39
+ try:
40
+ component = ComponentUtils.waitForComponentToBeVisibleByXpath(wait, xpath)
41
+ except Exception as e:
42
+ raise Exception(
43
+ f"Button with label '{label}' not found or not clickable."
44
+ ) from e
45
+ return component
46
+
47
+ @staticmethod
48
+ def __findByLabelText(wait: WebDriverWait, label: str):
49
+ xpath = f".//button[./span[normalize-space(.)='{label}']]"
50
+ try:
51
+ component = ComponentUtils.waitForComponentToBeVisibleByXpath(wait, xpath)
52
+ except Exception as e:
53
+ raise Exception(f"Button with label '{label}' not found.") from e
54
+ return component
55
+
56
+ @staticmethod
57
+ def clickByPartialLabelText(wait: WebDriverWait, label: str):
58
+ """Finds a button by its partial label and clicks it.
59
+
60
+ Parameters:
61
+ wait: Selenium WebDriverWait instance.
62
+ label: The partial label of the button to click.
63
+ Example:
64
+ ButtonUtils.clickByPartialLabelText(wait, "Button Label")
65
+ """
66
+ component = ButtonUtils._findByPartialLabelText(wait, label)
67
+ ButtonUtils.__click(wait, component)
68
+
69
+ @staticmethod
70
+ def clickByLabelText(wait: WebDriverWait, label: str):
71
+ """Finds a button by its label and clicks it.
72
+
73
+ Parameters:
74
+ wait: Selenium WebDriverWait instance.
75
+ label: The label of the button to click.
76
+ Example:
77
+ ButtonUtils.clickByLabelText(wait, "Button Label")
78
+ """
79
+ component = ButtonUtils.__findByLabelText(wait, label)
80
+ ButtonUtils.__click(wait, component)
81
+
82
+ @staticmethod
83
+ def clickById(wait: WebDriverWait, id: str):
84
+ """
85
+ Finds and clicks an input button by its HTML id attribute.
86
+
87
+ Parameters:
88
+ wait: Selenium WebDriverWait instance.
89
+ id: The HTML id of the input button.
90
+
91
+ Example:
92
+ ButtonUtils.clickById(wait, "button_id")
93
+
94
+ """
95
+ try:
96
+ component = wait.until(EC.element_to_be_clickable((By.ID, id)))
97
+ except Exception as e:
98
+ raise Exception(
99
+ f"Input button with id '{id}' not found or not clickable."
100
+ ) from e
101
+
102
+ ButtonUtils.__click(wait, component)
103
+
104
+ @staticmethod
105
+ def isButtonExistsByLabelText(wait: WebDriverWait, label: str):
106
+ xpath = f".//button[./span[normalize-space(.)='{label}']]"
107
+ try:
108
+ ComponentUtils.findComponentByXPath(wait, xpath)
109
+ except Exception:
110
+ return False
111
+ return True
112
+
113
+ @staticmethod
114
+ def isButtonExistsByPartialLabelText(wait: WebDriverWait, label: str):
115
+ xpath = f".//button[./span[contains(translate(normalize-space(.), '\u00a0', ' '), '{label}')]]"
116
+ try:
117
+ ComponentUtils.findComponentByXPath(wait, xpath)
118
+ except Exception:
119
+ return False
120
+ return True
121
+
122
+ @staticmethod
123
+ def isButtonExistsByPartialLabelTextAfterLoad(wait: WebDriverWait, label: str):
124
+ try:
125
+ ButtonUtils._findByPartialLabelText(wait, label)
126
+ except Exception:
127
+ return False
128
+ return True
129
+
130
+ @staticmethod
131
+ def waitForButtonToBeVisibleByPartialLabelText(wait: WebDriverWait, label: str):
132
+ xpath = f".//button[./span[contains(translate(normalize-space(.), '\u00a0', ' '), '{label}')]]"
133
+ try:
134
+ component = ComponentUtils.waitForComponentToBeVisibleByXpath(wait, xpath)
135
+ except Exception as e:
136
+ raise Exception(f"Button with partial label '{label}' not visible.") from e
137
+ return component
@@ -0,0 +1,64 @@
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
+
28
+ xpath = f'.//div[./div/label[text()="{label}"]]/div/div/div/input'
29
+ try:
30
+ component = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
31
+ except Exception as e:
32
+ raise Exception(
33
+ f"Could not find clickable date component with label '{label}': {e}"
34
+ )
35
+ return component
36
+
37
+ @staticmethod
38
+ def setValueByLabelText(wait: WebDriverWait, label: str, value: str):
39
+ """
40
+ Sets the value of a date component.
41
+ :param wait: WebDriverWait instance to wait for elements.
42
+ :param label: The label of the date component.
43
+ :param value: The value to set in the date component.
44
+ :return: The WebElement representing the date component.
45
+ Example:
46
+ DateUtils.setValueByLabelText(wait, "Start Date", "2023-10-01")
47
+ """
48
+ component = DateUtils.__findComponent(wait, label)
49
+ InputUtils._setValueByComponent(wait, component, value)
50
+ return component
51
+
52
+ @staticmethod
53
+ def clickByLabelText(wait: WebDriverWait, label: str):
54
+ """
55
+ Clicks on the date component to open the date picker.
56
+ :param wait: WebDriverWait instance to wait for elements.
57
+ :param label: The label of the date component.
58
+ :return: The WebElement representing the date component.
59
+ Example:
60
+ DateUtils.clickByLabelText(wait, "Start Date")
61
+ """
62
+ component = DateUtils.__findComponent(wait, label)
63
+ component.click()
64
+ return component
@@ -0,0 +1,388 @@
1
+ import time
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
+ from selenium.common.exceptions import NoSuchElementException
7
+
8
+
9
+ class DropdownUtils:
10
+ """
11
+ Utility class for interacting with dropdown components in Appian UI.
12
+ Usage Example:
13
+ # Select a value from a dropdown
14
+ from robo_appian.components.DropdownUtils import DropdownUtils
15
+ DropdownUtils.selectDropdownValueByLabelText(wait, "Status", "Approved")
16
+ """
17
+
18
+ @staticmethod
19
+ def __findComboboxByLabelText(
20
+ wait: WebDriverWait, label: str, isPartialText: bool = False
21
+ ):
22
+ """
23
+ Finds the combobox element by its label text.
24
+ :param wait: WebDriverWait instance to wait for elements.
25
+ :param label: The label of the combobox.
26
+ :param isPartialText: Whether to use partial text matching for the label.
27
+ :return: The combobox WebElement.
28
+ Example:
29
+ combobox = DropdownUtils.__findComboboxByLabelText(wait, "Dropdown Label", isPartialText=False)
30
+ combobox = DropdownUtils.__findComboboxByLabelText(wait, "Dropdown Label", isPartialText=True)
31
+ combobox = DropdownUtils.__findComboboxByLabelText(wait, "Dropdown Label")
32
+ """
33
+
34
+ if isPartialText:
35
+ xpath = f'//span[contains(normalize-space(.), "{label}")]/ancestor::div[@role="presentation"][1]//div[@aria-labelledby=//span[contains(normalize-space(.), "{label}")]/@id and @role="combobox" and not(@aria-disabled="true")]'
36
+ else:
37
+ xpath = f'//span[normalize-space(.)="{label}"]/ancestor::div[@role="presentation"][1]//div[@aria-labelledby=//span[normalize-space(.)="{label}"]/@id and @role="combobox" and not(@aria-disabled="true")]'
38
+
39
+ try:
40
+ component = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
41
+ except Exception as e:
42
+ raise Exception(f'Could not find combobox with label "{label}" : {str(e)}')
43
+
44
+ return component
45
+
46
+ @staticmethod
47
+ def __clickCombobox(wait: WebDriverWait, combobox: WebElement):
48
+ """
49
+ Clicks the combobox to open the dropdown options.
50
+
51
+ :param wait: WebDriverWait instance to wait for elements.
52
+ :param combobox: The combobox WebElement.
53
+ Example:
54
+ DropdownUtils.__clickCombobox(wait, combobox)
55
+ """
56
+ try:
57
+ wait.until(EC.element_to_be_clickable(combobox))
58
+ combobox.click()
59
+
60
+ except Exception as e:
61
+ raise Exception(f"Could not click combobox: {str(e)}")
62
+
63
+ @staticmethod
64
+ def __findDropdownOptionId(combobox: WebElement):
65
+ """
66
+ Finds the dropdown option id from the combobox.
67
+
68
+ :param wait: WebDriverWait instance to wait for elements.
69
+ :param combobox: The combobox WebElement.
70
+ :return: The id of the dropdown options list.
71
+ Example:
72
+ dropdown_option_id = DropdownUtils.__findDropdownOptionId(wait, combobox)
73
+ """
74
+ dropdown_option_id = combobox.get_attribute("aria-controls")
75
+ if dropdown_option_id is None:
76
+ raise Exception(
77
+ 'Dropdown component does not have a valid "aria-controls" attribute.'
78
+ )
79
+ return dropdown_option_id
80
+
81
+ @staticmethod
82
+ def __checkDropdownOptionValueExistsByDropdownOptionId(
83
+ wait: WebDriverWait, dropdown_option_id: str, value: str
84
+ ):
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(.)="{value}"]]'
100
+ try:
101
+ wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
102
+ return True
103
+ except NoSuchElementException:
104
+ return False
105
+ except Exception as e:
106
+ raise Exception(
107
+ f'Could not find dropdown option "{value}" with dropdown option id "{dropdown_option_id}": {str(e)}'
108
+ )
109
+
110
+ @staticmethod
111
+ def __selectDropdownValueByDropdownOptionId(
112
+ wait: WebDriverWait, dropdown_option_id: str, value: str
113
+ ):
114
+ """
115
+ Selects a value from a dropdown by its option id and value.
116
+
117
+ :param wait: WebDriverWait instance to wait for elements.
118
+ :param dropdown_option_id: The id of the dropdown options list.
119
+ :param value: The value to select from the dropdown.
120
+ Example:
121
+ DropdownUtils.selectDropdownValueByDropdownOptionId(wait, "dropdown_option_id", "Option Value")
122
+ """
123
+ option_xpath = f'.//div/ul[@id="{dropdown_option_id}"]/li[./div[normalize-space(.)="{value}"]]'
124
+ try:
125
+ try:
126
+ component = wait.until(
127
+ EC.presence_of_element_located((By.XPATH, option_xpath))
128
+ )
129
+ component = wait.until(
130
+ EC.element_to_be_clickable((By.XPATH, option_xpath))
131
+ )
132
+ component.click()
133
+ except Exception as e:
134
+ raise Exception(
135
+ f'Could not locate or click dropdown option "{value}" with dropdown option id "{dropdown_option_id}": {str(e)}' # noqa: E501
136
+ )
137
+ except Exception as e:
138
+ raise Exception(
139
+ f'Could not find or click dropdown option "{value}" with xpath "{option_xpath}": {str(e)}'
140
+ )
141
+
142
+ @staticmethod
143
+ def __selectDropdownValueByPartialLabelText(
144
+ wait: WebDriverWait, label: str, value: str
145
+ ):
146
+ """
147
+ Selects a value from a dropdown by its label text.
148
+
149
+ :param wait: WebDriverWait instance to wait for elements.
150
+ :param label: The label of the dropdown.
151
+ :param value: The value to select from the dropdown.
152
+ """
153
+ combobox = DropdownUtils.__findComboboxByLabelText(wait, label, True)
154
+ DropdownUtils.__clickCombobox(wait, combobox)
155
+ dropdown_option_id = DropdownUtils.__findDropdownOptionId(combobox)
156
+ DropdownUtils.__selectDropdownValueByDropdownOptionId(
157
+ wait, dropdown_option_id, value
158
+ )
159
+
160
+ @staticmethod
161
+ def __selectDropdownValueByLabelText(wait: WebDriverWait, label: str, value: str):
162
+ """
163
+ Selects a value from a dropdown by its label text.
164
+
165
+ :param wait: WebDriverWait instance to wait for elements.
166
+ :param label: The label of the dropdown.
167
+ :param value: The value to select from the dropdown.
168
+ """
169
+ combobox = DropdownUtils.__findComboboxByLabelText(wait, label)
170
+ DropdownUtils.__clickCombobox(wait, combobox)
171
+ dropdown_option_id = DropdownUtils.__findDropdownOptionId(combobox)
172
+ DropdownUtils.__selectDropdownValueByDropdownOptionId(
173
+ wait, dropdown_option_id, value
174
+ )
175
+
176
+ @staticmethod
177
+ def checkReadOnlyStatusByLabelText(wait: WebDriverWait, label: str):
178
+ """
179
+ Checks if a dropdown is read-only by its label text.
180
+
181
+ :param wait: WebDriverWait instance to wait for elements.
182
+ :param label: The label of the dropdown.
183
+ :return: True if the dropdown is read-only, False otherwise.
184
+ Example:
185
+ is_read_only = DropdownUtils.checkReadOnlyStatusByLabelText(wait, "Dropdown Label")
186
+ if is_read_only:
187
+ print("The dropdown is read-only.")
188
+ else:
189
+ print("The dropdown is editable.")
190
+ """
191
+ # xpath = f'.//div[./div/span[normalize-space(.)="{label}"]]/div/div/p[text()]'
192
+ xpath = f'//span[normalize-space(.)="{label}"]/ancestor::div[@role="presentation"][1]//div[@aria-labelledby=//span[normalize-space(.)="{label}"]/@id and not(@role="combobox")]'
193
+ try:
194
+ wait._driver.find_element(By.XPATH, xpath)
195
+ return True
196
+ except NoSuchElementException:
197
+ return False
198
+ except Exception:
199
+ raise Exception(f'Error checking read-only status for label "{label}"')
200
+
201
+ @staticmethod
202
+ def checkEditableStatusByLabelText(wait: WebDriverWait, label: str):
203
+ """
204
+ Checks if a dropdown is editable (not disabled) by its label text.
205
+
206
+ :param wait: WebDriverWait instance to wait for elements.
207
+ :param label: The label of the dropdown.
208
+ :return: True if the dropdown is editable, False if disabled.
209
+ Example:
210
+ is_editable = DropdownUtils.checkEditableStatusByLabelText(wait, "Dropdown Label")
211
+ if is_editable:
212
+ print("The dropdown is editable.")
213
+ else:
214
+ print("The dropdown is disabled.")
215
+ """
216
+ xpath = f'//span[text()="{label}"]/ancestor::div[@role="presentation"][1]//div[@aria-labelledby=//span[normalize-space(.)="{label}"]/@id and @role="combobox" and not(@aria-disabled="true")]'
217
+ try:
218
+ wait._driver.find_element(By.XPATH, xpath)
219
+ return True # If disabled element is found, dropdown is not editable
220
+ except NoSuchElementException:
221
+ return False # If disabled element is not found, dropdown is editable
222
+ except Exception:
223
+ raise Exception(f'Error checking editable status for label "{label}"')
224
+
225
+ @staticmethod
226
+ def waitForDropdownToBeEnabled(
227
+ wait: WebDriverWait, label: str, wait_interval: float = 0.5, timeout: int = 2
228
+ ):
229
+ elapsed_time = 0
230
+ status = False
231
+
232
+ while elapsed_time < timeout:
233
+ status = DropdownUtils.checkEditableStatusByLabelText(wait, label)
234
+ if status:
235
+ return True
236
+ time.sleep(wait_interval)
237
+ elapsed_time += wait_interval
238
+ return False
239
+
240
+ @staticmethod
241
+ def selectDropdownValueByComboboxComponent(
242
+ wait: WebDriverWait, combobox: WebElement, value: str
243
+ ):
244
+ """
245
+ Selects a value from a dropdown using the combobox component.
246
+
247
+ :param wait: WebDriverWait instance to wait for elements.
248
+ :param combobox: The combobox WebElement.
249
+ :param value: The value to select from the dropdown.
250
+ Example:
251
+ DropdownUtils.selectDropdownValueByComboboxComponent(wait, combobox, "Option Value")
252
+ """
253
+ dropdown_option_id = DropdownUtils.__findDropdownOptionId(combobox)
254
+ DropdownUtils.__clickCombobox(wait, combobox)
255
+ DropdownUtils.__selectDropdownValueByDropdownOptionId(
256
+ wait, dropdown_option_id, value
257
+ )
258
+
259
+ @staticmethod
260
+ def selectDropdownValueByLabelText(
261
+ wait: WebDriverWait, dropdown_label: str, value: str
262
+ ):
263
+ """
264
+ Selects a value from a dropdown by its label text.
265
+
266
+ :param wait: WebDriverWait instance to wait for elements.
267
+ :param dropdown_label: The label of the dropdown.
268
+ :param value: The value to select from the dropdown.
269
+ Example:
270
+ DropdownUtils.selectDropdownValueByLabelText(wait, "Dropdown Label", "Option Value")
271
+ """
272
+ DropdownUtils.__selectDropdownValueByLabelText(wait, dropdown_label, value)
273
+
274
+ @staticmethod
275
+ def selectDropdownValueByPartialLabelText(
276
+ wait: WebDriverWait, dropdown_label: str, value: str
277
+ ):
278
+ """
279
+ Selects a value from a dropdown by its partial label text.
280
+
281
+ :param wait: WebDriverWait instance to wait for elements.
282
+ :param dropdown_label: The partial label of the dropdown.
283
+ :param value: The value to select from the dropdown.
284
+ Example:
285
+ DropdownUtils.selectDropdownValueByPartialLabelText(wait, "Dropdown Label", "Option Value")
286
+ """
287
+ DropdownUtils.__selectDropdownValueByPartialLabelText(
288
+ wait, dropdown_label, value
289
+ )
290
+
291
+ @staticmethod
292
+ def checkDropdownOptionValueExists(
293
+ wait: WebDriverWait, dropdown_label: str, value: str
294
+ ):
295
+ """
296
+ Checks if a dropdown option value exists by its label text.
297
+
298
+ :param wait: WebDriverWait instance to wait for elements.
299
+ :param dropdown_label: The label of the dropdown.
300
+ :param value: The value to check in the dropdown.
301
+ :return: True if the value exists, False otherwise.
302
+ Example:
303
+ exists = DropdownUtils.checkDropdownOptionValueExists(wait, "Dropdown Label", "Option Value")
304
+ if exists:
305
+ print("The value exists in the dropdown.")
306
+ else:
307
+ print("The value does not exist in the dropdown.")
308
+ """
309
+ combobox = DropdownUtils.__findComboboxByLabelText(wait, dropdown_label)
310
+ DropdownUtils.__clickCombobox(wait, combobox)
311
+ dropdown_option_id = DropdownUtils.__findDropdownOptionId(combobox)
312
+ return DropdownUtils.__checkDropdownOptionValueExistsByDropdownOptionId(
313
+ wait, dropdown_option_id, value
314
+ )
315
+
316
+ @staticmethod
317
+ def getDropdownOptionValues(wait: WebDriverWait, dropdown_label: str) -> list[str]:
318
+ """
319
+ Gets all option values from a dropdown by its label text.
320
+
321
+ :param wait: WebDriverWait instance to wait for elements.
322
+ :param dropdown_label: The label of the dropdown.
323
+ :return: A list of all option values in the dropdown.
324
+ Example:
325
+ values = DropdownUtils.getDropdownOptionValues(wait, "Dropdown Label")
326
+ """
327
+ combobox = DropdownUtils.__findComboboxByLabelText(wait, dropdown_label)
328
+ DropdownUtils.__clickCombobox(wait, combobox)
329
+ dropdown_option_id = DropdownUtils.__findDropdownOptionId(combobox)
330
+
331
+ # Get all option elements
332
+ xpath = f'//ul[@id="{dropdown_option_id}"]//li[@role="option"]/div'
333
+ try:
334
+ option_elements = wait.until(
335
+ EC.presence_of_all_elements_located((By.XPATH, xpath))
336
+ )
337
+ # Extract text immediately to avoid stale element reference
338
+ option_texts = []
339
+ for element in option_elements:
340
+ try:
341
+ text = element.text.strip()
342
+ if text:
343
+ option_texts.append(text)
344
+ except Exception:
345
+ # If element becomes stale, try to re-find it
346
+ continue
347
+
348
+ # If we got no texts due to stale elements, try one more time
349
+ if not option_texts:
350
+ option_elements = wait._driver.find_elements(By.XPATH, xpath)
351
+ for element in option_elements:
352
+ try:
353
+ text = element.text.strip()
354
+ if text:
355
+ option_texts.append(text)
356
+ except Exception:
357
+ continue
358
+
359
+ DropdownUtils.__clickCombobox(wait, combobox)
360
+ return option_texts
361
+ except Exception as e:
362
+ raise Exception(
363
+ f'Could not get dropdown option values for label "{dropdown_label}": {str(e)}'
364
+ )
365
+
366
+ @staticmethod
367
+ def waitForDropdownValuesToBeChanged(
368
+ wait: WebDriverWait,
369
+ dropdown_label: str,
370
+ initial_values: list[str],
371
+ poll_frequency: float = 0.5,
372
+ timeout: int = 2,
373
+ ):
374
+
375
+ elapsed_time = 0
376
+ poll_frequency = 0.5
377
+ timeout = 4 # seconds
378
+ while elapsed_time < timeout:
379
+
380
+ current_values: list[str] = DropdownUtils.getDropdownOptionValues(
381
+ wait, dropdown_label
382
+ )
383
+
384
+ # Compare job series values before and after position job title selection
385
+ if initial_values != current_values:
386
+ break
387
+ time.sleep(poll_frequency)
388
+ elapsed_time += poll_frequency