import * as fs from 'fs';
import * as path from 'path';
import { jsonReportFilePath, reportFilePath } from '../../playwright.config';
interface PageSummary {
pageName: string;
critical: number;
serious: number;
moderate: number;
minor: number;
total: number;
}
export function updateAccessibilityReport(pageName: string, results: any) {
const reportDir = path.dirname(jsonReportFilePath);
if (!fs.existsSync(reportDir)) {
fs.mkdirSync(reportDir, { recursive: true });
}
let existingIssues: { [key: string]: any[] } = {};
if (fs.existsSync(jsonReportFilePath)) {
existingIssues = JSON.parse(fs.readFileSync(jsonReportFilePath, 'utf-8'));
}
if (!existingIssues[pageName]) {
existingIssues[pageName] = [];
}
results.violations.forEach(violation => {
const violationWithPage = { ...violation, pageName };
if (!isDuplicateIssue(existingIssues[pageName], violationWithPage)) {
existingIssues[pageName].push(violationWithPage);
}
});
fs.writeFileSync(jsonReportFilePath, JSON.stringify(existingIssues, null, 2));
}
export function consolidateJsonReport() {
if (!fs.existsSync(jsonReportFilePath)) {
console.error('JSON report file does not exist.');
return;
}
const existingIssues = JSON.parse(fs.readFileSync(jsonReportFilePath, 'utf-8'));
// Consolidate issues by page
const consolidatedIssues: { [key: string]: any[] } = {};
Object.keys(existingIssues).forEach(pageName => {
if (!consolidatedIssues[pageName]) {
consolidatedIssues[pageName] = [];
}
existingIssues[pageName].forEach(issue => {
if (!isDuplicateIssue(consolidatedIssues[pageName], issue)) {
consolidatedIssues[pageName].push(issue);
}
});
});
fs.writeFileSync(jsonReportFilePath, JSON.stringify(consolidatedIssues, null, 2));
}
function generateSummaryTable(existingIssues: { [key: string]: any[] }): string {
return `
| Page Name |
Critical |
Serious |
Moderate |
Minor |
Total |
${Object.keys(existingIssues).map(pageName => {
const issues = existingIssues[pageName];
const critical = issues.filter(issue => issue.impact === 'critical').length;
const serious = issues.filter(issue => issue.impact === 'serious').length;
const moderate = issues.filter(issue => issue.impact === 'moderate').length;
const minor = issues.filter(issue => issue.impact === 'minor').length;
const total = issues.length;
return `
| ${pageName} |
${critical} |
${serious} |
${moderate} |
${minor} |
${total} |
`;
}).join('')}
`;
}
function generateImpactSections(issues: any[], pageName: string): string {
return ['critical', 'serious', 'moderate', 'minor'].map(impactType => {
const violations = issues.filter(issue => issue.impact === impactType);
if (violations.length === 0) return '';
return `
${impactType.charAt(0).toUpperCase() + impactType.slice(1)} Impact
| Impact |
Description |
Help URL |
Tags |
Nodes |
${violations.map(violation => `
| ${violation.impact} |
${violation.description} |
${violation.helpUrl} |
${violation.tags.join(', ')} |
${violation.nodes.map(node => `
${node.html}
Target: ${node.target.join(', ')}
${node.failureSummary}
Any:
${node.any.map(check => `
`).join('')}
All:
${node.all.map(check => `
`).join('')}
None:
${node.none.map(check => `
`).join('')}
`).join('')}
|
`).join('')}
`;
}).join('');
}
function generateDetailedSections(existingIssues: { [key: string]: any[] }): string {
return Object.keys(existingIssues).map(pageName => {
const issues = existingIssues[pageName];
const impactSections = generateImpactSections(issues, pageName);
return `
${pageName}
${impactSections}
`;
}).join('');
}
export function createAccessibilityHtmlReport() {
consolidateJsonReport();
if (!fs.existsSync(jsonReportFilePath)) {
console.error('JSON report file does not exist.');
return;
}
const existingIssues = JSON.parse(fs.readFileSync(jsonReportFilePath, 'utf-8'));
const inlineStyles = `
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
color: #333;
}
h1 {
text-align: center;
color: #4CAF50;
}
.summary-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.summary-table th, .summary-table td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
.summary-table th {
background-color: #007BFF;
color: white;
}
.summary-table td a {
color: #007BFF;
text-decoration: none;
}
.summary-table td a:hover {
text-decoration: underline;
}
.page-section {
margin-bottom: 40px;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.impact-section {
margin-bottom: 20px;
}
.violation {
margin-bottom: 20px;
}
.violation .impact {
font-weight: bold;
color: #d9534f;
}
.violation .description {
margin-top: 5px;
}
.violation .helpUrl {
margin-top: 5px;
}
.violation .tags {
margin-top: 5px;
}
.violation .nodes {
margin-top: 10px;
}
.violation .node {
margin-top: 5px;
}
.collapsible {
background-color: #f9f9f9;
color: #333;
cursor: pointer;
padding: 10px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
}
.active, .collapsible:hover {
background-color: #ccc;
}
.content {
padding: 0 18px;
display: none;
overflow: hidden;
background-color: #f1f1f1;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
`;
let reportContent = `
ISS Accessibility Report
Accessibility Report
`;
reportContent += generateSummaryTable(existingIssues);
reportContent += generateDetailedSections(existingIssues);
reportContent += `
`;
try {
fs.writeFileSync(reportFilePath, reportContent);
console.log(`Accessibility Report generated successfully at ${reportFilePath}`);
} catch (error) {
console.error('Error writing report file:', error);
}
}
function isDuplicateIssue(existingIssues: any[], newIssue: any): boolean {
return existingIssues.some(issue => {
return issue.id === newIssue.id && issue.pageName === newIssue.pageName;
});
}