Files
motor-de-encuestas/scripts/a11y-audit.mjs
2026-06-02 10:27:52 -03:00

57 lines
1.6 KiB
JavaScript

/**
* a11y-audit.mjs — Axe-core + jsdom audit sobre el HTML servidor por Next.js
* Uso: node scripts/a11y-audit.mjs [url]
*/
import { JSDOM } from 'jsdom'
import axe from 'axe-core'
const url = process.argv[2] || 'http://localhost:3001'
console.log(`Auditando ${url}\n`)
// 1. Fetch the rendered HTML from the dev server
const res = await fetch(url)
if (!res.ok) {
console.error(`ERROR: servidor respondió ${res.status}`)
process.exit(1)
}
const html = await res.text()
// 2. Parse in jsdom
const dom = new JSDOM(html, {
url,
runScripts: 'dangerously',
resources: 'usable',
})
const { window } = dom
const { document } = window
// Wait a tick for DOM to stabilize
await new Promise((r) => setTimeout(r, 200))
// 3. Configure axe and run
axe.configure({ allowedOrigins: ['<unsafe_all_origins>'] })
const results = await axe.run(document.body, {
runOnly: { type: 'tag', values: ['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'] },
})
const { violations, passes, inapplicable, incomplete } = results
console.log(`✅ Reglas superadas: ${passes.length}`)
console.log(`⚠️ Incompletas: ${incomplete.length}`)
console.log(`— No aplican: ${inapplicable.length}`)
console.log(`\n❌ Violaciones AA: ${violations.length}`)
if (violations.length > 0) {
for (const v of violations) {
console.log(`\n [${v.impact?.toUpperCase()}] ${v.id}${v.description}`)
console.log(` Help: ${v.helpUrl}`)
for (const node of v.nodes.slice(0, 3)) {
console.log(` HTML: ${node.html.slice(0, 120)}`)
}
}
process.exit(1)
} else {
console.log('\n✅ 0 violaciones AA — PASS\n')
}