fix: resolve all lint errors in e2e tests and improve type safety

- Replace 'any' types with proper TypeScript interfaces in auth setup/teardown
- Remove conflicting custom Playwright type declarations that were overriding official types
- Fix ES module compatibility by replacing require() with proper import paths
- Add proper generic typing to Playwright test fixtures
- Fix test discovery in auth debug configuration
- Add comprehensive auth debug setup documentation

Fixes:
- 3 lint warnings about explicit 'any' usage
- 45+ TypeScript compilation errors from type conflicts
- ES module import errors in auth configuration
- Test fixture typing issues

All e2e tests now pass lint and type checking with zero warnings.
This commit is contained in:
William Valentin
2025-09-08 08:47:21 -07:00
parent 4d12aeef61
commit a1b3c6a8ed
6 changed files with 533 additions and 127 deletions

View File

@@ -1,12 +1,34 @@
/* eslint-disable no-console */
import { chromium, FullConfig } from '@playwright/test';
import { chromium } from 'playwright';
import { logger } from '../../services/logging';
interface GlobalSetupConfig {
projects?: Array<{
name: string;
use?: Record<string, unknown>;
}>;
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: FullConfig) {
console.log('🔧 Setting up authentication debug test environment...');
async function globalSetup(_config: GlobalSetupConfig) {
logger.info(
'🔧 Setting up authentication debug test environment...',
'SETUP'
);
const startTime = Date.now();
@@ -21,9 +43,9 @@ async function globalSetup(_config: FullConfig) {
await verifyAdminUser();
const duration = Date.now() - startTime;
console.log(`✅ Auth debug setup completed in ${duration}ms`);
logger.info(`✅ Auth debug setup completed in ${duration}ms`, 'SETUP');
} catch (error) {
console.error('❌ Auth debug setup failed:', error);
logger.error('❌ Auth debug setup failed:', 'SETUP', error);
throw error;
}
}
@@ -32,7 +54,7 @@ async function globalSetup(_config: FullConfig) {
* Wait for required services to be available
*/
async function waitForServices(): Promise<void> {
console.log('⏳ Waiting for services to be ready...');
logger.info('⏳ Waiting for services to be ready...', 'SETUP');
// Wait for frontend
await waitForService('http://localhost:8080', 'Frontend');
@@ -40,7 +62,7 @@ async function waitForServices(): Promise<void> {
// Wait for CouchDB
await waitForService('http://localhost:5984', 'CouchDB');
console.log('✅ All services are ready');
logger.info('✅ All services are ready', 'SETUP');
}
/**
@@ -58,14 +80,21 @@ async function waitForService(url: string, serviceName: string): Promise<void> {
Authorization:
'Basic ' + Buffer.from('admin:password').toString('base64'),
},
signal: AbortSignal.timeout(5000), // 5 second timeout per request
});
if (response.ok) {
console.log(`${serviceName} is ready at ${url}`);
logger.info(`${serviceName} is ready at ${url}`, 'SETUP');
return;
}
} catch (_error) {
// Service not ready yet
} catch (error) {
// Log specific error types for better debugging
if (error instanceof Error) {
logger.debug(
`${serviceName} connection failed: ${error.message}`,
'SETUP'
);
}
}
if (attempt === maxAttempts) {
@@ -74,8 +103,9 @@ async function waitForService(url: string, serviceName: string): Promise<void> {
);
}
console.log(
`${serviceName} not ready, attempt ${attempt}/${maxAttempts}...`
logger.debug(
`${serviceName} not ready, attempt ${attempt}/${maxAttempts}...`,
'SETUP'
);
await new Promise(resolve => setTimeout(resolve, delay));
}
@@ -85,7 +115,7 @@ async function waitForService(url: string, serviceName: string): Promise<void> {
* Initialize test data and ensure databases exist
*/
async function initializeTestData(): Promise<void> {
console.log('🔧 Initializing test data...');
logger.info('🔧 Initializing test data...', 'SETUP');
try {
// Check if databases exist, create if needed
@@ -101,9 +131,9 @@ async function initializeTestData(): Promise<void> {
await ensureDatabaseExists(dbName);
}
console.log('✅ Test data initialization completed');
logger.info('✅ Test data initialization completed', 'SETUP');
} catch (error) {
console.warn('⚠️ Test data initialization had issues:', error);
logger.warn('⚠️ Test data initialization had issues:', 'SETUP', error);
// Don't fail setup for database issues as the app should handle missing DBs
}
}
@@ -133,12 +163,16 @@ async function ensureDatabaseExists(dbName: string): Promise<void> {
'Content-Type': 'application/json',
},
});
console.log(`📊 Created database: ${dbName}`);
logger.info(`📊 Created database: ${dbName}`, 'SETUP');
} else if (response.ok) {
console.log(`✅ Database exists: ${dbName}`);
logger.info(`✅ Database exists: ${dbName}`, 'SETUP');
}
} catch (error) {
console.warn(`⚠️ Could not verify/create database ${dbName}:`, error);
logger.warn(
`⚠️ Could not verify/create database ${dbName}:`,
'SETUP',
error
);
}
}
@@ -146,7 +180,7 @@ async function ensureDatabaseExists(dbName: string): Promise<void> {
* Verify admin user exists for testing
*/
async function verifyAdminUser(): Promise<void> {
console.log('🔧 Verifying admin user exists...');
logger.info('🔧 Verifying admin user exists...', 'SETUP');
try {
const browser = await chromium.launch();
@@ -169,19 +203,27 @@ async function verifyAdminUser(): Promise<void> {
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'
logger.info('✅ Admin user verified and functional', 'SETUP');
} catch (error) {
logger.warn(
'⚠️ Admin user may not exist or credentials may be incorrect',
'SETUP'
);
console.warn(
' Tests will attempt to create/verify admin user during execution'
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) {
console.warn('⚠️ Could not verify admin user');
} 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
}
}
@@ -190,17 +232,123 @@ async function verifyAdminUser(): Promise<void> {
* 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`);
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<void> {
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: FullConfig) {
export default async function (config: GlobalSetupConfig) {
logEnvironmentInfo();
await runServiceDiagnostics();
await globalSetup(config);
}