Skip to content

Commit

Permalink
fix(form-field-multiple-label): incomplete rather than fail for multi…
Browse files Browse the repository at this point in the history
…ple labels (#1798)

* fix(form-field-multiple-label): multiple labels will not fail but instead incomplete

* add incomplete message
  • Loading branch information
straker authored Sep 5, 2019
1 parent 2664bae commit 0bdaa2b
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 52 deletions.
4 changes: 2 additions & 2 deletions lib/checks/label/multiple-label.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ if (labels.length > 1) {
);
// more than 1 AT visible label will fail IOS/Safari/VO even with aria-labelledby
if (ATVisibleLabels.length > 1) {
return true;
return undefined;
}
// make sure the ONE AT visible label is in the list of idRefs of aria-labelledby
const labelledby = axe.commons.dom.idrefs(node, 'aria-labelledby');
return !labelledby.includes(ATVisibleLabels[0]);
return !labelledby.includes(ATVisibleLabels[0]) ? undefined : false;
}

// only 1 CSS visible label
Expand Down
2 changes: 1 addition & 1 deletion lib/checks/label/multiple-label.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"impact": "moderate",
"messages": {
"pass": "Form field does not have multiple label elements",
"fail": "Multiple label elements is not widely supported in assistive technologies"
"incomplete": "Multiple label elements is not widely supported in assistive technologies. Ensure the first label contains all necessary information."
}
}
}
2 changes: 1 addition & 1 deletion lib/rules/form-field-multiple-labels.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"tags": ["cat.forms", "wcag2a", "wcag332"],
"metadata": {
"description": "Ensures form field does not have multiple label elements",
"help": "Form field must not have multiple label elements"
"help": "Form field should not have multiple label elements"
},
"all": [],
"any": [],
Expand Down
52 changes: 34 additions & 18 deletions test/checks/label/multiple-label.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ describe('multiple-label', function() {
checkContext.reset();
});

it('should return true if there are multiple implicit labels', function() {
it('should return undefined if there are multiple implicit labels', function() {
fixture.innerHTML =
'<label id="l2"><label id="l1"><input type="text" id="target"></label></label>';
var target = fixture.querySelector('#target');
var l1 = fixture.querySelector('#l1');
var l2 = fixture.querySelector('#l2');
assert.isTrue(checks['multiple-label'].evaluate.call(checkContext, target));
assert.isUndefined(
checks['multiple-label'].evaluate.call(checkContext, target)
);
assert.deepEqual(checkContext._relatedNodes, [l1, l2]);
});

Expand All @@ -31,7 +33,7 @@ describe('multiple-label', function() {
assert.deepEqual(checkContext._relatedNodes, [l1]);
});

it('should return true if there are multiple explicit labels', function() {
it('should return undefined if there are multiple explicit labels', function() {
fixture.innerHTML =
'<label id="l1" for="target">Foo</label>' +
'<label id="l2" for="target">Bar</label>' +
Expand All @@ -41,7 +43,9 @@ describe('multiple-label', function() {
var l1 = fixture.querySelector('#l1');
var l2 = fixture.querySelector('#l2');
var l3 = fixture.querySelector('#l3');
assert.isTrue(checks['multiple-label'].evaluate.call(checkContext, target));
assert.isUndefined(
checks['multiple-label'].evaluate.call(checkContext, target)
);
assert.deepEqual(checkContext._relatedNodes, [l1, l2, l3]);
});

Expand Down Expand Up @@ -69,7 +73,7 @@ describe('multiple-label', function() {
assert.deepEqual(checkContext._relatedNodes, [l1]);
});

it('should return true if there are multiple explicit labels but some are hidden', function() {
it('should return undefined if there are multiple explicit labels but some are hidden', function() {
fixture.innerHTML =
'<label for="me" id="l1">visible</label>' +
'<label for="me" style="display:none;" id="l2">hidden</label>' +
Expand All @@ -78,17 +82,21 @@ describe('multiple-label', function() {
var target = fixture.querySelector('#me');
var l1 = fixture.querySelector('#l1');
var l3 = fixture.querySelector('#l3');
assert.isTrue(checks['multiple-label'].evaluate.call(checkContext, target));
assert.isUndefined(
checks['multiple-label'].evaluate.call(checkContext, target)
);
assert.deepEqual(checkContext._relatedNodes, [l1, l3]);
});

it('should return true if there are implicit and explicit labels', function() {
it('should return undefined if there are implicit and explicit labels', function() {
fixture.innerHTML =
'<label id="l1" for="target">Foo</label><label id="l2"><input type="text" id="target"></label>';
var target = fixture.querySelector('#target');
var l1 = fixture.querySelector('#l1');
var l2 = fixture.querySelector('#l2');
assert.isTrue(checks['multiple-label'].evaluate.call(checkContext, target));
assert.isUndefined(
checks['multiple-label'].evaluate.call(checkContext, target)
);
assert.deepEqual(checkContext._relatedNodes, [l1, l2]);
});

Expand All @@ -101,7 +109,7 @@ describe('multiple-label', function() {
);
});

it('should return true given multiple labels and no aria-labelledby', function() {
it('should return undefined given multiple labels and no aria-labelledby', function() {
fixture.innerHTML = '<input type="checkbox" id="A">';
fixture.innerHTML += '<label for="A">Please</label>';
fixture.innerHTML += '<label for="A">Excuse</label>';
Expand All @@ -110,10 +118,12 @@ describe('multiple-label', function() {
fixture.innerHTML += '<label for="A">Aunt</label>';
fixture.innerHTML += '<label for="A">Sally</label>';
var target = fixture.querySelector('#A');
assert.isTrue(checks['multiple-label'].evaluate.call(checkContext, target));
assert.isUndefined(
checks['multiple-label'].evaluate.call(checkContext, target)
);
});

it('should return true given multiple labels, one label AT visible, and no aria-labelledby', function() {
it('should return undefined given multiple labels, one label AT visible, and no aria-labelledby', function() {
fixture.innerHTML = '<input type="checkbox" id="B">';
fixture.innerHTML += '<label for="B">Please</label>';
fixture.innerHTML += '<label for="B" aria-hidden="true">Excuse</label>';
Expand All @@ -122,7 +132,9 @@ describe('multiple-label', function() {
fixture.innerHTML += '<label for="B" aria-hidden="true">Aunt</label>';
fixture.innerHTML += '<label for="B" aria-hidden="true">Sally</label>';
var target = fixture.querySelector('#B');
assert.isTrue(checks['multiple-label'].evaluate.call(checkContext, target));
assert.isUndefined(
checks['multiple-label'].evaluate.call(checkContext, target)
);
});

it('should return false given multiple labels, one label AT visible, and aria-labelledby for AT visible', function() {
Expand Down Expand Up @@ -156,7 +168,7 @@ describe('multiple-label', function() {
);
});

it('should return true given multiple labels, all visible, aria-labelledby for all', function() {
it('should return undefined given multiple labels, all visible, aria-labelledby for all', function() {
fixture.innerHTML =
'<input type="checkbox" id="J" aria-labelledby="K L M N O P">';
fixture.innerHTML += '<label for="J" id="K">Please</label>';
Expand All @@ -166,15 +178,19 @@ describe('multiple-label', function() {
fixture.innerHTML += '<label for="J" id="O">Aunt</label>';
fixture.innerHTML += '<label for="J" id="P">Sally</label>';
var target = fixture.querySelector('#J');
assert.isTrue(checks['multiple-label'].evaluate.call(checkContext, target));
assert.isUndefined(
checks['multiple-label'].evaluate.call(checkContext, target)
);
});

it('should return true given multiple labels, one AT visible, no aria-labelledby', function() {
it('should return undefined given multiple labels, one AT visible, no aria-labelledby', function() {
fixture.innerHTML = '<input type="checkbox" id="Q"/>';
fixture.innerHTML += '<label for="Q" aria-hidden="true"></label>';
fixture.innerHTML += '<label for="Q" >Excuse</label>';
var target = fixture.querySelector('#Q');
assert.isTrue(checks['multiple-label'].evaluate.call(checkContext, target));
assert.isUndefined(
checks['multiple-label'].evaluate.call(checkContext, target)
);
});

(shadowSupported ? it : xit)(
Expand Down Expand Up @@ -216,7 +232,7 @@ describe('multiple-label', function() {
);

(shadowSupported ? it : xit)(
'should return true for invalid multiple labels in the same document/shadow tree',
'should return undefined for invalid multiple labels in the same document/shadow tree',
function() {
fixture.innerHTML = '<div id="target"></div>';
var target = document.querySelector('#target');
Expand All @@ -226,7 +242,7 @@ describe('multiple-label', function() {
innerHTML += '<label for="Q" >Excuse</label>';
shadowRoot.innerHTML = innerHTML;
var shadowTarget = target.shadowRoot;
assert.isTrue(
assert.isUndefined(
checks['multiple-label'].evaluate.call(
checkContext,
shadowTarget.firstElementChild
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
<!-- Fail -->
<label for="fail1">Hi</label>
<label for="fail1">Foo</label>
<input type="text" id="fail1" />
<!-- incomplete -->
<label for="incomplete1">Hi</label>
<label for="incomplete1">Foo</label>
<input type="text" id="incomplete1" />

<label for="fail2">label one</label>
<label for="fail2">label two</label>
<input type="checkbox" id="fail2" />
<label for="incomplete2">label one</label>
<label for="incomplete2">label two</label>
<input type="checkbox" id="incomplete2" />

<label for="fail3" id="l1">label one</label>
<label for="fail3">label two</label>
<input type="checkbox" id="fail3" aria-labelledby="l1" />
<label for="incomplete3" id="l1">label one</label>
<label for="incomplete3">label two</label>
<input type="checkbox" id="incomplete3" aria-labelledby="l1" />

<label for="fail4">First Name:</label>
<label for="incomplete4">First Name:</label>
<label
>First Name:
<input type="text" id="fail4" />
<input type="text" id="incomplete4" />
</label>

<label for="fail5">Choose an option:</label>
<label for="incomplete5">Choose an option:</label>
<label>
Choose an option:
<select id="fail5">
<select id="incomplete5">
<option selected="selected">Chosen</option>
<option>Not Selected</option>
</select>
</label>

<label for="fail6">Enter your comments:</label>
<label for="incomplete6">Enter your comments:</label>
<label>
Enter your comments:
<textarea id="fail6"></textarea>
<textarea id="incomplete6"></textarea>
</label>

<label>
Enter your comments:
<label>
Enter your comments:
<textarea id="fail7"></textarea>
<textarea id="incomplete7"></textarea>
</label>
</label>

Expand All @@ -46,19 +46,19 @@
Enter your comments:
<label>
Enter your comments:
<textarea id="fail8"></textarea>
<textarea id="incomplete8"></textarea>
</label>
</label>
</label>

<label for="fail9">Enter your comments:</label>
<label for="incomplete9">Enter your comments:</label>
<label>
Enter your comments:
<label>
Enter your comments:
<label>
Enter your comments:
<textarea id="fail9"></textarea>
<textarea id="incomplete9"></textarea>
</label>
</label>
</label>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"description": "form-field-multiple-labels label test",
"rule": "form-field-multiple-labels",
"violations": [
["#fail1"],
["#fail2"],
["#fail3"],
["#fail4"],
["#fail5"],
["#fail6"],
["#fail7"],
["#fail8"],
["#fail9"]
"incomplete": [
["#incomplete1"],
["#incomplete2"],
["#incomplete3"],
["#incomplete4"],
["#incomplete5"],
["#incomplete6"],
["#incomplete7"],
["#incomplete8"],
["#incomplete9"]
],
"passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"], ["#pass5"]]
}

0 comments on commit 0bdaa2b

Please sign in to comment.