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>
83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
/**
|
|
* Page object for the Accounts page (/accounts).
|
|
*
|
|
* Maps to: frontend/src/pages/accounts/AccountsPage.tsx
|
|
* Data: GET /api/accounts, POST /api/accounts, PUT /api/accounts/:id
|
|
*/
|
|
|
|
import { type Page, expect } from '@playwright/test';
|
|
import { BasePage } from './BasePage';
|
|
|
|
export class AccountsPage extends BasePage {
|
|
readonly path = '/accounts';
|
|
|
|
// ─── Locators ────────────────────────────────────────────────
|
|
|
|
get heading() {
|
|
return this.page.getByRole('heading', { name: /accounts|chart of accounts/i }).first();
|
|
}
|
|
|
|
get addAccountButton() {
|
|
return this.page.getByRole('button', { name: /add|create|new/i }).first();
|
|
}
|
|
|
|
/** Account name input in the create/edit modal */
|
|
get nameInput() {
|
|
return this.page.getByLabel(/name/i).first();
|
|
}
|
|
|
|
/** Account number input */
|
|
get numberInput() {
|
|
return this.page.getByLabel(/number/i).first();
|
|
}
|
|
|
|
/** Account type select */
|
|
get typeSelect() {
|
|
return this.page.getByLabel(/type/i).first();
|
|
}
|
|
|
|
/** Save/submit button in modal */
|
|
get saveButton() {
|
|
return this.page.getByRole('button', { name: /save|create|submit/i }).first();
|
|
}
|
|
|
|
/** Cancel button in modal */
|
|
get cancelButton() {
|
|
return this.page.getByRole('button', { name: /cancel/i }).first();
|
|
}
|
|
|
|
// ─── Actions ─────────────────────────────────────────────────
|
|
|
|
override async waitForReady(): Promise<void> {
|
|
await this.page.waitForLoadState('networkidle');
|
|
// Wait for the accounts list or heading to be visible
|
|
await expect(this.page.locator('main')).toBeVisible();
|
|
}
|
|
|
|
/** Get the count of visible account rows */
|
|
async getAccountCount(): Promise<number> {
|
|
return this.tableRows.count();
|
|
}
|
|
|
|
/** Find an account row by name */
|
|
accountRow(name: string) {
|
|
return this.tableBody.locator('tr').filter({ hasText: name });
|
|
}
|
|
|
|
/** Assert an account exists in the table */
|
|
async assertAccountExists(name: string): Promise<void> {
|
|
await expect(this.accountRow(name)).toBeVisible();
|
|
}
|
|
|
|
/** Assert an account does NOT exist in the table */
|
|
async assertAccountNotExists(name: string): Promise<void> {
|
|
await expect(this.accountRow(name)).not.toBeVisible();
|
|
}
|
|
|
|
/** Open the create account modal */
|
|
async openCreateModal(): Promise<void> {
|
|
await this.addAccountButton.click();
|
|
await expect(this.nameInput).toBeVisible();
|
|
}
|
|
}
|