Some checks failed
		
		
	
	HVAC Plugin CI/CD Pipeline / Code Quality & Standards (push) Has been cancelled
				
			HVAC Plugin CI/CD Pipeline / Unit Tests (push) Has been cancelled
				
			Security Monitoring & Compliance / Secrets & Credential Scan (push) Has been cancelled
				
			Security Monitoring & Compliance / WordPress Security Analysis (push) Has been cancelled
				
			HVAC Plugin CI/CD Pipeline / Security Analysis (push) Has been cancelled
				
			HVAC Plugin CI/CD Pipeline / Integration Tests (push) Has been cancelled
				
			Security Monitoring & Compliance / Dependency Vulnerability Scan (push) Has been cancelled
				
			Security Monitoring & Compliance / Static Code Security Analysis (push) Has been cancelled
				
			Security Monitoring & Compliance / Security Compliance Validation (push) Has been cancelled
				
			HVAC Plugin CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
				
			HVAC Plugin CI/CD Pipeline / Deploy to Production (push) Has been cancelled
				
			HVAC Plugin CI/CD Pipeline / Notification (push) Has been cancelled
				
			Security Monitoring & Compliance / Security Summary Report (push) Has been cancelled
				
			Security Monitoring & Compliance / Security Team Notification (push) Has been cancelled
				
			- Deploy 6 simultaneous WordPress specialized agents using sequential thinking and Zen MCP - Resolve all critical issues: permissions, jQuery dependencies, CDN mapping, security vulnerabilities - Implement bulletproof jQuery loading system with WordPress hook timing fixes - Create professional MapGeo Safety system with CDN health monitoring and fallback UI - Fix privilege escalation vulnerability with capability-based authorization - Add complete announcement admin system with modal forms and AJAX handling - Enhance import/export functionality (54 trainers successfully exported) - Achieve 100% operational master trainer functionality verified via MCP Playwright E2E testing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			421 lines
		
	
	
		
			No EOL
		
	
	
		
			15 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			421 lines
		
	
	
		
			No EOL
		
	
	
		
			15 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable file
		
	
	
	
	
| #!/usr/bin/env node
 | ||
| 
 | ||
| /**
 | ||
|  * HVAC Community Events - Comprehensive Build System Test Runner
 | ||
|  * 
 | ||
|  * Executes the complete test suite for the JavaScript build pipeline including:
 | ||
|  * - Build system validation
 | ||
|  * - Security vulnerability testing  
 | ||
|  * - WordPress integration testing
 | ||
|  * - E2E functionality testing
 | ||
|  * - Performance and compatibility testing
 | ||
|  *
 | ||
|  * @package HVAC_Community_Events
 | ||
|  * @since 2.0.0
 | ||
|  */
 | ||
| 
 | ||
| const { spawn } = require('child_process');
 | ||
| const fs = require('fs').promises;
 | ||
| const path = require('path');
 | ||
| 
 | ||
| // Test configuration
 | ||
| const TEST_CONFIG = {
 | ||
|     BASE_URL: process.env.BASE_URL || 'http://localhost:8080',
 | ||
|     HEADLESS: process.env.HEADLESS !== 'false',
 | ||
|     BROWSER: process.env.BROWSER || 'chromium',
 | ||
|     WORKERS: process.env.WORKERS || '1',
 | ||
|     
 | ||
|     // Test suites to run
 | ||
|     TEST_SUITES: [
 | ||
|         {
 | ||
|             name: 'Build System Validation',
 | ||
|             file: './tests/build-system-validation.test.js',
 | ||
|             description: 'Webpack builds, bundle generation, performance validation',
 | ||
|             critical: true
 | ||
|         },
 | ||
|         {
 | ||
|             name: 'Security Vulnerability Tests', 
 | ||
|             file: './tests/build-system-security.test.js',
 | ||
|             description: 'Critical security vulnerability detection and testing',
 | ||
|             critical: true
 | ||
|         },
 | ||
|         {
 | ||
|             name: 'E2E Bundled Assets Functionality',
 | ||
|             file: './tests/e2e-bundled-assets-functionality.test.js', 
 | ||
|             description: 'End-to-end functionality with bundled assets',
 | ||
|             critical: true
 | ||
|         }
 | ||
|     ],
 | ||
|     
 | ||
|     // Test environments
 | ||
|     ENVIRONMENTS: {
 | ||
|         DOCKER: 'http://localhost:8080',
 | ||
|         STAGING: 'https://staging.upskillhvac.com',
 | ||
|         LOCAL: 'http://localhost:8080'
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| /**
 | ||
|  * Build System Test Runner
 | ||
|  */
 | ||
| class BuildSystemTestRunner {
 | ||
|     
 | ||
|     constructor() {
 | ||
|         this.results = {
 | ||
|             suites: [],
 | ||
|             summary: {
 | ||
|                 total: 0,
 | ||
|                 passed: 0,
 | ||
|                 failed: 0,
 | ||
|                 skipped: 0
 | ||
|             },
 | ||
|             startTime: new Date(),
 | ||
|             endTime: null,
 | ||
|             environment: process.env.NODE_ENV || 'test'
 | ||
|         };
 | ||
|     }
 | ||
|     
 | ||
|     /**
 | ||
|      * Print colored console output
 | ||
|      */
 | ||
|     log(message, color = 'white') {
 | ||
|         const colors = {
 | ||
|             red: '\x1b[31m',
 | ||
|             green: '\x1b[32m',
 | ||
|             yellow: '\x1b[33m',
 | ||
|             blue: '\x1b[34m',
 | ||
|             magenta: '\x1b[35m',
 | ||
|             cyan: '\x1b[36m',
 | ||
|             white: '\x1b[37m',
 | ||
|             reset: '\x1b[0m'
 | ||
|         };
 | ||
|         
 | ||
|         console.log(`${colors[color]}${message}${colors.reset}`);
 | ||
|     }
 | ||
|     
 | ||
|     /**
 | ||
|      * Check prerequisites
 | ||
|      */
 | ||
|     async checkPrerequisites() {
 | ||
|         this.log('\n🔍 Checking Prerequisites...', 'cyan');
 | ||
|         
 | ||
|         const checks = [];
 | ||
|         
 | ||
|         // Check if build output exists
 | ||
|         try {
 | ||
|             await fs.access('./assets/js/dist');
 | ||
|             checks.push({ name: 'Build output directory', status: 'pass' });
 | ||
|         } catch (error) {
 | ||
|             checks.push({ name: 'Build output directory', status: 'fail', error: 'dist/ directory not found' });
 | ||
|         }
 | ||
|         
 | ||
|         // Check webpack config
 | ||
|         try {
 | ||
|             await fs.access('./webpack.config.js');
 | ||
|             checks.push({ name: 'Webpack configuration', status: 'pass' });
 | ||
|         } catch (error) {
 | ||
|             checks.push({ name: 'Webpack configuration', status: 'fail', error: 'webpack.config.js not found' });
 | ||
|         }
 | ||
|         
 | ||
|         // Check HVAC_Bundled_Assets class
 | ||
|         try {
 | ||
|             await fs.access('./includes/class-hvac-bundled-assets.php');
 | ||
|             checks.push({ name: 'HVAC_Bundled_Assets class', status: 'pass' });
 | ||
|         } catch (error) {
 | ||
|             checks.push({ name: 'HVAC_Bundled_Assets class', status: 'fail', error: 'class-hvac-bundled-assets.php not found' });
 | ||
|         }
 | ||
|         
 | ||
|         // Check test environment
 | ||
|         try {
 | ||
|             const response = await fetch(TEST_CONFIG.BASE_URL);
 | ||
|             if (response.ok) {
 | ||
|                 checks.push({ name: 'Test environment', status: 'pass', url: TEST_CONFIG.BASE_URL });
 | ||
|             } else {
 | ||
|                 checks.push({ name: 'Test environment', status: 'fail', error: `HTTP ${response.status}` });
 | ||
|             }
 | ||
|         } catch (error) {
 | ||
|             checks.push({ name: 'Test environment', status: 'fail', error: error.message });
 | ||
|         }
 | ||
|         
 | ||
|         // Print results
 | ||
|         checks.forEach(check => {
 | ||
|             if (check.status === 'pass') {
 | ||
|                 this.log(`  ✅ ${check.name}`, 'green');
 | ||
|                 if (check.url) this.log(`     ${check.url}`, 'white');
 | ||
|             } else {
 | ||
|                 this.log(`  ❌ ${check.name}: ${check.error}`, 'red');
 | ||
|             }
 | ||
|         });
 | ||
|         
 | ||
|         const failedChecks = checks.filter(c => c.status === 'fail');
 | ||
|         if (failedChecks.length > 0) {
 | ||
|             this.log(`\n⚠️  ${failedChecks.length} prerequisite checks failed`, 'yellow');
 | ||
|             this.log('Some tests may fail or be skipped', 'yellow');
 | ||
|         }
 | ||
|         
 | ||
|         return { checks, allPassed: failedChecks.length === 0 };
 | ||
|     }
 | ||
|     
 | ||
|     /**
 | ||
|      * Run build system validation
 | ||
|      */
 | ||
|     async runBuildValidation() {
 | ||
|         this.log('\n🏗️  Running Build System Validation...', 'blue');
 | ||
|         
 | ||
|         try {
 | ||
|             // Check if we need to build
 | ||
|             const distExists = await fs.access('./assets/js/dist').then(() => true).catch(() => false);
 | ||
|             
 | ||
|             if (!distExists) {
 | ||
|                 this.log('📦 Building assets...', 'yellow');
 | ||
|                 await this.runCommand('npm run build');
 | ||
|             }
 | ||
|             
 | ||
|             // Validate build output
 | ||
|             const distFiles = await fs.readdir('./assets/js/dist');
 | ||
|             const bundleFiles = distFiles.filter(f => f.endsWith('.bundle.js'));
 | ||
|             
 | ||
|             this.log(`✅ Found ${bundleFiles.length} bundle files:`, 'green');
 | ||
|             bundleFiles.forEach(file => {
 | ||
|                 this.log(`   • ${file}`, 'white');
 | ||
|             });
 | ||
|             
 | ||
|             return { success: true, bundleCount: bundleFiles.length };
 | ||
|             
 | ||
|         } catch (error) {
 | ||
|             this.log(`❌ Build validation failed: ${error.message}`, 'red');
 | ||
|             return { success: false, error: error.message };
 | ||
|         }
 | ||
|     }
 | ||
|     
 | ||
|     /**
 | ||
|      * Run a shell command
 | ||
|      */
 | ||
|     runCommand(command) {
 | ||
|         return new Promise((resolve, reject) => {
 | ||
|             const process = spawn('bash', ['-c', command], {
 | ||
|                 stdio: ['pipe', 'pipe', 'pipe']
 | ||
|             });
 | ||
|             
 | ||
|             let output = '';
 | ||
|             let errorOutput = '';
 | ||
|             
 | ||
|             process.stdout.on('data', (data) => {
 | ||
|                 output += data.toString();
 | ||
|             });
 | ||
|             
 | ||
|             process.stderr.on('data', (data) => {
 | ||
|                 errorOutput += data.toString();
 | ||
|             });
 | ||
|             
 | ||
|             process.on('close', (code) => {
 | ||
|                 if (code === 0) {
 | ||
|                     resolve(output);
 | ||
|                 } else {
 | ||
|                     reject(new Error(`Command failed: ${command}\n${errorOutput}`));
 | ||
|                 }
 | ||
|             });
 | ||
|         });
 | ||
|     }
 | ||
|     
 | ||
|     /**
 | ||
|      * Run Playwright test suite
 | ||
|      */
 | ||
|     async runTestSuite(suite) {
 | ||
|         this.log(`\n🧪 Running: ${suite.name}`, 'magenta');
 | ||
|         this.log(`   ${suite.description}`, 'white');
 | ||
|         
 | ||
|         const startTime = Date.now();
 | ||
|         
 | ||
|         try {
 | ||
|             // Build Playwright command
 | ||
|             const playwrightCmd = [
 | ||
|                 'npx playwright test',
 | ||
|                 `"${suite.file}"`,
 | ||
|                 `--project=${TEST_CONFIG.BROWSER}`,
 | ||
|                 `--workers=${TEST_CONFIG.WORKERS}`,
 | ||
|                 TEST_CONFIG.HEADLESS ? '--headless' : '',
 | ||
|                 '--reporter=json',
 | ||
|                 '--reporter=line'
 | ||
|             ].filter(Boolean).join(' ');
 | ||
|             
 | ||
|             this.log(`   Command: ${playwrightCmd}`, 'cyan');
 | ||
|             
 | ||
|             const output = await this.runCommand(playwrightCmd);
 | ||
|             const duration = Date.now() - startTime;
 | ||
|             
 | ||
|             // Parse results (simplified)
 | ||
|             const passed = (output.match(/passed/g) || []).length;
 | ||
|             const failed = (output.match(/failed/g) || []).length;
 | ||
|             const skipped = (output.match(/skipped/g) || []).length;
 | ||
|             
 | ||
|             const result = {
 | ||
|                 suite: suite.name,
 | ||
|                 file: suite.file,
 | ||
|                 passed,
 | ||
|                 failed,
 | ||
|                 skipped,
 | ||
|                 duration: Math.round(duration / 1000),
 | ||
|                 success: failed === 0,
 | ||
|                 output: output.slice(-1000) // Last 1000 chars
 | ||
|             };
 | ||
|             
 | ||
|             if (result.success) {
 | ||
|                 this.log(`   ✅ ${suite.name} completed successfully`, 'green');
 | ||
|                 this.log(`   📊 ${passed} passed, ${failed} failed, ${skipped} skipped (${result.duration}s)`, 'green');
 | ||
|             } else {
 | ||
|                 this.log(`   ❌ ${suite.name} had failures`, 'red');
 | ||
|                 this.log(`   📊 ${passed} passed, ${failed} failed, ${skipped} skipped (${result.duration}s)`, 'red');
 | ||
|             }
 | ||
|             
 | ||
|             return result;
 | ||
|             
 | ||
|         } catch (error) {
 | ||
|             const duration = Date.now() - startTime;
 | ||
|             
 | ||
|             this.log(`   ❌ ${suite.name} failed to run: ${error.message}`, 'red');
 | ||
|             
 | ||
|             return {
 | ||
|                 suite: suite.name,
 | ||
|                 file: suite.file,
 | ||
|                 passed: 0,
 | ||
|                 failed: 1,
 | ||
|                 skipped: 0,
 | ||
|                 duration: Math.round(duration / 1000),
 | ||
|                 success: false,
 | ||
|                 error: error.message
 | ||
|             };
 | ||
|         }
 | ||
|     }
 | ||
|     
 | ||
|     /**
 | ||
|      * Generate test report
 | ||
|      */
 | ||
|     async generateReport() {
 | ||
|         this.results.endTime = new Date();
 | ||
|         const duration = Math.round((this.results.endTime - this.results.startTime) / 1000);
 | ||
|         
 | ||
|         this.log('\n📋 BUILD SYSTEM TEST REPORT', 'cyan');
 | ||
|         this.log('═'.repeat(50), 'cyan');
 | ||
|         
 | ||
|         this.log(`\n🕐 Duration: ${duration} seconds`, 'white');
 | ||
|         this.log(`🌐 Environment: ${TEST_CONFIG.BASE_URL}`, 'white');
 | ||
|         this.log(`🔧 Browser: ${TEST_CONFIG.BROWSER}`, 'white');
 | ||
|         this.log(`👥 Workers: ${TEST_CONFIG.WORKERS}`, 'white');
 | ||
|         
 | ||
|         this.log(`\n📊 SUMMARY`, 'cyan');
 | ||
|         this.log(`   Total Suites: ${this.results.suites.length}`, 'white');
 | ||
|         this.log(`   Passed: ${this.results.summary.passed}`, 'green');
 | ||
|         this.log(`   Failed: ${this.results.summary.failed}`, this.results.summary.failed > 0 ? 'red' : 'white');
 | ||
|         this.log(`   Skipped: ${this.results.summary.skipped}`, this.results.summary.skipped > 0 ? 'yellow' : 'white');
 | ||
|         
 | ||
|         this.log(`\n🧪 SUITE DETAILS`, 'cyan');
 | ||
|         this.results.suites.forEach(suite => {
 | ||
|             const status = suite.success ? '✅' : '❌';
 | ||
|             const color = suite.success ? 'green' : 'red';
 | ||
|             
 | ||
|             this.log(`   ${status} ${suite.suite}`, color);
 | ||
|             this.log(`      📁 ${path.basename(suite.file)}`, 'white');
 | ||
|             this.log(`      📊 ${suite.passed}P ${suite.failed}F ${suite.skipped}S (${suite.duration}s)`, 'white');
 | ||
|             
 | ||
|             if (suite.error) {
 | ||
|                 this.log(`      ⚠️  ${suite.error}`, 'yellow');
 | ||
|             }
 | ||
|         });
 | ||
|         
 | ||
|         // Security vulnerabilities summary
 | ||
|         const securitySuite = this.results.suites.find(s => s.suite === 'Security Vulnerability Tests');
 | ||
|         if (securitySuite) {
 | ||
|             this.log(`\n🔒 SECURITY ASSESSMENT`, 'red');
 | ||
|             if (securitySuite.success) {
 | ||
|                 this.log('   ✅ All security tests passed', 'green');
 | ||
|                 this.log('   ⚠️  However, tests may pass even with vulnerabilities', 'yellow');
 | ||
|             } else {
 | ||
|                 this.log('   ❌ Security test failures detected', 'red');
 | ||
|             }
 | ||
|             this.log('   📋 Review security test output for vulnerability details', 'white');
 | ||
|         }
 | ||
|         
 | ||
|         // Overall status
 | ||
|         this.log(`\n🎯 OVERALL STATUS`, 'cyan');
 | ||
|         const overallSuccess = this.results.summary.failed === 0;
 | ||
|         if (overallSuccess) {
 | ||
|             this.log('   ✅ All test suites passed', 'green');
 | ||
|             this.log('   🚀 Build system ready for deployment validation', 'green');
 | ||
|         } else {
 | ||
|             this.log('   ❌ Some test suites failed', 'red');
 | ||
|             this.log('   ⚠️  Review failures before deployment', 'red');
 | ||
|         }
 | ||
|         
 | ||
|         // Recommendations
 | ||
|         this.log(`\n💡 RECOMMENDATIONS`, 'cyan');
 | ||
|         if (securitySuite && securitySuite.failed > 0) {
 | ||
|             this.log('   🔒 Fix all security vulnerabilities before production', 'red');
 | ||
|         }
 | ||
|         this.log('   🧪 Run tests in staging environment before production deployment', 'white');
 | ||
|         this.log('   📊 Monitor bundle performance in production', 'white');
 | ||
|         this.log('   🔄 Re-run tests after any build system changes', 'white');
 | ||
|         
 | ||
|         // Save report to file
 | ||
|         const reportPath = `./test-results/build-system-report-${Date.now()}.json`;
 | ||
|         await fs.mkdir('./test-results', { recursive: true });
 | ||
|         await fs.writeFile(reportPath, JSON.stringify(this.results, null, 2));
 | ||
|         
 | ||
|         this.log(`\n💾 Report saved: ${reportPath}`, 'cyan');
 | ||
|         
 | ||
|         return overallSuccess;
 | ||
|     }
 | ||
|     
 | ||
|     /**
 | ||
|      * Run all test suites
 | ||
|      */
 | ||
|     async run() {
 | ||
|         this.log('🧪 HVAC BUILD SYSTEM COMPREHENSIVE TEST SUITE', 'cyan');
 | ||
|         this.log('═'.repeat(60), 'cyan');
 | ||
|         
 | ||
|         // Prerequisites check
 | ||
|         const prereqs = await this.checkPrerequisites();
 | ||
|         
 | ||
|         if (!prereqs.allPassed) {
 | ||
|             this.log('\n⚠️  Some prerequisites failed - continuing with available tests', 'yellow');
 | ||
|         }
 | ||
|         
 | ||
|         // Build validation
 | ||
|         const buildValidation = await this.runBuildValidation();
 | ||
|         
 | ||
|         if (!buildValidation.success) {
 | ||
|             this.log('\n❌ Build validation failed - some tests may be skipped', 'red');
 | ||
|         }
 | ||
|         
 | ||
|         // Run test suites
 | ||
|         for (const suite of TEST_CONFIG.TEST_SUITES) {
 | ||
|             const result = await this.runTestSuite(suite);
 | ||
|             this.results.suites.push(result);
 | ||
|             
 | ||
|             // Update summary
 | ||
|             this.results.summary.total += 1;
 | ||
|             if (result.success) {
 | ||
|                 this.results.summary.passed += 1;
 | ||
|             } else {
 | ||
|                 this.results.summary.failed += 1;
 | ||
|             }
 | ||
|         }
 | ||
|         
 | ||
|         // Generate final report
 | ||
|         const overallSuccess = await this.generateReport();
 | ||
|         
 | ||
|         // Exit with appropriate code
 | ||
|         process.exit(overallSuccess ? 0 : 1);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| // Run the test suite
 | ||
| if (require.main === module) {
 | ||
|     const runner = new BuildSystemTestRunner();
 | ||
|     runner.run().catch(error => {
 | ||
|         console.error('Fatal error:', error.message);
 | ||
|         process.exit(1);
 | ||
|     });
 | ||
| }
 | ||
| 
 | ||
| module.exports = BuildSystemTestRunner; |