import { Page, expect } from '@playwright/test'; /** * Navigate to organizations and select the first one */ export async function selectFirstOrganization(page: Page) { await page.goto('/orgs'); const firstOrg = page.locator('[data-test="organization-card"]').first(); await firstOrg.waitFor({ timeout: 10000 }); await firstOrg.click(); await expect(page).toHaveURL(/\/orgs\/[^\/]+/); } /** * Wait for LiveView to be fully connected */ export async function waitForLiveView(page: Page) { // Wait for Phoenix LiveView to connect await page.waitForFunction(() => { // @ts-ignore return window.liveSocket && window.liveSocket.isConnected(); }, { timeout: 10000 }).catch(() => { // Fallback to network idle if LiveView check doesn't work return page.waitForLoadState('networkidle'); }); } /** * Check if an element exists on the page */ export async function elementExists(page: Page, selector: string): Promise { return (await page.locator(selector).count()) > 0; } /** * Get status emoji from page title */ export async function getStatusEmoji(page: Page): Promise { const title = await page.title(); const match = title.match(/^([🔴🟡🟢])/); return match ? match[1] : null; } /** * Wait for page title to update with specific emoji */ export async function waitForStatusEmoji(page: Page, expectedEmoji: string, timeout = 5000) { const startTime = Date.now(); while (Date.now() - startTime < timeout) { const emoji = await getStatusEmoji(page); if (emoji === expectedEmoji) { return true; } await page.waitForTimeout(100); } throw new Error(`Status emoji did not update to ${expectedEmoji} within ${timeout}ms`); } /** * Fill a form and submit it */ export async function fillAndSubmitForm( page: Page, formSelector: string, fields: Record ) { for (const [label, value] of Object.entries(fields)) { await page.getByLabel(new RegExp(label, 'i')).fill(value); } await page.locator(formSelector).getByRole('button', { name: /submit|save|create/i }).click(); }