Files
rxminder/tests/e2e/auth-debug-teardown.ts
William Valentin a1b3c6a8ed 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.
2025-09-08 08:47:21 -07:00

404 lines
11 KiB
TypeScript

/* eslint-disable no-console */
interface GlobalTeardownConfig {
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 teardown for authentication debug tests
* Cleans up test environment and generates summary report
*/
async function globalTeardown(_config: GlobalTeardownConfig) {
console.log('🧹 Starting authentication debug test teardown...');
const startTime = Date.now();
try {
// Clean up test data
await cleanupTestData();
// Generate test summary
await generateTestSummary();
// Clean up test artifacts
await cleanupTestArtifacts();
// Log final status
await logFinalStatus();
const duration = Date.now() - startTime;
console.log(`✅ Auth debug teardown completed in ${duration}ms`);
} catch (error) {
console.error('❌ Auth debug teardown failed:', error);
// Don't throw error to avoid masking test failures
}
}
/**
* Clean up test data created during tests
*/
async function cleanupTestData(): Promise<void> {
console.log('🗑️ Cleaning up test data...');
try {
// Clean up test users created during the test run
await cleanupTestUsers();
// Clean up any temporary files
await cleanupTempFiles();
console.log('✅ Test data cleanup completed');
} catch (error) {
console.warn('⚠️ Test data cleanup had issues:', error);
}
}
/**
* Remove test users created during testing
*/
async function cleanupTestUsers(): Promise<void> {
console.log('👥 Cleaning up test users...');
try {
// Get list of databases
const response = await fetch('http://localhost:5984/_all_dbs', {
headers: {
Authorization:
'Basic ' + Buffer.from('admin:password').toString('base64'),
},
});
if (!response.ok) {
console.warn('⚠️ Could not access CouchDB for user cleanup');
return;
}
// Look for users database
const databases = await response.json();
if (databases.includes('users')) {
await cleanupUsersFromDatabase();
}
console.log('✅ Test users cleanup completed');
} catch (error) {
console.warn('⚠️ Could not cleanup test users:', error);
}
}
/**
* Clean up test users from the users database
*/
async function cleanupUsersFromDatabase(): Promise<void> {
try {
// Get all users
const response = await fetch(
'http://localhost:5984/users/_all_docs?include_docs=true',
{
headers: {
Authorization:
'Basic ' + Buffer.from('admin:password').toString('base64'),
},
}
);
if (!response.ok) {
return;
}
const data = await response.json();
const testUserPattern =
/debug-test.*@localhost|test.*@localhost|strong.*@localhost/;
// Find and delete test users
for (const row of data.rows) {
if (row.doc && row.doc.email && testUserPattern.test(row.doc.email)) {
await deleteTestUser(row.doc._id, row.doc._rev);
}
}
} catch (error) {
console.warn('⚠️ Error cleaning users database:', error);
}
}
/**
* Delete a specific test user
*/
async function deleteTestUser(userId: string, rev: string): Promise<void> {
try {
const response = await fetch(
`http://localhost:5984/users/${userId}?rev=${rev}`,
{
method: 'DELETE',
headers: {
Authorization:
'Basic ' + Buffer.from('admin:password').toString('base64'),
},
}
);
if (response.ok) {
console.log(`🗑️ Deleted test user: ${userId}`);
}
} catch (error) {
console.warn(`⚠️ Could not delete test user ${userId}:`, error);
}
}
/**
* Clean up temporary files created during tests
*/
async function cleanupTempFiles(): Promise<void> {
console.log('📂 Cleaning up temporary files...');
try {
const fs = await import('fs').then(m => m.promises);
const path = await import('path');
// Clean up any temporary screenshots or videos from failed tests
const tempDirs = [
'test-results-auth',
'playwright-report-auth',
'screenshots-temp',
'videos-temp',
];
for (const dir of tempDirs) {
try {
const fullPath = path.join(process.cwd(), dir);
await fs.access(fullPath);
// Directory exists, but don't delete it as it may contain useful debug info
console.log(`📁 Preserved test artifacts in: ${dir}`);
} catch {
// Directory doesn't exist, which is fine
}
}
console.log('✅ Temporary files cleanup completed');
} catch (error) {
console.warn('⚠️ Temporary files cleanup had issues:', error);
}
}
/**
* Generate test summary report
*/
async function generateTestSummary(): Promise<void> {
console.log('📊 Generating test summary...');
try {
const fs = await import('fs').then(m => m.promises);
const path = await import('path');
// Check if test results exist
const reportPath = path.join(process.cwd(), 'playwright-report-auth.json');
try {
await fs.access(reportPath);
const reportData = await fs.readFile(reportPath, 'utf-8');
const report = JSON.parse(reportData);
// Generate summary
const summary = {
timestamp: new Date().toISOString(),
testType: 'Authentication Debug',
totalTests:
report.suites?.reduce(
(total: number, suite: { specs?: unknown[] }) =>
total + (suite.specs?.length || 0),
0
) || 0,
passedTests: 0,
failedTests: 0,
skippedTests: 0,
duration: report.stats?.duration || 0,
environment: {
nodeVersion: process.version,
platform: process.platform,
ci: !!process.env.CI,
},
};
// Count test results
if (report.suites) {
for (const suite of report.suites) {
if (suite.specs) {
for (const spec of suite.specs) {
if (spec.tests) {
for (const test of spec.tests) {
switch (test.status) {
case 'passed':
summary.passedTests++;
break;
case 'failed':
summary.failedTests++;
break;
case 'skipped':
summary.skippedTests++;
break;
}
}
}
}
}
}
}
// Save summary
const summaryPath = path.join(process.cwd(), 'auth-debug-summary.json');
await fs.writeFile(summaryPath, JSON.stringify(summary, null, 2));
console.log('📈 Test Summary:');
console.log(` Total Tests: ${summary.totalTests}`);
console.log(` Passed: ${summary.passedTests}`);
console.log(` Failed: ${summary.failedTests}`);
console.log(` Skipped: ${summary.skippedTests}`);
console.log(` Duration: ${summary.duration}ms`);
console.log(` Summary saved to: auth-debug-summary.json`);
} catch (_error) {
console.warn('⚠️ Could not find test report for summary generation');
}
console.log('✅ Test summary generation completed');
} catch (error) {
console.warn('⚠️ Test summary generation had issues:', error);
}
}
/**
* Clean up test artifacts but preserve important debug information
*/
async function cleanupTestArtifacts(): Promise<void> {
console.log('🧹 Managing test artifacts...');
try {
const fs = await import('fs').then(m => m.promises);
const path = await import('path');
// Archive old test results if they exist
const testResultsDir = 'test-results-auth';
const archiveDir = 'test-results-archive';
try {
await fs.access(testResultsDir);
// Create archive directory if it doesn't exist
try {
await fs.mkdir(archiveDir, { recursive: true });
} catch {
// Directory might already exist
}
// Move current results to archive with timestamp
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const archivePath = path.join(archiveDir, `auth-debug-${timestamp}`);
await fs.rename(testResultsDir, archivePath);
console.log(`📦 Archived test results to: ${archivePath}`);
} catch {
// No test results to archive
}
console.log('✅ Test artifacts management completed');
} catch (error) {
console.warn('⚠️ Test artifacts cleanup had issues:', error);
}
}
/**
* Log final status and cleanup recommendations
*/
async function logFinalStatus(): Promise<void> {
console.log('📋 Auth Debug Test Session Complete');
console.log('');
console.log('📁 Available Reports:');
console.log(' • HTML Report: playwright-report-auth/index.html');
console.log(' • JSON Report: playwright-report-auth.json');
console.log(' • Summary: auth-debug-summary.json');
console.log('');
console.log('🔧 Debug Commands:');
console.log(
' • View HTML report: npx playwright show-report playwright-report-auth'
);
console.log(
' • Run specific test: bunx playwright test auth-debug.spec.ts --debug'
);
console.log(' • Interactive mode: make test-e2e-ui');
console.log('');
console.log('🧹 Cleanup Status:');
console.log(' • Test users: Cleaned up');
console.log(' • Temporary files: Preserved for debugging');
console.log(' • Test artifacts: Archived');
console.log('');
// Check for failed tests and provide guidance
try {
const fs = await import('fs').then(m => m.promises);
const path = await import('path');
const summaryPath = path.join(process.cwd(), 'auth-debug-summary.json');
const summaryData = await fs.readFile(summaryPath, 'utf-8');
const summary = JSON.parse(summaryData);
if (summary.failedTests > 0) {
console.log('⚠️ Test Failures Detected:');
console.log(` ${summary.failedTests} test(s) failed`);
console.log(' Check the HTML report for detailed failure information');
console.log(' Use --debug flag to interactively debug failing tests');
console.log('');
} else if (summary.passedTests > 0) {
console.log('✅ All Authentication Tests Passed!');
console.log(' Authentication flows are working correctly');
console.log('');
}
} catch {
// Summary file might not exist
}
console.log('🎯 Next Steps:');
console.log(' • Review test reports for any issues');
console.log(' • Update authentication tests as features evolve');
console.log(' • Run tests regularly in CI/CD pipeline');
console.log('');
}
/**
* Emergency cleanup in case of critical errors
*/
async function emergencyCleanup(): Promise<void> {
console.log('🚨 Running emergency cleanup...');
try {
// Force cleanup of any hanging processes or connections
// This is a safety net for test environments
console.log('✅ Emergency cleanup completed');
} catch (error) {
console.error('❌ Emergency cleanup failed:', error);
}
}
// Execute teardown
export default async function (config: GlobalTeardownConfig) {
try {
await globalTeardown(config);
} catch (_error) {
console.error('❌ Teardown failed, running emergency cleanup...');
await emergencyCleanup();
}
}