-
Notifications
You must be signed in to change notification settings - Fork 779
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Break up duplicate-id rule for ARIA+labels and active elements
- Loading branch information
1 parent
a18c770
commit 2ecfea7
Showing
24 changed files
with
388 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 1 addition & 4 deletions
5
...hecks/shared/duplicate-id-accessible.json → lib/checks/parsing/duplicate-id-active.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"id": "duplicate-id-aria", | ||
"evaluate": "duplicate-id.js", | ||
"after": "duplicate-id-after.js", | ||
"metadata": { | ||
"impact": "critical", | ||
"messages": { | ||
"pass": "Document has no elements that share the same id attribute", | ||
"fail": "Document has multiple elements with the same id attribute: {{=it.data}}" | ||
} | ||
} | ||
} |
11 changes: 3 additions & 8 deletions
11
lib/checks/shared/duplicate-id.js → lib/checks/parsing/duplicate-id.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
const { dom, aria } = axe.commons; | ||
const id = node.getAttribute('id').trim(); | ||
const idSelector = `*[id="${axe.utils.escapeSelector(id)}"]`; | ||
const idMatchingElms = Array.from( | ||
dom.getRootNode(node).querySelectorAll(idSelector) | ||
); | ||
|
||
return idMatchingElms.some(dom.isFocusable) && !aria.isAccessibleRef(node); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"id": "duplicate-id-active", | ||
"selector": "[id]", | ||
"matches": "duplicate-id-active-matches.js", | ||
"excludeHidden": false, | ||
"tags": [ | ||
"cat.parsing", | ||
"wcag2a", | ||
"wcag411" | ||
], | ||
"metadata": { | ||
"description": "Ensures every id attribute value is unique", | ||
"help": "IDs of active elements must be unique" | ||
}, | ||
"all": [ | ||
"duplicate-id-active" | ||
], | ||
"any": [], | ||
"none": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
return axe.commons.aria.isAccessibleRef(node); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"id": "duplicate-id-aria", | ||
"selector": "[id]", | ||
"matches": "duplicate-id-aria-matches.js", | ||
"excludeHidden": false, | ||
"tags": [ | ||
"cat.parsing", | ||
"wcag2a", | ||
"wcag411" | ||
], | ||
"metadata": { | ||
"description": "Ensures every id attribute value used in ARIA and in labels is unique", | ||
"help": "IDs used in ARIA and labels must be unique" | ||
}, | ||
"all": [ | ||
"duplicate-id-aria" | ||
], | ||
"any": [], | ||
"none": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const { dom, aria } = axe.commons; | ||
const id = node.getAttribute('id').trim(); | ||
const idSelector = `*[id="${axe.utils.escapeSelector(id)}"]`; | ||
const idMatchingElms = Array.from( | ||
dom.getRootNode(node).querySelectorAll(idSelector) | ||
); | ||
|
||
return ( | ||
idMatchingElms.every(elm => !dom.isFocusable(elm)) && | ||
!aria.isAccessibleRef(node) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
test/integration/rules/duplicate-id-active/duplicate-id-active.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<p id="ignore1">This is my first paragraph with this ID.</p> | ||
<div style="display:none"> | ||
<p id="ignore1">This is my second paragraph with this ID.</p> | ||
</div> | ||
|
||
<button id="fail1" class="fail1"></button> | ||
<button id="fail1"></button> | ||
|
||
<input id="pass1" /> | ||
<textarea id="pass2"></textarea> | ||
<select id="pass3"></select> | ||
<div tabindex="0" id="pass4"></div> | ||
|
||
<span id="ignored1"></span> | ||
<button id="ignored2"></button> | ||
<div aria-labelledby="ignored1 ignored2"></div> | ||
<input id="ignore3" type="hidden" /> | ||
<button id="ignore4" disabled></button> | ||
<button id="ignore5" style="display:none"></button> |
6 changes: 6 additions & 0 deletions
6
test/integration/rules/duplicate-id-active/duplicate-id-active.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"description": "duplicate-id-active test", | ||
"rule": "duplicate-id-active", | ||
"violations": [[".fail1"]], | ||
"passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"]] | ||
} |
19 changes: 19 additions & 0 deletions
19
test/integration/rules/duplicate-id-aria/duplicate-id-aria.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<p id="ignore1">This is my first paragraph with this ID.</p> | ||
<div style="display:none"> | ||
<p id="ignore1">This is my second paragraph with this ID.</p> | ||
</div> | ||
|
||
<input id="ignore2" /> | ||
<textarea id="ignore3"></textarea> | ||
<select id="ignore4"></select> | ||
<div tabindex="0" id="ignore5"></div> | ||
|
||
<span id="fail1" class="fail1"></span> | ||
<button id="fail1"></button> | ||
<span id="pass1"></span> | ||
<button id="pass2"></button> | ||
<div aria-labelledby="fail1 pass1 pass2"></div> | ||
|
||
<input id="ignore6" type="hidden" /> | ||
<button id="ignore7" disabled></button> | ||
<button id="ignore8" style="display:none"></button> |
6 changes: 6 additions & 0 deletions
6
test/integration/rules/duplicate-id-aria/duplicate-id-aria.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"description": "duplicate-id-aria test", | ||
"rule": "duplicate-id-aria", | ||
"violations": [[".fail1"]], | ||
"passes": [["#pass1"], ["#pass2"]] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,17 @@ | ||
<p id="dupe">This is my first paragraph with this ID.</p> | ||
<p id="fail1" class="fail1">This is my first paragraph with this ID.</p> | ||
<div style="display:none"> | ||
<p id="dupe">This is my second paragraph with this ID.</p> | ||
<p id="fail1">This is my second paragraph with this ID.</p> | ||
</div> | ||
<p id="single">This is my only paragraph with this ID.</p> | ||
|
||
<input id="ignored1" /> | ||
<textarea id="ignored2"></textarea> | ||
<select id="ignored3"></select> | ||
<div tabindex="0" id="ignored4"></div> | ||
|
||
<span id="ignored5"></span> | ||
<button id="ignored6"></button> | ||
<div aria-labelledby="ignored5 ignored6"></div> | ||
|
||
<input id="pass1" type="hidden" /> | ||
<button id="pass2" disabled></button> | ||
<button id="pass3" style="display:none"></button> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"description": "duplicate-id test", | ||
"rule": "duplicate-id", | ||
"violations": [["#fixture > p:nth-child(1)"]], | ||
"passes": [["#fixture"], ["#single"]] | ||
"violations": [[".fail1"]], | ||
"passes": [["#fixture"], ["#pass1"], ["#pass2"], ["#pass3"]] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
describe('duplicate-id-mismatches', function() { | ||
'use strict'; | ||
|
||
var fixture = document.getElementById('fixture'); | ||
var fixtureSetup = axe.testUtils.fixtureSetup; | ||
var rule; | ||
|
||
beforeEach(function() { | ||
rule = axe._audit.rules.find(function(rule) { | ||
return rule.id === 'duplicate-id-active'; | ||
}); | ||
}); | ||
|
||
afterEach(function() { | ||
fixture.innerHTML = ''; | ||
}); | ||
|
||
it('is a function', function() { | ||
assert.isFunction(rule.matches); | ||
}); | ||
|
||
it('returns false if the ID is of an inactive non-referenced element', function() { | ||
fixtureSetup('<div id="foo"></div>'); | ||
var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; | ||
assert.isFalse(rule.matches(vNode.actualNode, vNode)); | ||
}); | ||
|
||
it('returns false if the ID is of an inactive non-referenced element with a duplicate', function() { | ||
fixtureSetup('<div id="foo"></div><span id="foo"></span>'); | ||
var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; | ||
assert.isFalse(rule.matches(vNode.actualNode, vNode)); | ||
}); | ||
|
||
it('returns true if the ID is of an active non-referenced element', function() { | ||
fixtureSetup('<button id="foo"></button>'); | ||
var vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; | ||
assert.isTrue(rule.matches(vNode.actualNode, vNode)); | ||
}); | ||
|
||
it('returns true if the ID is a duplicate of an active non-referenced element', function() { | ||
fixtureSetup('<div id="foo"></div>' + '<button id="foo"></button>'); | ||
var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; | ||
assert.isTrue(rule.matches(vNode.actualNode, vNode)); | ||
}); | ||
|
||
it('returns false if the ID is of an inactive ARIA referenced element', function() { | ||
fixtureSetup('<div id="foo"></div>' + '<div aria-labelledby="foo"></div>'); | ||
var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; | ||
assert.isFalse(rule.matches(vNode.actualNode, vNode)); | ||
}); | ||
|
||
it('returns false if the ID is a duplicate of an inactive ARIA referenced element', function() { | ||
fixtureSetup( | ||
'<div id="foo"></div>' + | ||
'<div aria-labelledby="foo"></div>' + | ||
'<span id="foo"></span>' | ||
); | ||
var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; | ||
assert.isFalse(rule.matches(vNode.actualNode, vNode)); | ||
}); | ||
|
||
it('returns false if the ID is of an active ARIA referenced element', function() { | ||
fixtureSetup( | ||
'<button id="foo"></button>' + '<div aria-labelledby="foo"></div>' | ||
); | ||
var vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; | ||
assert.isFalse(rule.matches(vNode.actualNode, vNode)); | ||
}); | ||
|
||
it('returns false if the ID is a duplicate of of an active ARIA referenced element', function() { | ||
fixtureSetup( | ||
'<button id="foo"></button>' + | ||
'<div aria-labelledby="foo"></div>' + | ||
'<span id="foo"></span>' | ||
); | ||
var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; | ||
assert.isFalse(rule.matches(vNode.actualNode, vNode)); | ||
}); | ||
}); |
Oops, something went wrong.