Bird
Raised Fist0
Selenium Pythontesting~15 mins

Page factory pattern in Selenium Python - Deep Dive

Choose your learning style10 modes available
Overview - Page factory pattern
What is it?
The Page Factory pattern is a way to organize web page elements and actions in Selenium tests. It helps create a clear structure by separating the page's elements and the test logic. This pattern uses special annotations to find and store web elements efficiently. It makes tests easier to read, write, and maintain.
Why it matters
Without the Page Factory pattern, tests can become messy and hard to manage because element locators and test steps mix together. This leads to duplicated code and fragile tests that break easily when the web page changes. Using this pattern saves time and reduces errors, making automated tests more reliable and faster to update.
Where it fits
Before learning Page Factory, you should understand basic Selenium concepts like locating elements and writing simple tests. After mastering Page Factory, you can explore advanced test design patterns, test frameworks integration, and parallel test execution.
Mental Model
Core Idea
Page Factory organizes web elements as reusable objects to keep tests clean and maintainable.
Think of it like...
It's like having a labeled toolbox where each tool (web element) is stored in a specific spot, so you can quickly grab and use it without searching every time.
Page Object Class
┌───────────────────────────────┐
│  @FindBy(locator)              │
│  WebElement elementName       │
│                               │
│  Methods to interact with     │
│  elements (click, input, etc) │
└───────────────────────────────┘

Test Class
┌───────────────────────────────┐
│  Create Page Object instance   │
│  Call methods on elements      │
│  Assert results                │
└───────────────────────────────┘
Build-Up - 6 Steps
1
FoundationUnderstanding Selenium Web Elements
🤔
Concept: Learn what web elements are and how Selenium finds them.
In Selenium, web elements are parts of a web page like buttons, text boxes, or links. You find them using locators such as ID, name, or XPath. For example, driver.find_element(By.ID, 'submit') finds the submit button.
Result
You can interact with web elements, like clicking a button or typing text.
Knowing how Selenium locates elements is the base for organizing them better with patterns.
2
FoundationIntroduction to Page Object Model
🤔
Concept: Separate page structure from test logic using classes.
Page Object Model means creating a class for each web page. This class holds locators and methods to interact with the page. Tests then use these classes instead of raw locators.
Result
Tests become cleaner and easier to maintain because page details are in one place.
Separating page details from tests reduces duplication and makes updates simpler.
3
IntermediateUsing Page Factory for Element Initialization
🤔Before reading on: do you think Page Factory finds elements immediately or only when used? Commit to your answer.
Concept: Page Factory initializes web elements lazily using annotations.
Page Factory uses @FindBy annotations to declare elements. It initializes them only when the test uses them, saving time and avoiding errors if elements are not present immediately. In Python, you use selenium.webdriver.support.page_factory with decorators.
Result
Elements are ready to use without manual find_element calls, improving code clarity.
Lazy initialization avoids unnecessary searches and speeds up test setup.
4
IntermediateBest Practices for Locators in Page Factory
🤔Before reading on: is it better to use complex XPath or simple IDs for locators? Commit to your answer.
Concept: Choosing stable and fast locators improves test reliability.
Use unique IDs or names when possible because they are fast and stable. Avoid brittle XPath that breaks with small page changes. Page Factory works best with simple, clear locators.
Result
Tests break less often and are easier to fix when locators are well chosen.
Good locators are the foundation of stable automated tests.
5
AdvancedHandling Dynamic Elements with Page Factory
🤔Before reading on: do you think Page Factory can handle elements that appear after page load automatically? Commit to your answer.
Concept: Use waits and custom element initialization for dynamic content.
Dynamic elements may not be present immediately. Combine Page Factory with explicit waits to wait for elements before interacting. You can write methods that wait for elements inside the page object class.
Result
Tests become more robust and less flaky when handling dynamic pages.
Combining Page Factory with waits handles real-world web page behavior effectively.
6
ExpertCustom Decorators and Extending Page Factory
🤔Before reading on: can you extend Page Factory to add logging or error handling automatically? Commit to your answer.
Concept: You can create custom decorators to enhance element behavior.
In Python, decorators can wrap element access to add features like logging, screenshots on failure, or retries. This extends Page Factory beyond simple element storage to smarter test helpers.
Result
Tests gain extra power and diagnostics without cluttering test code.
Extending Page Factory with custom decorators unlocks advanced test capabilities.
Under the Hood
Page Factory uses a proxy pattern where element locators are stored but actual element lookup happens only when the element is used. This lazy loading reduces initial overhead and avoids errors if elements are not immediately present. The framework uses reflection or decorators to bind locators to variables automatically.
Why designed this way?
It was designed to improve test code readability and maintainability by separating element definitions from test logic. Early Selenium tests mixed locators and actions, causing duplication and fragile tests. Page Factory automates element initialization and supports lazy loading to handle dynamic pages better.
Test Code
  │
  ▼
Page Object Class
  ├─ @FindBy locators stored
  ├─ Methods to interact
  │
  ▼
Proxy Element
  ├─ On first use: find_element called
  ├─ Element cached
  │
  ▼
WebDriver
  ├─ Executes find_element
  └─ Returns WebElement
Myth Busters - 4 Common Misconceptions
Quick: Does Page Factory find all elements immediately when the page object is created? Commit to yes or no.
Common Belief:Page Factory finds all elements as soon as the page object is created.
Tap to reveal reality
Reality:Page Factory initializes elements lazily, only when they are accessed in the test.
Why it matters:Assuming immediate lookup can cause confusion about test speed and errors if elements are not present yet.
Quick: Is it okay to use complex XPath locators with Page Factory for best results? Commit to yes or no.
Common Belief:Using complex XPath locators with Page Factory is fine and reliable.
Tap to reveal reality
Reality:Complex XPath locators are brittle and can break easily; simple locators like IDs are better.
Why it matters:Using brittle locators leads to flaky tests that break with minor page changes.
Quick: Can Page Factory alone handle waiting for elements that load dynamically? Commit to yes or no.
Common Belief:Page Factory automatically waits for elements to appear before interacting.
Tap to reveal reality
Reality:Page Factory does not handle waits; explicit waits must be added separately.
Why it matters:Without waits, tests may fail intermittently on dynamic pages.
Quick: Does using Page Factory guarantee your tests will never break? Commit to yes or no.
Common Belief:Using Page Factory makes tests completely stable and unbreakable.
Tap to reveal reality
Reality:Page Factory helps organize code but does not prevent all test failures due to page changes or timing issues.
Why it matters:Overreliance on Page Factory can lead to ignoring other important test design practices.
Expert Zone
1
Page Factory's lazy loading means element lookup errors happen at interaction time, not at page object creation, which affects debugging timing.
2
Custom decorators can wrap element access to add retries or logging, improving test resilience and diagnostics without cluttering test code.
3
Combining Page Factory with explicit waits is essential for handling modern dynamic web pages, but this is not built-in and requires careful design.
When NOT to use
Avoid Page Factory when testing very simple pages or scripts where overhead is unnecessary. For highly dynamic single-page applications, consider using explicit waits and direct element handling or frameworks designed for reactive content like Playwright or Cypress.
Production Patterns
In real projects, Page Factory is combined with test frameworks like pytest and continuous integration. Teams create base page classes with common methods and extend them for specific pages. Custom wrappers add logging, screenshots, and retries. Tests use dependency injection to manage page objects cleanly.
Connections
Object-Oriented Programming
Page Factory builds on OOP by encapsulating page elements as objects.
Understanding classes and objects helps grasp how Page Factory organizes web elements into reusable components.
Lazy Loading Pattern
Page Factory uses lazy loading to delay element lookup until needed.
Knowing lazy loading explains why Page Factory improves performance and handles dynamic content better.
Supply Chain Management
Both manage resources efficiently by delaying actions until necessary.
Just like supply chains avoid stockpiling by ordering parts only when needed, Page Factory delays finding elements until interaction, saving time and resources.
Common Pitfalls
#1Locating elements immediately in the constructor causing errors if elements are not present.
Wrong approach:class LoginPage: def __init__(self, driver): self.driver = driver self.username = driver.find_element(By.ID, 'username') # wrong: immediate lookup self.password = driver.find_element(By.ID, 'password')
Correct approach:from selenium.webdriver.support.page_factory import PageFactory class LoginPage: def __init__(self, driver): self.driver = driver self.username = None self.password = None PageFactory.init_elements(driver, self) # lazy initialization
Root cause:Misunderstanding that elements should be found only when used, not at object creation.
#2Using complex XPath locators that break easily when page structure changes.
Wrong approach:self.submit_button = driver.find_element(By.XPATH, '//div[3]/form/button[1]') # brittle XPath
Correct approach:self.submit_button = driver.find_element(By.ID, 'submit') # stable ID locator
Root cause:Not prioritizing stable, unique locators leads to fragile tests.
#3Not using explicit waits with Page Factory causing flaky tests on dynamic pages.
Wrong approach:self.login_button.click() # no wait, may fail if button not ready
Correct approach:from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC wait = WebDriverWait(driver, 10) wait.until(EC.element_to_be_clickable((By.ID, 'login'))) self.login_button.click()
Root cause:Assuming Page Factory handles waits automatically.
Key Takeaways
Page Factory pattern organizes web elements into reusable objects, separating page structure from test logic.
It uses lazy loading to find elements only when needed, improving test speed and handling dynamic content better.
Choosing stable locators like IDs over complex XPath makes tests more reliable and easier to maintain.
Page Factory does not handle waits; combining it with explicit waits is essential for robust tests.
Advanced users can extend Page Factory with custom decorators to add logging, retries, and other features.

Practice

(1/5)
1. What is the main purpose of using the Page Factory pattern in Selenium with Python?
easy
A. To generate test reports automatically
B. To execute tests faster by parallel processing
C. To group web elements in a class for easier access and maintenance
D. To handle browser pop-ups and alerts

Solution

  1. Step 1: Understand the role of Page Factory

    Page Factory helps organize web elements by grouping them in a class, making tests easier to read and maintain.
  2. Step 2: Compare with other options

    Options B, C, and D describe different Selenium features unrelated to Page Factory's main purpose.
  3. Final Answer:

    To group web elements in a class for easier access and maintenance -> Option C
  4. Quick Check:

    Page Factory = Group elements for easy access [OK]
Hint: Page Factory groups elements in classes for neat tests [OK]
Common Mistakes:
  • Confusing Page Factory with test execution speed
  • Thinking it generates reports
  • Assuming it handles browser alerts
2. Which of the following is the correct way to declare a web element using Page Factory in Selenium Python?
easy
A. element = driver.find_element(By.ID, 'username')
B. username = (By.ID, 'username')
C. username = self.driver.find_element_by_id('username')
D. username = self.driver.find_element(By.ID, 'username')

Solution

  1. Step 1: Identify Page Factory syntax in Python

    Page Factory uses class attributes with locator tuples like (By.ID, 'username') to declare elements before initializing them.
  2. Step 2: Check each option

    username = (By.ID, 'username') shows the correct locator tuple usage, which is standard in Page Factory.
  3. Final Answer:

    username = (By.ID, 'username') -> Option B
  4. Quick Check:

    Page Factory uses locator tuples (By.xx, 'value') [OK]
Hint: Declare Page Factory elements as (By.xx, 'value') tuples [OK]
Common Mistakes:
  • Using direct driver.find_element calls instead of Page Factory declarations
  • Missing the locator tuple syntax
  • Assigning elements directly without initialization
3. Given the following code snippet using Page Factory in Selenium Python, what will be the output of print(page.login_button.is_displayed()) if the button is visible on the page?
from selenium.webdriver.common.by import By
from selenium.webdriver.support.page_factory import PageFactory

class LoginPage:
    def __init__(self, driver):
        self.driver = driver
        PageFactory.init_elements(driver, self)

    login_button = (By.ID, 'loginBtn')

page = LoginPage(driver)
print(page.login_button.is_displayed())
medium
A. True
B. False
C. AttributeError
D. None

Solution

  1. Step 1: Understand Page Factory element initialization

    PageFactory.init_elements initializes elements so login_button refers to the actual web element.
  2. Step 2: Check the method call

    If the button is visible, is_displayed() returns True, so printing it outputs True.
  3. Final Answer:

    True -> Option A
  4. Quick Check:

    Visible element's is_displayed() = True [OK]
Hint: is_displayed() returns True if element is visible [OK]
Common Mistakes:
  • Expecting None because locator needs initialization
  • Confusing AttributeError due to wrong initialization
  • Assuming is_displayed() returns string
4. Identify the error in the following Page Factory code snippet and choose the correct fix:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.page_factory import PageFactory

class HomePage:
    def __init__(self, driver):
        self.driver = driver
        PageFactory.init_elements(self, self.driver)

    submit_button = (By.XPATH, "//button[@id='submit']")

page = HomePage(driver)
page.submit_button.click()
medium
A. Initialize elements with PageFactory.init_elements(driver, self)
B. Replace @FindBy with @find_by (lowercase)
C. Import FindBy from correct module and use it as decorator
D. Import and use find_element instead of PageFactory

Solution

  1. Step 1: Check PageFactory.init_elements arguments

    The code uses PageFactory.init_elements(self, self.driver) but arguments must be driver first, then self.
  2. Step 2: Confirm correct usage

    Using PageFactory.init_elements(driver, self) fixes the error and allows proper element initialization.
  3. Final Answer:

    Initialize elements with PageFactory.init_elements(driver, self) -> Option A
  4. Quick Check:

    init_elements(driver, self) order [OK]
Hint: PageFactory.init_elements(driver, self) - driver first [OK]
Common Mistakes:
  • Wrong argument order for PageFactory.init_elements
  • Using wrong decorator name case
  • Incorrect PageFactory.init_elements parameters
5. You want to create a Page Factory class for a login page with username, password fields, and a login button. Which approach correctly applies the Page Factory pattern to initialize and use these elements in Selenium Python?
hard
A. Write all element locators inside test functions without any class or decorator
B. Use driver.find_element calls inside each test method without class grouping
C. Create global variables for elements outside any class and access them directly
D. Declare elements with @FindBy decorators, initialize with PageFactory.init_elements, then use element methods

Solution

  1. Step 1: Understand Page Factory best practice

    Page Factory groups elements in a class using locator tuples and initializes them with PageFactory.init_elements.
  2. Step 2: Compare with other options

    Options B, C, and D do not use Page Factory pattern and lead to less maintainable code.
  3. Final Answer:

    Declare elements with @FindBy decorators, initialize with PageFactory.init_elements, then use element methods -> Option D
  4. Quick Check:

    Page Factory = locators + init_elements + class grouping [OK]
Hint: Use locators and init_elements to organize page elements [OK]
Common Mistakes:
  • Skipping class and locators for elements
  • Using driver calls directly in tests
  • Not initializing elements with PageFactory
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