Files
HOA_Financial_Platform/tests/page-objects/BasePage.ts
JoeBot dfd1bccb89 feat: add Playwright E2E and API regression test suite
Production-ready test infrastructure with Page Object Model pattern,
reusable fixtures for auth/DB/test-data, and example tests covering
login flow, dashboard, accounts CRUD API, and visual regression.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 12:40:05 -04:00

74 lines
2.2 KiB
TypeScript

/**
* Base page object with shared helpers.
*
* All page objects extend this class to inherit common navigation,
* waiting, and assertion patterns.
*/
import { type Page, type Locator, expect } from '@playwright/test';
export abstract class BasePage {
constructor(protected readonly page: Page) {}
/** The path segment for this page (e.g. '/dashboard', '/accounts') */
abstract readonly path: string;
/** Navigate to this page */
async goto(): Promise<void> {
await this.page.goto(this.path);
await this.waitForReady();
}
/**
* Override in subclasses to wait for page-specific readiness signals.
* Default: waits for network idle.
*/
async waitForReady(): Promise<void> {
await this.page.waitForLoadState('networkidle');
}
/** Assert the page URL contains the expected path */
async assertOnPage(): Promise<void> {
await expect(this.page).toHaveURL(new RegExp(this.path));
}
/** Get the page title text (Mantine AppShell header or h1) */
async getPageHeading(): Promise<string> {
const heading = this.page.getByRole('heading', { level: 1 }).first();
return heading.innerText();
}
/** Wait for a Mantine notification to appear with the given text */
async waitForNotification(text: string | RegExp): Promise<void> {
await expect(
this.page.locator('.mantine-Notification-root').filter({ hasText: text }),
).toBeVisible({ timeout: 10_000 });
}
/** Click a navigation link in the sidebar */
async navigateTo(linkText: string): Promise<void> {
await this.page.getByRole('link', { name: linkText }).click();
await this.page.waitForLoadState('networkidle');
}
/** Get a Mantine table body locator */
get tableBody(): Locator {
return this.page.locator('tbody');
}
/** Get all table rows */
get tableRows(): Locator {
return this.tableBody.locator('tr');
}
/** Wait for API response on a specific endpoint pattern */
async waitForApi(urlPattern: string | RegExp): Promise<void> {
await this.page.waitForResponse(
(response) =>
(typeof urlPattern === 'string'
? response.url().includes(urlPattern)
: urlPattern.test(response.url())) && response.status() < 400,
);
}
}