/** * Global Setup - Runs once before all tests * * This setup ensures a clean test environment by: * 1. Cleaning up any orphaned test data from previous runs * 2. Verifying the application is accessible * 3. Performing emergency ACL reset to prevent deadlock from previous failed runs */ import { request, APIRequestContext } from '@playwright/test'; import { existsSync } from 'fs'; import { TestDataManager } from './utils/TestDataManager'; import { STORAGE_STATE } from './constants'; /** * Get the base URL for the application */ function getBaseURL(): string { return process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:8080'; } async function globalSetup(): Promise { console.log('\n๐Ÿงน Running global test setup...'); const baseURL = getBaseURL(); console.log(`๐Ÿ“ Base URL: ${baseURL}`); // Pre-auth security reset attempt (crash protection failsafe) // This attempts to disable security modules BEFORE auth, in case a previous run crashed // with security enabled blocking the auth endpoint. const preAuthContext = await request.newContext({ baseURL }); try { await emergencySecurityReset(preAuthContext); } catch (e) { console.log('Pre-auth security reset skipped (may require auth)'); } await preAuthContext.dispose(); // Create a request context const requestContext = await request.newContext({ baseURL, extraHTTPHeaders: { Accept: 'application/json', 'Content-Type': 'application/json', }, }); try { // Verify the application is accessible console.log('๐Ÿ” Checking application health...'); const healthResponse = await requestContext.get('/api/v1/health', { timeout: 10000, }).catch(() => null); if (!healthResponse || !healthResponse.ok()) { console.warn('โš ๏ธ Health check failed - application may not be ready'); // Try the base URL as fallback const baseResponse = await requestContext.get('/').catch(() => null); if (!baseResponse || !baseResponse.ok()) { console.error('โŒ Application is not accessible at', baseURL); throw new Error(`Application not accessible at ${baseURL}`); } } console.log('โœ… Application is accessible'); // Clean up orphaned test data from previous runs console.log('๐Ÿ—‘๏ธ Cleaning up orphaned test data...'); const cleanupResults = await TestDataManager.forceCleanupAll(requestContext); if ( cleanupResults.proxyHosts > 0 || cleanupResults.accessLists > 0 || cleanupResults.dnsProviders > 0 || cleanupResults.certificates > 0 ) { console.log(' Cleaned up:'); if (cleanupResults.proxyHosts > 0) { console.log(` - ${cleanupResults.proxyHosts} proxy hosts`); } if (cleanupResults.accessLists > 0) { console.log(` - ${cleanupResults.accessLists} access lists`); } if (cleanupResults.dnsProviders > 0) { console.log(` - ${cleanupResults.dnsProviders} DNS providers`); } if (cleanupResults.certificates > 0) { console.log(` - ${cleanupResults.certificates} certificates`); } } else { console.log(' No orphaned test data found'); } console.log('โœ… Global setup complete\n'); } catch (error) { console.error('โŒ Global setup failed:', error); throw error; } finally { await requestContext.dispose(); } // Emergency security reset with auth (more complete) if (existsSync(STORAGE_STATE)) { const authenticatedContext = await request.newContext({ baseURL, storageState: STORAGE_STATE, }); try { await emergencySecurityReset(authenticatedContext); console.log('โœ“ Authenticated security reset complete'); } catch (error) { console.warn('โš ๏ธ Authenticated security reset failed:', error); } await authenticatedContext.dispose(); } else { console.log('โญ๏ธ Skipping authenticated security reset (no auth state file)'); } } /** * Perform emergency security reset to disable ALL security modules. * This prevents deadlock if a previous test run left any security module enabled. * * USES THE CORRECT ENDPOINT: /api/v1/emergency/security-reset * This endpoint bypasses all security checks when a valid emergency token is provided. */ async function emergencySecurityReset(requestContext: APIRequestContext): Promise { console.log('๐Ÿ”“ Performing emergency security reset...'); const emergencyToken = 'test-emergency-token-for-e2e-32chars'; try { // Use the CORRECT endpoint: /api/v1/emergency/security-reset // This endpoint bypasses ACL, WAF, and all security checks const response = await requestContext.post('/api/v1/emergency/security-reset', { headers: { 'X-Emergency-Token': emergencyToken, }, }); if (!response.ok()) { const body = await response.text(); console.error(` โŒ Emergency reset failed: ${response.status()} ${body}`); throw new Error(`Emergency reset returned ${response.status()}`); } const result = await response.json(); console.log(' โœ… Emergency reset successful'); console.log(` โœ… Disabled modules: ${result.disabled_modules?.join(', ')}`); } catch (e) { console.error(` โŒ Emergency reset error: ${e}`); throw e; } // Wait for settings to propagate console.log(' โณ Waiting for security reset to propagate...'); await new Promise(resolve => setTimeout(resolve, 2000)); console.log(' โœ… Security reset complete'); } export default globalSetup;