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; |