33import time
44import os
55import logging
6+ import re # Added for parsing
67from selenium import webdriver
78from selenium .webdriver .common .by import By
89from selenium .webdriver .support .ui import WebDriverWait
@@ -19,8 +20,9 @@ class US04Tests(unittest.TestCase):
1920 ADD_GRADE_BUTTON_SELECTOR = "button.home__add-button"
2021 GRADES_LIST_ITEM_SELECTOR = "div.home__grades-container > div.home__grade-row"
2122 CALCULATE_BUTTON_SELECTOR = "button.home__calculate-button"
22- # Hypothetical selector based on selenium-test-dev.md. May need verification.
23- CURRENT_AVERAGE_DISPLAY_SELECTOR = "#current-average-display"
23+ # Updated selector for the result page based on result.jsx
24+ CURRENT_AVERAGE_DISPLAY_SELECTOR = "p.result__card-current"
25+ RESULT_PAGE_CONTAINER_SELECTOR = "div.result" # A general selector for the result page
2426
2527 FIRST_TIME_ALERT_BUTTON_SELECTOR = ".alert__button.alert__button--single"
2628 ALERT_OVERLAY_SELECTOR = "div.alert__overlay"
@@ -123,6 +125,16 @@ def _add_grade_and_percentage(self, grade, percentage):
123125 self .fail ("Driver not available." )
124126 return
125127
128+ # Ensure we are on the home page before adding grades
129+ if "/result" in self .driver .current_url :
130+ logger .info ("Currently on result page, navigating back to home to add grades." )
131+ nav_back_button = self .wait_long .until (
132+ EC .element_to_be_clickable ((By .XPATH , self .NAV_BACK_BUTTON_XPATH ))
133+ )
134+ nav_back_button .click ()
135+ self .wait_long .until (EC .presence_of_element_located ((By .CSS_SELECTOR , self .HOME_CONTAINER_SELECTOR )))
136+ logger .info ("Navigated back to home page." )
137+
126138 grade_rows = self .driver .find_elements (By .CSS_SELECTOR , self .GRADES_LIST_ITEM_SELECTOR )
127139 if not grade_rows : # Should not happen if app starts with one row
128140 logger .error ("No grade rows found to add grade and percentage." )
@@ -169,10 +181,13 @@ def _add_grade_and_percentage(self, grade, percentage):
169181 def _get_current_weighted_average (self ):
170182 raw_text = ""
171183 try :
184+ # Ensure we are on the result page
185+ self .wait_long .until (EC .url_contains ("/result" ))
186+ self .wait_long .until (EC .presence_of_element_located ((By .CSS_SELECTOR , self .RESULT_PAGE_CONTAINER_SELECTOR )))
187+
172188 average_element = self .wait_long .until (
173189 EC .visibility_of_element_located ((By .CSS_SELECTOR , self .CURRENT_AVERAGE_DISPLAY_SELECTOR ))
174190 )
175- # Add a small delay or check for text to be non-empty if necessary
176191 time .sleep (0.2 ) # give a brief moment for text to update
177192
178193 raw_text = average_element .text .strip ()
@@ -182,35 +197,36 @@ def _get_current_weighted_average(self):
182197 raw_text = average_element .text .strip ()
183198 attempts += 1
184199
185- logger .info (f"Raw current weighted average text: '{ raw_text } '" )
200+ logger .info (f"Raw current weighted average text from result page : '{ raw_text } '" )
186201 if not raw_text :
187- logger .warning ("Current weighted average text is empty after retries." )
188- self ._take_screenshot ("empty_current_average " )
202+ logger .warning ("Current weighted average text is empty after retries on result page ." )
203+ self ._take_screenshot ("empty_current_average_result_page " )
189204 return "Error: Empty Value"
190205
191- # Assuming the text is just a number, possibly with a suffix like "/ 5.0" or similar.
192- # For now, let's assume it's a direct float value.
193- # If it has " / X.X", we might need to parse it.
194- # Example: "3.4 / 5.0" -> we need 3.4
195- # For now, try direct conversion. If it fails, the app might display it differently.
196- # The Subject.ts finalGrade is Number((weightedSum / 100).toFixed(1))
197- # So it should be a direct number like "1.7".
198-
199- # If the text might contain other characters like "Promedio: 1.7", parse accordingly.
200- # For now, assuming it's just the number.
201- return float (raw_text )
206+ # Parse the text: "Actualmente tienes un promedio de {finalGrade} en el {totalPercentage}% de la materia."
207+ match = re .search (r"Actualmente tienes un promedio de (\\d+\\.\\d+|\\d+) en el" , raw_text )
208+ if match :
209+ grade_str = match .group (1 )
210+ logger .info (f"Extracted grade string: '{ grade_str } '" )
211+ return float (grade_str )
212+ else :
213+ logger .error (f"Could not parse final grade from text: '{ raw_text } '" )
214+ self ._take_screenshot ("current_average_parse_error_result" )
215+ return "Error: Parse"
202216 except TimeoutException :
203- logger .error (f"Timeout waiting for current weighted average display element: { self .CURRENT_AVERAGE_DISPLAY_SELECTOR } " )
204- logger .info (f"Page source at timeout:\\ n{ self .driver .page_source [:2000 ]} " ) # Log part of page source
205- self ._take_screenshot ("current_average_timeout" )
217+ logger .error (f"Timeout waiting for result page elements or current weighted average display: { self .CURRENT_AVERAGE_DISPLAY_SELECTOR } " )
218+ logger .info (f"Current URL: { self .driver .current_url } " )
219+ logger .info (f"Page source at timeout:\\ n{ self .driver .page_source [:2000 ]} " )
220+ self ._take_screenshot ("current_average_timeout_result_page" )
206221 return "Error: Timeout"
207222 except ValueError :
208- logger .error (f"Could not convert current weighted average text '{ raw_text } ' to float." )
209- self ._take_screenshot ("current_average_value_error" )
223+ # This might happen if grade_str is not a valid float, though regex should prevent it.
224+ logger .error (f"Could not convert extracted grade string to float from '{ raw_text } '." )
225+ self ._take_screenshot ("current_average_value_error_result" )
210226 return "Error: Conversion"
211227 except Exception as e :
212- logger .error (f"Error getting current weighted average: { e } " )
213- self ._take_screenshot ("get_current_average_error " )
228+ logger .error (f"Error getting current weighted average from result page : { e } " )
229+ self ._take_screenshot ("get_current_average_error_result " )
214230 return "Error: General"
215231
216232 # US04: Cálculo del Promedio Ponderado Actual
@@ -219,53 +235,74 @@ def test_us04_verify_calculation_of_current_weighted_average(self):
219235 logger .info (f"Running test: { test_name } " )
220236
221237 try :
222- # Click "Calcular" to see initial state if any (likely 0 or not shown)
223- # For this test, we add grades first, then calculate and check.
238+ # Ensure we start on the home page for adding grades
239+ if "/result" in self .driver .current_url :
240+ self .driver .find_element (By .XPATH , self .NAV_BACK_BUTTON_XPATH ).click ()
241+ self .wait_long .until (EC .presence_of_element_located ((By .CSS_SELECTOR , self .HOME_CONTAINER_SELECTOR )))
242+ elif self .HOME_CONTAINER_SELECTOR not in self .driver .page_source :
243+ self .driver .get (self .BASE_URL )
244+ self ._initial_setup () # Re-run setup if not on home page and not on result page
224245
225246 # 1. Add first grade and verify average
226247 logger .info ("Adding first grade (4.5, 20%)." )
227248 self ._add_grade_and_percentage ("4.5" , "20" ) # Adds and clicks "Agregar nota"
228249
229- # Click "Calcular"
230250 calculate_button = self .wait_long .until (EC .element_to_be_clickable ((By .CSS_SELECTOR , self .CALCULATE_BUTTON_SELECTOR )))
231251 calculate_button .click ()
232- logger .info ("Clicked 'Calcular' button." )
233- time .sleep (0.5 ) # Wait for calculation and display update
252+ logger .info ("Clicked 'Calcular' button. Expecting navigation to /result." )
253+
254+ # Wait for navigation to result page and for the average display to be ready
255+ self .wait_long .until (EC .url_contains ("/result" ))
256+ logger .info (f"Navigated to { self .driver .current_url } " )
234257
235258 current_avg_1 = self ._get_current_weighted_average ()
236- expected_avg_1 = round (( 4.5 * 20 ) / 100 , 1 ) # 0.9
259+ expected_avg_1 = 0.9 # ( 4.5 * 20) / 100 = 90 / 100 = 0.9
237260 self .assertEqual (current_avg_1 , expected_avg_1 ,
238261 f"Average after 1st grade expected { expected_avg_1 } , but got { current_avg_1 } " )
239- logger .info (f"Average after 1st grade is correct: { current_avg_1 } " )
262+ logger .info (f"Average after 1st grade on result page is correct: { current_avg_1 } " )
263+
264+ # Navigate back to home to add more grades
265+ self .driver .find_element (By .XPATH , self .NAV_BACK_BUTTON_XPATH ).click ()
266+ self .wait_long .until (EC .presence_of_element_located ((By .CSS_SELECTOR , self .HOME_CONTAINER_SELECTOR )))
267+ logger .info ("Navigated back to home page to add second grade." )
240268
241269 # 2. Add second grade and verify average
242- # _add_grade_and_percentage already clicked "Agregar nota", so a new row should be ready.
243270 logger .info ("Adding second grade (3.0, 30%)." )
244271 self ._add_grade_and_percentage ("3.0" , "30" )
245272
246- calculate_button .click () # Re-click calculate
273+ calculate_button = self .wait_long .until (EC .element_to_be_clickable ((By .CSS_SELECTOR , self .CALCULATE_BUTTON_SELECTOR ))) # Re-locate button
274+ calculate_button .click ()
247275 logger .info ("Clicked 'Calcular' button again." )
248- time .sleep (0.5 )
276+ self .wait_long .until (EC .url_contains ("/result" ))
277+ logger .info (f"Navigated to { self .driver .current_url } " )
249278
250279 current_avg_2 = self ._get_current_weighted_average ()
251- expected_avg_2 = round (( 4.5 * 20 + 3.0 * 30 ) / 100 , 1 ) # (90 + 90)/100 = 1.8
280+ expected_avg_2 = 1.8 # ( 4.5 * 20 + 3.0 * 30) / 100 = (90 + 90)/100 = 1.8
252281 self .assertEqual (current_avg_2 , expected_avg_2 ,
253282 f"Average after 2nd grade expected { expected_avg_2 } , but got { current_avg_2 } " )
254- logger .info (f"Average after 2nd grade is correct: { current_avg_2 } " )
283+ logger .info (f"Average after 2nd grade on result page is correct: { current_avg_2 } " )
284+
285+ # Navigate back to home to add more grades
286+ self .driver .find_element (By .XPATH , self .NAV_BACK_BUTTON_XPATH ).click ()
287+ self .wait_long .until (EC .presence_of_element_located ((By .CSS_SELECTOR , self .HOME_CONTAINER_SELECTOR )))
288+ logger .info ("Navigated back to home page to add third grade." )
255289
256290 # 3. Add third grade and verify average
257291 logger .info ("Adding third grade (5.0, 50%)." )
258292 self ._add_grade_and_percentage ("5.0" , "50" )
259293
260- calculate_button .click () # Re-click calculate
294+ calculate_button = self .wait_long .until (EC .element_to_be_clickable ((By .CSS_SELECTOR , self .CALCULATE_BUTTON_SELECTOR ))) # Re-locate button
295+ calculate_button .click ()
261296 logger .info ("Clicked 'Calcular' button again." )
262- time .sleep (0.5 )
297+ self .wait_long .until (EC .url_contains ("/result" ))
298+ logger .info (f"Navigated to { self .driver .current_url } " )
263299
264300 current_avg_3 = self ._get_current_weighted_average ()
265- expected_avg_3 = round ((4.5 * 20 + 3.0 * 30 + 5.0 * 50 ) / 100 , 1 ) # (90 + 90 + 250)/100 = 430/100 = 4.3
301+ # (4.5*20 + 3.0*30 + 5.0*50)/100 = (90 + 90 + 250)/100 = 430/100 = 4.3
302+ expected_avg_3 = 4.3
266303 self .assertEqual (current_avg_3 , expected_avg_3 ,
267304 f"Average after 3rd grade expected { expected_avg_3 } , but got { current_avg_3 } " )
268- logger .info (f"Average after 3rd grade is correct: { current_avg_3 } " )
305+ logger .info (f"Average after 3rd grade on result page is correct: { current_avg_3 } " )
269306
270307 except AssertionError as e :
271308 logger .error (f"AssertionError in { test_name } : { e } " )
0 commit comments