@surea11y/core 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/README.md +179 -90
  3. package/docs/ACT_RULE_MAPPING.md +10 -8
  4. package/docs/API_STABILITY.md +67 -6
  5. package/docs/BINDING_AUTHORS_GUIDE.md +104 -2
  6. package/docs/CI_INTEGRATIONS.md +43 -0
  7. package/docs/DESIGN_CHALLENGES.md +162 -2
  8. package/docs/EARL.md +100 -0
  9. package/docs/ENGINE_OPTIONS.md +109 -5
  10. package/docs/I18N.md +62 -20
  11. package/docs/INTEGRATION.md +4 -2
  12. package/docs/JUNIT.md +73 -0
  13. package/docs/LIMITATIONS.md +4 -1
  14. package/docs/OUTPUT_SCHEMA.md +62 -11
  15. package/docs/POLICY.md +1 -1
  16. package/docs/REPORT.md +7 -2
  17. package/docs/RULE_AUTHORING.md +83 -17
  18. package/docs/RULE_CATALOG.md +212 -139
  19. package/docs/RULE_EXAMPLES.md +2189 -0
  20. package/docs/RULE_HELPERS.md +390 -0
  21. package/docs/RULE_TAXONOMY.md +27 -6
  22. package/docs/SARIF.md +23 -3
  23. package/docs/WCAG_CONFORMANCE.md +64 -3
  24. package/package.json +41 -12
  25. package/profiles/index.js +14 -0
  26. package/src/checks/automatic/area-alt-present.js +87 -31
  27. package/src/checks/automatic/aria-allowed-attr.js +6 -0
  28. package/src/checks/automatic/aria-allowed-role.js +32 -23
  29. package/src/checks/automatic/aria-braille-equivalent.js +43 -17
  30. package/src/checks/automatic/aria-conditional-attr.js +17 -10
  31. package/src/checks/automatic/aria-deprecated-role.js +12 -0
  32. package/src/checks/automatic/aria-hidden-body.js +1 -1
  33. package/src/checks/automatic/aria-hidden-focus.js +74 -18
  34. package/src/checks/automatic/aria-prohibited-attr.js +22 -4
  35. package/src/checks/automatic/aria-prohibited-children.js +6 -6
  36. package/src/checks/automatic/aria-required-attr.js +88 -12
  37. package/src/checks/automatic/aria-required-children.js +33 -16
  38. package/src/checks/automatic/aria-required-parent.js +32 -6
  39. package/src/checks/automatic/aria-role-name-present.js +20 -3
  40. package/src/checks/automatic/aria-roles-valid.js +52 -21
  41. package/src/checks/automatic/aria-valid-attr-value.js +89 -24
  42. package/src/checks/automatic/aria-valid-attr.js +14 -9
  43. package/src/checks/automatic/autocomplete-valid.js +152 -26
  44. package/src/checks/automatic/avoid-inline-spacing.js +207 -15
  45. package/src/checks/automatic/button-name-present.js +2 -1
  46. package/src/checks/automatic/canvas-text-alternative-present.js +105 -14
  47. package/src/checks/automatic/combobox-name-present.js +34 -51
  48. package/src/checks/automatic/contrast-computable.js +45 -4
  49. package/src/checks/automatic/contrast-enhanced.js +16 -4
  50. package/src/checks/automatic/contrast-minimum.js +57 -11
  51. package/src/checks/automatic/css-orientation-lock.js +171 -12
  52. package/src/checks/automatic/definition-list-children-valid.js +67 -23
  53. package/src/checks/automatic/deprecated-elements-not-used.js +43 -38
  54. package/src/checks/automatic/dialog-name-present.js +28 -9
  55. package/src/checks/automatic/duplicate-id-aria.js +5 -0
  56. package/src/checks/automatic/duplicate-id.js +19 -10
  57. package/src/checks/automatic/form-control-single-label.js +9 -0
  58. package/src/checks/automatic/identical-iframes-same-purpose.js +229 -0
  59. package/src/checks/automatic/iframe-focusable-content.js +12 -4
  60. package/src/checks/automatic/iframe-title-unique.js +36 -81
  61. package/src/checks/automatic/input-image-alt-present.js +32 -20
  62. package/src/checks/automatic/label-in-name.js +78 -69
  63. package/src/checks/automatic/language-page-present.js +12 -6
  64. package/src/checks/automatic/link-in-text-block.js +512 -44
  65. package/src/checks/automatic/link-name-present.js +13 -5
  66. package/src/checks/automatic/list-children-valid.js +18 -1
  67. package/src/checks/automatic/listbox-name-present.js +19 -49
  68. package/src/checks/automatic/listitem-parent-valid.js +4 -3
  69. package/src/checks/automatic/meta-refresh-no-exceptions.js +3 -3
  70. package/src/checks/automatic/page-title-present.js +16 -4
  71. package/src/checks/automatic/progressbar-name-present.js +11 -1
  72. package/src/checks/automatic/{role-img-alt-present.js → role-img-text-alternative-present.js} +9 -5
  73. package/src/checks/automatic/searchbox-name-present.js +32 -49
  74. package/src/checks/automatic/server-side-image-map-absent.js +48 -28
  75. package/src/checks/automatic/slider-name-present.js +38 -52
  76. package/src/checks/automatic/spinbutton-name-present.js +32 -49
  77. package/src/checks/automatic/target-size-minimum.js +84 -16
  78. package/src/checks/automatic/td-has-header.js +60 -23
  79. package/src/checks/automatic/text-spacing-content-loss.js +548 -0
  80. package/src/checks/automatic/textbox-name-present.js +32 -49
  81. package/src/checks/automatic/valid-lang.js +15 -10
  82. package/src/checks/manual/area-alt-quality-manual.js +113 -31
  83. package/src/checks/manual/canvas-text-alternative-quality-manual.js +0 -2
  84. package/src/checks/manual/css-focus-indicator-suppressed-manual.js +23 -10
  85. package/src/checks/manual/css-hidden-focus.js +215 -7
  86. package/src/checks/manual/form-control-label-quality-manual.js +243 -29
  87. package/src/checks/manual/heading-order-manual.js +9 -1
  88. package/src/checks/manual/heading-quality-manual.js +143 -9
  89. package/src/checks/manual/img-alt-decorative-manual.js +6 -3
  90. package/src/checks/manual/input-image-alt-quality-manual.js +81 -13
  91. package/src/checks/manual/landmark-complementary-is-top-level-manual.js +231 -0
  92. package/src/checks/manual/link-name-quality-manual.js +130 -4
  93. package/src/checks/manual/media-transcript-present-manual.js +65 -8
  94. package/src/checks/manual/mouse-only-event-handlers-manual.js +66 -5
  95. package/src/checks/manual/no-autoplay-audio-manual.js +93 -6
  96. package/src/checks/manual/p-as-heading-manual.js +89 -44
  97. package/src/checks/manual/page-title-patterns-manual.js +77 -8
  98. package/src/checks/manual/password-paste-enabled-manual.js +255 -0
  99. package/src/checks/manual/skip-link-manual.js +42 -14
  100. package/src/checks/manual/table-fake-caption-manual.js +32 -1
  101. package/src/checks/manual/video-caption-manual.js +47 -24
  102. package/src/checks/manual-review.js +0 -4
  103. package/src/core.js +18061 -46194
  104. package/src/coverage/en301549-map.js +187 -0
  105. package/src/coverage/standards.js +279 -0
  106. package/src/coverage/wcag-facets.js +1119 -0
  107. package/src/coverage/wcag-version-map.js +101 -0
  108. package/src/earl.js +144 -0
  109. package/src/en301549.js +33 -0
  110. package/src/junit.js +321 -0
  111. package/src/profile-kit.js +163 -0
  112. package/src/report.js +343 -74
  113. package/src/sarif.js +56 -5
  114. package/src/wcag.js +105 -0
  115. package/surea11y.browser.js +11 -41039
  116. package/surea11y.i18n.de.js +2 -21
  117. package/surea11y.i18n.es.js +2 -21
  118. package/surea11y.i18n.fr.js +2 -21
  119. package/surea11y.i18n.ja.js +3 -0
  120. package/src/checks/manual/area-alt-decorative-manual.js +0 -255
package/README.md CHANGED
@@ -6,30 +6,79 @@
6
6
  [![node](https://img.shields.io/node/v/@surea11y/core?style=flat-square&label=node&labelColor=101413&color=3A4441)](package.json)
7
7
  [![license](https://img.shields.io/badge/license-MPL--2.0-3A4441?style=flat-square&labelColor=101413)](LICENSE)
8
8
 
9
+ [Website](https://surea11y.dev/) · [Documentation](https://surea11y.dev/getting-started/) · [Rules](https://surea11y.dev/rules/)
10
+
9
11
  > **Accessibility testing that tells you what it can't tell you.**
10
12
 
11
- surea11y is an accessibility engine for teams that need to know what automated
12
- testing *can't* establish. It reports findings, non-findings, and — unusually —
13
- explicit uncertainty, so results are auditable rather than reassuring.
13
+ `@surea11y/core` is the WCAG accessibility testing engine behind the surea11y
14
+ family of packages. It runs in Node.js against a DOM you supply (such as
15
+ jsdom) or inside a real browser page, and returns deterministic,
16
+ standards-traceable results. The integrations for Playwright, Cypress,
17
+ Puppeteer, Selenium, WebdriverIO, Jest/Vitest and the command line are
18
+ separate packages built on this engine: see
19
+ [Which package do I need?](#which-package-do-i-need).
20
+
21
+ What sets it apart is what it does with the cases automated testing can't
22
+ settle. It implements the W3C's open [Accessibility Conformance Testing (ACT)
23
+ Rules Format](https://www.w3.org/TR/act-rules-format/), verified against
24
+ ACT's own published test corpus rather than judged only against itself, and
25
+ it reports findings, non-findings, and (unusually) explicit uncertainty, so
26
+ results are auditable rather than reassuring.
14
27
 
15
28
  *Sure* means certainty about what is known, and honesty about what isn't.
16
29
 
17
- It runs against either static HTML or fully rendered browser pages, producing
18
- deterministic, standards-traceable results suitable for local development,
19
- automated testing and CI/CD pipelines.
20
-
21
- Unlike browser extensions or cloud-based services, surea11y is a library-first
22
- project. You install it, run it where your code runs, and receive structured
23
- results that can be consumed by people, scripts or reporting tools.
30
+ 132 accessibility rules · 58 validated against the ACT corpus (798 reference
31
+ cases) · zero runtime dependencies
32
+
33
+ Unlike browser extensions or cloud-based services, the engine is a library.
34
+ You install it, run it where your code runs, and receive structured results
35
+ that can be consumed by people, scripts or reporting tools.
36
+
37
+ ## Contents
38
+
39
+ - [Goals](#goals)
40
+ - [What automated testing can and cannot do](#what-automated-testing-can-and-cannot-do)
41
+ - [What this engine does not detect](#what-this-engine-does-not-detect)
42
+ - [Key principles](#key-principles)
43
+ - [Choosing the right execution model](#choosing-the-right-execution-model)
44
+ - [Which package do I need?](#which-package-do-i-need)
45
+ - [Installation](#installation)
46
+ - [Quick Start](#quick-start)
47
+ - [Understanding the Results](#understanding-the-results)
48
+ - [Documentation](#documentation)
49
+ - [Philosophy](#philosophy)
50
+ - [Project Structure](#project-structure)
51
+ - [Building the Project](#building-the-project)
52
+ - [Contributing](#contributing)
53
+ - [Security](#security)
54
+ - [Versioning & stability](#versioning--stability)
55
+ - [Maintainer](#maintainer)
56
+ - [License](#license)
57
+
58
+ ## Goals
59
+
60
+ 1. **Say only what can be established, and say it plainly when it can't.**
61
+ `fail` is reserved for objective, normative violations; `cantTell` exists
62
+ so an ambiguous case is reported as ambiguous rather than silently
63
+ dropped or guessed at. A shorter report is not a goal in itself.
64
+
65
+ 2. **Verify against an open standard, not just internal tests.** Every rule
66
+ with a W3C ACT Rules counterpart runs against ACT's own published test
67
+ corpus — 798 examples across 58 rules — and the results are public. See
68
+ [Checked against the ACT corpus](#checked-against-the-act-corpus) below.
69
+
70
+ 3. **Make the engine and its rules approachable to build on.** Custom rules,
71
+ policies, and framework bindings are first-class extension points, and
72
+ every rule ships with its WCAG mapping, applicability, and expectation
73
+ documented. Worked examples are available in
74
+ [`docs/RULE_EXAMPLES.md`](./docs/RULE_EXAMPLES.md), and the complete rule
75
+ catalog can be browsed at [surea11y.dev/rules](https://surea11y.dev/rules/).
24
76
 
25
77
  ## What automated testing can and cannot do
26
78
 
27
- Automated tools are commonly reckoned to catch somewhere around a third of WCAG
28
- issues. The remainder require human judgement. That ceiling is a property of
29
- static analysis itself, not a gap in any particular tool.
30
-
31
- surea11y's answer is to be explicit about which side of that line every result
32
- falls on. Each rule makes a single deterministic decision:
79
+ Many WCAG requirements cannot be determined through automated testing alone and
80
+ require human judgement. surea11y's answer is to make that boundary explicit.
81
+ Each rule makes a single deterministic decision:
33
82
 
34
83
  - **`fail`** — a violation provable from the DOM. Reserved for objective,
35
84
  normative cases.
@@ -42,18 +91,52 @@ falls on. Each rule makes a single deterministic decision:
42
91
  `cantTell` is the point of the project. An engine that quietly discards what it
43
92
  cannot determine produces a shorter report and a false sense of coverage.
44
93
 
94
+ ### Checked against the ACT corpus
95
+
96
+ Every rule with a [W3C ACT Rules](https://act-rules.github.io/) counterpart runs
97
+ against ACT's own published test cases: 798 examples across 58 rules. The engine
98
+ fails none of the examples ACT marks `passed` or `inapplicable`, so it reports no
99
+ false positives against that corpus. Where it cannot decide a case it returns
100
+ `cantTell`, which ACT permits for an automated implementation.
101
+
102
+ Thirty-one examples ACT marks `failed` go unflagged. Most are judgement calls,
103
+ such as whether a heading describes the content under it.
104
+ [`docs/ACT_RULE_MAPPING.md`](./docs/ACT_RULE_MAPPING.md) lists every one with the
105
+ reasoning, and `node scripts/act-testcase-check.js` reproduces the figures. They
106
+ cover the rules that have an ACT counterpart.
107
+
108
+ The [EARL implementation report](https://surea11y.github.io/act-report/act-report.jsonld)
109
+ records the outcome for every one of those cases, passes and inapplicable
110
+ results included, so a rule that stayed silent because nothing applied is
111
+ distinguishable from one that is not implemented. `node scripts/act-report.js`
112
+ regenerates it against the corpus as it stands rather than a snapshot, and a
113
+ scheduled job republishes it weekly and on release.
114
+
45
115
  ## What this engine does not detect
46
116
 
47
- Keyboard traps, reflow and clipping at 400% zoom, anything that only exists
48
- after a click or an async load, and judgement calls such as whether a heading is
49
- meaningful — these lie outside what a static DOM scan can establish. Each is a
50
- reasoned decision rather than an oversight.
117
+ Some things lie outside what a scan of the DOM can establish. For example,
118
+ the engine will not:
51
119
 
52
- [`docs/LIMITATIONS.md`](./docs/LIMITATIONS.md) lists them in full with the
53
- reasoning for each. A `pass` from this engine — or from any automated tool — is
54
- never a substitute for the manual review WCAG itself requires.
120
+ - confirm that alt text is *meaningful*, only that it is present
121
+ (an alt attribute of `"image123.png"` passes the objective check);
122
+ - judge whether a color contrast choice is aesthetically appropriate,
123
+ only whether it meets the applicable contrast ratio;
124
+ - determine whether an error message actually *explains* the problem,
125
+ since that depends on validation logic a static scan can't see;
126
+ - detect a keyboard trap, or reflow and clipping at 400% zoom, since both
127
+ require simulating real user interaction over time;
128
+ - see anything that only exists after a click or an async load.
129
+
130
+ Where a case comes down to judgement, such as whether a heading is
131
+ meaningful, the engine reports `cantTell` rather than guessing. Each of these
132
+ boundaries is a reasoned decision rather than an oversight:
133
+ [Known limitations](https://surea11y.dev/help/known-limitations/) lists them
134
+ in full with the reasoning for each (also in
135
+ [`docs/LIMITATIONS.md`](./docs/LIMITATIONS.md)). A `pass` from this engine, or
136
+ from any automated tool, is never a substitute for the manual review WCAG
137
+ itself requires.
55
138
 
56
- ### Key principles
139
+ ## Key principles
57
140
 
58
141
  - **Deterministic execution.** The same input always produces the same
59
142
  output.
@@ -69,21 +152,22 @@ never a substitute for the manual review WCAG itself requires.
69
152
  by rule IDs, tags or WCAG version.
70
153
  - **Localized reporting.** Human-readable messages can be translated
71
154
  without affecting machine-readable data. Ships with `en`, `fr`, `de`,
72
- and `es` today — see [`docs/I18N.md`](./docs/I18N.md) to use one or
155
+ `es` and `ja` today. See [`docs/I18N.md`](./docs/I18N.md) to use one or
73
156
  contribute another.
74
157
 
75
158
  ---
76
159
 
77
160
  ## Choosing the right execution model
78
161
 
79
- surea11y supports two complementary execution models. Choosing the
162
+ The engine supports two complementary execution models. Choosing the
80
163
  correct one is essential because it determines which parts of the page
81
164
  the engine can inspect.
82
165
 
83
166
  ### Static HTML
84
167
 
85
- The CLI (`scan file.html` or `scan https://example.com`) and
86
- `runDomRulesInPage()` analyse HTML without executing page JavaScript.
168
+ `runDomRulesInPage()` analyses HTML without executing page JavaScript,
169
+ and so does the separate [`@surea11y/cli`](#cli) package, which wraps it
170
+ for the terminal.
87
171
 
88
172
  This approach is ideal for:
89
173
 
@@ -134,7 +218,9 @@ matches how you test — each pulls in `@surea11y/core` for you.
134
218
  | Scan static HTML from a **terminal or CI pipeline** | [`@surea11y/cli`](https://github.com/SureA11y/cli#readme) |
135
219
  | Run the engine against **a DOM I already have** | `@surea11y/core` (this package) |
136
220
 
137
- The rest of this README covers `@surea11y/core` itself.
221
+ [Getting Started](https://surea11y.dev/getting-started/) on surea11y.dev
222
+ covers installation and usage for each of these. The rest of this README
223
+ covers `@surea11y/core` itself.
138
224
 
139
225
  ---
140
226
 
@@ -329,6 +415,33 @@ embedded frame to also load the engine and opt in, which doesn't fit a
329
415
  single dropped-in `<script>` tag; reach for the npm package directly if
330
416
  you need that.
331
417
 
418
+ ### Conformance targets and EN 301 549
419
+
420
+ To test against a named target instead of a hand-picked tag list, pass a
421
+ profile:
422
+
423
+ ```js
424
+ runDomRulesInPage(url, null, { profile: 'en301549-v3.2.1' }, null);
425
+ ```
426
+
427
+ `wcag22-aa`, `en301549-v4.1.1`, `en301549-v3.2.1` and `section508` each run
428
+ the WCAG Level A and AA rules of the version they build on; the result records
429
+ the one used in `engine.profile`. A profile only chooses which rules
430
+ run; it does not certify conformance. A standard with verdicts of its own
431
+ comes as a profile under [`profiles/`](./profiles/README.md), with its own
432
+ rules, which run only when a scan targets it; to run every rule instead, pass
433
+ `optInRules: 'all'` with no profile; the result records it in
434
+ `engine.optInRules`.
435
+
436
+ An EN 301 549 profile also maps every WCAG criterion in the result to the
437
+ clause of that version that restates it (1.4.3 to 9.1.4.3, for example), and
438
+ the SARIF, JUnit and HTML reports carry those clauses. To get the clauses
439
+ without the profile, or for both versions, pass
440
+ `mappings: ['en301549']` (or `'en301549:V3.2.1'`); by default a result names
441
+ WCAG only. See
442
+ [`docs/ENGINE_OPTIONS.md`](./docs/ENGINE_OPTIONS.md#conformance-profiles) and
443
+ [`docs/WCAG_CONFORMANCE.md`](./docs/WCAG_CONFORMANCE.md#en-301-549).
444
+
332
445
  ---
333
446
 
334
447
  ## Understanding the Results
@@ -392,14 +505,25 @@ The complete schema also includes confidence, severity, WCAG
392
505
  traceability, composite rule results and other metadata intended for
393
506
  reporting and automation.
394
507
 
395
- For a complete field-by-field reference, see `docs/OUTPUT_SCHEMA.md`.
508
+ For a complete field-by-field reference, see
509
+ [Output schema](https://surea11y.dev/results-reports/output-schema/)
510
+ (`docs/OUTPUT_SCHEMA.md` in the repository).
396
511
 
397
512
  ---
398
513
 
399
514
  ## Documentation
400
515
 
401
- The project documentation is organized by topic so you can start quickly
402
- and progressively explore more advanced features.
516
+ Full documentation is available at **[surea11y.dev](https://surea11y.dev/)**:
517
+ [getting started](https://surea11y.dev/getting-started/) for each integration,
518
+ the [rule catalog](https://surea11y.dev/rules/),
519
+ [configuration](https://surea11y.dev/configuration/),
520
+ [results and reports](https://surea11y.dev/results-reports/),
521
+ [WCAG conformance](https://surea11y.dev/conformance/), and
522
+ [help](https://surea11y.dev/help/).
523
+
524
+ The repository also contains the following technical and contributor
525
+ documentation, useful as direct references when building on the engine or
526
+ contributing to it:
403
527
 
404
528
  | Document | Description |
405
529
  |---|---|
@@ -408,17 +532,20 @@ and progressively explore more advanced features.
408
532
  | `docs/BASELINE.md` | CI baseline/allowlist: gate builds only on new violations. |
409
533
  | `docs/REPORT.md` | Self-contained HTML report: browsable summary, WCAG rollup, filterable occurrence table. |
410
534
  | `docs/SARIF.md` | SARIF 2.1.0 report for GitHub Code Scanning and other SARIF dashboards. |
535
+ | `docs/JUNIT.md` | JUnit XML report for the test dashboards of GitLab, Azure DevOps, Jenkins and CircleCI. |
536
+ | `docs/EARL.md` | EARL 1.0 report in JSON-LD: the W3C interchange format, and the ACT implementation-report format. |
411
537
  | `docs/CI_INTEGRATIONS.md` | GitHub Actions and Bitbucket Pipelines templates wrapping the CLI. |
412
538
  | `docs/ENGINE_OPTIONS.md` | Configuration, filtering, policies and localization. |
413
539
  | `docs/INTEGRATION.md` | Using surea11y with jsdom, Playwright, Puppeteer, Selenium, Cypress and other drivers. |
414
540
  | `docs/BINDING_AUTHORS_GUIDE.md` | Building new framework integrations on top of the engine. |
415
- | `docs/RULE_CATALOG.md` | Reference of every built-in accessibility rule. |
541
+ | `docs/RULE_CATALOG.md` | Reference of every built-in accessibility rule; a profile's own rules are in its catalog, in `profiles/<key>/docs/RULE_CATALOG.md`. |
416
542
  | `docs/WCAG_CONFORMANCE.md` | Understanding WCAG rollups and conformance reporting. |
417
543
  | `docs/POLICY.md` | Built-in policy contracts and customization. |
418
544
  | `docs/I18N.md` | Translation support and localization. |
419
545
  | `docs/LIMITATIONS.md` | Structural limitations of automated accessibility testing. |
420
546
  | `docs/TROUBLESHOOTING.md` | Frequently asked questions and common issues. |
421
547
  | `docs/RULE_AUTHORING.md` | Writing custom accessibility rules. |
548
+ | `docs/RULE_HELPERS.md` | Reference for every `ctx.helpers` function available to a rule. |
422
549
  | `docs/RULE_TAXONOMY.md` | Rule categorization model. |
423
550
  | `docs/ACT_RULE_MAPPING.md` | Which ACT rules this engine implements, which it doesn't, and where the two differ by design. |
424
551
  | `docs/DESIGN_CHALLENGES.md` | Open and settled design questions, each with the reasoning behind the call. |
@@ -438,40 +565,16 @@ surea11y is built on a simple principle:
438
565
  > Automate what can be determined objectively. Never pretend to automate
439
566
  > what cannot.
440
567
 
441
- Accessibility is not something that can be reduced to a single score or
442
- a binary pass/fail result. Some WCAG requirements can be evaluated with
443
- complete confidence, while others require human judgement, knowledge of
444
- context or usability evaluation.
568
+ Some WCAG requirements can be checked with complete confidence. Others
569
+ need human judgement, knowledge of context, or usability evaluation. A
570
+ single score or a pass/fail verdict flattens that difference; surea11y
571
+ reports it.
445
572
 
446
- Rather than hiding that distinction, surea11y makes it explicit.
447
-
448
- That philosophy influences every rule in the engine and is the reason
449
- outcomes such as `cantTell` and `notApplicable` exist. They communicate
450
- uncertainty honestly instead of encouraging misleading conclusions.
451
-
452
- ### What surea11y won't catch
453
-
454
- Being explicit about the boundaries of automation is part of the same
455
- philosophy. For example, surea11y will not:
456
-
457
- - confirm that alt text is *meaningful*, only that it is present
458
- (an alt attribute of `"image123.png"` passes the objective check);
459
- - judge whether a color contrast choice is aesthetically appropriate,
460
- only whether it meets the applicable contrast ratio;
461
- - determine whether an error message actually *explains* the problem,
462
- since that depends on validation logic a static scan can't see;
463
- - detect a keyboard focus trap or content clipped at 400% zoom, since
464
- both require simulating real user interaction over time, not just
465
- reading the DOM at one instant.
466
-
467
- These are the cases where the engine reports `cantTell`, and where a
468
- human reviewer's judgement remains necessary. See
469
- `docs/LIMITATIONS.md` for the complete list of structural limitations.
470
-
471
- The objective of the project is not to replace accessibility experts. It
472
- is to remove repetitive verification work, provide reliable automated
473
- feedback to developers and help teams integrate accessibility into their
474
- normal development process.
573
+ This is why `cantTell` and `notApplicable` exist as outcomes (see
574
+ [What automated testing can and cannot do](#what-automated-testing-can-and-cannot-do)),
575
+ and why the engine is explicit about
576
+ [what it does not detect](#what-this-engine-does-not-detect). It shapes
577
+ every rule in the engine.
475
578
 
476
579
  ---
477
580
 
@@ -490,6 +593,11 @@ src/
490
593
  baseline.js # Baseline entry point (@surea11y/core/baseline)
491
594
  report.js # HTML report entry point (@surea11y/core/report)
492
595
  sarif.js # SARIF entry point (@surea11y/core/sarif)
596
+ junit.js # JUnit XML entry point (@surea11y/core/junit)
597
+ earl.js # EARL entry point (@surea11y/core/earl)
598
+ en301549.js # EN 301 549 clause table (@surea11y/core/en301549)
599
+ wcag.js # WCAG criteria per version (@surea11y/core/wcag)
600
+ profile-kit.js # Mapping for a profile made with profile:new (internal, not exported)
493
601
 
494
602
  checks/
495
603
  automatic/ # Deterministic automated rules
@@ -502,6 +610,10 @@ src/
502
610
  catalogs/ # Composite rule catalogs
503
611
  explain/ # Occurrence grouping, internal
504
612
 
613
+ profiles/
614
+ index.js # The profiles built into the engine (none yet)
615
+ README.md # What a profile holds and how to add one
616
+
505
617
  scripts/
506
618
  build-core.js # Generates src/core.js
507
619
  build-browser.js # Generates the browser bundle and its locale side files
@@ -550,9 +662,7 @@ engine consistency to ensure deterministic results across releases.
550
662
 
551
663
  Contributions are welcome.
552
664
 
553
- Whether you are fixing a bug, improving documentation or implementing a
554
- new accessibility rule, please keep the project's core principles in
555
- mind:
665
+ Bug fix, documentation, or a new rule — the same principles apply:
556
666
 
557
667
  - deterministic behaviour;
558
668
  - objective rule evaluation;
@@ -603,24 +713,3 @@ This project is released under the Mozilla Public License 2.0 (MPL-2.0).
603
713
  See the accompanying `LICENSE` file for the complete license text.
604
714
 
605
715
  MPL-2.0 is file-level copyleft: it applies to `@surea11y/core`'s own source files, not to code that merely depends on it. A project that installs `@surea11y/core` as a normal package dependency and imports its public API — without copying or modifying this repository's source files — is unaffected by MPL-2.0 and may keep its own license (including a permissive one like MIT).
606
-
607
- ---
608
-
609
- ## Final Notes
610
-
611
- surea11y was created with a simple goal: make accessibility testing
612
- trustworthy enough to become part of everyday software engineering.
613
-
614
- It does not attempt to replace manual accessibility reviews, usability
615
- testing or expert judgement. Instead, it focuses on providing reliable
616
- automated verification for the parts of accessibility that can be
617
- evaluated objectively.
618
-
619
- By combining deterministic rules, standards traceability, stable
620
- machine-readable output and honest reporting of uncertainty, surea11y
621
- enables teams to detect accessibility issues earlier, reduce regressions
622
- and build more accessible products with confidence.
623
-
624
- Accessibility is not a checkbox performed before release. It is an
625
- engineering practice that benefits from continuous feedback, and
626
- surea11y is designed to become one of those feedback loops.
@@ -7,7 +7,7 @@ Cross-reference between the [W3C ACT Rules](https://act-rules.github.io/rules/)
7
7
  - **~2** are covered structurally by our composite/rollup layer, not a named rule
8
8
  - **~46 are gaps**, no corresponding rule in this repo, listed in [Gaps](#gaps-no-corresponding-rule) below
9
9
 
10
- **Every matched rule has now been run through ACT's own official test-case corpus** (`scripts/act-testcase-check.js`, 713 test cases across the 51-rule matched set of the time). Started at 86 mismatches; real bugs were fixed, mapping errors corrected, and every remaining mismatch triaged into a scope difference, a jsdom/environment limit, or a genuine open design question (tracked in [`docs/DESIGN_CHALLENGES.md`](./DESIGN_CHALLENGES.md)). A second pass then re-ran the whole corpus from a local checkout (see "Second pass" below) and repeated the exercise on what it turned up. Current state: **798 examples across the 58-rule matched set, 32 mismatches, all explained** below or in that file; see "Progress" further down for the full per-rule breakdown. (The exact example count drifts slightly over time as ACT's own published corpus gains or loses cases; re-run `scripts/act-testcase-check.js` for the live figure rather than trusting this number indefinitely.)
10
+ **Every matched rule has now been run through ACT's own official test-case corpus** (`scripts/act-testcase-check.js`, 713 test cases across the 51-rule matched set of the time). Started at 86 mismatches; real bugs were fixed, mapping errors corrected, and every remaining mismatch triaged into a scope difference, a jsdom/environment limit, or a genuine open design question (tracked in [`docs/DESIGN_CHALLENGES.md`](./DESIGN_CHALLENGES.md)). A second pass then re-ran the whole corpus from a local checkout (see "Second pass" below) and repeated the exercise on what it turned up. Current state: **798 examples across the 58-rule matched set, 31 mismatches, all explained** below or in that file, and — the figure that matters for an implementation report — **zero false positives**: no example ACT declares `passed` or `inapplicable` is failed by this engine, so every remaining mismatch is a case it does not catch rather than one it gets wrong; see "Progress" further down for the full per-rule breakdown. (The exact example count drifts slightly over time as ACT's own published corpus gains or loses cases; re-run `scripts/act-testcase-check.js` for the live figure rather than trusting this number indefinitely.)
11
11
 
12
12
  Real rule bugs found and fixed this way, in rough chronological order:
13
13
  - `button-name-present` wasn't crediting the UA-default label on `input[type=submit]`/`input[type=reset]` with no `value`, and wasn't honoring `role="none"`/`role="presentation"` conflict-resolution.
@@ -31,6 +31,7 @@ Real rule bugs found and fixed this way, in rough chronological order:
31
31
  - `getContainmentRole` handed several native tags an implicit role in every context, where HTML-AAM makes them conditional: `<li>` is a `listitem` only inside `<ul>`/`<ol>`/`<menu>`, `<option>` only inside `select`/`datalist`/`optgroup`, the table family only inside a real table. ACT `bc4a75` fails `<div role="list"><li>Item</li>…</div>` for exactly that reason and the engine passed it. The three rules built on that helper (`aria-required-children`, `aria-prohibited-children`, `aria-required-parent`) all inherit the fix.
32
32
  - `identical-links-same-purpose`'s `a[href]`-only selector missed `role="link"` elements entirely; ACT `fd3a94`/`b20e66`'s own failed examples are `<span role="link" tabindex="0" onclick="location='...'">`. Widened to `a[href], [role="link"]`, with a regex fallback that reads a `location`/`location.href`/`location.assign(...)`/`location.replace(...)` destination straight out of the `onclick` attribute value, a literal string already present in markup, no script execution needed. This rule is `cantTell`-capped, so an unrecognized `onclick` shape just costs recall, not a false fail.
33
33
  - `iframe-name-present`'s focusability exemption only applied inside the `role="none"`/`"presentation"` branch; a plain `<iframe tabindex="-1">` with no role at all (ACT cae760's own passed example) still demanded a name. Per cae760's own Applicability text, an iframe is only in scope when it is BOTH accessibility-tree-eligible AND reachable by sequential focus navigation, unconditionally, not only as a role="none" carve-out. The focusability check now gates applicability directly, regardless of role.
34
+ - `avoid-inline-spacing` failed text that can never take a soft wrap break, which ACT 78fd32/24afc2/9e45ec exclude from applicability altogether. This was the engine's last false positive on the corpus, and the rule's own header had already predicted it: layout settles whether text wraps and a static scan cannot. Two shapes do establish that no wrap is possible without layout — text not allowed to wrap, and a fixed-width element inside a horizontally scrolling ancestor — and those now report `cantTell` instead of `fail`. Everything else is still treated as wrapping, so an ordinary forced value below the metric fails as before.
34
35
 
35
36
  Mapping-table corrections found this way (data-only, no rule-code change):
36
37
  - `bc4a75` was mapped to `aria-required-children` alone, but this repo splits ACT's single question into two atomic decisions: "does a required child exist" and "is every owned child allowed," the second being `aria-prohibited-children`. Measuring one rule against a two-part expectation reported the missing half as an engine gap; it was a mapping gap. Now a family match.
@@ -47,7 +48,7 @@ Gaps closed since:
47
48
  - `oj04fd` "Element in sequential focus order has visible focus" is now partly covered by the new `css-focus-indicator-suppressed` rule: it reads the page's own stylesheets for a `:focus`/`:focus-visible` rule that removes the outline, and reports the tab stops it matches unless some other focus rule draws a replacement for them. ACT's expectation is a pixel comparison between the focused and unfocused states, which no static check performs, and its passed examples paint their indicator from an `onfocus` handler onto a sibling, so the rule is `cantTell`-capped and the mapping is `partial`.
48
49
  - `cc0f0a` "Form field label is descriptive" is now partly covered by the new `form-control-label-quality` rule. Three shapes of a bad label are decidable from markup: a placeholder string, a label repeated on several fields with no *visible* heading, legend or row text telling them apart, and a label split between visible and hidden parts. The second and third are what ACT's own failed examples 4 and 5 test, and the rule catches both; the remaining three failures turn on the meaning of an ordinary word, so the mapping is `partial` and the rule is `cantTell`-capped.
49
50
  - `5effbb` "Link in context is descriptive" is now partly covered by `link-name-quality`, which already flagged a curated list of generic phrases ("click here", "read more", ...) with no regard for context. It gained a second curated list, bare file-format names ("HTML", "PDF", "EPUB", ...), and both lists now check for adjacent context (an `aria-describedby` target, the enclosing list item/table cell/paragraph's own text, or, for the format-name list only, a table's first-row header) before flagging, so a phrase that context already resolves is left alone. Clean on 17 of ACT's 18 examples; the remaining one needs to judge whether an ordinary word ("Workshop") actually relates to a nearby paragraph, a step beyond a phrase list.
50
- - `3ea0c8` "Id attribute value is unique" is closed by the new `duplicate-id` rule, clean against all 10 of ACT's examples, including the per-tree scoping that keeps the same id inside two different shadow roots from counting as a duplicate. It is the first rule in the catalog whose Success Criterion no longer exists in the current WCAG version, so it carries `wcag22-removed` alongside its `wcag2a` origin tag; see `docs/ENGINE_OPTIONS.md` for how a 2.2 conformance run excludes it.
51
+ - `3ea0c8` "Id attribute value is unique" is closed by the new `duplicate-id` rule, clean against all 10 of ACT's examples, including the per-tree scoping that keeps the same id inside two different shadow roots from counting as a duplicate. It is the first rule in the catalog whose Success Criterion no longer exists in the current WCAG version, so it carries `wcag22-removed` alongside its `wcag2a` origin tag; under the default 2.2 target the engine reports its findings as `cantTell` rather than `fail`. See `docs/ENGINE_OPTIONS.md` for that and for excluding the rule outright.
51
52
 
52
53
  ### Second pass: the corpus read from a local checkout
53
54
 
@@ -73,9 +74,11 @@ We also have automatic rules with **no ACT counterpart at all** (see [Extra cove
73
74
 
74
75
  ### Progress: full validation results, by ACT rule
75
76
 
76
- **Clean (0 mismatches):** `5f99a7`, `80f0bf`, `4c31df`, `73f2c2`, `97a4e1`, `cf77f2`, `b40fd1`, `46ca7f`, `6cfa84`, `307n5z`, `4e8ab6`, `a25f45`, `ffd0e9`, `b5c3f8`, `2779a5`, `5b7ae0`, `bf051a`, `qt1vmo`, `59796f`, `23a2a8`, `24afc2`, `9e45ec`, `c487ae`, `m6b1q3`, `bc659a`, `bisz58`, `b4f0c3`, `674b10`, `0ssw9k`, `3ea0c8`, `5c01ea`, `bc4a75`, `2ee8b8`, `e88epe`, `7d6734`, `de46e4`, `6a7281`, `8fc3b6`, `akn7bn`, `fd3a94`, `b20e66`, `cae760` (42 of 57 matched rules).
77
+ **Clean (0 mismatches):** `5f99a7`, `80f0bf`, `4c31df`, `73f2c2`, `97a4e1`, `cf77f2`, `b40fd1`, `46ca7f`, `6cfa84`, `307n5z`, `4e8ab6`, `a25f45`, `ffd0e9`, `b5c3f8`, `2779a5`, `5b7ae0`, `bf051a`, `qt1vmo`, `59796f`, `23a2a8`, `24afc2`, `9e45ec`, `c487ae`, `m6b1q3`, `bc659a`, `bisz58`, `b4f0c3`, `674b10`, `0ssw9k`, `3ea0c8`, `5c01ea`, `bc4a75`, `2ee8b8`, `e88epe`, `7d6734`, `de46e4`, `6a7281`, `8fc3b6`, `akn7bn`, `fd3a94`, `b20e66`, `cae760`, `78fd32` (43 of 58 matched rules).
77
78
 
78
- **Remaining mismatches (32 total), all triaged:**
79
+ Two rules changed what they report after this table was last regenerated, both from `fail` to `cantTell`: `3ea0c8`/`duplicate-id` under the default WCAG 2.2 target, and `6a7281`/`aria-valid-attr-value` for an unresolved `aria-controls` target (see `docs/DESIGN_CHALLENGES.md`). The verdicts above should still hold, since `evaluate()` in `scripts/act-testcase-check.js` counts a `cantTell` carrying occurrences as satisfying an ACT "failed" expectation and a `cantTell` never breaks a "passed" one, but neither was re-run against the live corpus at the time (the site was unreachable from that environment). Re-run both when convenient.
80
+
81
+ **Remaining mismatches (31 total), all triaged.** Every one is an ACT `failed` example this engine does not flag — a coverage gap, which a partially consistent implementation is allowed — not an example it fails wrongly:
79
82
 
80
83
  | ACT ID | Mismatches | Category |
81
84
  |---|---|---|
@@ -87,7 +90,6 @@ We also have automatic rules with **no ACT counterpart at all** (see [Extra cove
87
90
  | `oj04fd` | 1 | env/harness limit: ACT's one failed example keeps its `outline: none` in a linked stylesheet, which the example runner does not fetch, so no focus rule is visible to parse at all. Inlining that same CSS reports the element (`tests/engine-checks/manual/css-focus-indicator-suppressed.test.js` pins it); a real page hands the engine its stylesheets through the CSSOM |
88
91
  | `cc0f0a` | 3 | inherent limitation: `form-control-label-quality` catches the three deterministic shapes (a placeholder label, a label repeated with no visible heading/legend/row telling the fields apart, a label split between visible and hidden parts, which covers ACT's failed examples 4 and 5). The remaining three fail on the meaning of a well-formed word, `<label>Menu</label>` over a first-name field, which no markup-level check reaches |
89
92
  | `b49b2e` | 5 | inherent limitation: `heading-quality` catches placeholder heading text (a generic word, a numbered template slot, a filename, a URL), which is the deterministic half of this rule; whether a well-formed heading actually describes the content after it is a reading-comprehension judgment, and all 5 of ACT's failed examples are exactly that shape ("Weather" over opening hours, across five different heading-naming mechanisms) |
90
- | `78fd32` | 1 | documented limitation: `avoid-inline-spacing`'s own header comment already states it can't detect "text that never soft-wraps" without real layout |
91
93
  | `aizyf1` | 2 | inherent tension with `5effbb`'s own examples, not a bug: both remaining cases (`<a>this product</a>` after "See the description of", and a format-name list under an "Ulysses" heading) are ACT's own *passed* examples for `5effbb` (context-aware) but *failed* examples for `aizyf1` (context-blind: the accessible name alone, ignoring what makes it clear, must already be descriptive). One shared rule can credit context or not, not both on the same markup; `link-name-quality` sides with `5effbb`'s reading, which is what its context-detection is for |
92
94
  | `5effbb` | 1 | genuine judgment gap: the one remaining case (`<a>Workshop</a>` after an unrelated paragraph) needs to judge whether an ordinary word actually relates to nearby prose, not a phrase-list or context-structure question `link-name-quality` can answer |
93
95
  | `d0f69e` | 3 | documented false-negative policy: `table-th-has-data-cells`'s own header comment explains it only catches the unambiguous "zero data cells anywhere" case, not real positional header-association (the new ARIA-grid coverage added during this pass is real but doesn't happen to close these 3 specific positional-mismatch cases) |
@@ -185,7 +187,7 @@ Grouped by theme, with WCAG SC where ACT declares one:
185
187
  - `3e12e1` Block of repeated content is collapsible
186
188
 
187
189
  **Judgment-call gaps found during test-case validation:**
188
- - `4b1c6c` "Iframes with identical accessible names have equivalent purpose" was originally mapped to `iframe-title-unique`, but running ACT's own test cases against it exposed that they test different things: ACT's rule accepts a duplicate name when the two iframes point to equivalent content (same resource, mirrors, equivalent ads/sections) and only fails when duplicate-named iframes point to genuinely different content, a content-equivalence judgment call, the same class of check as our existing manual `identical-links-same-purpose`. `iframe-title-unique` instead flags *any* duplicate `title` attribute outright, by design (see its own header comment), a stricter, different, independently-valid check with no ACT counterpart of its own. Moved to "Extra coverage" below; `4b1c6c` itself stays a gap, closing it for real would mean a new manual `identical-iframes-same-purpose`-style rule, not a fix to `iframe-title-unique`.
190
+ - `4b1c6c` "Iframes with identical accessible names have equivalent purpose" was originally mapped to `iframe-title-unique`, but ACT's own test cases showed they test different things: ACT's rule accepts a duplicate name when the frames embed equivalent content (same resource, mirrors, equivalent ads or sections) and fails only when they embed different content, a content-equivalence judgment of the same kind as our manual `identical-links-same-purpose`. `iframe-title-unique` failed any duplicate `title` attribute, which this note first filed as a deliberate, stricter check with no ACT counterpart. `4b1c6c` was then closed by `identical-iframes-same-purpose`. On a second look (#16), the stricter check had no normative basis: WCAG 4.1.2 asks that a frame's name be exposed, not unique, and seven of 4b1c6c's ten passed examples failed under it. A frame's `title` is also its accessible name unless `aria-label` or `aria-labelledby` overrides it, so the two rules asked the same question of the same elements. `iframe-title-unique` is deprecated since 1.8.0 and reports `notApplicable`; `identical-iframes-same-purpose` alone covers `4b1c6c`. See `DESIGN_CHALLENGES.md`.
189
191
  - `5effbb` "Link in context is descriptive" was originally mapped to `link-in-text-block` on a name-similarity guess ("link" + "context/text"); its real applicability/expectation (fetched directly from act-rules.github.io) is "the accessible name together with its programmatically determined link context describes the purpose of the link," WCAG 2.4.4, the *context-aware* sibling of `aizyf1`/`link-name-quality`, unrelated to `link-in-text-block`'s WCAG 1.4.1 color-distinguishability check (which is itself correctly scoped to `a[href]` only, per its own header comment, not a bug). This was later closed by teaching `link-name-quality` to weigh adjacent context; see "Gaps closed since" below.
190
192
  - `oj04fd` "Element in sequential focus order has visible focus" was originally mapped to `css-hidden-focus` on a surface keyword match ("focus," "visible"); its real applicability/expectation is about whether a browser draws *any* visible focus indicator for a normally-visible, normally-positioned element (i.e. `:focus`/`:focus-visible` CSS suppressing the outline with no replacement), a completely different concern from `css-hidden-focus`'s actual check (a keyboard-focusable element that is itself visually hidden by CSS, e.g. `opacity:0`/clip/off-screen). Removed from the matched table and moved to Gaps; a plausible new-rule candidate, not a fix to `css-hidden-focus`, and built as one since, `css-focus-indicator-suppressed`, which is what `oj04fd` maps to now.
191
193
  - `cc0f0a` "Form field label is descriptive" and `c4a8a4` "HTML page title is descriptive" were both mapped to rules that only catch a narrower, adjacent concern: `form-control-programmatic-label-quality` flags a *weak primary labeling mechanism* (title/placeholder used instead of a real label), never whether a properly-associated label's own text is relevant to the field; `page-title-patterns` flags generic/templated title *patterns* (e.g. "Home", "Untitled"), never whether a specific, plausible-looking title actually matches the page's content (ACT's own failed example: `<title>Apple harvesting season</title>` on a page about clementines, a real title/content mismatch neither pattern-list nor mechanism-check was ever designed to catch). Both ACT ids moved to Gaps; both of our rules moved to [Extra coverage](#extra-coverage-beyond-act) as valid, independent, narrower checks with no ACT counterpart of their own. `cc0f0a` has since been picked up by a new rule of its own, `form-control-label-quality`; `c4a8a4` remains a gap.
@@ -207,7 +209,7 @@ The goal is maximum automation, not just parity with ACT's own scope; several ga
207
209
  - `c4a8a4` HTML page title is descriptive (title-vs-content relevance): harder to heuristic than the others in this tier (needs some notion of "does this title's vocabulary overlap with the page's own content," not just a pattern/word list), so lower confidence within this tier.
208
210
 
209
211
  **Design decision needed before building (not purely a confidence question):**
210
- - ~~`3ea0c8` Page-wide unique `id`~~: built as `duplicate-id`, tagged `wcag2a` plus the new `wcag22-removed`, which a 2.2 conformance run excludes and a 2.0/2.1 run keeps. The decision that unblocked it, and the reasoning, are in `docs/DESIGN_CHALLENGES.md`'s "Decided" section; the tag is documented in `docs/ENGINE_OPTIONS.md`.
212
+ - ~~`3ea0c8` Page-wide unique `id`~~: built as `duplicate-id`, tagged `wcag2a` plus the new `wcag22-removed`, which a 2.2 conformance run reports as `cantTell` (or excludes outright) and a 2.0/2.1 run keeps as a real failure. The decision that unblocked it, and the reasoning, are in `docs/DESIGN_CHALLENGES.md`'s "Decided" section; the tag is documented in `docs/ENGINE_OPTIONS.md`.
211
213
 
212
214
  **Lower confidence, needs a different technique than the rest of the engine:**
213
215
  - `e6952f` Attribute is not duplicated: only detectable from the raw HTML *text* (the DOM has already collapsed duplicate attributes by the time any DOM-based rule runs), a different input than every other rule in this engine uses. Feasible only where raw source is available (not guaranteed in every integration).
@@ -233,7 +235,7 @@ The goal is maximum automation, not just parity with ACT's own scope; several ga
233
235
 
234
236
  Rules in this repo with no ACT counterpart, mostly finer decomposition of ACT's single `e086e5` "form field has accessible name" rule into one rule per ARIA widget type, plus some ARIA-validity and structural rules ACT doesn't break out separately:
235
237
 
236
- `aria-hidden-body`, `aria-braille-equivalent`, `aria-conditional-attr`, `aria-deprecated-role`, `aria-prohibited-attr`, `aria-prohibited-children`, `aria-role-name-present`, `binary-control-name-present`, `canvas-text-alternative-present`, `combobox-name-present`, `contrast-computable`, `definition-list-children-valid`, `deprecated-elements-not-used`, `dialog-name-present`, `dlitem-parent-valid`, `duplicate-id-aria`, `embed-text-alternative-present`, `form-control-programmatic-label-quality`, `form-control-single-label`, `iframe-title-unique`, `list-children-valid`, `listbox-name-present`, `listitem-parent-valid`, `meter-name-present`, `nested-interactive-controls-absent`, `option-name-present`, `page-title-patterns`, `progressbar-name-present`, `searchbox-name-present`, `server-side-image-map-absent`, `slider-name-present`, `spinbutton-name-present`, `summary-name-present`, `svg-image-text-alternative-present`, `tab-name-present`, `target-size-minimum`, `td-has-header`, `textbox-name-present`, `tooltip-name-present`, `treeitem-name-present`, `video-poster-text-alternative-present`, `area-alt-present`.
238
+ `aria-hidden-body`, `aria-braille-equivalent`, `aria-conditional-attr`, `aria-deprecated-role`, `aria-prohibited-attr`, `aria-prohibited-children`, `aria-role-name-present`, `binary-control-name-present`, `canvas-text-alternative-present`, `combobox-name-present`, `contrast-computable`, `definition-list-children-valid`, `deprecated-elements-not-used`, `dialog-name-present`, `dlitem-parent-valid`, `duplicate-id-aria`, `embed-text-alternative-present`, `form-control-programmatic-label-quality`, `form-control-single-label`, `list-children-valid`, `listbox-name-present`, `listitem-parent-valid`, `meter-name-present`, `nested-interactive-controls-absent`, `option-name-present`, `page-title-patterns`, `progressbar-name-present`, `searchbox-name-present`, `server-side-image-map-absent`, `slider-name-present`, `spinbutton-name-present`, `summary-name-present`, `svg-image-text-alternative-present`, `tab-name-present`, `target-size-minimum`, `td-has-header`, `textbox-name-present`, `tooltip-name-present`, `treeitem-name-present`, `video-poster-text-alternative-present`, `area-alt-present`.
237
239
 
238
240
  ## Next steps
239
241