Bird
Raised Fist0
Selenium Pythontesting~15 mins

Page class structure in Selenium Python - Build an Automation Script

Choose your learning style10 modes available
Automate login page using Page Object Model
Preconditions (2)
Step 1: Open the browser and navigate to the login page URL
Step 2: Enter 'testuser@example.com' in the email input field
Step 3: Enter 'TestPass123' in the password input field
Step 4: Click the login button
Step 5: Wait for the dashboard page to load
✅ Expected Result: User is successfully logged in and dashboard page is displayed with URL containing '/dashboard'
Automation Requirements - selenium
Assertions Needed:
Verify current URL contains '/dashboard' after login
Verify login button is clickable before clicking
Verify email and password fields are present before entering text
Best Practices:
Use Page Object Model to separate page structure and test logic
Use explicit waits to wait for elements to be interactable
Use meaningful locators like By.ID or By.NAME instead of brittle XPath
Keep test code clean and readable
Automated Solution
Selenium Python
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.

Common Mistakes - 3 Pitfalls
{'mistake': 'Using hardcoded sleeps instead of explicit waits', 'why_bad': 'Hardcoded sleeps slow tests and can cause flaky failures if the page loads faster or slower than expected.', 'correct_approach': "Use Selenium's explicit waits like WebDriverWait with expected_conditions to wait only as long as needed."}
Locating elements directly in test code instead of using a page class
Using brittle XPath locators that break easily
Bonus Challenge

Now add data-driven testing with 3 different sets of login credentials

Show Hint

Practice

(1/5)
1. What is the main purpose of a page class in Selenium Python testing?
easy
A. To write assertions for test results
B. To store test data for multiple test cases
C. To execute the browser driver directly
D. To group web elements and actions for a single web page

Solution

  1. Step 1: Understand the role of page classes

    Page classes organize locators and methods related to one web page, making tests cleaner.
  2. Step 2: Identify the correct purpose

    Grouping elements and actions for a page matches the page class concept.
  3. Final Answer:

    To group web elements and actions for a single web page -> Option D
  4. Quick Check:

    Page class = group elements and actions [OK]
Hint: Page classes group elements and actions per page [OK]
Common Mistakes:
  • Confusing page class with test data storage
  • Thinking page class runs the browser driver
  • Mixing page class with assertion logic
2. Which of the following is the correct way to define a locator inside a Selenium page class in Python?
easy
A. submit_button = (By.ID, 'submit')
B. submit_button = 'By.ID, submit'
C. submit_button = By.ID('submit')
D. submit_button = By('ID', 'submit')

Solution

  1. Step 1: Recall locator tuple syntax

    Locators use tuples like (By.ID, 'value') to specify how to find elements.
  2. 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.
  3. Final Answer:

    submit_button = (By.ID, 'submit') -> Option A
  4. Quick Check:

    Locator = (By.METHOD, 'value') tuple [OK]
Hint: Use tuple (By.METHOD, 'value') for locators [OK]
Common Mistakes:
  • Using string instead of tuple for locator
  • Calling By.ID as a function
  • Incorrect tuple structure
3. Given the following page class snippet, what will 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)
medium
A. An error because get_title is missing
B. "Welcome Page"
C. None
D. "HomePage"

Solution

  1. Step 1: Understand get_title method

    The method returns self.driver.title, which is the browser's current page title.
  2. Step 2: Check given title

    The browser's title is "Welcome Page", so the method returns this string.
  3. Final Answer:

    "Welcome Page" -> Option B
  4. Quick Check:

    driver.title returns current page title [OK]
Hint: driver.title gives current page title string [OK]
Common Mistakes:
  • Assuming method returns None by default
  • Thinking method is missing or undefined
  • Confusing class name with page title
4. Identify the error in this page class method and how to fix it:
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)
medium
A. Missing return statement in enter_username method
B. send_keys should be called on driver, not element
C. find_element expects two arguments, fix by unpacking locator: *self.username_input
D. Locator should be a string, not a tuple

Solution

  1. Step 1: Check find_element usage

    find_element expects two arguments: method and locator string, not a tuple as one argument.
  2. Step 2: Fix by unpacking tuple

    Use *self.username_input to unpack tuple into two arguments.
  3. Final Answer:

    find_element expects two arguments, fix by unpacking locator: *self.username_input -> Option C
  4. Quick Check:

    Use * to unpack locator tuple in find_element [OK]
Hint: Unpack locator tuple with * in find_element [OK]
Common Mistakes:
  • Passing locator tuple as single argument
  • Calling send_keys on driver instead of element
  • Thinking return is required for action methods
5. You want to create a page class for a login page with username and password fields and a login button. Which design best follows the page class structure and good practices?
hard
A. 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()
B. 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()
C. 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()
D. 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()

Solution

  1. 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.
  2. 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.
  3. 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.
  4. Final Answer:

    Option A follows page class structure and good practices best -> Option A
  5. Quick Check:

    Store locators once, use methods for actions [OK]
Hint: Store locators as tuples, use methods for actions [OK]
Common Mistakes:
  • Repeating locators inside methods
  • Storing locators as plain strings
  • Not separating actions into methods
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard