Skip to content

Commit e914ead

Browse files
test: Enhance US05 tests with improved back button navigation and error handling
1 parent c412fcb commit e914ead

File tree

1 file changed

+148
-29
lines changed

1 file changed

+148
-29
lines changed

tests/us5.py

Lines changed: 148 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class US05Tests(unittest.TestCase):
3232
FIRST_TIME_ALERT_BUTTON_SELECTOR = ".alert__button.alert__button--single"
3333
ALERT_OVERLAY_SELECTOR = "div.alert__overlay"
3434
NAV_BACK_BUTTON_XPATH = "//button[contains(@class, 'nav-bar__button') and .//span[contains(@class, 'back-icon')]/svg[contains(@class, 'lucide-chevron-left')]]"
35+
# Simpler CSS selector for the back button - targeting the first button in the nav-bar
36+
NAV_BACK_BUTTON_SELECTOR = "nav.nav-bar > button.nav-bar__button:first-child"
3537
HOME_CONTAINER_SELECTOR = "div.home__container"
3638
SETTINGS_NAV_BUTTON_XPATH = "//button[contains(@class, 'nav-bar__button') and .//span[contains(@class, 'settings-icon')]/svg[contains(@class, 'lucide-settings')]]"
3739
APPROVAL_GRADE_INPUT_SELECTOR = "input.settings__input[type='number']" # Hypothetical for settings page
@@ -65,14 +67,14 @@ def setUp(self):
6567
logger.error("Driver is not initialized after setup attempt.")
6668
self.fail("Driver could not be initialized.")
6769
return
68-
self._initial_setup()
69-
70+
self._initial_setup()
71+
7072
def tearDown(self):
7173
if hasattr(self, 'is_driver_managed_by_fallback') and self.is_driver_managed_by_fallback:
7274
if self.driver:
7375
self.driver.quit()
7476
# For pytest-managed driver, teardown is handled by the fixture
75-
77+
7678
def _take_screenshot(self, name_suffix):
7779
timestamp = int(time.time())
7880
test_method_name = getattr(self, '_testMethodName', 'unknown_test')
@@ -83,21 +85,41 @@ def _take_screenshot(self, name_suffix):
8385
logger.info(f"Screenshot saved: {screenshot_name}")
8486
except Exception as e:
8587
logger.error(f"Error saving screenshot {screenshot_name}: {e}")
86-
88+
8789
def _initial_setup(self):
90+
if not hasattr(self, 'driver') or not self.driver:
91+
logger.error("Driver not initialized in _initial_setup. Aborting setup.")
92+
self.fail("Driver not initialized for test setup.")
93+
return
94+
8895
self.driver.get(self.BASE_URL)
8996
logger.info(f"Navigated to base URL: {self.BASE_URL}")
9097
try:
98+
logger.info(f"Attempting to handle first-time alert with button '{self.FIRST_TIME_ALERT_BUTTON_SELECTOR}'.")
9199
alert_button = WebDriverWait(self.driver, 10).until(
92100
EC.element_to_be_clickable((By.CSS_SELECTOR, self.FIRST_TIME_ALERT_BUTTON_SELECTOR))
93101
)
94102
alert_button.click()
103+
logger.info(f"Clicked first-time alert button: '{self.FIRST_TIME_ALERT_BUTTON_SELECTOR}'.")
104+
95105
WebDriverWait(self.driver, 5).until(
96106
EC.invisibility_of_element_located((By.CSS_SELECTOR, self.ALERT_OVERLAY_SELECTOR))
97107
)
98-
nav_back_button = WebDriverWait(self.driver, 10).until(
99-
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
100-
)
108+
logger.info(f"Alert overlay '{self.ALERT_OVERLAY_SELECTOR}' is no longer visible. App should be on Settings page.")
109+
110+
# Try CSS selector first, fall back to XPath if needed
111+
try:
112+
nav_back_button = WebDriverWait(self.driver, 5).until(
113+
EC.element_to_be_clickable((By.CSS_SELECTOR, self.NAV_BACK_BUTTON_SELECTOR))
114+
)
115+
logger.info("Found back button using CSS selector.")
116+
except TimeoutException:
117+
logger.info("CSS selector failed for back button, trying XPath...")
118+
nav_back_button = WebDriverWait(self.driver, 5).until(
119+
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
120+
)
121+
logger.info("Found back button using XPath selector.")
122+
101123
nav_back_button.click()
102124
WebDriverWait(self.driver, 10).until(
103125
EC.presence_of_element_located((By.CSS_SELECTOR, self.HOME_CONTAINER_SELECTOR))
@@ -116,11 +138,9 @@ def _initial_setup(self):
116138
logger.error(f"An unexpected error occurred during initial setup: {e}", exc_info=True)
117139
self._take_screenshot("initial_setup_error")
118140
self.fail(f"Unexpected error during initial setup: {e}")
119-
120-
# Ensure approval grade is 3.0 (default)
141+
# Ensure approval grade is 3.0 (default)
121142
self._set_approval_grade("3.0")
122143

123-
124144
def _set_approval_grade(self, approval_grade_value):
125145
logger.info(f"Setting approval grade to: {approval_grade_value}")
126146
# Navigate to settings if not already there or on home
@@ -155,9 +175,13 @@ def _set_approval_grade(self, approval_grade_value):
155175
self.driver.find_element(By.XPATH, self.NAV_BACK_BUTTON_XPATH).click()
156176
self.wait_long.until(EC.presence_of_element_located((By.CSS_SELECTOR, self.HOME_CONTAINER_SELECTOR)))
157177
logger.info("Navigated back to Home page from Settings.")
158-
159-
160178
def _add_grade_and_percentage(self, grade, percentage):
179+
if not hasattr(self, 'driver') or not self.driver:
180+
logger.error("Driver not available in _add_grade_and_percentage.")
181+
self.fail("Driver not available.")
182+
return
183+
184+
# First check if we're on the result page and navigate back if needed
161185
on_result_page = False
162186
try:
163187
if self.driver.find_element(By.CSS_SELECTOR, self.RESULT_PAGE_CONTAINER_SELECTOR).is_displayed():
@@ -166,29 +190,124 @@ def _add_grade_and_percentage(self, grade, percentage):
166190
on_result_page = False
167191

168192
if on_result_page:
169-
logger.info("On result page, navigating back to home to add grades.")
170-
self.driver.find_element(By.XPATH, self.NAV_BACK_BUTTON_XPATH).click()
193+
logger.info("Currently on result page, navigating back to home to add grades.")
194+
try:
195+
# First try with the CSS selector
196+
nav_back_button = self.wait_short.until(
197+
EC.element_to_be_clickable((By.CSS_SELECTOR, self.NAV_BACK_BUTTON_SELECTOR))
198+
)
199+
logger.info("Found back button using CSS selector in _add_grade_and_percentage.")
200+
except TimeoutException:
201+
try:
202+
# Then try with XPath
203+
logger.info("CSS selector failed for back button in _add_grade_and_percentage, trying XPath...")
204+
nav_back_button = self.wait_long.until(
205+
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
206+
)
207+
logger.info("Found back button using XPath selector in _add_grade_and_percentage.")
208+
except TimeoutException:
209+
# As a last resort, try to find any buttons in the nav bar
210+
logger.info("XPath also failed. Looking for any button in the nav bar...")
211+
nav_bar = self.wait_long.until(
212+
EC.presence_of_element_located((By.CSS_SELECTOR, "nav.nav-bar"))
213+
)
214+
nav_buttons = nav_bar.find_elements(By.TAG_NAME, "button")
215+
if nav_buttons:
216+
nav_back_button = nav_buttons[0] # First button in nav bar is usually back
217+
logger.info("Using first button found in nav bar")
218+
else:
219+
logger.error("No buttons found in nav bar")
220+
self._take_screenshot("no_buttons_in_nav_bar_add_grade")
221+
self.fail("No buttons found in nav bar when trying to navigate back")
222+
223+
# Click the back button once found
224+
nav_back_button.click()
171225
self.wait_long.until(EC.presence_of_element_located((By.CSS_SELECTOR, self.HOME_CONTAINER_SELECTOR)))
226+
logger.info("Successfully navigated back to home page.")
227+
228+
# Take a small pause to ensure the UI is fully loaded
229+
time.sleep(0.5)
172230

231+
# Now we're on the home page
232+
# Take a screenshot of the current state for debugging
233+
self._take_screenshot("before_adding_grade")
234+
235+
# Find all grade rows currently in the UI
173236
grade_rows = self.driver.find_elements(By.CSS_SELECTOR, self.GRADES_LIST_ITEM_SELECTOR)
174-
if not grade_rows:
175-
self.driver.find_element(By.CSS_SELECTOR, self.ADD_GRADE_BUTTON_SELECTOR).click()
176-
time.sleep(0.5)
237+
logger.info(f"Found {len(grade_rows)} grade rows before adding.")
238+
239+
# First check if we need to add a new row
240+
need_new_row = True
241+
if grade_rows:
242+
# Check if the last row is empty (which means we can use it)
243+
last_row = grade_rows[-1]
244+
try:
245+
grade_input = last_row.find_element(By.CSS_SELECTOR, self.GRADE_INPUT_SELECTOR)
246+
percentage_input = last_row.find_element(By.CSS_SELECTOR, self.PERCENTAGE_INPUT_SELECTOR)
247+
248+
grade_value = grade_input.get_attribute("value")
249+
percentage_value = percentage_input.get_attribute("value")
250+
251+
# If both inputs are empty, we can use this row
252+
if not grade_value and not percentage_value:
253+
need_new_row = False
254+
logger.info("Found empty row to use for new grade entry.")
255+
except NoSuchElementException:
256+
# If we can't find inputs in the last row, we'll add a new one
257+
logger.warning("Last row doesn't have expected input elements.")
258+
need_new_row = True
259+
260+
# If we need a new row or there are no rows, add one
261+
if need_new_row or not grade_rows:
262+
logger.info("Adding a new grade row...")
263+
add_button = self.wait_long.until(EC.element_to_be_clickable((By.CSS_SELECTOR, self.ADD_GRADE_BUTTON_SELECTOR)))
264+
add_button.click()
265+
time.sleep(0.5) # Wait for the row to be added
266+
267+
# Refresh the list of grade rows
177268
grade_rows = self.driver.find_elements(By.CSS_SELECTOR, self.GRADES_LIST_ITEM_SELECTOR)
178-
if not grade_rows: self.fail("Failed to add initial grade row.")
179-
180-
last_row = grade_rows[-1]
181-
grade_input_element = last_row.find_element(By.CSS_SELECTOR, self.GRADE_INPUT_SELECTOR)
182-
percentage_input_element = last_row.find_element(By.CSS_SELECTOR, self.PERCENTAGE_INPUT_SELECTOR)
269+
if not grade_rows:
270+
logger.error("Failed to add grade row - no rows found after clicking 'Add' button")
271+
self._take_screenshot("failed_to_add_grade_row")
272+
self.fail("Failed to add grade row - no rows found after clicking 'Add' button")
183273

184-
grade_input_element.clear()
185-
grade_input_element.send_keys(str(grade))
186-
percentage_input_element.clear()
187-
percentage_input_element.send_keys(str(percentage))
274+
# Now use the last row to add our grade
275+
last_row = grade_rows[-1]
276+
logger.info(f"Using the last of {len(grade_rows)} rows to add grade: {grade}, percentage: {percentage}")
188277

189-
self.driver.find_element(By.CSS_SELECTOR, self.ADD_GRADE_BUTTON_SELECTOR).click()
190-
time.sleep(0.5)
191-
logger.info(f"Added grade: {grade}, percentage: {percentage}.")
278+
try:
279+
grade_input_element = last_row.find_element(By.CSS_SELECTOR, self.GRADE_INPUT_SELECTOR)
280+
percentage_input_element = last_row.find_element(By.CSS_SELECTOR, self.PERCENTAGE_INPUT_SELECTOR)
281+
282+
# Clear and enter the grade and percentage
283+
grade_input_element.clear()
284+
grade_input_element.send_keys(str(grade))
285+
percentage_input_element.clear()
286+
percentage_input_element.send_keys(str(percentage))
287+
288+
# Take screenshot after entering values
289+
self._take_screenshot(f"after_entering_grade_{grade}_percent_{percentage}")
290+
291+
# Click the add button to confirm this grade
292+
add_button = self.wait_long.until(EC.element_to_be_clickable((By.CSS_SELECTOR, self.ADD_GRADE_BUTTON_SELECTOR)))
293+
add_button.click()
294+
logger.info(f"Clicked 'Add' button after entering grade: {grade}, percentage: {percentage}")
295+
296+
# Allow time for the UI to update
297+
time.sleep(0.5)
298+
299+
# Verify the grade was added by checking for more rows or for values in the inputs
300+
new_grade_rows = self.driver.find_elements(By.CSS_SELECTOR, self.GRADES_LIST_ITEM_SELECTOR)
301+
logger.info(f"After adding: {len(new_grade_rows)} grade rows (previously {len(grade_rows)})")
302+
303+
# Take screenshot after adding grade
304+
self._take_screenshot("after_adding_grade")
305+
306+
except NoSuchElementException as e:
307+
logger.error(f"Could not find input elements in the grade row: {e}")
308+
self._take_screenshot("input_elements_not_found")
309+
self.fail(f"Input elements not found: {e}")
310+
return
192311

193312
def _get_required_grade_or_message(self):
194313
raw_text = ""

0 commit comments

Comments
 (0)