How to Generate Page Object Models Automatically

📋 Table of Contents

What is Page Object Model (POM)?

The Page Object Model is a design pattern that creates an object repository for web elements. Each web page has a corresponding Page Object class that encapsulates the page structure and provides methods for interacting with it.

Simple Example:

// Instead of this in your test:
await page.locator('#email').fill('test@example.com');
await page.locator('#password').fill('password123');
await page.locator('#submit').click();

// You write this:
await loginPage.login('test@example.com', 'password123');

The Page Object hides the implementation details and provides a clean, reusable interface for your tests.

Why Use Page Object Model?

✅ Benefits:

Without POM:

// test1.spec.js
await page.locator('#search-input').fill('laptop');
await page.locator('.search-button').click();

// test2.spec.js
await page.locator('#search-input').fill('phone');
await page.locator('.search-button').click();

// If locator changes, update in 50+ places! 😱

With POM:

// Both tests use:
await searchPage.search('laptop');
await searchPage.search('phone');

// If locator changes, update in 1 place! ✅

The Problem with Manual POM Creation

Creating Page Objects manually is time-consuming and error-prone:

❌ Manual Process:

  1. Open the page in browser
  2. Inspect each element (30-50 per page)
  3. Choose the best locator strategy
  4. Write the locator in your Page Object class
  5. Create getter methods for each element
  6. Write action methods (login, search, etc.)
  7. Repeat for every page in your app

⏱️ Time Investment

Manual POM creation takes 2-4 hours per page. For a 20-page application, that's 40-80 hours of repetitive work!

Common Issues:

Automatic POM Generation Solution

Modern tools can automatically scan your pages and generate complete Page Object classes in seconds.

How It Works:

  1. Scan Page - Tool analyzes all interactive elements
  2. Smart Locators - Chooses best strategy for each element
  3. Quality Scoring - Rates locator stability (0-10)
  4. Generate Code - Creates POM class in your language
  5. Export & Use - Copy into your test project

⚡ Speed Comparison

Manual: 2-4 hours per page
Automatic: 30 seconds per page
Time Saved: 95-99%

Step-by-Step: Using LocatorLab

Let's walk through generating a Page Object for a login page using LocatorLab.

Step 1: Navigate to Your Page

https://example.com/login

Step 2: Open LocatorLab Sidepanel

Click the LocatorLab extension icon and enable Side Panel mode.

Step 3: Scan the Page

Click "Scan Page Elements" button or press Alt+Shift+S

LocatorLab will:

Step 4: Review Scanned Elements

The scanner found:

Step 5: Export Page Object Model

Click "Export POM" and choose your language:

LocatorLab generates a complete, production-ready Page Object class!

Generated JavaScript POM Example (Playwright)

Auto-Generated LoginPage.js:

// LoginPage.js - Generated by LocatorLab
// Date: 2026-01-14
// Page: https://example.com/login

class LoginPage {
  constructor(page) {
    this.page = page;

    // Locators (Quality Score: 10/10)
    this.emailInput = page.getByTestId('email-input');

    // Locators (Quality Score: 10/10)
    this.passwordInput = page.getByTestId('password-input');

    // Locators (Quality Score: 9/10)
    this.submitButton = page.getByRole('button', { name: 'Sign In' });

    // Locators (Quality Score: 8/10)
    this.forgotPasswordLink = page.getByText('Forgot password?');

    // Locators (Quality Score: 8/10)
    this.signUpLink = page.getByRole('link', { name: 'Sign up' });
  }

  // Navigate to login page
  async goto() {
    await this.page.goto('https://example.com/login');
  }

  // Fill email field
  async fillEmail(email) {
    await this.emailInput.fill(email);
  }

  // Fill password field
  async fillPassword(password) {
    await this.passwordInput.fill(password);
  }

  // Click submit button
  async clickSubmit() {
    await this.submitButton.click();
  }

  // Complete login action
  async login(email, password) {
    await this.fillEmail(email);
    await this.fillPassword(password);
    await this.clickSubmit();
  }

  // Click forgot password link
  async clickForgotPassword() {
    await this.forgotPasswordLink.click();
  }

  // Click sign up link
  async clickSignUp() {
    await this.signUpLink.click();
  }
}

module.exports = { LoginPage };

Using the Generated Page Object:

// login.spec.js
import { test, expect } from '@playwright/test';
import { LoginPage } from './pages/LoginPage';

test('user can login successfully', async ({ page }) => {
  const loginPage = new LoginPage(page);

  await loginPage.goto();
  await loginPage.login('test@example.com', 'SecurePass123');

  await expect(page).toHaveURL(/.*dashboard/);
});

💡 Notice

LocatorLab chose the best locator strategies automatically:

Generated Python POM Example (Selenium)

Auto-Generated login_page.py:

# login_page.py - Generated by LocatorLab
# Date: 2026-01-14
# Page: https://example.com/login

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:
    # URL
    URL = "https://example.com/login"

    # Locators (Quality Score: 10/10)
    EMAIL_INPUT = (By.CSS_SELECTOR, '[data-testid="email-input"]')

    # Locators (Quality Score: 10/10)
    PASSWORD_INPUT = (By.CSS_SELECTOR, '[data-testid="password-input"]')

    # Locators (Quality Score: 9/10)
    SUBMIT_BUTTON = (By.XPATH, '//button[text()="Sign In"]')

    # Locators (Quality Score: 8/10)
    FORGOT_PASSWORD_LINK = (By.LINK_TEXT, 'Forgot password?')

    # Locators (Quality Score: 8/10)
    SIGN_UP_LINK = (By.LINK_TEXT, 'Sign up')

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

    def goto(self):
        """Navigate to login page"""
        self.driver.get(self.URL)

    def fill_email(self, email):
        """Fill email field"""
        element = self.wait.until(
            EC.element_to_be_clickable(self.EMAIL_INPUT)
        )
        element.clear()
        element.send_keys(email)

    def fill_password(self, password):
        """Fill password field"""
        element = self.wait.until(
            EC.element_to_be_clickable(self.PASSWORD_INPUT)
        )
        element.clear()
        element.send_keys(password)

    def click_submit(self):
        """Click submit button"""
        element = self.wait.until(
            EC.element_to_be_clickable(self.SUBMIT_BUTTON)
        )
        element.click()

    def login(self, email, password):
        """Complete login action"""
        self.fill_email(email)
        self.fill_password(password)
        self.click_submit()

    def click_forgot_password(self):
        """Click forgot password link"""
        element = self.wait.until(
            EC.element_to_be_clickable(self.FORGOT_PASSWORD_LINK)
        )
        element.click()

    def click_sign_up(self):
        """Click sign up link"""
        element = self.wait.until(
            EC.element_to_be_clickable(self.SIGN_UP_LINK)
        )
        element.click()

Using the Python Page Object:

# test_login.py
import pytest
from selenium import webdriver
from pages.login_page import LoginPage

def test_user_can_login():
    driver = webdriver.Chrome()
    login_page = LoginPage(driver)

    login_page.goto()
    login_page.login('test@example.com', 'SecurePass123')

    assert '/dashboard' in driver.current_url

    driver.quit()

Generated Java POM Example (Selenium)

Auto-Generated LoginPage.java:

// LoginPage.java - Generated by LocatorLab
// Date: 2026-01-14
// Page: https://example.com/login

package pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;

public class LoginPage {
    private WebDriver driver;
    private WebDriverWait wait;

    // URL
    private static final String URL = "https://example.com/login";

    // Locators (Quality Score: 10/10)
    private By emailInput = By.cssSelector("[data-testid='email-input']");

    // Locators (Quality Score: 10/10)
    private By passwordInput = By.cssSelector("[data-testid='password-input']");

    // Locators (Quality Score: 9/10)
    private By submitButton = By.xpath("//button[text()='Sign In']");

    // Locators (Quality Score: 8/10)
    private By forgotPasswordLink = By.linkText("Forgot password?");

    // Locators (Quality Score: 8/10)
    private By signUpLink = By.linkText("Sign up");

    public LoginPage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    public void goTo() {
        driver.get(URL);
    }

    public void fillEmail(String email) {
        WebElement element = wait.until(
            ExpectedConditions.elementToBeClickable(emailInput)
        );
        element.clear();
        element.sendKeys(email);
    }

    public void fillPassword(String password) {
        WebElement element = wait.until(
            ExpectedConditions.elementToBeClickable(passwordInput)
        );
        element.clear();
        element.sendKeys(password);
    }

    public void clickSubmit() {
        WebElement element = wait.until(
            ExpectedConditions.elementToBeClickable(submitButton)
        );
        element.click();
    }

    public void login(String email, String password) {
        fillEmail(email);
        fillPassword(password);
        clickSubmit();
    }

    public void clickForgotPassword() {
        WebElement element = wait.until(
            ExpectedConditions.elementToBeClickable(forgotPasswordLink)
        );
        element.click();
    }

    public void clickSignUp() {
        WebElement element = wait.until(
            ExpectedConditions.elementToBeClickable(signUpLink)
        );
        element.click();
    }
}

Best Practices for Generated POMs

✅ DO:

❌ DON'T:

Enhance Generated POMs:

// Add validation methods
async isEmailErrorVisible() {
  return await this.emailError.isVisible();
}

// Add custom wait conditions
async waitForLoginComplete() {
  await this.page.waitForURL(/.*dashboard/);
}

// Add business logic
async loginAsAdmin() {
  await this.login('admin@example.com', process.env.ADMIN_PASSWORD);
}

Time Savings Calculator

Let's calculate the actual time savings:

Example Project: E-commerce Site

Task Manual Automated Saved
Home Page (15 elements) 2 hours 30 sec 1h 59m
Product Page (25 elements) 3 hours 45 sec 2h 59m
Cart Page (12 elements) 1.5 hours 25 sec 1h 29m
Checkout (30 elements) 4 hours 1 min 3h 59m
Login/Signup (8 elements) 1 hour 20 sec 59m
TOTAL (5 pages) 11.5 hours 3 minutes 11h 27m (99% saved!)

💰 ROI Calculation

Assumptions: QA Engineer salary = $60/hour
Cost of Manual POM: 11.5 hours × $60 = $690
Cost with LocatorLab: 3 minutes × $60 = $3
💵 Money Saved: $687 per project

Conclusion: Stop Writing POMs Manually

Automatic Page Object Model generation is a game-changer for test automation teams:

The Modern Workflow:

  1. Scan page with LocatorLab (30 seconds)
  2. Review generated locators
  3. Export POM in your language
  4. Copy into your project
  5. Enhance with business logic
  6. Start writing tests immediately

🚀 Try LocatorLab Today

Stop wasting hours creating Page Objects manually. LocatorLab scans your pages, generates intelligent locators with quality scores, and exports production-ready POM classes in JavaScript, Python, or Java.

Install Free Chrome Extension →

Remember: The best code is the code you don't have to write.

Found this helpful? Share it!