import { Page, BrowserContext } from '@playwright/test'; /** * Authentication fixture for E2E tests * Handles login flows and session management */ export interface LoginCredentials { username: string; password: string; } export interface AuthSession { token: string; userId: string; email: string; isAdmin: boolean; } /** * Perform LDAP authentication */ export async function loginWithLdap( page: Page, credentials: LoginCredentials, baseUrl: string = 'http://localhost' ): Promise { await page.goto(`${baseUrl}`); // Wait for login form to appear await page.waitForSelector('[data-testid="login-form"]', { timeout: 5000 }); // Fill in username await page.fill('[data-testid="username-input"]', credentials.username); // Fill in password await page.fill('[data-testid="password-input"]', credentials.password); // Click login button await page.click('[data-testid="login-submit"]'); // Wait for navigation to inventory page await page.waitForURL(`${baseUrl}/*`, { waitUntil: 'networkidle' }); } /** * Perform local user authentication */ export async function loginWithLocalUser( page: Page, credentials: LoginCredentials, baseUrl: string = 'http://localhost' ): Promise { await page.goto(`${baseUrl}`); // Wait for identity check overlay await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 5000 }); // Click "Local User" tab if it exists const localUserTab = page.locator('[data-testid="local-user-tab"]'); if (await localUserTab.isVisible()) { await localUserTab.click(); } // Fill in username await page.fill('[data-testid="local-username-input"]', credentials.username); // Fill in password await page.fill('[data-testid="local-password-input"]', credentials.password); // Click login button await page.click('[data-testid="local-login-submit"]'); // Wait for navigation to inventory page await page.waitForURL(`${baseUrl}/*`, { waitUntil: 'networkidle' }); } /** * Logout from the application */ export async function logout(page: Page, baseUrl: string = 'http://localhost'): Promise { // Click logout button or menu const logoutButton = page.locator('[data-testid="logout-button"]'); if (await logoutButton.isVisible()) { await logoutButton.click(); } else { // Try finding it in menu const menu = page.locator('[data-testid="user-menu"]'); if (await menu.isVisible()) { await menu.click(); await page.click('[data-testid="logout-menu-item"]'); } } // Wait for redirect to login await page.waitForURL(`${baseUrl}/*`, { timeout: 5000 }); } /** * Get authentication token from local storage */ export async function getAuthToken(page: Page): Promise { const token = await page.evaluate(() => { return localStorage.getItem('auth_token') || sessionStorage.getItem('auth_token'); }); return token; } /** * Set authentication token in local storage */ export async function setAuthToken(page: Page, token: string): Promise { await page.evaluate((t) => { localStorage.setItem('auth_token', t); }, token); } /** * Clear authentication data */ export async function clearAuth(page: Page): Promise { await page.evaluate(() => { localStorage.removeItem('auth_token'); sessionStorage.removeItem('auth_token'); localStorage.removeItem('user_data'); sessionStorage.removeItem('user_data'); }); } /** * Check if user is authenticated */ export async function isAuthenticated(page: Page): Promise { const token = await getAuthToken(page); return !!token; } /** * Get current user info from page */ export async function getCurrentUser(page: Page): Promise<{ username: string; email: string } | null> { try { const userData = await page.evaluate(() => { const stored = localStorage.getItem('user_data') || sessionStorage.getItem('user_data'); return stored ? JSON.parse(stored) : null; }); return userData; } catch { return null; } } /** * Wait for authentication to complete */ export async function waitForAuth(page: Page, timeout: number = 5000): Promise { // Wait for either: // 1. Token to be in storage // 2. Navigation to happen // 3. Auth overlay to disappear await page.waitForFunction( () => { const token = typeof window !== 'undefined' ? localStorage.getItem('auth_token') || sessionStorage.getItem('auth_token') : null; return !!token; }, { timeout } ); } /** * Verify login was successful by checking inventory page loaded */ export async function verifyLoginSuccess(page: Page, baseUrl: string = 'http://localhost'): Promise { try { // Check if we're on the inventory page await page.waitForURL(/inventory|dashboard/, { timeout: 5000 }); return true; } catch { return false; } } /** * Create test user via API (helper for setup) */ export async function createTestUserViaApi( baseUrl: string, token: string, user: { username: string; password: string; email: string } ): Promise<{ id: string; username: string }> { const response = await fetch(`${baseUrl}/api/admin/users`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify(user), }); if (!response.ok) { throw new Error(`Failed to create user: ${response.statusText}`); } return response.json(); } /** * Delete test user via API (helper for cleanup) */ export async function deleteTestUserViaApi( baseUrl: string, token: string, userId: string ): Promise { const response = await fetch(`${baseUrl}/api/admin/users/${userId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}`, }, }); if (!response.ok) { throw new Error(`Failed to delete user: ${response.statusText}`); } } /** * Helper to setup admin context for tests */ export async function setupAdminContext( context: BrowserContext, baseUrl: string, adminToken: string ): Promise { // Add auth headers to all API requests await context.addInitScript((token) => { (window as any).__testAuthToken = token; }, adminToken); }