import { type Page, type Locator, expect } from '@playwright/test'; /** * Page Object Model for the Contact Page * Encapsulates all selectors and interactions for the contact form */ export class ContactPage { readonly page: Page; readonly form: Locator; readonly nameInput: Locator; readonly emailInput: Locator; readonly phoneInput: Locator; readonly subjectSelect: Locator; readonly messageTextarea: Locator; readonly submitButton: Locator; readonly honeypotInput: Locator; readonly toastContainer: Locator; // Error elements readonly nameError: Locator; readonly emailError: Locator; readonly phoneError: Locator; readonly subjectError: Locator; readonly messageError: Locator; constructor(page: Page) { this.page = page; this.form = page.locator('#contact-form'); this.nameInput = page.locator('input[name="name"]'); this.emailInput = page.locator('input[name="email"]'); this.phoneInput = page.locator('input[name="phone"]'); this.subjectSelect = page.locator('select[name="subject"]'); this.messageTextarea = page.locator('textarea[name="message"]'); this.submitButton = page.locator('button[type="submit"]'); this.honeypotInput = page.locator('input[name="website"]'); this.toastContainer = page.locator('#toast-container'); this.nameError = page.locator('[data-error="name"]'); this.emailError = page.locator('[data-error="email"]'); this.phoneError = page.locator('[data-error="phone"]'); this.subjectError = page.locator('[data-error="subject"]'); this.messageError = page.locator('[data-error="message"]'); } async goto() { await this.page.goto('/contact'); await this.page.waitForLoadState('domcontentloaded'); } async fillValidForm(overrides: Partial<{ name: string; email: string; phone: string; subject: string; message: string; }> = {}) { const data = { name: 'John Doe', email: 'john.doe@example.com', phone: '+1 555-123-4567', subject: 'web-development', message: 'I am interested in building a custom web application for my business.', ...overrides, }; await this.nameInput.fill(data.name); await this.emailInput.fill(data.email); if (data.phone) await this.phoneInput.fill(data.phone); await this.subjectSelect.selectOption(data.subject); await this.messageTextarea.fill(data.message); } async submit() { await this.submitButton.click(); } async fillAndSubmit(overrides: Parameters[0] = {}) { await this.fillValidForm(overrides); await this.submit(); } async waitForSuccessToast() { await expect(this.page.locator('#toast-container')).toContainText(/sent successfully/i, { timeout: 10000 }); } async waitForErrorToast() { await expect(this.page.locator('#toast-container')).toContainText(/error|wrong|fix/i, { timeout: 5000 }); } async isSubmitButtonDisabled() { return this.submitButton.isDisabled(); } async getFieldError(field: 'name' | 'email' | 'phone' | 'subject' | 'message') { const errorLocator = this.page.locator(`[data-error="${field}"]`); const isHidden = await errorLocator.evaluate((el) => el.classList.contains('hidden')); return !isHidden; } }