Skip to content

Commit

Permalink
Add new rule no-invalid-aria-attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
judithhinlung committed Dec 13, 2021
1 parent 4d7ea0b commit 5bd7274
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ Each rule has emojis denoting:
| [no-inline-styles](./docs/rule/no-inline-styles.md) || | | |
| [no-input-block](./docs/rule/no-input-block.md) || | | |
| [no-input-tagname](./docs/rule/no-input-tagname.md) || | | |
| [no-invalid-aria-attributes](./docs/rule/no-invalid-aria-attributes.md) | | | ⌨️ | |
| [no-invalid-block-param-definition](./docs/rule/no-invalid-block-param-definition.md) || | | |
| [no-invalid-interactive](./docs/rule/no-invalid-interactive.md) || | ⌨️ | |
| [no-invalid-link-text](./docs/rule/no-invalid-link-text.md) || | ⌨️ | |
Expand Down
23 changes: 23 additions & 0 deletions docs/rule/no-invalid-aria-attributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# no-invalid-aria-attributes

This rule checks for the use of invalid ARIA attributes, or any aria-\* property on an element that is not included in the [WAI-ARIA States and Properties spec](https://www.w3.org/WAI/PF/aria-1.1/states_and_properties).

## Examples

This rule **forbids** the following:

```hbs
<input type="text" aria-require="true" />
```

This rule **allows** the following:

```hbs
<input type="text" aria-required="true" />
```

## References

- [Using ARIA, Roles, States, and Properties](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques)

- TODO: link to relevant guide goes here
1 change: 1 addition & 0 deletions lib/config/a11y.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
'no-duplicate-landmark-elements': 'error',
'no-empty-headings': 'error',
'no-heading-inside-button': 'error',
'no-invalid-aria-attributes': 'error',
'no-invalid-interactive': 'error',
'no-invalid-link-text': 'error',
'no-invalid-link-title': 'error',
Expand Down
89 changes: 89 additions & 0 deletions lib/rules/no-invalid-aria-attributes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
'use strict';

const Rule = require('./_base');

const VALID_ARIA_ATTRIBUTES = new Set([
'aria-activedescendant',
'aria-atomic',
'aria-autocomplete',
'aria-busy',
'aria-checked',
'aria-colcount',
'aria-colindex',
'aria-colspan',
'aria-controls',
'aria-current',
'aria-describedby',
'aria-details',
'aria-disabled',
'aria-dragged',
'aria-dropeffect',
'aria-errormessage',
'aria-expanded',
'aria-flowto',
'aria-haspopup',
'aria-hidden',
'aria-invalid',
'aria-label',
'aria-labelledby',
'aria-level',
'aria-live',
'aria-modal',
'aria-multiline',
'aria-multiselectable',
'aria-orientation',
'aria-owns',
'aria-placeholder',
'aria-posinset',
'aria-pressed',
'aria-readonly',
'aria-relevant',
'aria-required',
'aria-rowcount',
'aria-rowindex',
'aria-rowspan',
'aria-selected',
'aria-setsize',
'aria-sort',
'aria-valuemax',
'aria-valuemin',
'aria-valuenow',
'aria-valuetext',
]);

function getAriaAttributes(node) {
let attributes = node.attributes;
let ariaAttributes = [];
for (let attribute of attributes) {
if (attribute.name.startsWith('aria-')) {
ariaAttributes.push(attribute);
}
}
return ariaAttributes;
}

module.exports = class NoInvalidAriaAttributes extends Rule {
logNode({ node, message }) {
return this.log({
message,
node,
});
}
visitor() {
return {
ElementNode(node) {
const ariaAttributes = getAriaAttributes(node);
if (ariaAttributes.length > 0) {
for (let attribute of ariaAttributes) {
if (!VALID_ARIA_ATTRIBUTES.has(attribute.name)) {
this.logNode({
message: `${attribute.name} is not a valid ARIA attribute.`,
node,
});
}
}
}
},
};
}
};
102 changes: 102 additions & 0 deletions test/unit/rules/no-invalid-aria-attributes-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
'use strict';

const generateRuleTests = require('../../helpers/rule-test-harness');

generateRuleTests({
name: 'no-invalid-aria-attributes',

config: true,

good: [
'<h1 aria-hidden="true">Valid Heading</h1>',
'<input type="email" aria-required="true" />',
'<div role="slider" aria-valuenow={{this.foo}} aria-valuemax={{this.bar}} aria-valuemin={{this.baz}} />',
'<div role="region" aria-live="polite">Valid live region</div>',
'<CustomComponent @ariaRequired={{this.ariaRequired}} aria-errormessage="errorId" />',
],

bad: [
{
template: '<input aria-text="inaccessible text" />',
verifyResults(results) {
expect(results).toMatchInlineSnapshot(`
Array [
Object {
"column": 0,
"endColumn": 39,
"endLine": 1,
"filePath": "layout.hbs",
"line": 1,
"message": "aria-text is not a valid ARIA attribute.",
"rule": "no-invalid-aria-attributes",
"severity": 2,
"source": "<input aria-text=\\"inaccessible text\\" />",
},
]
`);
},
},
{
template:
'<div role="slider" aria-valuenow={{this.foo}} aria-valuemax={{this.bar}} aria-value-min={{this.baz}} />',
verifyResults(results) {
expect(results).toMatchInlineSnapshot(`
Array [
Object {
"column": 0,
"endColumn": 103,
"endLine": 1,
"filePath": "layout.hbs",
"line": 1,
"message": "aria-value-min is not a valid ARIA attribute.",
"rule": "no-invalid-aria-attributes",
"severity": 2,
"source": "<div role=\\"slider\\" aria-valuenow={{this.foo}} aria-valuemax={{this.bar}} aria-value-min={{this.baz}} />",
},
]
`);
},
},
{
template: '<h1 aria--hidden="true">Broken heading</h1>',
verifyResults(results) {
expect(results).toMatchInlineSnapshot(`
Array [
Object {
"column": 0,
"endColumn": 43,
"endLine": 1,
"filePath": "layout.hbs",
"line": 1,
"message": "aria--hidden is not a valid ARIA attribute.",
"rule": "no-invalid-aria-attributes",
"severity": 2,
"source": "<h1 aria--hidden=\\"true\\">Broken heading</h1>",
},
]
`);
},
},

{
template: '<CustomComponent role="region" aria-alert="polite" />',
verifyResults(results) {
expect(results).toMatchInlineSnapshot(`
Array [
Object {
"column": 0,
"endColumn": 53,
"endLine": 1,
"filePath": "layout.hbs",
"line": 1,
"message": "aria-alert is not a valid ARIA attribute.",
"rule": "no-invalid-aria-attributes",
"severity": 2,
"source": "<CustomComponent role=\\"region\\" aria-alert=\\"polite\\" />",
},
]
`);
},
},
],
});

0 comments on commit 5bd7274

Please sign in to comment.