import { type Page, expect } from '@playwright/test'; export const PORT_SLUG = 'port-nimara'; export const USERS = { super_admin: { email: 'admin@portnimara.test', password: 'SuperAdmin12345!', }, sales_agent: { email: 'agent@portnimara.test', password: 'SalesAgent12345!', }, viewer: { email: 'viewer@portnimara.test', password: 'ViewerUser12345!', }, }; /** * Log in as a specific user via the UI login page. * Waits for the dashboard to load after successful login. */ export async function login( page: Page, role: keyof typeof USERS = 'super_admin', ) { const user = USERS[role]; await page.goto('/login'); await page.waitForSelector('#email', { state: 'visible' }); await page.fill('#email', user.email); await page.fill('#password', user.password); await page.click('button[type="submit"]'); // Wait for redirect away from /login await page.waitForURL((url) => !url.pathname.includes('/login'), { timeout: 15_000, }); } /** * Log out via the topbar user menu. * Falls back to navigating to /login if the logout button isn't found. */ export async function logout(page: Page) { // Try clicking a logout button/link if visible const logoutBtn = page.getByRole('button', { name: /log\s?out|sign\s?out/i }); if (await logoutBtn.isVisible({ timeout: 2000 }).catch(() => false)) { await logoutBtn.click(); await page.waitForURL('**/login**', { timeout: 10_000 }); return; } // Fallback: clear cookies and navigate to login await page.context().clearCookies(); await page.goto('/login'); await page.waitForSelector('#email', { state: 'visible' }); } /** * Navigate to a page within the current port context. */ export async function navigateTo(page: Page, path: string) { const url = `/${PORT_SLUG}${path.startsWith('/') ? path : `/${path}`}`; await page.goto(url); await page.waitForLoadState('networkidle'); } /** * Wait for a toast notification and verify its text. */ export async function expectToast(page: Page, textPattern: string | RegExp) { const toast = page.locator('[data-sonner-toast]').last(); await expect(toast).toBeVisible({ timeout: 10_000 }); if (typeof textPattern === 'string') { await expect(toast).toContainText(textPattern); } else { await expect(toast).toHaveText(textPattern); } } /** * Wait for a sheet (slide-in panel) to be visible. */ export async function waitForSheet(page: Page) { await page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5_000, }); }