From 71e6d23ffa274f08f9ed299c4e874bbe6c1647a6 Mon Sep 17 00:00:00 2001 From: Wilco Fiers Date: Fri, 20 Oct 2023 12:55:27 +0200 Subject: [PATCH] fix(aria-valid-attr-value): report incomplete when idrefs are not required --- doc/rule-descriptions.md | 2 +- .../aria/aria-valid-attr-value-evaluate.js | 49 +++++++------------ lib/rules/aria-valid-attr-value.json | 2 +- package-lock.json | 8 +-- package.json | 2 +- ...aria-required-id-references-in6db8.spec.js | 5 ++ test/act-rules/id-value-unique-3ea0c8.spec.js | 5 -- 7 files changed, 31 insertions(+), 42 deletions(-) create mode 100644 test/act-rules/aria-required-id-references-in6db8.spec.js delete mode 100644 test/act-rules/id-value-unique-3ea0c8.spec.js diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index bf03843516..7b7940b2a4 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -32,7 +32,7 @@ | [aria-roles](https://dequeuniversity.com/rules/axe/4.8/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure | [674b10](https://act-rules.github.io/rules/674b10) | | [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.8/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Serious | cat.aria, wcag2a, wcag412, TTv5, TT5.c, EN-301-549, EN-9.4.1.2, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | | [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.8/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure, needs review | | -| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.8/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure, needs review | [6a7281](https://act-rules.github.io/rules/6a7281) | +| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.8/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure, needs review | [6a7281](https://act-rules.github.io/rules/6a7281), [in6db8](https://act-rules.github.io/rules/in6db8) | | [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.8/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure | [5f99a7](https://act-rules.github.io/rules/5f99a7) | | [blink](https://dequeuniversity.com/rules/axe/4.8/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j, TTv5, TT2.b, EN-301-549, EN-9.2.2.2 | failure | | | [button-name](https://dequeuniversity.com/rules/axe/4.8/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, TTv5, TT6.a, EN-301-549, EN-9.4.1.2, ACT | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1), [m6b1q3](https://act-rules.github.io/rules/m6b1q3) | diff --git a/lib/checks/aria/aria-valid-attr-value-evaluate.js b/lib/checks/aria/aria-valid-attr-value-evaluate.js index 36e824afc8..69a7a6c3f0 100644 --- a/lib/checks/aria/aria-valid-attr-value-evaluate.js +++ b/lib/checks/aria/aria-valid-attr-value-evaluate.js @@ -1,4 +1,8 @@ -import { validateAttrValue } from '../../commons/aria'; +import { + validateAttrValue, + getExplicitRole, + requiredAttr as getRequiredAttrs +} from '../../commons/aria'; import standards from '../../standards'; /** @@ -34,6 +38,9 @@ export default function ariaValidAttrValueEvaluate(node, options, virtualNode) { const aria = /^aria-/; const skipAttrs = ['aria-errormessage']; + const role = getExplicitRole(virtualNode); + const requiredAttrs = getRequiredAttrs(role); + const preChecks = { // aria-controls should only check if element exists if the element // doesn't have aria-expanded=false or aria-selected=false (tabs) @@ -59,34 +66,6 @@ export default function ariaValidAttrValueEvaluate(node, options, virtualNode) { // @see https://github.com/dequelabs/axe-core/issues/1524 'aria-owns': () => { return virtualNode.attr('aria-expanded') !== 'false'; - }, - // aria-describedby should not mark missing element as violation but - // instead as needs review - // @see https://github.com/dequelabs/axe-core/issues/1151 - 'aria-describedby': validValue => { - if (!validValue) { - needsReview = `aria-describedby="${virtualNode.attr( - 'aria-describedby' - )}"`; - // TODO: es-modules_tree - messageKey = - axe._tree && axe._tree[0]._hasShadowRoot ? 'noIdShadow' : 'noId'; - } - - return; - }, - // aria-labelledby should not mark missing element as violation but - // instead as needs review - // @see https://github.com/dequelabs/axe-core/issues/2621 - 'aria-labelledby': validValue => { - if (!validValue) { - needsReview = `aria-labelledby="${virtualNode.attr( - 'aria-labelledby' - )}"`; - // TODO: es-modules_tree - messageKey = - axe._tree && axe._tree[0]._hasShadowRoot ? 'noIdShadow' : 'noId'; - } } }; @@ -114,7 +93,17 @@ export default function ariaValidAttrValueEvaluate(node, options, virtualNode) { (preChecks[attrName] ? preChecks[attrName](validValue) : true) && !validValue ) { - if (attrValue === '' && !isStringType(attrName)) { + const attrType = standards.ariaAttrs[attrName]?.type; + // Only required IDREFs can fail this check + if ( + ['idref', 'idrefs'].includes(attrType) && + !requiredAttrs.includes(attrName) + ) { + needsReview = `aria-labelledby="${attrValue}"`; + // TODO: es-modules_tree + messageKey = + axe._tree && axe._tree[0]._hasShadowRoot ? 'noIdShadow' : 'noId'; + } else if (attrValue === '' && !isStringType(attrName)) { needsReview = attrName; messageKey = 'empty'; } else { diff --git a/lib/rules/aria-valid-attr-value.json b/lib/rules/aria-valid-attr-value.json index 924380388a..491dc9a7e4 100644 --- a/lib/rules/aria-valid-attr-value.json +++ b/lib/rules/aria-valid-attr-value.json @@ -3,7 +3,7 @@ "impact": "critical", "matches": "aria-has-attr-matches", "tags": ["cat.aria", "wcag2a", "wcag412", "EN-301-549", "EN-9.4.1.2"], - "actIds": ["6a7281"], + "actIds": ["6a7281", "in6db8"], "metadata": { "description": "Ensures all ARIA attributes have valid values", "help": "ARIA attributes must conform to valid values" diff --git a/package-lock.json b/package-lock.json index 65afe0daec..f4b18bdc55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,7 +74,7 @@ "typedarray": "^0.0.7", "typescript": "^5.2.2", "uglify-js": "^3.17.4", - "wcag-act-rules": "github:w3c/wcag-act-rules#2341a1b", + "wcag-act-rules": "github:w3c/wcag-act-rules#f03fb85", "weakmap-polyfill": "^2.0.4" }, "engines": { @@ -12064,7 +12064,7 @@ } }, "node_modules/wcag-act-rules": { - "resolved": "git+ssh://git@github.com/w3c/wcag-act-rules.git#2341a1ba4d47bc4cdccd5a3b7534e67b52c59002", + "resolved": "git+ssh://git@github.com/w3c/wcag-act-rules.git#f03fb852b9b098afa83004c40a0083b557cec4e0", "dev": true }, "node_modules/wcwidth": { @@ -21537,9 +21537,9 @@ } }, "wcag-act-rules": { - "version": "git+ssh://git@github.com/w3c/wcag-act-rules.git#2341a1ba4d47bc4cdccd5a3b7534e67b52c59002", + "version": "git+ssh://git@github.com/w3c/wcag-act-rules.git#f03fb852b9b098afa83004c40a0083b557cec4e0", "dev": true, - "from": "wcag-act-rules@github:w3c/wcag-act-rules#2341a1b" + "from": "wcag-act-rules@github:w3c/wcag-act-rules#f03fb85" }, "wcwidth": { "version": "1.0.1", diff --git a/package.json b/package.json index b4a326bda8..5d27a10ed2 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,7 @@ "typedarray": "^0.0.7", "typescript": "^5.2.2", "uglify-js": "^3.17.4", - "wcag-act-rules": "github:w3c/wcag-act-rules#2341a1b", + "wcag-act-rules": "github:w3c/wcag-act-rules#f03fb85", "weakmap-polyfill": "^2.0.4" }, "lint-staged": { diff --git a/test/act-rules/aria-required-id-references-in6db8.spec.js b/test/act-rules/aria-required-id-references-in6db8.spec.js new file mode 100644 index 0000000000..95b214ede8 --- /dev/null +++ b/test/act-rules/aria-required-id-references-in6db8.spec.js @@ -0,0 +1,5 @@ +require('./act-runner.js')({ + id: 'in6db8', + title: 'ARIA required ID references exist', + axeRules: ['aria-valid-attr-value'] +}); diff --git a/test/act-rules/id-value-unique-3ea0c8.spec.js b/test/act-rules/id-value-unique-3ea0c8.spec.js deleted file mode 100644 index d83e86d0ab..0000000000 --- a/test/act-rules/id-value-unique-3ea0c8.spec.js +++ /dev/null @@ -1,5 +0,0 @@ -require('./act-runner.js')({ - id: '3ea0c8', - title: 'id attribute value is unique', - axeRules: ['duplicate-id', 'duplicate-id-aria', 'duplicate-id-active'] -});