@casoon/auditmysite
Version:
A comprehensive command-line tool for automated accessibility, security, performance, and SEO testing using Playwright and pa11y, based on sitemap URLs
229 lines • 8.61 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParallelTestManager = void 0;
const event_driven_queue_1 = require("./event-driven-queue");
const accessibility_checker_1 = require("./accessibility-checker");
class ParallelTestManager {
constructor(options = {}) {
this.isRunning = false;
this.startTime = null;
this.activeTests = new Map();
this.options = {
maxConcurrent: 3,
maxRetries: 3,
retryDelay: 1000,
enableProgressBar: true,
progressUpdateInterval: 1000,
enableResourceMonitoring: true,
maxMemoryUsage: 512, // 512 MB
maxCpuUsage: 80, // 80%
...options
};
// Event-Driven Queue initialisieren
this.queue = new event_driven_queue_1.EventDrivenQueue({
maxRetries: this.options.maxRetries,
maxConcurrent: this.options.maxConcurrent,
retryDelay: this.options.retryDelay,
enableEvents: true,
eventCallbacks: {
onUrlAdded: this.handleUrlAdded.bind(this),
onUrlStarted: this.handleUrlStarted.bind(this),
onUrlCompleted: this.handleUrlCompleted.bind(this),
onUrlFailed: this.handleUrlFailed.bind(this),
onUrlRetrying: this.handleUrlRetrying.bind(this),
onQueueEmpty: this.handleQueueEmpty.bind(this),
onProgressUpdate: this.handleProgressUpdate.bind(this),
onError: this.handleError.bind(this)
}
});
// Accessibility Checker initialisieren
this.accessibilityChecker = new accessibility_checker_1.AccessibilityChecker();
}
async initialize() {
await this.accessibilityChecker.initialize();
console.log(`🚀 Parallel Test Manager initialized with ${this.options.maxConcurrent} concurrent workers`);
}
async runTests(urls) {
if (this.isRunning) {
throw new Error('Test manager is already running');
}
this.isRunning = true;
this.startTime = new Date();
this.activeTests.clear();
console.log(`🧪 Starting parallel tests for ${urls.length} URLs with ${this.options.maxConcurrent} workers`);
// URLs zur Queue hinzufügen
this.queue.addUrls(urls);
// Event-Listener für Queue-Events
this.setupEventListeners();
// Parallele Test-Ausführung starten
await this.processQueue();
const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
const stats = this.queue.getStats();
const results = this.queue.getCompletedResults();
const errors = this.queue.getFailedResults();
this.isRunning = false;
return {
results,
stats,
duration,
errors
};
}
async processQueue() {
return new Promise((resolve, reject) => {
// Event-Listener für Queue-Ende
this.queue.onQueueEmpty(() => {
resolve();
});
// Event-Listener für Fehler
this.queue.onError((event) => {
reject(new Error(event.data.error));
});
// Starte Worker-Prozesse
this.startWorkers();
});
}
startWorkers() {
// Starte initiale Worker bis zur maxConcurrent-Grenze
for (let i = 0; i < this.options.maxConcurrent; i++) {
this.processNextUrl();
}
}
async processNextUrl() {
if (!this.isRunning)
return;
const queuedUrl = this.queue.getNextUrl();
if (!queuedUrl)
return;
try {
// Resource-Monitoring
if (this.options.enableResourceMonitoring) {
this.checkResourceLimits();
}
// Test ausführen
const testPromise = this.accessibilityChecker.testPage(queuedUrl.url, this.options.testOptions);
this.activeTests.set(queuedUrl.url, testPromise);
const result = await testPromise;
this.queue.markCompleted(queuedUrl.url, result);
}
catch (error) {
this.queue.markFailed(queuedUrl.url, String(error));
}
finally {
this.activeTests.delete(queuedUrl.url);
// Starte nächsten Worker
this.processNextUrl();
}
}
checkResourceLimits() {
const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024; // MB
const cpuUsage = process.cpuUsage().user / 1000000; // Sekunden
if (memoryUsage > this.options.maxMemoryUsage) {
console.warn(`⚠️ High memory usage: ${memoryUsage.toFixed(2)} MB`);
// Optional: Queue pausieren oder Worker reduzieren
}
if (cpuUsage > this.options.maxCpuUsage) {
console.warn(`⚠️ High CPU usage: ${cpuUsage.toFixed(2)}s`);
// Optional: Queue pausieren oder Worker reduzieren
}
}
// Event Handler
handleUrlAdded(url, priority) {
console.log(`📋 Added URL to queue: ${url} (priority: ${priority})`);
}
handleUrlStarted(url) {
console.log(`🚀 Started testing: ${url}`);
this.options.onTestStart?.(url);
}
handleUrlCompleted(url, result, duration) {
const status = result.passed ? '✅ PASSED' : '❌ FAILED';
console.log(`${status} ${url} (${duration}ms) - ${result.errors.length} errors, ${result.warnings.length} warnings`);
this.options.onTestComplete?.(url, result);
}
handleUrlFailed(url, error, attempts) {
console.log(`💥 Failed ${url} (attempt ${attempts}): ${error}`);
this.options.onTestError?.(url, error);
}
handleUrlRetrying(url, attempts) {
console.log(`🔄 Retrying ${url} (attempt ${attempts + 1}/${this.options.maxRetries})`);
}
handleQueueEmpty() {
console.log('🎉 All tests completed!');
this.options.onQueueEmpty?.();
}
handleProgressUpdate(stats) {
if (this.options.enableProgressBar) {
this.displayProgressBar(stats);
}
this.options.onProgressUpdate?.(stats);
}
handleError(error) {
console.error(`❌ Queue error: ${error}`);
}
setupEventListeners() {
// Progress-Update-Interval
if (this.options.enableProgressBar) {
setInterval(() => {
const stats = this.queue.getStats();
this.handleProgressUpdate(stats);
}, this.options.progressUpdateInterval);
}
}
displayProgressBar(stats) {
const progress = Math.round(stats.progress);
const barLength = 30;
const filledLength = Math.round((progress / 100) * barLength);
const bar = '█'.repeat(filledLength) + '░'.repeat(barLength - filledLength);
const eta = stats.estimatedTimeRemaining > 0
? `ETA: ${Math.round(stats.estimatedTimeRemaining / 1000)}s`
: '';
const memory = `Memory: ${stats.memoryUsage}MB`;
const workers = `Workers: ${stats.activeWorkers}/${this.options.maxConcurrent}`;
process.stdout.write(`\r🧪 Progress: [${bar}] ${progress}% | ${stats.completed}/${stats.total} | ${workers} | ${memory} | ${eta}`);
if (stats.progress >= 100) {
process.stdout.write('\n');
}
}
// Public API
pause() {
this.queue.pause();
console.log('⏸️ Tests paused');
}
resume() {
this.queue.resume();
console.log('▶️ Tests resumed');
this.startWorkers();
}
stop() {
this.isRunning = false;
this.queue.clear();
console.log('⏹️ Tests stopped');
}
getStats() {
return this.queue.getStats();
}
getActiveTests() {
return this.activeTests.size;
}
getQueueSize() {
return this.queue.getQueueSize();
}
setMaxConcurrent(max) {
this.queue.setMaxConcurrent(max);
console.log(`🔧 Max concurrent workers set to ${max}`);
}
// Resource Management
getMemoryUsage() {
return process.memoryUsage().heapUsed / 1024 / 1024;
}
getCpuUsage() {
return process.cpuUsage().user / 1000000;
}
// Cleanup
async cleanup() {
this.stop();
await this.accessibilityChecker.cleanup();
}
}
exports.ParallelTestManager = ParallelTestManager;
//# sourceMappingURL=parallel-test-manager.js.map