## 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>
		
			
				
	
	
		
			351 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			351 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | ||
|  * Master Trainer Layout Fix Verification Test
 | ||
|  * 
 | ||
|  * Tests that Master Trainer pages now have proper single-column layouts
 | ||
|  * and navigation/breadcrumbs in both Safari and non-Safari browsers.
 | ||
|  * 
 | ||
|  * This test specifically validates the fix for Safari CSS loading issues
 | ||
|  * that were preventing hvac-page-templates.css from loading.
 | ||
|  */
 | ||
| 
 | ||
| const { chromium, webkit } = require('playwright');
 | ||
| 
 | ||
| /**
 | ||
|  * Test Configuration
 | ||
|  */
 | ||
| const TEST_CONFIG = {
 | ||
|     baseUrl: process.env.BASE_URL || 'http://localhost:8080',
 | ||
|     timeout: 30000,
 | ||
|     credentials: {
 | ||
|         master_trainer: {
 | ||
|             username: 'test_master',
 | ||
|             password: 'test_password_123'
 | ||
|         }
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| /**
 | ||
|  * Master Trainer pages to test
 | ||
|  */
 | ||
| const MASTER_TRAINER_PAGES = [
 | ||
|     {
 | ||
|         name: 'Google Sheets Integration',
 | ||
|         path: '/master-trainer/google-sheets/',
 | ||
|         expectedTitle: 'Google Sheets Integration',
 | ||
|         layoutChecks: ['single-column', 'navigation', 'breadcrumbs']
 | ||
|     },
 | ||
|     {
 | ||
|         name: 'Announcements',
 | ||
|         path: '/master-trainer/announcements/',
 | ||
|         expectedTitle: 'Announcements',
 | ||
|         layoutChecks: ['single-column', 'navigation', 'breadcrumbs']
 | ||
|     },
 | ||
|     {
 | ||
|         name: 'Pending Approvals',
 | ||
|         path: '/master-trainer/pending-approvals/',
 | ||
|         expectedTitle: 'Pending Approvals',
 | ||
|         layoutChecks: ['single-column', 'navigation', 'breadcrumbs']
 | ||
|     },
 | ||
|     {
 | ||
|         name: 'All Trainers',
 | ||
|         path: '/master-trainer/trainers/',
 | ||
|         expectedTitle: 'All Trainers',
 | ||
|         layoutChecks: ['single-column', 'navigation', 'breadcrumbs']
 | ||
|     }
 | ||
| ];
 | ||
| 
 | ||
| /**
 | ||
|  * Login helper function
 | ||
|  */
 | ||
| async function loginAsMasterTrainer(page) {
 | ||
|     console.log('🔐 Logging in as master trainer...');
 | ||
|     
 | ||
|     await page.goto(`${TEST_CONFIG.baseUrl}/training-login/`);
 | ||
|     await page.waitForSelector('#user_login', { timeout: 10000 });
 | ||
|     
 | ||
|     await page.fill('#user_login', TEST_CONFIG.credentials.master_trainer.username);
 | ||
|     await page.fill('#user_pass', TEST_CONFIG.credentials.master_trainer.password);
 | ||
|     await page.click('#wp-submit');
 | ||
|     
 | ||
|     // Wait for successful login
 | ||
|     await page.waitForURL(/dashboard|master-trainer/, { timeout: 15000 });
 | ||
|     console.log('✅ Successfully logged in as master trainer');
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * Check if page has single-column layout
 | ||
|  */
 | ||
| async function checkSingleColumnLayout(page, pageName) {
 | ||
|     console.log(`  📐 Checking single-column layout for ${pageName}...`);
 | ||
|     
 | ||
|     // Check that Master Trainer specific CSS fixes are applied
 | ||
|     const gridColumns = await page.evaluate(() => {
 | ||
|         const elements = document.querySelectorAll('.hvac-grid-2, .hvac-grid-3, .hvac-grid-4, .sync-options, .hvac-stats-tiles, .hvac-trainers-grid');
 | ||
|         const columnCounts = [];
 | ||
|         
 | ||
|         elements.forEach(element => {
 | ||
|             const computedStyle = window.getComputedStyle(element);
 | ||
|             const gridColumns = computedStyle.getPropertyValue('grid-template-columns');
 | ||
|             columnCounts.push(gridColumns);
 | ||
|         });
 | ||
|         
 | ||
|         return columnCounts;
 | ||
|     });
 | ||
|     
 | ||
|     // Check if any elements still have multi-column layouts
 | ||
|     const hasMultiColumn = gridColumns.some(columns => 
 | ||
|         columns && !columns.includes('1fr') && (columns.includes('fr') || columns.includes('px'))
 | ||
|     );
 | ||
|     
 | ||
|     if (hasMultiColumn) {
 | ||
|         console.log(`  ❌ ${pageName} still has multi-column elements:`, gridColumns);
 | ||
|         return false;
 | ||
|     }
 | ||
|     
 | ||
|     console.log(`  ✅ ${pageName} has proper single-column layout`);
 | ||
|     return true;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * Check if navigation is present and visible
 | ||
|  */
 | ||
| async function checkNavigation(page, pageName) {
 | ||
|     console.log(`  🧭 Checking navigation for ${pageName}...`);
 | ||
|     
 | ||
|     const navigation = await page.$('.hvac-trainer-menu-wrapper, .hvac-master-navigation, .hvac-navigation');
 | ||
|     if (!navigation) {
 | ||
|         console.log(`  ❌ ${pageName} missing navigation element`);
 | ||
|         return false;
 | ||
|     }
 | ||
|     
 | ||
|     const isVisible = await navigation.isVisible();
 | ||
|     if (!isVisible) {
 | ||
|         console.log(`  ❌ ${pageName} navigation is not visible`);
 | ||
|         return false;
 | ||
|     }
 | ||
|     
 | ||
|     console.log(`  ✅ ${pageName} has visible navigation`);
 | ||
|     return true;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * Check if breadcrumbs are present and visible
 | ||
|  */
 | ||
| async function checkBreadcrumbs(page, pageName) {
 | ||
|     console.log(`  🍞 Checking breadcrumbs for ${pageName}...`);
 | ||
|     
 | ||
|     const breadcrumbs = await page.$('.hvac-breadcrumbs');
 | ||
|     if (!breadcrumbs) {
 | ||
|         console.log(`  ❌ ${pageName} missing breadcrumbs element`);
 | ||
|         return false;
 | ||
|     }
 | ||
|     
 | ||
|     const isVisible = await breadcrumbs.isVisible();
 | ||
|     if (!isVisible) {
 | ||
|         console.log(`  ❌ ${pageName} breadcrumbs are not visible`);
 | ||
|         return false;
 | ||
|     }
 | ||
|     
 | ||
|     console.log(`  ✅ ${pageName} has visible breadcrumbs`);
 | ||
|     return true;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * Verify CSS files are loaded properly
 | ||
|  */
 | ||
| async function checkCSSLoading(page, browserType) {
 | ||
|     console.log(`  📄 Checking CSS loading for ${browserType}...`);
 | ||
|     
 | ||
|     const cssFiles = await page.evaluate(() => {
 | ||
|         const links = document.querySelectorAll('link[rel="stylesheet"]');
 | ||
|         return Array.from(links).map(link => ({
 | ||
|             href: link.href,
 | ||
|             id: link.id
 | ||
|         })).filter(link => link.href.includes('hvac-'));
 | ||
|     });
 | ||
|     
 | ||
|     // Check if hvac-page-templates.css or hvac-page-templates-safari.css is loaded
 | ||
|     const hasPageTemplatesCSS = cssFiles.some(css => 
 | ||
|         css.href.includes('hvac-page-templates.css') || 
 | ||
|         css.id.includes('page-templates')
 | ||
|     );
 | ||
|     
 | ||
|     if (!hasPageTemplatesCSS) {
 | ||
|         console.log(`  ❌ ${browserType} - Master Trainer layout CSS not loaded`);
 | ||
|         console.log('    Loaded CSS files:', cssFiles.map(css => css.href).join(', '));
 | ||
|         return false;
 | ||
|     }
 | ||
|     
 | ||
|     console.log(`  ✅ ${browserType} - Master Trainer layout CSS properly loaded`);
 | ||
|     return true;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * Test a single Master Trainer page
 | ||
|  */
 | ||
| async function testMasterTrainerPage(page, pageConfig, browserType) {
 | ||
|     console.log(`\n🧪 Testing ${pageConfig.name} (${browserType})...`);
 | ||
|     
 | ||
|     try {
 | ||
|         // Navigate to the page
 | ||
|         await page.goto(`${TEST_CONFIG.baseUrl}${pageConfig.path}`);
 | ||
|         await page.waitForLoadState('networkidle');
 | ||
|         
 | ||
|         // Check for WordPress errors
 | ||
|         const hasError = await page.$('.error, .wp-die-message, .notice-error');
 | ||
|         if (hasError) {
 | ||
|             const errorText = await hasError.textContent();
 | ||
|             throw new Error(`WordPress error detected: ${errorText}`);
 | ||
|         }
 | ||
|         
 | ||
|         // Verify page title
 | ||
|         const title = await page.$('h1.page-title, h1.entry-title, h1');
 | ||
|         if (title) {
 | ||
|             const titleText = await title.textContent();
 | ||
|             console.log(`  📝 Page title: ${titleText}`);
 | ||
|         }
 | ||
|         
 | ||
|         let allChecksPass = true;
 | ||
|         
 | ||
|         // Perform layout checks
 | ||
|         for (const check of pageConfig.layoutChecks) {
 | ||
|             let checkResult = false;
 | ||
|             
 | ||
|             switch (check) {
 | ||
|                 case 'single-column':
 | ||
|                     checkResult = await checkSingleColumnLayout(page, pageConfig.name);
 | ||
|                     break;
 | ||
|                 case 'navigation':
 | ||
|                     checkResult = await checkNavigation(page, pageConfig.name);
 | ||
|                     break;
 | ||
|                 case 'breadcrumbs':
 | ||
|                     checkResult = await checkBreadcrumbs(page, pageConfig.name);
 | ||
|                     break;
 | ||
|             }
 | ||
|             
 | ||
|             if (!checkResult) {
 | ||
|                 allChecksPass = false;
 | ||
|             }
 | ||
|         }
 | ||
|         
 | ||
|         // Check CSS loading
 | ||
|         const cssLoaded = await checkCSSLoading(page, browserType);
 | ||
|         if (!cssLoaded) {
 | ||
|             allChecksPass = false;
 | ||
|         }
 | ||
|         
 | ||
|         if (allChecksPass) {
 | ||
|             console.log(`✅ ${pageConfig.name} (${browserType}) - All checks passed`);
 | ||
|         } else {
 | ||
|             console.log(`❌ ${pageConfig.name} (${browserType}) - Some checks failed`);
 | ||
|         }
 | ||
|         
 | ||
|         return allChecksPass;
 | ||
|         
 | ||
|     } catch (error) {
 | ||
|         console.log(`❌ ${pageConfig.name} (${browserType}) - Error: ${error.message}`);
 | ||
|         return false;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * Run tests for a specific browser
 | ||
|  */
 | ||
| async function runBrowserTests(browserType) {
 | ||
|     console.log(`\n🌐 Testing with ${browserType.toUpperCase()} browser`);
 | ||
|     console.log('=' .repeat(60));
 | ||
|     
 | ||
|     const browser = browserType === 'safari' ? 
 | ||
|         await webkit.launch({ headless: process.env.HEADLESS !== 'false' }) :
 | ||
|         await chromium.launch({ headless: process.env.HEADLESS !== 'false' });
 | ||
|     
 | ||
|     const context = await browser.newContext();
 | ||
|     const page = await context.newPage();
 | ||
|     
 | ||
|     try {
 | ||
|         // Login as master trainer
 | ||
|         await loginAsMasterTrainer(page);
 | ||
|         
 | ||
|         let allTestsPass = true;
 | ||
|         
 | ||
|         // Test each Master Trainer page
 | ||
|         for (const pageConfig of MASTER_TRAINER_PAGES) {
 | ||
|             const result = await testMasterTrainerPage(page, pageConfig, browserType);
 | ||
|             if (!result) {
 | ||
|                 allTestsPass = false;
 | ||
|             }
 | ||
|         }
 | ||
|         
 | ||
|         return allTestsPass;
 | ||
|         
 | ||
|     } finally {
 | ||
|         await browser.close();
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * Main test runner
 | ||
|  */
 | ||
| async function runMasterTrainerLayoutTests() {
 | ||
|     console.log('🚀 Master Trainer Layout Fix Verification Test');
 | ||
|     console.log('=' .repeat(60));
 | ||
|     console.log('Testing Master Trainer page layouts across browsers');
 | ||
|     console.log('Verifying Safari CSS loading fix implementation');
 | ||
|     
 | ||
|     let overallSuccess = true;
 | ||
|     
 | ||
|     try {
 | ||
|         // Test with Chrome (non-Safari)
 | ||
|         const chromeResults = await runBrowserTests('chrome');
 | ||
|         
 | ||
|         // Test with Safari/WebKit
 | ||
|         const safariResults = await runBrowserTests('safari');
 | ||
|         
 | ||
|         if (!chromeResults || !safariResults) {
 | ||
|             overallSuccess = false;
 | ||
|         }
 | ||
|         
 | ||
|         console.log('\n' + '=' .repeat(60));
 | ||
|         console.log('📊 TEST RESULTS SUMMARY');
 | ||
|         console.log('=' .repeat(60));
 | ||
|         console.log(`Chrome Browser Tests: ${chromeResults ? '✅ PASSED' : '❌ FAILED'}`);
 | ||
|         console.log(`Safari Browser Tests: ${safariResults ? '✅ PASSED' : '❌ FAILED'}`);
 | ||
|         console.log(`Overall Result: ${overallSuccess ? '✅ ALL TESTS PASSED' : '❌ SOME TESTS FAILED'}`);
 | ||
|         
 | ||
|         if (overallSuccess) {
 | ||
|             console.log('\n🎉 Master Trainer layout fixes are working correctly!');
 | ||
|             console.log('✅ Single-column layouts enforced across all browsers');
 | ||
|             console.log('✅ Navigation and breadcrumbs properly displayed');
 | ||
|             console.log('✅ Safari CSS loading issues resolved');
 | ||
|         } else {
 | ||
|             console.log('\n⚠️  Some Master Trainer layout issues still exist');
 | ||
|             console.log('❌ Review the test output above for specific failures');
 | ||
|         }
 | ||
|         
 | ||
|         return overallSuccess;
 | ||
|         
 | ||
|     } catch (error) {
 | ||
|         console.error('❌ Test execution failed:', error);
 | ||
|         return false;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| // Run the tests if this script is executed directly
 | ||
| if (require.main === module) {
 | ||
|     runMasterTrainerLayoutTests()
 | ||
|         .then(success => {
 | ||
|             process.exit(success ? 0 : 1);
 | ||
|         })
 | ||
|         .catch(error => {
 | ||
|             console.error('Fatal error:', error);
 | ||
|             process.exit(1);
 | ||
|         });
 | ||
| }
 | ||
| 
 | ||
| module.exports = {
 | ||
|     runMasterTrainerLayoutTests,
 | ||
|     testMasterTrainerPage,
 | ||
|     checkSingleColumnLayout,
 | ||
|     checkNavigation,
 | ||
|     checkBreadcrumbs
 | ||
| }; |