Module 7 · Python for SDETs

Page Object
Model

Hide selectors behind readable page classes — tests become scenarios

page classes one place for selectors pages/ package pythonpath = .
AI with Rufat
Selectors copy-pasted everywhere

Fifty tests, the same selectors — change one, edit them all

# in test_login.py, and test_checkout.py, and test_profile.py …
page.get_by_label("Email").fill("customer@test.io")
page.get_by_label("Password").fill("customer123")
page.get_by_test_id("login-submit").click()
💥When the login button's data-testid changes, you hunt it down in every test. The selectors belong in one place.
AI with Rufat
One class owns the page's selectors + actions
# pages/login_page.py
class LoginPage:
def __init__(self, page, base_url):
self.page, self.base_url = page, base_url
self.email = page.get_by_label("Email")
self.password = page.get_by_label("Password")
self.submit = page.get_by_test_id("login-submit")
def goto(self):
self.page.goto(f"{self.base_url}/auth/login")
return self
def login(self, email, pw):
self.email.fill(email)
self.password.fill(pw)
self.submit.click()
📦Locators live in __init__; each user task (login, search) is a method. The selector appears once.
🔗Return self from navigations like goto() so calls can chain: LoginPage(...).goto().login(...).
AI with Rufat
The test reads as a scenario
Without a page object
page.get_by_label("Email").fill(…)
page.get_by_label("Password").fill(…)
page.get_by_test_id("login-submit").click()
With LoginPage
(
LoginPage(page, base_url)
.goto()
.login("customer@test.io", "customer123")
)
📖Reads like the intent — the how is hidden in the page class.
AI with Rufat
Where page objects live
python-sdet/
├── pages/
│ ├── __init__.py
│ └── login_page.py
├── tests/
│ └── test_login.py
└── pytest.ini
# pytest.ini
[pytest]
testpaths = tests
pythonpath = .
🧭pythonpath = . (pytest ≥ 7) puts the project root on sys.path so from pages… import … resolves.
AI with Rufat
📦

Selectors in
one place

Page classes hide the how, so tests read like scenarios and survive redesigns

🧪
Practice
Move your Module 6 login into a LoginPage and a ProductsPage
🔗
Chain
Return self from goto() so LoginPage(...).goto().login(...) reads cleanly
➡️
Module 8
Data-driven tests — one test body, many cases from a file
AI with Rufat
← / → · space