0
0
Selenium Javatesting~15 mins

Page class design in Selenium Java - Deep Dive

Choose your learning style9 modes available
Overview - Page class design
What is it?
Page class design is a way to organize code for testing web pages. Each web page or part of it is represented by a class in code. This class contains methods to interact with the page, like clicking buttons or entering text. It helps testers write clear and reusable test scripts.
Why it matters
Without page class design, test code becomes messy and hard to maintain. Testers would repeat the same code for interacting with pages, making tests fragile and slow to update. Using page classes saves time, reduces errors, and makes tests easier to understand and fix when the website changes.
Where it fits
Before learning page class design, you should know basic Selenium commands and Java programming. After mastering it, you can learn advanced test frameworks, test data management, and continuous integration for automated testing.
Mental Model
Core Idea
A page class acts like a smart remote control for a web page, bundling all ways to interact with that page into one place.
Think of it like...
Imagine a TV remote control designed only for your TV model. Instead of pressing random buttons, you have labeled buttons for volume, channel, and power. The page class is like that remote, giving you easy buttons to control the web page.
┌───────────────────────────┐
│        Page Class         │
│ ┌───────────────┐         │
│ │ Locators      │         │
│ │ (buttons,     │         │
│ │  fields)      │         │
│ └───────────────┘         │
│ ┌───────────────┐         │
│ │ Methods       │         │
│ │ (click, input)│         │
│ └───────────────┘         │
└────────────┬──────────────┘
             │
             ▼
    Test script calls methods
    to interact with the page
Build-Up - 7 Steps
1
FoundationUnderstanding Web Page Elements
🤔
Concept: Learn what web elements are and how Selenium finds them.
Web pages have buttons, text boxes, links, and more. Selenium uses locators like id, name, or xpath to find these elements. For example, driver.findElement(By.id("submit")) finds a button with id 'submit'.
Result
You can identify and access any element on a web page using Selenium locators.
Knowing how to find elements is the base for interacting with pages and building page classes.
2
FoundationBasic Selenium Actions
🤔
Concept: Learn how to perform simple actions like clicking and typing.
Once you find an element, you can click it with element.click() or type text with element.sendKeys("text"). These actions simulate user behavior on the page.
Result
You can automate simple user interactions on web pages.
Mastering these actions is essential before grouping them into page classes.
3
IntermediateCreating a Page Class Structure
🤔Before reading on: do you think a page class should contain test assertions or only page interactions? Commit to your answer.
Concept: Introduce the idea of a class representing a page with locators and methods.
A page class has private locators as variables and public methods to interact with them. For example, a LoginPage class has locators for username, password, and login button, plus methods like enterUsername(), enterPassword(), and clickLogin().
Result
You organize page interactions in one place, making tests cleaner.
Separating page details from tests improves code reuse and maintenance.
4
IntermediateUsing Constructor and WebDriver
🤔Before reading on: should each page class create its own WebDriver instance or receive it from outside? Commit to your answer.
Concept: Learn how to pass WebDriver to page classes and initialize locators.
Page classes receive a WebDriver object via constructor. This driver is used to find elements. For example: public LoginPage(WebDriver driver) { this.driver = driver; usernameField = driver.findElement(By.id("username")); } This avoids creating multiple drivers and keeps control centralized.
Result
Page classes share the same browser session controlled by one WebDriver.
Passing WebDriver keeps tests flexible and avoids resource conflicts.
5
IntermediateEncapsulating Page Actions
🤔Before reading on: do you think page classes should expose locators directly or only methods? Commit to your answer.
Concept: Hide locators and expose only meaningful methods to interact with the page.
Locators are private to the class. Tests call methods like loginPage.enterUsername("user") instead of accessing elements directly. This hides page details and allows changing locators without breaking tests.
Result
Tests become simpler and less fragile to page changes.
Encapsulation protects tests from page structure changes.
6
AdvancedHandling Page Navigation and Returns
🤔Before reading on: should a method that clicks a login button return a new page object or void? Commit to your answer.
Concept: Methods can return other page classes to model navigation flows.
For example, clickLogin() returns a HomePage object because clicking login moves to the home page: public HomePage clickLogin() { loginButton.click(); return new HomePage(driver); } This models the real user journey and helps chain actions in tests.
Result
Tests can write fluent sequences like loginPage.enterUsername().enterPassword().clickLogin().verifyHomePage().
Returning page objects models user flow and improves test readability.
7
ExpertOptimizing with Lazy Element Initialization
🤔Before reading on: do you think locating elements once in constructor is always best, or locating them fresh each time? Commit to your answer.
Concept: Use lazy loading to find elements only when needed to avoid stale element errors.
Instead of locating elements in constructor, define locators and find elements inside methods. For example: private By usernameLocator = By.id("username"); public void enterUsername(String user) { driver.findElement(usernameLocator).sendKeys(user); } This avoids errors when page reloads or changes after initial load.
Result
Tests become more stable and less prone to failures from page updates.
Understanding element lifecycle prevents common Selenium errors in real tests.
Under the Hood
Page classes work by holding references to locators and using WebDriver to find and interact with elements at runtime. WebDriver sends commands to the browser to perform actions like clicks or typing. The page class abstracts these commands into meaningful methods, hiding the complexity from test scripts.
Why designed this way?
Page class design was created to solve the problem of duplicated and fragile test code. Early Selenium tests mixed page details with test logic, making maintenance hard. Separating page interactions into classes follows software design principles like encapsulation and single responsibility, improving test quality and scalability.
┌───────────────┐       ┌───────────────┐
│   Test Script │──────▶│  Page Class   │
│ (calls methods)│       │ (locators +   │
└───────────────┘       │  actions)     │
                        └──────┬────────┘
                               │
                               ▼
                      ┌─────────────────┐
                      │  WebDriver API  │
                      │ (browser control)│
                      └─────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think page classes should contain test assertions? Commit yes or no.
Common Belief:Page classes should include assertions to verify page state.
Tap to reveal reality
Reality:Page classes only handle interactions; assertions belong in test scripts.
Why it matters:Mixing assertions into page classes makes code less reusable and harder to maintain.
Quick: Do you think locating elements once in constructor is always best? Commit yes or no.
Common Belief:Finding elements once in the constructor is best for performance.
Tap to reveal reality
Reality:Locating elements fresh in each method avoids stale element errors after page changes.
Why it matters:Failing to refresh elements causes flaky tests that break unpredictably.
Quick: Do you think each page class should create its own WebDriver instance? Commit yes or no.
Common Belief:Each page class should create its own WebDriver to be independent.
Tap to reveal reality
Reality:All page classes share the same WebDriver instance to control one browser session.
Why it matters:Multiple WebDriver instances cause conflicts and resource waste.
Quick: Do you think exposing locators publicly is good practice? Commit yes or no.
Common Belief:Making locators public helps tests access elements directly.
Tap to reveal reality
Reality:Locators should be private to protect encapsulation and allow changes without breaking tests.
Why it matters:Public locators lead to fragile tests tightly coupled to page structure.
Expert Zone
1
Page classes can implement wait strategies internally to handle dynamic page loading, improving test stability.
2
Using interfaces or abstract base classes for page classes enables flexible test design and easier maintenance.
3
Combining page classes with the Factory pattern allows dynamic page object creation based on runtime conditions.
When NOT to use
Page class design is less useful for very simple or one-off tests where overhead is unnecessary. For API testing or non-UI tests, other patterns like service objects or direct calls are better.
Production Patterns
In real projects, page classes are combined with test frameworks like TestNG or JUnit, use dependency injection for WebDriver, and integrate with reporting tools. They often include helper methods for common flows and handle exceptions gracefully.
Connections
Object-Oriented Programming
Page class design builds on OOP principles like encapsulation and abstraction.
Understanding OOP helps grasp why page classes hide locators and expose only methods.
Design Patterns - Factory Pattern
Page classes can be created dynamically using the Factory pattern to manage different page states.
Knowing design patterns improves page class flexibility and scalability.
Human-Computer Interaction (HCI)
Page class design models user interactions with web pages programmatically.
Understanding HCI concepts helps design page classes that mimic real user behavior accurately.
Common Pitfalls
#1Locating elements once in constructor causes stale element errors after page reload.
Wrong approach:public LoginPage(WebDriver driver) { this.driver = driver; usernameField = driver.findElement(By.id("username")); } public void enterUsername(String user) { usernameField.sendKeys(user); }
Correct approach:private By usernameLocator = By.id("username"); public void enterUsername(String user) { driver.findElement(usernameLocator).sendKeys(user); }
Root cause:Misunderstanding that web elements can become invalid after page changes.
#2Exposing locators publicly leads to fragile tests tightly coupled to page structure.
Wrong approach:public WebElement usernameField = driver.findElement(By.id("username"));
Correct approach:private By usernameLocator = By.id("username"); public void enterUsername(String user) { driver.findElement(usernameLocator).sendKeys(user); }
Root cause:Not applying encapsulation principles in test code.
#3Creating new WebDriver instances in each page class causes conflicts and resource waste.
Wrong approach:public LoginPage() { this.driver = new ChromeDriver(); }
Correct approach:public LoginPage(WebDriver driver) { this.driver = driver; }
Root cause:Not understanding WebDriver lifecycle and shared browser session.
Key Takeaways
Page class design organizes web page interactions into classes with locators and methods, improving test clarity and reuse.
Encapsulation hides page details from tests, making tests less fragile and easier to maintain.
Passing a shared WebDriver instance to page classes ensures consistent browser control and resource efficiency.
Locating elements fresh in methods prevents stale element errors common in dynamic web pages.
Modeling page navigation by returning page objects from methods helps write fluent and readable test flows.