29 / 80 · 12 Programming for QA · OOP for Testing← prev⊞ allnext →☰ Read as one page
4.3Inheritance: Base Page Classes
When pages share common behavior (navigation bar, footer, common waits), use a base class.
class BasePage:
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
def get_page_title(self) -> str:
return self.driver.title
def is_loaded(self, locator) -> bool:
try:
self.wait.until(EC.presence_of_element_located(locator))
return True
except TimeoutException:
return False
def scroll_to_element(self, locator):
element = self.driver.find_element(*locator)
self.driver.execute_script("arguments[0].scrollIntoView(true);", element)
class LoginPage(BasePage):
# Inherits __init__, get_page_title, is_loaded, scroll_to_element
EMAIL = (By.CSS_SELECTOR, "input[name='email']")
# ...
class AdminPage(BasePage):
USER_TABLE = (By.CSS_SELECTOR, ".user-table")
def is_loaded(self, locator=None):
return super().is_loaded(locator or self.USER_TABLE)
The Inheritance Trap
Deep inheritance hierarchies become brittle:
# BAD: 4 levels deep — hard to understand and modify
class BasePage: ...
class AuthenticatedPage(BasePage): ...
class AdminPage(AuthenticatedPage): ...
class SuperAdminPage(AdminPage): ...
When SuperAdminPage behaves unexpectedly, you must trace through four levels to find the issue. Changes to BasePage can break all downstream classes.
Rule of thumb: Keep inheritance to one or two levels maximum.