fix and add som usecases

This commit is contained in:
2025-09-15 17:41:07 +08:00
parent 838806b9e3
commit 414737fd48
37 changed files with 1133 additions and 51 deletions

View File

@@ -11,24 +11,23 @@ class BasePage:
improve test maintenance.
"""
def __init__(self, driver: WebDriver, base_url: str = "http://120.53.89.168:90"):
def __init__(self, driver: WebDriver):
"""
Initializes the BasePage with a WebDriver instance and a base URL.
Initializes the BasePage with a WebDriver instance.
:param driver: The WebDriver instance to interact with the browser.
:param base_url: The base URL of the web application under test.
"""
self.driver = driver
self.base_url = base_url
self.wait = WebDriverWait(driver, 10) # Default explicit wait of 10 seconds
def open_url(self, path: str):
def open(self, base_url: str, path: str):
"""
Navigates to a specific path relative to the base URL.
:param base_url: The base URL of the web application.
:param path: The relative path to open (e.g., "/form-elements").
"""
url = self.base_url + path
url = base_url.rstrip('/') + path
self.driver.get(url)
def find_element(self, locator: tuple) -> WebElement:
@@ -177,3 +176,12 @@ class BasePage:
:return: True if the text is present, False otherwise.
"""
return self.wait.until(EC.text_to_be_present_in_element(locator, text))
def wait_for_url_contains(self, url_substring: str):
"""
Waits until the current URL contains the given substring.
:param url_substring: The substring to look for in the URL.
:return: True if the URL contains the substring, False otherwise.
"""
return self.wait.until(EC.url_contains(url_substring))

View File

@@ -0,0 +1,56 @@
from typing import Self
from selenium.webdriver.common import by
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from page_objects.base_page import BasePage
class DangerZonePage(BasePage):
"""
Page object for the Danger Zone page.
"""
# Locators
DELETE_ACCOUNT_BUTTON = (By.XPATH, '/html/body/div/div/main/div/div[3]/div/div[2]/button')
CONFIRM_DELETE_BUTTON = (By.XPATH, '/html/body/div[3]/div[3]/button')
CANCEL_DELETE_BUTTON = (By.XPATH, '/html/body/div[3]/button')
DIALOG_TITLE = (By.XPATH, '/html/body/div[3]/div[1]/h2') # Assuming dialog title
DIALOG_INPUT = (By.XPATH,'/html/body/div[3]/div[2]/input')
_DANGER_ZONE_TITLE = (By.XPATH,'//*[@id="root"]/div/main/div/div[3]/div/div[1]/h3')
def get_page_header(self):
"""
Gets the header text of the page.
Assumes the header is an h1 element.
"""
return self.get_text((By.TAG_NAME, "h1"))
def click_delete_account(self):
"""
Clicks the 'Delete Account' button to open the confirmation dialog.
"""
self.click(self.DELETE_ACCOUNT_BUTTON)
def verify_confirmation_dialog_exist(self):
return self.get_text(self.DIALOG_TITLE)
def set_dialog_input(self):
self.send_keys(self.DIALOG_INPUT,'delete my account')
return ''
def click_cancel_in_dialog(self, timeout=5):
"""
Safely clicks the cancel button in the confirmation dialog.
"""
self.click(self.CANCEL_DELETE_BUTTON)
def click_confirm_in_dialog(self):
"""
Clicks the 'Confirm' button within the confirmation dialog.
"""
self.click(self.CONFIRM_DELETE_BUTTON)
def verify_danger_zone_exist(self):
return self.get_text(self._DANGER_ZONE_TITLE)

View File

@@ -29,9 +29,9 @@ class DynamicContentPage(BasePage):
# --- Page Actions ---
def open(self):
def open(self, base_url: str):
"""Navigates to the dynamic content page."""
self.open_url(self.page_path)
super().open(base_url, self.page_path)
def get_delayed_text(self) -> str:
"""

View File

@@ -28,9 +28,9 @@ class FormElementsPage(BasePage):
# --- Page Actions ---
def open(self):
def open(self, base_url: str):
"""Navigates to the form elements page."""
self.open_url(self.page_path)
super().open(base_url, self.page_path)
def enter_text_in_input(self, text: str):
"""Enters text into the main text input field."""

View File

@@ -0,0 +1,34 @@
from selenium.webdriver.common.by import By
from page_objects.base_page import BasePage
class HomeDashboardPage(BasePage):
"""
Page object for the main Home/Dashboard page, specifically handling the top navigation.
"""
# Locators
_PROFILE_TAB = (By.XPATH, "//button[@role='tab' and contains(@id,'trigger-profile')]")
_SETTINGS_TAB = (By.XPATH, "//button[@role='tab' and contains(@id,'trigger-settings')]")
DANGER_ZONE_LINK = (By.LINK_TEXT, "Danger Zone")
LOGOUT_BUTTON = (By.XPATH, "//button[text()='Logout']")
_DASHBORAD_TEST_CASES_TITLE = (By.XPATH,'//*[contains(@id,"content-dashboard")]/div/div[1]//h3')
def navigate_to_profile(self):
"""
Clicks the 'Profile' link to navigate to the Profile Editor page.
"""
self.click(self._PROFILE_TAB)
def navigate_to_settings(self):
"""
Clicks the 'Settings' link to navigate to the Settings Panel page.
"""
self.click(self._SETTINGS_TAB)
def verify_title_is_dashboarde(self):
return self.get_text(self._DASHBORAD_TEST_CASES_TITLE)
def logout(self):
"""
Clicks the 'Logout' button.
"""
self.click(self.LOGOUT_BUTTON)

View File

@@ -0,0 +1,49 @@
from selenium.webdriver.common.by import By
from .base_page import BasePage
class HomePage(BasePage):
"""
Page Object for the Home page (Dashboard).
"""
# --- Locators ---
_WELCOME_MESSAGE = (By.XPATH, '//*[@id="root"]/div/main/div/div[1]/h1')
_LOGOUT_BUTTON = (By.XPATH, "//button[text()='Logout']")
_PROFILE_TAB = (By.XPATH, "//button[@role='tab' and text()='Profile']")
_DASHBOARD_CONTENT = (By.XPATH, '/html/body/div/div/main/div/div[2]/div[2]/div')
_DASHBORAD_TEST_CASES_TITLE = (By.XPATH,'//*[contains(@id,"content-dashboard")]/div/div[1]//h3')
def __init__(self, driver):
"""Initializes the HomePage with the WebDriver."""
super().__init__(driver)
self.page_path = "/" # The home page is at the root path after login
# --- Page Actions ---
def open(self, base_url: str):
"""Navigates to the home page."""
super().open(base_url, self.page_path)
def get_welcome_message(self) -> str:
"""
Gets the welcome message text from the page header.
"""
try:
return self.find_visible_element(self._WELCOME_MESSAGE).text
except:
return ""
def is_dashboard_content_visible(self) -> bool:
"""
Checks if the main dashboard content area is visible.
"""
return self.get_text(self._DASHBORAD_TEST_CASES_TITLE) == 'Test Cases'
def switch_to_profile_tab(self):
"""
Clicks the 'Profile' tab to switch to the profile view.
"""
self.click(self._PROFILE_TAB)
def click_logout_button(self):
"""Clicks the logout button."""
self.click(self._LOGOUT_BUTTON)

View File

@@ -0,0 +1,61 @@
from selenium.webdriver.common.by import By
from .base_page import BasePage
class LoginPage(BasePage):
"""
Page Object for the Login page.
"""
# --- Locators ---
_EMAIL_INPUT = (By.ID, "email")
_PASSWORD_INPUT = (By.ID, "password")
_SIGN_IN_BUTTON = (By.XPATH, "//button[@type='submit']")
_ERROR_MESSAGE = (By.XPATH, "//p[contains(@class, 'text-red-500')]")
_LOGIN_FORM = (By.XPATH, "//form")
def __init__(self, driver):
"""Initializes the LoginPage with the WebDriver."""
super().__init__(driver)
self.page_path = "/login"
# --- Page Actions ---
def open(self, base_url: str):
"""Navigates to the login page."""
super().open(base_url, self.page_path)
def enter_email(self, email: str):
"""Enters the email into the email input field."""
self.send_keys(self._EMAIL_INPUT, email)
def enter_password(self, password: str):
"""Enters the password into the password input field."""
self.send_keys(self._PASSWORD_INPUT, password)
def click_sign_in(self):
"""Clicks the 'Sign in' button."""
self.click(self._SIGN_IN_BUTTON)
def login(self, email: str, password: str):
"""Performs a full login action."""
self.enter_email(email)
self.enter_password(password)
self.click_sign_in()
def get_error_message(self) -> str:
"""
Waits for the error message to be visible and returns its text.
Returns an empty string if the message is not found.
"""
try:
return self.find_visible_element(self._ERROR_MESSAGE).text
except:
return ""
def is_login_form_visible(self) -> bool:
"""Checks if the login form is visible on the page."""
try:
self.find_visible_element(self._LOGIN_FORM)
return True
except:
return False

View File

@@ -0,0 +1,53 @@
from selenium.webdriver.common import by
from selenium.webdriver.common.by import By
from page_objects.base_page import BasePage
class ProfileEditorPage(BasePage):
"""
Page object for the Profile Editor page.
"""
# Locators
USERNAME_INPUT = (By.ID, "name")
EMAIL_INPUT = (By.ID, "email")
SAVE_BUTTON = (By.XPATH, "//button[text()='Save Changes']")
SUCCESS_MESSAGE = (By.XPATH, "//*[contains(text(), 'Profile updated successfully')]") # Assuming a success message appears
_PROFILE_TITLE = (By.XPATH,'//*[contains(@id,"content-profile")]//h3')
def get_page_header(self):
"""
Gets the header text of the page.
Assumes the header is an h1 element.
"""
return self.get_text((By.TAG_NAME, "h1"))
def set_username(self, username: str):
"""
Enters the given username into the username input field.
"""
self.send_keys(self.USERNAME_INPUT, username)
def set_email(self, email: str):
"""
Enters the given email into the email input field.
"""
self.send_keys(self.EMAIL_INPUT, email)
def click_save_changes(self):
"""
Clicks the 'Save Changes' button.
"""
self.click(self.SAVE_BUTTON)
def is_success_message_displayed(self) -> bool:
"""
Checks if the success message is visible.
"""
try:
return self.find_visible_element(self.SUCCESS_MESSAGE).is_displayed()
except:
return False
def verify_title_is_profile(self):
return self.get_text(self._PROFILE_TITLE)

View File

@@ -0,0 +1,48 @@
from selenium.webdriver.common.by import By
from page_objects.base_page import BasePage
class SettingsPanelPage(BasePage):
"""
Page object for the Settings Panel page.
"""
# Locators
_SETTING_TAB_TITLE = (By.XPATH, '//*[contains(@id,"content-settings")]//h3')
NOTIFICATIONS_SWITCH = (By.ID, "notifications")
THEME_SELECTOR = (By.ID, "theme")
def get_page_header(self):
"""
Gets the header text of the page.
Assumes the header is an h1 element.
"""
return self.get_text((By.TAG_NAME, "h1"))
def verify_title_is_settings(self):
return self.get_text(self._SETTING_TAB_TITLE)
def toggle_notifications(self):
"""
Clicks the notifications switch to toggle it.
"""
self.click(self.NOTIFICATIONS_SWITCH)
def is_notifications_enabled(self) -> bool:
"""
Checks if the notifications switch is in the 'on' or 'selected' state.
Note: This might need adjustment based on the actual HTML implementation (e.g., aria-checked).
"""
return self.is_element_selected(self.NOTIFICATIONS_SWITCH)
def select_theme(self, theme_name: str):
"""
Selects a theme from the dropdown.
:param theme_name: The visible text of the theme to select (e.g., "Dark").
"""
# This is a placeholder. The actual implementation depends on the select/dropdown component.
# If it's a standard <select>, this would involve the Select class from Selenium.
# from selenium.webdriver.support.ui import Select
# select = Select(self.find_element(self.THEME_SELECTOR))
# select.select_by_visible_text(theme_name)
pass