feat: add comprehensive authentication debug test suite

Add automated authentication testing infrastructure:

- AUTH-DEBUG-GUIDE.md: Complete guide for auth debugging
- auth-debug.spec.ts: Comprehensive auth flow validation tests
- playwright.auth.config.ts: Specialized config with extended timeouts
- auth-debug-setup.ts: Global test environment setup
- auth-debug-teardown.ts: Test cleanup and environment reset

Features:
- Admin user validation and permissions testing
- Email format validation including localhost domains
- User registration and OAuth integration testing
- Database connectivity and session management
- Password security and error handling validation
- Cross-browser testing with mobile support
- Enhanced reporting and interactive debugging
- CI/CD integration with artifacts and JUnit reports

Replaces manual browser console debugging scripts with
automated, cross-browser E2E tests for better reliability
and maintainability.
This commit is contained in:
William Valentin
2025-09-08 01:48:26 -07:00
parent d0ae5eb17a
commit 4d12aeef61
5 changed files with 1560 additions and 0 deletions

View File

@@ -0,0 +1,206 @@
/* eslint-disable no-console */
import { chromium, FullConfig } from '@playwright/test';
/**
* Global setup for authentication debug tests
* Ensures services are running and database is properly initialized
*/
async function globalSetup(_config: FullConfig) {
console.log('🔧 Setting up authentication debug test environment...');
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;
console.log(`✅ Auth debug setup completed in ${duration}ms`);
} catch (error) {
console.error('❌ Auth debug setup failed:', error);
throw error;
}
}
/**
* Wait for required services to be available
*/
async function waitForServices(): Promise<void> {
console.log('⏳ Waiting for services to be ready...');
// Wait for frontend
await waitForService('http://localhost:8080', 'Frontend');
// Wait for CouchDB
await waitForService('http://localhost:5984', 'CouchDB');
console.log('✅ All services are ready');
}
/**
* Wait for a specific service to be available
*/
async function waitForService(url: string, serviceName: string): Promise<void> {
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'),
},
});
if (response.ok) {
console.log(`${serviceName} is ready at ${url}`);
return;
}
} catch (_error) {
// Service not ready yet
}
if (attempt === maxAttempts) {
throw new Error(
`${serviceName} not available at ${url} after ${maxAttempts} attempts`
);
}
console.log(
`${serviceName} not ready, attempt ${attempt}/${maxAttempts}...`
);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
/**
* Initialize test data and ensure databases exist
*/
async function initializeTestData(): Promise<void> {
console.log('🔧 Initializing test data...');
try {
// Check if databases exist, create if needed
const databases = [
'users',
'medications',
'settings',
'taken_doses',
'reminders',
];
for (const dbName of databases) {
await ensureDatabaseExists(dbName);
}
console.log('✅ Test data initialization completed');
} catch (error) {
console.warn('⚠️ Test data initialization had issues:', 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<void> {
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',
},
});
console.log(`📊 Created database: ${dbName}`);
} else if (response.ok) {
console.log(`✅ Database exists: ${dbName}`);
}
} catch (error) {
console.warn(`⚠️ Could not verify/create database ${dbName}:`, error);
}
}
/**
* Verify admin user exists for testing
*/
async function verifyAdminUser(): Promise<void> {
console.log('🔧 Verifying admin user exists...');
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,
});
console.log('✅ Admin user verified and functional');
} catch (_error) {
console.warn(
'⚠️ Admin user may not exist or credentials may be incorrect'
);
console.warn(
' Tests will attempt to create/verify admin user during execution'
);
}
await browser.close();
} catch (_error) {
console.warn('⚠️ Could not verify admin user');
// Don't fail setup, let individual tests handle this
}
}
/**
* Log environment information
*/
function logEnvironmentInfo(): void {
console.log('🌍 Environment Information:');
console.log(` Node.js: ${process.version}`);
console.log(` Platform: ${process.platform}`);
console.log(` NODE_ENV: ${process.env.NODE_ENV || 'not set'}`);
console.log(` CI: ${process.env.CI || 'false'}`);
console.log(` Frontend URL: http://localhost:8080`);
console.log(` CouchDB URL: http://localhost:5984`);
}
// Execute setup
export default async function (config: FullConfig) {
logEnvironmentInfo();
await globalSetup(config);
}