UNPKG

@casoon/auditmysite

Version:

A comprehensive command-line tool for automated accessibility, security, performance, and SEO testing using Playwright and pa11y, based on sitemap URLs

329 lines 14.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.DetailedReportGenerator = void 0; const fs = __importStar(require("fs")); const path = __importStar(require("path")); class DetailedReportGenerator { /** * Generiert einen detaillierten Fehlerbericht */ async generateDetailedReport(summary, options = {}) { const timestamp = new Date().toISOString(); const outputDir = options.outputDir || './reports'; const domain = this.extractDomainFromResults(summary.results); const filename = `${domain}-detailed-errors-${timestamp.split('T')[0]}.md`; const outputPath = path.join(outputDir, filename); // Erstelle Output-Verzeichnis falls nicht vorhanden if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } const content = this.generateDetailedReportContent(summary, timestamp, options); fs.writeFileSync(outputPath, content, 'utf8'); return outputPath; } extractDomainFromResults(results) { if (results.length === 0) return 'unknown'; try { const url = new URL(results[0].url); return url.hostname.replace(/\./g, '-'); } catch { return 'unknown'; } } generateDetailedReportContent(summary, timestamp, options) { const lines = []; // Header lines.push('# Detailed Accessibility Error Report'); lines.push(`Generated: ${timestamp}`); lines.push(`Total Errors: ${summary.totalErrors}`); lines.push(`Total Warnings: ${summary.totalWarnings}`); lines.push(`Failed Pages: ${summary.failedPages}`); lines.push(''); // Executive Summary lines.push('## Executive Summary'); lines.push(''); lines.push('This report contains structured accessibility errors that can be automatically fixed by AI tools.'); lines.push(`- **Critical Issues**: ${summary.totalErrors} errors requiring immediate attention`); lines.push(`- **Warnings**: ${summary.totalWarnings} issues for improvement`); lines.push(`- **Pages with Issues**: ${summary.failedPages} out of ${summary.testedPages} tested`); lines.push(`- **Success Rate**: ${summary.testedPages > 0 ? (summary.passedPages / summary.testedPages * 100).toFixed(1) : 0}%`); lines.push(''); // Gruppierte Fehler nach Typ if (options.groupByType !== false) { lines.push('## Errors Grouped by Type'); lines.push(''); const errorGroups = this.groupErrorsByType(summary.results); for (const [errorType, errors] of Object.entries(errorGroups)) { lines.push(`### ${errorType} (${errors.length} occurrences)`); lines.push(''); errors.forEach((error, index) => { lines.push(`#### Error ${index + 1}: ${error.title}`); lines.push(`- **URL**: ${error.url}`); lines.push(`- **Error**: ${error.message}`); if (error.selector && options.includeContext !== false) { lines.push(`- **Element**: \`${error.selector}\``); } if (error.context && options.includeContext !== false) { lines.push(`- **Context**: \`${error.context}\``); } if (error.recommendation && options.includeRecommendations !== false) { lines.push(`- **AI Fix**: ${error.recommendation}`); } lines.push(''); }); } } // Detaillierte Fehlerliste lines.push('## Detailed Error List'); lines.push(''); const allErrors = this.extractAllErrors(summary.results); allErrors.forEach((error, index) => { lines.push(`### Error ${index + 1}`); lines.push(`- **Page**: ${error.url}`); lines.push(`- **Title**: ${error.title}`); lines.push(`- **Type**: ${error.type}`); lines.push(`- **Code**: ${error.code}`); lines.push(`- **Message**: ${error.message}`); if (error.selector) { lines.push(`- **Selector**: \`${error.selector}\``); } if (error.context) { lines.push(`- **Context**: \`${error.context}\``); } if (options.includeCodeExamples !== false) { const codeExample = this.generateCodeExample(error); if (codeExample) { lines.push(`- **Code Example**:`); lines.push('```html'); lines.push(codeExample); lines.push('```'); } } if (options.includeRecommendations !== false) { const recommendation = this.generateRecommendation(error); if (recommendation) { lines.push(`- **Recommendation**: ${recommendation}`); } } lines.push(''); }); // Verarbeitungsanweisungen lines.push('## Processing Instructions'); lines.push(''); lines.push('This report is structured for automated tools to fix accessibility issues:'); lines.push(''); lines.push('1. **Parse each error** using the structured format above'); lines.push('2. **Identify the element** using the provided selector'); lines.push('3. **Apply the recommended fix** based on the error type'); lines.push('4. **Test the fix** to ensure it resolves the issue'); lines.push('5. **Update the code** with the corrected version'); lines.push(''); lines.push('### Common Fix Patterns:'); lines.push('- **Missing alt attributes**: Add descriptive alt text to images'); lines.push('- **Missing aria-labels**: Add aria-label or aria-labelledby to interactive elements'); lines.push('- **Color contrast**: Adjust text/background colors for better contrast'); lines.push('- **Heading structure**: Ensure proper heading hierarchy (h1, h2, h3, etc.)'); lines.push('- **Form labels**: Associate form controls with their labels'); lines.push('- **Keyboard navigation**: Ensure all interactive elements are keyboard accessible'); lines.push(''); // Prioritätsliste lines.push('## Priority List'); lines.push(''); lines.push('Process errors in this order for maximum impact:'); lines.push(''); const priorityErrors = this.getPriorityErrors(allErrors); priorityErrors.forEach((error, index) => { lines.push(`${index + 1}. **${error.type}** - ${error.message} (${error.url})`); }); return lines.join('\n'); } groupErrorsByType(results) { const groups = {}; results.forEach(result => { // Playwright-Fehler result.errors.forEach(error => { const type = this.categorizeError(error); if (!groups[type]) groups[type] = []; groups[type].push({ url: result.url, title: result.title, message: error, type: type, selector: null, context: null }); }); // pa11y-Fehler if (result.pa11yIssues) { result.pa11yIssues.forEach(issue => { const type = this.categorizePa11yIssue(issue); if (!groups[type]) groups[type] = []; groups[type].push({ url: result.url, title: result.title, message: issue.message, type: type, code: issue.code, selector: issue.selector, context: issue.context }); }); } }); return groups; } extractAllErrors(results) { const allErrors = []; results.forEach(result => { // Playwright-Fehler result.errors.forEach(error => { allErrors.push({ url: result.url, title: result.title, message: error, type: this.categorizeError(error), code: 'PLAYWRIGHT_ERROR', selector: null, context: null }); }); // pa11y-Fehler if (result.pa11yIssues) { result.pa11yIssues.forEach(issue => { allErrors.push({ url: result.url, title: result.title, message: issue.message, type: this.categorizePa11yIssue(issue), code: issue.code, selector: issue.selector, context: issue.context }); }); } }); return allErrors; } categorizeError(error) { if (error.includes('alt')) return 'Missing Alt Attributes'; if (error.includes('aria-label')) return 'Missing ARIA Labels'; if (error.includes('heading')) return 'Heading Structure Issues'; if (error.includes('title')) return 'Missing Page Title'; return 'General Accessibility Issue'; } categorizePa11yIssue(issue) { const code = issue.code.toLowerCase(); if (code.includes('alt')) return 'Missing Alt Attributes'; if (code.includes('aria')) return 'ARIA Issues'; if (code.includes('color') || code.includes('contrast')) return 'Color Contrast Issues'; if (code.includes('heading')) return 'Heading Structure Issues'; if (code.includes('label')) return 'Form Label Issues'; if (code.includes('keyboard')) return 'Keyboard Navigation Issues'; if (code.includes('focus')) return 'Focus Management Issues'; return 'WCAG Compliance Issue'; } generateCodeExample(error) { if (!error.selector) return null; switch (error.type) { case 'Missing Alt Attributes': return `<img src="image.jpg" alt="Descriptive text about the image">`; case 'Missing ARIA Labels': return `<button aria-label="Submit form">Submit</button>`; case 'Heading Structure Issues': return `<h1>Main Heading</h1>\n<h2>Sub Heading</h2>\n<h3>Section Heading</h3>`; case 'Color Contrast Issues': return `<p style="color: #000; background-color: #fff;">High contrast text</p>`; case 'Form Label Issues': return `<label for="email">Email:</label>\n<input type="email" id="email" name="email">`; default: return null; } } generateRecommendation(error) { switch (error.type) { case 'Missing Alt Attributes': return 'Add descriptive alt text to all images that convey information'; case 'Missing ARIA Labels': return 'Add aria-label or aria-labelledby attributes to interactive elements without visible text'; case 'Heading Structure Issues': return 'Ensure proper heading hierarchy: h1 for main title, h2 for sections, h3 for subsections'; case 'Color Contrast Issues': return 'Increase color contrast ratio to at least 4.5:1 for normal text, 3:1 for large text'; case 'Form Label Issues': return 'Associate form controls with their labels using for/id attributes or aria-labelledby'; case 'Keyboard Navigation Issues': return 'Ensure all interactive elements are accessible via keyboard navigation'; default: return 'Review WCAG guidelines for this specific error type'; } } getPriorityErrors(errors) { // Sortiere Fehler nach Priorität const priorityOrder = [ 'Missing Alt Attributes', 'Missing ARIA Labels', 'Heading Structure Issues', 'Color Contrast Issues', 'Form Label Issues', 'Keyboard Navigation Issues', 'WCAG Compliance Issue', 'General Accessibility Issue' ]; return errors.sort((a, b) => { const aIndex = priorityOrder.indexOf(a.type); const bIndex = priorityOrder.indexOf(b.type); return aIndex - bIndex; }); } } exports.DetailedReportGenerator = DetailedReportGenerator; //# sourceMappingURL=detailed-report.js.map