Skip to content

Page Objects

Page Objects keep selectors and common actions in one class. The standard scaffold generated by dolphin init creates a small Notepad Page Object.

Generated Example

objects/notepad_page.py
from __future__ import annotations

from dolphin_desktop._window import Window


class NotepadPage:
    def __init__(self, window: Window) -> None:
        self._win = window
        self._editor = window.get_by_role("Document")

    def type_text(self, text: str) -> "NotepadPage":
        self._editor.click()
        self._editor.type_text(text)
        return self

    def clear(self) -> "NotepadPage":
        self._editor.clear()
        return self

    def read_text(self) -> str:
        return self._editor.text()

The test imports and uses it:

tests/test_sample.py
import pytest

from objects.notepad_page import NotepadPage

pytestmark = pytest.mark.integration


def test_notepad_with_page_object(launch):
    app = launch("notepad.exe")
    win = app.window(class_name="Notepad")
    page = NotepadPage(win)

    page.type_text("Hello, Dolphin!")
    assert "Hello, Dolphin!" in page.read_text()

Keep locator creation inside the class and expose user-level operations:

class LoginPage:
    def __init__(self, window):
        self._win = window

    @property
    def _username(self):
        return self._win.get_by_automation_id("txtUsername")

    @property
    def _password(self):
        return self._win.get_by_automation_id("txtPassword")

    def sign_in(self, username: str, password: str) -> None:
        self._username.set_text(username)
        self._password.set_text(password)
        self._win.get_by_role("Button", name="Sign in").click()

Using properties keeps locators lazy. Each action resolves the element against the current UI.

Project Layout

my-tests/
|-- objects/
|   |-- __init__.py
|   `-- notepad_page.py
`-- tests/
    |-- __init__.py
    `-- test_sample.py

Next: Fallback Selectors.