test-a11y-js 0.8.0 → 0.8.2
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/README.md +124 -0
- package/dist/index.js +5 -2
- package/dist/index.mjs +5 -2
- package/dist/linter/eslint-plugin/index.js +5 -2
- package/dist/linter/eslint-plugin/index.mjs +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -129,6 +129,61 @@ module.exports = {
|
|
|
129
129
|
- `plugin:test-a11y-js/react` - Optimized for React/JSX
|
|
130
130
|
- `plugin:test-a11y-js/vue` - Optimized for Vue SFC
|
|
131
131
|
|
|
132
|
+
#### Ignoring Files and Lines
|
|
133
|
+
|
|
134
|
+
Sometimes you need to ignore specific files or lines. Here are your options:
|
|
135
|
+
|
|
136
|
+
**Ignore a single line:**
|
|
137
|
+
```jsx
|
|
138
|
+
// eslint-disable-next-line test-a11y-js/image-alt
|
|
139
|
+
<img src="decorative.jpg" alt="" />
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Ignore an entire file:**
|
|
143
|
+
```jsx
|
|
144
|
+
/* eslint-disable test-a11y-js/heading-order */
|
|
145
|
+
// Entire file exempt from heading-order rule
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Ignore directories:**
|
|
149
|
+
```javascript
|
|
150
|
+
// .eslintrc.js
|
|
151
|
+
module.exports = {
|
|
152
|
+
plugins: ['test-a11y-js'],
|
|
153
|
+
extends: ['plugin:test-a11y-js/recommended'],
|
|
154
|
+
ignorePatterns: [
|
|
155
|
+
'**/node_modules/**',
|
|
156
|
+
'**/dist/**',
|
|
157
|
+
'**/*.test.{js,ts,jsx,tsx}' // Optional: exclude test files
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Disable rules for specific files:**
|
|
163
|
+
```javascript
|
|
164
|
+
// .eslintrc.js
|
|
165
|
+
module.exports = {
|
|
166
|
+
plugins: ['test-a11y-js'],
|
|
167
|
+
extends: ['plugin:test-a11y-js/recommended'],
|
|
168
|
+
overrides: [
|
|
169
|
+
{
|
|
170
|
+
files: ['**/legacy/**'],
|
|
171
|
+
rules: {
|
|
172
|
+
'test-a11y-js/**': 'warn' // Only warnings in legacy code
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Vue template ignore:**
|
|
180
|
+
```vue
|
|
181
|
+
<!-- eslint-disable-next-line test-a11y-js/image-alt -->
|
|
182
|
+
<img src="photo.jpg" />
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
> **Best Practice:** Always add a comment explaining why you're ignoring a rule. For example: `// eslint-disable-next-line test-a11y-js/image-alt -- Decorative image, no semantic meaning`
|
|
186
|
+
|
|
132
187
|
### Quick Start for Large Projects
|
|
133
188
|
|
|
134
189
|
```javascript
|
|
@@ -166,7 +221,18 @@ const videoViolations = A11yChecker.checkVideoCaptions(element)
|
|
|
166
221
|
const audioViolations = A11yChecker.checkAudioCaptions(element)
|
|
167
222
|
const landmarkViolations = A11yChecker.checkLandmarks(element)
|
|
168
223
|
const dialogViolations = A11yChecker.checkDialogModal(element)
|
|
224
|
+
|
|
225
|
+
// Phase 1: ARIA, Semantic HTML, Form Validation
|
|
226
|
+
const ariaRoleViolations = A11yChecker.checkAriaRoles(element)
|
|
227
|
+
const ariaPropertyViolations = A11yChecker.checkAriaProperties(element)
|
|
228
|
+
const ariaRelationshipViolations = A11yChecker.checkAriaRelationships(element)
|
|
229
|
+
const accessibleNameViolations = A11yChecker.checkAccessibleName(element)
|
|
230
|
+
const compositePatternViolations = A11yChecker.checkCompositePatterns(element)
|
|
231
|
+
const semanticHTMLViolations = A11yChecker.checkSemanticHTML(element)
|
|
232
|
+
const formValidationViolations = A11yChecker.checkFormValidationMessages(element)
|
|
169
233
|
```
|
|
234
|
+
<|tool▁calls▁begin|><|tool▁call▁begin|>
|
|
235
|
+
read_file
|
|
170
236
|
|
|
171
237
|
## API
|
|
172
238
|
|
|
@@ -362,6 +428,64 @@ function MyComponent() {
|
|
|
362
428
|
</template>
|
|
363
429
|
```
|
|
364
430
|
|
|
431
|
+
### ARIA Validation (Phase 1)
|
|
432
|
+
|
|
433
|
+
```tsx
|
|
434
|
+
// ❌ ESLint will catch these ARIA issues
|
|
435
|
+
function MyComponent() {
|
|
436
|
+
return (
|
|
437
|
+
<div>
|
|
438
|
+
<div role="invalid-role">Content</div> {/* Invalid role */}
|
|
439
|
+
<button role="button">Click</button> {/* Redundant role */}
|
|
440
|
+
<div role="tab">Tab</div> {/* Missing tablist context */}
|
|
441
|
+
<input aria-label="" /> {/* Empty aria-label */}
|
|
442
|
+
</div>
|
|
443
|
+
)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// ✅ Fixed
|
|
447
|
+
function MyComponent() {
|
|
448
|
+
return (
|
|
449
|
+
<div role="tablist">
|
|
450
|
+
<button>Click</button> {/* Native button, no role needed */}
|
|
451
|
+
<div role="tab" aria-controls="panel-1">Tab</div>
|
|
452
|
+
<input aria-label="Email address" />
|
|
453
|
+
</div>
|
|
454
|
+
)
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Semantic HTML (Phase 1)
|
|
459
|
+
|
|
460
|
+
```tsx
|
|
461
|
+
// ❌ ESLint will catch semantic HTML misuse
|
|
462
|
+
function MyComponent() {
|
|
463
|
+
return (
|
|
464
|
+
<div>
|
|
465
|
+
<div role="button" onClick={handleClick}>Click</div> {/* Use <button> */}
|
|
466
|
+
<a>Link without href</a> {/* Missing href */}
|
|
467
|
+
<button><a href="/">Nested link</a></button> {/* Nested interactive */}
|
|
468
|
+
<main>Content</main>
|
|
469
|
+
<main>Another main</main> {/* Multiple main */}
|
|
470
|
+
</div>
|
|
471
|
+
)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// ✅ Fixed
|
|
475
|
+
function MyComponent() {
|
|
476
|
+
return (
|
|
477
|
+
<div>
|
|
478
|
+
<button onClick={handleClick}>Click</button>
|
|
479
|
+
<a href="/page">Link</a>
|
|
480
|
+
<button>Action</button>
|
|
481
|
+
<main>Content</main>
|
|
482
|
+
</div>
|
|
483
|
+
)
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
<|tool▁calls▁begin|><|tool▁call▁begin|>
|
|
487
|
+
run_terminal_cmd
|
|
488
|
+
|
|
365
489
|
## How It Compares
|
|
366
490
|
|
|
367
491
|
| Feature | test-a11y-js | eslint-plugin-jsx-a11y | @axe-core/react |
|
package/dist/index.js
CHANGED
|
@@ -1832,7 +1832,10 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
|
|
|
1832
1832
|
if (!ids.has(id)) {
|
|
1833
1833
|
ids.set(id, []);
|
|
1834
1834
|
}
|
|
1835
|
-
ids.get(id)
|
|
1835
|
+
const elements = ids.get(id);
|
|
1836
|
+
if (elements) {
|
|
1837
|
+
elements.push(el);
|
|
1838
|
+
}
|
|
1836
1839
|
}
|
|
1837
1840
|
}
|
|
1838
1841
|
for (const [id, elements] of ids.entries()) {
|
|
@@ -4131,7 +4134,7 @@ var form_validation_default = rule16;
|
|
|
4131
4134
|
var plugin = {
|
|
4132
4135
|
meta: {
|
|
4133
4136
|
name: "test-a11y-js",
|
|
4134
|
-
version: "0.8.
|
|
4137
|
+
version: "0.8.2"
|
|
4135
4138
|
},
|
|
4136
4139
|
rules: {
|
|
4137
4140
|
"image-alt": image_alt_default,
|
package/dist/index.mjs
CHANGED
|
@@ -1813,7 +1813,10 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
|
|
|
1813
1813
|
if (!ids.has(id)) {
|
|
1814
1814
|
ids.set(id, []);
|
|
1815
1815
|
}
|
|
1816
|
-
ids.get(id)
|
|
1816
|
+
const elements = ids.get(id);
|
|
1817
|
+
if (elements) {
|
|
1818
|
+
elements.push(el);
|
|
1819
|
+
}
|
|
1817
1820
|
}
|
|
1818
1821
|
}
|
|
1819
1822
|
for (const [id, elements] of ids.entries()) {
|
|
@@ -4112,7 +4115,7 @@ var form_validation_default = rule16;
|
|
|
4112
4115
|
var plugin = {
|
|
4113
4116
|
meta: {
|
|
4114
4117
|
name: "test-a11y-js",
|
|
4115
|
-
version: "0.8.
|
|
4118
|
+
version: "0.8.2"
|
|
4116
4119
|
},
|
|
4117
4120
|
rules: {
|
|
4118
4121
|
"image-alt": image_alt_default,
|
|
@@ -1900,7 +1900,10 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
|
|
|
1900
1900
|
if (!ids.has(id)) {
|
|
1901
1901
|
ids.set(id, []);
|
|
1902
1902
|
}
|
|
1903
|
-
ids.get(id)
|
|
1903
|
+
const elements = ids.get(id);
|
|
1904
|
+
if (elements) {
|
|
1905
|
+
elements.push(el);
|
|
1906
|
+
}
|
|
1904
1907
|
}
|
|
1905
1908
|
}
|
|
1906
1909
|
for (const [id, elements] of ids.entries()) {
|
|
@@ -4130,7 +4133,7 @@ var form_validation_default = rule16;
|
|
|
4130
4133
|
var plugin = {
|
|
4131
4134
|
meta: {
|
|
4132
4135
|
name: "test-a11y-js",
|
|
4133
|
-
version: "0.8.
|
|
4136
|
+
version: "0.8.2"
|
|
4134
4137
|
},
|
|
4135
4138
|
rules: {
|
|
4136
4139
|
"image-alt": image_alt_default,
|
|
@@ -1882,7 +1882,10 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
|
|
|
1882
1882
|
if (!ids.has(id)) {
|
|
1883
1883
|
ids.set(id, []);
|
|
1884
1884
|
}
|
|
1885
|
-
ids.get(id)
|
|
1885
|
+
const elements = ids.get(id);
|
|
1886
|
+
if (elements) {
|
|
1887
|
+
elements.push(el);
|
|
1888
|
+
}
|
|
1886
1889
|
}
|
|
1887
1890
|
}
|
|
1888
1891
|
for (const [id, elements] of ids.entries()) {
|
|
@@ -4112,7 +4115,7 @@ var form_validation_default = rule16;
|
|
|
4112
4115
|
var plugin = {
|
|
4113
4116
|
meta: {
|
|
4114
4117
|
name: "test-a11y-js",
|
|
4115
|
-
version: "0.8.
|
|
4118
|
+
version: "0.8.2"
|
|
4116
4119
|
},
|
|
4117
4120
|
rules: {
|
|
4118
4121
|
"image-alt": image_alt_default,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "test-a11y-js",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "Zero-config accessibility testing for React, Vue & JSX. ESLint plugin + programmatic API. Catch a11y issues before production.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|