Skip to main content

pom-generator 1.2.0

Python Version License Status

📦 PyPI: https://pypi.org/project/pom-generator/
🌐 GitHub: https://github.com/khaledlim/pom-generator

pom-generator is a Python/Playwright engine for generating and maintaining YAML Page Object Models (POMs) from web applications.

It provides UI scanning, page and element models, robust locator generation, YAML read/write, validation, diff, update, statistics, export, and a command-line interface.

pom-generator is framework-neutral from a test-automation point of view: it has no dependency on a test-automation framework and exposes only Python/Playwright generation and maintenance capabilities.

Authors: Khaled Limem / Olivier RENAULT


Purpose

The primary objective of pom-generator is to build a reusable pom.yml describing an application's pages, elements, locators, and navigation.

A generated POM can then be consumed by any compatible Python tool or test-automation layer without duplicating page discovery or locator-selection logic.

The package owns the POM generation and maintenance logic:

  • browser-driven page discovery with Playwright;
  • DOM extraction and page scanning;
  • Page/Element data models;
  • locator candidate generation and robustness ranking;
  • YAML persistence and incremental update;
  • validation and comparison of POM files;
  • statistics and export;
  • optional Python authentication provider;
  • reusable Python API;
  • CLI orchestration.

Main features

POM generation

Three generation modes are available:

  • csv: scan a controlled list of pages from a CSV file;
  • crawl: browse internal application links automatically and scan discovered pages;
  • record: navigate manually and decide interactively which pages to capture.

All modes write to a single YAML POM file.

When an existing --pom-file is reused, pages already present are preserved and updated according to the current upsert rules instead of resetting the whole file.

Robust locators

Locator candidates are generated in semantic priority order:

  1. test attributes: data-testid, data-test, data-qa, data-cy;
  2. id;
  3. ARIA role + accessible name;
  4. aria-label;
  5. name;
  6. stable href for links;
  7. placeholder;
  8. title;
  9. exact-text XPath;
  10. stable CSS class as a last-resort fallback.

When the live DOM provides match counts, candidates known to be unique are promoted ahead of candidates with unknown uniqueness. Known ambiguous candidates are kept only as late fallbacks, and candidates known to match no element are discarded.

Generated or styling-oriented CSS classes are deliberately deprioritized or rejected when they appear unstable.

POM maintenance

In addition to generation, the CLI supports:

  • validate: verify POM structure and data integrity;
  • diff: compare two POM files and generate a unified diff;
  • update: merge pages from one POM into another;
  • statistics: compute POM metrics;
  • export: export POM data to JSON or flattened CSV.

Requirements

  • Python 3.9 or newer;
  • PyYAML 6 or newer;
  • Playwright 1.45 or newer.

The package itself has no dependency on a test-automation framework.


Installation

From a source checkout

python -m pip install .
python -m playwright install chromium

From PyPI

Once published on PyPI:

python -m pip install pom-generator
python -m playwright install chromium

Check the installation:

pom-generator --version
pom-generator --help

CLI overview

The general syntax is:

pom-generator --action <action> [options]

Available actions:

generate      Generate or enrich a POM
validate      Validate a POM
diff          Compare two POMs
update        Merge another POM into the target POM
statistics    Compute statistics about a POM
export        Export POM data

generate is the default action, so --action generate may be omitted.


Generate a POM

Record mode

Record mode opens the application in Playwright and lets the user navigate freely.

pom-generator \
  --mode record \
  --url "https://example.test/" \
  --pom-file ./pom/example.yml \
  --app-name example

Equivalent explicit form:

pom-generator \
  --action generate \
  --mode record \
  --url "https://example.test/" \
  --pom-file ./pom/example.yml \
  --app-name example

The interactive dialog provides these actions:

  • Scan: capture the current page;
  • Wait: temporarily close the dialog, return focus to the browser, wait, then show the dialog again;
  • Skip: do not capture the current page;
  • Quit: stop the session and save safely.

You can also stop execution with Ctrl+C; the current POM is saved before the browser is closed cleanly.


Crawl mode

Crawl mode discovers internal pages from the configured application and scans them automatically.

pom-generator \
  --mode crawl \
  --url "https://example.test/" \
  --pom-file ./pom/example.yml \
  --max-pages 30

Useful options:

--max-pages 30
--crawl-settle-timeout 3
--headless
--executable-path /path/to/chrome

--max-pages limits the number of pages visited during the crawl.

--crawl-settle-timeout controls how long the engine waits for page readiness before scanning elements.


CSV mode

CSV mode scans a predefined list of pages.

pom-generator \
  --mode csv \
  --url "https://example.test/" \
  --csv ./pages.csv \
  --pom-file ./pom/example.yml

CSV format

The CSV file uses a header followed by name,url rows:

name,url
login,/login
home,/home
customer,/customer
orders,/orders

Relative URLs are resolved against --url.

Interactive CSV mode

For applications that need manual intervention or stabilization between pages:

pom-generator \
  --mode csv \
  --url "https://example.test/" \
  --csv ./pages.csv \
  --pom-file ./pom/example.yml \
  --csv-interactive

An automatic timeout can be added:

--csv-interactive-timeout 10

A delay between pages can also be configured:

--csv-transition-delay 2

Authentication provider

pom-generator can execute a Python login provider before POM generation.

Example:

pom-generator \
  --mode record \
  --url "https://example.test/" \
  --login ./login.py \
  --pom-file ./pom/example.yml

The provider receives these environment variables:

POM_LOGIN_URL
POM_STORAGE_STATE
POM_EXECUTABLE_PATH

The login script must write a Playwright storage-state JSON file to the path contained in POM_STORAGE_STATE.

Minimal example:

import os
from playwright.sync_api import sync_playwright

url = os.environ["POM_LOGIN_URL"]
storage_state = os.environ["POM_STORAGE_STATE"]
executable_path = os.environ.get("POM_EXECUTABLE_PATH") or None

with sync_playwright() as p:
    launch_options = {"headless": False}
    if executable_path:
        launch_options["executable_path"] = executable_path

    browser = p.chromium.launch(**launch_options)
    context = browser.new_context()
    page = context.new_page()
    page.goto(url)

    # Perform authentication here.

    context.storage_state(path=storage_state)
    browser.close()

The default login timeout is 300 seconds and can be changed with:

--login-timeout 600

Browser options

Headless mode

pom-generator \
  --mode crawl \
  --url "https://example.test/" \
  --headless

Use a specific Chrome/Chromium executable

pom-generator \
  --mode record \
  --url "https://example.test/" \
  --executable-path "/path/to/chrome"

Incognito mode

pom-generator \
  --mode record \
  --url "https://example.test/" \
  --incognito

Validate a POM

Validate the POM structure and data integrity:

pom-generator \
  --action validate \
  --pom-file ./pom/example.yml

Validation checks include:

  • required root sections;
  • page integrity;
  • page URLs and element collections;
  • locator structure (type, value);
  • navigation references to existing pages.

The default output format is text.

Generate JSON output:

pom-generator \
  --action validate \
  --pom-file ./pom/example.yml \
  --validate-format json \
  --validate-output ./reports/pom-validation.json

Compare two POMs

Generate a unified diff between two POM files:

pom-generator \
  --action diff \
  --pom-file ./pom/current.yml \
  --against ./pom/reference.yml

By default, only a summary is printed in the terminal.

Display the full patch:

--print-diff

Specify the diff output file:

--diff-output ./reports/pom.diff

The diff uses standard unified-diff markers:

- removed content
+ added content

If there are no differences, no diff file is created.

For richer .diff visualization in VS Code, a diff-viewer extension can be used.


Update / merge a POM

Merge pages from another POM into the target POM:

pom-generator \
  --action update \
  --pom-file ./pom/current.yml \
  --source-pom ./pom/incoming.yml

The update process merges the source pages and rebuilds navigation information.


Statistics

Compute POM metrics:

pom-generator \
  --action statistics \
  --pom-file ./pom/example.yml

Statistics include information such as:

  • page count;
  • element count;
  • locator count;
  • element types;
  • top pages.

Supported formats:

text
json
html

Example HTML report:

pom-generator \
  --action statistics \
  --pom-file ./pom/example.yml \
  --stats-format html \
  --stats-output ./reports/pom-statistics.html

Example JSON report:

pom-generator \
  --action statistics \
  --pom-file ./pom/example.yml \
  --stats-format json \
  --stats-output ./reports/pom-statistics.json

If --stats-format is omitted, text statistics are printed directly to the console.


Export

Export the full POM as JSON:

pom-generator \
  --action export \
  --pom-file ./pom/example.yml \
  --export-format json \
  --export-output ./exports/example.json

Export a flattened element list as CSV:

pom-generator \
  --action export \
  --pom-file ./pom/example.yml \
  --export-format csv \
  --export-output ./exports/example-elements.csv

Supported export formats:

json
csv

POM structure

A generated POM contains four main sections:

application
runtime
pom
navigation

Simplified example:

application:
  name: example
  module: frontoffice
  version: 1.2.3
  context_path: /
  base_url: https://example.test/

runtime:
  environment: qa
  browser: chrome
  generated_by: pom-generator
  generated_at: '2026-09-08T12:00:00'
  generator_version: 1.2.0

pom:
  format_version: '2.0'
  description: POM for example
  generated_at: '2026-09-08T12:00:00'
  generation_notes:
    - Generated automatically from UI scan (crawl/csv/record mode).
    - Locator list is ordered by robustness.
    - Review and enrich business-critical flows after baseline generation.
  pages:
    login:
      name: login
      url: https://example.test/login
      title: Login
      entry_type: page
      elements:
        username_input:
          type: input
          locators:
            - type: css
              value: '[data-testid="username"]'
        submit_button:
          type: button
          locators:
            - type: role
              value: 'role=button[name="Sign in"]'

navigation:
  - name: Login
    level: 1
    entry_type: menu_group
    children:
      - name: Login
        level: 2
        entry_type: page
        url: https://example.test/login
        page: login

Metadata such as application.module, application.version, application.context_path and runtime information are populated from the application/URL when available.


Locator strategy

Each element can contain several locators:

username_input:
  type: input
  locators:
    - type: css
      value: '[data-testid="username"]'
    - type: id
      value: 'id=username'
    - type: css
      value: '[name="username"]'

The list is ordered by robustness. Consumers should normally use the first compatible locator rather than selecting a strategy independently from the POM ranking.

The locator engine also:

  • removes duplicates;
  • escapes attribute values safely;
  • generates safe XPath literals, including text containing quotes;
  • avoids known generated CSS class patterns;
  • promotes locators known to be unique in the current DOM;
  • retains ambiguous candidates only as fallback when useful.

Incremental generation

Reusing the same --pom-file across several generation runs is supported.

Example:

pom-generator \
  --mode csv \
  --url "https://example.test/" \
  --csv ./public-pages.csv \
  --pom-file ./pom/application.yml

pom-generator \
  --mode record \
  --url "https://example.test/" \
  --pom-file ./pom/application.yml

Existing POM sections are loaded before new pages are processed. Pages are updated according to URL/page identity rules, and navigation is rebuilt after relevant changes.

This makes it possible to build the same POM progressively using different generation modes.


Python API

The main engine components are exported directly by the package:

from POMGenerator import (
    PomGenerator,
    PageScanner,
    LocatorBuilder,
    YamlManager,
)

This allows Python applications to reuse the same generation rules as the CLI instead of implementing another POM format or locator strategy.

Example imports:

from pathlib import Path

from POMGenerator import LocatorBuilder, YamlManager

Build locator candidates directly:

raw_element = {
    "tag": "button",
    "data-testid": "save-button",
    "role": "button",
    "accessible_name": "Save",
}

locators = LocatorBuilder.build_priority_list(raw_element)
print(locators)

The exact construction of PomGenerator depends on the browser lifecycle and the generation flow being embedded. For standard usage, the CLI remains the simplest entry point.


Package layout

src/POMGenerator/
├── __init__.py
├── __main__.py
├── browser_manager.py
├── cli.py
├── dialogs.py
├── dom_extractor.py
├── generator.py
├── locator_builder.py
├── login_runner.py
├── page_scanner.py
├── pom_diff.py
├── pom_export.py
├── pom_statistics.py
├── pom_update.py
├── pom_validate.py
├── yaml_manager.py
├── models/
│   ├── element.py
│   └── page.py
└── modes/
    ├── crawl_mode.py
    ├── csv_mode.py
    └── record_mode.py

Main responsibilities:

Module Responsibility
browser_manager.py Playwright browser lifecycle and navigation
dom_extractor.py Browser-side DOM extraction
locator_builder.py Locator candidates, escaping and robustness ranking
page_scanner.py Convert the current DOM into Page/Element models
generator.py Generation orchestration
yaml_manager.py YAML persistence, page upsert and navigation rebuild
pom_validate.py POM structural validation
pom_diff.py Unified comparison between POM files
pom_update.py POM merge/update
pom_statistics.py Metrics and text/JSON/HTML reports
pom_export.py JSON and flattened CSV export
login_runner.py Optional Python authentication provider
modes/ CSV, crawl and record generation workflows
models/ Page and Element data models
cli.py Command-line entry point

Development

Install the project in editable mode:

python -m pip install -e .
python -m playwright install chromium

Run the tests:

python -m unittest discover -s tests -p "test_*.py"

Build the package:

python -m build

The generated wheel and source archive are written to dist/.


Versioning and compatibility

Package version:

1.2.0

Current YAML POM format:

2.0

The POM format and public Python API should evolve compatibly within a minor release line whenever possible.

Any incompatible change to the YAML schema should be documented explicitly because generated POM files are intended to remain reusable independently from the generation session that created them.


Quick reference

Generate interactively:

pom-generator --mode record --url https://example.test --pom-file pom.yml

Crawl:

pom-generator --mode crawl --url https://example.test --pom-file pom.yml

Generate from CSV:

pom-generator --mode csv --url https://example.test --csv pages.csv --pom-file pom.yml

Validate:

pom-generator --action validate --pom-file pom.yml

Diff:

pom-generator --action diff --pom-file pom.yml --against baseline.yml --print-diff

Update:

pom-generator --action update --pom-file pom.yml --source-pom incoming.yml

Statistics:

pom-generator --action statistics --pom-file pom.yml --stats-format html

Export:

pom-generator --action export --pom-file pom.yml --export-format json

Release files for pom-generator 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pom-generator 1.2.0
File Size Uploaded
pom_generator-1.2.0.tar.gz 51.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pom-generator 1.2.0
File Interpreter ABI Platform
pom_generator-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 103.9 kB

Release files / pom_generator-1.2.0.tar.gz

Download URL pom_generator-1.2.0.tar.gz
Size 51.7 kB
Tags Source
SHA-256 checksum
How to use checksums
45c5e72d73759975ed2a840498382d694310a92e917e4d9916ed1ea290599937
BLAKE2b-256 checksum
How to use checksums
cf0904ca0eacc630738f96f8fb1e9a985f9368df9ba875bec84c48b46f6d9a4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.9

Release files / pom_generator-1.2.0-py3-none-any.whl

Download URL pom_generator-1.2.0-py3-none-any.whl
Size 52.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
effc0aaf379adf8067eb539ae5cd0918d4d10e89859fa8c46d839425ea077b12
BLAKE2b-256 checksum
How to use checksums
b0ceed94a4ae59e141af3e0bfc3fcfaf1938c2df7c1bf3e5f2d3d75575b6b8a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.9

Release history Release notifications | RSS feed

This release

1.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page