Some checks are pending
		
		
	
	HVAC Plugin CI/CD Pipeline / Security Analysis (push) Waiting to run
				
			HVAC Plugin CI/CD Pipeline / Code Quality & Standards (push) Waiting to run
				
			HVAC Plugin CI/CD Pipeline / Unit Tests (push) Waiting to run
				
			HVAC Plugin CI/CD Pipeline / Integration Tests (push) Waiting to run
				
			HVAC Plugin CI/CD Pipeline / Deploy to Staging (push) Blocked by required conditions
				
			HVAC Plugin CI/CD Pipeline / Deploy to Production (push) Blocked by required conditions
				
			HVAC Plugin CI/CD Pipeline / Notification (push) Blocked by required conditions
				
			Security Monitoring & Compliance / Dependency Vulnerability Scan (push) Waiting to run
				
			Security Monitoring & Compliance / Secrets & Credential Scan (push) Waiting to run
				
			Security Monitoring & Compliance / WordPress Security Analysis (push) Waiting to run
				
			Security Monitoring & Compliance / Static Code Security Analysis (push) Waiting to run
				
			Security Monitoring & Compliance / Security Compliance Validation (push) Waiting to run
				
			Security Monitoring & Compliance / Security Summary Report (push) Blocked by required conditions
				
			Security Monitoring & Compliance / Security Team Notification (push) Blocked by required conditions
				
			- Add 90+ test files including E2E, unit, and integration tests - Implement Page Object Model (POM) architecture - Add Docker testing environment with comprehensive services - Include modernized test framework with error recovery - Add specialized test suites for master trainer and trainer workflows - Update .gitignore to properly track test infrastructure 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			364 lines
		
	
	
		
			No EOL
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
		
			No EOL
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| #!/usr/bin/env node
 | |
| 
 | |
| /**
 | |
|  * Master Trainer Comprehensive E2E Test Setup Validator
 | |
|  * 
 | |
|  * Validates that all components are properly configured for comprehensive testing
 | |
|  * 
 | |
|  * @package HVAC_Community_Events  
 | |
|  * @version 2.0.0
 | |
|  * @created 2025-08-27
 | |
|  */
 | |
| 
 | |
| const fs = require('fs').promises;
 | |
| const path = require('path');
 | |
| const { execSync } = require('child_process');
 | |
| 
 | |
| class MasterTrainerSetupValidator {
 | |
|     constructor() {
 | |
|         this.validationResults = {
 | |
|             passed: 0,
 | |
|             failed: 0,
 | |
|             warnings: 0,
 | |
|             details: []
 | |
|         };
 | |
|         
 | |
|         this.requiredFiles = [
 | |
|             'e2e/master-trainer-comprehensive.test.js',
 | |
|             'page-objects/master-trainer/MasterTrainerDashboard.js',
 | |
|             'page-objects/master-trainer/MasterTrainerEvents.js',
 | |
|             'page-objects/master-trainer/MasterTrainerTrainers.js',
 | |
|             'scripts/run-master-trainer-comprehensive.js',
 | |
|             'playwright-master-trainer.config.js',
 | |
|             'README-MASTER-TRAINER-COMPREHENSIVE.md'
 | |
|         ];
 | |
|         
 | |
|         this.requiredDirectories = [
 | |
|             'test-results',
 | |
|             'test-results/master-trainer-comprehensive', 
 | |
|             'test-results/screenshots',
 | |
|             'test-results/screenshots/master-trainer',
 | |
|             'test-results/videos',
 | |
|             'test-results/videos/master-trainer'
 | |
|         ];
 | |
|         
 | |
|         this.environment = {
 | |
|             baseUrl: process.env.BASE_URL || 'https://upskill-staging.measurequick.com',
 | |
|             display: process.env.DISPLAY || ':0',
 | |
|             xauthority: process.env.XAUTHORITY || '/run/user/1000/.mutter-Xwaylandauth.U8VEB3',
 | |
|             desktop: process.env.XDG_CURRENT_DESKTOP || 'unknown'
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     async validate() {
 | |
|         console.log('🔍 Master Trainer E2E Test Setup Validation');
 | |
|         console.log('==========================================');
 | |
|         console.log('');
 | |
| 
 | |
|         try {
 | |
|             await this.validateFileStructure();
 | |
|             await this.validateDirectoryStructure();
 | |
|             await this.validatePackageJsonScripts();
 | |
|             await this.validatePlaywrightConfig();
 | |
|             await this.validateEnvironment();
 | |
|             await this.validateTestAccounts();
 | |
|             await this.validatePageObjects();
 | |
|             await this.validateDependencies();
 | |
|             
 | |
|             this.printValidationReport();
 | |
|             
 | |
|             if (this.validationResults.failed === 0) {
 | |
|                 console.log('✅ All validations passed! Master Trainer E2E tests are ready to execute.');
 | |
|                 console.log('');
 | |
|                 console.log('🚀 Quick start commands:');
 | |
|                 console.log('   npm run test:master-trainer-comprehensive');
 | |
|                 console.log('   HEADLESS=false npm run test:master-trainer-headed');
 | |
|                 console.log('');
 | |
|                 return true;
 | |
|             } else {
 | |
|                 console.log(`❌ ${this.validationResults.failed} validation(s) failed. Please fix the issues above.`);
 | |
|                 return false;
 | |
|             }
 | |
|             
 | |
|         } catch (error) {
 | |
|             console.error('❌ Validation failed with error:', error.message);
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     async validateFileStructure() {
 | |
|         console.log('📁 Validating file structure...');
 | |
|         
 | |
|         for (const file of this.requiredFiles) {
 | |
|             const filePath = path.join(__dirname, '..', file);
 | |
|             try {
 | |
|                 await fs.access(filePath);
 | |
|                 this.pass(`✅ ${file} exists`);
 | |
|             } catch (error) {
 | |
|                 this.fail(`❌ Missing required file: ${file}`);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     async validateDirectoryStructure() {
 | |
|         console.log('📂 Validating directory structure...');
 | |
|         
 | |
|         for (const dir of this.requiredDirectories) {
 | |
|             const dirPath = path.join(__dirname, '..', dir);
 | |
|             try {
 | |
|                 await fs.mkdir(dirPath, { recursive: true });
 | |
|                 this.pass(`✅ Directory ${dir} exists/created`);
 | |
|             } catch (error) {
 | |
|                 this.fail(`❌ Failed to create directory: ${dir} - ${error.message}`);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     async validatePackageJsonScripts() {
 | |
|         console.log('📜 Validating package.json scripts...');
 | |
|         
 | |
|         try {
 | |
|             const packagePath = path.join(__dirname, '..', 'package.json');
 | |
|             const packageData = await fs.readFile(packagePath, 'utf8');
 | |
|             const packageJson = JSON.parse(packageData);
 | |
|             
 | |
|             const requiredScripts = [
 | |
|                 'test:master-trainer',
 | |
|                 'test:master-trainer-headed', 
 | |
|                 'test:master-trainer-comprehensive',
 | |
|                 'test:master-trainer-debug'
 | |
|             ];
 | |
|             
 | |
|             for (const script of requiredScripts) {
 | |
|                 if (packageJson.scripts && packageJson.scripts[script]) {
 | |
|                     this.pass(`✅ Script "${script}" defined`);
 | |
|                 } else {
 | |
|                     this.fail(`❌ Missing script: ${script}`);
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|         } catch (error) {
 | |
|             this.fail(`❌ Failed to validate package.json: ${error.message}`);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     async validatePlaywrightConfig() {
 | |
|         console.log('⚙️ Validating Playwright configuration...');
 | |
|         
 | |
|         try {
 | |
|             const configPath = path.join(__dirname, '..', 'playwright-master-trainer.config.js');
 | |
|             const configExists = await fs.access(configPath).then(() => true).catch(() => false);
 | |
|             
 | |
|             if (configExists) {
 | |
|                 this.pass('✅ Playwright master trainer config exists');
 | |
|                 
 | |
|                 // Try to load the config to validate syntax
 | |
|                 try {
 | |
|                     const config = require(configPath);
 | |
|                     if (config.projects && config.projects.length > 0) {
 | |
|                         this.pass('✅ Playwright config has browser projects');
 | |
|                     } else {
 | |
|                         this.warn('⚠️ Playwright config missing browser projects');
 | |
|                     }
 | |
|                 } catch (error) {
 | |
|                     this.fail(`❌ Playwright config syntax error: ${error.message}`);
 | |
|                 }
 | |
|             } else {
 | |
|                 this.fail('❌ Playwright master trainer config missing');
 | |
|             }
 | |
|             
 | |
|         } catch (error) {
 | |
|             this.fail(`❌ Failed to validate Playwright config: ${error.message}`);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     async validateEnvironment() {
 | |
|         console.log('🌍 Validating environment configuration...');
 | |
|         
 | |
|         // Base URL validation
 | |
|         if (this.environment.baseUrl) {
 | |
|             this.pass(`✅ Base URL configured: ${this.environment.baseUrl}`);
 | |
|         } else {
 | |
|             this.fail('❌ BASE_URL not configured');
 | |
|         }
 | |
|         
 | |
|         // Desktop environment
 | |
|         if (this.environment.desktop === 'GNOME') {
 | |
|             this.pass('✅ GNOME desktop detected - headed testing available');
 | |
|         } else {
 | |
|             this.warn(`⚠️ Non-GNOME desktop (${this.environment.desktop}) - may use headless mode`);
 | |
|         }
 | |
|         
 | |
|         // Display configuration
 | |
|         if (this.environment.display) {
 | |
|             this.pass(`✅ Display configured: ${this.environment.display}`);
 | |
|         } else {
 | |
|             this.warn('⚠️ DISPLAY not set - headless mode recommended');
 | |
|         }
 | |
|         
 | |
|         // Check Node.js version
 | |
|         try {
 | |
|             const nodeVersion = process.version;
 | |
|             const majorVersion = parseInt(nodeVersion.substring(1).split('.')[0]);
 | |
|             if (majorVersion >= 16) {
 | |
|                 this.pass(`✅ Node.js version compatible: ${nodeVersion}`);
 | |
|             } else {
 | |
|                 this.fail(`❌ Node.js version too old: ${nodeVersion} (requires 16+)`);
 | |
|             }
 | |
|         } catch (error) {
 | |
|             this.warn('⚠️ Could not verify Node.js version');
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     async validateTestAccounts() {
 | |
|         console.log('🔑 Validating test account configuration...');
 | |
|         
 | |
|         const testAccounts = [
 | |
|             { name: 'Primary Master', username: 'test_master', password: 'TestMaster123!' },
 | |
|             { name: 'Alternate Master', username: 'JoeMedosch@gmail.com', password: 'JoeTrainer2025@' }
 | |
|         ];
 | |
|         
 | |
|         for (const account of testAccounts) {
 | |
|             // Basic validation - in a real scenario you might ping the staging server
 | |
|             if (account.username && account.password) {
 | |
|                 this.pass(`✅ ${account.name} account configured: ${account.username}`);
 | |
|             } else {
 | |
|                 this.fail(`❌ ${account.name} account incomplete`);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         // Test staging URL availability
 | |
|         try {
 | |
|             const url = new URL(this.environment.baseUrl);
 | |
|             this.pass(`✅ Staging URL format valid: ${url.hostname}`);
 | |
|         } catch (error) {
 | |
|             this.fail(`❌ Invalid staging URL: ${this.environment.baseUrl}`);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     async validatePageObjects() {
 | |
|         console.log('🎭 Validating page object classes...');
 | |
|         
 | |
|         const pageObjects = [
 | |
|             { file: 'MasterTrainerDashboard.js', className: 'MasterTrainerDashboard' },
 | |
|             { file: 'MasterTrainerEvents.js', className: 'MasterTrainerEvents' },
 | |
|             { file: 'MasterTrainerTrainers.js', className: 'MasterTrainerTrainers' }
 | |
|         ];
 | |
|         
 | |
|         for (const po of pageObjects) {
 | |
|             try {
 | |
|                 const poPath = path.join(__dirname, '..', 'page-objects', 'master-trainer', po.file);
 | |
|                 const poContent = await fs.readFile(poPath, 'utf8');
 | |
|                 
 | |
|                 if (poContent.includes(`class ${po.className}`)) {
 | |
|                     this.pass(`✅ Page object ${po.className} properly defined`);
 | |
|                 } else {
 | |
|                     this.fail(`❌ Page object ${po.className} class not found in ${po.file}`);
 | |
|                 }
 | |
|                 
 | |
|                 if (poContent.includes('module.exports =')) {
 | |
|                     this.pass(`✅ Page object ${po.className} properly exported`);
 | |
|                 } else {
 | |
|                     this.fail(`❌ Page object ${po.className} not exported`);
 | |
|                 }
 | |
|                 
 | |
|             } catch (error) {
 | |
|                 this.fail(`❌ Failed to validate page object ${po.file}: ${error.message}`);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     async validateDependencies() {
 | |
|         console.log('📦 Validating dependencies...');
 | |
|         
 | |
|         try {
 | |
|             const packagePath = path.join(__dirname, '..', 'package.json');
 | |
|             const packageData = await fs.readFile(packagePath, 'utf8');
 | |
|             const packageJson = JSON.parse(packageData);
 | |
|             
 | |
|             const requiredDeps = [
 | |
|                 '@playwright/test',
 | |
|                 'playwright'
 | |
|             ];
 | |
|             
 | |
|             for (const dep of requiredDeps) {
 | |
|                 if (packageJson.dependencies && packageJson.dependencies[dep]) {
 | |
|                     this.pass(`✅ Dependency ${dep} defined`);
 | |
|                 } else {
 | |
|                     this.fail(`❌ Missing dependency: ${dep}`);
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             // Check if node_modules exists
 | |
|             const nodeModulesPath = path.join(__dirname, '..', 'node_modules');
 | |
|             try {
 | |
|                 await fs.access(nodeModulesPath);
 | |
|                 this.pass('✅ node_modules directory exists');
 | |
|             } catch (error) {
 | |
|                 this.fail('❌ node_modules not found - run "npm install"');
 | |
|             }
 | |
|             
 | |
|         } catch (error) {
 | |
|             this.fail(`❌ Failed to validate dependencies: ${error.message}`);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pass(message) {
 | |
|         this.validationResults.passed++;
 | |
|         this.validationResults.details.push({ type: 'pass', message });
 | |
|         console.log(`  ${message}`);
 | |
|     }
 | |
| 
 | |
|     fail(message) {
 | |
|         this.validationResults.failed++;
 | |
|         this.validationResults.details.push({ type: 'fail', message });
 | |
|         console.log(`  ${message}`);
 | |
|     }
 | |
| 
 | |
|     warn(message) {
 | |
|         this.validationResults.warnings++;
 | |
|         this.validationResults.details.push({ type: 'warn', message });
 | |
|         console.log(`  ${message}`);
 | |
|     }
 | |
| 
 | |
|     printValidationReport() {
 | |
|         console.log('');
 | |
|         console.log('📊 Validation Summary');
 | |
|         console.log('====================');
 | |
|         console.log(`✅ Passed: ${this.validationResults.passed}`);
 | |
|         console.log(`❌ Failed: ${this.validationResults.failed}`);
 | |
|         console.log(`⚠️ Warnings: ${this.validationResults.warnings}`);
 | |
|         console.log(`📊 Total: ${this.validationResults.passed + this.validationResults.failed + this.validationResults.warnings}`);
 | |
|         console.log('');
 | |
| 
 | |
|         if (this.validationResults.warnings > 0) {
 | |
|             console.log('⚠️ Warnings (non-blocking):');
 | |
|             const warnings = this.validationResults.details.filter(d => d.type === 'warn');
 | |
|             warnings.forEach(w => console.log(`  ${w.message}`));
 | |
|             console.log('');
 | |
|         }
 | |
| 
 | |
|         if (this.validationResults.failed > 0) {
 | |
|             console.log('❌ Failed validations (must fix):');
 | |
|             const failures = this.validationResults.details.filter(d => d.type === 'fail');
 | |
|             failures.forEach(f => console.log(`  ${f.message}`));
 | |
|             console.log('');
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Execute validation if called directly
 | |
| if (require.main === module) {
 | |
|     const validator = new MasterTrainerSetupValidator();
 | |
|     
 | |
|     validator.validate()
 | |
|         .then(success => {
 | |
|             process.exit(success ? 0 : 1);
 | |
|         })
 | |
|         .catch(error => {
 | |
|             console.error('Validation error:', error.message);
 | |
|             process.exit(1);
 | |
|         });
 | |
| }
 | |
| 
 | |
| module.exports = MasterTrainerSetupValidator; |