From 2fc3eeb38fea611c7ee254b1932c40a14651b45f Mon Sep 17 00:00:00 2001 From: Jey Date: Fri, 18 Jan 2019 16:32:13 +0000 Subject: [PATCH] fix: autocomplete-appropriate node type resolution (#1318) `Firefox` returns `node.type` as `text` for certain scenarios like - ``, hence using `getAttribute` to resolve the value of `type` solves for this edge case. Due to this, the number of violations returned across different browsers were different as described in the bug below. Closes issue: - https://dequesrc.atlassian.net/browse/WWD-1957 ## Reviewer checks **Required fields, to be filled out by PR reviewer(s)** - [x] Follows the commit message policy, appropriate for next version - [x] Has documentation updated, a DU ticket, or requires no documentation change - [x] Includes new tests, or was unnecessary - [x] Code is reviewed for security by: << Name here >> --- lib/checks/forms/autocomplete-appropriate.js | 19 +++++++++- lib/commons/utils/valid-input-type.js | 38 +++++++++++++++++++ test/checks/forms/autocomplete-appropriate.js | 18 +++++++++ .../autocomplete-valid.html | 4 ++ .../autocomplete-valid.json | 8 +++- 5 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 lib/commons/utils/valid-input-type.js diff --git a/lib/checks/forms/autocomplete-appropriate.js b/lib/checks/forms/autocomplete-appropriate.js index 610c5f0d32..b01eca4910 100644 --- a/lib/checks/forms/autocomplete-appropriate.js +++ b/lib/checks/forms/autocomplete-appropriate.js @@ -45,8 +45,23 @@ if (axe.commons.text.autocomplete.stateTerms.includes(purposeTerm)) { } const allowedTypes = allowedTypesMap[purposeTerm]; + +/** + * Note: + * Inconsistent response for `node.type` across browsers, hence resolving and sanitizing using getAttribute + * Example: + * Firefox returns `node.type` as `text` for `type='month'` + * + * Reference HTML Spec - https://html.spec.whatwg.org/multipage/input.html#the-input-element to filter allowed values for `type` + * and sanitize (https://html.spec.whatwg.org/multipage/input.html#value-sanitization-algorithm) + */ +let type = node.hasAttribute('type') + ? axe.commons.text.sanitize(node.getAttribute('type')).toLowerCase() + : 'text'; +type = axe.utils.validInputTypes().includes(type) ? type : 'text'; + if (typeof allowedTypes === 'undefined') { - return node.type === 'text'; + return type === 'text'; } -return allowedTypes.includes(node.type); +return allowedTypes.includes(type); diff --git a/lib/commons/utils/valid-input-type.js b/lib/commons/utils/valid-input-type.js new file mode 100644 index 0000000000..fae153ea04 --- /dev/null +++ b/lib/commons/utils/valid-input-type.js @@ -0,0 +1,38 @@ +/* global axe */ + +/** + * Returns array of valid input type values + * @method validInputTypes + * @memberof axe.commons.utils + * @instance + * @return {Array} + */ +axe.utils.validInputTypes = function validInputTypes() { + 'use strict'; + + // Reference - https://html.spec.whatwg.org/multipage/input.html#the-input-element + return [ + 'hidden', + 'text', + 'search', + 'tel', + 'url', + 'email', + 'password', + 'date', + 'month', + 'week', + 'time', + 'datetime-local', + 'number', + 'range', + 'color', + 'checkbox', + 'radio', + 'file', + 'submit', + 'image', + 'reset', + 'button' + ]; +}; diff --git a/test/checks/forms/autocomplete-appropriate.js b/test/checks/forms/autocomplete-appropriate.js index 30be5c6bc1..e2229ac7c6 100644 --- a/test/checks/forms/autocomplete-appropriate.js +++ b/test/checks/forms/autocomplete-appropriate.js @@ -66,9 +66,27 @@ describe('autocomplete-appropriate', function() { assert.isTrue(evaluate.apply(checkContext, params)); }); + it('returns true if the input type is foobar and the term is undefined', function() { + var options = {}; + var params = autocompleteCheckParams('foo', 'foobar', options); + assert.isTrue(evaluate.apply(checkContext, params)); + }); + it('returns false if the input type is text and the term maps to an empty array', function() { var options = { foo: [] }; var params = autocompleteCheckParams('foo', 'text', options); assert.isFalse(evaluate.apply(checkContext, params)); }); + + it('returns false if the input type is month and term is bday-month', function() { + var options = {}; + var params = autocompleteCheckParams('bday-month', 'month', options); + assert.isFalse(evaluate.apply(checkContext, params)); + }); + + it('returns false if the input type is MONTH (case-insensitive & sanitized) and term is bday-month', function() { + var options = {}; + var params = autocompleteCheckParams('bday-month', ' MONTH ', options); + assert.isFalse(evaluate.apply(checkContext, params)); + }); }); diff --git a/test/integration/rules/autocomplete-valid/autocomplete-valid.html b/test/integration/rules/autocomplete-valid/autocomplete-valid.html index a43350e01d..c5bf6d8ca5 100644 --- a/test/integration/rules/autocomplete-valid/autocomplete-valid.html +++ b/test/integration/rules/autocomplete-valid/autocomplete-valid.html @@ -119,4 +119,8 @@ + + + + \ No newline at end of file diff --git a/test/integration/rules/autocomplete-valid/autocomplete-valid.json b/test/integration/rules/autocomplete-valid/autocomplete-valid.json index 47a6736d24..6d4f41da47 100644 --- a/test/integration/rules/autocomplete-valid/autocomplete-valid.json +++ b/test/integration/rules/autocomplete-valid/autocomplete-valid.json @@ -7,7 +7,9 @@ ["#fail3"], ["#fail4"], ["#fail5"], - ["#fail6"] + ["#fail6"], + ["#fail7"], + ["#fail8"] ], "passes": [ ["#pass1"], @@ -76,6 +78,8 @@ ["#pass64"], ["#pass65"], ["#pass66"], - ["#pass67"] + ["#pass67"], + ["#pass68"], + ["#pass69"] ] }