## Major Enhancements ### 🏗️ Architecture & Infrastructure - Implement comprehensive Docker testing infrastructure with hermetic environment - Add Forgejo Actions CI/CD pipeline for automated deployments - Create Page Object Model (POM) testing architecture reducing test duplication by 90% - Establish security-first development patterns with input validation and output escaping ### 🧪 Testing Framework Modernization - Migrate 146+ tests from 80 duplicate files to centralized architecture - Add comprehensive E2E test suites for all user roles and workflows - Implement WordPress error detection with automatic site health monitoring - Create robust browser lifecycle management with proper cleanup ### 📚 Documentation & Guides - Add comprehensive development best practices guide - Create detailed administrator setup documentation - Establish user guides for trainers and master trainers - Document security incident reports and migration guides ### 🔧 Core Plugin Features - Enhance trainer profile management with certification system - Improve find trainer functionality with advanced filtering - Strengthen master trainer area with content management - Add comprehensive venue and organizer management ### 🛡️ Security & Reliability - Implement security-first patterns throughout codebase - Add comprehensive input validation and output escaping - Create secure credential management system - Establish proper WordPress role-based access control ### 🎯 WordPress Integration - Strengthen singleton pattern implementation across all classes - Enhance template hierarchy with proper WordPress integration - Improve page manager with hierarchical URL structure - Add comprehensive shortcode and menu system ### 🔍 Developer Experience - Add extensive debugging and troubleshooting tools - Create comprehensive test data seeding scripts - Implement proper error handling and logging - Establish consistent code patterns and standards ### 📊 Performance & Optimization - Optimize database queries and caching strategies - Improve asset loading and script management - Enhance template rendering performance - Streamline user experience across all interfaces 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			309 lines
		
	
	
		
			No EOL
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			No EOL
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| #!/usr/bin/env node
 | ||
| 
 | ||
| /**
 | ||
|  * Comprehensive Organizer Management Test
 | ||
|  * Tests the complete organizer management workflow including authentication
 | ||
|  */
 | ||
| 
 | ||
| const { chromium } = require('playwright');
 | ||
| 
 | ||
| // Configuration
 | ||
| const config = {
 | ||
|     BASE_URL: process.env.BASE_URL || 'http://localhost:8080',
 | ||
|     HEADLESS: process.env.HEADLESS !== 'false',
 | ||
|     USERNAME: process.env.TEST_USERNAME || 'testtrainer',
 | ||
|     PASSWORD: process.env.TEST_PASSWORD || 'TestPass123!'
 | ||
| };
 | ||
| 
 | ||
| async function runComprehensiveOrganizerTest() {
 | ||
|     console.log('🧪 Comprehensive Organizer Management Test');
 | ||
|     console.log('==========================================\n');
 | ||
|     
 | ||
|     const browser = await chromium.launch({ 
 | ||
|         headless: config.HEADLESS,
 | ||
|         args: ['--no-sandbox', '--disable-setuid-sandbox']
 | ||
|     });
 | ||
|     
 | ||
|     const page = await browser.newPage();
 | ||
|     
 | ||
|     let testResults = {
 | ||
|         passed: 0,
 | ||
|         failed: 0,
 | ||
|         skipped: 0,
 | ||
|         details: []
 | ||
|     };
 | ||
| 
 | ||
|     try {
 | ||
|         // Test 1: Login as trainer
 | ||
|         console.log('1. Testing trainer login...');
 | ||
|         
 | ||
|         try {
 | ||
|             await page.goto(`${config.BASE_URL}/community-login/`);
 | ||
|             await page.waitForLoadState('networkidle');
 | ||
|             
 | ||
|             // Check if login form exists
 | ||
|             const loginForm = await page.locator('#loginform');
 | ||
|             if (await loginForm.isVisible()) {
 | ||
|                 await page.fill('#user_login', config.USERNAME);
 | ||
|                 await page.fill('#user_pass', config.PASSWORD);
 | ||
|                 await page.click('#wp-submit');
 | ||
|                 await page.waitForLoadState('networkidle');
 | ||
|                 
 | ||
|                 // Check if redirected to trainer dashboard
 | ||
|                 const currentUrl = page.url();
 | ||
|                 if (currentUrl.includes('/trainer/dashboard/')) {
 | ||
|                     console.log('   ✅ Login successful');
 | ||
|                     testResults.passed++;
 | ||
|                     testResults.details.push('Login: ✅ Successful');
 | ||
|                 } else {
 | ||
|                     console.log('   ❌ Login failed - not redirected to dashboard');
 | ||
|                     testResults.failed++;
 | ||
|                     testResults.details.push('Login: ❌ Not redirected to dashboard');
 | ||
|                 }
 | ||
|             } else {
 | ||
|                 console.log('   ⏭️ Login form not found - may already be logged in');
 | ||
|                 testResults.skipped++;
 | ||
|                 testResults.details.push('Login: ⏭️ Form not found');
 | ||
|             }
 | ||
|         } catch (error) {
 | ||
|             console.log(`   ❌ Login error: ${error.message}`);
 | ||
|             testResults.failed++;
 | ||
|             testResults.details.push(`Login: ❌ Error - ${error.message}`);
 | ||
|         }
 | ||
|         
 | ||
|         // Test 2: Access organizer list page
 | ||
|         console.log('\n2. Testing organizer list page access...');
 | ||
|         
 | ||
|         try {
 | ||
|             await page.goto(`${config.BASE_URL}/trainer/organizer/list/`);
 | ||
|             await page.waitForLoadState('networkidle');
 | ||
|             
 | ||
|             const response = await page.goto(`${config.BASE_URL}/trainer/organizer/list/`, { waitUntil: 'networkidle' });
 | ||
|             const status = response.status();
 | ||
|             
 | ||
|             if (status === 200) {
 | ||
|                 const pageTitle = await page.locator('h1').textContent();
 | ||
|                 if (pageTitle && pageTitle.includes('Organizers')) {
 | ||
|                     console.log('   ✅ Organizer list page accessible');
 | ||
|                     testResults.passed++;
 | ||
|                     testResults.details.push('Organizer List: ✅ Accessible');
 | ||
|                 } else {
 | ||
|                     console.log('   ❌ Page accessible but title incorrect');
 | ||
|                     testResults.failed++;
 | ||
|                     testResults.details.push('Organizer List: ❌ Incorrect title');
 | ||
|                 }
 | ||
|             } else {
 | ||
|                 console.log(`   ❌ Organizer list page returned ${status}`);
 | ||
|                 testResults.failed++;
 | ||
|                 testResults.details.push(`Organizer List: ❌ Status ${status}`);
 | ||
|             }
 | ||
|         } catch (error) {
 | ||
|             console.log(`   ❌ Error accessing organizer list: ${error.message}`);
 | ||
|             testResults.failed++;
 | ||
|             testResults.details.push(`Organizer List: ❌ ${error.message}`);
 | ||
|         }
 | ||
|         
 | ||
|         // Test 3: Access organizer manage page
 | ||
|         console.log('\n3. Testing organizer manage page access...');
 | ||
|         
 | ||
|         try {
 | ||
|             await page.goto(`${config.BASE_URL}/trainer/organizer/manage/`);
 | ||
|             await page.waitForLoadState('networkidle');
 | ||
|             
 | ||
|             const response = await page.goto(`${config.BASE_URL}/trainer/organizer/manage/`, { waitUntil: 'networkidle' });
 | ||
|             const status = response.status();
 | ||
|             
 | ||
|             if (status === 200) {
 | ||
|                 const pageTitle = await page.locator('h1').textContent();
 | ||
|                 if (pageTitle && (pageTitle.includes('Create') || pageTitle.includes('Organizer'))) {
 | ||
|                     console.log('   ✅ Organizer manage page accessible');
 | ||
|                     testResults.passed++;
 | ||
|                     testResults.details.push('Organizer Manage: ✅ Accessible');
 | ||
|                 } else {
 | ||
|                     console.log('   ❌ Page accessible but title incorrect');
 | ||
|                     testResults.failed++;
 | ||
|                     testResults.details.push('Organizer Manage: ❌ Incorrect title');
 | ||
|                 }
 | ||
|             } else {
 | ||
|                 console.log(`   ❌ Organizer manage page returned ${status}`);
 | ||
|                 testResults.failed++;
 | ||
|                 testResults.details.push(`Organizer Manage: ❌ Status ${status}`);
 | ||
|             }
 | ||
|         } catch (error) {
 | ||
|             console.log(`   ❌ Error accessing organizer manage: ${error.message}`);
 | ||
|             testResults.failed++;
 | ||
|             testResults.details.push(`Organizer Manage: ❌ ${error.message}`);
 | ||
|         }
 | ||
|         
 | ||
|         // Test 4: Check shortcode processing
 | ||
|         console.log('\n4. Testing shortcode processing...');
 | ||
|         
 | ||
|         try {
 | ||
|             const content = await page.content();
 | ||
|             const hasUnprocessedShortcode = content.includes('[hvac_trainer_organizer_manage]');
 | ||
|             const hasFormContainer = content.includes('hvac-organizer-manage');
 | ||
|             
 | ||
|             if (!hasUnprocessedShortcode && hasFormContainer) {
 | ||
|                 console.log('   ✅ Shortcode processed correctly');
 | ||
|                 testResults.passed++;
 | ||
|                 testResults.details.push('Shortcode: ✅ Processed correctly');
 | ||
|             } else if (hasUnprocessedShortcode) {
 | ||
|                 console.log('   ❌ Shortcode not processed');
 | ||
|                 testResults.failed++;
 | ||
|                 testResults.details.push('Shortcode: ❌ Not processed');
 | ||
|             } else {
 | ||
|                 console.log('   ❌ Form container not found');
 | ||
|                 testResults.failed++;
 | ||
|                 testResults.details.push('Shortcode: ❌ Form container not found');
 | ||
|             }
 | ||
|         } catch (error) {
 | ||
|             console.log(`   ❌ Error checking shortcode: ${error.message}`);
 | ||
|             testResults.failed++;
 | ||
|             testResults.details.push(`Shortcode: ❌ ${error.message}`);
 | ||
|         }
 | ||
|         
 | ||
|         // Test 5: Check form elements
 | ||
|         console.log('\n5. Testing form elements...');
 | ||
|         
 | ||
|         try {
 | ||
|             const form = await page.locator('#hvac-organizer-form');
 | ||
|             
 | ||
|             if (await form.isVisible()) {
 | ||
|                 console.log('   ✅ Main form visible');
 | ||
|                 
 | ||
|                 // Check required fields
 | ||
|                 const requiredFields = ['org_name', 'hq_city', 'hq_state', 'hq_country'];
 | ||
|                 let fieldsFound = 0;
 | ||
|                 
 | ||
|                 for (const field of requiredFields) {
 | ||
|                     const fieldElement = await page.locator(`#${field}`);
 | ||
|                     if (await fieldElement.isVisible()) {
 | ||
|                         fieldsFound++;
 | ||
|                     }
 | ||
|                 }
 | ||
|                 
 | ||
|                 if (fieldsFound === requiredFields.length) {
 | ||
|                     console.log('   ✅ All required fields present');
 | ||
|                     testResults.passed++;
 | ||
|                     testResults.details.push('Form Fields: ✅ All present');
 | ||
|                 } else {
 | ||
|                     console.log(`   ❌ Only ${fieldsFound}/${requiredFields.length} required fields found`);
 | ||
|                     testResults.failed++;
 | ||
|                     testResults.details.push(`Form Fields: ❌ Only ${fieldsFound}/${requiredFields.length} found`);
 | ||
|                 }
 | ||
|             } else {
 | ||
|                 console.log('   ❌ Main form not visible');
 | ||
|                 testResults.failed++;
 | ||
|                 testResults.details.push('Form Fields: ❌ Form not visible');
 | ||
|             }
 | ||
|         } catch (error) {
 | ||
|             console.log(`   ❌ Error checking form elements: ${error.message}`);
 | ||
|             testResults.failed++;
 | ||
|             testResults.details.push(`Form Elements: ❌ ${error.message}`);
 | ||
|         }
 | ||
|         
 | ||
|         // Test 6: Check assets loading
 | ||
|         console.log('\n6. Testing assets loading...');
 | ||
|         
 | ||
|         try {
 | ||
|             const content = await page.content();
 | ||
|             const cssLoaded = content.includes('hvac-organizers.css') || content.includes('hvac-organizers-style');
 | ||
|             const jsLoaded = content.includes('hvac-organizers.js');
 | ||
|             
 | ||
|             if (cssLoaded && jsLoaded) {
 | ||
|                 console.log('   ✅ CSS and JS assets loaded');
 | ||
|                 testResults.passed++;
 | ||
|                 testResults.details.push('Assets: ✅ CSS and JS loaded');
 | ||
|             } else if (cssLoaded) {
 | ||
|                 console.log('   ⚠️  CSS loaded but JS missing');
 | ||
|                 testResults.failed++;
 | ||
|                 testResults.details.push('Assets: ❌ JS missing');
 | ||
|             } else if (jsLoaded) {
 | ||
|                 console.log('   ⚠️  JS loaded but CSS missing');
 | ||
|                 testResults.failed++;
 | ||
|                 testResults.details.push('Assets: ❌ CSS missing');
 | ||
|             } else {
 | ||
|                 console.log('   ❌ Neither CSS nor JS loaded');
 | ||
|                 testResults.failed++;
 | ||
|                 testResults.details.push('Assets: ❌ Neither CSS nor JS loaded');
 | ||
|             }
 | ||
|         } catch (error) {
 | ||
|             console.log(`   ❌ Error checking assets: ${error.message}`);
 | ||
|             testResults.failed++;
 | ||
|             testResults.details.push(`Assets: ❌ ${error.message}`);
 | ||
|         }
 | ||
|         
 | ||
|         // Test 7: Check navigation
 | ||
|         console.log('\n7. Testing navigation elements...');
 | ||
|         
 | ||
|         try {
 | ||
|             const hasNavigation = await page.locator('.hvac-menu, .trainer-menu').isVisible();
 | ||
|             const hasBreadcrumbs = await page.locator('.hvac-breadcrumb, .breadcrumb').isVisible();
 | ||
|             
 | ||
|             let navScore = 0;
 | ||
|             if (hasNavigation) {
 | ||
|                 console.log('   ✅ Navigation menu found');
 | ||
|                 navScore++;
 | ||
|             }
 | ||
|             if (hasBreadcrumbs) {
 | ||
|                 console.log('   ✅ Breadcrumbs found');
 | ||
|                 navScore++;
 | ||
|             }
 | ||
|             
 | ||
|             if (navScore === 2) {
 | ||
|                 testResults.passed++;
 | ||
|                 testResults.details.push('Navigation: ✅ Menu and breadcrumbs present');
 | ||
|             } else if (navScore === 1) {
 | ||
|                 testResults.passed++;
 | ||
|                 testResults.details.push('Navigation: ⚠️ Partial navigation present');
 | ||
|             } else {
 | ||
|                 testResults.failed++;
 | ||
|                 testResults.details.push('Navigation: ❌ No navigation elements found');
 | ||
|             }
 | ||
|         } catch (error) {
 | ||
|             console.log(`   ❌ Error checking navigation: ${error.message}`);
 | ||
|             testResults.failed++;
 | ||
|             testResults.details.push(`Navigation: ❌ ${error.message}`);
 | ||
|         }
 | ||
|         
 | ||
|     } catch (globalError) {
 | ||
|         console.log(`💥 Global test error: ${globalError.message}`);
 | ||
|         testResults.failed++;
 | ||
|         testResults.details.push(`Global: ❌ ${globalError.message}`);
 | ||
|     } finally {
 | ||
|         await browser.close();
 | ||
|     }
 | ||
|     
 | ||
|     // Print results
 | ||
|     console.log('\n📊 Test Results Summary');
 | ||
|     console.log('=======================');
 | ||
|     console.log(`✅ Passed: ${testResults.passed}`);
 | ||
|     console.log(`❌ Failed: ${testResults.failed}`);
 | ||
|     console.log(`⏭️  Skipped: ${testResults.skipped}`);
 | ||
|     
 | ||
|     const total = testResults.passed + testResults.failed;
 | ||
|     const successRate = total > 0 ? Math.round((testResults.passed / total) * 100) : 0;
 | ||
|     console.log(`📈 Success Rate: ${successRate}%`);
 | ||
|     
 | ||
|     console.log('\n📋 Detailed Results:');
 | ||
|     testResults.details.forEach(detail => {
 | ||
|         console.log(`   ${detail}`);
 | ||
|     });
 | ||
|     
 | ||
|     if (successRate >= 80) {
 | ||
|         console.log('\n🎉 Organizer management functionality is working well!');
 | ||
|     } else if (successRate >= 50) {
 | ||
|         console.log('\n⚠️  Organizer management has some issues but basic functionality works.');
 | ||
|     } else {
 | ||
|         console.log('\n❌ Organizer management needs significant fixes.');
 | ||
|     }
 | ||
|     
 | ||
|     return testResults;
 | ||
| }
 | ||
| 
 | ||
| // Run the test
 | ||
| if (require.main === module) {
 | ||
|     runComprehensiveOrganizerTest().catch(console.error);
 | ||
| }
 | ||
| 
 | ||
| module.exports = runComprehensiveOrganizerTest; |