Back to Test Automation
2025-12-198 min read

Page Object Model

Learn Page Object Model step by step with clear examples and exercises.

Title: Page Object Model - A full guide to Test Automation with JavaScript

Why This Matters

In test automation, efficiency and accuracy are paramount. The Page Object Model (POM) is a design pattern that simplifies this process by promoting code reusability, maintainability, and readability. By mastering POM, you'll be better prepared to write robust tests for web applications using popular testing frameworks such as Selenium, Cypress, and Playwright.

Prerequisites

To follow this lesson, you should have a basic understanding of:

  1. JavaScript programming language
  2. HTML and CSS for web application structure
  3. Familiarity with one or more test automation frameworks (Selenium, Cypress, Playwright)
  4. Basic concepts of Object-Oriented Programming (OOP)
  5. Understanding of asynchronous JavaScript and promises
  6. Familiarity with web drivers like WebDriverJS, Puppeteer, or Nightwatch for executing tests in headless browsers
  7. Knowledge of Git for version control and collaboration
  8. Basic understanding of browser development tools (e.g., Chrome DevTools, Firefox Developer Edition)
  9. Familiarity with a code editor like Visual Studio Code, Atom, or Sublime Text
  10. Understanding of REST APIs and HTTP requests for testing web applications that rely on backend services

Core Concept

The Page Object Model is a design pattern that isolates the page's UI elements and encapsulates them into reusable functions and objects. This separation allows for easier maintenance, faster test execution, and more readable code.

Key Components of POM:

  1. Page Class: Represents a specific webpage or part of a webpage. Each page class contains methods that interact with the UI elements on that particular page.
  2. Base Class: Contains common functions used across multiple pages, such as navigating to URLs, logging in, or closing the browser.
  3. Page Factory: A factory class responsible for creating and managing instances of page classes. It simplifies the process of finding UI elements by using locators and abstracting them into methods.
  4. Helper Functions: Additional utility functions used across multiple pages or tests to perform common tasks like waiting for elements, handling cookies, or logging test results.
  5. Test Scripts: Contain the actual test cases that exercise the application under test. They instantiate page classes and call their methods to interact with the UI elements.
  6. Configuration Files: Store environment-specific settings, such as base URLs, user credentials, or browser configurations. These files can be read by tests and page classes to customize the behavior based on the current environment.
  7. Test Runner: A script that executes test scripts in a specific order, manages test results, and provides features for running tests in parallel or with different configurations.

Worked Example

Let's create a simple example using Selenium WebDriver with JavaScript to illustrate POM in action.

// Base class for common functionality
class Base {
constructor() {
this.driver = null;
}

init(browser, url) {
const options = {
...browserOptions,
url: url
};
this.driver = new webdriver.Builder().withCapabilities(options).build();
}

closeBrowser() {
this.driver.quit();
}
}

// Page class for a sample webpage
class SamplePage extends Base {
constructor() {
super();
this.sampleElement = 'css=#sample-element';
}

getSampleElementText() {
return this.driver.findElement(webdriver.By.cssSelector(this.sampleElement)).then((elem) => {
return elem.getText();
});
}
}

// Test script
const samplePage = new SamplePage();
const browserOptions = {
'browser': 'chrome',
'version': 'latest'
};
samplePage.init(browserOptions, 'http://example.com');
samplePage.getSampleElementText().then((text) => {
console.log(text);
});
samplePage.closeBrowser();

In this example, we have a Base class that contains common methods like initializing the WebDriver and closing the browser. The SamplePage extends the Base class and represents our sample webpage. It has a method getSampleElementText() that retrieves the text of a specific UI element on the page using Selenium's findElement() function.

Common Mistakes

  1. Not encapsulating all UI elements: Make sure to include every UI element you interact with in your page classes. This promotes code reusability and maintainability.
  2. Hardcoding locators: Avoid hardcoding locators directly into test methods. Instead, use a factory class or helper functions to abstract locators and make them easier to manage.
  3. Ignoring DRY (Don't Repeat Yourself) principle: If you find yourself writing the same code across multiple tests or page classes, consider encapsulating that logic in a base class or common function.
  4. Not using meaningful names for elements and methods: Clearly name your UI elements and methods to make your code easier to understand and maintain.
  5. Neglecting test data management: Ensure you have a robust system for managing test data, such as reading from configuration files or databases, to avoid hardcoding test data in your tests.
  6. Not handling asynchronous actions correctly: When dealing with asynchronous actions like waiting for elements or making API calls, make sure to use promises and handle them properly to prevent test failures due to timing issues.
  7. Ignoring browser-specific issues: Some browsers may have quirks that can affect your tests. Make sure to test your automation scripts across multiple browsers to ensure compatibility.
  8. Not logging or reporting test results: Logging and reporting test results is crucial for understanding the success or failure of your tests, as well as identifying any issues that may arise during execution.
  9. Using fragile locators: Fragile locators are prone to breakage when the underlying HTML structure changes. Use robust locators like CSS selectors or XPath expressions that can withstand minor changes in the UI.
  10. Not using waits and timeouts appropriately: Properly use waits and timeouts to ensure your tests don't fail due to timing issues, but also avoid excessive waiting that could slow down test execution.
  11. Ignoring performance considerations: Optimize your test code by minimizing the number of DOM queries, using efficient locators, and implementing caching strategies for frequently used elements or data.

Practice Questions

  1. How can you create a page class for a login page using POM?
  2. What are some best practices for naming UI elements and methods in POM?
  3. Why is it important to abstract locators using a factory class or helper functions in POM?
  4. How would you handle dynamic UI elements (e.g., elements that appear based on user interaction) in your POM design?
  5. What are some common pitfalls to avoid when implementing POM in test automation?
  6. How can you handle asynchronous actions correctly in POM?
  7. How would you ensure compatibility across multiple browsers using POM?
  8. What tools or libraries help with logging and reporting test results in POM?
  9. How can you write maintainable tests when dealing with complex web applications using POM?
  10. How can you handle browser-specific issues when implementing POM for cross-browser testing?
  11. What are some strategies to optimize the performance of your POM-based test automation scripts?
  12. How would you implement a mechanism for waiting for dynamic UI elements in POM?
  13. Why is it important to use robust locators in POM and how can you achieve this?

FAQ

  1. Why should I use POM for test automation?
  • POM promotes code reusability, maintainability, and readability. It simplifies the process of finding UI elements and makes it easier to write robust tests.
  1. How do I decide which elements to encapsulate in my page classes?
  • Encapsulate all UI elements you interact with in your test methods. This includes buttons, text fields, dropdowns, etc.
  1. Can I use POM with multiple testing frameworks (e.g., Selenium, Cypress, Playwright)?
  • Yes, the Page Object Model is a design pattern and can be used with various test automation frameworks. The implementation may differ slightly depending on the framework you're using.
  1. What are some tools or libraries that help manage test data in POM?
  • Tools like TestNG (Java), Allure (multiple languages), and Jest (JavaScript) provide features for managing test data, such as reading from configuration files or databases.
  1. How can I handle dynamic UI elements using POM?
  • For dynamic UI elements, you can use JavaScript to wait for their appearance or implement a mechanism that refreshes the page after each test run to ensure the element is available during the test execution.
  1. What are some common pitfalls to avoid when implementing POM in test automation?
  • Common pitfalls include not encapsulating all UI elements, hardcoding locators, ignoring DRY principle, neglecting test data management, and not handling asynchronous actions correctly.
  1. How can I handle asynchronous actions correctly in POM?
  • Handle asynchronous actions using promises and ensure that your tests wait for the desired element or action to complete before proceeding.
  1. How would you ensure compatibility across multiple browsers using POM?
  • Ensure compatibility by testing your automation scripts across multiple browsers and handling browser-specific issues in your page classes or base class.
  1. What tools or libraries help with logging and reporting test results in POM?
  • Tools like Mochawesome (JavaScript), Allure (multiple languages), and TestNG (Java) provide features for logging and reporting test results.
  1. How can you write maintainable tests when dealing with complex web applications using POM?
  • Write maintainable tests by organizing your page classes, base class, and helper functions logically, using meaningful names, and encapsulating all UI elements and common functionality.
  1. How can you handle browser-specific issues when implementing POM for cross-browser testing?
  • Handle browser-specific issues by using conditional statements in your page classes or base class to execute different code based on the current browser being used. You may also consider using a testing framework that supports multiple browsers out of the box, such as Cypress.
  1. What are some strategies to optimize the performance of your POM-based test automation scripts?
  • Optimize your test code by minimizing the number of DOM queries, using efficient locators, and implementing caching strategies for frequently used elements or data.
  1. How would you implement a mechanism for waiting for dynamic UI elements in POM?
  • Implement a mechanism to wait for dynamic UI elements by using JavaScript's setTimeout() function or WebDriver's wait() method with explicit or implicit wait strategies.
  1. Why is it important to use robust locators in POM and how can you achieve this?
  • Robust locators are less prone to breakage when the underlying HTML structure changes. Use CSS selectors, XPath expressions, or other stable locator strategies to ensure your tests remain functional even with UI updates.
Page Object Model | Test Automation | XQA Learn