@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.
- package/CHANGELOG.md +140 -0
- package/README.md +179 -90
- package/docs/ACT_RULE_MAPPING.md +10 -8
- package/docs/API_STABILITY.md +67 -6
- package/docs/BINDING_AUTHORS_GUIDE.md +104 -2
- package/docs/CI_INTEGRATIONS.md +43 -0
- package/docs/DESIGN_CHALLENGES.md +162 -2
- package/docs/EARL.md +100 -0
- package/docs/ENGINE_OPTIONS.md +109 -5
- package/docs/I18N.md +62 -20
- package/docs/INTEGRATION.md +4 -2
- package/docs/JUNIT.md +73 -0
- package/docs/LIMITATIONS.md +4 -1
- package/docs/OUTPUT_SCHEMA.md +62 -11
- package/docs/POLICY.md +1 -1
- package/docs/REPORT.md +7 -2
- package/docs/RULE_AUTHORING.md +83 -17
- package/docs/RULE_CATALOG.md +212 -139
- package/docs/RULE_EXAMPLES.md +2189 -0
- package/docs/RULE_HELPERS.md +390 -0
- package/docs/RULE_TAXONOMY.md +27 -6
- package/docs/SARIF.md +23 -3
- package/docs/WCAG_CONFORMANCE.md +64 -3
- package/package.json +41 -12
- package/profiles/index.js +14 -0
- package/src/checks/automatic/area-alt-present.js +87 -31
- package/src/checks/automatic/aria-allowed-attr.js +6 -0
- package/src/checks/automatic/aria-allowed-role.js +32 -23
- package/src/checks/automatic/aria-braille-equivalent.js +43 -17
- package/src/checks/automatic/aria-conditional-attr.js +17 -10
- package/src/checks/automatic/aria-deprecated-role.js +12 -0
- package/src/checks/automatic/aria-hidden-body.js +1 -1
- package/src/checks/automatic/aria-hidden-focus.js +74 -18
- package/src/checks/automatic/aria-prohibited-attr.js +22 -4
- package/src/checks/automatic/aria-prohibited-children.js +6 -6
- package/src/checks/automatic/aria-required-attr.js +88 -12
- package/src/checks/automatic/aria-required-children.js +33 -16
- package/src/checks/automatic/aria-required-parent.js +32 -6
- package/src/checks/automatic/aria-role-name-present.js +20 -3
- package/src/checks/automatic/aria-roles-valid.js +52 -21
- package/src/checks/automatic/aria-valid-attr-value.js +89 -24
- package/src/checks/automatic/aria-valid-attr.js +14 -9
- package/src/checks/automatic/autocomplete-valid.js +152 -26
- package/src/checks/automatic/avoid-inline-spacing.js +207 -15
- package/src/checks/automatic/button-name-present.js +2 -1
- package/src/checks/automatic/canvas-text-alternative-present.js +105 -14
- package/src/checks/automatic/combobox-name-present.js +34 -51
- package/src/checks/automatic/contrast-computable.js +45 -4
- package/src/checks/automatic/contrast-enhanced.js +16 -4
- package/src/checks/automatic/contrast-minimum.js +57 -11
- package/src/checks/automatic/css-orientation-lock.js +171 -12
- package/src/checks/automatic/definition-list-children-valid.js +67 -23
- package/src/checks/automatic/deprecated-elements-not-used.js +43 -38
- package/src/checks/automatic/dialog-name-present.js +28 -9
- package/src/checks/automatic/duplicate-id-aria.js +5 -0
- package/src/checks/automatic/duplicate-id.js +19 -10
- package/src/checks/automatic/form-control-single-label.js +9 -0
- package/src/checks/automatic/identical-iframes-same-purpose.js +229 -0
- package/src/checks/automatic/iframe-focusable-content.js +12 -4
- package/src/checks/automatic/iframe-title-unique.js +36 -81
- package/src/checks/automatic/input-image-alt-present.js +32 -20
- package/src/checks/automatic/label-in-name.js +78 -69
- package/src/checks/automatic/language-page-present.js +12 -6
- package/src/checks/automatic/link-in-text-block.js +512 -44
- package/src/checks/automatic/link-name-present.js +13 -5
- package/src/checks/automatic/list-children-valid.js +18 -1
- package/src/checks/automatic/listbox-name-present.js +19 -49
- package/src/checks/automatic/listitem-parent-valid.js +4 -3
- package/src/checks/automatic/meta-refresh-no-exceptions.js +3 -3
- package/src/checks/automatic/page-title-present.js +16 -4
- package/src/checks/automatic/progressbar-name-present.js +11 -1
- package/src/checks/automatic/{role-img-alt-present.js → role-img-text-alternative-present.js} +9 -5
- package/src/checks/automatic/searchbox-name-present.js +32 -49
- package/src/checks/automatic/server-side-image-map-absent.js +48 -28
- package/src/checks/automatic/slider-name-present.js +38 -52
- package/src/checks/automatic/spinbutton-name-present.js +32 -49
- package/src/checks/automatic/target-size-minimum.js +84 -16
- package/src/checks/automatic/td-has-header.js +60 -23
- package/src/checks/automatic/text-spacing-content-loss.js +548 -0
- package/src/checks/automatic/textbox-name-present.js +32 -49
- package/src/checks/automatic/valid-lang.js +15 -10
- package/src/checks/manual/area-alt-quality-manual.js +113 -31
- package/src/checks/manual/canvas-text-alternative-quality-manual.js +0 -2
- package/src/checks/manual/css-focus-indicator-suppressed-manual.js +23 -10
- package/src/checks/manual/css-hidden-focus.js +215 -7
- package/src/checks/manual/form-control-label-quality-manual.js +243 -29
- package/src/checks/manual/heading-order-manual.js +9 -1
- package/src/checks/manual/heading-quality-manual.js +143 -9
- package/src/checks/manual/img-alt-decorative-manual.js +6 -3
- package/src/checks/manual/input-image-alt-quality-manual.js +81 -13
- package/src/checks/manual/landmark-complementary-is-top-level-manual.js +231 -0
- package/src/checks/manual/link-name-quality-manual.js +130 -4
- package/src/checks/manual/media-transcript-present-manual.js +65 -8
- package/src/checks/manual/mouse-only-event-handlers-manual.js +66 -5
- package/src/checks/manual/no-autoplay-audio-manual.js +93 -6
- package/src/checks/manual/p-as-heading-manual.js +89 -44
- package/src/checks/manual/page-title-patterns-manual.js +77 -8
- package/src/checks/manual/password-paste-enabled-manual.js +255 -0
- package/src/checks/manual/skip-link-manual.js +42 -14
- package/src/checks/manual/table-fake-caption-manual.js +32 -1
- package/src/checks/manual/video-caption-manual.js +47 -24
- package/src/checks/manual-review.js +0 -4
- package/src/core.js +18061 -46194
- package/src/coverage/en301549-map.js +187 -0
- package/src/coverage/standards.js +279 -0
- package/src/coverage/wcag-facets.js +1119 -0
- package/src/coverage/wcag-version-map.js +101 -0
- package/src/earl.js +144 -0
- package/src/en301549.js +33 -0
- package/src/junit.js +321 -0
- package/src/profile-kit.js +163 -0
- package/src/report.js +343 -74
- package/src/sarif.js +56 -5
- package/src/wcag.js +105 -0
- package/surea11y.browser.js +11 -41039
- package/surea11y.i18n.de.js +2 -21
- package/surea11y.i18n.es.js +2 -21
- package/surea11y.i18n.fr.js +2 -21
- package/surea11y.i18n.ja.js +3 -0
- package/src/checks/manual/area-alt-decorative-manual.js +0 -255
package/README.md
CHANGED
|
@@ -6,30 +6,79 @@
|
|
|
6
6
|
[](package.json)
|
|
7
7
|
[](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
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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 `
|
|
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
|
-
|
|
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
|
-
|
|
86
|
-
`
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
402
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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
|
-
|
|
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.
|
package/docs/ACT_RULE_MAPPING.md
CHANGED
|
@@ -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,
|
|
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;
|
|
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` (
|
|
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
|
-
|
|
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
|
|
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`, `
|
|
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
|
|