Framework Implementation — Page Objects, Custom Commands, Data Management and Reporting

With the plan in place, this lesson walks through implementing the core framework components: the BasePage with shared methods, page objects for login, inventory, cart, and checkout, data builders for test data generation, API helper commands, and a reporting utility that captures screenshots on failure. Each component references the patterns taught throughout this series.

Implementing the Framework — Component by Component

Implementation follows the dependency order: config first, then driver management, then BasePage, then page objects, then tests.

# Implementation roadmap — build in this order

IMPLEMENTATION_ORDER = [
    {
        "component": "1. Configuration (config/settings.py)",
        "references": "Chapter 42 — Five-Layer Architecture (Layer 1)",
        "key_decisions": [
            "Use environment variables for all configurable values",
            "Support local and CI environments via env var overrides",
            "Store secrets in .env (gitignored), not in code",
        ],
        "code_sample": (
            "import os\n"
            "class Settings:\n"
            "    BASE_URL = os.getenv('BASE_URL', 'https://www.saucedemo.com')\n"
            "    BROWSER = os.getenv('BROWSER', 'chrome')\n"
            "    HEADLESS = os.getenv('HEADLESS', 'true') == 'true'\n"
            "    TIMEOUT = int(os.getenv('TIMEOUT', '10'))\n"
            "    GRID_URL = os.getenv('GRID_URL', None)"
        ),
    },
    {
        "component": "2. Driver Factory (utils/driver_factory.py)",
        "references": "Chapter 43 — DriverFactory pattern",
        "key_decisions": [
            "Support Chrome, Firefox, Edge via browser name parameter",
            "Support local and Grid execution via GRID_URL",
            "Headless mode configurable via environment variable",
        ],
    },
    {
        "component": "3. BasePage (pages/base_page.py)",
        "references": "Chapter 38 — BasePage pattern",
        "key_decisions": [
            "Wrap click, type_text, get_text with WebDriverWait",
            "Add is_visible, take_screenshot, scroll_to_element utilities",
            "All page objects inherit from BasePage",
        ],
    },
    {
        "component": "4. Page Objects (pages/login_page.py, etc.)",
        "references": "Chapter 38 — Page Object Model",
        "key_decisions": [
            "Locators as class-level tuple constants",
            "Action methods return page object instances (model transitions)",
            "No assertions in page objects — only in tests",
            "Constructor verifies page loaded (wait for key element)",
        ],
    },
    {
        "component": "5. Data Builders (utils/data_builder.py)",
        "references": "Chapter 77 — Builder pattern + test data management",
        "key_decisions": [
            "UserBuilder with sensible defaults and .with_*() methods",
            "Timestamp-based unique identifiers for parallel safety",
            "External fixture files (JSON) for static test data",
        ],
    },
    {
        "component": "6. Test Cases (tests/test_*.py)",
        "references": "Chapters 38-42 — Test design, data-driven, POM",
        "key_decisions": [
            "One test file per feature area (login, cart, checkout)",
            "Descriptive test names: test_valid_login_shows_inventory",
            "Data-driven tests with @parametrize for login variants",
            "API tests using cy.request() or requests library",
        ],
    },
    {
        "component": "7. Reporting (utils/reporter.py + conftest hooks)",
        "references": "Chapter 42 — Reporting, logging, screenshots",
        "key_decisions": [
            "Auto-capture screenshot on test failure",
            "Generate HTML report (pytest-html or Allure)",
            "Log meaningful actions (not every find_element call)",
        ],
    },
    {
        "component": "8. Security + Accessibility (tests/test_security.py)",
        "references": "Chapters 60, 79 — Security payloads, axe-core",
        "key_decisions": [
            "XSS payloads parameterised across input fields",
            "Access control checks (IDOR via API ID manipulation)",
            "cy.checkA11y() or axe-core integration in key tests",
        ],
    },
]

# Quality checklist before submission
QUALITY_CHECKLIST = [
    "All tests pass locally on Chrome and Firefox",
    "CI pipeline runs green on GitHub Actions",
    "No hardcoded credentials — all secrets via env vars",
    "No time.sleep() or cy.wait(ms) without justification",
    "Every page object inherits from BasePage",
    "Every test is independent — can run alone, in parallel, in any order",
    "Test data uses unique identifiers (timestamps/UUIDs)",
    "README includes setup instructions and architecture overview",
    "Linter configured and passing (flake8/eslint)",
    ".gitignore excludes reports/, node_modules/, .env, __pycache__/",
]

print("Implementation Order:")
for comp in IMPLEMENTATION_ORDER:
    print(f"\n  {comp['component']}")
    print(f"    References: {comp['references']}")

print("\n\nQuality Checklist:")
for item in QUALITY_CHECKLIST:
    print(f"  [ ] {item}")
Note: The implementation order follows the dependency graph: configuration has no dependencies, the driver factory depends on configuration, BasePage depends on the driver, page objects depend on BasePage, and tests depend on everything. Building in this order means each component can be tested as you go — you can verify the driver factory works before writing page objects, and verify page objects work before writing tests. This incremental approach catches integration issues early.
Tip: After implementing each component, commit it to Git with a descriptive message: “feat: add BasePage with click, type_text, get_text methods,” “feat: add LoginPage with login() and login_expecting_error(),” “feat: add CI pipeline with Chrome and Firefox.” These commits demonstrate your development process to anyone reviewing your repository — far more informative than a single “initial commit” with 50 files.
Warning: The capstone is not a race to write the most tests. Fifteen well-architected tests with clean page objects, proper data management, and CI/CD integration demonstrate more skill than 100 copy-pasted tests with duplicated locators and hardcoded data. Quality of engineering over quantity of test cases — always.

Common Mistakes

Mistake 1 — Skipping BasePage and duplicating wait logic in every page object

❌ Wrong: Every page object has its own WebDriverWait instantiation and its own click/type/getText wrapper — 6 page objects with the same boilerplate.

✅ Correct: BasePage defines click(), type_text(), get_text() once. All page objects inherit these methods. Zero duplication.

Mistake 2 — Not including API tests alongside UI tests

❌ Wrong: Framework only has UI tests — misses the opportunity to demonstrate API testing skills.

✅ Correct: Include 5-10 API tests (product listing, CRUD operations, error responses) to demonstrate full-stack testing capability.

🧠 Test Yourself

In what order should capstone framework components be implemented?