Opciones del motor
Todos los ejecutores (runDomRulesInPage, runa11yCoreInPage) reciben los mismos cuatro argumentos: (pageUrl, contextSelector, engineOptions, runOnly). Esta página documenta engineOptions y runOnly en su totalidad. Para comprobar una página frente a una versión y un nivel de WCAG, empieza por runOnly.wcag.
Seleccionar qué reglas se ejecutan
Nombra aquello contra lo que pruebas y el motor elige las reglas. Sin ninguna selección, se ejecutan las reglas predeterminadas: todas salvo las reglas opcionales de un estándar o de un pack, que solo se ejecutan una vez desbloqueadas (consulta Reglas opcionales).
| Para ejecutar | Pasa |
|---|---|
| Las reglas predeterminadas: todas salvo las opcionales no desbloqueadas | nada: runOnly null |
| Un objetivo de conformidad de WCAG: las reglas de los criterios de una versión en un nivel y en los inferiores | runOnly: { wcag: { version: '2.2', level: 'AA' } } |
| Lo mismo, y las reglas de buenas prácticas, que no comprueban ningún criterio de WCAG | runOnly: { wcag: { version: '2.2', level: 'AA' }, bestPractices: true } |
| Solo las reglas de buenas prácticas | runOnly: { bestPractices: true } |
| Una versión y un nivel de WCAG por su nombre | engineOptions: { profile: 'wcag21-aa' } |
| Un estándar basado en WCAG, desde un pack (EN 301 549) | engineOptions: { packs: [en301549], profile: 'en301549-v4.1.1' } |
| Lo mismo, y las reglas de buenas prácticas | engineOptions: { packs: [en301549], profile: 'en301549-v4.1.1' }, runOnly: { bestPractices: true } |
// WCAG 2.2 AA, with the best practices:runDomRulesInPage(url, null, {}, {wcag: { version: '2.2', level: 'AA' },bestPractices: true});
Toda regla o bien comprueba criterios de WCAG o bien es una buena práctica, así que { wcag: { version: '2.2', level: 'AAA' }, bestPractices: true } ejecuta todas las reglas salvo las del 4.1.1 Parsing, que WCAG 2.2 eliminó. Para algo más fino, como un solo criterio, una lista de reglas o una exclusión, consulta "Selección avanzada: etiquetas e ids de regla"; esos campos se combinan con los de arriba. Un análisis que nombra reglas informa también de los criterios que comprueban ("Qué criterios informa un análisis").
Seleccionar por objetivo de WCAG (runOnly.wcag)
runOnly.wcag nombra una versión y un nivel de conformidad de WCAG, y selecciona las reglas de los criterios de ese objetivo:
// WCAG 2.2 Level A and AA:runDomRulesInPage(url, null, {}, { wcag: { version: '2.2', level: 'AA' } });
versiones'2.0','2.1'o'2.2';leveles'A','AA'o'AAA'(sin distinguir mayúsculas y minúsculas).- Una regla se selecciona cuando uno de los criterios que nombra forma parte del objetivo: vigente en esa versión (introducido en ella o antes, y no eliminado en ella ni antes), en el nivel del objetivo o en uno inferior, según el nivel que tiene el criterio en esa versión. Los niveles vienen de
WCAG_CRITERIAen@surea11y/core/wcag, que tiene un nivel por versión. - Así, el 4.1.1 Parsing, que 2.2 eliminó, forma parte de los objetivos
{ version: '2.1' }y no de los{ version: '2.2' }:duplicate-idse ejecuta para los primeros y no para los segundos, donde las etiquetas de versión sí lo ejecutarían. - Una regla que no nombra ningún criterio (una regla de buenas prácticas) no forma parte de ningún objetivo. Añádelas con
bestPractices: true(siguiente sección), o reglas sueltas contagsoincludeRuleIds: junto awcag, todos ellos seleccionan reglas además, la unión de las reglas del objetivo y lo que seleccionan los demás.excludeTags,excludeRuleIdsyexcludeTestIdsse aplican después, como siempre. - La versión del objetivo es el objetivo de WCAG de la ejecución (
engine.wcagVersion), salvo que se definaengineOptions.wcagVersion; su nivel decide qué resultados agregados de WCAG se informan, como hace una etiqueta de nivel, salvo que se definaengineOptions.wcagLevel("Indicar el nivel de un análisis que nombra comprobaciones"). - Un objetivo incluye reglas, así que las selecciona en lugar de
engineOptions.profile, igual quetags.getProfileWcagTarget(profile)da el objetivo al que equivale un perfil (consulta "Perfiles de conformidad"), ygetChecksForRunOnly(runOnly, engineOptions)enumera las reglas que ejecuta unrunOnlyconwcag, ygetRulesForRunOnly(runOnly, engineOptions)los resultados agregados que informa. - Cualquier otra cosa lanza
INVALID_RUN_ONLY, nombrando lo que está mal:runOnly.wcag.version must be "2.0", "2.1" or "2.2", not "3.0".
// WCAG 2.1 AA, plus the best-practice rules, without one of them:{ wcag: { version: '2.1', level: 'AA' }, tags: ['best-practice'], excludeRuleIds: ['region'] }
Añadir las buenas prácticas (runOnly.bestPractices)
bestPractices: true selecciona las reglas de buenas prácticas: las reglas que no nombran ningún criterio de WCAG, como region, landmark-one-main, heading-order, page-has-heading-one, skip-link, tabindex e image-redundant-alt. Son las reglas etiquetadas como best-practice, así que equivale a añadir esa etiqueta. Un hallazgo de una de ellas es una buena práctica, no un fallo de WCAG: ningún resultado agregado de WCAG lo cuenta. La mayoría informan cantTell; una cuyo hallazgo es en sí una barrera informa fail, como hace empty-heading con un encabezado sin nombre.
- Junto a
wcag,tagso ids de regla, añade esas reglas a lo que ellos seleccionan; las exclusiones se aplican después, así queexcludeRuleIds: ['region']sigue dejando fueraregion. - Por sí solo, selecciona solo las reglas de buenas prácticas.
false, u omitirlo, no añade nada. Por sí solo,{ bestPractices: false }es una selección vacía, así que se ejecutan las reglas predeterminadas, como con{}.- Cualquier otro valor lanza
INVALID_RUN_ONLY:runOnly.bestPractices must be true or false, not "yes". - Junto a
engineOptions.profile, añade las reglas de buenas prácticas a las del perfil, y el perfil se sigue aplicando: sus reglas, sus resultados agregados, sus asociaciones yengine.profile, igual que sin él.{ bestPractices: true }conprofile: 'en301549-v4.1.1'ejecuta ese estándar y las buenas prácticas. Las reglas de buenas prácticas no cuentan en ninguno de los resultados agregados del perfil, ya que no comprueban ningún criterio de WCAG.
// WCAG 2.1 AA and the best practices, without one of them:{ wcag: { version: '2.1', level: 'AA' }, bestPractices: true, excludeRuleIds: ['region'] }
Perfiles de conformidad
engineOptions.profile nombra un objetivo de conformidad en lugar de enumerar su conjunto de etiquetas. Cada versión de WCAG tiene un perfil por nivel, llamado wcag<version>-<level>:
| Perfil | Ejecuta las reglas con las etiquetas | Objetivo WCAG | getProfileWcagTarget | Por qué |
|---|---|---|---|---|
wcag20-a | wcag2a | 2.0 | { version: '2.0', level: 'A' } | WCAG 2.0 nivel A |
wcag20-aa | wcag2a, wcag2aa | 2.0 | { version: '2.0', level: 'AA' } | WCAG 2.0 nivel A y AA |
wcag20-aaa | wcag2a, wcag2aa, wcag2aaa | 2.0 | { version: '2.0', level: 'AAA' } | WCAG 2.0 nivel A, AA y AAA |
wcag21-a | wcag2a, wcag21a | 2.1 | { version: '2.1', level: 'A' } | WCAG 2.1 nivel A |
wcag21-aa | wcag2a, wcag2aa, wcag21a, wcag21aa | 2.1 | { version: '2.1', level: 'AA' } | WCAG 2.1 nivel A y AA |
wcag21-aaa | las etiquetas de wcag21-aa y wcag2aaa, wcag21aaa | 2.1 | { version: '2.1', level: 'AAA' } | WCAG 2.1 nivel A, AA y AAA |
wcag22-a | wcag2a, wcag21a, wcag22a | 2.2 | { version: '2.2', level: 'A' } | WCAG 2.2 nivel A |
wcag22-aa | wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22a, wcag22aa | 2.2 | { version: '2.2', level: 'AA' } | WCAG 2.2 nivel A y AA |
wcag22-aaa | las etiquetas de wcag22-aa y wcag2aaa, wcag21aaa, wcag22aaa | 2.2 | { version: '2.2', level: 'AAA' } | WCAG 2.2 nivel A, AA y AAA |
en301549-v4.1.1 | igual que wcag22-aa | 2.2 | { version: '2.2', level: 'AA' } | Obsoleto desde la 1.13.0, se elimina en la 2.0.0: usa @surea11y/pack-en301549, o wcag22-aa para WCAG solo. El capítulo 9 de EN 301 549 V4.1.1 reformula WCAG 2.2 A y AA |
en301549-v3.2.1 | igual que wcag21-aa | 2.1 | { version: '2.1', level: 'AA' } | Obsoleto desde la 1.13.0, se elimina en la 2.0.0: usa @surea11y/pack-en301549, o wcag21-aa para WCAG solo (que da 4.1.1 Procesamiento por satisfecho, como hacen las erratas de WCAG 2.1). El capítulo 9 de EN 301 549 V3.2.1 reformula WCAG 2.1 A y AA, incluido 4.1.1 Procesamiento |
section508 | igual que wcag20-aa | 2.0 | { version: '2.0', level: 'AA' } | Obsoleto desde la 1.16.0, se elimina en la 2.0.0: usa wcag20-aa, que ejecuta las mismas reglas y da los mismos resultados. Un análisis que lo nombra lo avisa una vez por proceso |
getProfileWcagTarget(profile) da el objetivo runOnly.wcag al que equivale el conjunto de etiquetas de un perfil, o null para un nombre que no es un perfil. Cada nivel de WCAG incluye los inferiores, como los niveles de WCAG: wcag22-aaa ejecuta todas las reglas de wcag22-aa y añade las de AAA, así que un análisis nombra un nivel, no varios. wcag22-a y wcag22-aaa son nuevos en core 1.15.0, y los perfiles de WCAG 2.0 y 2.1 en la 1.16.0: cada uno ejecuta lo que ejecuta runOnly: { wcag: { version, level } } y, a diferencia de runOnly, puede analizarse junto al perfil de un pack. Un perfil sigue seleccionando por sus etiquetas, como en la tabla: con wcag22-aa (y wcag22-a y wcag22-aaa), duplicate-id (4.1.1) se ejecuta y no puede dar fail, mientras que { wcag: getProfileWcagTarget('wcag22-aa') } lo deja fuera.
runDomRulesInPage(url, null, { profile: 'wcag21-aa' }, null);
en301549-v4.1.1 y en301549-v3.2.1 pasan al pack de EN 301 549, @surea11y/pack-en301549, y salen de core en la 2.0.0. Funcionan como antes, con un console.warn por proceso. Con el pack (packs: [en301549]), un análisis toma de él los mismos nombres y no muestra el aviso; los perfiles del pack informan un resultado por cláusula en lugar de los resultados agregados de WCAG. section508 también sale de core en la 2.0.0, obsoleto desde la 1.16.0: solo era WCAG 2.0 A y AA con otro nombre, así que usa wcag20-aa, que ejecuta las mismas reglas. Ver cómo core declara obsoleto un estándar.
Los perfiles propios de core son los de WCAG: cuando los obsoletos se vayan en la 2.0.0, el perfil de cualquier otro estándar vendrá de un pack, cuyo estándar o lista de comprobación añade sus propios perfiles a esta lista.
Varios perfiles a la vez
profile acepta también una lista, con los packs que los traen en packs: un solo análisis juzga entonces la página con WCAG y con WAI-ARIA, con EN 301 549 y tu propia política, o con dos versiones de un estándar mientras pasas de una a otra. Cada perfil juzga la página como lo haría un análisis solo de él, y el resultado se lee como un solo perfil con las reglas de todos: el outcome de una comprobación es el peor que le dan sus perfiles, y los verdicts de cada hallazgo dicen qué hace de él cada perfil (Esquema de salida). Core 1.15.0 y posteriores.
const waiAria = require('@surea11y/pack-wai-aria');const result = runDomRulesInPage(url, null, {packs: [waiAria],profile: ['wcag22-aa', 'wai-aria-1.2']});// <div role="group" aria-checked="true">: an attribute the role doesn't// support, a question for WCAG 4.1.2 and a failure of WAI-ARIA.result.checksResults.find((c) => c.ruleId === 'aria-allowed-attr').verdicts;// { 'wcag22-aa': 'cantTell', 'wai-aria-1.2': 'fail' }
Cada perfil se analiza por turno, sobre la misma página, así que el análisis tarda más o menos lo que uno por perfil. Un perfil que no se aplica (no existe ese perfil, su pack se omitió, o un include de runOnly elige las reglas en su lugar) figura en engine.profilesNotRun con el motivo, y los demás se siguen ejecutando; SARIF, JUnit, la CLI y los test matchers tratan ese análisis como un error, ya que juzgó menos de lo que se le pidió. Una lista de uno es su único nombre, y analiza exactamente como antes. El pack de WAI-ARIA es el caso para el que se creó.
El objetivo de WCAG se deduce de las etiquetas igual que con un conjunto escrito a mano (ver "Filtrado por versión de WCAG" más abajo), así que en301549-v3.2.1 apunta a WCAG 2.1 y en301549-v4.1.1 a WCAG 2.2. Un id duplicado todavía puede dar fail con en301549-v3.2.1 porque su perfil mantiene el texto del 4.1.1 (keepsParsing, ver más abajo); con en301549-v4.1.1 no. El perfil de un pack puede nombrar su versión en su lugar, con wcagVersion (Packs): un perfil que ejecuta solo las reglas que asocia su estándar no tiene etiquetas de WCAG que impliquen una. Los nombres no distinguen mayúsculas y minúsculas. Una ejecución que usó un perfil lo devuelve como engine.profile.
Precedencia: cualquier cosa que incluya reglas las selecciona en lugar del perfil: un runOnly con wcag, tags, includeRuleIds o includeTestIds, o un include en engineOptions.rules/.tags/.tests. Las exclusiones se siguen aplicando sobre el perfil, tanto si vienen de runOnly (excludeTags, excludeRuleIds, excludeTestIds, de modo que el disableTags() de una integración acota el perfil en lugar de sustituirlo) como, si no hay filtro runOnly, de engineOptions (tags.exclude, rules.exclude, tests.exclude), y un engineOptions.wcagVersion explícito sigue ganando a la versión que implica o nombra el perfil. Un perfil que no surte efecto (un nombre desconocido, o uno anulado como se acaba de describir) no es un error: la ejecución continúa como si no se hubiera indicado ninguno, registra un console.warn que explica por qué y no lleva engine.profile. runOnly.bestPractices: true no es una inclusión de ese tipo: añade las reglas de buenas prácticas a las del perfil, y el perfil se aplica ("Añadir las buenas prácticas").
El perfil de un estándar también puede dejar reglas fuera, cuando su estándar exime de un criterio de WCAG o sustituye una comprobación de WCAG por una propia: las reglas que nombra, las reglas de las que exime todos los criterios y los resultados agregados de WCAG de los criterios eximidos no se ejecutan, y el catálogo de reglas también los deja fuera. Una regla que también comprueba un criterio que el perfil conserva se sigue ejecutando (link-name-present, que comprueba 2.4.4 y 4.1.2, con un perfil que exime del 2.4.4), y engine.profileExcludes nombra lo que se dejó fuera. Hoy ningún perfil incluido excluye nada.
Un perfil solo elige qué reglas se ejecutan. No dice nada sobre si superarlas cumple el estándar del que toma el nombre: la mayoría de los criterios de éxito necesitan un juicio humano que ninguna regla automatizada cubre (ver lo que este motor no puede decirte).
Un perfil de EN 301 549 también activa las cláusulas de EN 301 549 de la versión a la que apunta, como si se hubiera pasado mappings: ['en301549:V4.1.1'] (o V3.2.1); ver "Otros estándares" más abajo. El perfil de cualquier estándar activa su propia versión de la misma forma. Un perfil con mappedRules también ejecuta, sean cuales sean sus etiquetas, las reglas a las que se asocia su estándar: las que no tienen asociación con WCAG, como heading-order y skip-link, no tienen ninguna etiqueta de WCAG por la que seleccionarse. Un estándar con requisitos propios, o la lista de comprobación de una organización, llega al motor como un pack, con sus propios nombres de perfil, reglas y resultados agregados. El propio motor no incluye ningún estándar así.
Reglas opcionales
Algunas reglas comprueban requisitos propios de un estándar que WCAG no impone: un estándar nacional puede exigir un doctype, o prohibir atributos de presentación como bgcolor. Un fail de una regla así es un fallo de ese estándar, no de WCAG, así que estas reglas están desactivadas por defecto. Cada una lleva la etiqueta de regla de su estándar y solo se ejecuta cuando la selección la pide:
- mediante el perfil del estándar, que enumera la etiqueta,
- por esa etiqueta (
tags: { include: '<tag>' }, sola o con otras), - por su id (
rules: { include: '<rule id>' }, orunOnly.includeRuleIds), - por el id de uno de los resultados agregados propios de su estándar que la agrupe (
rules: { include: '<rollup id>' }ejecuta las reglas de ese resultado agregado, opcionales o no), o - desbloqueándola con
engineOptions.optInRules, más abajo.
Nada más selecciona una: ni una ejecución por defecto, ni un conjunto de etiquetas de WCAG, ni un perfil de WCAG o de EN 301 549, ni un id de resultado agregado de WCAG. Las exclusiones se les aplican como a cualquier regla. Seleccionar solo la etiqueta ejecuta las reglas propias de ese estándar, no las reglas de WCAG con las que también está asociado, así que responde a "qué exige el estándar además de WCAG" y no es una auditoría frente a él. Para una auditoría, usa el perfil del estándar: con la etiqueta sola, sus propios resultados agregados informan cantTell para cualquier requisito cuyas reglas no se ejecutaron. Una regla añadida mediante customRules que lleva la etiqueta sigue la misma barrera. Hoy ninguno de los estándares incluidos en el motor tiene reglas opcionales; la etiqueta de espacio de nombres de un pack funciona así.
Ejecutar todas las reglas (optInRules)
Para ejecutar todas las reglas del motor, sea cual sea el estándar al que pertenecen, omite el perfil y desbloquea las reglas opcionales:
runDomRulesInPage(url, null, { optInRules: 'all' }, null);
'all' desbloquea las reglas opcionales de todos los estándares; una lista de etiquetas desbloquea solo esas. Levanta la barrera y nada más: el resto de la selección sigue decidiendo qué reglas se ejecutan. Así, sin filtro y sin perfil, como arriba, la ejecución cubre todas las reglas y los resultados agregados de todos los estándares; con profile: 'wcag22-aa' sigue ejecutando solo las reglas de WCAG, ya que las reglas opcionales no llevan etiquetas de WCAG. Las exclusiones se aplican como siempre. Una etiqueta que no es de reglas opcionales se ignora con un console.warn. Solo esta opción del motor desbloquea: runOnly no tiene clave optInTags, así que una indicada ahí es una clave desconocida, que lanza INVALID_RUN_ONLY por sí sola y se ignora con un aviso junto a claves que runOnly lee, con un mensaje que remite a engineOptions.optInRules.
Sirve para ver todo lo que el motor puede informar, durante el desarrollo o al explorar un sitio. No es un objetivo de conformidad: una ejecución así hace fallar una página por cosas que WCAG permite y que solo otro estándar prohíbe. El resultado lo indica: engine.optInRules enumera las etiquetas cuyas reglas se ejecutaron, y el informe HTML, SARIF y JUnit lo muestran junto al perfil. No añade a los resultados los números de ningún otro estándar; para eso, pasa mappings, por ejemplo { optInRules: 'all', mappings: ['<key>'] }.
Otros estándares (mappings)
El meta.normativeMappings de cada resultado nombra los criterios de éxito de WCAG que comprueba. engineOptions.mappings añade el requisito de otro estándar que corresponde a cada uno. Por defecto no añade ninguno: una cláusula de un estándar con el que no auditas es ruido en cada etiqueta SARIF, propiedad JUnit e informe.
| Valor | Añade |
|---|---|
'en301549' | La cláusula del capítulo 9 de EN 301 549 de cada criterio, en todas las versiones que la tienen (V3.2.1 y V4.1.1) |
'en301549:V3.2.1', 'en301549:V4.1.1' | Lo mismo, solo para esa versión |
runDomRulesInPage(url, null, { mappings: ['en301549:V3.2.1'] }, null);
Los mapeos en301549 pasan al pack de EN 301 549, @surea11y/pack-en301549, y salen de core en la 2.0.0. Funcionan como antes, con un console.warn por proceso. Con el pack, mappings: ['en301549'] toma el mismo nombre y da a cada resultado las mismas entradas, sin aviso.
Acepta un array o una cadena separada por comas, con nombres y versiones sin distinguir mayúsculas y minúsculas. Con profile: 'en301549-v4.1.1' las cláusulas de V4.1.1 están ahí sin pedirlas, y mappings puede añadir más. Un nombre o versión para el que el motor no tiene tabla se ignora con un console.warn. Una ejecución que lleva cualquier otro estándar informa cuáles en engine.mappings, con la grafía canónica (["en301549:V3.2.1"], o ["en301549"] para todas las versiones).
Solo cambia lo que nombra un resultado, nunca qué reglas se ejecutan ni sus resultados. El catálogo de reglas sigue la misma opción: getChecksCatalog(engineOptions), getCheckDefById(ruleId, engineOptions), getChecksForRunOnly(runOnly, engineOptions), getRulesCatalog(engineOptions), getRulesForRunOnly(runOnly, engineOptions) y getCompositeRuleById(id, engineOptions) nombran los estándares que nombraría un análisis con esas opciones, incluido un perfil cuando se aplicaría, así que una entrada del catálogo y un resultado siempre coinciden. Sin opciones, solo nombran WCAG. Una regla añadida mediante customRules conserva exactamente las asociaciones que declara. Qué son las cláusulas y en qué se diferencian las dos versiones está en Mapeo de conformidad con WCAG.
Selección avanzada: etiquetas e ids de regla
Los campos siguientes seleccionan por las etiquetas que llevan las reglas y por ids de regla. Recurre a ellos para lo que no dicen un objetivo de WCAG y bestPractices: un criterio (tags: ['wcag1412']), una lista de reglas, una exclusión o un conjunto de etiquetas propio. Se combinan con wcag y bestPractices: lo que incluyen se añade a lo que estos seleccionan, y lo que excluyen se quita después.
Hay dos formas independientes de indicarlos: el cuarto argumento (runOnly), o bien engineOptions.rules/.tags/.tests/.includeMode. Si runOnly contiene algún filtro, tiene prioridad; de lo contrario, el motor recurre a engineOptions. No combines ambos mecanismos: no se aplican simultáneamente. Elige uno. engineOptions.rules, .tags y .tests aceptan { include, exclude }; una lista o una cadena simples son la lista de inclusión.
Mediante runOnly (4.º argumento)
runDomRulesInPage(url, null, {}, {includeRuleIds: ['img-alt-present', 'button-name-present'],excludeRuleIds: ['region'],tags: ['wcag412'],excludeTags: ['best-practice'],includeMode: 'and' // 'and' (default) | 'or' — see below});
Un array o una cadena simples funcionan como forma abreviada: runOnly: ['img-alt-present', 'button-name-present'] ejecuta esas reglas (un id compuesto incluye sus reglas), y runOnly: ['wcag2a', 'wcag2aa'] equivale a { tags: ['wcag2a', 'wcag2aa'] }. Un array no puede mezclar ids de regla y etiquetas, y cada valor tiene que nombrar una regla (integrada, compuesta o una de engineOptions.customRules) o una etiqueta: cualquier otra cosa lanza un error, para que una errata no pueda ejecutar en silencio todas las reglas o ninguna. Usa la forma de objeto para combinar ids y etiquetas o para excluir. Antes de la 1.10.0, un array simple se ignoraba y se ejecutaban todas las reglas.
| Campo | Tipo | Significado |
|---|---|---|
wcag | { version, level } | Un objetivo de conformidad de WCAG: las reglas de los criterios de esa versión en ese nivel y en los inferiores. Consulta Seleccionar por objetivo de WCAG, más arriba. |
bestPractices | boolean | true añade las reglas de buenas prácticas. Consulta Añadir las buenas prácticas, más arriba. |
includeRuleIds | string[] | Ejecuta solo estos IDs de regla (además, para un ID compuesto, sus reglas atómicas hijas). |
excludeRuleIds | string[] | Nunca ejecuta estos, se aplica después de la inclusión. |
includeTestIds / excludeTestIds | string[] | Misma coincidencia que arriba: se mantiene como un campo separado porque las reglas se llaman internamente "tests" (la unidad ejecutable atómica); funcionalmente idéntico a includeRuleIds/excludeRuleIds hoy en día. |
tags | string[] | Ejecuta solo las reglas que llevan al menos una de estas etiquetas (por ejemplo, wcag412, wcag2aa, best-practice). |
excludeTags | string[] | Nunca ejecuta reglas que lleven cualquiera de estas etiquetas, se aplica después de la inclusión. |
includeMode | 'and' | 'or' | Cuando se dan tanto una inclusión de ID como una de etiqueta: 'and' (predeterminado) requiere que una regla satisfaga ambas; 'or' ejecuta una regla si satisface cualquiera de las dos. Irrelevante si solo usas una dimensión. |
Cada uno de estos acepta un array o una cadena separada por comas, igual que la forma de engineOptions de más abajo: includeRuleIds: 'img-alt-present, button-name-present' y includeRuleIds: ['img-alt-present', 'button-name-present'] son equivalentes.
Los nombres se comprueban, aquí y en engineOptions.rules/.tags más abajo. Una lista de inclusión (includeRuleIds, includeTestIds, tags, el values heredado, rules.include, tags.include) en la que ningún valor nombra una regla o una etiqueta (una que lleva una regla o un resultado agregado, así que la etiqueta de un estándar se conoce aunque solo la lleven sus resultados agregados) lanza un error con code: 'INVALID_RUN_ONLY' y un mensaje que nombra el campo y los valores, ya que no seleccionaría nada y una ejecución sin reglas se lee como un resultado limpio. Una selección cuyos nombres existen todos pero cuyas partes se anulan entre sí (una regla incluida y excluida a la vez, reglas y etiquetas sin ninguna regla en común con includeMode: 'and') tampoco ejecuta ninguna regla: el análisis avisa, nombrando las partes, y lanza INVALID_RUN_ONLY con strictOptions. includeMode es 'and' u 'or'; cualquier otro valor se lee como 'and', con un aviso, y lanza un error con strictOptions; en una integración de navegador, lo define .includeMode('or'). Un valor que no nombra nada junto a otros que sí, o en una lista de exclusión, se ignora con un console.warn. Antes de la 1.10.0, todos esos valores se ignoraban en silencio.
Las nueve etiquetas de versión/nivel de WCAG, de wcag2a a wcag22aaa, siempre se conocen, la lleve o no alguna regla. Algunas no las lleva hoy ninguna (wcag21aaa, wcag22a, wcag22aaa): sus criterios no tienen ninguna regla automatizada, y eso no es una errata. En una lista de inclusión junto a otros valores, una etiqueta así se señala con un console.info, no con un aviso:
[surea11y] runOnly.tags: no rules for WCAG 2.2 Level A ("wcag22a"); its criteria need manual review.
engineOptions.logUntestedWcag: false omite esa línea. Cuando todos los valores de una lista de inclusión son etiquetas así, no se ejecutaría nada, así que sigue lanzando INVALID_RUN_ONLY, explicando por qué. Junto a un objetivo runOnly.wcag o bestPractices: true, que seleccionan reglas propias, solo se señala. En una lista de exclusión no se toca.
Los IDs de regla van sin prefijo (sin prefijo del motor), por ejemplo 'img-alt-present'. Por compatibilidad con versiones anteriores, la coincidencia también acepta una forma heredada con el prefijo a11ycore- del mismo id ('a11ycore-img-alt-present'). Los ids se comparan sin distinguir mayúsculas y minúsculas, igual que las etiquetas: 'IMG-ALT-PRESENT' selecciona img-alt-present, en toda lista que nombra reglas (runOnly en cada una de sus formas, engineOptions.rules y engineOptions.tests, inclusión y exclusión). No hay dos reglas cuyos ids difieran solo en mayúsculas, así que esto no puede seleccionar la equivocada.
También se acepta la forma { type, values } como valor completo de runOnly: { type: 'tag', values: ['wcag2a', 'wcag2aa'] } equivale a { tags: ['wcag2a', 'wcag2aa'] }, y { type: 'rule', values: ['img-alt-present'] } equivale a { includeRuleIds: ['img-alt-present'] } ('tags' y 'rules' también funcionan). values puede ser una cadena separada por comas, sus nombres se comprueban como cualquier id de regla o etiqueta, y las demás claves que lo acompañan (excludeTags, excludeRuleIds...) se siguen aplicando. Un Set de nombres se lee como la lista que contiene. Una clave que la forma de objeto no lee, junto a otras que sí, se ignora con un aviso. Cualquier otro type lanza INVALID_RUN_ONLY, igual que un runOnly que sea un número o un booleano, o un objeto sin ninguna clave que el motor lea ({ includeRuleId: [...] }): antes, cada uno de estos casos ejecutaba todas las reglas. Un array, una cadena o un objeto vacíos siguen significando la selección predeterminada.
Qué criterios informa un análisis
Un análisis informa el resultado agregado de un criterio (rulesResults) cuando la selección lo selecciona: un objetivo de WCAG o una etiqueta de versión/nivel, un perfil, el propio id del resultado agregado, o ninguna selección. También informa el resultado agregado de cada criterio que comprueba una regla que la selección nombró por sí misma, cuando esa regla se ejecutó:
- por su id (
includeRuleIds,includeTestIds,rules.include, o la propia lista de reglas de un perfil), - por una etiqueta que no es de WCAG (la de una regla personalizada, la de un pack o la de un estándar; las etiquetas de WCAG son las de versión/nivel, las de criterio como
wcag244, ywcag22-removed, así que una etiqueta personalizada comowcagteamno lo es), - por
optInRules, o - como regla de buenas prácticas (
bestPractices).
Una regla que el perfil de un estándar ejecuta solo porque su estándar la asocia (mappedRules) está nombrada para ese estándar, no por sí misma: añade los requisitos del estándar y ninguno de sus criterios de WCAG. Así, un perfil que ejecuta solo lo que pide su estándar informa únicamente de ese estándar (Packs); una regla que nombra su lista rules añade también sus criterios de WCAG. Antes de la 1.12.0, un análisis que nombraba reglas en lugar de criterios tenía un rulesResults vacío.
// The unnamed link fails link-name-present, and with it 2.4.4 and 4.1.2:runDomRulesInPage(url, null, {}, { includeRuleIds: ['link-name-present'] });// rulesResults: wcag-2.4.4-link-purpose-in-context: fail, wcag-4.1.2-name: fail
- El veredicto es el del propio resultado agregado. Una regla que falla hace fallar el criterio. Una regla que se supera no hace que se supere cuando el análisis dejó fuera las demás reglas del criterio: es
cantTell, conreasonCodecomposite.rollup.cantTell.notSelectedChild, y cada regla que el análisis no seleccionó figura entre los contribuyentes comomissingconnotSelected: true. Con todas ellas seleccionadas y aprobadas, un criterio de WCAG sigue siendocantTell(composite.rollup.cantTell.partialCheck), ya que las reglas de ningún criterio comprueban todavía todo lo que pide (consulta Mapeo de conformidad con WCAG). El informe HTML muestra «Comprobado en parte: 1 de 2 comprobaciones no se seleccionó para este análisis» debajo. Consulta el esquema de salida. - Una etiqueta de criterio nombra su propio criterio.
tags: ['wcag244']informa del 2.4.4, y no de los demás criterios que comprueban sus reglas (el 4.1.2 en el caso delink-name-present). Una regla que entra por el id de un resultado agregado, un objetivo de WCAG, una etiqueta de versión o de nivel, o un perfil de WCAG no añade ningún criterio: ahí la selección nombra los criterios. Así, un análisis que selecciona sus criterios informa lo mismo que antes. - Se aplican la versión y el nivel de WCAG de la ejecución. Un criterio solo se añade si está vigente en
engine.wcagVersion(duplicate-idpor sí sola no añade el 4.1.1 con 2.2, y sí lo hace conwcagVersion: '2.1'), y si está en el nivel de la ejecución o por debajo, como haría un objetivo:engineOptions.wcagLevelcuando se indica (siguiente sección); si no, el nivel que da la selección (runOnly.wcag.level, o las etiquetas de versión/nivel junto a los ids de regla). Sin ninguno de los dos, se informan todos los niveles. - Las exclusiones se aplican. Un resultado agregado que la selección excluye (
excludeRuleIds: ['wcag-4.1.2-name'], o una etiqueta) no se añade. Una regla que excluyó quien llama cuenta como no seleccionada. Una regla que excluye un perfil acota el criterio: figura comomissingsinnotSelected, y un criterio del que exime el perfil nunca se añade. - Los resultados agregados propios de un estándar (uno por requisito) se añaden del mismo modo, pero solo mientras el estándar está en juego: el perfil aplicado apunta a él, o la selección nombra su etiqueta, o
optInRuleslo desbloquea. Un análisis de WCAG nunca muestra los requisitos de un estándar que nadie pidió. Un perfil que no se aplicó, ymappingspor sí solo, no ponen un estándar en juego. Con su perfil, solo se añade la versión del perfil; desbloqueado sin perfil, se añaden todas las versiones, igual que las informa un análisis seleccionado por su etiqueta. Esto vale tanto para un estándar o una lista de comprobación de un pack como para uno incluido: un perfil de lista de comprobación que nombra sus reglas (tags: [],rules: [...]) obtiene sus criterios de WCAG y sus propios elementos. - La lista antes del análisis.
getRulesForRunOnly(runOnly, engineOptions)enumera los resultados agregados que informa un análisis con esa selección y esas opciones, incluidos los añadidos, como entradas degetRulesCatalog. Los calcula con el mismo paso de agregación que el análisis, así que ambos coinciden;getChecksForRunOnlyenumera las reglas.getRulesCatalog(engineOptions)enumera todos los resultados agregados que las opciones ponen a disposición, sea cual sea la selección. Una herramienta puede registrar qué comprueba un análisis antes de ejecutarlo; los constructores de las integraciones de navegador dan las mismas listas comoplannedChecks()yplannedCriteria().
Indicar el nivel de un análisis que nombra comprobaciones (wcagLevel)
Un análisis pensado como WCAG 2.2 AA que ejecuta solo algunas comprobaciones las nombra, e indica la versión en engineOptions.wcagVersion. Eso no dice ningún nivel, así que los criterios de esas comprobaciones se informan en todos los niveles: contrast-computable comprueba el 1.4.3 (AA) y el 1.4.6 (AAA), y se informan ambos. engineOptions.wcagLevel indica el nivel:
// Only the contrast checks of a WCAG 2.2 AA scan: 1.4.3 is reported, 1.4.6 is not.runDomRulesInPage(url, null,{ wcagVersion: '2.2', wcagLevel: 'AA' },{ includeRuleIds: ['contrast-computable'] });
- Valores.
'A','AA'o'AAA', en mayúsculas o minúsculas. Cualquier otro valor se ignora con unconsole.warn(engineOptions.wcagLevel: ignoring "AA+"; use "A", "AA" or "AAA". ...), y lanzaINVALID_ENGINE_OPTIONSconstrictOptions. La ejecución informa un nivel válido comoengine.wcagLevel, escrito'A','AA'o'AAA'; sin la opción,engine.wcagLeveles el nivel que implica la selección, y no aparece cuando no implica ninguno. - Decide lo que se informa, nunca lo que se ejecuta. La selección decide lo que se ejecuta, igual que sin la opción. Una comprobación por encima del nivel que la selección nombra se sigue ejecutando e informa su propio resultado; solo sus criterios por encima del nivel quedan fuera de
rulesResults. - Se aplica a todos los resultados agregados de WCAG, no solo a los criterios añadidos por comprobaciones nombradas.
wcagLevel: 'AA'en un análisis completo, un perfil o una selección por etiquetas deja los criterios AAA fuera derulesResults, mientras sus comprobaciones se siguen ejecutando e informando enchecksResults. En esto difiere dewcagVersion, que nunca quita un resultado agregado que la selección selecciona: un análisis 2.2 sigue informando del 4.1.1, con sus reglas convertidas acantTell. Un análisis sin la opción informa lo mismo que antes. - Gana al nivel que implica la selección (
runOnly.wcag.level, o el nivel más alto que nombran sus etiquetas de versión/nivel), igual que unwcagVersionexplícito gana a la versión que implican. Un conflicto entre ambos no genera aviso, igual que no lo genera uno entrewcagVersiony la versión de un objetivo;engine.wcagLevelmuestra el nivel por el que se filtraron los criterios. - Un resultado agregado nombrado por id se informa tal como se nombró.
includeRuleIds: ['wcag-1.4.6-contrast-enhanced']conwcagLevel: 'AA'informa del 1.4.6: la opción dice qué criterios informar, no que se quite uno que pidió quien llama. Un nivel que implican las propias etiquetas de la selección sigue filtrando un resultado agregado nombrado, igual que sin la opción. - Los resultados agregados propios de un estándar no tienen nivel de WCAG y no se filtran por él. El perfil de un pack no puede indicar un nivel (sus etiquetas implican uno); quien lo llama puede pasar
wcagLevel. getRulesForRunOnly(runOnly, engineOptions)la respeta, así que enumera lo que informa el análisis, y avisa de un valor no válido igual que el análisis, o lanza un error constrictOptions.
Sin la opción, las etiquetas de versión/nivel junto a los ids de regla también dan un nivel, ya que el includeMode: 'and' predeterminado conserva las reglas nombradas que llevan una de ellas: { includeRuleIds: ['contrast-computable'], tags: wcagTags('2.2') } ejecuta contrast-computable e informa solo del 1.4.3. Pero las etiquetas también deciden lo que se ejecuta: una regla nombrada sin etiqueta de WCAG (una regla de buenas prácticas como region, una regla personalizada sin etiquetas de WCAG), o una que comprueba solo criterios AAA, queda fuera de la ejecución, y una etiqueta de versión/nivel que no lleva ninguna regla (wcag22a) se señala con un console.info. wcagLevel indica el nivel sin cambiar lo que se ejecuta. En una integración de navegador, lo define el .wcagLevel('AA') del constructor.
Filtrado por versión de WCAG (2.0, 2.1, 2.2)
Cada regla y compuesto lleva exactamente una etiqueta de nivel de versión de origen de WCAG: wcag2a/wcag2aa/wcag2aaa para un Criterio de Éxito (SC) que sea línea base de WCAG 2.0, wcag21a/wcag21aa/wcag21aaa para uno introducido en WCAG 2.1 (por ejemplo, 1.3.5 Identify Input Purpose), wcag22a/wcag22aa/wcag22aaa para uno introducido en WCAG 2.2 (por ejemplo, 2.5.8 Target Size Minimum). Una regla obtiene solo la etiqueta de la versión de origen real de su criterio de éxito: un criterio de éxito introducido en 2.1 nunca lleva también la etiqueta wcag2aa, ya que no existe bajo un objetivo de conformidad de WCAG 2.0.
runOnly.wcag selecciona un objetivo de conformidad en un solo campo (más arriba), y deja fuera el 4.1.1 bajo 2.2. Con etiquetas, dado que las versiones son acumulativas (2.1 = 2.0 + nuevo; 2.2 = 2.0 + 2.1 + nuevo), selecciona un objetivo de conformidad de versión de WCAG combinando conjuntos de etiquetas: la coincidencia OR del motor sobre tags (cualquier coincidencia incluye la regla) hace el resto:
// WCAG 2.0 AA only (excludes every 2.1/2.2-introduced SC, even at level AA):{ tags: ['wcag2a', 'wcag2aa'] }// WCAG 2.1 AA conformance (2.0 baseline + everything 2.1 added, both at A and AA):{ tags: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'] }// WCAG 2.2 AA conformance (2.0 baseline + 2.1 additions + 2.2 additions):{ tags: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22a', 'wcag22aa'] }// Just the SCs 2.2 introduced, nothing else:{ tags: ['wcag22a', 'wcag22aa', 'wcag22aaa'] }
Un criterio de éxito va en sentido contrario. WCAG 2.2 eliminó el criterio de éxito 4.1.1 Parsing: el único criterio que se ha eliminado alguna vez en lugar de añadirse. Una regla mapeada a él lleva su etiqueta de origen 2.0 (wcag2a) como cualquier otra regla de línea base, más wcag22-removed, y por eso los conjuntos de etiquetas de versión de arriba la incluyen bajo un objetivo 2.2, donde no pertenece.
No tienes que hacer nada al respecto. El motor resuelve una versión objetivo de WCAG para cada ejecución y, cuando ese objetivo es 2.2, una regla wcag22-removed no puede informar fail: sigue ejecutándose, sigue informando cada ocurrencia que encontró, pero su resultado se fuerza a cantTell y el resultado lleva un campo wcagVersionScope que explica por qué (consulta el esquema de salida). Nada se descarta silenciosamente, y una ejecución 2.2 no queda bloqueada por un criterio que 2.2 no contiene.
Con un objetivo 2.0 o 2.1 ocurre lo mismo: las erratas de 2023 a WCAG 2.0 y 2.1 dan el 4.1.1 por cumplido siempre para el contenido en HTML o XML, así que la regla pregunta en lugar de fallar, y wcagVersionScope.by es "errata". La única excepción es un perfil cuyo estándar mantiene el texto del 4.1.1, como en301549-v3.2.1 (keepsParsing en el perfil del estándar, ver Packs): ahí un id duplicado todavía puede dar fail. Core 1.14.0 y posteriores; antes, un objetivo 2.0 o 2.1 dejaba que fallara.
La versión objetivo se resuelve en este orden:
engineOptions.wcagVersion:'2.0','2.1'o'2.2', si lo configuras.- El
wcagVersiondel perfil de pack que aplica la ejecución, si nombra uno: un estándar basado en WCAG 2.1 cuyo perfil ejecuta solo las reglas que asocia no selecciona ninguna etiqueta de WCAG, así que indica la versión él mismo. Gana a la versión que implican las propias etiquetas del perfil. Un perfil que no surte efecto (anulado por una selección tuya) no aporta ninguna versión. - La versión de un objetivo
runOnly.wcag. - Las etiquetas de origen de versión en tu propio filtro: un conjunto que llega como máximo hasta
wcag21a/wcag21aase interpreta como objetivo 2.1, uno que contiene cualquierwcag22*etiqueta como 2.2, uno con solo etiquetaswcag2*como 2.0. Solo cuentan esas nueve etiquetas: una etiqueta de criterio de éxito (wcag411) obest-practiceno dice nada sobre una versión. - En caso contrario
'2.2', el objetivo predeterminado de este motor.
// Nothing to declare: a plain run already targets 2.2, so a duplicate id// comes back cantTell rather than fail.runDomRulesInPage(url, null, {}, null);// Conformance-testing against 2.1, where SC 4.1.1 still exists:runDomRulesInPage(url, null, { wcagVersion: '2.1' }, null);// Same thing, implied by the tag set — no extra option needed:runDomRulesInPage(url, null, {}, { tags: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'] });
La versión de destino resuelta se incluye en cada resultado como engine.wcagVersion, así puedes confirmar cuál usó realmente una ejecución.
Si prefieres no ver la regla en absoluto bajo 2.2, exclúyela directamente: la etiqueta está ahí precisamente para eso:
// WCAG 2.2 AA conformance, with the removed criterion left out entirely:{tags: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22a', 'wcag22aa'],excludeTags: ['wcag22-removed']}
duplicate-id es la única regla que lleva esa etiqueta hoy en día. Si se deja, sigue informando algo real (un id duplicado rompe <label for>, los enlaces de fragmento y getElementById diga lo que diga el estándar), simplemente no es un fallo de conformidad 2.2.
Mediante engineOptions (sin runOnly)
El mismo filtrado, expresado como cadenas separadas por comas (o arrays) anidadas en engineOptions:
runDomRulesInPage(url, null, {rules: { include: 'img-alt-present, button-name-present', exclude: 'region' },tags: { include: 'wcag412', exclude: 'best-practice' },includeMode: 'and'}, null);
rules.include/.exclude, tags.include/.exclude, tests.include/.exclude (alias de rules), y el includeMode de nivel superior reflejan exactamente los campos de runOnly de arriba. Las cadenas separadas por comas se recortan, se eliminan duplicados y los tokens vacíos se descartan automáticamente. Una lista o una cadena simples, como rules: ['img-alt-present'], se leen como la lista de inclusión.
engineOptions: el resto
const engineOptions = {strictOptions: false, // default false — true throws on an unknown option or a value of the wrong typelocale: 'en', // default 'en'; de-DE falls back to de, then to en per stringwcagVersion: '2.2', // default '2.2' — the conformance targetwcagLevel: 'AA', // optional — the level of the criteria reportedprofile: 'wcag22-aa', // optional — a named conformance target, or a list of themmappings: ['en301549'], // optional — standards besides WCAG to name on each resultoptInRules: 'all', // optional — also run rules other standards add beyond WCAGmessages: { de: { /* key: text */ } }, // optional caller-supplied dictionaries; win over built-in onesincludeHiddenElements: false, // default false — set true to evaluate hidden/collapsed subtrees tooincludeShadowDom: true, // default true — opt OUT with false to skip open shadow rootsfragment: false, // default false — set true when the scan target isn't a real pageembeddedAriaHidden: false, // default false — a frame's document shown under aria-hidden="true"embeddedInert: false, // default false — a frame's document shown under [inert]topLevelDocument: true, // optional — unset, a document shown in a frame is no page of its ownassumeModal: false, // default false — under jsdom, take an open <dialog aria-modal="true"> as modalexcludeSelectors: ['#cookie-banner', '.third-party-widget'], // array or comma-separated stringstyleSheetTexts: [{ href: 'https://cdn.example/site.css', text: '/* its CSS */' }], // sheets the page can't readtimestamp: '2026-07-20T12:00:00Z', // optional — engine has no built-in clockperfStats: false, // default false — internal timing counters, debug-only shapeprofileRules: false, // default false — per-rule timings; needs perfStatscontrast: {mode: 'strictConformance', // 'strictConformance' (default) | 'auditorAssist'rootCanvasFallback: '#ffffff', // a canvas to measure on in place of the page's own; unset, the page's color scheme gives itrootCanvasFallbackSet: true // echoed on each result: whether rootCanvasFallback was given; read back, false means the default},visibilityMode: undefined, // 'styleOnly' | 'styleAndGeometry'; unset: geometry with a layout, else stylespolicyContract: 'a11y', // 'a11y' (default) | 'generic' | inline contract objectpolicy: { // optional overrides on top of policyContractcoerceManualFailToCantTell: true},output: {includeSelector: true, // set false to suppress auto-filled selectorsincludeHtml: true,detail: 'full' // 'findings': pass/notApplicable results keep only rule, outcome, type},rules: {'some-rule-id': {excludeSelectors: ['.some-noisy-widget'] // narrows candidates for THIS rule only}},probes: { /* optional host-supplied evidence */ },customRules: [ /* runtime-registered rules, see below */ ],packs: [ /* rules and standards from outside core, see Packs */ ],// Only read by runa11yCoreAcrossFrames. Ignored by runDomRulesInPage/runa11yCoreInPage.pingWaitTime: 500, // ms to wait for a child frame to answer a pingframeWaitTime: 60000 // ms to wait for a child frame's full scan result};
| Opción | Significado |
|---|---|
strictOptions | Predeterminado false. true comprueba todas las opciones antes del análisis, y lanza INVALID_ENGINE_OPTIONS ante una clave que el motor no lee o un valor de tipo incorrecto o fuera de su conjunto; consulta "Detectar errores en las opciones" más abajo. |
locale | Cualquier cadena. Un código con una subetiqueta recurre primero a su idioma base, así de-DE usa de; si eso falla, inglés. Las cadenas individuales luego recurren de la misma manera (configuración regional elegida → en → el texto literal en inglés de la regla), por lo que una configuración regional parcialmente traducida nunca produce texto faltante. Todo esto es silencioso en las propias cadenas, así que el resultado informa lo que realmente ocurrió en engine.locale: compruébalo si necesitas saber si obtuviste el idioma que pediste. Consulta Configuración regional. |
wcagVersion | '2.0', '2.1' o '2.2': qué versión de WCAG está probando la conformidad de la ejecución. El valor predeterminado es la versión que nombra el perfil de pack de la ejecución (su wcagVersion); si no, la que implican tus etiquetas de origen de versión, y '2.2' cuando no implican ninguna. Lo que cambia es qué criterios informa un análisis y, para el criterio de éxito 4.1.1 Parsing, por qué una regla etiquetada wcag22-removed no puede dar fail: se eliminó en 2.2, y las erratas de 2.0 y 2.1 lo dan siempre por cumplido, salvo con un perfil cuyo estándar lo mantiene, como en301549-v3.2.1. Consulta "Filtrado por versión de WCAG" más arriba. Cualquier otro valor, de cualquier tipo (el número 2.1, '3.0'), se ignora con un console.warn que nombra la versión a la que apunta la ejecución en su lugar. |
wcagLevel | Opcional: 'A', 'AA' o 'AAA', en mayúsculas o minúsculas: el nivel de WCAG de los criterios que informa una ejecución. Los resultados agregados de WCAG por encima de él quedan fuera de rulesResults mientras sus reglas se siguen ejecutando; nunca cambia lo que se ejecuta. Gana al nivel que implica la selección; un resultado agregado nombrado por id se informa tal como se nombró. Se devuelve como engine.wcagLevel, que sin la opción contiene el nivel que implica la selección, si implica alguno. Cualquier otro valor se ignora con un console.warn, y lanza un error con strictOptions. Consulta "Indicar el nivel de un análisis que nombra comprobaciones" más arriba. |
profile | Objetivo de conformidad con nombre, opcional: 'wcag20-a', 'wcag20-aa', 'wcag20-aaa', 'wcag21-a', 'wcag21-aa', 'wcag21-aaa', 'wcag22-a', 'wcag22-aa', 'wcag22-aaa', los obsoletos 'en301549-v4.1.1', 'en301549-v3.2.1' y 'section508', o uno propio de un pack; o una lista de ellos, para un análisis de varios perfiles a la vez. Selecciona reglas por el conjunto de etiquetas correspondiente cuando nada más incluye ninguna, y el objetivo de WCAG se deduce de esas etiquetas. Se devuelve como engine.profile cuando surtió efecto (en una lista, el primero que se ejecutó, con todos en engine.profiles); si no, se ignora con un aviso en consola. Un nombre que no es de ningún perfil lanza INVALID_ENGINE_OPTIONS con strictOptions, también en una lista, con un mensaje que nombra los perfiles que hay (también en knownProfiles del error): sin perfil, el análisis ejecutaría todas las reglas. Ver "Perfiles de conformidad" más arriba. |
mappings | Estándares opcionales además de WCAG cuyos requisitos nombra meta.normativeMappings: 'en301549', 'en301549:V3.2.1' o 'en301549:V4.1.1', o la clave del estándar de un pack, como array o cadena separada por comas. Por defecto ninguno, así que los resultados solo nombran WCAG; un perfil de EN 301 549 añade su propia versión. Se devuelve como engine.mappings cuando se aplica alguno. Ver "Otros estándares" más arriba. |
logUntestedWcag | Predeterminado true. false omite la nota de console.info para una etiqueta de versión/nivel de WCAG que no lleva ninguna regla (wcag22a), en una lista de inclusión junto a otras; consulta "Mediante runOnly" más arriba. |
optInRules | Opcional: 'all', o una lista de etiquetas de reglas opcionales, como array o cadena separada por comas. Desbloquea esas reglas fuera del perfil de su estándar; el resto de la selección sigue decidiendo qué se ejecuta. Se devuelve como engine.optInRules cuando ejecutó una regla que la selección no habría ejecutado de otro modo; las etiquetas desconocidas se ignoran con un aviso en consola. Ver "Ejecutar todas las reglas" más arriba. |
messages | Opcional { [locale]: { key: text } }. Se comprueba antes que las propias tablas del motor, así que puede sobrescribir cadenas individuales o proporcionar un idioma que la compilación no incluye. Las claves que omitas recurren al comportamiento normal, así que una sobrescritura parcial está bien. Así es como el paquete independiente para navegador recibe un archivo lateral de configuración regional, y es la única forma de introducir un diccionario en un contexto de página, ya que el ejecutor en la página está serializado y no puede leer archivos. A diferencia de las demás opciones, no se devuelve en el engineOptions de cada resultado; engine.locale informa del diccionario usado. Consulta Configuración regional. |
includeHiddenElements | Predeterminado false: las consultas auxiliares excluyen elementos ocultos por mecanismos estructurales/CSS como display:none, [hidden], <details> cerrados (todo salvo su primer <summary>, a cualquier profundidad), contenido content-visibility:hidden y hidden="until-found", el contenido de un subárbol [inert] (que las reglas sobre cómo se ve el contenido, como contraste y espaciado del texto, siguen juzgando, ya que se dibuja), y elementos host ocultos de solo renderizado (con sus descendientes también excluidos). runa11yCoreAcrossFrames no analiza un frame oculto de esta forma. Configura true para incluir esos subárboles ocultos/colapsados en la evaluación (comportamiento heredado/de marcado estático). Amplía lo que devuelven las consultas compartidas; aun así, la mayoría de las reglas juzgan solo lo que está en el árbol de accesibilidad, ya que un elemento oculto no tiene nombre ni rol que comprobar, así que para ellas no cambia nada. Importa en las reglas sobre el propio marcado, como una referencia de ID rota. |
includeShadowDom | Predeterminado true: las reglas que usan helpers.queryAllSmart atraviesan las raíces shadow abiertas. Configura false para analizar solo el DOM ligero (light DOM). Las raíces shadow cerradas nunca son alcanzables de todos modos: ninguna API del DOM las expone: se pregunta (cantTell, name_closedContent) por un elemento cuyo nombre podría venir de un elemento personalizado sin contenido que el motor pueda leer (un botón, enlace, elemento de menú, opción, pestaña, elemento de árbol, summary o tooltip), en lugar de hacerlo fallar. |
fragment | Predeterminado false. Un puñado de reglas comprueba la presencia de una propiedad que existe una vez por página real: page-title-present, html-lang-attr-present, html-xml-lang-mismatch, aria-hidden-body, css-orientation-lock, meta-refresh-no-exceptions, meta-refresh-timing-absent, meta-viewport-zoom-enabled, meta-viewport-large, page-title-patterns, region, bypass-blocks-present, landmark-one-main, page-has-heading-one, e informa correctamente notApplicable para estas en cuanto contextSelector ha delimitado una ejecución más estrecha que el documento completo (document.documentElement ya no está entre las raíces resueltas), ya que nunca se esperó que un subárbol delimitado llevara su propio <title>/<html lang>/etc. Configura fragment: true para el caso que la delimitación por sí sola no puede detectar: un objetivo de análisis que es el documento completo dado pero que nunca pretendió representar una página real (por ejemplo, un fragmento de componente aislado analizado por sí solo): esto fuerza la misma notApplicable restringida incluso sin delimitar. Un documento mostrado en un frame tampoco es una página propia: page-title-present, page-title-patterns, html-lang-attr-present, meta-viewport-zoom-enabled, meta-viewport-large, region, bypass-blocks-present, landmark-one-main y page-has-heading-one son notApplicable en él diga lo que diga esta opción, salvo que topLevelDocument: true (más abajo) diga que es la página. Core 1.15.0 y posteriores. |
embeddedAriaHidden | Predeterminado false. true indica que el documento se muestra en un frame bajo aria-hidden="true" (en el <iframe> o en un elemento que lo rodea): cada elemento se lee como se lee el contenido aria-hidden, fuera del árbol de accesibilidad salvo lo que lo anula. Las reglas sobre nombres y roles (img-alt-present, button-name-present, …) dejan entonces de aplicarse, y las de lo que se ve y se maneja (contraste, foco, teclado) siguen aplicándose. runa11yCoreAcrossFrames la establece para ese frame, y un binding que analiza los frames por sí mismo la establece en el engineOptions de ese frame. El foco que toma ese frame es el hallazgo aria-hidden-focus de la página superior sobre el <iframe>. Core 1.15.0 y posteriores. |
embeddedInert | Predeterminado false. true indica que el documento se muestra en un frame bajo [inert]: cada elemento se lee como se lee el contenido inerte, fuera del árbol de accesibilidad y sin tomar el foco, así que solo lo juzgan las reglas sobre cómo se ve el contenido (contraste, espaciado del texto). runa11yCoreAcrossFrames la establece para ese frame, y deja fuera un frame tras un diálogo modal abierto, como deja fuera uno oculto; un binding que analiza los frames por sí mismo hace lo mismo. Core 1.15.0 y posteriores. |
topLevelDocument | Sin valor por defecto: si el documento es una página propia. Sin valor, lo es cuando es el de la ventana superior: un documento mostrado en un frame no es una página propia, y las nueve reglas sobre la página que nombra la fila fragment son notApplicable en él. Un ejecutor de pruebas que muestra la página bajo prueba en un frame propio, como hace Cypress, la pone a true (@surea11y/cypress lo hace por ti); false lee un documento de nivel superior como el de un frame. runa11yCoreAcrossFrames no la pasa a los frames que analiza. Core 1.15.0 y posteriores. |
assumeModal | Por defecto false. Solo un <dialog> abierto con showModal() (uno que coincide con :modal) es modal: el navegador vuelve inerte el resto de la página, y el motor deja esa página fuera de todas las reglas y no cuenta nada de ella como enfocable. Un diálogo abierto con el atributo open o con show() no es modal, ni siquiera con aria-modal="true", así que el mismo marcado recibe los mismos veredictos en jsdom y en un navegador. jsdom no puede abrir un diálogo modal (no tiene showModal()), así que una prueba allí que sustituye showModal() poniendo open y aria-modal="true" en el diálogo pone assumeModal: true: ese diálogo se toma entonces como modal, como lo tomaban en jsdom las versiones anteriores a la 1.16.0. Un DOM que puede abrir un diálogo modal (cualquier navegador) la ignora. Ver Limitaciones conocidas. |
excludeSelectors | Los elementos que coinciden con cualquiera de estos selectores (y sus descendientes, incluido lo que hay en sus shadow roots, y los documentos de los frames entre ellos) se omiten por completo, para todas las reglas: útil para banners de cookies, contenidos incrustados de terceros o widgets conocidos por generar ruido que no controlas. Para excluir algo de una sola regla específica en su lugar, usa rules[ruleId].excludeSelectors más abajo. Un array de selectores, o una cadena con una lista de selectores: '#cookie-banner, img:not(.a, .b)' equivale a ['#cookie-banner', 'img:not(.a, .b)'], ya que la cadena solo se corta en las comas entre selectores. Cada selector se aplica por separado: uno que no es CSS válido no excluye nada, con un console.warn, y los demás se siguen aplicando. |
styleSheetTexts | El texto de hojas de estilo que la página no puede leer, [{ href, text }]: una hoja de otro origen, por su URL, y su CSS. Las reglas que leen el CSS (css-orientation-lock, css-hidden-focus, css-focus-indicator-suppressed) lo leen en lugar de la hoja. El engineOptions de cada resultado lo repite como los href de las hojas, [{ href }], sin su texto. preloadStyleSheets() obtiene desde dentro de la página las que el servidor comparte, y runa11yCoreInPageAsync las obtiene antes de analizar; una herramienta que controla el navegador puede obtener las demás desde fuera. Consulta «Style sheets from another origin» en la guía de integración de core en GitHub. Core 1.14.0 y posteriores. |
timestamp | Se pasa directamente al campo timestamp de nivel superior del resultado; el motor no genera uno por sí mismo (determinista por diseño). Un valor que no es una cadena (un Date, un número) se ignora con un console.warn; pasa new Date().toISOString(). |
contrast.mode | strictConformance (predeterminado): las reglas de contraste permanecen en silencio (notApplicable/omitidas) cuando el fondo realmente renderizado no se puede calcular con confianza, para proteger contra falsos fail. auditorAssist: sacrifica parte de ese margen de seguridad a cambio de más hallazgos, pensado para un auditor humano que revisará los casos marcados, no para una puerta de CI sin supervisión. Una página que no pinta ningún fondo opaco no es uno de esos casos: el lienzo que hay detrás se deduce del propio esquema de color de la página, así que su texto se mide en cualquiera de los dos modos sin suponer nada. Donde no se puede conocer el lienzo de la página (en un frame, con colores forzados), auditorAssist mide el texto sobre contrast.rootCanvasFallback, y lo registra como ROOT_CANVAS_FALLBACK. |
contrast.rootCanvasFallback | Un color de lienzo para una página que no pinta ningún fondo opaco. Sin indicarlo, las reglas de contraste miden el texto de esa página sobre el lienzo que el navegador pinta detrás, en cualquiera de los dos modos: el lienzo del esquema de color en que se dibuja la página, que decide su propio color-scheme (en la raíz, o la forma <meta>). Una página que no declara ninguno se dibuja en claro, sobre blanco, prefiera lo que prefiera el usuario; light dark se dibuja sobre blanco para un usuario en modo claro y sobre el lienzo oscuro para uno en modo oscuro, y su texto se mide en los dos esquemas, y falla donde falla en cualquiera de ellos (data.details.colorScheme nombra cuál). Con jsdom, que no resuelve colores del sistema, el motor usa los de Chromium, y pregunta por el texto cuyos colores no puede deducir allí (COLOR_SCHEME_NOT_RENDERED). Si se indica, blanco incluido, el color sustituye al lienzo de la página en todos los esquemas: el texto se mide sobre él una vez, registrado como una suposición (ROOT_CANVAS_FALLBACK). El lienzo de la página no se puede conocer en un frame, cuyo lienzo puede dejar ver la página padre, ni con colores forzados: ahí contrast-computable pregunta y las reglas de ratio dejan fuera el texto, salvo que auditorAssist lo mida sobre este color. El engineOptions.contrast de cada resultado repite el color usado, blanco si no se indicó ninguno. |
contrast.rootCanvasFallbackSet | Se repite en cada resultado: true cuando contrast.rootCanvasFallback es del llamador, false para el blanco predeterminado (también cuando el valor indicado no era un color utilizable). No hace falta como entrada: las opciones que se pasan de nuevo desde la copia de un resultado se leen tal como estaban, así que false mantiene el blanco repetido como predeterminado. Un valor que no es true ni false produce un aviso y se lee como no indicado. Core 1.14.0 y posteriores. |
visibilityMode | Controla cuán estrictas son las tres reglas de contraste (contrast-minimum, contrast-enhanced, contrast-computable) al decidir si un nodo de texto es realmente elegible para comprobar. No lo lee ninguna otra regla. Sin definir (el valor predeterminado), es 'styleAndGeometry' donde la página tiene diseño, es decir, en cualquier análisis en navegador, y 'styleOnly' donde no lo tiene (jsdom): quien lee solo ve el texto que se dibuja en algún lugar visible, y eso solo lo puede saber el diseño. 'styleOnly': la elegibilidad es solo CSS: display, visibility, opacity, ocultamiento por ancestro, etc. 'styleAndGeometry': añade comprobaciones reales de diseño (getClientRects()/getBoundingClientRect()) encima de eso: el texto sin rects de cliente o con ancho/alto cero también se excluye, igual que el texto situado por completo por encima o a la izquierda de la página, adonde no llega ningún desplazamiento (la técnica left: -9999px), y el texto que un ancestro con overflow: hidden o clip recorta por completo (height: 0; overflow: hidden, una diapositiva de carrusel fuera de la vista). Una caja con desplazamiento (auto, scroll) no excluye su texto, porque quien lee puede llegar a él. Las opciones de un <select> se juzgan por la posición de su <select> en la página. En ambos modos se excluye el texto con un tamaño de fuente de 0 o un color totalmente transparente, ya que no se dibuja nada; el texto transparente que deja ver un fondo a través de sus glifos (background-clip: text, en él o en un antecesor) no se excluye: se mide en el color de ese fondo cuando es sólido, y se pregunta por él cuando es un degradado o una imagen. Configura 'styleOnly' en un navegador para comprobar el texto solo a partir de los estilos calculados, como hacían las versiones anteriores; bajo jsdom puro (runDomRulesInPage) no hay un motor de diseño real, así que 'styleAndGeometry' básicamente solo añade comprobaciones de tamaño cero de getBoundingClientRect(), no una detección real de recorte/desbordamiento. Consulta limitaciones conocidas. |
policyContract | Consulta POLICY.md: controla qué valores de resultado/confianza están permitidos y si los fail que emitirían las reglas manuales se fuerzan a cantTell. |
output.includeSelector / .includeHtml | Suprime el autocompletado automático de selector/html del motor. Dado que todas las reglas se migraron para informar su elemento en lugar de construir ocurrencias a mano (1.5.0), ese autocompletado es el camino que siguen casi todas las reglas: configurar includeSelector: false / includeHtml: false elimina selectores y fragmentos de HTML de casi todas ellas. Un puñado todavía ensambla esos campos por sí mismo dentro de runInPage y no se ve afectado: entre ellas contrast-minimum/contrast-enhanced (cuyos hallazgos son fragmentos de texto, no elementos), page-title-present e identical-links-same-purpose. Así que esto reduce sustancialmente la salida pero aún no es una garantía de que no haya selectores ni HTML en ninguna parte del resultado. |
output.detail | 'full' (predeterminado) o 'findings': un resultado más pequeño, que conserva completos solo los resultados de comprobación que informan algo (fail, cantTell y cualquiera que enumere ocurrencias); cada pass y notApplicable restante conserva su ruleId, su outcome y su type, y su margin o su error si lo tiene. Los resultados agregados y los veredictos no cambian, y los generadores de informes lo leen como un resultado completo. Una regla que el catálogo de core no podría volver a rellenar se queda completa: todas las reglas de un análisis con packs, una regla personalizada, y una que los messages del análisis reformulan. Consulta engine.outputDetail; en TypeScript, ese resultado es un CompactScanResult. |
rules[ruleId] | Se pasa a esa regla como ctx.config, y, específicamente para excludeSelectors, el propio motor lo lee antes de que la regla se ejecute. Consulta "excludeSelectors por regla" más abajo. Cualquier otra clave es solo de paso: ninguna regla distribuida toma nada más de ella. Los ajustes que declara una regla, como los umbrales de contrast-minimum, son los de su estándar, así que el valor que indique quien llama se descarta: un resultado que nombra WCAG 1.4.3 siempre se decide a 4.5:1. Un estándar con otros umbrales tiene su propia regla, una variante, que un pack puede aportar. Una clave se compara igual que un id de regla, sin distinguir mayúsculas y minúsculas o con el prefijo heredado a11ycore-; una que no nombra ninguna regla del análisis genera un aviso con el id más parecido. |
packs | Packs opcionales de @surea11y/core/pack: reglas, variantes de las reglas de core, un estándar o una lista de comprobación y mensajes de fuera de core, que se suman al análisis. Una lista: los objetos de pack para runDomRulesInPage y las funciones de catálogo en Node, y para runa11yCoreInPage el name@version de los packs que un packScript registró en la página. Cualquier otra cosa no ejecuta ningún pack, con un aviso, y lanza un error con strictOptions, con code: 'INVALID_ENGINE_OPTIONS'. Se devuelve como engine.packs. Consulta Packs. |
probes | Un objeto de evidencia opcional, seguro para JSON, que proporciona tu aplicación anfitriona, para lo que el análisis de una sola página no puede ver, como las demás páginas del sitio. El motor lo limita antes de que las reglas lo lean (ctx.inputs.probes): seis niveles de profundidad, 200 elementos por array, 50 claves por objeto, 2.000 caracteres por cadena. page-title-patterns lee crawl.pageTitles ({ pages: [{ url, title }] }) para buscar títulos genéricos y de plantilla en todo un sitio. Las reglas de un pack pueden leer sondas propias, que el pack documenta. |
perfStats / profileRules | Solo para depuración. perfStats: true devuelve contadores internos en el campo perfStats del resultado; profileRules: true además añade allí un desglose de tiempos por regla. profileRules por sí solo no hace nada: perfStats es lo que crea el objeto donde vive el desglose. La forma no es parte del contrato de salida estable: no construyas nada sobre ella. Ten en cuenta también que profileRules es la única opción que hace que la salida sea no determinista: los contadores son estables entre ejecuciones idénticas, los tiempos de reloj no lo son. Déjala desactivada si comparas resultados entre ejecuciones. Con profileRules, las cachés compartidas (estilos calculados y elegibilidad en el árbol de accesibilidad) se llenan antes de la primera regla y se miden aparte como perfStats.warmUpMs, para que su coste no se cargue a la primera regla que recorra la página. |
pingWaitTime / frameWaitTime | Solo lo lee runa11yCoreAcrossFrames (consulta INTEGRATION.md): cuánto tiempo esperar a que un frame hijo responda a un ping (predeterminado 500ms) y a una solicitud de ejecución completa (predeterminado 60000ms) antes de tratarlo como inalcanzable. Lo ignoran runDomRulesInPage/runa11yCoreInPage. |
Detectar errores en las opciones (strictOptions)
Una opción que el motor no lee se deja pasar: una regla personalizada puede leer ajustes propios de ctx.engineOptions, y una opción eliminada en una versión posterior no rompe un análisis. Así que, por defecto, una opción mal escrita se ignora, y el análisis se ejecuta como si no estuviera. Dos cosas lo indican:
- Siempre, una clave a una o dos letras de una conocida (sin distinguir mayúsculas y minúsculas) genera un aviso, incluidas las claves anidadas:
lcoaleproduce[surea11y] engineOptions: unknown option "lcoale" (did you mean "locale"?); ignored. - Siempre, un valor de tipo incorrecto genera un aviso y se lee como no indicado, igual que un
engineOptionsque no es un objeto. Las opciones de activar/desactivar (includeShadowDom,includeHiddenElements,fragment,perfStats,profileRules,output.includeHtml,output.includeSelector) aceptantrueofalse, o'true','false','1','0',1y0tal como los escribe una línea de comandos:perfStats: 'false'está desactivada. - Con
strictOptions: true(o'true','1'o1), todas las opciones se comprueban antes del análisis, y cualquier error lanza una excepción concode: 'INVALID_ENGINE_OPTIONS'que nombra cada uno, conproblemsenumerándolos como{ path, kind, message, suggestion }: una clave desconocida (kind: 'unknown'), enengineOptionso en uno de sus objetos, y un valor de tipo incorrecto o fuera de su conjunto (kind: 'invalid'), comoincludeHiddenElements: 'yes'ocontrast.mode: 'strict'.
runDomRulesInPage(url, null, { strictOptions: true, lcoale: 'de' }, null);// Error: engineOptions: unknown option "lcoale" (did you mean "locale"?). (strictOptions)
Las funciones de catálogo que aceptan engineOptions (getChecksCatalog, getRulesCatalog, getCheckDefById, getCompositeRuleById, getChecksForRunOnly, getRulesForRunOnly, getTestsForRunOnly) las comprueban del mismo modo, con las mismas palabras: getRulesForRunOnly(runOnly, { wcagLevel: 'AA+' }) avisa, lee el nivel como no indicado y enumera lo que informa un análisis con esas opciones; con strictOptions: true lanza INVALID_ENGINE_OPTIONS, igual que el análisis. Una selección que se anula a sí misma (una regla incluida y excluida a la vez, partes sin ninguna regla en común) se señala como la señala el análisis: un aviso, y INVALID_RUN_ONLY con strictOptions.
No se comprueban: los ajustes propios de una regla (rules[ruleId]), las claves de messages y probes, que el motor transmite sin leer; ni las reglas personalizadas, que tienen sus propias comprobaciones (skippedCustomRules). En TypeScript, StrictEngineOptions es el mismo conjunto de opciones sin la firma de índice que permite compilar cualquier clave, así que una opción mal escrita también es un error ahí.
excludeSelectors por regla
El excludeSelectors de nivel superior se aplica a todas las reglas: no hay forma de excluir un elemento de una sola regla mientras se siguen ejecutando todas las demás reglas sobre él. rules[ruleId].excludeSelectors llena ese vacío: reduce los candidatos para solo esa regla, además de (nunca en lugar de) la lista global.
const engineOptions = {excludeSelectors: ['#cookie-banner'], // applies to every rule, as alwaysrules: {'aria-required-children': {excludeSelectors: ['mat-select', 'mat-stepper', 'mat-horizontal-stepper', 'mat-vertical-stepper']},'aria-allowed-attr': {excludeSelectors: ['mat-progress-spinner']}}};
Por qué querrías esto: el <mat-select> de Angular Material construye su estructura ARIA interna de una manera que dispara un falso positivo específicamente en aria-required-children, aunque el componente por lo demás esté bien. Con solo el excludeSelectors global, la única forma de silenciar ese falso positivo es excludeSelectors: ['mat-select']: lo cual también oculta mat-select a todas las demás reglas, incluidas contrast-minimum y aria-allowed-attr, eliminando silenciosamente cobertura real con la que esas comprobaciones nunca tuvieron problema. El ejemplo de arriba mantiene mat-select completamente visible para todas las reglas excepto la que falla incorrectamente con él.
Las exclusiones efectivas para una regla dada son la unión de la lista global y la lista propia de esa regla: un elemento que coincide con cualquiera de las dos se elimina de los candidatos de esa regla. Una regla cuyos únicos elementos que fallarían quedan todos excluidos de esta manera informa outcome: 'pass' o 'notApplicable' (siguiendo la convención propia de esa regla para el caso sin candidatos), con occurrences: []; nunca outcome: 'fail' con un array occurrences vacío, ya que el fail de una regla integrada siempre nombra lo que ha fallado. (Una regla que lanza un error es otro caso: informa cantTell con error definido; consulta el esquema de salida.)
Acepta las mismas formas que la opción global: un array (['mat-select', 'mat-stepper']) o una cadena separada por comas ('mat-select, mat-stepper').
Si estás usando un paquete de integración (binding) (@surea11y/binding-base y sus wrappers de Playwright/Puppeteer), consulta el propio README de esa integración para ver si su método constructor .exclude() ya tiene una forma por regla: esta es una forma de engineOptions documentada aquí a nivel del motor; no todas las integraciones la han incorporado todavía.
Recetas: combinar opciones para escenarios reales
Puerta de CI: solo WCAG 2.2 AA, ignorando un widget de terceros que no controlas
runDomRulesInPage(url, null, {excludeSelectors: ['#cookie-banner', '.intercom-launcher']}, { wcag: { version: '2.2', level: 'AA' } });
Añade bestPractices: true junto a wcag para ejecutar también las reglas de buenas prácticas, que una puerta de WCAG suele informar sin fallar por ellas. Algunas pueden dar fail (empty-heading), así que una puerta que falla ante cualquier fail también falla por ellas.
Auditor humano haciendo una pasada de contraste en profundidad en un navegador real: sacrifica algo de protección contra falsos positivos a cambio de más hallazgos. En un navegador real, las reglas de contraste ya comprueban el diseño, no solo los estilos calculados, así que solo hace falta configurar el modo de contraste. Se muestra con el page.evaluate de Puppeteer (acepta múltiples argumentos); si estás en Playwright, primero envuelve los cuatro argumentos posicionales en un solo objeto; consulta INTEGRATION.md:
const result = await page.evaluate(runa11yCoreInPage, url, null, {contrast: { mode: 'auditorAssist' }}, null);
Reanálisis delimitado de una región tras un cambio de interfaz, omitiendo el shadow DOM: útil en una prueba a nivel de componente donde solo te importa el widget que acabas de cambiar:
runDomRulesInPage(url, '#checkout-form', {includeShadowDom: false}, { includeRuleIds: ['form-control-programmatic-label-present', 'button-name-present'] });
Salida para pruebas de snapshot: fija un timestamp para que la marca de tiempo del propio resultado no cambie entre ejecuciones, y deja desactivados perfStats y profileRules: sus tiempos varían, y su estructura no forma parte de la salida estable. Un snapshot también necesita el mismo DOM, las mismas opciones y las mismas condiciones de renderizado (navegador, viewport, fuentes) en cada ejecución; la marca de tiempo por sí sola no hace idénticos dos resultados.
runDomRulesInPage(url, null, {timestamp: '2026-01-01T00:00:00Z'}, null);
Una regla personalizada, específica de la organización, junto a las integradas, solo para esta llamada:
runDomRulesInPage(url, null, {customRules: [{id: 'org-no-inline-onclick',meta: { title: 'No inline onclick handlers', defaultSeverity: 'moderate' },runInPage(ctx) {// queryAllSmart applies excludeSelectors, the scope's shadow roots and// the hidden-content filter; queryAll is the plain light-DOM query.// ctx.helpers.dom reads the DOM so the page's markup can't redirect it.const dom = ctx.helpers.dom;const els = ctx.helpers.queryAllSmart('[onclick]');const occurrences = els.map((el) => ({selector: ctx.helpers.buildSelector(el),html: dom.outerHTML(el),summary: 'Inline onclick handler found.',hint: 'Move event handling into an external script.'}));return { ruleId: ctx.rule.ruleId, outcome: occurrences.length ? 'fail' : 'pass', severity: 'moderate', occurrences };}}]}, null);
customRules: reglas registradas en tiempo de ejecución
Todas las reglas distribuidas están incorporadas en src/core.js en tiempo de compilación. engineOptions.customRules es la vía de escape en tiempo de ejecución: un array de descriptores de regla registrados solo para esa llamada; no se añade nada al catálogo estático, y nada persiste entre llamadas. Las funciones de catálogo aceptan las mismas engineOptions y enumeran lo que tiene un análisis con ellas: getChecksCatalog(engineOptions) enumera las reglas personalizadas válidas, con cada sustitución en el lugar de su regla integrada, getCheckDefById(id, engineOptions) las encuentra, y getChecksForRunOnly(runOnly, engineOptions) las selecciona igual que el análisis, y getRulesForRunOnly(runOnly, engineOptions) enumera los resultados agregados que añaden. Esto es deliberado, no una limitación que sortear: surea11y ya toma engineOptions nuevas en cada llamada sin configuración global mutable, y las reglas personalizadas siguen ese mismo modelo por llamada.
Llamar a la biblioteca directamente es una forma de acceder; la CLI también expone esto vía --custom-rules <path> (un archivo local, cargado una vez por análisis). Consulta la documentación de la CLI.
Una regla personalizada, como la de un pack, se ejecuta después de las reglas integradas, y los ctx.helpers, ctx.engineOptions y ctx.inputs.probes que recibe son de solo lectura: definir o eliminar cualquier cosa en ellos lanza un error (la regla se informa como cantTell con ese error), así que no puede cambiar lo que ven las demás reglas. No debe modificar la página: una que lo hace se nombra en un console.warn. Los resultados conservan el orden del catálogo. Lance o devuelva lo que sea, el análisis devuelve un resultado, y el resultado de la regla se convierte en datos simples, para que el resultado del análisis se pueda escribir como JSON y clonar.
Un descriptor tiene la misma forma que la propia exportación de un módulo de regla interno: si ya sabes cómo escribir un archivo de regla para este motor, ya conoces esta API:
{id: 'my-org-custom-rule', // requiredmeta: { title, description, tags, defaultSeverity, defaultConfidence, /* same fields as a rule module's meta */ },runInPage(ctx) { /* same ctx shape and same return contract as any built-in rule */ },applicability(ctx) { return true; }, // optional, same contract as a built-in rule's applicabilitydata: { /* optional, JSON-serializable */ }}
runInPage/applicabilitypuede ser una función real o una cadena con el código fuente de la función (es decir,fn.toString()). Pasa una función real cuandoengineOptionsnunca sale del ámbito de JS actual (uso normal en Node/jsdom). Pasa una cadena cuando sí lo hace: por ejemplo, una llamada de Playwrightpage.evaluate(runa11yCoreInPage, { engineOptions }), dondeengineOptionscruza un límite de JSON/clonación estructurada que no puede llevar una referenciaFunctionviva pero sí puede llevar una cadena. El motor reconstruye una cadena víanew Function, el mismo mecanismo que usa la compilación para incrustar el código fuente de cada regla integrada en el ejecutor dentro de la página. Sirve el código fuente de cualquier función: una función flecha, una declaraciónfunctiono un método escrito en forma abreviada como en el ejemplo de arriba (runInPage(ctx) {…}, tambiénasync), cuyotoString()no es una expresión por sí solo. La reconstrucción necesita queevalesté permitido, así que una página cuya Content Security Policy prohíbe'unsafe-eval'omite una regla dada como cadena, y su motivo enskippedCustomRulesindica que la causa es la política; ahí, pasa una función real.metarecibe los mismos valores predeterminados/validación que una regla en tiempo de compilación: omite lo que no necesites;defaultSeveritytiene como predeterminadomoderate,defaultConfidencetiene como predeterminadomedium,typetiene como predeterminadoautomatic, etc. Un valor fuera de su conjunto (minor/moderate/serious/critical;high/medium/low;automatic/manual, sin distinguir mayúsculas) es unmetaque no supera la validación, y la regla se omite. Unaseverityque una regla devuelve fuera del conjunto se sustituye por su valor predeterminado, con una nota enerror.- Una regla personalizada cuyo
idcoincide con el de una regla integrada la sobrescribe para ese análisis, en lugar de ejecutar ambas. Dado que una regla personalizada con el mismo nombre es tan probable que sea una colisión accidental como una sobrescritura deliberada, cada colisión se muestra de dos formas: unconsole.warnque nombra el/los id(s), y un arrayoverriddenBuiltinIdsde nivel superior en el resultado (vacío cuando no hay colisión). Consulta el esquema de salida. Los ids se comparan sin distinguir mayúsculas y minúsculas: una regla personalizadaIMG-ALT-PRESENTsustituye aimg-alt-presenty toma su id, y un segundo aviso nombra ambas grafías. - Una regla personalizada que se ejecutó cuenta para el resultado agregado de WCAG (
rulesResults) de cada criterio al que se asocia, mediantemeta.wcagSco una entrada de WCAG enmeta.normativeMappings, igual que una regla integrada: si falla, el resultado agregado falla. El resultado agregado la marca concustom: trueentre sus contribuyentes y la enumera endata.details.customChecksIds. Una regla personalizada que la selección nombra por sí misma (por su id o por una de sus etiquetas) y que se ejecutó informa los resultados agregados de sus criterios aunque la selección no nombre ninguno de ellos ("Qué criterios informa un análisis"). Una sustitución cuenta donde dice su propia asociación: en el lugar de su regla integrada cuando se asocia a ese criterio, y en ningún resultado agregado cuando no se asocia a ninguno, con un aviso que nombra los resultados agregados que abandonó. - Una regla personalizada se selecciona igual que una integrada, por su id y sus
meta.tags. UnrunOnlyque nombra una regla personalizada que el análisis omitió lanzaINVALID_RUN_ONLY, con el motivo por el que se omitió.customRuleses una lista: una sola regla pasada por sí sola no se ejecuta, y figura enskippedCustomRules. Bajo un perfil o un objetivo de WCAG, una regla etiquetada comobest-practice, o sin etiqueta de WCAG, no forma parte de la ejecución: figura enskippedCustomRules, con unconsole.warn, y se ejecuta cuando le das las etiquetas de los criterios que comprueba ('wcag111') o añadesrunOnly.bestPractices: true. Una regla personalizada que la selección excluye (excludeRuleIds: ['org-b'],rules.exclude...) también figura ahí, con el motivoexcluded by the selection.yexcluded: true, y sin aviso. Una sustitución se ejecuta allí donde se habría ejecutado su regla integrada. - Una regla personalizada puede informar un margen igual que una regla integrada: declara
meta.margin({ measure, unit, limit }) y devuelvemarginCandidates(consultaRULE_AUTHORING.md,meta.margin, la guía de autoría de reglas en GitHub). Unmeta.marginmal formado se ignora, así que esa regla no informa ningún margen; el análisis continúa. - Un descriptor inválido (
idausente/no-string, unrunInPageque no es una función ni una cadena de código fuente reconstruible, unapplicabilityque no se puede convertir en una función, unmetaque no supera la validación, comodeprecated: truesindeprecation, un id que ya tiene otra regla personalizada de la lista, o el id de una regla compuesta) se omite con unconsole.warnque nombra la regla y el motivo, y figura en elskippedCustomRulesdel resultado: el resto del análisis, incluidas todas las reglas integradas, sigue ejecutándose con normalidad. Esto no es un vacío de validación por corregir: una regla personalizada es código arbitrario proporcionado por quien la llama, así que "fallar cerrado en esta sola entrada, sin abortar el análisis" es el comportamiento predeterminado más seguro, reflejando cómo una regla integrada que lanza un error queda contenida en uncantTellpara esa regla en lugar de hacer fallar toda la ejecución. - Las reglas se ejecutan de forma síncrona. Un
runInPageo unapplicabilityque devuelve una Promise (una funciónasync) se informa comocantTellcon unerrorque lo indica, igual que unrunInPageque devuelve algo que no es un objeto de resultado. Unoutcomefuera depass,fail,cantTellynotApplicable(como'failed') pasa a sercantTell, yerrornombra el valor devuelto. Eltypede una regla viene de sumeta: untypeen lo que devuelve se ignora, con una nota enerror. - Los resultados aparecen en
checksResultsexactamente igual que los de cualquier otra regla, incluido el autocompletado automático deselector/html/structuralPathpara ocurrenciasfail/cantTellque solo adjuntan{ __node }(consulta el esquema de salida). - Un
failnombra lo que ha fallado. Unfailde una regla personalizada sin ocurrencias (un fallo de toda la página) se informa con una ocurrencia en el elemento del documento (selector: 'html', código de motivoFAIL_WITHOUT_OCCURRENCE), para que JUnit, SARIF, las líneas base y el informe HTML lo muestren como el fallo que es.
Packs: reglas y estándares de fuera de core
Un pack trae reglas, variantes de las reglas de core, un estándar o una lista de comprobación, y los mensajes que usan, desde un paquete independiente, sin una compilación de core. Pasa los packs a un análisis en engineOptions.packs; el análisis se ejecuta en un motor preparado con ellos, mediante los pasos que usa la compilación para las propias reglas de core, así que el estándar, los perfiles, los resultados agregados y las reglas opcionales de un pack se comportan como lo harían los de uno integrado. El motor se conserva para el siguiente análisis con los mismos objetos de pack, así que un rastreo que pasa los mismos packs a cada página los prepara una sola vez.
const { runDomRulesInPage, getChecksCatalog } = require('@surea11y/core');const acmePolicy = require('./acme-policy-pack');const result = runDomRulesInPage(url, null, { packs: [acmePolicy], profile: 'acme-web-2026' });result.engine.packs; // ['@acme/a11y-policy@1.0.0']getChecksCatalog({ packs: [acmePolicy] }); // core's rules and the pack's
Un pack que no encaja con core (su rango core excluye esta versión, un id de regla sin el espacio de nombres, una clave de diccionario que core ya tiene) se omite con un console.warn, figura en el skippedPacks del resultado como { name, reason }, y el análisis se ejecuta sin él; con strictOptions lanza un error, con code: 'INVALID_ENGINE_OPTIONS'. Los packs que chocan entre sí lanzan un error. En una página, un pack se registra primero con packScript(packs) y se nombra en engineOptions.packs como name@version. Qué contiene un pack, cómo usar uno desde cada integración, los test matchers y la CLI, y cómo escribir uno, está en Packs.
contextSelector (2.º argumento del ejecutor, no un campo de engineOptions)
Un selector CSS (o array de selectores) que delimita el análisis a uno o más subárboles, resuelto vía document.querySelectorAll (todas las coincidencias, no solo la primera). Pasa null para analizar todo el documento.
- Un selector que no coincide con nada no analiza nada. Todas las reglas informan
notApplicable, incluidas las de nivel de página, y elcontextMatchdel resultado lo indica:{ elementCount: 0, unmatchedSelectors: ['#mian'] }(consulta el esquema de salida). La ejecución también registra unconsole.warn. Un ámbito que la página no tiene no se amplía a toda la página: un resultado sobre contenido que nunca pediste, con unpassde página completa entre medias, se leería como un resultado sobre la parte que sí pediste. En un array, un selector que no coincide con nada figura enunmatchedSelectorsmientras los demás se analizan con normalidad, así que un contenido que solo a veces está en la página, como un banner de cookies, puede estar en la lista. Antes de la 1.10.0, un ámbito sin coincidencias recurría a todo el documento, sin ninguna indicación en el resultado. - Un selector que el navegador no puede analizar lanza un error, solo o en un array, antes de que se ejecute ninguna regla:
contextSelector: "#main[" is not a valid CSS selector.El error llevacode: 'INVALID_CONTEXT_SELECTOR'yselector, el selector que ha fallado. A diferencia de un selector que no coincide con nada, siempre es un error en la llamada.runa11yCoreAcrossFramesse rechaza con el mismo error. Un error que cruzapage.evaluate(Playwright, Puppeteer) conserva solo su mensaje, por eso el mensaje nombra la opción y el selector. Antes de la 1.10.0, un selector inválido se omitía, así que por sí solo analizaba todo el documento. - Cualquier cosa que no sea un selector, un array de selectores o
nulllanza el mismo error, nombrando lo que se pasó: un elemento, una NodeList, un objeto{ include, exclude }, un número o un elemento del array que no es una cadena (contextSelector[1] must be a CSS selector, not the number 5.). Pasa en su lugar un selector que coincida con el elemento, y pon lo que dejaría fuera unexcludeenengineOptions.excludeSelectors. - Un selector o una lista vacíos analizan toda la página, y lo avisan.
'',' ',[]y una lista de cadenas en blanco no nombran ninguna parte de la página, así que el análisis la cubre entera, como connull, y registra unconsole.warn. ConstrictOptionslanza en su lugarINVALID_CONTEXT_SELECTOR, ya que una lista que quedó vacía por error puede haberse pensado como "nada que analizar". Pasanullpara toda la página. ElcontextMatchdel resultado esnull, como sin selector. Core 1.16.0 y posteriores. - Una sola cadena puede ser en sí misma una lista de selectores separados por comas (semántica de unión CSS habitual):
'#a, #b'analiza tanto#acomo#b. - Un array de cadenas analiza la unión de las coincidencias de cada selector:
['#a', '.card']se comporta igual que'#a, .card'; la forma de array existe para quienes construyen la lista de forma programática. - Shadow DOM. Con
includeShadowDom(el valor predeterminado), un ámbito incluye las raíces shadow que contiene, y un ámbito que es él mismo un host shadow incluye su propia raíz shadow. El selector se compara con el documento, así que no puede seleccionar un elemento dentro de una raíz shadow; delimita a su host en su lugar. - Las regiones superpuestas/anidadas se deduplican automáticamente: un elemento alcanzable desde más de una raíz coincidente solo se informa una vez, no una vez por región.
- Qué significa un resultado delimitado. La mayoría de las reglas juzgan cada elemento por sí solo, y juzgan los elementos del ámbito exactamente igual que en un análisis de toda la página. Dos tipos de regla dependen de la página que los rodea. Las reglas de página completa (
page-title-present,landmark-one-mainy el resto de las que figuran enfragmentmás arriba) informannotApplicable. Las reglas que comparan elementos en toda la página (landmark-unique,landmark-no-duplicate-banner,-contentinfoy-main,landmark-banner-is-top-level,-complementary-,-contentinfo-y-main-is-top-level,accesskeys,heading-order,identical-links-same-purpose,identical-iframes-same-purpose) siguen informando lo que encuentran dentro del ámbito, ya que dos landmarks que ahí comparten nombre lo comparten en cualquier página, pero informannotApplicableen lugar depass: el análisis solo vio parte de la página, así que no puede afirmar que la página esté bien.duplicate-idyduplicate-id-ariacomparan cada elemento del ámbito con todo el documento, ya que su duplicado puede estar fuera del ámbito, e informan de un elemento del ámbito cuyo id aparece en cualquier otro lugar. Supasssignifica que ningún elemento del ámbito comparte id con otro elemento de la página; un par duplicado completamente fuera del ámbito no se informa, como en cualquier regla, así que no afirma que toda la página esté libre de duplicados.target-size-minimumjuzga los objetivos del ámbito frente a vecinos de cualquier parte del documento, ya que la excepción de espaciado depende de lo que la página pone junto a un objetivo.text-spacing-content-lossjuzga el texto del ámbito y comprueba si llega a solaparse con texto de cualquier parte de la página.