Accessibility Audit Results
${score}
Automated Score / 100
${reviewCount}
Manual Review Findings
`;
if (issues.length) {
const errors = issues.filter(i => i.type === 'error');
const warns = issues.filter(i => i.type === 'warning');
if (errors.length) {
html2 += `
Errors — Must Fix (${errors.length})
`;
errors.forEach(i => { html2 += `
${a11yEsc(i.label)}
${a11yEsc(i.desc)}
${i.fix?`
Fix: ${a11yEsc(i.fix)}
`:''}
`; });
html2 += '
';
}
if (warns.length) {
html2 += `
Warnings (${warns.length})
`;
warns.forEach(i => { html2 += `
${a11yEsc(i.label)}
${a11yEsc(i.desc)}
${i.fix?`
Fix: ${a11yEsc(i.fix)}
`:''}
`; });
html2 += '
';
}
}
if (issues.some(i => i.type === 'review')) {
const reviews = issues.filter(i => i.type === 'review');
html2 += `
Manual Review Required (${reviews.length})
`;
reviews.forEach(i => { html2 += `
${a11yEsc(i.label)}
${a11yEsc(i.desc)}
${i.fix?`
Check: ${a11yEsc(i.fix)}
`:''}
`; });
html2 += '
';
}
if (passes.length) {
html2 += `
Passed (${passes.length})
`;
passes.forEach(p => { html2 += `
✓ ${a11yEsc(p)}
`; });
html2 += '
';
}
if (notes.length) {
html2 += `
Notes
`;
notes.forEach(n => { html2 += `
ℹ ${a11yEsc(n)}
`; });
html2 += '
';
}
// WCAG grading: report verification progress separately from the automated score.
{
const rows = a11yCoverage;
const summarize = level => {
const subset = rows.filter(r => r.level === level);
const count = status => subset.filter(r => r.status === status).length;
return {
total: subset.length,
pass: count('pass'),
fail: count('fail'),
warn: count('warn'),
review: count('review'),
person: count('person'),
notrun: count('notrun')
};
};
const A = summarize('A');
const AA = summarize('AA');
// Existing optional AAA results. Do not interpret these as full AAA conformance.
const aaaLinkPass = passes.find(p => /WCAG 2\.4\.9, AAA/.test(p));
const aaaLinkIssue = issues.find(i => /WCAG 2\.4\.9, AAA/.test(
(i.label || '') + ' ' + (i.desc || '')
));
const aaaLinkResult = aaaLinkIssue
? 'Issues found: ' + a11yEsc(aaaLinkIssue.label)
: aaaLinkPass
? 'Automated check passed: ' + a11yEsc(aaaLinkPass)
: 'No completed result available';
const aaaContrastMeasured = !!(
contrast && contrast.status === 'ok'
);
const aaaContrastBelow = aaaContrastMeasured && Array.isArray(contrast.aaa)
? contrast.aaa.length
: null;
const aaaContrastResult = aaaContrastBelow === null
? 'No completed enhanced-contrast result available'
: aaaContrastBelow > 0
? aaaContrastBelow + ' measured text elements below the AAA enhanced contrast threshold'
: 'No measured text elements below the AAA enhanced contrast threshold';
const pending = x => x.review + x.person + x.notrun + x.warn;
const gradeStatus = (x, prerequisite) =>
x.fail ? 'Failed checks found' :
prerequisite && prerequisite.fail ? 'Level A failures outstanding' :
pending(x) || (prerequisite && pending(prerequisite))
? 'Verification in progress'
: 'Automated checks found no outstanding criteria; human verification required';
const gradeRow = (level, data, status) =>
`
| Level ${level} |
${data.pass} / ${data.total} |
${data.fail} failed; ${data.warn} warnings |
${data.review} further review; ${data.person} human checks; ${data.notrun} not checked |
${status} |
`;
html2 += `
Achieving WCAG 2.2 AA
${A.fail || AA.fail ? 'Detected failures require correction.' : 'Verification in progress.'}
Automated test results do not establish complete WCAG conformance.
All applicable Level A and AA requirements must be verified to claim AA conformance.
WCAG grading and verification breakdown
| Grade |
No problems found |
Detected problems |
Outstanding verification |
Status |
${gradeRow('A', A, gradeStatus(A))}
${gradeRow('AA', AA, gradeStatus(AA, A))}
| Level AAA |
WCAG 2.4.9 — Link Purpose: ${aaaLinkResult}.
WCAG 1.4.6 — Enhanced Contrast: ${aaaContrastResult}.
Coverage: Selected AAA checks only.
Full AAA conformance is not assessed or graded.
|
“No problems found” describes the result of the checks performed,
not a fully verified conformance pass.
Criteria requiring human review or not checked remain outstanding.
`;
}
// WCAG coverage list
{
const cnt = k => a11yCoverage.filter(r => r.status === k).length;