@casoon/auditmysite
Version:
A comprehensive command-line tool for automated accessibility, security, performance, and SEO testing using Playwright and pa11y, based on sitemap URLs
226 lines • 9.41 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsonGenerator = void 0;
class JsonGenerator {
/**
* Generiert JSON-Export für Test-Ergebnisse
*/
generateJson(summary, options = {}) {
const exportData = {
metadata: {
generatedAt: new Date().toISOString(),
tool: 'auditmysite',
version: '1.0.1',
summary: {
totalPages: summary.totalPages,
testedPages: summary.testedPages,
passedPages: summary.passedPages,
failedPages: summary.failedPages,
totalErrors: summary.totalErrors,
totalWarnings: summary.totalWarnings,
totalDuration: summary.totalDuration,
successRate: summary.testedPages > 0 ? (summary.passedPages / summary.testedPages * 100) : 0
}
},
results: this.processResults(summary.results, options),
statistics: this.generateStatistics(summary.results),
recommendations: this.generateRecommendations(summary.results)
};
return options.pretty !== false
? JSON.stringify(exportData, null, 2)
: JSON.stringify(exportData);
}
/**
* Verarbeitet Test-Ergebnisse für JSON-Export
*/
processResults(results, options) {
return results.map(result => {
const processedResult = {
url: result.url,
title: result.title,
passed: result.passed,
duration: result.duration,
errorCount: result.errors.length,
warningCount: result.warnings.length,
imagesWithoutAlt: result.imagesWithoutAlt,
buttonsWithoutLabel: result.buttonsWithoutLabel,
headingsCount: result.headingsCount
};
if (options.includeDetails) {
processedResult.errors = result.errors;
processedResult.warnings = result.warnings;
if (result.pa11yIssues) {
processedResult.pa11yIssues = result.pa11yIssues;
}
if (result.pa11yScore) {
processedResult.pa11yScore = result.pa11yScore;
}
if (result.performanceMetrics) {
processedResult.performanceMetrics = result.performanceMetrics;
}
if (result.lighthouseScores) {
processedResult.lighthouseScores = result.lighthouseScores;
}
if (result.lighthouseMetrics) {
processedResult.lighthouseMetrics = result.lighthouseMetrics;
}
}
return processedResult;
});
}
/**
* Generiert Statistiken für JSON-Export
*/
generateStatistics(results) {
const errorTypes = new Map();
const warningTypes = new Map();
const urlsByStatus = {
passed: 0,
failed: 0
};
results.forEach(result => {
// Count URLs by status
if (result.passed) {
urlsByStatus.passed++;
}
else {
urlsByStatus.failed++;
}
// Count error types
result.errors.forEach(error => {
const key = this.extractErrorType(error);
errorTypes.set(key, (errorTypes.get(key) || 0) + 1);
});
// Count warning types
result.warnings.forEach(warning => {
const key = this.extractErrorType(warning);
warningTypes.set(key, (warningTypes.get(key) || 0) + 1);
});
});
return {
urlsByStatus,
errorTypes: Object.fromEntries(errorTypes),
warningTypes: Object.fromEntries(warningTypes),
totalErrors: results.reduce((sum, r) => sum + r.errors.length, 0),
totalWarnings: results.reduce((sum, r) => sum + r.warnings.length, 0),
averageDuration: results.length > 0
? results.reduce((sum, r) => sum + r.duration, 0) / results.length
: 0
};
}
/**
* Generiert Empfehlungen basierend auf Ergebnissen
*/
generateRecommendations(results) {
const recommendations = [];
const errorTypes = new Map();
// Sammle alle Fehler-Typen (basierend auf Error-Messages)
results.forEach(result => {
result.errors.forEach(error => {
// Extrahiere Fehler-Typ aus Error-Message
const key = this.extractErrorType(error);
errorTypes.set(key, (errorTypes.get(key) || 0) + 1);
});
});
// Generiere Empfehlungen basierend auf häufigen Fehlern
if (errorTypes.get('missing-alt-text') || errorTypes.get('alt-text')) {
recommendations.push({
priority: 'high',
category: 'images',
title: 'Add Alt Text to Images',
description: 'Images without alt text are not accessible to screen readers',
count: (errorTypes.get('missing-alt-text') || 0) + (errorTypes.get('alt-text') || 0),
impact: 'critical',
effort: 'low',
examples: ['Add alt="description" to <img> elements']
});
}
if (errorTypes.get('color-contrast') || errorTypes.get('contrast')) {
recommendations.push({
priority: 'high',
category: 'visual',
title: 'Improve Color Contrast',
description: 'Text with insufficient color contrast is difficult to read',
count: (errorTypes.get('color-contrast') || 0) + (errorTypes.get('contrast') || 0),
impact: 'high',
effort: 'medium',
examples: ['Increase contrast ratio to at least 4.5:1 for normal text']
});
}
if (errorTypes.get('missing-labels') || errorTypes.get('form-labels')) {
recommendations.push({
priority: 'high',
category: 'forms',
title: 'Add Labels to Form Elements',
description: 'Form elements without labels are not accessible',
count: (errorTypes.get('missing-labels') || 0) + (errorTypes.get('form-labels') || 0),
impact: 'critical',
effort: 'low',
examples: ['Add <label> elements for all form inputs']
});
}
if (errorTypes.get('heading-structure') || errorTypes.get('headings')) {
recommendations.push({
priority: 'medium',
category: 'structure',
title: 'Fix Heading Structure',
description: 'Improper heading hierarchy makes navigation difficult',
count: (errorTypes.get('heading-structure') || 0) + (errorTypes.get('headings') || 0),
impact: 'medium',
effort: 'medium',
examples: ['Use proper heading hierarchy (h1, h2, h3, etc.)']
});
}
if (errorTypes.get('aria-labels') || errorTypes.get('aria')) {
recommendations.push({
priority: 'medium',
category: 'aria',
title: 'Add ARIA Labels',
description: 'Interactive elements need proper ARIA labels',
count: (errorTypes.get('aria-labels') || 0) + (errorTypes.get('aria') || 0),
impact: 'medium',
effort: 'low',
examples: ['Add aria-label or aria-labelledby to interactive elements']
});
}
return recommendations;
}
/**
* Extrahiert Fehler-Typ aus Error-Message
*/
extractErrorType(errorMessage) {
const lowerMessage = errorMessage.toLowerCase();
if (lowerMessage.includes('alt') || lowerMessage.includes('image')) {
return 'missing-alt-text';
}
if (lowerMessage.includes('contrast') || lowerMessage.includes('color')) {
return 'color-contrast';
}
if (lowerMessage.includes('label') || lowerMessage.includes('form')) {
return 'missing-labels';
}
if (lowerMessage.includes('heading') || lowerMessage.includes('h1') || lowerMessage.includes('h2')) {
return 'heading-structure';
}
if (lowerMessage.includes('aria') || lowerMessage.includes('role')) {
return 'aria-labels';
}
if (lowerMessage.includes('button') || lowerMessage.includes('link')) {
return 'interactive-elements';
}
if (lowerMessage.includes('table') || lowerMessage.includes('list')) {
return 'structure';
}
return 'other';
}
/**
* Speichert JSON-Export in Datei
*/
async saveToFile(summary, filePath, options = {}) {
const fs = require('fs').promises;
const jsonContent = this.generateJson(summary, options);
await fs.writeFile(filePath, jsonContent, 'utf8');
}
}
exports.JsonGenerator = JsonGenerator;
//# sourceMappingURL=json-generator.js.map