/** * Copyright since 2025 Mifos Initiative * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { Page, Locator } from '@playwright/test'; /** * BasePage - Abstract base class for Page Object Model. * * Provides common functionality for all page objects: * - Navigation helpers with wait states * - Reusable interaction methods * - Screenshot utilities * * All page objects should extend this class. */ export abstract class BasePage { /** * The Playwright Page instance. * Protected to allow access in child classes. */ protected readonly page: Page; /** * The URL path for this page (relative to baseURL). * Must be implemented by child classes. */ abstract readonly url: string; /** * Creates a new BasePage instance. * @param page - The Playwright Page instance */ constructor(page: Page) { this.page = page; } /** * Navigate to this page's URL. * Uses the route defined in the `url` property. */ async navigate(): Promise { // Navigate with extended timeout and wait until load event await this.page.goto(this.url, { waitUntil: 'load', timeout: 60000 }); await this.waitForLoad(); } /** * Wait for the page to be fully loaded. * Override in child classes for page-specific load conditions. */ async waitForLoad(): Promise { await this.page.waitForLoadState('networkidle'); } /** * Get the page title. * @returns The document title */ async getTitle(): Promise { return this.page.title(); } /** * Get the current URL. * @returns The current page URL */ getCurrentUrl(): string { return this.page.url(); } /** * Wait for an element to be visible. * @param locator - The Playwright Locator * @param timeout - Optional timeout in milliseconds */ async waitForVisible(locator: Locator, timeout?: number): Promise { await locator.waitFor({ state: 'visible', timeout }); } /** * Wait for an element to be hidden. * @param locator - The Playwright Locator * @param timeout - Optional timeout in milliseconds */ async waitForHidden(locator: Locator, timeout?: number): Promise { await locator.waitFor({ state: 'hidden', timeout }); } /** * Click an element and wait for navigation. * Useful for buttons that trigger page redirects. * @param locator - The Playwright Locator to click */ async clickAndWaitForNavigation(locator: Locator): Promise { await Promise.all([ this.page.waitForURL(/.*/, { waitUntil: 'networkidle' }), locator.click() ]); } /** * Fill a form field after clearing existing content. * @param locator - The Playwright Locator for the input * @param value - The value to fill */ async fillField(locator: Locator, value: string): Promise { await locator.clear(); await locator.fill(value); } /** * Take a screenshot of the current page. * @param name - Name for the screenshot file */ async takeScreenshot(name: string): Promise { await this.page.screenshot({ path: `playwright-report/${name}.png` }); } /** * Check if an element is visible. * @param locator - The Playwright Locator * @returns true if visible, false otherwise */ async isVisible(locator: Locator): Promise { return locator.isVisible(); } /** * Get text content from an element. * @param locator - The Playwright Locator * @returns The text content or null */ async getText(locator: Locator): Promise { return locator.textContent(); } }