@@ -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