From 3ca2f04b0f737914dda667c26f0193b7b312e6f6 Mon Sep 17 00:00:00 2001 From: Wilco Fiers Date: Thu, 29 Oct 2020 19:21:17 +0100 Subject: [PATCH] feat(new-rule): check that meter role has an accessible name (#2607) --- doc/rule-descriptions.md | 1 + lib/rules/aria-meter-name.json | 13 +++ .../aria-meter-name/aria-meter-name.html | 26 ++++++ .../aria-meter-name/aria-meter-name.json | 6 ++ .../virtual-rules/aria-meter-name.js | 89 +++++++++++++++++++ 5 files changed, 135 insertions(+) create mode 100644 lib/rules/aria-meter-name.json create mode 100644 test/integration/rules/aria-meter-name/aria-meter-name.html create mode 100644 test/integration/rules/aria-meter-name/aria-meter-name.json create mode 100644 test/integration/virtual-rules/aria-meter-name.js diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 21183a37f7..35682376dc 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -18,6 +18,7 @@ | [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.0/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | | [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.0/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | | [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.0/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.0/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.0/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | [aria-required-attr](https://dequeuniversity.com/rules/axe/4.0/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | | [aria-required-children](https://dequeuniversity.com/rules/axe/4.0/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | diff --git a/lib/rules/aria-meter-name.json b/lib/rules/aria-meter-name.json new file mode 100644 index 0000000000..813cbb6427 --- /dev/null +++ b/lib/rules/aria-meter-name.json @@ -0,0 +1,13 @@ +{ + "id": "aria-meter-name", + "selector": "[role=\"meter\"]", + "matches": "no-naming-method-matches", + "tags": ["cat.aria", "wcag2a", "wcag111"], + "metadata": { + "description": "Ensures every ARIA meter node has an accessible name", + "help": "ARIA meter nodes must have an accessible name" + }, + "all": [], + "any": ["aria-label", "aria-labelledby", "non-empty-title"], + "none": [] +} diff --git a/test/integration/rules/aria-meter-name/aria-meter-name.html b/test/integration/rules/aria-meter-name/aria-meter-name.html new file mode 100644 index 0000000000..b9f56f3730 --- /dev/null +++ b/test/integration/rules/aria-meter-name/aria-meter-name.html @@ -0,0 +1,26 @@ + +
+
+
+ +
CPU usage
+ + +
CPU usage
+
+
+
+ +
+ + +Label + + + + + diff --git a/test/integration/rules/aria-meter-name/aria-meter-name.json b/test/integration/rules/aria-meter-name/aria-meter-name.json new file mode 100644 index 0000000000..728af9f40c --- /dev/null +++ b/test/integration/rules/aria-meter-name/aria-meter-name.json @@ -0,0 +1,6 @@ +{ + "description": "aria-meter-name test", + "rule": "aria-meter-name", + "passes": [["#pass1"], ["#pass2"], ["#pass3"]], + "violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"]] +} diff --git a/test/integration/virtual-rules/aria-meter-name.js b/test/integration/virtual-rules/aria-meter-name.js new file mode 100644 index 0000000000..cae97666bf --- /dev/null +++ b/test/integration/virtual-rules/aria-meter-name.js @@ -0,0 +1,89 @@ +describe('aria-meter-name', function() { + it('should pass for aria-label', function() { + var node = new axe.SerialVirtualNode({ + nodeName: 'div', + attributes: { + role: 'meter', + 'aria-label': 'foobar' + } + }); + node.parent = null; + + var results = axe.runVirtualRule('aria-meter-name', node); + + assert.lengthOf(results.passes, 1); + assert.lengthOf(results.violations, 0); + assert.lengthOf(results.incomplete, 0); + }); + + it('should incomplete for aria-labelledby', function() { + var node = new axe.SerialVirtualNode({ + nodeName: 'div', + attributes: { + role: 'meter', + 'aria-labelledby': 'foobar' + } + }); + node.parent = null; + + var results = axe.runVirtualRule('aria-meter-name', node); + + assert.lengthOf(results.passes, 0); + assert.lengthOf(results.violations, 0); + assert.lengthOf(results.incomplete, 1); + }); + + it('should pass for title', function() { + var node = new axe.SerialVirtualNode({ + nodeName: 'div', + attributes: { + role: 'meter', + title: 'foobar' + } + }); + // children are required since titleText comes after subtree text + // in accessible name calculation + node.children = []; + node.parent = null; + + var results = axe.runVirtualRule('aria-meter-name', node); + + assert.lengthOf(results.passes, 1); + assert.lengthOf(results.violations, 0); + assert.lengthOf(results.incomplete, 0); + }); + + it('should fail when aria-label contains only whitespace', function() { + var node = new axe.SerialVirtualNode({ + nodeName: 'div', + attributes: { + role: 'meter', + 'aria-label': ' \t \n ' + } + }); + node.children = []; + + var results = axe.runVirtualRule('aria-meter-name', node); + + assert.lengthOf(results.passes, 0); + assert.lengthOf(results.violations, 1); + assert.lengthOf(results.incomplete, 0); + }); + + it('should fail when title is empty', function() { + var node = new axe.SerialVirtualNode({ + nodeName: 'div', + attributes: { + role: 'meter', + title: '' + } + }); + node.children = []; + + var results = axe.runVirtualRule('aria-meter-name', node); + + assert.lengthOf(results.passes, 0); + assert.lengthOf(results.violations, 1); + assert.lengthOf(results.incomplete, 0); + }); +});