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>
806 lines
No EOL
30 KiB
JavaScript
Executable file
806 lines
No EOL
30 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
||
/**
|
||
* Master Test Runner - Phase 3 Integration & Validation
|
||
*
|
||
* Production-ready execution script that demonstrates the complete E2E test integration
|
||
* for all 5 agent implementations with cross-functional workflows, performance monitoring,
|
||
* and comprehensive error recovery.
|
||
*
|
||
* Usage:
|
||
* node tests/integration/master-test-runner.js
|
||
* node tests/integration/master-test-runner.js --environment=docker
|
||
* node tests/integration/master-test-runner.js --agents=A,B,C --headed
|
||
* node tests/integration/master-test-runner.js --performance-only
|
||
*
|
||
* @package HVAC_Community_Events
|
||
* @version 3.0.0
|
||
* @created 2025-08-27
|
||
*/
|
||
|
||
const path = require('path');
|
||
const fs = require('fs').promises;
|
||
const { Command } = require('commander');
|
||
|
||
// Core integration components
|
||
const MasterTestOrchestrator = require('./master-test-orchestrator');
|
||
const CrossFunctionalWorkflows = require('./cross-functional-workflows');
|
||
const PerformanceMonitor = require('../framework/monitoring/PerformanceMonitor');
|
||
const ErrorRecoveryManager = require('../framework/recovery/ErrorRecoveryManager');
|
||
|
||
// Configuration
|
||
const DEFAULT_CONFIG = {
|
||
environment: 'staging',
|
||
baseUrl: process.env.BASE_URL || 'https://upskill-staging.measurequick.com',
|
||
dockerUrl: process.env.DOCKER_BASE_URL || 'http://localhost:8080',
|
||
headless: process.env.HEADLESS !== 'false',
|
||
slowMo: parseInt(process.env.PLAYWRIGHT_SLOW_MO) || 0,
|
||
timeout: 30 * 60 * 1000, // 30 minutes
|
||
evidenceDir: path.join(__dirname, '../evidence/master-test-run'),
|
||
reportDir: path.join(__dirname, '../reports'),
|
||
display: process.env.DISPLAY || ':0',
|
||
xAuthority: process.env.XAUTHORITY || '/run/user/1000/.mutter-Xwaylandauth.U8VEB3'
|
||
};
|
||
|
||
class MasterTestRunner {
|
||
constructor(options = {}) {
|
||
this.config = { ...DEFAULT_CONFIG, ...options };
|
||
this.startTime = Date.now();
|
||
this.orchestrator = null;
|
||
this.workflows = null;
|
||
this.performanceMonitor = null;
|
||
this.errorRecoveryManager = null;
|
||
this.results = {
|
||
orchestration: null,
|
||
workflows: null,
|
||
performance: null,
|
||
recovery: null,
|
||
summary: null
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Execute complete integration test suite
|
||
*/
|
||
async execute() {
|
||
console.log('════════════════════════════════════════════════════════');
|
||
console.log(' HVAC E2E Integration & Validation - Master Test Runner');
|
||
console.log('════════════════════════════════════════════════════════');
|
||
console.log('Phase 3: Agent Implementation Coordination');
|
||
console.log(`Environment: ${this.config.environment}`);
|
||
console.log(`Base URL: ${this.config.baseUrl}`);
|
||
console.log(`Headless: ${this.config.headless}`);
|
||
console.log(`Target Duration: <${this.config.timeout / 60000} minutes`);
|
||
console.log(`Evidence Directory: ${this.config.evidenceDir}`);
|
||
console.log('════════════════════════════════════════════════════════');
|
||
|
||
try {
|
||
// Initialize all components
|
||
await this.initializeComponents();
|
||
|
||
// Execute test phases
|
||
if (this.config.skipOrchestration !== true) {
|
||
await this.executeOrchestration();
|
||
}
|
||
|
||
if (this.config.skipWorkflows !== true) {
|
||
await this.executeWorkflows();
|
||
}
|
||
|
||
if (this.config.skipPerformance !== true) {
|
||
await this.executePerformanceTesting();
|
||
}
|
||
|
||
if (this.config.skipRecovery !== true) {
|
||
await this.executeRecoveryTesting();
|
||
}
|
||
|
||
// Generate final report
|
||
await this.generateFinalReport();
|
||
|
||
// Display results
|
||
this.displayResults();
|
||
|
||
const success = this.evaluateOverallSuccess();
|
||
console.log(`\n🏁 Master Test Runner: ${success ? 'SUCCESS' : 'FAILED'}`);
|
||
|
||
return success;
|
||
|
||
} catch (error) {
|
||
console.error('\n💥 Master Test Runner failed:', error.message);
|
||
console.error('Stack trace:', error.stack);
|
||
|
||
await this.handleExecutionError(error);
|
||
return false;
|
||
|
||
} finally {
|
||
await this.cleanup();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Initialize all test components
|
||
*/
|
||
async initializeComponents() {
|
||
console.log('\n🔧 Initializing test components...');
|
||
|
||
// Create evidence directories
|
||
await this.createDirectories();
|
||
|
||
// Initialize Master Test Orchestrator
|
||
if (!this.config.skipOrchestration) {
|
||
console.log(' Initializing Master Test Orchestrator...');
|
||
this.orchestrator = new MasterTestOrchestrator();
|
||
await this.orchestrator.setUp();
|
||
console.log(' ✓ Master Test Orchestrator ready');
|
||
}
|
||
|
||
// Initialize Cross-Functional Workflows
|
||
if (!this.config.skipWorkflows) {
|
||
console.log(' Initializing Cross-Functional Workflows...');
|
||
this.workflows = new CrossFunctionalWorkflows();
|
||
await this.workflows.setUp();
|
||
console.log(' ✓ Cross-Functional Workflows ready');
|
||
}
|
||
|
||
// Initialize Performance Monitor
|
||
if (!this.config.skipPerformance) {
|
||
console.log(' Initializing Performance Monitor...');
|
||
this.performanceMonitor = new PerformanceMonitor();
|
||
await this.performanceMonitor.initialize();
|
||
console.log(' ✓ Performance Monitor ready');
|
||
}
|
||
|
||
// Initialize Error Recovery Manager
|
||
if (!this.config.skipRecovery) {
|
||
console.log(' Initializing Error Recovery Manager...');
|
||
this.errorRecoveryManager = new ErrorRecoveryManager();
|
||
const browserManager = this.orchestrator ? this.orchestrator.browserManager : null;
|
||
await this.errorRecoveryManager.initialize(browserManager);
|
||
console.log(' ✓ Error Recovery Manager ready');
|
||
}
|
||
|
||
console.log('✓ All components initialized successfully');
|
||
}
|
||
|
||
/**
|
||
* Execute master test orchestration
|
||
*/
|
||
async executeOrchestration() {
|
||
console.log('\n🎭 Executing Master Test Orchestration...');
|
||
|
||
const orchestrationStart = Date.now();
|
||
|
||
try {
|
||
// Start performance monitoring for orchestration
|
||
if (this.performanceMonitor) {
|
||
await this.performanceMonitor.startAgentMonitoring('MasterOrchestration');
|
||
}
|
||
|
||
// Execute orchestration
|
||
const orchestrationResults = await this.orchestrator.executeIntegrationValidation();
|
||
|
||
// Stop performance monitoring
|
||
if (this.performanceMonitor) {
|
||
await this.performanceMonitor.stopAgentMonitoring('MasterOrchestration');
|
||
}
|
||
|
||
const orchestrationDuration = Date.now() - orchestrationStart;
|
||
|
||
this.results.orchestration = {
|
||
status: 'completed',
|
||
duration: orchestrationDuration,
|
||
results: orchestrationResults,
|
||
timestamp: new Date().toISOString()
|
||
};
|
||
|
||
console.log(`✓ Master Test Orchestration completed in ${(orchestrationDuration / 1000).toFixed(1)}s`);
|
||
|
||
} catch (error) {
|
||
const orchestrationDuration = Date.now() - orchestrationStart;
|
||
|
||
this.results.orchestration = {
|
||
status: 'failed',
|
||
duration: orchestrationDuration,
|
||
error: error.message,
|
||
timestamp: new Date().toISOString()
|
||
};
|
||
|
||
console.error(`✗ Master Test Orchestration failed after ${(orchestrationDuration / 1000).toFixed(1)}s:`, error.message);
|
||
|
||
if (this.config.continueOnFailure !== true) {
|
||
throw error;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Execute cross-functional workflows
|
||
*/
|
||
async executeWorkflows() {
|
||
console.log('\n🔄 Executing Cross-Functional Workflows...');
|
||
|
||
const workflowsStart = Date.now();
|
||
|
||
try {
|
||
// Start performance monitoring for workflows
|
||
if (this.performanceMonitor) {
|
||
await this.performanceMonitor.startAgentMonitoring('CrossFunctionalWorkflows');
|
||
}
|
||
|
||
// Execute workflows
|
||
const workflowResults = await this.workflows.executeAllWorkflows();
|
||
|
||
// Stop performance monitoring
|
||
if (this.performanceMonitor) {
|
||
await this.performanceMonitor.stopAgentMonitoring('CrossFunctionalWorkflows');
|
||
}
|
||
|
||
const workflowsDuration = Date.now() - workflowsStart;
|
||
|
||
this.results.workflows = {
|
||
status: 'completed',
|
||
duration: workflowsDuration,
|
||
results: workflowResults,
|
||
timestamp: new Date().toISOString()
|
||
};
|
||
|
||
const passedWorkflows = workflowResults.filter(w => w.status === 'passed').length;
|
||
console.log(`✓ Cross-Functional Workflows completed: ${passedWorkflows}/${workflowResults.length} passed in ${(workflowsDuration / 1000).toFixed(1)}s`);
|
||
|
||
} catch (error) {
|
||
const workflowsDuration = Date.now() - workflowsStart;
|
||
|
||
this.results.workflows = {
|
||
status: 'failed',
|
||
duration: workflowsDuration,
|
||
error: error.message,
|
||
timestamp: new Date().toISOString()
|
||
};
|
||
|
||
console.error(`✗ Cross-Functional Workflows failed after ${(workflowsDuration / 1000).toFixed(1)}s:`, error.message);
|
||
|
||
if (this.config.continueOnFailure !== true) {
|
||
throw error;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Execute performance testing
|
||
*/
|
||
async executePerformanceTesting() {
|
||
console.log('\n📊 Executing Performance Testing...');
|
||
|
||
const performanceStart = Date.now();
|
||
|
||
try {
|
||
// Concurrent load testing
|
||
const concurrentSessionConfigs = [
|
||
{
|
||
sessionId: 'trainer_session_1',
|
||
actions: [
|
||
{ type: 'login', duration: 2000 },
|
||
{ type: 'navigate', url: '/trainer/dashboard', duration: 1500 },
|
||
{ type: 'create_event', duration: 5000 }
|
||
]
|
||
},
|
||
{
|
||
sessionId: 'trainer_session_2',
|
||
actions: [
|
||
{ type: 'login', duration: 2000 },
|
||
{ type: 'navigate', url: '/trainer/my-events', duration: 1500 },
|
||
{ type: 'form_submit', duration: 3000 }
|
||
]
|
||
},
|
||
{
|
||
sessionId: 'master_session_1',
|
||
actions: [
|
||
{ type: 'login', duration: 2000 },
|
||
{ type: 'navigate', url: '/master-trainer/pending-approvals', duration: 2000 },
|
||
{ type: 'form_submit', duration: 2000 }
|
||
]
|
||
}
|
||
];
|
||
|
||
const loadTestResults = await this.performanceMonitor.executeConcurrentLoadTest(concurrentSessionConfigs);
|
||
|
||
// Generate performance benchmark
|
||
const performanceBenchmark = await this.performanceMonitor.generatePerformanceBenchmark();
|
||
|
||
const performanceDuration = Date.now() - performanceStart;
|
||
|
||
this.results.performance = {
|
||
status: 'completed',
|
||
duration: performanceDuration,
|
||
loadTest: loadTestResults,
|
||
benchmark: performanceBenchmark,
|
||
timestamp: new Date().toISOString()
|
||
};
|
||
|
||
console.log(`✓ Performance Testing completed in ${(performanceDuration / 1000).toFixed(1)}s`);
|
||
console.log(` Concurrent Sessions: ${loadTestResults.successfulSessions}/${loadTestResults.totalSessions} successful`);
|
||
console.log(` Performance Rating: ${loadTestResults.concurrentPerformanceRating}`);
|
||
|
||
} catch (error) {
|
||
const performanceDuration = Date.now() - performanceStart;
|
||
|
||
this.results.performance = {
|
||
status: 'failed',
|
||
duration: performanceDuration,
|
||
error: error.message,
|
||
timestamp: new Date().toISOString()
|
||
};
|
||
|
||
console.error(`✗ Performance Testing failed after ${(performanceDuration / 1000).toFixed(1)}s:`, error.message);
|
||
|
||
if (this.config.continueOnFailure !== true) {
|
||
throw error;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Execute error recovery testing
|
||
*/
|
||
async executeRecoveryTesting() {
|
||
console.log('\n🛡️ Executing Error Recovery Testing...');
|
||
|
||
const recoveryStart = Date.now();
|
||
|
||
try {
|
||
// Execute comprehensive recovery tests
|
||
const recoveryResults = await this.errorRecoveryManager.executeComprehensiveRecoveryTests(this.config.baseUrl);
|
||
|
||
// Get recovery statistics
|
||
const recoveryStats = this.errorRecoveryManager.getRecoveryStatistics();
|
||
|
||
const recoveryDuration = Date.now() - recoveryStart;
|
||
|
||
this.results.recovery = {
|
||
status: 'completed',
|
||
duration: recoveryDuration,
|
||
results: recoveryResults,
|
||
statistics: recoveryStats,
|
||
timestamp: new Date().toISOString()
|
||
};
|
||
|
||
console.log(`✓ Error Recovery Testing completed in ${(recoveryDuration / 1000).toFixed(1)}s`);
|
||
console.log(` Recovery Tests: ${recoveryResults.summary.passed}/${recoveryResults.summary.total} passed`);
|
||
console.log(` Success Rate: ${recoveryResults.summary.successRate.toFixed(1)}%`);
|
||
|
||
} catch (error) {
|
||
const recoveryDuration = Date.now() - recoveryStart;
|
||
|
||
this.results.recovery = {
|
||
status: 'failed',
|
||
duration: recoveryDuration,
|
||
error: error.message,
|
||
timestamp: new Date().toISOString()
|
||
};
|
||
|
||
console.error(`✗ Error Recovery Testing failed after ${(recoveryDuration / 1000).toFixed(1)}s:`, error.message);
|
||
|
||
if (this.config.continueOnFailure !== true) {
|
||
throw error;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Generate final comprehensive report
|
||
*/
|
||
async generateFinalReport() {
|
||
console.log('\n📋 Generating final integration report...');
|
||
|
||
const totalDuration = Date.now() - this.startTime;
|
||
|
||
const finalReport = {
|
||
meta: {
|
||
version: '3.0.0',
|
||
generatedAt: new Date().toISOString(),
|
||
totalDuration: totalDuration,
|
||
environment: this.config.environment,
|
||
baseUrl: this.config.baseUrl,
|
||
configuration: this.config
|
||
},
|
||
summary: {
|
||
overallStatus: this.evaluateOverallSuccess() ? 'SUCCESS' : 'FAILED',
|
||
totalDuration: totalDuration,
|
||
targetDuration: this.config.timeout,
|
||
performanceMet: totalDuration <= this.config.timeout,
|
||
phases: {
|
||
orchestration: this.results.orchestration?.status || 'skipped',
|
||
workflows: this.results.workflows?.status || 'skipped',
|
||
performance: this.results.performance?.status || 'skipped',
|
||
recovery: this.results.recovery?.status || 'skipped'
|
||
}
|
||
},
|
||
results: this.results,
|
||
recommendations: this.generateRecommendations()
|
||
};
|
||
|
||
// Export performance report if available
|
||
if (this.performanceMonitor) {
|
||
const performanceReportPath = path.join(this.config.reportDir, `performance-report-${Date.now()}.json`);
|
||
await this.performanceMonitor.exportPerformanceReport(performanceReportPath);
|
||
finalReport.performanceReportPath = performanceReportPath;
|
||
}
|
||
|
||
// Save final report
|
||
const finalReportPath = path.join(this.config.reportDir, `master-test-report-${Date.now()}.json`);
|
||
await fs.writeFile(finalReportPath, JSON.stringify(finalReport, null, 2));
|
||
|
||
// Generate executive summary
|
||
const summaryPath = await this.generateExecutiveSummary(finalReport);
|
||
|
||
console.log(`✓ Final integration report generated:`);
|
||
console.log(` Report: ${finalReportPath}`);
|
||
console.log(` Summary: ${summaryPath}`);
|
||
|
||
this.results.summary = finalReport;
|
||
|
||
return finalReport;
|
||
}
|
||
|
||
/**
|
||
* Generate executive summary
|
||
*/
|
||
async generateExecutiveSummary(finalReport) {
|
||
const summary = `
|
||
# HVAC E2E Integration & Validation - Executive Summary
|
||
|
||
**Generated:** ${new Date().toISOString()}
|
||
**Environment:** ${this.config.environment}
|
||
**Base URL:** ${this.config.baseUrl}
|
||
**Total Duration:** ${(finalReport.meta.totalDuration / 1000).toFixed(1)} seconds
|
||
|
||
## Overall Status: ${finalReport.summary.overallStatus}
|
||
|
||
### Phase Execution Results
|
||
|
||
**Master Test Orchestration:** ${finalReport.summary.phases.orchestration.toUpperCase()}
|
||
- Status: ${this.results.orchestration?.status || 'Not executed'}
|
||
- Duration: ${this.results.orchestration ? (this.results.orchestration.duration / 1000).toFixed(1) + 's' : 'N/A'}
|
||
|
||
**Cross-Functional Workflows:** ${finalReport.summary.phases.workflows.toUpperCase()}
|
||
- Status: ${this.results.workflows?.status || 'Not executed'}
|
||
- Duration: ${this.results.workflows ? (this.results.workflows.duration / 1000).toFixed(1) + 's' : 'N/A'}
|
||
|
||
**Performance Testing:** ${finalReport.summary.phases.performance.toUpperCase()}
|
||
- Status: ${this.results.performance?.status || 'Not executed'}
|
||
- Duration: ${this.results.performance ? (this.results.performance.duration / 1000).toFixed(1) + 's' : 'N/A'}
|
||
|
||
**Error Recovery Testing:** ${finalReport.summary.phases.recovery.toUpperCase()}
|
||
- Status: ${this.results.recovery?.status || 'Not executed'}
|
||
- Duration: ${this.results.recovery ? (this.results.recovery.duration / 1000).toFixed(1) + 's' : 'N/A'}
|
||
|
||
### Performance Summary
|
||
|
||
**Total Execution Time:** ${(finalReport.meta.totalDuration / 1000).toFixed(1)}s
|
||
**Target Execution Time:** ${(this.config.timeout / 1000).toFixed(1)}s
|
||
**Performance Target Met:** ${finalReport.summary.performanceMet ? 'YES' : 'NO'}
|
||
|
||
### Key Findings
|
||
|
||
${this.generateKeyFindings()}
|
||
|
||
### Recommendations
|
||
|
||
${finalReport.recommendations.map(r => `- ${r}`).join('\n')}
|
||
|
||
---
|
||
*Generated by Master Test Runner v3.0.0*
|
||
`;
|
||
|
||
const summaryPath = path.join(this.config.reportDir, `executive-summary-${Date.now()}.md`);
|
||
await fs.writeFile(summaryPath, summary.trim());
|
||
|
||
return summaryPath;
|
||
}
|
||
|
||
/**
|
||
* Generate key findings
|
||
*/
|
||
generateKeyFindings() {
|
||
const findings = [];
|
||
|
||
// Orchestration findings
|
||
if (this.results.orchestration?.status === 'completed') {
|
||
findings.push('✓ Master test orchestration successfully coordinated all agent implementations');
|
||
} else if (this.results.orchestration?.status === 'failed') {
|
||
findings.push('✗ Master test orchestration encountered failures');
|
||
}
|
||
|
||
// Workflow findings
|
||
if (this.results.workflows?.results) {
|
||
const passedWorkflows = this.results.workflows.results.filter(w => w.status === 'passed').length;
|
||
const totalWorkflows = this.results.workflows.results.length;
|
||
findings.push(`✓ Cross-functional workflows: ${passedWorkflows}/${totalWorkflows} passed`);
|
||
}
|
||
|
||
// Performance findings
|
||
if (this.results.performance?.benchmark) {
|
||
const benchmark = this.results.performance.benchmark;
|
||
findings.push(`✓ Performance rating: ${benchmark.overall.rating}`);
|
||
findings.push(`✓ Page load performance: ${benchmark.pageLoads.rating}`);
|
||
}
|
||
|
||
// Recovery findings
|
||
if (this.results.recovery?.results) {
|
||
const recovery = this.results.recovery.results;
|
||
findings.push(`✓ Error recovery tests: ${recovery.summary.passed}/${recovery.summary.total} passed (${recovery.summary.successRate.toFixed(1)}%)`);
|
||
}
|
||
|
||
if (findings.length === 0) {
|
||
findings.push('No significant findings to report');
|
||
}
|
||
|
||
return findings.join('\n');
|
||
}
|
||
|
||
/**
|
||
* Generate recommendations
|
||
*/
|
||
generateRecommendations() {
|
||
const recommendations = [];
|
||
|
||
// Performance recommendations
|
||
const totalDuration = Date.now() - this.startTime;
|
||
if (totalDuration > this.config.timeout) {
|
||
recommendations.push(`Optimize execution time - exceeded ${this.config.timeout / 60000} minute target by ${((totalDuration - this.config.timeout) / 1000).toFixed(1)}s`);
|
||
}
|
||
|
||
// Phase-specific recommendations
|
||
if (this.results.orchestration?.status === 'failed') {
|
||
recommendations.push('Review and fix master test orchestration failures');
|
||
}
|
||
|
||
if (this.results.workflows?.results) {
|
||
const failedWorkflows = this.results.workflows.results.filter(w => w.status === 'failed');
|
||
if (failedWorkflows.length > 0) {
|
||
recommendations.push(`Address ${failedWorkflows.length} failed cross-functional workflow(s)`);
|
||
}
|
||
}
|
||
|
||
if (this.results.performance?.benchmark) {
|
||
const perfRecommendations = this.results.performance.benchmark.recommendations;
|
||
if (perfRecommendations && perfRecommendations.length > 0) {
|
||
recommendations.push(...perfRecommendations.map(r => r.message));
|
||
}
|
||
}
|
||
|
||
if (this.results.recovery?.results) {
|
||
const recovery = this.results.recovery.results;
|
||
if (recovery.summary.successRate < 90) {
|
||
recommendations.push('Improve error recovery mechanisms - success rate below 90%');
|
||
}
|
||
}
|
||
|
||
if (recommendations.length === 0) {
|
||
recommendations.push('All integration criteria met - continue with regular maintenance');
|
||
}
|
||
|
||
return recommendations;
|
||
}
|
||
|
||
/**
|
||
* Display results summary
|
||
*/
|
||
displayResults() {
|
||
console.log('\n' + '═'.repeat(60));
|
||
console.log(' MASTER TEST RUNNER - EXECUTION SUMMARY');
|
||
console.log('═'.repeat(60));
|
||
|
||
const totalDuration = Date.now() - this.startTime;
|
||
|
||
console.log(`Total Execution Time: ${(totalDuration / 1000).toFixed(1)}s`);
|
||
console.log(`Performance Target: ${totalDuration <= this.config.timeout ? 'MET' : 'EXCEEDED'}`);
|
||
console.log('');
|
||
|
||
// Phase results
|
||
const phases = [
|
||
['Master Orchestration', this.results.orchestration],
|
||
['Cross-Functional Workflows', this.results.workflows],
|
||
['Performance Testing', this.results.performance],
|
||
['Error Recovery Testing', this.results.recovery]
|
||
];
|
||
|
||
phases.forEach(([name, result]) => {
|
||
if (result) {
|
||
const status = result.status === 'completed' ? '✓' :
|
||
result.status === 'failed' ? '✗' : '○';
|
||
const duration = result.duration ? `(${(result.duration / 1000).toFixed(1)}s)` : '';
|
||
console.log(`${status} ${name}: ${result.status.toUpperCase()} ${duration}`);
|
||
|
||
if (result.error) {
|
||
console.log(` Error: ${result.error}`);
|
||
}
|
||
} else {
|
||
console.log(`○ ${name}: SKIPPED`);
|
||
}
|
||
});
|
||
|
||
console.log('');
|
||
|
||
// Success metrics
|
||
const success = this.evaluateOverallSuccess();
|
||
console.log(`Overall Status: ${success ? '🎉 SUCCESS' : '❌ FAILED'}`);
|
||
console.log(`Evidence Directory: ${this.config.evidenceDir}`);
|
||
console.log(`Reports Directory: ${this.config.reportDir}`);
|
||
}
|
||
|
||
/**
|
||
* Evaluate overall success
|
||
*/
|
||
evaluateOverallSuccess() {
|
||
const phaseResults = [
|
||
this.results.orchestration,
|
||
this.results.workflows,
|
||
this.results.performance,
|
||
this.results.recovery
|
||
].filter(Boolean); // Only include executed phases
|
||
|
||
if (phaseResults.length === 0) {
|
||
return false; // No phases executed
|
||
}
|
||
|
||
// All executed phases must be completed (not failed)
|
||
const allPhasesSuccessful = phaseResults.every(result => result.status === 'completed');
|
||
|
||
// Performance target should be met
|
||
const totalDuration = Date.now() - this.startTime;
|
||
const performanceTargetMet = totalDuration <= this.config.timeout;
|
||
|
||
return allPhasesSuccessful && (this.config.ignorePerformanceTarget || performanceTargetMet);
|
||
}
|
||
|
||
/**
|
||
* Handle execution error
|
||
*/
|
||
async handleExecutionError(error) {
|
||
const errorReport = {
|
||
timestamp: new Date().toISOString(),
|
||
error: error.message,
|
||
stack: error.stack,
|
||
config: this.config,
|
||
results: this.results,
|
||
executionDuration: Date.now() - this.startTime
|
||
};
|
||
|
||
const errorReportPath = path.join(this.config.reportDir, `error-report-${Date.now()}.json`);
|
||
await fs.writeFile(errorReportPath, JSON.stringify(errorReport, null, 2));
|
||
|
||
console.error(`\nError report saved: ${errorReportPath}`);
|
||
}
|
||
|
||
/**
|
||
* Create necessary directories
|
||
*/
|
||
async createDirectories() {
|
||
const dirs = [
|
||
this.config.evidenceDir,
|
||
this.config.reportDir,
|
||
path.join(this.config.evidenceDir, 'screenshots'),
|
||
path.join(this.config.evidenceDir, 'videos'),
|
||
path.join(this.config.evidenceDir, 'logs')
|
||
];
|
||
|
||
for (const dir of dirs) {
|
||
try {
|
||
await fs.mkdir(dir, { recursive: true });
|
||
} catch (error) {
|
||
console.warn(`Failed to create directory ${dir}: ${error.message}`);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Cleanup all components
|
||
*/
|
||
async cleanup() {
|
||
console.log('\n🧹 Cleaning up components...');
|
||
|
||
try {
|
||
if (this.orchestrator) {
|
||
await this.orchestrator.tearDown();
|
||
console.log(' ✓ Master Test Orchestrator cleanup complete');
|
||
}
|
||
|
||
if (this.workflows) {
|
||
await this.workflows.tearDown();
|
||
console.log(' ✓ Cross-Functional Workflows cleanup complete');
|
||
}
|
||
|
||
if (this.performanceMonitor) {
|
||
await this.performanceMonitor.cleanup();
|
||
console.log(' ✓ Performance Monitor cleanup complete');
|
||
}
|
||
|
||
if (this.errorRecoveryManager) {
|
||
await this.errorRecoveryManager.cleanup();
|
||
console.log(' ✓ Error Recovery Manager cleanup complete');
|
||
}
|
||
|
||
console.log('✓ All components cleaned up successfully');
|
||
|
||
} catch (error) {
|
||
console.warn('Cleanup error:', error.message);
|
||
}
|
||
}
|
||
}
|
||
|
||
// CLI Configuration
|
||
function setupCLI() {
|
||
const program = new Command();
|
||
|
||
program
|
||
.version('3.0.0')
|
||
.description('HVAC E2E Integration & Validation - Master Test Runner')
|
||
.option('-e, --environment <env>', 'Test environment (staging|docker|production)', 'staging')
|
||
.option('-u, --base-url <url>', 'Base URL for testing')
|
||
.option('-h, --headed', 'Run in headed mode (show browser)')
|
||
.option('-s, --slow-mo <ms>', 'Slow motion delay in milliseconds', parseInt)
|
||
.option('-t, --timeout <ms>', 'Total execution timeout in milliseconds', parseInt)
|
||
.option('-c, --continue-on-failure', 'Continue execution even if phases fail')
|
||
.option('--skip-orchestration', 'Skip master test orchestration phase')
|
||
.option('--skip-workflows', 'Skip cross-functional workflows phase')
|
||
.option('--skip-performance', 'Skip performance testing phase')
|
||
.option('--skip-recovery', 'Skip error recovery testing phase')
|
||
.option('--performance-only', 'Run only performance testing')
|
||
.option('--recovery-only', 'Run only error recovery testing')
|
||
.option('--ignore-performance-target', 'Ignore performance target for success evaluation')
|
||
.parse();
|
||
|
||
return program.opts();
|
||
}
|
||
|
||
// Main execution
|
||
async function main() {
|
||
const cliOptions = setupCLI();
|
||
|
||
// Configure based on CLI options
|
||
const config = {
|
||
...DEFAULT_CONFIG,
|
||
...cliOptions
|
||
};
|
||
|
||
// Handle environment-specific URLs
|
||
if (config.environment === 'docker') {
|
||
config.baseUrl = config.baseUrl || config.dockerUrl;
|
||
}
|
||
|
||
// Handle specialized execution modes
|
||
if (config.performanceOnly) {
|
||
config.skipOrchestration = true;
|
||
config.skipWorkflows = true;
|
||
config.skipRecovery = true;
|
||
}
|
||
|
||
if (config.recoveryOnly) {
|
||
config.skipOrchestration = true;
|
||
config.skipWorkflows = true;
|
||
config.skipPerformance = true;
|
||
}
|
||
|
||
// Set display environment for headed mode
|
||
if (!config.headless) {
|
||
process.env.DISPLAY = config.display;
|
||
process.env.XAUTHORITY = config.xAuthority;
|
||
}
|
||
|
||
// Initialize and execute
|
||
const runner = new MasterTestRunner(config);
|
||
const success = await runner.execute();
|
||
|
||
process.exit(success ? 0 : 1);
|
||
}
|
||
|
||
// Execute if run directly
|
||
if (require.main === module) {
|
||
main().catch(error => {
|
||
console.error('Fatal error:', error);
|
||
process.exit(1);
|
||
});
|
||
}
|
||
|
||
module.exports = MasterTestRunner; |