🤖 Pa11y & Pa11y-CI — Automatización de Accesibilidad en Terminal y Pipelines

Runner Automatizado de Accesibilidad Web Basado en Chromium Headless

Pa11y es una suite de herramientas de código abierto en Node.js que ejecuta auditorías de accesibilidad web (A11Y) directamente desde la terminal o dentro de pipelines de Integración Continua (Pa11y-CI). Levanta una instancia real de Chromium vía Puppeteer, inyecta motores de análisis como HTML_CodeSniffer (htmlcs) y Deque axe-core (axe), e inspecciona el DOM renderizado en busca de violaciones a los estándares WCAG 2.1 / 2.2 (Niveles A, AA y AAA).


🧭 Arquitectura de Ejecución de Pa11y

flowchart LR
    CLI(["⌨️ Pa11y / Pa11y-CI"]) --> Puppeteer["🌐 Headless Chromium\n(Puppeteer Render + JS Execution)"]
    Puppeteer --> Actions["🎬 Acciones Pre-Auditoría\n(Login, Click Modal, Toggle Dark Mode)"]
    Actions --> Runners["🔬 Motores de Reglas (Runners)"]
    
    Runners --> HTMLCS["📜 HTML_CodeSniffer (htmlcs)\n(Mapeo estricto a técnicas W3C WCAG)"]
    Runners --> AXE["🪓 Deque axe-core (axe)\n(Cero falsos positivos, estándar industrial)"]
    
    HTMLCS & AXE --> Report["📊 Reporte & Exit Code\n(CLI, JSON, CSV, HTML o Fallo en PR)"]

🔬 Comparativa de Motores: htmlcs vs. axe

Uno de los mayores superpoderes de Pa11y es que permite ejecutar ambos motores simultáneamente ("runners": ["axe", "htmlcs"]), logrando cubrir hasta un 55% de los criterios de accesibilidad automatizables (frente al ~35% que detecta un solo motor por separado):

Característicahtmlcs (HTML_CodeSniffer — Default)axe (Deque axe-core)
Filosofía de AnálisisEstricto; evalúa cada técnica formal del documento W3C.Pragmático; prioriza reportar cero falsos positivos.
Formato de CódigosWCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Failcolor-contrast, button-name, image-alt, label
SensibilidadAlta (incluye warnings y notices preventivos).Enfocada en violaciones reales confirmadas en el Accessibility Tree.
Recomendación RyukamiUsar ambos combinados (-r axe -r htmlcs) para máxima cobertura en auditorías locales y en CI.

🚦 Códigos de Salida (Exit Codes) para Scripts y CI

Pa11y utiliza códigos de retorno POSIX estándar para detener despliegues automáticamente cuando se detectan regresiones:

Exit CodeSignificado TécnicoComportamiento en GitHub Actions / Bash
0Éxito TotalCero errores de accesibilidad (o por debajo del --threshold configurado).
1Fallo Técnico / RedLa URL no responde, timeout de Puppeteer o sintaxis inválida en la configuración.
2Violación A11Y DetectadaSe encontraron errores de accesibilidad que superan el umbral permitido; bloquea el Merge del PR.

💻 Comandos Esenciales en Terminal (pa11y CLI)

Ejecución Rápida con npx o Instalación Global

# 1. Auditoría rápida con ambos motores (axe + htmlcs) en estándar WCAG2AA
npx pa11y http://localhost:4321 --runner axe --runner htmlcs --standard WCAG2AA
 
# 2. Exportar resultados en JSON para procesarlos con jq o scripts
npx pa11y https://mise-curso.pages.dev --runner axe --reporter json > pa11y-audit.json
 
# 3. Auditar incluyendo advertencias y capturando screenshot de evidencia
npx pa11y http://localhost:4321 \
  --include-warnings \
  --screen-capture ./evidencia-a11y.png \
  --viewport-width 390 \
  --viewport-height 844
 
# 4. Ignorar una regla específica justificada durante pruebas
npx pa11y http://localhost:4321 --ignore "WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail"

🎬 Interacciones Guionizadas (Actions) — Auditar Modales, Login y Dark Mode

A diferencia de un escáner estático básico, Pa11y puede interactuar con la página antes de lanzar la auditoría usando sentencias en lenguaje natural:

{
  "standard": "WCAG2AA",
  "runners": ["axe", "htmlcs"],
  "actions": [
    "wait for element #theme-toggle to be visible",
    "click element #theme-toggle",
    "wait for element #open-modal-btn to be visible",
    "click element #open-modal-btn",
    "wait for element dialog[open] to be visible",
    "screen capture ./audit-modal-dark.png"
  ]
}

Diccionario de Acciones Soportadas por Pa11y

  • click element <selector> — Simula clic sobre botones, menús o interruptores de tema.
  • set field <selector> to <value> — Rellena inputs de formularios o credenciales de prueba.
  • check field <selector> / uncheck field <selector> — Marca o desmarca checkboxes/radios.
  • wait for element <selector> to be visible (o added / removed / hidden) — Espera cambios reactivos del DOM.
  • wait for url to be <url> (o path to be <path>) — Espera redirecciones tras un login.
  • navigate to <url> — Cambia de ruta conservando las cookies de sesión activas.
  • screen capture <filepath> — Toma captura visual del estado exacto antes de auditar.

🤖 Configuración Maestra de pa11y-ci para Proyectos

Para auditar múltiples rutas o un sitemap.xml entero en un proyecto web, crea el archivo .pa11yci.json en la raíz del repositorio:

{
  "defaults": {
    "standard": "WCAG2AA",
    "runners": ["axe", "htmlcs"],
    "timeout": 30000,
    "wait": 500,
    "threshold": 0,
    "includeWarnings": false,
    "includeNotices": false,
    "viewport": {
      "width": 1280,
      "height": 800
    },
    "chromeLaunchConfig": {
      "args": [
        "--no-sandbox",
        "--disable-setuid-sandbox",
        "--disable-dev-shm-usage"
      ]
    }
  },
  "urls": [
    "http://localhost:4321/",
    "http://localhost:4321/cursos",
    {
      "url": "http://localhost:4321/cursos/neovim",
      "actions": [
        "click element #theme-toggle",
        "wait for 300ms"
      ],
      "screenCapture": "./screenshots/neovim-dark.png"
    }
  ]
}

Auditar un Sitemap Completo Automáticamente

Si tu proyecto en Astro genera sitemap-index.xml o sitemap-0.xml (mediante @astrojs/sitemap), puedes auditar todas las páginas del sitio sin listarlas manualmente:

npx pa11y-ci --sitemap http://localhost:4321/sitemap-0.xml

🔄 Workflow de GitHub Actions (.github/workflows/pa11y.yml)

name: ♿ Pa11y Accessibility CI
 
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
 
jobs:
  a11y-audit:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Código
        uses: actions/checkout@v4
 
      - name: Configurar PNPM & Node.js
        uses: pnpm/action-setup@v4
        with:
          version: 9
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: 'pnpm'
 
      - name: Instalar Dependencias y Compilar
        run: |
          pnpm install --frozen-lockfile
          pnpm build
 
      - name: Levantar Servidor y Ejecutar Pa11y-CI
        run: |
          pnpm preview --port 4321 &
          npx wait-on http://localhost:4321 --timeout 30000
          npx pa11y-ci --config ./.pa11yci.json

🔗 Conexiones en la Bóveda