Uso desde la línea de comandos

Un comando en lugar de código. No requiere un framework de pruebas ni un script de Node y resulta adecuado para un paso del pipeline de CI o para una comprobación rápida de un artefacto de compilación.

Primer análisis

$ npm install -g @surea11y/cli
$ surea11y scan ./index.html
$ surea11y scan https://example.com/ --wcag 2.2

Requiere Node.js ^20.19.0 || ^22.13.0 || >=24.0.0. El resumen nombra la versión de @surea11y/core que ejecutó el análisis:

$ surea11y scan ./index.html
surea11y scan: file:///path/to/index.html
engine: @surea11y/core 1.16.1
pass: 16 fail: 4 cantTell: 4 notApplicable: 121
occurrences by tier: fail: 4 cantTell: 4
needs review: likely fail: 1 likely pass: 0 needs a person: 3
FAIL (4 rule(s)):
button-name-present (serious, 1 fail occurrence(s))
- html > body > main > button
This button has no accessible name.
hint: Give the button visible text, or name it with aria-label, so screen
reader users know what it does.
contrast-enhanced (serious, 1 fail occurrence(s))
- html > body > main > p
Element has insufficient color contrast (AAA) of 2.85:1 (foreground:
#999999, background: #ffffff, font size: 16px, font weight: normal).
Expected contrast ratio of 7:1 (normal text).
hint: Change the text color, the background color, or both, so the
contrast ratio reaches at least 7:1.
contrast-minimum (serious, 1 fail occurrence(s))
- html > body > main > p
Element has insufficient color contrast of 2.85:1 (foreground: #999999,
background: #ffffff, font size: 16px, font weight: normal). Expected
contrast ratio of 4.5:1 (normal text).
hint: Change the text color, the background color, or both, so the
contrast ratio reaches at least 4.5:1.
img-alt-present (serious, 1 fail occurrence(s))
- html > body > main > img
This <img> has no alt attribute.
hint: Add an alt attribute that says what the image shows, or alt="" if
the image is purely decorative.
LIKELY FAIL — confirm (1 occurrence(s)):
- heading-order (minor): html > body > main > h3
This heading jumps from level 1 to level 3, skipping a level.
why: The heading skips a level after the one before it.
cantTell — needs human review (4 rule(s)): heading-order, link-name-quality,
manual-review, page-title-patterns
criteria (WCAG 2.2):
fail 1.1.1 Non-text content: text alternatives; 1.4.3 Contrast: minimum;
1.4.6 Contrast: enhanced; 4.1.2 Name, role, value: accessible name
cantTell 1.2.1 Audio-only and video-only (prerecorded): transcript; 1.2.2
Captions (Prerecorded); 1.3.1 Info and Relationships; 1.3.4
Orientation; 1.3.5 Identify Input Purpose; 1.4.1 Use of Color;
1.4.2 Audio Control; 1.4.4 Resize Text; 1.4.5 Images of Text;
1.4.12 Text Spacing; 2.1.1 Keyboard; 2.1.3 Keyboard (No Exception);
2.2.1 Timing Adjustable; 2.2.2 Pause, Stop, Hide; 2.2.4
Interruptions; 2.4.1 Bypass Blocks; 2.4.2 Page titled; 2.4.3 Focus
order; 2.4.4 Link Purpose (In Context); 2.4.6 Headings and Labels;
2.4.7 Focus visible; 2.4.9 Link Purpose (Link Only); 2.5.8 Target
size: minimum; 3.1.1 Language of page; 3.1.2 Language of Parts;
3.2.5 Change on Request; 3.3.1 Error Identification; 3.3.2 Labels
or Instructions; 3.3.8 Accessible Authentication (Minimum); 4.1.2
Name, role, value: ARIA validity; 4.1.3 Status Messages
notApplicable: 2
A criterion that passes here means the checks that ran found nothing in it,
not that the page conforms.

La línea needs review ordena las preguntas según lo que hace con ellas quien revisa: likely fail (las evidencias de la página apuntan a un fallo, como el salto de nivel de encabezado de este ejemplo), likely pass y needs a person. Los probables fallos se enumeran con el motivo de su tendencia, y cada pregunta en --json y en los informes lleva los pasos para responderla (howToCheck).

El bloque criteria lee el mismo análisis por criterio de WCAG, que es como se suele preguntar ("¿falla el 1.4.3?"): primero fail, luego cantTell, y un recuento de notApplicable. Desde @surea11y/core 1.14 ningún criterio figura como pass: un criterio solo pasa cuando sus reglas comprueban todo lo que pide, y todavía no hay ninguno que se compruebe por completo, así que, cuando todas sus reglas pasan, queda en cantTell para que una persona compruebe el resto. El bloque nunca cambia el código de salida, y --compact lo muestra como recuentos. Si no falla ninguna regla, el resumen termina diciendo que eso no significa que la página sea conforme, y nombra lo que todavía revisa una persona.

Varias páginas, o un sitemap

Nombra varias páginas, enuméralas en un archivo (una ruta o URL por línea, con comentarios #), o apunta el análisis a un sitemap:

$ surea11y scan ./dist/index.html ./dist/pricing.html
$ surea11y scan --urls pages.txt
$ surea11y scan --sitemap https://example.com/sitemap.xml # up to 50 pages; --max-pages to change it

Cada página tiene su propia sección en el resumen, una última línea cuenta las páginas con fallos, y la ejecución falla cuando falla cualquier página. --json imprime un array, --sarif y --junit escriben un archivo que cubre todas las páginas, --html escribe un informe por página (report.html, report-2.html…), y una baseline recuerda en qué página estaba cada fallo conocido. Un sitemap puede ser una URL o un archivo local, sin comprimir o con gzip, y un índice de sitemaps se sigue un nivel hacia abajo. Una página que no se puede analizar detiene la ejecución con el código 2, nombrándola, antes de escribir nada.

En un navegador real

Por defecto, la CLI lee HTML estático. Para páginas cuyo contenido renderiza su JavaScript, instala Playwright en tu proyecto y añade --browser: cada página se abre en Chromium headless, se ejecutan sus scripts y el análisis ve lo que se renderiza, con un layout real para las reglas que lo miden. El motor es el mismo @surea11y/core, y todas las opciones funcionan con él, incluidos informes, baselines, packs y reglas personalizadas.

$ npm install --save-dev playwright
$ npx playwright install chromium
$ surea11y scan https://app.example.com/ https://app.example.com/settings --browser

Una aplicación que obtiene sus datos después de cargar puede hacer que el análisis los espere, y una página se puede analizar con el ancho de un móvil, en modo oscuro o en todas las combinaciones de varios valores:

$ surea11y scan https://app.example.com/orders --browser --wait-for "#orders-table"
$ surea11y scan https://example.com/ --browser --width 320 --color-scheme dark
$ surea11y scan https://example.com/ --browser --width 1280,320 --color-scheme light,dark

--wait-for espera hasta 30 segundos (--wait-timeout lo cambia) y detiene la ejecución con el código 2 si el elemento no aparece nunca. Varios anchos o esquemas de color cargan la página una vez y combinan los análisis en un único resultado por página: el peor resultado de cada regla, y cada hallazgo una sola vez, con las combinaciones en las que se vio (seen in:).

Antes de que cargue cada página, la CLI instala los hooks de internals y de listeners de core, así que el análisis juzga los nombres que los componentes web fijan mediante ElementInternals y los manejadores de clic añadidos desde un script: un role="button" al que nunca llegan Intro ni Espacio falla. --live-regions añade el hook de regiones vivas, de modo que se pregunta por un mensaje de estado añadido con su texto ya dentro, que los lectores de pantalla no suelen anunciar; --no-hooks deja fuera los dos primeros. El resumen nombra el viewport, el esquema de color y los hooks de cada análisis. La CLI no hace clic, no escribe ni inicia sesión: para contenido que solo aparece después de eso, controla el navegador con una de las integraciones (bindings). Los frames dentro de la página todavía no se analizan.

Elegir qué se ejecuta

--wcag selecciona las reglas de un objetivo de conformidad de WCAG, según el nivel que tiene cada criterio en esa versión; --wcag-level establece su nivel (AA salvo que se indique otro). --best-practices añade las reglas que no comprueban ningún criterio de WCAG, como region y heading-order; por sí solo, ejecuta solo esas. --profile ejecuta un perfil de conformidad, como en301549-v4.1.1 o uno propio de un pack.

$ surea11y scan ./dist/index.html --wcag 2.2 # WCAG 2.2, Level A and AA
$ surea11y scan ./dist/index.html --wcag 2.1 --wcag-level A # WCAG 2.1, Level A
$ surea11y scan ./dist/index.html --wcag 2.2 --best-practices # and the best practices

El 4.1.1 Parsing, que WCAG 2.2 eliminó, forma parte de un objetivo 2.1 y no de uno 2.2. --rules y --tags añaden reglas a las de un objetivo, y --exclude-rules se aplica después. Junto a --profile, --best-practices añade sus reglas y el perfil sigue aplicándose; --wcag, --rules y --tags eligen las reglas en lugar de un perfil, así que --profile con cualquiera de ellos sale con 2. Se corresponden con runOnly.wcag, runOnly.bestPractices y engineOptions.profile (ver Opciones del motor).

Nombrar tú mismo las comprobaciones

Con ambos, --rules y --tags ejecutan las reglas que coinciden con los dos. Para decir "esta área, y además estas comprobaciones", pasa --include-mode or, que ejecuta las reglas que coinciden con cualquiera de ellos. Sin él, el análisis de abajo no ejecuta ninguna regla, porque contrast-computable no lleva la etiqueta forms, y sale con 2 en lugar de pasar sin haber comprobado nada.

$ surea11y scan ./dist/form.html --tags forms --rules contrast-computable --include-mode or

Un análisis que nombra comprobaciones informa de los criterios de WCAG a los que pertenecen, en todos los niveles. contrast-computable comprueba el 1.4.3 (AA) y el 1.4.6 (AAA), así que un sitio que cumple AA puede mostrar un criterio AAA que falla y al que nunca aspiró. Sin --wcag, --wcag-level establece el nivel de los criterios de los que se informa, sin cambiar qué reglas se ejecutan:

$ surea11y scan ./index.html --rules contrast-computable --wcag-level AA
surea11y scan: file:///path/to/index.html
engine: @surea11y/core 1.16.1
WCAG level reported: AA
pass: 1 fail: 0 cantTell: 0 notApplicable: 0
occurrences by tier: fail: 0 cantTell: 0
criteria (WCAG 2.2 AA):
cantTell 1.4.3 Contrast: minimum (partly checked: 1 of 2 checks not selected)
A criterion that passes here means the checks that ran found nothing in it,
not that the page conforms.
No rule failed, which is not a claim that the page conforms: the automated rules
found nothing definite. A person still checks the cantTell findings, keyboard
use, how a screen reader reads the page, and the content itself.

El 1.4.3 queda comprobado en parte: su otra comprobación, contrast-minimum, no se seleccionó, así que su resultado solo cubre la comprobación que se ejecutó, y como no falló ninguna regla, el resumen termina recordando que eso no significa que la página sea conforme. Los ids de regla y los niveles se leen sin distinguir mayúsculas de minúsculas (--rules IMG-ALT-PRESENT, --wcag-level aa). --include-mode se corresponde con engineOptions.includeMode, y --wcag-level sin --wcag, con engineOptions.wcagLevel.

Packs

--pack carga un pack (reglas, un estándar o una lista de comprobación, y sus perfiles) por nombre de paquete, resuelto desde el proyecto del directorio de trabajo, o por ruta; --profile ejecuta uno de sus perfiles. Repite --pack para analizar con varios.

$ surea11y scan ./dist/index.html --pack @acme/a11y-policy --profile acme-web-2026
$ surea11y scan ./dist/index.html --pack ./acme-policy-pack.js --profile acme-web-2026

El resumen nombra el perfil y los packs que se ejecutaron, y --json los incluye como engine.profile y engine.packs. Un pack que no se puede encontrar o cargar, o que el motor omite, sale con 2 sin escribir ningún informe, así que un análisis nunca pasa con las comprobaciones del pack sin ejecutar.

Varios perfiles

--profile puede indicarse más de una vez, para juzgar cada página con varios perfiles a la vez, el de un pack junto al de WCAG o al de otro pack (@surea11y/cli 1.5.0, core 1.15.0 y posteriores):

$ surea11y scan ./dist/index.html --pack @surea11y/pack-wai-aria --profile wcag22-aa --profile wai-aria-1.2

Cada perfil juzga la página como lo haría por sí solo, y el resultado se lee como un solo perfil con las reglas de todos: el resultado de una regla es el peor que le dan sus perfiles, así que un fallo en cualquier perfil sale con 1, y los verdicts de cada hallazgo en --json dicen qué hace de él cada perfil (ver Esquema de salida). El resumen los enumera (profiles: wcag22-aa, wai-aria-1.2), --html nombra cada uno y muestra el veredicto de cada uno sobre un hallazgo, y --sarif y --junit condicionan según el peor resultado. Un perfil que no se ejecutó sale con 2, indicando por qué; --allow-profiles-not-run lo convierte en una advertencia, salvo para un perfil cuyo pack omitió el motor, ya que el pack omitido sale él mismo con 2.

Fallar solo con problemas graves

--fail-on-severity (critical, serious, moderate o minor) hace fallar la ejecución solo con reglas que fallan con esa gravedad o más; con --baseline, solo con las nuevas. Todos los fallos se siguen informando, y el resumen marca los que quedan por debajo del nivel, para que un equipo empiece bloqueando los problemas graves y endurezca el umbral a medida que se reduce lo pendiente.

$ surea11y scan --urls pages.txt --fail-on-severity serious

Preguntas que probablemente fallan

--fail-on-lean hace fallar la ejecución también con las preguntas que probablemente fallan (leaningFailures() de core), con la gravedad de --fail-on-severity o más cuando la indicas; --lean-fail-wcag-only cuenta solo las de reglas asociadas a un criterio de WCAG, sin las buenas prácticas. Con él, --junit informa de esa regla como una prueba fallida y --sarif de ese hallazgo como un error, y --write-baseline registra también los probables fallos de hoy, para que --baseline solo bloquee los nuevos. Es opcional porque una tendencia es una evidencia, no una prueba: si un hallazgo tiene tendencia, y hacia dónde, puede cambiar en una versión menor de core.

$ surea11y scan ./dist/index.html --fail-on-lean --lean-fail-wcag-only
$ surea11y scan ./dist/index.html --fail-on-lean --write-baseline baseline.json # once, commit it
$ surea11y scan ./dist/index.html --fail-on-lean --baseline baseline.json # in CI, from then on

Comprobaciones manuales

Un análisis decide lo que las reglas pueden decidir. --manual-checks <path> escribe, junto a él, el resto: una hoja de trabajo de las comprobaciones que ninguna regla decide por completo, para que una persona las haga a mano, con los pasos de cada una, qué cumple y qué falla, y un resultado y notas que registrar (los procedimientos de prueba de core). Con --html, cuyo informe termina ahora con «Lo que queda para una persona», el equipo tiene las dos mitades de la evaluación en una sola ejecución:

$ surea11y scan https://example.com/ --wcag 2.2 --html report.html --manual-checks manual-checks.html
  • Para qué estándar: el analizado. El perfil de un pack da ese estándar y versión, con su propia numeración, cuando el pack da procedimientos; si no, WCAG, en la versión y el nivel de --wcag y --wcag-level, o del objetivo de --profile, y WCAG 2.2 A y AA por defecto. Con varios --profile, una hoja de trabajo por estándar y versión.
  • En qué idioma: el de --locale. Una ruta que termina en .md escribe Markdown en su lugar, con una tarea por comprobación.
  • Varias páginas: una hoja de trabajo por página, numeradas como las de --html, cada una titulada con su página, para que los resultados de cada página queden separados.

Nunca cambia el código de salida. Abre la hoja de trabajo desde el disco, registra cada resultado y notas, y descárgalos como JSON, con el resultado de cada criterio agregado a partir de sus comprobaciones, o como CSV.

Procedimientos, sin análisis

surea11y procedures escribe cómo evalúa una persona a mano cada requisito de un estándar, sin análisis: una referencia para leer, o una hoja de trabajo para completar (--checklist), en HTML, Markdown o JSON.

# How to assess every WCAG 2.2 A and AA criterion, as a page
$ surea11y procedures --wcag 2.2 --wcag-level AA -o wcag-22-aa.html
# A worksheet for a manual audit, titled for it
$ surea11y procedures --wcag-level AA --checklist --title "Audit: example.com" -o audit.html
# Only what no rule decides in full, as Markdown for a repository
$ surea11y procedures --wcag-level AA --automation manual,partial -o left-to-a-person.md
# What needs a screen reader, for a session with a person who uses one
$ surea11y procedures --wcag-level AA --tools screen-reader -o screen-reader-session.html
# One criterion, in French, with the steps a scan's questions give
$ surea11y procedures 1.4.12 --locale fr --variants -o 1.4.12.html
# A pack's standard, under its own numbers
$ surea11y procedures --pack @surea11y/pack-en301549 --profile en301549-v4.1.1 --checklist -o en-301-549.html

--standard y --standard-version nombran el estándar de un pack por clave y versión, --rules conserva solo lo que prueban algunas reglas, --no-record da una hoja de trabajo sin nada que registrar, y --json los datos en lugar de una página. Las opciones de un análisis son aquí un error de uso, como estas lo son en scan. Consulta la referencia de la CLI en GitHub para ver todas las opciones.

Resultados compactos

--compact reduce cada resultado pass y notApplicable a su regla, su resultado y su tipo (engineOptions.output.detail: 'findings'): un --json más pequeño, para un resultado que se guarda como artefacto de CI. El resumen, el código de salida, la línea base y los informes HTML, SARIF y JUnit son los mismos que sin él.

$ surea11y scan ./dist/index.html --compact --json > result.json

Códigos de salida y limitaciones

cantTell no afecta al código de salida salvo que pases --fail-on-lean: el 0 indica que no se han encontrado fallos, el 1 que existe al menos un resultado fail (o, analizando con --baseline, un resultado fail nuevo) en alguna página, y el 2 un error de uso o de análisis, o un análisis que no habría comprobado nada o menos de lo pedido: una lista --rules/--tags que no nombra ninguna regla ni etiqueta conocida, un selector --context que no coincide con nada, una regla personalizada o un pack que no se ejecutó, un --profile que no se aplicó (con varios, uno que no se ejecutó, salvo con --allow-profiles-not-run). Un archivo de --baseline o de --migrate-baseline con una entrada que no lo es (null, sin ruleId, un selector que no es una cadena) sale con 2 antes del análisis, nombrando el archivo y la entrada (@surea11y/cli 1.6.0 y posteriores). El resultado fail es el caso que condiciona CI (--fail-on-severity solo cuenta los de su nivel o más); consulta Baseline / allowlist para saber qué cuenta como "conocido" frente a "nuevo". Una baseline escrita por la versión menor anterior sigue coincidiendo con los hallazgos cuyos códigos de motivo cambiaron desde entonces; --migrate-baseline baseline.json la reescribe con los códigos nuevos (ver Actualizar de versión).

Sin --browser, la CLI solo lee HTML estático: un archivo local, o el cuerpo sin procesar de un GET HTTP(S), y nunca ejecuta el JavaScript de la página. Ningún modo hace clic, escribe ni inicia sesión: para contenido que solo aparece después de eso, usa una de las integraciones (bindings), o llama al motor directamente contra un navegador que controles tú (el Patrón 2 de INTEGRATION.md, la guía de integración en GitHub).

Referencia completa de flags, contrato de reglas personalizadas, packs y recetas de CI: docs/CLI.md. Para plantillas de pipeline de CI en concreto, ver Integración con CI.