Metadata-Version: 2.4
Name: rf-pomlibrary
Version: 1.2.0
Summary: Generic Robot Framework keywords for POMGenerator YAML POMs
Author: Khaled Limem, Olivier RENAULT
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: License
Requires-Dist: pom-generator==1.2.0
Requires-Dist: robotframework>=6.1
Provides-Extra: browser
Requires-Dist: robotframework-browser>=18.6.0; extra == "browser"
Dynamic: license-file

# rf-pomlibrary

[![Python Version](https://img.shields.io/badge/python-3.9%2B-blue)](https://www.python.org/)
[![License](https://img.shields.io/badge/license-MIT-green)](License)
[![Status](https://img.shields.io/badge/status-stable-brightgreen)](https://github.com/khaledlim/rf-pomlibrary)

📦 **PyPI:** [https://pypi.org/project/rf-pomlibrary/](https://pypi.org/project/rf-pomlibrary/)  
🌐 **GitHub:** [https://github.com/khaledlim/rf-pomlibrary](https://github.com/khaledlim/rf-pomlibrary)

`rf-pomlibrary` provides generic Robot Framework keywords for reading, exposing, maintaining and optionally recording YAML Page Object Models (POMs) managed by [`pom-generator`](https://pypi.org/project/pom-generator/).

The library is intentionally lightweight: the POM model, YAML handling, locator resolution, scanning and locator-generation rules remain in `pom-generator`; `rf-pomlibrary` adds the Robot Framework-facing layer.

**Version:** 1.2.0  
**Authors:** Khaled Limem / Olivier RENAULT

## Architecture

```text
                    pom-generator
                         |
                         | POM model / YAML / locators
                         v
                     pom.yml
                         |
                         v
                  rf-pomlibrary
                         |
                         v
                 Robot Framework
```

Responsibilities are deliberately separated:

- **`pom-generator`** owns the POM format, generation, parsing, locator rules and Python/Playwright engine.
- **`rf-pomlibrary`** consumes that shared POM model and exposes it through Robot Framework keywords.
- Browser-based capture and UI action keywords are optional and use Robot Framework Browser when installed.

This avoids duplicating POM logic while keeping the Robot Framework layer small.

## Requirements

- Python 3.9 or later
- `pom-generator==1.2.0`
- `robotframework>=6.1`
- `robotframework-browser>=18.6.0` only for:
  - Browser-based POM recording
  - generic UI action keywords such as `Click Element` and `Fill Text`

## Installation

Install the library:

```powershell
pip install rf-pomlibrary
```

`pom-generator==1.2.0` and Robot Framework are installed automatically.

For Browser integration:

```powershell
pip install "rf-pomlibrary[browser]"
rfbrowser init
```

For local development:

```powershell
pip install -e .
```

or, with Browser support:

```powershell
pip install -e ".[browser]"
rfbrowser init
```

## Import in Robot Framework

A POM file can be passed when importing the library:

```robot
*** Settings ***
Library    RF_POMLibrary    pom_file=${CURDIR}${/}pom.yml
```

The default path is:

```text
pom.yml
```

Therefore this is also valid when `pom.yml` is in the current working directory:

```robot
*** Settings ***
Library    RF_POMLibrary
```

By default, the POM must already exist.

For a workflow that intentionally starts before the file exists, such as capturing a new POM from an already-open Browser session:

```robot
*** Settings ***
Library    RF_POMLibrary
...    pom_file=${CURDIR}${/}pom.yml
...    require_pom=${False}
```

## POM format

`rf-pomlibrary` consumes the YAML format managed by `pom-generator`.

A minimal example is:

```yaml
pom:
  metadata:
    schema_version: "2.0"

  pages:
    login:
      url: https://example.test/login
      title: Login
      elements:
        username:
          tag: input
          locators:
            - type: css
              value: '[name="username"]'
            - type: xpath
              value: '//input[@name="username"]'

        submit:
          tag: button
          locators:
            - type: role
              value: 'role=button[name="Sign in"]'
            - type: css
              value: '[type="submit"]'
```

Locators remain ordered by priority. Unless a locator type is explicitly requested, the first usable locator is returned.

## Main keywords

### POM inspection and consumption

| Keyword | Purpose |
| --- | --- |
| `List POM Keywords` | Lists public POM-related functions exposed by the library. |
| `Count POM Keywords` | Returns the number of public POM-related functions. |
| `Get Element Locator` | Returns the primary locator, or the first locator of a requested type. |
| `Get Element Descriptor` | Returns a locator dictionary containing `type` and `value`. |
| `Load Locators` | Returns the primary locator of every element in every page. |
| `Get Page URL` | Returns the URL stored for a page. |
| `Get Page Title` | Returns the expected title stored for a page. |
| `List Pages` | Returns all page names. |
| `Get Page Elements` | Returns all elements stored for one page. |
| `Expose Page Variables` | Exposes page locators as Robot Framework suite variables. |

### POM maintenance

| Keyword | Purpose |
| --- | --- |
| `Update Element Locator` | Adds or updates a locator and persists the POM. |
| `Delete Element Locator` | Removes one locator, or all locators of a given type. |
| `Delete Page` | Deletes a page and can remove related navigation entries. |

### Browser-based POM recording

| Keyword | Purpose |
| --- | --- |
| `Start POM Recording` | Starts/configures POM capture from an already-open Browser session. |
| `Capture Current Page To POM` | Scans the current Browser page and writes it to the POM. |
| `Pause POM Recording` | Temporarily pauses capture. |
| `Resume POM Recording` | Resumes capture. |
| `POM Recording Status` | Returns current recording state. |
| `Finish POM Recording` | Saves and finishes the recording session. |

### Generic Browser action keywords

| Keyword | Delegates to Robot Framework Browser |
| --- | --- |
| `Click Element` | `Browser.Click` |
| `Fill Text` | `Browser.Fill Text` |
| `Fill Secret` | `Browser.Fill Secret` |
| `Select Option By Value` | `Browser.Select Options By ... value` |
| `Check Checkbox` | `Browser.Check Checkbox` |
| `Uncheck Checkbox` | `Browser.Uncheck Checkbox` |
| `Wait Until Element Is Visible` | `Browser.Wait For Elements State ... visible` |

These action keywords provide a small, stable RF-facing vocabulary. They require the optional Browser dependency.

## Reading a locator

```robot
*** Settings ***
Library    RF_POMLibrary    pom_file=${CURDIR}${/}pom.yml

*** Test Cases ***
Read A Locator
    ${locator}=    Get Element Locator    login    username
    Log    ${locator}
```

To request a specific locator type:

```robot
${xpath}=    Get Element Locator    login    username    xpath
```

If the requested page, element or locator type does not exist, the keyword fails explicitly.

## Reading a locator descriptor

`Get Element Descriptor` keeps the locator strategy and raw value separate:

```robot
*** Test Cases ***
Read Descriptor
    ${descriptor}=    Get Element Descriptor    login    username
    Log    ${descriptor}[type]
    Log    ${descriptor}[value]
```

Typical returned value:

```python
{
    "type": "css",
    "value": "[name=\"username\"]"
}
```

This is useful when another technical layer needs to decide how the locator should be consumed.

## Loading all locators

```robot
*** Test Cases ***
Load Complete POM
    ${locators}=    Load Locators
    Log    ${locators}
```

The returned structure is organized by page and element and uses each element's primary locator.

## Exposing page variables

`Expose Page Variables` resolves every element of a page and exposes it as a Robot Framework suite variable.

```robot
*** Settings ***
Library    Browser
Library    RF_POMLibrary    pom_file=${CURDIR}${/}pom.yml

*** Test Cases ***
Login
    Expose Page Variables    login

    Fill Text       ${username}    demo
    Click Element   ${submit}
```

For a page containing:

```yaml
elements:
  username:
    ...
  submit:
    ...
```

the keyword exposes:

```text
${username}
${submit}
```

### Prefixing variables

A prefix can be used to avoid collisions:

```robot
Expose Page Variables    login    LOGIN

Fill Text       ${LOGIN_username}    demo
Click Element   ${LOGIN_submit}
```

The keyword also returns a dictionary containing the variables that were exposed:

```robot
${variables}=    Expose Page Variables    login    LOGIN
Log    ${variables}
```

## Maintaining locators from Robot Framework

### Add or update a locator

```robot
Update Element Locator
...    login
...    username
...    [data-testid="username"]
...    css
...    ${True}
...    ${False}
```

Arguments:

```text
page_name
element_name
locator_value
locator_type=css
make_primary=True
replace_type=False
```

`make_primary=True` moves the locator to the first position.

`replace_type=True` removes existing locators of the same type before inserting the new value.

### Delete a locator

Delete all locators of a type:

```robot
${deleted}=    Delete Element Locator
...    login
...    username
...    xpath
```

Delete only one exact locator:

```robot
${deleted}=    Delete Element Locator
...    login
...    username
...    css
...    [name="username"]
```

### Delete a page

```robot
${navigation_removed}=    Delete Page    legacy_page
```

By default, navigation entries that point to the deleted page are also removed.

To preserve navigation data:

```robot
Delete Page    legacy_page    cleanup_navigation=${False}
```

## Generic UI actions

With Browser support installed:

```robot
*** Settings ***
Library    Browser
Library    RF_POMLibrary    pom_file=${CURDIR}${/}pom.yml

*** Test Cases ***
Login Through Standard Actions
    Expose Page Variables    login

    Wait Until Element Is Visible    ${username}
    Fill Text                        ${username}    demo
    Fill Secret                      ${password}    secret
    Click Element                    ${submit}
```

The library delegates the actual browser interaction to Robot Framework Browser.

It does not implement its own browser engine.

## Recording a POM from Robot Framework Browser

`rf-pomlibrary` can populate the shared POM format from an already-running Robot Framework Browser session.

This is useful when the Robot suite owns browser creation, authentication and navigation.

```robot
*** Settings ***
Library    Browser
Library    RF_POMLibrary
...    pom_file=${CURDIR}${/}pom.yml
...    require_pom=${False}

*** Test Cases ***
Capture Application
    New Browser    chromium    headless=${False}
    New Page       https://example.test/

    Start POM Recording
    ...    reset=${True}
    ...    app_name=example
    ...    base_url=https://example.test/

    Capture Current Page To POM    home

    Go To    https://example.test/profile
    Capture Current Page To POM    profile

    Finish POM Recording
```

The page scanning, YAML generation and locator-ranking rules come from `pom-generator`. A POM captured through `rf-pomlibrary` therefore follows the same model and locator strategy as one generated directly by `pom-generator`.

### Recording controls

Pause:

```robot
Pause POM Recording
```

Resume:

```robot
Resume POM Recording
```

Inspect state:

```robot
${status}=    POM Recording Status
Log    ${status}
```

Finish:

```robot
${result}=    Finish POM Recording
Log    ${result}
```

## Multiple POM files

The library can be imported more than once using Robot Framework aliases:

```robot
*** Settings ***
Library    RF_POMLibrary
...    ${CURDIR}${/}authentication.yml
...    WITH NAME    AUTH_POM

Library    RF_POMLibrary
...    ${CURDIR}${/}application.yml
...    WITH NAME    APP_POM

*** Test Cases ***
Use Multiple POMs
    AUTH_POM.Expose Page Variables    login        AUTH
    APP_POM.Expose Page Variables     dashboard    APP

    Log    ${AUTH_username}
    Log    ${APP_profile_button}
```

This keeps variable namespaces explicit while allowing several POMs in the same suite.

## Python API for technical extensions

Although `rf-pomlibrary` is primarily a Robot Framework library, it exposes a small internal API for technical adapters.

```python
from RF_POMLibrary import RFPOMLibrary

library = RFPOMLibrary("pom.yml")

locator = library.internal_api.resolve_locator(
    page_name="login",
    element_name="submit",
    backend="browser",
)

print(locator)
```

Available backend families include:

```text
browser / playwright
selenium
raw
```

The API can also return descriptors and candidate locators.

Business-level Robot Framework suites should normally prefer the public Robot keywords.

## Relationship with pom-generator

`rf-pomlibrary` does not duplicate the POM engine.

It depends on `pom-generator==1.2.0` for:

- the shared YAML POM format
- page and element models
- scanning
- locator generation and ranking
- POM persistence rules

This dependency is installed automatically with `rf-pomlibrary`.

The separation is intentional:

```text
pom-generator
    = POM engine and generation

rf-pomlibrary
    = Robot Framework adapter and keywords
```

## Error handling

The library fails explicitly when:

- the configured POM file does not exist and `require_pom=True`
- a page is unknown
- an element is unknown
- no locator exists for an element
- a requested locator type is unavailable
- a Browser-dependent keyword is used without a valid Robot Framework Browser context

This is preferable to silently returning an unusable locator.

## Development

Install in editable mode:

```powershell
pip install -e .
```

Run the unit tests:

```powershell
python -m unittest discover -s tests -v
```

Compile the package:

```powershell
python -m compileall src
```

Basic import check:

```powershell
python -c "from RF_POMLibrary import RFPOMLibrary; print(RFPOMLibrary)"
```

For Browser integration tests:

```powershell
pip install -e ".[browser]"
rfbrowser init
```

## Build

A standard Python build can be produced with:

```powershell
python -m build
```

The project metadata declares:

```text
package: rf-pomlibrary
version: 1.2.0
Python: >=3.9
pom-generator: ==1.2.0
Robot Framework: >=6.1
Browser extra: robotframework-browser>=18.6.0
```

## Version compatibility

`rf-pomlibrary 1.2.0` targets `pom-generator 1.2.0`.

The two packages share the same POM contract. When that contract changes, compatible versions should be released together.

## Authors

Khaled Limem / Olivier RENAULT
