Skip to content

Commit 95fb02c

Browse files
test: Refactor US04 tests to improve back button navigation using CSS selectors and enhance error handling
1 parent d9db6cd commit 95fb02c

File tree

1 file changed

+111
-116
lines changed

1 file changed

+111
-116
lines changed

tests/us4.py

Lines changed: 111 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -26,62 +26,12 @@ class US04Tests(unittest.TestCase):
2626
RESULT_PAGE_CONTAINER_SELECTOR = "div.result"
2727
FIRST_TIME_ALERT_BUTTON_SELECTOR = ".alert__button.alert__button--single"
2828
ALERT_OVERLAY_SELECTOR = "div.alert__overlay"
29+
# Original complex XPath selector
2930
NAV_BACK_BUTTON_XPATH = "//button[contains(@class, 'nav-bar__button') and .//span[contains(@class, 'back-icon')]/svg[contains(@class, 'lucide-chevron-left')]]"
31+
# Simpler CSS selector for the back button - targeting the first button in the nav-bar
32+
NAV_BACK_BUTTON_SELECTOR = "nav.nav-bar > button.nav-bar__button:first-child"
3033
HOME_CONTAINER_SELECTOR = "div.home__container"
3134

32-
def set_driver_fixture(self, driver):
33-
self.driver = driver
34-
self.wait_short = WebDriverWait(self.driver, 5)
35-
self.wait_long = WebDriverWait(self.driver, 15)
36-
if not os.path.exists("screenshots"):
37-
os.makedirs("screenshots")
38-
39-
def setUp(self):
40-
if not hasattr(self, 'driver') or not self.driver:
41-
logger.info("WebDriver not set by fixture, attempting fallback setup for direct unittest execution.")
42-
try:
43-
options = webdriver.ChromeOptions()
44-
# options.add_argument('--headless')
45-
# options.add_argument('--disable-gpu')
46-
# options.add_argument('--window-size=1920,1080')
47-
self.driver = webdriver.Chrome(options=options)
48-
self.is_driver_managed_by_fallback = True
49-
logger.info("Fallback WebDriver initialized for direct unittest execution.")
50-
except Exception as e:
51-
logger.error(f"Failed to initialize fallback WebDriver: {e}")
52-
self.fail(f"Failed to initialize fallback WebDriver: {e}")
53-
else:
54-
logger.info("WebDriver already set, likely by a pytest fixture.")
55-
self.is_driver_managed_by_fallback = False
56-
57-
if hasattr(self, 'driver') and self.driver:
58-
self.set_driver_fixture(self.driver)
59-
else:
60-
logger.error("Driver is not initialized after setup attempt.")
61-
self.fail("Driver could not be initialized.")
62-
return
63-
64-
self._initial_setup()
65-
66-
def tearDown(self):
67-
if hasattr(self, 'is_driver_managed_by_fallback') and self.is_driver_managed_by_fallback:
68-
if self.driver:
69-
self.driver.quit()
70-
logger.info("Fallback WebDriver quit.")
71-
else:
72-
logger.info("Driver teardown managed by pytest fixture (if applicable).")
73-
74-
def _take_screenshot(self, name_suffix):
75-
timestamp = int(time.time())
76-
test_method_name = getattr(self, '_testMethodName', 'unknown_test')
77-
screenshot_name = f"screenshots/{test_method_name}_{name_suffix}_{timestamp}.png"
78-
try:
79-
if hasattr(self, 'driver') and self.driver:
80-
self.driver.save_screenshot(screenshot_name)
81-
logger.info(f"Screenshot saved: {screenshot_name}")
82-
except Exception as e:
83-
logger.error(f"Error saving screenshot {screenshot_name}: {e}")
84-
8535
def _initial_setup(self):
8636
if not hasattr(self, 'driver') or not self.driver:
8737
logger.error("Driver not initialized in _initial_setup. Aborting setup.")
@@ -104,9 +54,19 @@ def _initial_setup(self):
10454
)
10555
logger.info(f"Alert overlay '{self.ALERT_OVERLAY_SELECTOR}' is no longer visible. App should be on Settings page.")
10656

107-
nav_back_button = WebDriverWait(self.driver, 10).until(
108-
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
109-
)
57+
# Try CSS selector first, fall back to XPath if needed
58+
try:
59+
nav_back_button = WebDriverWait(self.driver, 5).until(
60+
EC.element_to_be_clickable((By.CSS_SELECTOR, self.NAV_BACK_BUTTON_SELECTOR))
61+
)
62+
logger.info("Found back button using CSS selector.")
63+
except TimeoutException:
64+
logger.info("CSS selector failed for back button, trying XPath...")
65+
nav_back_button = WebDriverWait(self.driver, 5).until(
66+
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
67+
)
68+
logger.info("Found back button using XPath selector.")
69+
11070
nav_back_button.click()
11171
logger.info("Clicked nav back button to return to Home page.")
11272

@@ -153,9 +113,18 @@ def _add_grade_and_percentage(self, grade, percentage):
153113

154114
if on_result_page:
155115
logger.info("Currently on result page (detected by element presence), navigating back to home to add grades.")
156-
nav_back_button = self.wait_long.until(
157-
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
158-
)
116+
try:
117+
nav_back_button = self.wait_short.until(
118+
EC.element_to_be_clickable((By.CSS_SELECTOR, self.NAV_BACK_BUTTON_SELECTOR))
119+
)
120+
logger.info("Found back button using CSS selector in _add_grade_and_percentage.")
121+
except TimeoutException:
122+
logger.info("CSS selector failed for back button in _add_grade_and_percentage, trying XPath...")
123+
nav_back_button = self.wait_long.until(
124+
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
125+
)
126+
logger.info("Found back button using XPath selector in _add_grade_and_percentage.")
127+
159128
nav_back_button.click()
160129
self.wait_long.until(EC.presence_of_element_located((By.CSS_SELECTOR, self.HOME_CONTAINER_SELECTOR)))
161130
logger.info("Navigated back to home page.")
@@ -209,53 +178,6 @@ def _add_grade_and_percentage(self, grade, percentage):
209178
logger.info(f"Clicked 'Agregar nota' after filling grade: {grade}, percentage: {percentage} into the last available row.")
210179
time.sleep(0.5) # Brief pause for UI to update, e.g., adding a new empty row
211180

212-
def _get_current_weighted_average(self):
213-
raw_text = ""
214-
try:
215-
average_element = self.wait_long.until(
216-
EC.visibility_of_element_located((By.CSS_SELECTOR, self.CURRENT_AVERAGE_DISPLAY_SELECTOR))
217-
)
218-
time.sleep(0.2)
219-
220-
raw_text = average_element.text.strip()
221-
attempts = 0
222-
while raw_text == "" and attempts < 5:
223-
logger.info(f"Average text is empty, attempt {attempts+1}/5. Waiting and retrying...")
224-
time.sleep(0.3)
225-
raw_text = average_element.text.strip()
226-
attempts += 1
227-
228-
logger.info(f"Raw current weighted average text from result page: '{raw_text}'")
229-
if not raw_text:
230-
logger.warning("Current weighted average text is empty after retries on result page.")
231-
self._take_screenshot("empty_current_average_result_page")
232-
return "Error: Empty Value"
233-
234-
# Regex to find a number (integer or float) after "promedio de "
235-
match = re.search(r"Actualmente tienes un promedio de (\d+\.?\d*|\.\d+) en el", raw_text)
236-
if match:
237-
grade_str = match.group(1)
238-
logger.info(f"Extracted grade string: '{grade_str}'")
239-
return float(grade_str)
240-
else:
241-
logger.error(f"Could not parse final grade from text: '{raw_text}'")
242-
self._take_screenshot("current_average_parse_error_result")
243-
return "Error: Parse"
244-
except TimeoutException:
245-
logger.error(f"Timeout waiting for result page elements or current weighted average display: {self.CURRENT_AVERAGE_DISPLAY_SELECTOR}")
246-
logger.info(f"Current URL: {self.driver.current_url}")
247-
# logger.info(f"Page source at timeout:\\n{self.driver.page_source[:2000]}") # Potentially too verbose
248-
self._take_screenshot("current_average_timeout_result_page")
249-
return "Error: Timeout"
250-
except ValueError:
251-
logger.error(f"Could not convert extracted grade string to float from '{raw_text}'.")
252-
self._take_screenshot("current_average_value_error_result")
253-
return "Error: Conversion"
254-
except Exception as e:
255-
logger.error(f"Error getting current weighted average from result page: {e}", exc_info=True)
256-
self._take_screenshot("get_current_average_error_result")
257-
return "Error: General"
258-
259181
def test_us04_verify_calculation_of_current_weighted_average(self):
260182
test_name = self._testMethodName
261183
logger.info(f"Running test: {test_name}")
@@ -271,7 +193,19 @@ def test_us04_verify_calculation_of_current_weighted_average(self):
271193

272194
if on_result_page_initial:
273195
logger.info("Initial state is result page, navigating back to home.")
274-
self.driver.find_element(By.XPATH, self.NAV_BACK_BUTTON_XPATH).click()
196+
try:
197+
nav_back_button_initial = self.wait_short.until(
198+
EC.element_to_be_clickable((By.CSS_SELECTOR, self.NAV_BACK_BUTTON_SELECTOR))
199+
)
200+
logger.info("Found initial back button using CSS selector.")
201+
except TimeoutException:
202+
logger.info("CSS selector failed for initial back button, trying XPath...")
203+
nav_back_button_initial = self.wait_long.until(
204+
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
205+
)
206+
logger.info("Found initial back button using XPath selector.")
207+
208+
nav_back_button_initial.click()
275209
self.wait_long.until(EC.presence_of_element_located((By.CSS_SELECTOR, self.HOME_CONTAINER_SELECTOR)))
276210
else:
277211
try:
@@ -302,10 +236,43 @@ def test_us04_verify_calculation_of_current_weighted_average(self):
302236

303237
# --- Navigate back for Test Step 2 ---
304238
logger.info("Navigating back to home page for 2nd grade.")
305-
nav_back_button_step1 = self.wait_long.until(
306-
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
307-
)
239+
# Try both selectors with a more extended wait time
240+
try:
241+
logger.info("Attempting to find back button with CSS selector...")
242+
self._take_screenshot("before_finding_back_button_step1")
243+
nav_back_button_step1 = self.wait_long.until(
244+
EC.element_to_be_clickable((By.CSS_SELECTOR, self.NAV_BACK_BUTTON_SELECTOR))
245+
)
246+
logger.info("Found back button using CSS selector for step 1.")
247+
except TimeoutException:
248+
logger.warning("CSS selector failed for back button in step 1, trying XPath with more wait time...")
249+
# Take debug screenshot
250+
self._take_screenshot("css_selector_failed_step1")
251+
# Try a more verbose approach to locate the button
252+
try:
253+
# First, check if there's a nav bar
254+
nav_bar = self.wait_long.until(
255+
EC.presence_of_element_located((By.CSS_SELECTOR, "nav.nav-bar"))
256+
)
257+
logger.info("Nav bar found, looking for the first button inside it...")
258+
nav_buttons = nav_bar.find_elements(By.TAG_NAME, "button")
259+
if nav_buttons:
260+
nav_back_button_step1 = nav_buttons[0] # First button in the nav bar
261+
logger.info("Using first button in nav bar")
262+
else:
263+
logger.error("No buttons found in nav bar")
264+
self._take_screenshot("no_buttons_in_nav_bar")
265+
self.fail("No buttons found in nav bar")
266+
except Exception as e:
267+
logger.error(f"Error finding nav bar or buttons: {e}")
268+
self._take_screenshot("error_finding_nav_elements")
269+
self.fail(f"Error finding nav bar or buttons: {e}")
270+
271+
# Click the back button once found
308272
nav_back_button_step1.click()
273+
logger.info("Clicked on back button for step 1")
274+
self._take_screenshot("after_back_button_click_step1")
275+
309276
self.wait_long.until(EC.presence_of_element_located((By.CSS_SELECTOR, self.HOME_CONTAINER_SELECTOR)))
310277
logger.info(f"Navigated back to home page for 2nd grade.")
311278

@@ -328,10 +295,41 @@ def test_us04_verify_calculation_of_current_weighted_average(self):
328295

329296
# --- Navigate back for Test Step 3 ---
330297
logger.info("Navigating back to home page for 3rd grade.")
331-
nav_back_button_step2 = self.wait_long.until(
332-
EC.element_to_be_clickable((By.XPATH, self.NAV_BACK_BUTTON_XPATH))
333-
)
298+
# Try both selectors with a more extended wait time
299+
try:
300+
logger.info("Attempting to find back button with CSS selector for step 2...")
301+
self._take_screenshot("before_finding_back_button_step2")
302+
nav_back_button_step2 = self.wait_long.until(
303+
EC.element_to_be_clickable((By.CSS_SELECTOR, self.NAV_BACK_BUTTON_SELECTOR))
304+
)
305+
logger.info("Found back button using CSS selector for step 2.")
306+
except TimeoutException:
307+
logger.warning("CSS selector failed for back button in step 2, trying alternative approaches...")
308+
self._take_screenshot("css_selector_failed_step2")
309+
try:
310+
# First, check if there's a nav bar
311+
nav_bar = self.wait_long.until(
312+
EC.presence_of_element_located((By.CSS_SELECTOR, "nav.nav-bar"))
313+
)
314+
logger.info("Nav bar found, looking for the first button inside it...")
315+
nav_buttons = nav_bar.find_elements(By.TAG_NAME, "button")
316+
if nav_buttons:
317+
nav_back_button_step2 = nav_buttons[0] # First button in the nav bar
318+
logger.info("Using first button in nav bar")
319+
else:
320+
logger.error("No buttons found in nav bar")
321+
self._take_screenshot("no_buttons_in_nav_bar_step2")
322+
self.fail("No buttons found in nav bar for step 2")
323+
except Exception as e:
324+
logger.error(f"Error finding nav bar or buttons for step 2: {e}")
325+
self._take_screenshot("error_finding_nav_elements_step2")
326+
self.fail(f"Error finding nav bar or buttons for step 2: {e}")
327+
328+
# Click the back button once found
334329
nav_back_button_step2.click()
330+
logger.info("Clicked on back button for step 2")
331+
self._take_screenshot("after_back_button_click_step2")
332+
335333
self.wait_long.until(EC.presence_of_element_located((By.CSS_SELECTOR, self.HOME_CONTAINER_SELECTOR)))
336334
logger.info(f"Navigated back to home page for 3rd grade.")
337335

@@ -362,6 +360,3 @@ def test_us04_verify_calculation_of_current_weighted_average(self):
362360
self.fail(f"Exception in {test_name}: {e}")
363361

364362
logger.info(f"Test {test_name} completed successfully.")
365-
366-
if __name__ == '__main__':
367-
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)