-
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.
fix(nested-interactive): add message for negative tabindex (#3194)
* refactor(checks/navigation): improve `internal-link-present-evaluate` Make `internal-link-present-evaluate` work with virtualNode rather than actualNode. Closes issue #2466 * test commit 1 * test commit 2 * test commit 3 * Revert "Merge branch 'dan-test-branch-1' into develop" This reverts commit 428e015, reversing changes made to 9f996bc. * Revert "test commit 1" This reverts commit 9f996bc. * fix(rule): allow "tabindex=-1" for rules "aria-text" and "nested-interactive" Closes issue #2934 * Revert "fix(rule): allow "tabindex=-1" for rules "aria-text" and "nested-interactive"" This reverts commit 30f0e01. * refactor(check): split no-focusable-content rule into three. That rule is now: no-focusable-content-for-aria-text, no-focusable-content-for-nested-interactive, and no-focusable-content-for-frame These three are all copy-and-pastes of each other, so far. * fix(rule): add custom message for nested-interactive. aria-hidden and negative tabindex will trigger messageKey. * style(rule): fix lint errors Errors were in parent commit. * fix(no-focusable-content-for-frame): fix locale files Was broken by recent rename of this check. * refactor(check): undo recent check rename Rename check "no-focusable-content-for-frame" back to "frame-focusable-content". * refactor(check): undo recent split of checks Recombine checks "no-focusable-content-for-aria-text" and "no-focusable-content-for-nested-interactive" back into "no-focusable-content". * refactor(check): rename local variable * fix(rule): make no-focusable-content not consult aria-hidden no-focusable content now consults only tabindex (for the 'not a reliable way of hiding interactive elements' messageKey check) * fix(checks/keyboard): make no-focusable-content use messageKey the right way * refactor(check): misc. renaming and refactoring * Updating description / messageKey text as per #3163 (comment) * add unit test for frame-focusable-content check * update the no-focusable-content unit tests to add a test to capture negative tabindex * update the nested-interactive integration test to add a failure for elements with negative tabindex values * fix(no-focusable-content-for-frame): fix locale files Was broken by recent rename of this check. * Update lib/rules/nested-interactive.json Co-authored-by: Steven Lambert <2433219+straker@users.noreply.github.com> * Update lib/checks/keyboard/no-focusable-content.json Co-authored-by: Steven Lambert <2433219+straker@users.noreply.github.com> * fixing botched merge * update rule-descriptions.md * fix locale files Co-authored-by: Steven Lambert <2433219+straker@users.noreply.github.com>
- Loading branch information
Showing
11 changed files
with
193 additions
and
75 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
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,35 @@ | ||
import isFocusable from '../../commons/dom/is-focusable'; | ||
|
||
function focusableDescendants(vNode) { | ||
if (isFocusable(vNode)) { | ||
return true; | ||
} | ||
|
||
if (!vNode.children) { | ||
if (vNode.props.nodeType === 1) { | ||
throw new Error('Cannot determine children'); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
return vNode.children.some(child => { | ||
return focusableDescendants(child); | ||
}); | ||
} | ||
|
||
function frameFocusableContentEvaluate(node, options, virtualNode) { | ||
if (!virtualNode.children) { | ||
return undefined; | ||
} | ||
|
||
try { | ||
return !virtualNode.children.some(child => { | ||
return focusableDescendants(child); | ||
}); | ||
} catch (e) { | ||
return undefined; | ||
} | ||
} | ||
|
||
export default frameFocusableContentEvaluate; |
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 |
---|---|---|
@@ -1,35 +1,47 @@ | ||
import isFocusable from '../../commons/dom/is-focusable'; | ||
|
||
function focusableDescendants(vNode) { | ||
if (isFocusable(vNode)) { | ||
return true; | ||
} | ||
|
||
function getFocusableDescendants(vNode) { | ||
if (!vNode.children) { | ||
if (vNode.props.nodeType === 1) { | ||
throw new Error('Cannot determine children'); | ||
} | ||
|
||
return false; | ||
return []; | ||
} | ||
|
||
return vNode.children.some(child => { | ||
return focusableDescendants(child); | ||
const retVal = []; | ||
vNode.children.forEach(child => { | ||
if(isFocusable(child)) { | ||
retVal.push(child); | ||
} else { | ||
retVal.push(...getFocusableDescendants(child)); | ||
} | ||
}); | ||
return retVal; | ||
} | ||
|
||
function noFocusbleContentEvaluate(node, options, virtualNode) { | ||
function usesUnreliableHidingStrategy(vNode) { | ||
const tabIndex = parseInt(vNode.attr('tabindex'), 10); | ||
return !isNaN(tabIndex) && tabIndex < 0; | ||
} | ||
|
||
function noFocusableContentEvaluate(node, options, virtualNode) { | ||
if (!virtualNode.children) { | ||
return undefined; | ||
} | ||
|
||
try { | ||
return !virtualNode.children.some(child => { | ||
return focusableDescendants(child); | ||
}); | ||
const focusableDescendants = getFocusableDescendants(virtualNode); | ||
if(focusableDescendants.length > 0) { | ||
const notHiddenElements = focusableDescendants.filter(usesUnreliableHidingStrategy); | ||
if(notHiddenElements.length > 0) { | ||
this.data({ messageKey: 'notHidden' }); | ||
this.relatedNodes(notHiddenElements); | ||
} | ||
} | ||
return focusableDescendants.length === 0; | ||
} catch (e) { | ||
return undefined; | ||
} | ||
} | ||
|
||
export default noFocusbleContentEvaluate; | ||
export default noFocusableContentEvaluate; |
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,41 @@ | ||
describe('frame-focusable-content tests', function() { | ||
var fixture = document.querySelector('#fixture'); | ||
var queryFixture = axe.testUtils.queryFixture; | ||
var frameFocusableContent = axe.testUtils.getCheckEvaluate( | ||
'frame-focusable-content' | ||
); | ||
|
||
afterEach(function() { | ||
fixture.innerHTML = ''; | ||
}); | ||
|
||
it('should return true if element has no focusable content', function() { | ||
var vNode = queryFixture('<button id="target"><span>Hello</span></button>'); | ||
assert.isTrue(frameFocusableContent(null, null, vNode)); | ||
}); | ||
|
||
it('should return true if element is empty', function() { | ||
var vNode = queryFixture('<button id="target"></button>'); | ||
assert.isTrue(frameFocusableContent(null, null, vNode)); | ||
}); | ||
|
||
it('should return true if element only has text content', function() { | ||
var vNode = queryFixture('<button id="target">Hello</button>'); | ||
assert.isTrue(frameFocusableContent(null, null, vNode)); | ||
}); | ||
|
||
it('should return false if element has focusable content', function() { | ||
var vNode = queryFixture( | ||
'<button id="target"><span tabindex="0">Hello</span></button>' | ||
); | ||
assert.isFalse(frameFocusableContent(null, null, vNode)); | ||
}); | ||
|
||
it('should return false if element has natively focusable content', function() { | ||
var vNode = queryFixture( | ||
'<button id="target"><a href="foo.html">Hello</a></button>' | ||
); | ||
assert.isFalse(frameFocusableContent(null, null, vNode)); | ||
}); | ||
|
||
}); |
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
13 changes: 11 additions & 2 deletions
13
test/integration/rules/nested-interactive/nested-interactive.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 |
---|---|---|
@@ -1,13 +1,22 @@ | ||
{ | ||
"description": "nested-interactive tests", | ||
"rule": "nested-interactive", | ||
"violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"], ["#fail5"]], | ||
"violations": [ | ||
["#fail1"], | ||
["#fail2"], | ||
["#fail3"], | ||
["#fail4"], | ||
["#fail5"], | ||
["#fail6"], | ||
["#fail7"] | ||
], | ||
"passes": [ | ||
["#pass1"], | ||
["#pass2"], | ||
["#pass3"], | ||
["#pass4"], | ||
["#pass5"], | ||
["#pass6"] | ||
["#pass6"], | ||
["#pass7"] | ||
] | ||
} |