Page class structure in Selenium Python - Build an Automation Script
from selenium import webdriver 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: def __init__(self, driver): self.driver = driver self.email_input = (By.ID, 'email') self.password_input = (By.ID, 'password') self.login_button = (By.ID, 'loginBtn') def enter_email(self, email): email_field = WebDriverWait(self.driver, 10).until( EC.presence_of_element_located(self.email_input) ) email_field.clear() email_field.send_keys(email) def enter_password(self, password): password_field = WebDriverWait(self.driver, 10).until( EC.presence_of_element_located(self.password_input) ) password_field.clear() password_field.send_keys(password) def click_login(self): login_btn = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable(self.login_button) ) login_btn.click() def test_login(): driver = webdriver.Chrome() driver.get('https://example.com/login') login_page = LoginPage(driver) login_page.enter_email('testuser@example.com') login_page.enter_password('TestPass123') login_page.click_login() WebDriverWait(driver, 10).until( EC.url_contains('/dashboard') ) assert '/dashboard' in driver.current_url, 'Dashboard URL not found after login' driver.quit()
This code uses the Page Object Model to organize the login page interactions.
The LoginPage class stores locators and methods to interact with the email, password, and login button elements.
Each method uses explicit waits to ensure elements are present or clickable before interacting, which avoids timing issues.
The test function test_login opens the browser, navigates to the login page, uses the page object methods to enter credentials and click login, then waits for the dashboard URL to appear.
Finally, it asserts the URL contains '/dashboard' to confirm successful login and closes the browser.
Now add data-driven testing with 3 different sets of login credentials
Practice
Solution
Step 1: Understand the role of page classes
Page classes organize locators and methods related to one web page, making tests cleaner.Step 2: Identify the correct purpose
Grouping elements and actions for a page matches the page class concept.Final Answer:
To group web elements and actions for a single web page -> Option DQuick Check:
Page class = group elements and actions [OK]
- Confusing page class with test data storage
- Thinking page class runs the browser driver
- Mixing page class with assertion logic
Solution
Step 1: Recall locator tuple syntax
Locators use tuples like (By.ID, 'value') to specify how to find elements.Step 2: Check each option
submit_button = (By.ID, 'submit') correctly uses a tuple with By.ID and string 'submit'. Others have syntax errors or wrong formats.Final Answer:
submit_button = (By.ID, 'submit') -> Option AQuick Check:
Locator = (By.METHOD, 'value') tuple [OK]
- Using string instead of tuple for locator
- Calling By.ID as a function
- Incorrect tuple structure
page.get_title() return if the browser's current page title is "Welcome Page"?
class HomePage:
def __init__(self, driver):
self.driver = driver
def get_title(self):
return self.driver.title
page = HomePage(driver)Solution
Step 1: Understand get_title method
The method returnsself.driver.title, which is the browser's current page title.Step 2: Check given title
The browser's title is "Welcome Page", so the method returns this string.Final Answer:
"Welcome Page" -> Option BQuick Check:
driver.title returns current page title [OK]
- Assuming method returns None by default
- Thinking method is missing or undefined
- Confusing class name with page title
class LoginPage:
def __init__(self, driver):
self.driver = driver
self.username_input = (By.ID, 'username')
def enter_username(self, username):
self.driver.find_element(self.username_input).send_keys(username)Solution
Step 1: Check find_element usage
find_element expects two arguments: method and locator string, not a tuple as one argument.Step 2: Fix by unpacking tuple
Use *self.username_input to unpack tuple into two arguments.Final Answer:
find_element expects two arguments, fix by unpacking locator: *self.username_input -> Option CQuick Check:
Use * to unpack locator tuple in find_element [OK]
- Passing locator tuple as single argument
- Calling send_keys on driver instead of element
- Thinking return is required for action methods
Solution
Step 1: Check locator storage
class LoginPage: def __init__(self, driver): self.driver = driver self.username = (By.ID, 'user') self.password = (By.ID, 'pass') self.login_btn = (By.ID, 'login') def enter_username(self, name): self.driver.find_element(*self.username).send_keys(name) def enter_password(self, pwd): self.driver.find_element(*self.password).send_keys(pwd) def click_login(self): self.driver.find_element(*self.login_btn).click() stores locators as tuples in __init__, which is best practice for reuse and clarity.Step 2: Check method structure
class LoginPage: def __init__(self, driver): self.driver = driver self.username = (By.ID, 'user') self.password = (By.ID, 'pass') self.login_btn = (By.ID, 'login') def enter_username(self, name): self.driver.find_element(*self.username).send_keys(name) def enter_password(self, pwd): self.driver.find_element(*self.password).send_keys(pwd) def click_login(self): self.driver.find_element(*self.login_btn).click() has separate methods for each action, improving readability and maintainability.Step 3: Compare other options
class LoginPage: def __init__(self, driver): self.driver = driver def login(self, user, pwd): self.driver.find_element(By.ID, 'user').send_keys(user) self.driver.find_element(By.ID, 'pass').send_keys(pwd) self.driver.find_element(By.ID, 'login').click() repeats locators in methods, class LoginPage: def __init__(self, driver): self.driver = driver self.username = 'user' self.password = 'pass' self.login_btn = 'login' def login(self, user, pwd): self.driver.find_element(By.ID, self.username).send_keys(user) self.driver.find_element(By.ID, self.password).send_keys(pwd) self.driver.find_element(By.ID, self.login_btn).click() stores locators as strings only, class LoginPage: def __init__(self, driver): self.driver = driver def enter_username(self, name): self.driver.find_element(By.ID, 'user').send_keys(name) def enter_password(self, pwd): self.driver.find_element(By.ID, 'pass').send_keys(pwd) def click_login(self): self.driver.find_element(By.ID, 'login').click() does not store locators as variables.Final Answer:
Option A follows page class structure and good practices best -> Option AQuick Check:
Store locators once, use methods for actions [OK]
- Repeating locators inside methods
- Storing locators as plain strings
- Not separating actions into methods
Ready to prove it?
Pass the test and this pattern moves unknown
