Files
HOA_Financial_Platform/tests/page-objects/LoginPage.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

86 lines
2.4 KiB
TypeScript

/**
* Page object for the Login page (/login).
*
* Maps to: frontend/src/pages/auth/LoginPage.tsx
* Auth: POST /api/auth/login (Passport local strategy)
*/
import { type Page, expect } from '@playwright/test';
import { BasePage } from './BasePage';
export class LoginPage extends BasePage {
readonly path = '/login';
// ─── Locators (resilient, role/label based) ──────────────────
get emailInput() {
return this.page.getByLabel('Email');
}
get passwordInput() {
return this.page.getByLabel('Password');
}
get signInButton() {
return this.page.getByRole('button', { name: 'Sign in' });
}
get passkeyButton() {
return this.page.getByRole('button', { name: /passkey/i });
}
get errorAlert() {
return this.page.getByRole('alert');
}
get registerLink() {
return this.page.getByRole('link', { name: /register/i });
}
// ─── MFA locators ────────────────────────────────────────────
get mfaHeading() {
return this.page.getByText('Two-Factor Authentication');
}
get mfaPinInput() {
return this.page.locator('.mantine-PinInput-input').first();
}
get mfaVerifyButton() {
return this.page.getByRole('button', { name: 'Verify' });
}
// ─── Actions ─────────────────────────────────────────────────
/** Fill and submit login credentials */
async login(email: string, password: string): Promise<void> {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.signInButton.click();
}
/** Login and wait for successful redirect */
async loginAndWaitForRedirect(
email: string,
password: string,
): Promise<void> {
await this.login(email, password);
await this.page.waitForURL(/\/(select-org|dashboard|admin|onboarding)/, {
timeout: 15_000,
});
}
/** Assert an error message is displayed */
async assertError(message: string | RegExp): Promise<void> {
await expect(this.errorAlert).toContainText(message);
}
/** Assert we're still on the login page */
async assertStillOnLogin(): Promise<void> {
await expect(this.page).toHaveURL(/\/login/);
}
override async waitForReady(): Promise<void> {
await expect(this.signInButton).toBeVisible();
}
}