resume/tests/accessibility/generate-report.js

213 lines
5.8 KiB
JavaScript

/**
* 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}`);