213 lines
5.8 KiB
JavaScript
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}`);
|