Page Object Model, Done Properly
Once you have more than a handful of tests, they start to sprawl. This pattern keeps them tidy — and it's exactly the structure interviewers hope to see.
The problem, in one line
When locators are copy-pasted across many tests, one renamed button breaks twenty files. That's a maintenance tax you don't want.
The idea, in one line
The Page Object Model gives each page (or component) a class that owns its locators and offers plain-English actions. Tests call the actions and never touch a raw selector.
Where to draw the line
- A page object holds locators and actions like
login(user, pw)oradd_first_item(). It returns data or the next page — and contains no assertions. - A test holds the scenario and the assertions. It calls
login(), then checks the result. - A helper is anything reused across many pages — a random-email generator, an API seeding call. It's not a page.
Keep methods at the user's level. A test should read like cart.add_first_item(), never a raw selector. When the UI changes, you edit one method in one class and every test keeps passing.
See it work
# pages/login_page.py — locators + actions, NO assertions
from playwright.sync_api import Page
class LoginPage:
def __init__(self, page: Page):
self.page = page
self.username = page.get_by_placeholder("Username")
self.password = page.get_by_placeholder("Password")
self.login_btn = page.get_by_role("button", name="Login")
def load(self):
self.page.goto("https://www.saucedemo.com/")
def login(self, user: str, pw: str):
self.username.fill(user)
self.password.fill(pw)
self.login_btn.click()
# test_login.py — scenario + assertions live here
from playwright.sync_api import expect
from pages.login_page import LoginPage
def test_valid_login(page):
login = LoginPage(page)
login.load()
login.login("standard_user", "secret_sauce")
expect(page.get_by_text("Products")).to_be_visible()Read it top to bottom: the page class knows where the fields are and how to log in. The test just says 'load, log in, and check I landed on Products.' Clean and easy to read.
Advanced — this is how frameworks scale
Grounded in the official Selenium docs (Page Object Models) and Playwright POM guide
All lessons in UI Automation: Selenium + Playwright + pytest
- Selenium Locators: Finding the Element You Mean
- Waits, Actions & Frames — Killing Flakiness at the Source
- Playwright: Auto-Waiting, Locators & Tracing
- pytest Deep-Dive: Fixtures, conftest, Parametrize & Markers
- Page Object Model, Done Properly
- The Hard Stuff: Dynamic Elements, iframes, Uploads & Network Stubbing