diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index dce2b75c1a..390d0dd097 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -17,6 +17,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 | wcag2a, wcag412 | 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 | | [aria-required-parent](https://dequeuniversity.com/rules/axe/4.0/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | diff --git a/lib/rules/aria-progressbar-name.json b/lib/rules/aria-progressbar-name.json new file mode 100644 index 0000000000..1f889fdaae --- /dev/null +++ b/lib/rules/aria-progressbar-name.json @@ -0,0 +1,13 @@ +{ + "id": "aria-progressbar-name", + "selector": "[role=\"progressbar\"]", + "matches": "aria-form-field-name-matches", + "tags": ["cat.aria", "wcag2a", "wcag111"], + "metadata": { + "description": "Ensures every ARIA progressbar node has an accessible name", + "help": "ARIA progressbar nodes must have an accessible name" + }, + "all": [], + "any": ["aria-label", "aria-labelledby", "non-empty-title"], + "none": [] +} diff --git a/test/integration/rules/aria-progressbar-name/aria-progressbar-name.html b/test/integration/rules/aria-progressbar-name/aria-progressbar-name.html new file mode 100644 index 0000000000..ac9b08590b --- /dev/null +++ b/test/integration/rules/aria-progressbar-name/aria-progressbar-name.html @@ -0,0 +1,26 @@ + +
+
+
+ +
loading, please wait
+ + +
loading, please wait
+
+
+
+ +
+ + +Label + + + + + diff --git a/test/integration/rules/aria-progressbar-name/aria-progressbar-name.json b/test/integration/rules/aria-progressbar-name/aria-progressbar-name.json new file mode 100644 index 0000000000..098bb7b477 --- /dev/null +++ b/test/integration/rules/aria-progressbar-name/aria-progressbar-name.json @@ -0,0 +1,6 @@ +{ + "description": "aria-progressbar-name test", + "rule": "aria-progressbar-name", + "passes": [["#pass1"], ["#pass2"], ["#pass3"]], + "violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"]] +} diff --git a/test/integration/virtual-rules/aria-progressbar-name.js b/test/integration/virtual-rules/aria-progressbar-name.js new file mode 100644 index 0000000000..3ae7e2a8f7 --- /dev/null +++ b/test/integration/virtual-rules/aria-progressbar-name.js @@ -0,0 +1,89 @@ +describe('aria-progressbar-name', function() { + it('should pass for aria-label', function() { + var node = new axe.SerialVirtualNode({ + nodeName: 'div', + attributes: { + role: 'progressbar', + 'aria-label': 'foobar' + } + }); + node.parent = null; + + var results = axe.runVirtualRule('aria-progressbar-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: 'progressbar', + 'aria-labelledby': 'foobar' + } + }); + node.parent = null; + + var results = axe.runVirtualRule('aria-progressbar-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: 'progressbar', + 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-progressbar-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: 'progressbar', + 'aria-label': ' \t \n ' + } + }); + node.children = []; + + var results = axe.runVirtualRule('aria-progressbar-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: 'progressbar', + title: '' + } + }); + node.children = []; + + var results = axe.runVirtualRule('aria-progressbar-name', node); + + assert.lengthOf(results.passes, 0); + assert.lengthOf(results.violations, 1); + assert.lengthOf(results.incomplete, 0); + }); +});