import { chromium } from 'playwright'; import { logger } from '../../services/logging'; interface GlobalSetupConfig { projects?: Array<{ name: string; use?: Record; }>; webServer?: Array<{ command: string; port: number; timeout: number; reuseExistingServer: boolean; }>; use?: { baseURL?: string; trace?: string; screenshot?: string; }; [key: string]: unknown; } /** * Global setup for authentication debug tests * Ensures services are running and database is properly initialized */ async function globalSetup(_config: GlobalSetupConfig) { logger.info( '🔧 Setting up authentication debug test environment...', 'SETUP' ); const startTime = Date.now(); try { // Wait for services to be ready await waitForServices(); // Initialize test data if needed await initializeTestData(); // Verify admin user exists await verifyAdminUser(); const duration = Date.now() - startTime; logger.info(`✅ Auth debug setup completed in ${duration}ms`, 'SETUP'); } catch (error) { logger.error('❌ Auth debug setup failed:', 'SETUP', error); throw error; } } /** * Wait for required services to be available */ async function waitForServices(): Promise { logger.info('⏳ Waiting for services to be ready...', 'SETUP'); // Wait for frontend await waitForService('http://localhost:8080', 'Frontend'); // Wait for CouchDB await waitForService('http://localhost:5984', 'CouchDB'); logger.info('✅ All services are ready', 'SETUP'); } /** * Wait for a specific service to be available */ async function waitForService(url: string, serviceName: string): Promise { const maxAttempts = 30; const delay = 2000; // 2 seconds for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { const response = await fetch(url, { method: 'GET', headers: { Authorization: 'Basic ' + Buffer.from('admin:password').toString('base64'), }, signal: AbortSignal.timeout(5000), // 5 second timeout per request }); if (response.ok) { logger.info(`✅ ${serviceName} is ready at ${url}`, 'SETUP'); return; } } catch (error) { // Log specific error types for better debugging if (error instanceof Error) { logger.debug( `⏳ ${serviceName} connection failed: ${error.message}`, 'SETUP' ); } } if (attempt === maxAttempts) { throw new Error( `${serviceName} not available at ${url} after ${maxAttempts} attempts` ); } logger.debug( `⏳ ${serviceName} not ready, attempt ${attempt}/${maxAttempts}...`, 'SETUP' ); await new Promise(resolve => setTimeout(resolve, delay)); } } /** * Initialize test data and ensure databases exist */ async function initializeTestData(): Promise { logger.info('🔧 Initializing test data...', 'SETUP'); try { // Check if databases exist, create if needed const databases = [ 'users', 'medications', 'settings', 'taken_doses', 'reminders', ]; for (const dbName of databases) { await ensureDatabaseExists(dbName); } logger.info('✅ Test data initialization completed', 'SETUP'); } catch (error) { logger.warn('⚠️ Test data initialization had issues:', 'SETUP', error); // Don't fail setup for database issues as the app should handle missing DBs } } /** * Ensure a database exists */ async function ensureDatabaseExists(dbName: string): Promise { const url = `http://localhost:5984/${dbName}`; try { const response = await fetch(url, { method: 'HEAD', headers: { Authorization: 'Basic ' + Buffer.from('admin:password').toString('base64'), }, }); if (response.status === 404) { // Database doesn't exist, create it await fetch(url, { method: 'PUT', headers: { Authorization: 'Basic ' + Buffer.from('admin:password').toString('base64'), 'Content-Type': 'application/json', }, }); logger.info(`📊 Created database: ${dbName}`, 'SETUP'); } else if (response.ok) { logger.info(`✅ Database exists: ${dbName}`, 'SETUP'); } } catch (error) { logger.warn( `⚠️ Could not verify/create database ${dbName}:`, 'SETUP', error ); } } /** * Verify admin user exists for testing */ async function verifyAdminUser(): Promise { logger.info('🔧 Verifying admin user exists...', 'SETUP'); try { const browser = await chromium.launch(); const context = await browser.newContext(); const page = await context.newPage(); // Navigate to the app await page.goto('http://localhost:8080'); // Wait for login form await page.waitForSelector('input[type="email"]', { timeout: 10000 }); // Try to login with admin credentials await page.fill('input[type="email"]', 'admin@localhost'); await page.fill('input[type="password"]', 'admin123!'); await page.click('button[type="submit"]'); // Check if login was successful try { await page.waitForSelector('h1:has-text("Medication Reminder")', { timeout: 15000, }); logger.info('✅ Admin user verified and functional', 'SETUP'); } catch (error) { logger.warn( '⚠️ Admin user may not exist or credentials may be incorrect', 'SETUP' ); logger.warn( ' Tests will attempt to create/verify admin user during execution', 'SETUP' ); if (error instanceof Error) { logger.debug(`Login verification error: ${error.message}`, 'SETUP'); } } await browser.close(); } catch (error) { logger.warn('⚠️ Could not verify admin user', 'SETUP'); if (error instanceof Error) { logger.debug(`Admin verification error: ${error.message}`, 'SETUP'); } // Don't fail setup, let individual tests handle this } } /** * Log environment information */ function logEnvironmentInfo(): void { logger.info('🌍 Environment Information:', 'SETUP'); logger.info(` Node.js: ${process.version}`, 'SETUP'); logger.info(` Platform: ${process.platform}`, 'SETUP'); logger.info(` NODE_ENV: ${process.env.NODE_ENV || 'not set'}`, 'SETUP'); logger.info(` CI: ${process.env.CI || 'false'}`, 'SETUP'); logger.info(` Frontend URL: http://localhost:8080`, 'SETUP'); logger.info(` CouchDB URL: http://localhost:5984`, 'SETUP'); } /** * Test database connectivity and return detailed status */ async function testDatabaseConnectivity(): Promise<{ connected: boolean; databases: string[]; errors: string[]; }> { const result = { connected: false, databases: [] as string[], errors: [] as string[], }; try { // Test basic connectivity const response = await fetch('http://localhost:5984/', { headers: { Authorization: 'Basic ' + Buffer.from('admin:password').toString('base64'), }, signal: AbortSignal.timeout(5000), }); if (response.ok) { result.connected = true; const info = await response.json(); logger.debug(`CouchDB version: ${info.version}`, 'SETUP'); // Get list of databases const dbResponse = await fetch('http://localhost:5984/_all_dbs', { headers: { Authorization: 'Basic ' + Buffer.from('admin:password').toString('base64'), }, }); if (dbResponse.ok) { result.databases = await dbResponse.json(); logger.debug( `Found databases: ${result.databases.join(', ')}`, 'SETUP' ); } } else { result.errors.push(`HTTP ${response.status}: ${response.statusText}`); } } catch (error) { if (error instanceof Error) { result.errors.push(error.message); } } return result; } /** * Perform comprehensive service diagnostics */ async function runServiceDiagnostics(): Promise { logger.info('🔍 Running comprehensive service diagnostics...', 'SETUP'); // Test frontend try { const frontendResponse = await fetch('http://localhost:8080', { signal: AbortSignal.timeout(5000), }); logger.info( `Frontend status: ${frontendResponse.status} ${frontendResponse.statusText}`, 'SETUP' ); } catch (error) { logger.warn( `Frontend not accessible: ${error instanceof Error ? error.message : 'Unknown error'}`, 'SETUP' ); } // Test database with detailed info const dbStatus = await testDatabaseConnectivity(); if (dbStatus.connected) { logger.info( `Database connected with ${dbStatus.databases.length} databases`, 'SETUP' ); } else { logger.warn( `Database connection failed: ${dbStatus.errors.join(', ')}`, 'SETUP' ); } // Test network connectivity try { const response = await fetch('http://localhost:8080/health', { signal: AbortSignal.timeout(3000), }); if (response.ok) { logger.info('Health endpoint accessible', 'SETUP'); } } catch { logger.debug('Health endpoint not available (this is optional)', 'SETUP'); } } // Execute setup export default async function (config: GlobalSetupConfig) { logEnvironmentInfo(); await runServiceDiagnostics(); await globalSetup(config); }