Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

work in progress #5

Merged
merged 1 commit into from
Nov 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/checks/keyboard/no-focusable-content-evaluate.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import isFocusable from '../../commons/dom/is-focusable';
import { getRole, getRoleType } from '../../commons/aria';

export default function noFocusableContentEvaluate(node, options, virtualNode) {
if (!virtualNode.children) {
Expand Down Expand Up @@ -40,7 +41,8 @@ function getFocusableDescendants(vNode) {

const retVal = [];
vNode.children.forEach(child => {
if (isFocusable(child)) {
const role = getRole(child);
if(getRoleType(role) === 'widget' && isFocusable(child)) {
retVal.push(child);
} else {
retVal.push(...getFocusableDescendants(child));
Expand Down
34 changes: 23 additions & 11 deletions test/checks/keyboard/no-focusable-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,22 @@ describe('no-focusable-content tests', function() {
assert.isTrue(noFocusableContent(null, null, vNode));
});

it('should return false if element has focusable content', function() {
it('should return true if element has content which is focusable (tabindex=0) and does not have a widget role', function() {
var params = checkSetup(
'<button id="target"><span tabindex="0">Hello</span></button>'
);

assert.isFalse(noFocusableContent.apply(checkContext, params));
assert.deepEqual(checkContext._data, null);
assert.deepEqual(checkContext._relatedNodes, [params[2].children[0]]);
assert.isTrue(noFocusableContent.apply(checkContext, params));
});

it('should return true if element has content which has negative tabindex and non-widget role', function() {
var vNode = queryFixture(
'<button id="target"><span tabindex="-1">Hello</span></button>'
);
assert.isTrue(noFocusableContent(null, null, vNode));
});

it('should return false if element has natively focusable content', function() {
it('should return false if element has content which is natively focusable and has a widget role', function() {
var params = checkSetup(
'<button id="target"><a href="foo.html">Hello</a></button>'
);
Expand All @@ -50,7 +55,7 @@ describe('no-focusable-content tests', function() {

it('should add each focusable child as related nodes', function() {
var params = checkSetup(
'<button id="target"><span tabindex="0">Hello</span><a href="foo.html">Hello</a></button>'
'<button id="target"><input type="checkbox"><a href="foo.html">Hello</a></button>'
);

assert.isFalse(noFocusableContent.apply(checkContext, params));
Expand All @@ -61,7 +66,7 @@ describe('no-focusable-content tests', function() {
]);
});

it('should return false if element has natively focusable content with negative tabindex', function() {
it('should return false if element has natively focusable widget role content with negative tabindex', function() {
var params = checkSetup(
'<button id="target"><a href="foo.html" tabindex="-1">Hello</a></button>'
);
Expand All @@ -71,25 +76,32 @@ describe('no-focusable-content tests', function() {
assert.deepEqual(checkContext._relatedNodes, [params[2].children[0]]);
});

it('should return true on span with tabindex=-1', function() {
it('should return true if element has content which is natively focusable and has a widget role but is disabled', function() {
var vNode = queryFixture(
'<button id="target"><a href="foo.html" disabled>Hello</a></button>'
);
assert.isTrue(noFocusableContent(null, null, vNode));
});

it('should return true on span with negative tabindex (focusable, does not have a widget role)', function() {
var vNode = queryFixture('<span id="target" role="text"> some text '
+'<span tabIndex="-1">JavaScript is able to focus this</span> '
+'</span>');
assert.isTrue(noFocusableContent(null, null, vNode));
});

it('should return true on aria-hidden span with tabindex=-1', function() {
it('should return true on aria-hidden span with negative tabindex (focusable, does not have a widget role)', function() {
var vNode = queryFixture('<span id="target" role="text"> some text '
+'<span tabIndex="-1" aria-hidden="true">JavaScript is able to focus this</span> '
+'</span>');
assert.isTrue(noFocusableContent(null, null, vNode));
});

it('should return false on span with tabindex=0', function() {
it('should return true on nested span with tabindex=0 (focusable, does not have a widget role)', function() {
var vNode = queryFixture('<span id="target" role="text"> some text '
+'<span tabIndex="0">anyone is able to focus this</span> '
+'</span>');
assert.isFalse(noFocusableContent(null, null, vNode));
assert.isTrue(noFocusableContent(null, null, vNode));
});

});
14 changes: 11 additions & 3 deletions test/integration/rules/aria-text/aria-text.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,16 @@ <h1>
<div role="text" id="fail2">
<a href="#" role="none">Flattened text</a> because of the explicit role.
</div>
<div role="text" id="pass4">
<div role="text" id="fail3">
<a href="#" tabindex="-1" role="none">Flattened text</a> because of the
explicit role. Considered non-focusable because of tabindex=-1...
explicit role.
</div>
<p role="text" id="fail4"><button>Hello</button></p>
<p role="text" id="fail5"><button tabindex="-1">Hello</button></p>
<p role="text" id="pass4"><span tabindex="-1">Hello</span></p>
<div role="text" id="pass5">
<a tabindex="-1">passes because no href makes this not have the implicit role of 'link'</a>
</div>
<div role="text" id="pass6">
<a>passes because no href makes this not have the implicit role of 'link'</a>
</div>
<p role="text" id="fail3"><button>Hello</button></p>
4 changes: 2 additions & 2 deletions test/integration/rules/aria-text/aria-text.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"description": "aria-text tests",
"rule": "aria-text",
"violations": [["#fail1"], ["#fail2"], ["#fail3"]],
"passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"]]
"violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"], ["#fail5"]],
"passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"], ["#pass5"], ["#pass6"]]
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
<div role="radio" id="pass6"><span>pass</span></div>
<div role="radio" id="pass7"><span tabindex="-1">pass</span></div>

<button id="fail1"><span tabindex="0">fail</span></button>
<div role="button" id="fail2"><input /></div>
<div role="tab" id="fail3"><button id="pass8">div fails, button passes</button></div>
<div role="checkbox" id="fail4"><a href="foo.html">fail</a></div>
<div role="radio" id="fail5"><span tabindex="0">fail</span></div>
<div role="radio" id="fail6"><button id="pass7" tabindex="-1">not really hidden</button></div>
<div role="radio" id="fail7"><button aria-hidden="true" tabindex="-1">not really hidden</button></div>
<button id="pass8"><span tabindex="0">pass</span></button>
<div role="button" id="fail1"><input /></div>
<div role="tab" id="fail2"><button id="pass9">div fails, button passes</button></div>
<div role="checkbox" id="fail3"><a href="foo.html">fail</a></div>
<div role="radio" id="pass10"><span tabindex="0">pass</span></div>
<div role="radio" id="fail4"><button id="pass11" tabindex="-1">not really hidden</button></div>
<div role="radio" id="fail5"><button aria-hidden="true" tabindex="-1">not really hidden</button></div>

<a id="ignored1" href="foo.html">ignored</a>
<span id="ignored2">ignored</span>
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
["#fail2"],
["#fail3"],
["#fail4"],
["#fail5"],
["#fail6"],
["#fail7"]
["#fail5"]
],
"passes": [
["#pass1"],
Expand All @@ -18,6 +16,9 @@
["#pass5"],
["#pass6"],
["#pass7"],
["#pass8"]
["#pass8"],
["#pass9"],
["#pass10"],
["#pass11"]
]
}
8 changes: 4 additions & 4 deletions test/integration/virtual-rules/nested-interactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('nested-interactive virtual-rule', function() {
assert.lengthOf(results.incomplete, 0);
});

it('should fail for element with focusable content', function() {
it('should pass for element with non-widget content', function() {
var node = new axe.SerialVirtualNode({
nodeName: 'button'
});
Expand All @@ -89,12 +89,12 @@ describe('nested-interactive virtual-rule', function() {

var results = axe.runVirtualRule('nested-interactive', node);

assert.lengthOf(results.passes, 0);
assert.lengthOf(results.violations, 1);
assert.lengthOf(results.passes, 1);
assert.lengthOf(results.violations, 0);
assert.lengthOf(results.incomplete, 0);
});

it('should fail for element with natively focusable content', function() {
it('should fail for element with native widget content', function() {
var node = new axe.SerialVirtualNode({
nodeName: 'div',
attributes: {
Expand Down