|
4 | 4 | from selenium.webdriver.common.by import By |
5 | 5 | from selenium.webdriver.support.ui import WebDriverWait |
6 | 6 | from selenium.webdriver.support import expected_conditions as EC |
| 7 | +from selenium.common.exceptions import TimeoutException |
7 | 8 |
|
8 | 9 | class TestHomePage: |
| 10 | + def _initial_setup(self, driver): |
| 11 | + base_url = os.environ.get('APP_URL', 'http://localhost:3000') |
| 12 | + driver.get(base_url) |
| 13 | + try: |
| 14 | + # Wait for and click the initial alert button if present |
| 15 | + alert_button = WebDriverWait(driver, 10).until( |
| 16 | + EC.element_to_be_clickable((By.CSS_SELECTOR, ".alert__button.alert__button--single")) |
| 17 | + ) |
| 18 | + alert_button.click() |
| 19 | + except TimeoutException: |
| 20 | + print("Initial alert not found or not clickable within 10s, proceeding with test.") |
| 21 | + except Exception as e: |
| 22 | + print(f"An unexpected error occurred during initial alert handling: {e}, proceeding with test.") |
| 23 | + |
| 24 | + def _add_grade_and_percentage(self, driver, grade, percentage): |
| 25 | + grade_input = WebDriverWait(driver, 10).until( |
| 26 | + EC.presence_of_element_located((By.ID, "grade-input")) |
| 27 | + ) |
| 28 | + grade_input.clear() |
| 29 | + grade_input.send_keys(str(grade)) |
| 30 | + |
| 31 | + percentage_input = WebDriverWait(driver, 10).until( |
| 32 | + EC.presence_of_element_located((By.ID, "percentage-input")) |
| 33 | + ) |
| 34 | + percentage_input.clear() |
| 35 | + percentage_input.send_keys(str(percentage)) |
| 36 | + |
| 37 | + add_button = WebDriverWait(driver, 10).until( |
| 38 | + EC.element_to_be_clickable((By.ID, "add-grade-btn")) |
| 39 | + ) |
| 40 | + add_button.click() |
| 41 | + |
| 42 | + def _get_grades_list_item_count(self, driver): |
| 43 | + try: |
| 44 | + grades_list_container = driver.find_element(By.ID, "grades-list") |
| 45 | + # Assuming direct children are the items; adjust selector if structure is different |
| 46 | + return len(grades_list_container.find_elements(By.XPATH, "./*")) |
| 47 | + except Exception: |
| 48 | + return 0 # If list not found or empty |
| 49 | + |
| 50 | + def test_us01_add_single_valid_grade(self, driver, request): # Added request fixture |
| 51 | + test_name = request.node.name # Use request fixture to get test name |
| 52 | + try: |
| 53 | + self._initial_setup(driver) |
| 54 | + |
| 55 | + grade_to_add = "4.0" |
| 56 | + percentage_to_add = "20" |
| 57 | + |
| 58 | + initial_item_count = self._get_grades_list_item_count(driver) |
| 59 | + self._add_grade_and_percentage(driver, grade_to_add, percentage_to_add) |
| 60 | + |
| 61 | + # Wait for list to update |
| 62 | + WebDriverWait(driver, 10).until( |
| 63 | + lambda d: self._get_grades_list_item_count(d) > initial_item_count |
| 64 | + ) |
| 65 | + |
| 66 | + grades_list_container = WebDriverWait(driver, 10).until( |
| 67 | + EC.presence_of_element_located((By.ID, "grades-list")) |
| 68 | + ) |
| 69 | + # Verify the added grade and percentage are present in the list |
| 70 | + # This assumes a simple text representation; more specific selectors for items are better |
| 71 | + assert grade_to_add in grades_list_container.text |
| 72 | + assert percentage_to_add + "%" in grades_list_container.text # Assuming '%' is displayed |
| 73 | + |
| 74 | + except Exception as e: |
| 75 | + os.makedirs("screenshots", exist_ok=True) |
| 76 | + driver.save_screenshot(f"screenshots/error_{test_name}_{int(time.time())}.png") |
| 77 | + print(f"Current URL on error in {test_name}: {driver.current_url}") |
| 78 | + print(f"Page source excerpt on error in {test_name}: {driver.page_source[:500]}...") |
| 79 | + raise e |
| 80 | + |
| 81 | + def test_us01_add_multiple_valid_grades(self, driver, request): # Added request fixture |
| 82 | + test_name = request.node.name # Use request fixture to get test name |
| 83 | + try: |
| 84 | + self._initial_setup(driver) |
| 85 | + |
| 86 | + grades_data = [ |
| 87 | + {"grade": "4.5", "percentage": "25"}, |
| 88 | + {"grade": "3.0", "percentage": "30"}, |
| 89 | + {"grade": "5.0", "percentage": "15"}, |
| 90 | + ] |
| 91 | + |
| 92 | + initial_item_count = self._get_grades_list_item_count(driver) |
| 93 | + |
| 94 | + for i, item in enumerate(grades_data): |
| 95 | + self._add_grade_and_percentage(driver, item["grade"], item["percentage"]) |
| 96 | + # Wait for the list to update after each addition |
| 97 | + WebDriverWait(driver, 10).until( |
| 98 | + lambda d: self._get_grades_list_item_count(d) == initial_item_count + i + 1 |
| 99 | + ) |
| 100 | + |
| 101 | + grades_list_container = WebDriverWait(driver, 10).until( |
| 102 | + EC.presence_of_element_located((By.ID, "grades-list")) |
| 103 | + ) |
| 104 | + for item in grades_data: |
| 105 | + assert item["grade"] in grades_list_container.text |
| 106 | + assert item["percentage"] + "%" in grades_list_container.text |
| 107 | + |
| 108 | + assert self._get_grades_list_item_count(driver) == initial_item_count + len(grades_data) |
| 109 | + |
| 110 | + except Exception as e: |
| 111 | + os.makedirs("screenshots", exist_ok=True) |
| 112 | + driver.save_screenshot(f"screenshots/error_{test_name}_{int(time.time())}.png") |
| 113 | + print(f"Current URL on error in {test_name}: {driver.current_url}") |
| 114 | + print(f"Page source excerpt on error in {test_name}: {driver.page_source[:500]}...") |
| 115 | + raise e |
| 116 | + |
| 117 | + def test_us01_validate_grade_input_below_range(self, driver, request): # Added request fixture |
| 118 | + test_name = request.node.name # Use request fixture to get test name |
| 119 | + try: |
| 120 | + self._initial_setup(driver) |
| 121 | + initial_item_count = self._get_grades_list_item_count(driver) |
| 122 | + |
| 123 | + self._add_grade_and_percentage(driver, "-1.0", "20") # Invalid grade |
| 124 | + |
| 125 | + error_message_element = WebDriverWait(driver, 10).until( |
| 126 | + EC.visibility_of_element_located((By.ID, "error-message-grade")) # Hypothetical ID |
| 127 | + ) |
| 128 | + assert "válido" in error_message_element.text.lower() or "rango" in error_message_element.text.lower() |
| 129 | + |
| 130 | + # Verify grade was not added |
| 131 | + assert self._get_grades_list_item_count(driver) == initial_item_count |
| 132 | + |
| 133 | + except Exception as e: |
| 134 | + os.makedirs("screenshots", exist_ok=True) |
| 135 | + driver.save_screenshot(f"screenshots/error_{test_name}_{int(time.time())}.png") |
| 136 | + print(f"Current URL on error in {test_name}: {driver.current_url}") |
| 137 | + print(f"Page source excerpt on error in {test_name}: {driver.page_source[:500]}...") |
| 138 | + raise e |
| 139 | + |
| 140 | + def test_us01_validate_grade_input_above_range(self, driver, request): # Added request fixture |
| 141 | + test_name = request.node.name # Use request fixture to get test name |
| 142 | + try: |
| 143 | + self._initial_setup(driver) |
| 144 | + initial_item_count = self._get_grades_list_item_count(driver) |
| 145 | + |
| 146 | + self._add_grade_and_percentage(driver, "6.0", "20") # Invalid grade (assuming max 5.0) |
| 147 | + |
| 148 | + error_message_element = WebDriverWait(driver, 10).until( |
| 149 | + EC.visibility_of_element_located((By.ID, "error-message-grade")) |
| 150 | + ) |
| 151 | + assert "válido" in error_message_element.text.lower() or "rango" in error_message_element.text.lower() |
| 152 | + |
| 153 | + assert self._get_grades_list_item_count(driver) == initial_item_count |
| 154 | + |
| 155 | + except Exception as e: |
| 156 | + os.makedirs("screenshots", exist_ok=True) |
| 157 | + driver.save_screenshot(f"screenshots/error_{test_name}_{int(time.time())}.png") |
| 158 | + print(f"Current URL on error in {test_name}: {driver.current_url}") |
| 159 | + print(f"Page source excerpt on error in {test_name}: {driver.page_source[:500]}...") |
| 160 | + raise e |
| 161 | + |
| 162 | + def test_us01_validate_percentage_input_negative(self, driver, request): # Added request fixture |
| 163 | + test_name = request.node.name # Use request fixture to get test name |
| 164 | + try: |
| 165 | + self._initial_setup(driver) |
| 166 | + initial_item_count = self._get_grades_list_item_count(driver) |
| 167 | + |
| 168 | + self._add_grade_and_percentage(driver, "4.0", "-10") # Invalid percentage |
| 169 | + |
| 170 | + error_message_element = WebDriverWait(driver, 10).until( |
| 171 | + EC.visibility_of_element_located((By.ID, "error-message-percentage")) # Hypothetical ID |
| 172 | + ) |
| 173 | + assert "positivo" in error_message_element.text.lower() or "válido" in error_message_element.text.lower() |
| 174 | + |
| 175 | + assert self._get_grades_list_item_count(driver) == initial_item_count |
| 176 | + |
| 177 | + except Exception as e: |
| 178 | + os.makedirs("screenshots", exist_ok=True) |
| 179 | + driver.save_screenshot(f"screenshots/error_{test_name}_{int(time.time())}.png") |
| 180 | + print(f"Current URL on error in {test_name}: {driver.current_url}") |
| 181 | + print(f"Page source excerpt on error in {test_name}: {driver.page_source[:500]}...") |
| 182 | + raise e |
| 183 | + |
| 184 | + def test_us01_validate_percentage_input_non_numeric(self, driver, request): # Added request fixture |
| 185 | + test_name = request.node.name # Use request fixture to get test name |
| 186 | + try: |
| 187 | + self._initial_setup(driver) |
| 188 | + initial_item_count = self._get_grades_list_item_count(driver) |
| 189 | + |
| 190 | + # Manually interact for this specific case to send "abc" |
| 191 | + grade_input = WebDriverWait(driver, 10).until( |
| 192 | + EC.presence_of_element_located((By.ID, "grade-input")) |
| 193 | + ) |
| 194 | + grade_input.clear() |
| 195 | + grade_input.send_keys("3.0") |
| 196 | + |
| 197 | + percentage_input_loc = (By.ID, "percentage-input") |
| 198 | + percentage_input = WebDriverWait(driver, 10).until( |
| 199 | + EC.presence_of_element_located(percentage_input_loc) |
| 200 | + ) |
| 201 | + percentage_input.clear() |
| 202 | + percentage_input.send_keys("abc") # Non-numeric |
| 203 | + |
| 204 | + add_button = WebDriverWait(driver, 10).until( |
| 205 | + EC.element_to_be_clickable((By.ID, "add-grade-btn")) |
| 206 | + ) |
| 207 | + add_button.click() |
| 208 | + |
| 209 | + # Verification depends on behavior: error message or input rejection |
| 210 | + try: |
| 211 | + error_message_element = WebDriverWait(driver, 5).until( |
| 212 | + EC.visibility_of_element_located((By.ID, "error-message-percentage")) |
| 213 | + ) |
| 214 | + assert "número" in error_message_element.text.lower() or "válido" in error_message_element.text.lower() |
| 215 | + except TimeoutException: |
| 216 | + # If no error message, check if the input was rejected or field is empty/still "abc" |
| 217 | + current_percentage_value = driver.find_element(*percentage_input_loc).get_attribute("value") |
| 218 | + # If type="number", browser might prevent "abc" or convert to empty. |
| 219 | + # If type="text", "abc" might remain. |
| 220 | + assert current_percentage_value == "" or current_percentage_value == "abc", \ |
| 221 | + "Percentage input did not show error for non-numeric and value is not as expected." |
| 222 | + |
| 223 | + assert self._get_grades_list_item_count(driver) == initial_item_count |
| 224 | + |
| 225 | + except Exception as e: |
| 226 | + os.makedirs("screenshots", exist_ok=True) |
| 227 | + driver.save_screenshot(f"screenshots/error_{test_name}_{int(time.time())}.png") |
| 228 | + print(f"Current URL on error in {test_name}: {driver.current_url}") |
| 229 | + print(f"Page source excerpt on error in {test_name}: {driver.page_source[:500]}...") |
| 230 | + raise e |
| 231 | + |
9 | 232 | def test_home_page_functional_flow(self, driver): |
10 | 233 | # Navigate to application using environment variable |
11 | 234 | base_url = os.environ.get('APP_URL', 'http://localhost:3000') |
|
0 commit comments