Informe EARL
@surea11y/core/earl convierte los resultados de un análisis en EARL 1.0 en JSON-LD: el vocabulario que publica el W3C para declarar "esta herramienta probó esto y obtuvo este resultado", y el formato que el grupo comunitario ACT Rules acepta como informe de implementación.
const { renderEarlReport } = require('@surea11y/core/earl');const report = renderEarlReport(result, {assertor: { name: 'surea11y', version: '1.16.1' },mode: 'earl:automatic'});fs.writeFileSync('earl.jsonld', JSON.stringify(report, null, 2));
Para qué sirve
Dos audiencias, y ambas quieren el mismo documento por razones distintas.
Un informe de implementación le dice al grupo comunitario ACT Rules cómo se comporta este motor frente a sus casos de prueba, que es lo que permite que un motor aparezca listado junto a las demás implementaciones. Estar listado no es un aval y el W3C no verifica los datos: la formulación correcta es "listado como implementación ACT", nunca "certificado por el W3C". Este motor publica dos, ambos regenerados por scripts/act-report.js a partir de la última versión: uno de un análisis en jsdom, como ejecutan el motor la CLI y test-matchers, con el asertor llamado «SureA11y»; y otro de un análisis en Chromium (--runner=chromium), como lo ejecutan los bindings de navegador, con el asertor llamado «SureA11y in a browser» y la versión de Chromium en la descripción del informe. Un workflow en SureA11y/act-report vuelve a publicar ambos cada lunes, y se ejecuta a mano tras cada versión.
Un consumidor obtiene un formato de intercambio. EARL es lo que lee una herramienta de accesibilidad cuando tiene que combinar resultados de más de una fuente (un análisis automatizado y una auditoría manual, por ejemplo, o varios motores), porque cada aserción indica quién la hizo y cómo. Eso tiene valor aunque nunca se envíe a ningún sitio.
En qué se diferencia de los demás informes
El informe SARIF y el informe HTML llevan solo las violaciones: informan de las ocurrencias fail y cantTell y descartan todo lo demás. EARL es lo contrario. Cada regla que se ejecutó se convierte en una aserción, incluidas pass e inapplicable, porque un informe de implementación es una afirmación sobre lo que decidió el motor en todos los casos. Una regla que no dijo nada porque no encontró nada aplicable es evidencia, no ruido: es lo que permite distinguir "este motor comprobó y no encontró nada que comprobar" de "este motor no implementa esa regla en absoluto". Cada aserción trata de una regla sobre un sujeto: el passed de una regla no es un veredicto sobre el criterio de WCAG al que se asocia, la mayoría de los cuales tienen partes que ninguna regla cubre (ver Mapeo de conformidad con WCAG).
Forma
El grafo se agrupa por sujeto en lugar de ser una lista plana de aserciones:
{"@context": "https://www.w3.org/WAI/content-assets/wcag-act-rules/earl-context.json","@graph": [{"@type": "TestSubject","source": "https://example.test/","assertions": [{"@type": "Assertion","test": { "title": "img-alt-present", "isPartOf": ["WCAG2:non-text-content"] },"result": { "outcome": "earl:failed" },"assertedBy": {"@type": "Assertor","name": "surea11y","release": { "@type": "Version", "revision": "1.16.1" }},"mode": "earl:automatic"}]}]}
sourcees la URL analizada, o bienabout:blankcuando un resultado no lleva ninguna. Cuando varios resultados no llevan ninguna, cada uno es un sujeto propio,about:blank#result-<n>según su posición en la lista (empezando por 1), en lugar de fusionarse todos en uno.test.titlees el ID de regla propio del motor. En términos ACT, una regla es el procedimiento que ejecutó la implementación, que es exactamente lo que nombra un ID de regla.test.isPartOfenumera los Criterios de Éxito a los que se asocia esa regla, comoWCAG2:<criterion-id>: cada entrada denormativeMappingscuyostandardesWCAGo está ausente (como en SARIF) y que no tienetype. Se omite por completo para una regla que no reclama ningún criterio:aria-allowed-role,empty-headingylandmark-role-name-presentson las reglas automáticas del motor en esa situación, y afirmar una lista vacía se leería como "no encontramos a qué se asocia" en lugar de "deliberadamente no se asocia a ninguno". Una regla así puede darfailigualmente (empty-headingfalla con un encabezado sin nombre): su aserción es entoncesearl:failedsinisPartOf, un fallo de la regla que no afirma que haya fallado ningún criterio de WCAG.isPartOfsigue el nivel y la versión de WCAG del análisis. Un criterio que el análisis dejó fuera derulesResultspor ellos no se enumera, como 1.4.6 (AAA) conengineOptions.wcagLevel: 'AA', o 4.1.1 cuandoincludeRuleIds: ['duplicate-id']se ejecutó con WCAG 2.2, que lo eliminó; una regla cuyos criterios quedan todos fuera no tieneisPartOf. La aserción en sí se mantiene, ya que trata de la regla. Un criterio que el análisis informa sí se enumera, como un resultado agregado nombrado por id por encima del nivel, o 4.1.1 en un análisis 2.2 que lo seleccionó, y también todos los criterios de un resultado que no registra niengine.wcagLevelniengine.wcagVersion.assertedBysiempre está presente salvo que pasesassertor: null: por defecto essurea11yy la versión del motor que llevan los resultados.modeaparece solo cuando lo proporcionas.
Los ids de criterio se derivan del propio título del criterio (Non-text Content → non-text-content). normativeMappings también lleva referencias a documentos Understanding, que tienen un type, y entradas de otros estándares (cláusulas de EN 301 549, los requisitos o elementos de lista de comprobación de un pack), que nombran su propio standard; ambas pueden compartir un número de requirement con un criterio. Solo las entradas cuyo standard es WCAG o está ausente y que no tienen type se leen como Criterios de Éxito. No hace falta ningún nivel de conformidad. isPartOf enumera solo criterios de WCAG; las entradas de otros estándares se dejan fuera.
Un resultado compacto (engineOptions.output.detail: 'findings', ver Esquema de salida) se lee como el resultado completo que representa, así que se informa igual.
Resultados
| Motor | EARL |
|---|---|
pass | earl:passed |
fail | earl:failed |
cantTell | earl:cantTell |
notApplicable | earl:inapplicable |
earl:untested no tiene contraparte: una regla que no se ejecutó no produce ningún resultado sobre el cual hacer una aserción, así que no aporta ninguna aserción en lugar de aportar una de "no probada".
cantTell no le resta crédito de conformidad. Las propias reglas de consistencia de ACT permiten que una implementación automatizada indique "no se puede determinar" en algunos ejemplos (aunque no en todos) y aun así cuente como consistente. Lo que una implementación parcialmente consistente no puede hacer es producir un falso positivo: fallar un ejemplo que la regla dice que debería pasar o que es inaplicable. Esa es la condición que vale la pena vigilar, y es una propiedad de las reglas, no de este informe. Según la última ejecución completa, el motor produce cero falsos positivos entre los 957 ejemplos que el W3C publica para sus 60 reglas asociadas. Ver ACT_RULE_MAPPING.md, y volver a ejecutar scripts/act-testcase-check.js para la cifra actual en lugar de confiar en esta indefinidamente.
Varios resultados, un solo informe
renderEarlReport acepta un array con la misma facilidad que un solo resultado, porque un informe que cubre muchas páginas es el caso normal:
renderEarlReport([homeResult, checkoutResult, searchResult], { assertor });
Un resultado entre frames de runa11yCoreAcrossFrames se acepta tal cual, solo o dentro del array: cada frame que respondió es un resultado más y se convierte en un sujeto con su propia URL. Un frame por debajo del superior cuya URL no lo distingue, porque es about:srcdoc o about:blank o porque otro frame del resultado también la tiene, se nombra por su URL y su ruta, los selectores con los que lo nombran SARIF y JUnit, cada uno codificado y unidos con /: about:srcdoc#frame=%23pay, about:srcdoc#frame=%23widget/%23inner. Donde incluso la ruta se comparte, como en los frames de un binding, que no llevan selector, se añade su posición entre los frames del resultado, desde 1: about:srcdoc#frame=iframe&n=3. Cualquier otra cosa que no sea un resultado de análisis, como null o una cadena, lanza un TypeError.
Los resultados que comparten una URL se fusionan en un solo sujeto: quien llama y analiza la misma página con distintas engineOptions sigue describiendo un único recurso, y el contexto no tiene forma de expresar dos sujetos con la misma fuente. Cuando dos resultados hacen una aserción sobre la misma regla para la misma URL, se conserva el peor resultado: earl:failed, luego earl:cantTell, luego earl:passed, luego earl:inapplicable, así que ningún orden de las entradas puede ocultar un fallo. Eso incluye la misma página analizada con dos anchos de viewport: EARL no tiene ningún término para las condiciones en que se renderizó una página, así que un informe construido a partir de varios anchos conserva, para cada regla, un fallo en cualquier ancho. Genera un informe por ancho si los propios anchos importan.
La salida es determinista: los sujetos se ordenan por fuente, las aserciones por ID de regla, y las mismas entradas producen una salida idéntica byte a byte sin importar el orden. La única excepción son los resultados sin URL, que se distinguen por su posición en la lista (about:blank#result-2); da a cada resultado su URL cuando el orden no deba importar. Eso es lo que hace útil una comparación entre dos versiones del motor.
Un análisis de varios perfiles
En un resultado de varios perfiles (core 1.15.0 y posteriores), el outcome de una comprobación es el peor que le dan sus perfiles, que puede ser el fallo de un estándar en un hallazgo por el que WCAG solo pregunta. Cada aserción toma en su lugar el resultado propio de la regla, checkOutcome: un atributo que un rol no admite, que WAI-ARIA hace fallar y por el que WCAG 4.1.2 pregunta, se afirma earl:cantTell frente a WCAG2:name-role-value. Así, el fallo de un estándar nunca se afirma como uno de WCAG.
Opciones
| Opción | Significado |
|---|---|
assertor | { name, version }. El nombre por defecto es surea11y, y la versión, indicada como la versión (release) del asertor, es por defecto el engine.version que llevan los resultados cuando todos llevan el mismo; los resultados de versiones distintas no reciben ninguna salvo que la indiques. Pasa null para omitir assertedBy por completo. |
mode | Un modo de prueba EARL como 'earl:automatic'. Se omite cuando no se proporciona. |
Ver también
- Esquema de salida: el resultado que este informe lee
ACT_RULE_MAPPING.md: a qué reglas ACT corresponden las reglas del motorAPI_STABILITY.md: qué está cubierto por el versionado semántico