/** * Generate a comprehensive accessibility report * This script analyzes the axe-core and Pa11y test results and generates a report * of all accessibility issues that need to be fixed */ const fs = require('fs'); const path = require('path'); // Directory containing test reports const reportsDir = path.join(__dirname, '../reports'); // Output report file const outputFile = path.join(reportsDir, 'accessibility-issues.md'); // Get all axe-core report files const axeReports = fs.readdirSync(reportsDir) .filter(file => file.startsWith('axe-') && file.endsWith('.json')) .map(file => { try { const content = fs.readFileSync(path.join(reportsDir, file), 'utf8'); return { file, content: JSON.parse(content) }; } catch (error) { console.error(`Error reading ${file}:`, error.message); return { file, content: null }; } }) .filter(report => report.content !== null); // Get all Pa11y report files const pa11yReports = fs.readdirSync(reportsDir) .filter(file => file.startsWith('pa11y') && file.endsWith('.json') && !file.includes('summary')) .map(file => { try { const content = fs.readFileSync(path.join(reportsDir, file), 'utf8'); return { file, content: JSON.parse(content) }; } catch (error) { console.error(`Error reading ${file}:`, error.message); return { file, content: null }; } }) .filter(report => report.content !== null); // Generate report let report = `# Accessibility Issues Report Generated on: ${new Date().toISOString()} This report lists all accessibility issues found by automated testing tools. Fixing these issues will help achieve WCAG 2.1 AAA compliance. ## Summary `; // Process axe-core reports const axeIssues = []; axeReports.forEach(report => { if (report.content && report.content.violations) { report.content.violations.forEach(violation => { violation.nodes.forEach(node => { axeIssues.push({ page: report.file.replace('axe-', '').replace('.json', ''), id: violation.id, impact: violation.impact, description: violation.description, help: violation.help, helpUrl: violation.helpUrl, element: node.html || node.target?.join(', ') || 'Unknown element', wcag: violation.tags.filter(t => t.startsWith('wcag')).join(', ') }); }); }); } }); // Process Pa11y reports const pa11yIssues = []; pa11yReports.forEach(report => { if (report.content && report.content.issues) { report.content.issues.forEach(issue => { pa11yIssues.push({ page: report.file.replace('pa11y', '').replace('.json', ''), code: issue.code, type: issue.type, message: issue.message, context: issue.context, selector: issue.selector }); }); } }); // Add summary counts to report report += `- Total pages tested: ${axeReports.length} - Pages with axe-core issues: ${axeReports.filter(r => r.content?.violations?.length > 0).length} - Total axe-core issues: ${axeIssues.length} - Pages with Pa11y issues: ${pa11yReports.filter(r => r.content?.issues?.length > 0).length} - Total Pa11y issues: ${pa11yIssues.length} ## Common Issues `; // Group issues by type const issuesByType = {}; axeIssues.forEach(issue => { if (!issuesByType[issue.id]) { issuesByType[issue.id] = { count: 0, description: issue.description, help: issue.help, helpUrl: issue.helpUrl, wcag: issue.wcag, pages: new Set() }; } issuesByType[issue.id].count++; issuesByType[issue.id].pages.add(issue.page); }); // Sort issues by count const sortedIssues = Object.entries(issuesByType) .sort((a, b) => b[1].count - a[1].count); // Add common issues to report sortedIssues.forEach(([id, info]) => { report += `### ${id} (${info.count} occurrences) - **Description**: ${info.description} - **Help**: ${info.help} - **WCAG**: ${info.wcag} - **Pages affected**: ${Array.from(info.pages).join(', ')} - **More info**: ${info.helpUrl} `; }); // Add detailed issues by page report += `## Issues by Page `; // Group issues by page const issuesByPage = {}; axeIssues.forEach(issue => { if (!issuesByPage[issue.page]) { issuesByPage[issue.page] = []; } issuesByPage[issue.page].push(issue); }); // Add page-specific issues to report Object.entries(issuesByPage).forEach(([page, issues]) => { report += `### ${page} `; issues.forEach(issue => { report += `- **${issue.id}** (${issue.impact}): ${issue.help} - Element: \`${issue.element.substring(0, 100)}${issue.element.length > 100 ? '...' : ''}\` - WCAG: ${issue.wcag} `; }); }); // Add recommended fixes report += `## Recommended Fixes Based on the issues found, here are the recommended fixes: `; // Add specific recommendations for common issues if (issuesByType['color-contrast-enhanced']) { report += `### Color Contrast Issues 1. Update link colors to meet 7:1 contrast ratio: - Current blue link color (#0056b3) on light background (#f5f5f5) has 6.45:1 ratio - Recommended: Change to darker blue (#004494) for 7:1+ ratio 2. Update CSS in the following files: - \`docker/resume/styles.css\`: Update link colors - \`docker/resume/stories/stories.css\`: Update story-specific link colors `; } // Add implementation plan report += `## Implementation Plan 1. Fix color contrast issues first (highest impact) 2. Address any document structure issues 3. Fix remaining issues by priority (serious > moderate > minor) 4. Re-run tests to verify fixes ## Testing Instructions To test accessibility compliance: \`\`\`bash # Run all accessibility tests npm run test:accessibility # Generate updated report node tests/accessibility/generate-report.js \`\`\` `; // Write report to file fs.writeFileSync(outputFile, report); console.log(`Accessibility issues report generated at: ${outputFile}`);