import type { Page, Locator } from '@playwright/test'; export class JoinPage { readonly page: Page; readonly nameInput: Locator; readonly submitButton: Locator; readonly errorMessage: Locator; readonly pinModal: Locator; readonly pinDisplay: Locator; readonly pinCopyButton: Locator; readonly continueButton: Locator; readonly linkToRecover: Locator; // Inline recovery state (shown when the name is taken) readonly recoveryPinInput: Locator; readonly recoverySubmit: Locator; readonly recoveryError: Locator; readonly tryDifferentNameButton: Locator; constructor(page: Page) { this.page = page; this.nameInput = page.getByTestId('join-name-input'); this.submitButton = page.getByTestId('join-submit'); this.errorMessage = page.getByTestId('join-error'); this.pinModal = page.getByTestId('pin-modal'); this.pinDisplay = page.getByTestId('pin-display'); this.pinCopyButton = page.getByTestId('pin-copy'); this.continueButton = page.getByTestId('continue-to-feed'); this.linkToRecover = page.getByTestId('link-to-recover'); this.recoveryPinInput = page.getByTestId('recovery-pin-input'); this.recoverySubmit = page.getByTestId('recovery-submit'); this.recoveryError = page.getByTestId('recovery-error'); this.tryDifferentNameButton = page.getByTestId('try-different-name'); } async goto() { await this.page.goto('/join'); } async fillName(name: string) { await this.nameInput.fill(name); } async submit() { await this.submitButton.click(); } /** End-to-end: type a name and submit, then either resolve when the PIN modal appears or surface the name-taken UI. */ async joinAs(name: string): Promise<{ pin: string }> { await this.fillName(name); await this.submit(); await this.pinModal.waitFor({ state: 'visible' }); const pin = (await this.pinDisplay.textContent())?.trim() ?? ''; return { pin }; } /** Continue to the gallery after the PIN modal appears. */ async continueToFeed() { await this.continueButton.click(); await this.page.waitForURL('**/feed'); } }