Skip to content

Commit 766fee5

Browse files
committed
Updated the check of autocomplete valid
1 parent ffb263c commit 766fee5

File tree

14 files changed

+372
-230
lines changed

14 files changed

+372
-230
lines changed

doc/rule-descriptions.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@
7777

7878
## WCAG 2.1 Level A & AA Rules
7979

80-
| Rule ID | Description | Impact | Tags | Issue Type | ACT Rules |
81-
| :----------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------- | :--------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- |
82-
| [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.9/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135, EN-301-549, EN-9.1.3.5, ACT | failure | [73f2c2](https://act-rules.github.io/rules/73f2c2) |
83-
| [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.9/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412, EN-301-549, EN-9.1.4.12, ACT | failure | [24afc2](https://act-rules.github.io/rules/24afc2), [9e45ec](https://act-rules.github.io/rules/9e45ec), [78fd32](https://act-rules.github.io/rules/78fd32) |
80+
| Rule ID | Description | Impact | Tags | Issue Type | ACT Rules |
81+
| :----------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :------- | :-------------------------------------------------------------- | :--------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- |
82+
| [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.9/autocomplete-valid?application=RuleDescription) | Ensure that the necessary form fields use the autocomplete attribute with a valid input. | Moderate | cat.forms, wcag21aa, wcag135, EN-301-549, EN-9.1.3.5, ACT | failure | [73f2c2](https://act-rules.github.io/rules/73f2c2) |
83+
| [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.9/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412, EN-301-549, EN-9.1.4.12, ACT | failure | [24afc2](https://act-rules.github.io/rules/24afc2), [9e45ec](https://act-rules.github.io/rules/9e45ec), [78fd32](https://act-rules.github.io/rules/78fd32) |
8484

8585
## WCAG 2.2 Level A & AA Rules
8686

lib/checks/forms/autocomplete-a11y-evaluate.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { isValidAutocomplete } from '../../commons/text';
2+
import ErrorHandler from '../../core/errors/error-handler';
23

34
function checkIsElementValidAutocomplete(node, options, virtualNode) {
45
const autocomplete = virtualNode.attr('autocomplete')?.toLowerCase().trim();
@@ -61,7 +62,7 @@ function autocompleteA11yEvaluate(node, options, virtualNode) {
6162
return checkIsElementValidAutocomplete(node, options, virtualNode);
6263
}
6364
} catch (err) {
64-
// ErrorHandler.addCheckError('autocomplete-attribute-valid-check', err);
65+
ErrorHandler.addCheckError('autocomplete-attribute-valid-check', err);
6566
return undefined;
6667
}
6768
}

lib/checks/forms/autocomplete-valid.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"id": "autocomplete-valid",
3-
"evaluate": "autocomplete-valid-evaluate",
3+
"evaluate": "autocomplete-a11y-evaluate",
44
"metadata": {
55
"impact": "serious",
66
"messages": {
77
"pass": "the autocomplete attribute is correctly formatted",
8-
"fail": "the autocomplete attribute is incorrectly formatted"
8+
"fail": "Add autocomplete attribute to form fields with a valid value as per HTML specification. In \"name\" attribute of field, prefer to use standard autocomplete value since browsers use \"name\" to suggest autofill. For field with no standard autocomplete value (eg: College ID), prefer to use autocomplete=\"on\"."
99
}
1010
},
1111
"options": {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class A11yEngineError {
2+
constructor(message, error) {
3+
this.message = message;
4+
this.error = error;
5+
}
6+
}
7+
8+
export default A11yEngineError;

lib/core/errors/error-handler.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import A11yEngineError from "./a11y-engine-error";
2+
import ErrorTypes from "./error-types";
3+
4+
let ErrorHandler = {
5+
/*
6+
Error Object Structure
7+
errors: {
8+
check_errors: {
9+
check_name_1: {
10+
details: [err1, err2 ...]
11+
},
12+
check_name_2: {
13+
details: [err3, err4 ...]
14+
},
15+
},
16+
metadata_error: {
17+
details: [err1, err2, ...]
18+
},
19+
configuration_error: {
20+
details: [err1, err2, ...]
21+
},
22+
runtime_error: {
23+
details: [err1, err2, ...]
24+
}
25+
}
26+
*/
27+
errors: {},
28+
29+
addCheckError(checkName = "anonymous", err) {
30+
try {
31+
let error = this.errors[ErrorTypes.CHECK_ERROR] ? this.errors[ErrorTypes.CHECK_ERROR]: {};
32+
let check_error = error[checkName] ? error[checkName] : [];
33+
if(err) {
34+
check_error.push(new A11yEngineError(err.message, err.stack));
35+
}
36+
error[checkName] = check_error;
37+
this.errors[ErrorTypes.CHECK_ERROR] = error;
38+
}
39+
catch(e) {
40+
console.error("A11y Engine Error - Error in addCheckError", e);
41+
}
42+
},
43+
44+
getCheckErrors() {
45+
return this.errors[ErrorTypes.CHECK_ERROR];
46+
},
47+
48+
clearErrors() {
49+
try {
50+
this.errors = {};
51+
}
52+
catch(err) {
53+
console.error("A11y Engine Error - Error in clearErrors", err);
54+
}
55+
},
56+
57+
addNonCheckError(type, message, err) {
58+
try{
59+
let error = this.errors[type]? this.errors[type]: [];
60+
if(err) {
61+
error.push(new A11yEngineError(message, err.stack));
62+
}
63+
else {
64+
error.push(new A11yEngineError(message));
65+
}
66+
67+
this.errors[type] = error;
68+
}
69+
catch(e) {
70+
console.error("A11y Engine Error - Error in addNonCheckError", e);
71+
}
72+
}
73+
74+
}
75+
76+
export default ErrorHandler;

lib/core/errors/error-types.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const ErrorTypes = Object.freeze({
2+
CHECK_ERROR: "check_errors",
3+
RUNTIME_ERROR: "runtime_errors",
4+
CONFIGURATION_ERROR: "configuration_errors",
5+
METADATA_ERROR: "metadata_errors",
6+
INSTRUMENTATION_ERROR: "instrumentation_errors"
7+
});
8+
9+
export default ErrorTypes;
Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,62 @@
11
import autocompleteMatches from './autocomplete-matches';
22

3-
function autocompleteA11yMatches(node, virtualNode) {
3+
function nodeIsASearchFunctionality(node, currLevel=0, maxLevels=4) {
4+
if(!node) {
5+
return false;
6+
}
7+
8+
function currentLevelSearch(node, currentLevel) {
9+
if(!node || currentLevel > maxLevels) {
10+
return false;
11+
}
12+
13+
let details = `\nLevel ${currentLevel}:\n`;
14+
15+
//collecting all the HTML attributes
16+
details += "Attributes:\n";
17+
if(node.hasAttributes()) {
18+
const attributes = axe.utils.getNodeAttributes(node);
19+
for (let i = 0; i < attributes.length; i++) {
20+
let attr = attributes[i];
21+
details += ` ${attr.name}: ${attr.value}\n`;
22+
}
23+
}
24+
25+
// Collect any associated labels (if node is an input, select, textarea, etc.)
26+
if (node.labels) {
27+
details += "Labels:\n";
28+
for (let j = 0; j < node.labels.length; j++) {
29+
details += ` ${node.labels[j].innerText}\n`;
30+
}
31+
} else if (node.nodeName.toLowerCase() === 'input' && node.type !== 'hidden') {
32+
let labels = document.querySelectorAll('label[for="' + node.id + '"]');
33+
details += "Labels:\n";
34+
labels.forEach(label => {
35+
details += ` ${label.innerText}\n`;
36+
});
37+
}
38+
39+
// Collect the given id
40+
details += `ID: ${node.id}\n`;
41+
// Collect all class names
42+
details += `Class Names: ${node.className.split(' ').filter(name => name).join(', ')}\n`;
43+
44+
const regex = new RegExp('search', 'i');
45+
if(regex.test(details)) {
46+
return true;
47+
} else {
48+
currentLevelSearch(node.parentElement, currentLevel + 1);
49+
}
50+
}
51+
return currentLevelSearch(node, currLevel);
52+
}
53+
54+
function autocompleteA11yMatches(node, virtualNode) {
455
const a11yEngineFlag = true;
5-
// the flag is used to tell autocomplete matcher that it is being called
6-
// by a11y-engine and thus bypass an if block
7-
return autocompleteMatches(node, virtualNode, a11yEngineFlag);
56+
/* the flag is used to tell autocomplete matcher that it is being called
57+
by a11y-engine and thus bypass an if block
58+
The second condition is to check we are not matching with search functionality */
59+
return (autocompleteMatches(node, virtualNode, a11yEngineFlag) && !nodeIsASearchFunctionality(node));
860
}
961

1062
export default autocompleteA11yMatches;

lib/rules/autocomplete-valid.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "autocomplete-valid",
3-
"impact": "serious",
4-
"matches": "autocomplete-matches",
3+
"impact": "moderate",
4+
"matches": "autocomplete-a11y-matches",
55
"tags": [
66
"cat.forms",
77
"wcag21aa",
@@ -12,8 +12,8 @@
1212
],
1313
"actIds": ["73f2c2"],
1414
"metadata": {
15-
"description": "Ensure the autocomplete attribute is correct and suitable for the form field",
16-
"help": "autocomplete attribute must be used correctly"
15+
"description": "Ensure that the necessary form fields use the autocomplete attribute with a valid input.",
16+
"help": "Autocomplete attribute must have a valid value"
1717
},
1818
"all": ["autocomplete-valid"],
1919
"any": [],

locales/_template.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@
110110
"help": "<audio> elements must have a captions track"
111111
},
112112
"autocomplete-valid": {
113-
"description": "Ensure the autocomplete attribute is correct and suitable for the form field",
114-
"help": "autocomplete attribute must be used correctly"
113+
"description": "Ensure that the necessary form fields use the autocomplete attribute with a valid input.",
114+
"help": "Autocomplete attribute must have a valid value"
115115
},
116116
"avoid-inline-spacing": {
117117
"description": "Ensure that text spacing set through style attributes can be adjusted with custom stylesheets",
@@ -682,7 +682,7 @@
682682
},
683683
"autocomplete-valid": {
684684
"pass": "the autocomplete attribute is correctly formatted",
685-
"fail": "the autocomplete attribute is incorrectly formatted"
685+
"fail": "Add autocomplete attribute to form fields with a valid value as per HTML specification. In \"name\" attribute of field, prefer to use standard autocomplete value since browsers use \"name\" to suggest autofill. For field with no standard autocomplete value (eg: College ID), prefer to use autocomplete=\"on\"."
686686
},
687687
"accesskeys": {
688688
"pass": "Accesskey attribute value is unique",

0 commit comments

Comments
 (0)