28 / 80 · 12 Programming for QA · OOP for Testing← prev⊞ allnext →☰ Read as one page
4.2Classes for Page Objects
A class encapsulates data (locators) and behavior (actions) for a single page or component. This separation keeps test files clean and localizes changes to one place.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class LoginPage:
URL = "/login"
EMAIL = (By.CSS_SELECTOR, "input[name='email']")
PASSWORD = (By.CSS_SELECTOR, "input[name='password']")
SUBMIT = (By.CSS_SELECTOR, "button[type='submit']")
ERROR_MESSAGE = (By.CSS_SELECTOR, ".error-message")
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
def open(self):
self.driver.get(f"{BASE_URL}{self.URL}")
return self
def login(self, email: str, password: str) -> "DashboardPage":
self.driver.find_element(*self.EMAIL).send_keys(email)
self.driver.find_element(*self.PASSWORD).send_keys(password)
self.driver.find_element(*self.SUBMIT).click()
return DashboardPage(self.driver)
def get_error_message(self) -> str:
element = self.wait.until(EC.visibility_of_element_located(self.ERROR_MESSAGE))
return element.text
class DashboardPage:
WELCOME_HEADER = (By.CSS_SELECTOR, "h1.welcome")
LOGOUT_BUTTON = (By.CSS_SELECTOR, "[data-testid='logout']")
def __init__(self, driver):
self.driver = driver
def get_welcome_text(self) -> str:
return self.driver.find_element(*self.WELCOME_HEADER).text
def logout(self) -> "LoginPage":
self.driver.find_element(*self.LOGOUT_BUTTON).click()
return LoginPage(self.driver)
Using Page Objects in Tests
def test_login_success(driver):
dashboard = LoginPage(driver).open().login("user@test.com", "pass123")
assert dashboard.get_welcome_text() == "Welcome"
def test_login_invalid_password(driver):
login_page = LoginPage(driver).open()
login_page.login("user@test.com", "wrongpass")
assert login_page.get_error_message() == "Invalid email or password"
The test reads like a user story. Locators and interactions are hidden inside the page object. If the CSS selector for the email field changes, you update one line in LoginPage, not every test.