Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk8 min

How to Use the Page Object Model in Selenium with Python

Organize Selenium Python tests with page classes that own locators and user actions, while tests handle assertions and explicit waits synchronize dynamic pages.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use one class for each meaningful page or reusable UI component, pass it a Selenium WebDriver, and expose methods that describe user actions. Keep assertions in the test, where expected behavior belongs, and use explicit waits for the conditions your test needs. This structure keeps page-specific selectors and interactions in one place, so a UI change is less likely to require edits across many tests.

What the Page Object Model does

The Page Object Model (POM) is a way to organize browser tests around the web pages and interface regions they use. A page object owns knowledge of its page’s locators and provides useful operations such as entering credentials or submitting a search. A test uses those operations to describe a scenario and checks whether the expected outcome occurred.

Selenium’s Page Object Models guidance explains that this reduces duplicated code and localizes fixes when the UI changes. A page object is not a second test case: its job is to interact with the UI, not to decide whether the application’s behavior passed acceptance criteria.

Set up Selenium with Python

Install Selenium in the Python environment used by your project:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
python -m pip install selenium

Recent Selenium releases can manage compatible browser drivers through Selenium Manager, but the browser itself must be installed. If your environment blocks driver downloads or requires a pinned browser/driver, configure that separately according to your project’s setup.

The examples below use Python 3, Selenium’s current By locator style, and pytest. Install pytest if it is not already available:

python -m pip install pytest

Build a page object around user actions

Suppose a login page has elements with stable IDs username, password, and submit, and a successful login displays an element with ID welcome. Adapt these locators and the expected result to your application’s actual markup.

# pages/login_page.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


class LoginPage:
    URL = "https://example.com/login"
    USERNAME = (By.ID, "username")
    PASSWORD = (By.ID, "password")
    SUBMIT = (By.ID, "submit")
    WELCOME = (By.ID, "welcome")

    def __init__(self, driver):
        self.driver = driver
        self.wait = WebDriverWait(driver, 10)

    def open(self):
        self.driver.get(self.URL)
        self.wait.until(EC.visibility_of_element_located(self.USERNAME))
        return self

    def login_as(self, username, password):
        self.wait.until(EC.visibility_of_element_located(self.USERNAME)).send_keys(username)
        self.driver.find_element(*self.PASSWORD).send_keys(password)
        self.wait.until(EC.element_to_be_clickable(self.SUBMIT)).click()

    def welcome_message(self):
        return self.wait.until(EC.visibility_of_element_located(self.WELCOME)).text

The class receives an existing driver rather than creating its own browser. That keeps browser lifecycle and test setup under the test runner’s control. The open() method checks that the login form is ready before returning; login_as() performs a user-level operation; and welcome_message() exposes observable state for the test to verify.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Returning self from open() is optional. A workflow may instead return a different page object after navigation, a component object, or no value. Choose the return style that makes the scenario readable; Selenium’s page-object guidance does not require a particular project layout or method convention.

Keep behavioral assertions in the test

Here is a pytest test using the page object. The example assumes the application provides a test account through environment variables and that the successful-login message is stable.

# tests/test_login.py
import os

from selenium import webdriver
from pages.login_page import LoginPage


def test_user_can_log_in():
    driver = webdriver.Chrome()
    try:
        page = LoginPage(driver).open()
        page.login_as(
            os.environ["TEST_USERNAME"],
            os.environ["TEST_PASSWORD"],
        )

        assert "Welcome" in page.welcome_message()
    finally:
        driver.quit()

Run it with credentials set in your shell, for example:

TEST_USERNAME='test-user' TEST_PASSWORD='test-password' pytest -q

Do not put real credentials in source control. In a larger suite, create the driver in a pytest fixture so setup and cleanup are shared consistently. Keep the assertion in the test: Selenium’s guidance says page objects should not make ordinary verifications or assertions. A narrow readiness check, such as confirming the expected form is visible when opening a page, is different from asserting that a business outcome succeeded.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose locators the page can own

Keep each locator beside the page or component that describes it. A short page class can define locator tuples as class attributes, as above; a project with many locators may use a separate locator class or module. The important point is that separating files should make ownership clearer, not scatter UI knowledge across the test suite.

Selenium supports locator strategies including ID, name, CSS selector, link text, partial link text, class name, tag name, and XPath. See the official locator strategies reference. Prefer an application-provided stable test attribute when one is available; otherwise choose a locator that is both clear and resilient to incidental markup changes. No locator strategy is universally best.

  • Use a page method such as login_as() when it expresses a meaningful user task.
  • Avoid methods that only rename one low-level call, such as click_submit_button(), unless that abstraction adds useful meaning or coordination.
  • When a locator changes, update the page or component that owns it rather than duplicating a replacement across tests.

Wait for the condition the next action needs

A navigation command returning does not guarantee that JavaScript-rendered content is ready. Selenium’s Waiting Strategies documentation describes race conditions caused by asynchronous page changes as a primary source of flaky tests. Use WebDriverWait(driver, seconds).until(...) with a condition tied to the next operation: presence or visibility before reading, clickability before clicking, or another condition that reflects the UI state you need.

In the example, the username field is awaited before typing, the submit control is awaited before clicking, and the welcome element is awaited before its text is read. The ten-second timeout is an example project choice, not a Selenium requirement; set a consistent timeout appropriate to the application and test environment.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Avoid using fixed sleeps as normal synchronization: they may waste time when a page is fast and still fail when it is slower than expected. Also avoid casually combining implicit and explicit waits. Selenium’s waits guidance warns that mixing them can produce unpredictable timing behavior; choose a consistent wait policy and make it explicit in test setup.

Extract a component when it earns its own object

A repeated navigation bar, product card, or substantial form region can be represented as a component object when it has meaningful operations or appears on multiple pages. The containing page can compose that object rather than growing into one class that represents the entire site.

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


class MainNavigation:
    SEARCH = (By.CSS_SELECTOR, "nav input[name='q']")
    SEARCH_BUTTON = (By.CSS_SELECTOR, "nav button[type='submit']")

    def __init__(self, driver):
        self.driver = driver
        self.wait = WebDriverWait(driver, 10)

    def search_for(self, term):
        field = self.wait.until(EC.visibility_of_element_located(self.SEARCH))
        field.clear()
        field.send_keys(term)
        self.wait.until(EC.element_to_be_clickable(self.SEARCH_BUTTON)).click()


class HomePage:
    def __init__(self, driver):
        self.driver = driver
        self.navigation = MainNavigation(driver)

Use component objects for coherent regions with reusable behavior, not for every small fragment. Excessively fine-grained classes add indirection without necessarily reducing maintenance.

Or skip the browser setup

A Selenium page object is for browser-driven tests and interactions. If your separate need is to capture a page image or PDF as visual evidence, ScreenshotNeo is a screenshot API and MCP server; it does not replace Selenium’s page-object pattern or your assertions. For example, this cURL request saves a screenshot:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. It accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.

Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month with no card.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting common POM failures

NoSuchElementException or a missing element

Check that the locator matches the current page, that the test opened the intended URL, and that the element is not inside an iframe or shadow root requiring additional handling. For asynchronously rendered elements, wait for the relevant presence or visibility condition instead of searching immediately.

ElementNotInteractableException or click interception

The element may be hidden, disabled, covered by an overlay, or not yet ready. Wait for visibility or clickability as appropriate, and inspect the page state and locator. Do not treat a JavaScript click as a routine workaround; it can bypass the user interaction your test is meant to exercise.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Tests pass locally but fail intermittently in CI

Look for race conditions, shared browser state, unstable locators, and tests depending on leftover data or execution order. Replace broad timing assumptions with waits for the actual state, ensure each test creates or receives a clean driver, and retain failure evidence such as screenshots or browser logs where your test infrastructure supports them.

Unexpected delays or timeouts

Identify which condition timed out and whether the page actually reached that state. A timeout should not be hidden by increasing it blindly: first check navigation, test data, selectors, overlays, and application errors, then adjust the project’s consistent wait policy if the legitimate operation needs longer.

Further reading

Frequently Asked Questions

Should a page object contain assertions?

Keep behavioral assertions in the test. A page object may check that its expected page is ready during initialization, but it should not decide whether the scenario passed.

Do I need a separate locator class or a pages package?

No. Locators can live on the page class for a small project, or in separate modules if that improves clarity. Choose organization that keeps UI knowledge easy to find.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should every UI element have its own component object?

No. Extract a component when it represents a coherent region with meaningful reusable behavior; trivial fragments often do not justify an extra class.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. Shenzhen desk3 min
    HONOR Expands Beyond Smartphones With Humanoid Robot RevealHONOR said it unveiled its first humanoid robot at MWC 2026 and named shopping assistance, workplace inspections, and supportive companionship as intended uses. Later Robotics D1 claims and a reported…
  2. Cupertino desk5 min
    Apple Unveils AirPods Max 2: The Upgrade That Should Have Happened Years AgoAirPods Max 2 adds H2-powered audio features and Apple claims up to 1.5× more effective ANC, but its design, Smart Case, and 20-hour battery rating are unchanged. Wired lossless audio…
  3. Cupertino desk4 min
    Apple’s OLED Touch MacBooks Are Coming—but the Dynamic Island Is the Real GambleApple has not announced an OLED touchscreen MacBook, but reports point to high-end models arriving in late 2026 or early 2027. The reported Mac Dynamic Island could be useful, but…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.