From da2deae1bd863ebe518ca39e86246c06ba690758 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 19 Jan 2021 17:31:36 +0000 Subject: [PATCH 01/20] changed package name to denote DAISY fork --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7b7a697c81..4f3f3db52a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "axe-core", + "name": "axe-core-for-daisy-ace", "version": "4.1.1", "lockfileVersion": 1, "requires": true, diff --git a/package.json b/package.json index d16519fa0f..e7ee949dd0 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "axe-core", + "name": "axe-core-for-daisy-ace", "description": "Accessibility engine for automated Web UI testing", "version": "4.1.1", "license": "MPL-2.0", From bdcf58d3ff218f531d0a13b015f31a1ed88108d2 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 19 Jan 2021 17:32:09 +0000 Subject: [PATCH 02/20] initial patching (scripts/axe-patch-is-aria-role-allowed.js scripts/axe-patch-listitem scripts/axe-patch-only-list-items) --- lib/checks/aria/aria-required-children-evaluate.js | 10 ++++++++-- lib/checks/lists/listitem-evaluate.js | 6 +++++- lib/checks/lists/only-listitems-evaluate.js | 5 +++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/checks/aria/aria-required-children-evaluate.js b/lib/checks/aria/aria-required-children-evaluate.js index 7b225d1a26..fdce5b330b 100644 --- a/lib/checks/aria/aria-required-children-evaluate.js +++ b/lib/checks/aria/aria-required-children-evaluate.js @@ -10,16 +10,22 @@ import { hasContentVirtual, idrefs } from '../../commons/dom'; * Get all owned roles of an element */ function getOwnedRoles(virtualNode) { + const parentRole = getRole(virtualNode, { dpub: true }); + const ownedRoles = []; const ownedElements = getOwnedVirtual(virtualNode); for (let i = 0; i < ownedElements.length; i++) { let ownedElement = ownedElements[i]; - let role = getRole(ownedElement); + let role = getRole(ownedElement, { dpub: true }); // if owned node has no role or is presentational we keep // parsing the descendant tree. this means intermediate roles // between a required parent and child will fail the check - if (['presentation', 'none', null].includes(role)) { + if ( + ['presentation', 'none', null].includes(role) || + (['list'].includes(role) && + ['doc-bibliography', 'doc-endnotes'].includes(parentRole)) + ) { ownedElements.push(...ownedElement.children); } else if (role) { ownedRoles.push(role); diff --git a/lib/checks/lists/listitem-evaluate.js b/lib/checks/lists/listitem-evaluate.js index aebcbd8cc9..b00c140276 100644 --- a/lib/checks/lists/listitem-evaluate.js +++ b/lib/checks/lists/listitem-evaluate.js @@ -1,5 +1,5 @@ import { getComposedParent } from '../../commons/dom'; -import { isValidRole } from '../../commons/aria'; +import { getRoleType, isValidRole } from '../../commons/aria'; function listitemEvaluate(node) { const parent = getComposedParent(node); @@ -16,6 +16,10 @@ function listitemEvaluate(node) { } if (parentRole && isValidRole(parentRole)) { + if (getRoleType(parentRole) === 'list') { + return true; + } + this.data({ messageKey: 'roleNotValid' }); diff --git a/lib/checks/lists/only-listitems-evaluate.js b/lib/checks/lists/only-listitems-evaluate.js index d1ab863428..1e76ef6ada 100644 --- a/lib/checks/lists/only-listitems-evaluate.js +++ b/lib/checks/lists/only-listitems-evaluate.js @@ -1,5 +1,5 @@ import { isVisible } from '../../commons/dom'; -import { getRole } from '../../commons/aria'; +import { getRole, getRoleType } from '../../commons/aria'; function onlyListitemsEvaluate(node, options, virtualNode) { let hasNonEmptyTextNode = false; @@ -24,7 +24,8 @@ function onlyListitemsEvaluate(node, options, virtualNode) { isEmpty = false; const isLi = actualNode.nodeName.toUpperCase() === 'LI'; const role = getRole(vNode); - const isListItemRole = role === 'listitem'; + const isListItemRole = + role === 'listitem' || getRoleType(role) === 'listitem'; if (!isLi && !isListItemRole) { badNodes.push(actualNode); From 5830ea961f9385e2fc36f650579cecab182950a3 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 19 Jan 2021 21:04:08 +0000 Subject: [PATCH 03/20] Mocha fast bail --- test/runner.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/runner.tmpl b/test/runner.tmpl index 6c71d29d20..d673adba45 100644 --- a/test/runner.tmpl +++ b/test/runner.tmpl @@ -24,7 +24,8 @@ From 8b3740d829031238e7538fb10857f6f14ba22720 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 19 Jan 2021 21:04:53 +0000 Subject: [PATCH 04/20] semver is same as Axe Core but with DAISY addon suffix. Also added NPM run test-fast command --- package-lock.json | 2 +- package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f3f3db52a..106bdf931e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "axe-core-for-daisy-ace", - "version": "4.1.1", + "version": "4.1.1-daisy.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e7ee949dd0..ab17772069 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "axe-core-for-daisy-ace", "description": "Accessibility engine for automated Web UI testing", - "version": "4.1.1", + "version": "4.1.1-daisy.0", "license": "MPL-2.0", "engines": { "node": ">=4" @@ -64,6 +64,7 @@ "eslint": "eslint --color --format stylish '{lib,test,build,doc}/**/*.js' 'Gruntfile.js'", "test:headless": "node ./build/test/headless", "test": "tsc && grunt test", + "test-fast": "tsc && grunt test-fast", "test:examples": "node ./doc/examples/test-examples", "test:locales": "mocha test/test-locales.js", "test:rule-help-version": "mocha test/test-rule-help-version.js", From 723b98a9aa388766cc3ce19bc0c8178606706663 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 19 Jan 2021 21:06:42 +0000 Subject: [PATCH 05/20] semver is reflected in auto-generated doc --- doc/rule-descriptions.md | 200 +++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 4f143435d6..c865207e6c 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -10,119 +10,119 @@ ## WCAG 2.0 Level A & AA Rules -| Rule ID | Description | Impact | Tags | Issue Type | -| :------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ | :---------------- | :----------------------------------------------------------------------------------------- | :------------------------- | -| [area-alt](https://dequeuniversity.com/rules/axe/4.1/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | -| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.1/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-command-name](https://dequeuniversity.com/rules/axe/4.1/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.1/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.1/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | -| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.1/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | -| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.1/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | -| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.1/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | -| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.1/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-required-children](https://dequeuniversity.com/rules/axe/4.1/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | -| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.1/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | -| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.1/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-roles](https://dequeuniversity.com/rules/axe/4.1/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.1/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | -| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.1/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.1/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.1/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | -| [audio-caption](https://dequeuniversity.com/rules/axe/4.1/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | -| [blink](https://dequeuniversity.com/rules/axe/4.1/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | -| [button-name](https://dequeuniversity.com/rules/axe/4.1/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | -| [bypass](https://dequeuniversity.com/rules/axe/4.1/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | failure | -| [color-contrast](https://dequeuniversity.com/rules/axe/4.1/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | -| [definition-list](https://dequeuniversity.com/rules/axe/4.1/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | -| [dlitem](https://dequeuniversity.com/rules/axe/4.1/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | -| [document-title](https://dequeuniversity.com/rules/axe/4.1/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | -| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.1/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | -| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.1/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | -| [duplicate-id](https://dequeuniversity.com/rules/axe/4.1/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | -| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.1/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | -| [frame-title](https://dequeuniversity.com/rules/axe/4.1/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a non-empty title attribute | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | -| [html-has-lang](https://dequeuniversity.com/rules/axe/4.1/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | -| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.1/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | -| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.1/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | -| [image-alt](https://dequeuniversity.com/rules/axe/4.1/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [input-button-name](https://dequeuniversity.com/rules/axe/4.1/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | -| [input-image-alt](https://dequeuniversity.com/rules/axe/4.1/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [label](https://dequeuniversity.com/rules/axe/4.1/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | -| [link-name](https://dequeuniversity.com/rules/axe/4.1/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | -| [list](https://dequeuniversity.com/rules/axe/4.1/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | -| [listitem](https://dequeuniversity.com/rules/axe/4.1/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | -| [marquee](https://dequeuniversity.com/rules/axe/4.1/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | -| [meta-refresh](https://dequeuniversity.com/rules/axe/4.1/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag2aaa, wcag221, wcag224, wcag325 | failure | -| [object-alt](https://dequeuniversity.com/rules/axe/4.1/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | -| [role-img-alt](https://dequeuniversity.com/rules/axe/4.1/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.1/scrollable-region-focusable?application=RuleDescription) | Elements that have scrollable content should be accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | -| [select-name](https://dequeuniversity.com/rules/axe/4.1/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | -| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.1/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | -| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.1/svg-img-alt?application=RuleDescription) | Ensures svg elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.1/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table using the headers refers to another cell in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | -| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.1/th-has-data-cells?application=RuleDescription) | Ensure that each table header in a data table refers to data cells | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | -| [valid-lang](https://dequeuniversity.com/rules/axe/4.1/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | -| [video-caption](https://dequeuniversity.com/rules/axe/4.1/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | +| Rule ID | Description | Impact | Tags | Issue Type | +| :--------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ | :---------------- | :----------------------------------------------------------------------------------------- | :------------------------- | +| [area-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | +| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-command-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | +| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | +| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | +| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | +| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-required-children](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | +| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | +| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-roles](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | +| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | +| [audio-caption](https://dequeuniversity.com/rules/axe/4.1.1-daisy/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | +| [blink](https://dequeuniversity.com/rules/axe/4.1.1-daisy/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | +| [button-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | +| [bypass](https://dequeuniversity.com/rules/axe/4.1.1-daisy/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | failure | +| [color-contrast](https://dequeuniversity.com/rules/axe/4.1.1-daisy/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | +| [definition-list](https://dequeuniversity.com/rules/axe/4.1.1-daisy/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | +| [dlitem](https://dequeuniversity.com/rules/axe/4.1.1-daisy/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | +| [document-title](https://dequeuniversity.com/rules/axe/4.1.1-daisy/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | +| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.1.1-daisy/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | +| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.1.1-daisy/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | +| [duplicate-id](https://dequeuniversity.com/rules/axe/4.1.1-daisy/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | +| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.1.1-daisy/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | +| [frame-title](https://dequeuniversity.com/rules/axe/4.1.1-daisy/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a non-empty title attribute | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | +| [html-has-lang](https://dequeuniversity.com/rules/axe/4.1.1-daisy/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | +| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.1.1-daisy/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | +| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.1.1-daisy/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | +| [image-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [input-button-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | +| [input-image-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [label](https://dequeuniversity.com/rules/axe/4.1.1-daisy/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | +| [link-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | +| [list](https://dequeuniversity.com/rules/axe/4.1.1-daisy/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | +| [listitem](https://dequeuniversity.com/rules/axe/4.1.1-daisy/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | +| [marquee](https://dequeuniversity.com/rules/axe/4.1.1-daisy/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | +| [meta-refresh](https://dequeuniversity.com/rules/axe/4.1.1-daisy/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag2aaa, wcag221, wcag224, wcag325 | failure | +| [object-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | +| [role-img-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.1.1-daisy/scrollable-region-focusable?application=RuleDescription) | Elements that have scrollable content should be accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | +| [select-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | +| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.1.1-daisy/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | +| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/svg-img-alt?application=RuleDescription) | Ensures svg elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.1.1-daisy/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table using the headers refers to another cell in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | +| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.1.1-daisy/th-has-data-cells?application=RuleDescription) | Ensure that each table header in a data table refers to data cells | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | +| [valid-lang](https://dequeuniversity.com/rules/axe/4.1.1-daisy/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | +| [video-caption](https://dequeuniversity.com/rules/axe/4.1.1-daisy/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | ## WCAG 2.1 Level A & AA Rules -| Rule ID | Description | Impact | Tags | Issue Type | -| :----------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :------ | :-------------------------------- | :--------- | -| [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.1/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | failure | -| [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.1/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412 | failure | +| Rule ID | Description | Impact | Tags | Issue Type | +| :------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :------ | :-------------------------------- | :--------- | +| [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.1.1-daisy/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | failure | +| [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.1.1-daisy/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412 | failure | ## Best Practices Rules Rules that do not necessarily conform to WCAG success criterion but are industry accepted practices that improve the user experience. -| Rule ID | Description | Impact | Tags | Issue Type | -| :----------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- | :----------------- | :---------------------------------------------- | :------------------------- | -| [accesskeys](https://dequeuniversity.com/rules/axe/4.1/accesskeys?application=RuleDescription) | Ensures every accesskey attribute value is unique | Serious | cat.keyboard, best-practice | failure | -| [aria-allowed-role](https://dequeuniversity.com/rules/axe/4.1/aria-allowed-role?application=RuleDescription) | Ensures role attribute has an appropriate value for the element | Minor | cat.aria, best-practice | failure, needs review | -| [aria-dialog-name](https://dequeuniversity.com/rules/axe/4.1/aria-dialog-name?application=RuleDescription) | Ensures every ARIA dialog and alertdialog node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | -| [aria-treeitem-name](https://dequeuniversity.com/rules/axe/4.1/aria-treeitem-name?application=RuleDescription) | Ensures every ARIA treeitem node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | -| [empty-heading](https://dequeuniversity.com/rules/axe/4.1/empty-heading?application=RuleDescription) | Ensures headings have discernible text | Minor | cat.name-role-value, best-practice | failure, needs review | -| [frame-tested](https://dequeuniversity.com/rules/axe/4.1/frame-tested?application=RuleDescription) | Ensures <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, review-item, best-practice | failure, needs review | -| [frame-title-unique](https://dequeuniversity.com/rules/axe/4.1/frame-title-unique?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, best-practice | failure | -| [heading-order](https://dequeuniversity.com/rules/axe/4.1/heading-order?application=RuleDescription) | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | failure | -| [identical-links-same-purpose](https://dequeuniversity.com/rules/axe/4.1/identical-links-same-purpose?application=RuleDescription) | Ensure that links with the same accessible name serve a similar purpose | Minor | cat.semantics, wcag2aaa, wcag249, best-practice | needs review | -| [image-redundant-alt](https://dequeuniversity.com/rules/axe/4.1/image-redundant-alt?application=RuleDescription) | Ensure image alternative is not repeated as text | Minor | cat.text-alternatives, best-practice | failure | -| [label-title-only](https://dequeuniversity.com/rules/axe/4.1/label-title-only?application=RuleDescription) | Ensures that every form element is not solely labeled using the title or aria-describedby attributes | Serious | cat.forms, best-practice | failure | -| [landmark-banner-is-top-level](https://dequeuniversity.com/rules/axe/4.1/landmark-banner-is-top-level?application=RuleDescription) | Ensures the banner landmark is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-complementary-is-top-level](https://dequeuniversity.com/rules/axe/4.1/landmark-complementary-is-top-level?application=RuleDescription) | Ensures the complementary landmark or aside is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-contentinfo-is-top-level](https://dequeuniversity.com/rules/axe/4.1/landmark-contentinfo-is-top-level?application=RuleDescription) | Ensures the contentinfo landmark is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-main-is-top-level](https://dequeuniversity.com/rules/axe/4.1/landmark-main-is-top-level?application=RuleDescription) | Ensures the main landmark is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-no-duplicate-banner](https://dequeuniversity.com/rules/axe/4.1/landmark-no-duplicate-banner?application=RuleDescription) | Ensures the document has at most one banner landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-no-duplicate-contentinfo](https://dequeuniversity.com/rules/axe/4.1/landmark-no-duplicate-contentinfo?application=RuleDescription) | Ensures the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-no-duplicate-main](https://dequeuniversity.com/rules/axe/4.1/landmark-no-duplicate-main?application=RuleDescription) | Ensures the document has at most one main landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-one-main](https://dequeuniversity.com/rules/axe/4.1/landmark-one-main?application=RuleDescription) | Ensures the document has a main landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-unique](https://dequeuniversity.com/rules/axe/4.1/landmark-unique?application=RuleDescription) | Landmarks must have a unique role or role/label/title (i.e. accessible name) combination | Moderate | cat.semantics, best-practice | failure | -| [meta-viewport-large](https://dequeuniversity.com/rules/axe/4.1/meta-viewport-large?application=RuleDescription) | Ensures <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | failure | -| [meta-viewport](https://dequeuniversity.com/rules/axe/4.1/meta-viewport?application=RuleDescription) | Ensures <meta name="viewport"> does not disable text scaling and zooming | Critical | cat.sensory-and-visual-cues, best-practice, ACT | failure | -| [page-has-heading-one](https://dequeuniversity.com/rules/axe/4.1/page-has-heading-one?application=RuleDescription) | Ensure that the page, or at least one of its frames contains a level-one heading | Moderate | cat.semantics, best-practice | failure | -| [presentation-role-conflict](https://dequeuniversity.com/rules/axe/4.1/presentation-role-conflict?application=RuleDescription) | Flags elements whose role is none or presentation and which cause the role conflict resolution to trigger. | Minor | cat.aria, best-practice | failure | -| [region](https://dequeuniversity.com/rules/axe/4.1/region?application=RuleDescription) | Ensures all page content is contained by landmarks | Moderate | cat.keyboard, best-practice | failure | -| [scope-attr-valid](https://dequeuniversity.com/rules/axe/4.1/scope-attr-valid?application=RuleDescription) | Ensures the scope attribute is used correctly on tables | Moderate, Critical | cat.tables, best-practice | failure | -| [skip-link](https://dequeuniversity.com/rules/axe/4.1/skip-link?application=RuleDescription) | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice | failure, needs review | -| [tabindex](https://dequeuniversity.com/rules/axe/4.1/tabindex?application=RuleDescription) | Ensures tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | failure | -| [table-duplicate-name](https://dequeuniversity.com/rules/axe/4.1/table-duplicate-name?application=RuleDescription) | Ensure that tables do not have the same summary and caption | Minor | cat.tables, best-practice | failure | +| Rule ID | Description | Impact | Tags | Issue Type | +| :------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- | :----------------- | :---------------------------------------------- | :------------------------- | +| [accesskeys](https://dequeuniversity.com/rules/axe/4.1.1-daisy/accesskeys?application=RuleDescription) | Ensures every accesskey attribute value is unique | Serious | cat.keyboard, best-practice | failure | +| [aria-allowed-role](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-allowed-role?application=RuleDescription) | Ensures role attribute has an appropriate value for the element | Minor | cat.aria, best-practice | failure, needs review | +| [aria-dialog-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-dialog-name?application=RuleDescription) | Ensures every ARIA dialog and alertdialog node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | +| [aria-treeitem-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-treeitem-name?application=RuleDescription) | Ensures every ARIA treeitem node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | +| [empty-heading](https://dequeuniversity.com/rules/axe/4.1.1-daisy/empty-heading?application=RuleDescription) | Ensures headings have discernible text | Minor | cat.name-role-value, best-practice | failure, needs review | +| [frame-tested](https://dequeuniversity.com/rules/axe/4.1.1-daisy/frame-tested?application=RuleDescription) | Ensures <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, review-item, best-practice | failure, needs review | +| [frame-title-unique](https://dequeuniversity.com/rules/axe/4.1.1-daisy/frame-title-unique?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, best-practice | failure | +| [heading-order](https://dequeuniversity.com/rules/axe/4.1.1-daisy/heading-order?application=RuleDescription) | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | failure | +| [identical-links-same-purpose](https://dequeuniversity.com/rules/axe/4.1.1-daisy/identical-links-same-purpose?application=RuleDescription) | Ensure that links with the same accessible name serve a similar purpose | Minor | cat.semantics, wcag2aaa, wcag249, best-practice | needs review | +| [image-redundant-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/image-redundant-alt?application=RuleDescription) | Ensure image alternative is not repeated as text | Minor | cat.text-alternatives, best-practice | failure | +| [label-title-only](https://dequeuniversity.com/rules/axe/4.1.1-daisy/label-title-only?application=RuleDescription) | Ensures that every form element is not solely labeled using the title or aria-describedby attributes | Serious | cat.forms, best-practice | failure | +| [landmark-banner-is-top-level](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-banner-is-top-level?application=RuleDescription) | Ensures the banner landmark is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-complementary-is-top-level](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-complementary-is-top-level?application=RuleDescription) | Ensures the complementary landmark or aside is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-contentinfo-is-top-level](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-contentinfo-is-top-level?application=RuleDescription) | Ensures the contentinfo landmark is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-main-is-top-level](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-main-is-top-level?application=RuleDescription) | Ensures the main landmark is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-no-duplicate-banner](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-no-duplicate-banner?application=RuleDescription) | Ensures the document has at most one banner landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-no-duplicate-contentinfo](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-no-duplicate-contentinfo?application=RuleDescription) | Ensures the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-no-duplicate-main](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-no-duplicate-main?application=RuleDescription) | Ensures the document has at most one main landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-one-main](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-one-main?application=RuleDescription) | Ensures the document has a main landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-unique](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-unique?application=RuleDescription) | Landmarks must have a unique role or role/label/title (i.e. accessible name) combination | Moderate | cat.semantics, best-practice | failure | +| [meta-viewport-large](https://dequeuniversity.com/rules/axe/4.1.1-daisy/meta-viewport-large?application=RuleDescription) | Ensures <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | failure | +| [meta-viewport](https://dequeuniversity.com/rules/axe/4.1.1-daisy/meta-viewport?application=RuleDescription) | Ensures <meta name="viewport"> does not disable text scaling and zooming | Critical | cat.sensory-and-visual-cues, best-practice, ACT | failure | +| [page-has-heading-one](https://dequeuniversity.com/rules/axe/4.1.1-daisy/page-has-heading-one?application=RuleDescription) | Ensure that the page, or at least one of its frames contains a level-one heading | Moderate | cat.semantics, best-practice | failure | +| [presentation-role-conflict](https://dequeuniversity.com/rules/axe/4.1.1-daisy/presentation-role-conflict?application=RuleDescription) | Flags elements whose role is none or presentation and which cause the role conflict resolution to trigger. | Minor | cat.aria, best-practice | failure | +| [region](https://dequeuniversity.com/rules/axe/4.1.1-daisy/region?application=RuleDescription) | Ensures all page content is contained by landmarks | Moderate | cat.keyboard, best-practice | failure | +| [scope-attr-valid](https://dequeuniversity.com/rules/axe/4.1.1-daisy/scope-attr-valid?application=RuleDescription) | Ensures the scope attribute is used correctly on tables | Moderate, Critical | cat.tables, best-practice | failure | +| [skip-link](https://dequeuniversity.com/rules/axe/4.1.1-daisy/skip-link?application=RuleDescription) | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice | failure, needs review | +| [tabindex](https://dequeuniversity.com/rules/axe/4.1.1-daisy/tabindex?application=RuleDescription) | Ensures tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | failure | +| [table-duplicate-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/table-duplicate-name?application=RuleDescription) | Ensure that tables do not have the same summary and caption | Minor | cat.tables, best-practice | failure | ## Experimental Rules Rules we are still testing and developing. They are not enabled by default in axe-core, but are enabled for the axe browser extensions. -| Rule ID | Description | Impact | Tags | Issue Type | -| :------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------- | :------------------------- | -| [css-orientation-lock](https://dequeuniversity.com/rules/axe/4.1/css-orientation-lock?application=RuleDescription) | Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations | Serious | cat.structure, wcag134, wcag21aa, experimental | failure, needs review | -| [focus-order-semantics](https://dequeuniversity.com/rules/axe/4.1/focus-order-semantics?application=RuleDescription) | Ensures elements in the focus order have an appropriate role | Minor | cat.keyboard, best-practice, experimental | failure | -| [hidden-content](https://dequeuniversity.com/rules/axe/4.1/hidden-content?application=RuleDescription) | Informs users about hidden content. | Minor | cat.structure, experimental, review-item, best-practice | failure, needs review | -| [label-content-name-mismatch](https://dequeuniversity.com/rules/axe/4.1/label-content-name-mismatch?application=RuleDescription) | Ensures that elements labelled through their content must have their visible text as part of their accessible name | Serious | cat.semantics, wcag21a, wcag253, experimental | failure | -| [link-in-text-block](https://dequeuniversity.com/rules/axe/4.1/link-in-text-block?application=RuleDescription) | Links can be distinguished without relying on color | Serious | cat.color, experimental, wcag2a, wcag141 | failure, needs review | -| [no-autoplay-audio](https://dequeuniversity.com/rules/axe/4.1/no-autoplay-audio?application=RuleDescription) | Ensures <video> or <audio> elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio | Moderate | cat.time-and-media, wcag2a, wcag142, experimental | failure, needs review | -| [p-as-heading](https://dequeuniversity.com/rules/axe/4.1/p-as-heading?application=RuleDescription) | Ensure p elements are not used to style headings | Serious | cat.semantics, wcag2a, wcag131, experimental | failure | -| [table-fake-caption](https://dequeuniversity.com/rules/axe/4.1/table-fake-caption?application=RuleDescription) | Ensure that tables with a caption use the <caption> element. | Serious | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | -| [td-has-header](https://dequeuniversity.com/rules/axe/4.1/td-has-header?application=RuleDescription) | Ensure that each non-empty data cell in a large table has one or more table headers | Critical | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | +| Rule ID | Description | Impact | Tags | Issue Type | +| :--------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------- | :------------------------- | +| [css-orientation-lock](https://dequeuniversity.com/rules/axe/4.1.1-daisy/css-orientation-lock?application=RuleDescription) | Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations | Serious | cat.structure, wcag134, wcag21aa, experimental | failure, needs review | +| [focus-order-semantics](https://dequeuniversity.com/rules/axe/4.1.1-daisy/focus-order-semantics?application=RuleDescription) | Ensures elements in the focus order have an appropriate role | Minor | cat.keyboard, best-practice, experimental | failure | +| [hidden-content](https://dequeuniversity.com/rules/axe/4.1.1-daisy/hidden-content?application=RuleDescription) | Informs users about hidden content. | Minor | cat.structure, experimental, review-item, best-practice | failure, needs review | +| [label-content-name-mismatch](https://dequeuniversity.com/rules/axe/4.1.1-daisy/label-content-name-mismatch?application=RuleDescription) | Ensures that elements labelled through their content must have their visible text as part of their accessible name | Serious | cat.semantics, wcag21a, wcag253, experimental | failure | +| [link-in-text-block](https://dequeuniversity.com/rules/axe/4.1.1-daisy/link-in-text-block?application=RuleDescription) | Links can be distinguished without relying on color | Serious | cat.color, experimental, wcag2a, wcag141 | failure, needs review | +| [no-autoplay-audio](https://dequeuniversity.com/rules/axe/4.1.1-daisy/no-autoplay-audio?application=RuleDescription) | Ensures <video> or <audio> elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio | Moderate | cat.time-and-media, wcag2a, wcag142, experimental | failure, needs review | +| [p-as-heading](https://dequeuniversity.com/rules/axe/4.1.1-daisy/p-as-heading?application=RuleDescription) | Ensure p elements are not used to style headings | Serious | cat.semantics, wcag2a, wcag131, experimental | failure | +| [table-fake-caption](https://dequeuniversity.com/rules/axe/4.1.1-daisy/table-fake-caption?application=RuleDescription) | Ensure that tables with a caption use the <caption> element. | Serious | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | +| [td-has-header](https://dequeuniversity.com/rules/axe/4.1.1-daisy/td-has-header?application=RuleDescription) | Ensure that each non-empty data cell in a large table has one or more table headers | Critical | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | ## Deprecated Rules From 2e702359de37eca40d093f0e7b76d73693cdb19f Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 19 Jan 2021 21:07:00 +0000 Subject: [PATCH 06/20] added unit tests for implicit/explicit and DPUB role parsing --- test/commons/aria/get-role.js | 68 ++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/test/commons/aria/get-role.js b/test/commons/aria/get-role.js index 6a82302dc6..e76a1bfb90 100644 --- a/test/commons/aria/get-role.js +++ b/test/commons/aria/get-role.js @@ -315,11 +315,29 @@ describe('aria.getRole', function() { assert.equal(aria.getRole(node, { dpub: true }), 'doc-chapter'); }); - it('does not returns DPUB roles with `dpub: false`', function() { + it('returns DPUB roles with `dpub: true` whilst ignoring implicit roles', function() { + var node = document.createElement('li'); + node.setAttribute('role', 'doc-chapter'); + flatTreeSetup(node); + assert.equal(aria.getRole(node, { dpub: true }), 'doc-chapter'); + }); + + it('returns non-DPUB implicit roles with `dpub: false/undefined`', function() { + var node = document.createElement('li'); + node.setAttribute('role', 'doc-chapter'); + var parentNode = document.createElement('div'); + parentNode.appendChild(node); + flatTreeSetup(parentNode); + assert.equal(aria.getRole(node, { dpub: false }), 'listitem'); + assert.equal(aria.getRole(node, { dpub: undefined }), 'listitem'); + }); + + it('does not returns DPUB roles with `dpub: false/undefined`', function() { var node = document.createElement('section'); node.setAttribute('role', 'doc-chapter'); flatTreeSetup(node); assert.isNull(aria.getRole(node, { dpub: false })); + assert.isNull(aria.getRole(node, { dpub: undefined })); }); }); @@ -379,6 +397,54 @@ describe('aria.getRole', function() { 'doc-chapter' ); }); + + it('respect the `dpub: false/undefined` option, whilst skipping the implicit roles due to non-abstract explicit role', function() { + var node = document.createElement('li'); + node.setAttribute('role', 'doc-chapter region'); + var parentNode = document.createElement('div'); + parentNode.appendChild(node); + flatTreeSetup(parentNode); + assert.equal( + aria.getRole(node, { fallback: true, dpub: false }), + 'region' + ); + assert.equal( + aria.getRole(node, { fallback: true, dpub: undefined }), + 'region' + ); + }); + + it('respect the `dpub: false/undefined` option, whilst ignoring the implicit roles and abstract explicit role', function() { + var node = document.createElement('li'); + node.setAttribute('role', 'doc-chapter section'); + var parentNode = document.createElement('div'); + parentNode.appendChild(node); + flatTreeSetup(parentNode); + assert.isNull( + aria.getRole(node, { noImplicit: true, fallback: true, dpub: false }) + ); + assert.isNull( + aria.getRole(node, { + noImplicit: true, + fallback: true, + dpub: undefined + }) + ); + }); + + it('respect the `dpub: false/undefined` option', function() { + var node = document.createElement('div'); + node.setAttribute('role', 'doc-chapter region'); + flatTreeSetup(node); + assert.equal( + aria.getRole(node, { fallback: true, dpub: false }), + 'region' + ); + assert.equal( + aria.getRole(node, { fallback: true, dpub: undefined }), + 'region' + ); + }); }); describe('noPresentational is honored', function() { From 4ce706daf6d9ff6ef64df80c44c9e503a750a5d9 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 19 Jan 2021 21:25:51 +0000 Subject: [PATCH 07/20] Scoped NPM package name, and files selection for NPM publish --- package-lock.json | 2 +- package.json | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 106bdf931e..882b4c9178 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "axe-core-for-daisy-ace", + "name": "@daisy/axe-core-for-ace", "version": "4.1.1-daisy.0", "lockfileVersion": 1, "requires": true, diff --git a/package.json b/package.json index ab17772069..90efa9aa6a 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "axe-core-for-daisy-ace", + "name": "@daisy/axe-core-for-ace", "description": "Accessibility engine for automated Web UI testing", "version": "4.1.1-daisy.0", "license": "MPL-2.0", @@ -50,6 +50,15 @@ ], "main": "axe.js", "typings": "axe.d.ts", + "files": [ + "LICENSE", + "README.md", + "CHANGELOG.md", + "locales/**/*", + "axe.js", + "axe.min.js", + "axe.d.ts" + ], "standard-version": { "scripts": { "postbump": "npm ci && npm run sri-update" From 1c9a0b2c351105cbfbac18e936cc8252526f0c7d Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 19 Jan 2021 21:29:08 +0000 Subject: [PATCH 08/20] NPM public publish --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 90efa9aa6a..bb47e60f5c 100644 --- a/package.json +++ b/package.json @@ -159,5 +159,8 @@ "prettier --write", "git add" ] + }, + "publishConfig": { + "access": "public" } } From ea67596738d4b8be1dc3375901eca48cba7aea53 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 16 Feb 2021 11:44:34 +0000 Subject: [PATCH 09/20] rules MD --- doc/rule-descriptions.md | 184 +++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index c865207e6c..7a420605fd 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -12,65 +12,65 @@ | Rule ID | Description | Impact | Tags | Issue Type | | :--------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ | :---------------- | :----------------------------------------------------------------------------------------- | :------------------------- | -| [area-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | -| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-command-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | -| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | -| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | -| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | -| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-required-children](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | -| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | -| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-roles](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | -| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | -| [audio-caption](https://dequeuniversity.com/rules/axe/4.1.1-daisy/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | -| [blink](https://dequeuniversity.com/rules/axe/4.1.1-daisy/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | -| [button-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | -| [bypass](https://dequeuniversity.com/rules/axe/4.1.1-daisy/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | failure | -| [color-contrast](https://dequeuniversity.com/rules/axe/4.1.1-daisy/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | -| [definition-list](https://dequeuniversity.com/rules/axe/4.1.1-daisy/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | -| [dlitem](https://dequeuniversity.com/rules/axe/4.1.1-daisy/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | -| [document-title](https://dequeuniversity.com/rules/axe/4.1.1-daisy/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | -| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.1.1-daisy/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | -| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.1.1-daisy/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | -| [duplicate-id](https://dequeuniversity.com/rules/axe/4.1.1-daisy/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | -| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.1.1-daisy/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | -| [frame-title](https://dequeuniversity.com/rules/axe/4.1.1-daisy/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a non-empty title attribute | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | -| [html-has-lang](https://dequeuniversity.com/rules/axe/4.1.1-daisy/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | -| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.1.1-daisy/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | -| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.1.1-daisy/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | -| [image-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [input-button-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | -| [input-image-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [label](https://dequeuniversity.com/rules/axe/4.1.1-daisy/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | -| [link-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | -| [list](https://dequeuniversity.com/rules/axe/4.1.1-daisy/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | -| [listitem](https://dequeuniversity.com/rules/axe/4.1.1-daisy/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | -| [marquee](https://dequeuniversity.com/rules/axe/4.1.1-daisy/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | -| [meta-refresh](https://dequeuniversity.com/rules/axe/4.1.1-daisy/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag2aaa, wcag221, wcag224, wcag325 | failure | -| [object-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | -| [role-img-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.1.1-daisy/scrollable-region-focusable?application=RuleDescription) | Elements that have scrollable content should be accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | -| [select-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | -| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.1.1-daisy/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | -| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/svg-img-alt?application=RuleDescription) | Ensures svg elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.1.1-daisy/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table using the headers refers to another cell in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | -| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.1.1-daisy/th-has-data-cells?application=RuleDescription) | Ensure that each table header in a data table refers to data cells | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | -| [valid-lang](https://dequeuniversity.com/rules/axe/4.1.1-daisy/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | -| [video-caption](https://dequeuniversity.com/rules/axe/4.1.1-daisy/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | +| [area-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | +| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-command-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | +| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | +| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | +| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | +| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-required-children](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | +| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | +| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-roles](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | +| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | +| [audio-caption](https://dequeuniversity.com/rules/axe/4.1.2-daisy/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | +| [blink](https://dequeuniversity.com/rules/axe/4.1.2-daisy/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | +| [button-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | +| [bypass](https://dequeuniversity.com/rules/axe/4.1.2-daisy/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | failure | +| [color-contrast](https://dequeuniversity.com/rules/axe/4.1.2-daisy/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | +| [definition-list](https://dequeuniversity.com/rules/axe/4.1.2-daisy/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | +| [dlitem](https://dequeuniversity.com/rules/axe/4.1.2-daisy/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | +| [document-title](https://dequeuniversity.com/rules/axe/4.1.2-daisy/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | +| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.1.2-daisy/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | +| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.1.2-daisy/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | +| [duplicate-id](https://dequeuniversity.com/rules/axe/4.1.2-daisy/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | +| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.1.2-daisy/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | +| [frame-title](https://dequeuniversity.com/rules/axe/4.1.2-daisy/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a non-empty title attribute | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | +| [html-has-lang](https://dequeuniversity.com/rules/axe/4.1.2-daisy/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | +| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.1.2-daisy/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | +| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.1.2-daisy/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | +| [image-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [input-button-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | +| [input-image-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [label](https://dequeuniversity.com/rules/axe/4.1.2-daisy/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | +| [link-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | +| [list](https://dequeuniversity.com/rules/axe/4.1.2-daisy/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | +| [listitem](https://dequeuniversity.com/rules/axe/4.1.2-daisy/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | +| [marquee](https://dequeuniversity.com/rules/axe/4.1.2-daisy/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | +| [meta-refresh](https://dequeuniversity.com/rules/axe/4.1.2-daisy/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag2aaa, wcag221, wcag224, wcag325 | failure | +| [object-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | +| [role-img-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.1.2-daisy/scrollable-region-focusable?application=RuleDescription) | Elements that have scrollable content should be accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | +| [select-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | +| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.1.2-daisy/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | +| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/svg-img-alt?application=RuleDescription) | Ensures svg elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.1.2-daisy/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table using the headers refers to another cell in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | +| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.1.2-daisy/th-has-data-cells?application=RuleDescription) | Ensure that each table header in a data table refers to data cells | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | +| [valid-lang](https://dequeuniversity.com/rules/axe/4.1.2-daisy/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | +| [video-caption](https://dequeuniversity.com/rules/axe/4.1.2-daisy/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | ## WCAG 2.1 Level A & AA Rules | Rule ID | Description | Impact | Tags | Issue Type | | :------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :------ | :-------------------------------- | :--------- | -| [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.1.1-daisy/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | failure | -| [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.1.1-daisy/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412 | failure | +| [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.1.2-daisy/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | failure | +| [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.1.2-daisy/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412 | failure | ## Best Practices Rules @@ -78,35 +78,35 @@ Rules that do not necessarily conform to WCAG success criterion but are industry | Rule ID | Description | Impact | Tags | Issue Type | | :------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- | :----------------- | :---------------------------------------------- | :------------------------- | -| [accesskeys](https://dequeuniversity.com/rules/axe/4.1.1-daisy/accesskeys?application=RuleDescription) | Ensures every accesskey attribute value is unique | Serious | cat.keyboard, best-practice | failure | -| [aria-allowed-role](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-allowed-role?application=RuleDescription) | Ensures role attribute has an appropriate value for the element | Minor | cat.aria, best-practice | failure, needs review | -| [aria-dialog-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-dialog-name?application=RuleDescription) | Ensures every ARIA dialog and alertdialog node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | -| [aria-treeitem-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/aria-treeitem-name?application=RuleDescription) | Ensures every ARIA treeitem node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | -| [empty-heading](https://dequeuniversity.com/rules/axe/4.1.1-daisy/empty-heading?application=RuleDescription) | Ensures headings have discernible text | Minor | cat.name-role-value, best-practice | failure, needs review | -| [frame-tested](https://dequeuniversity.com/rules/axe/4.1.1-daisy/frame-tested?application=RuleDescription) | Ensures <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, review-item, best-practice | failure, needs review | -| [frame-title-unique](https://dequeuniversity.com/rules/axe/4.1.1-daisy/frame-title-unique?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, best-practice | failure | -| [heading-order](https://dequeuniversity.com/rules/axe/4.1.1-daisy/heading-order?application=RuleDescription) | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | failure | -| [identical-links-same-purpose](https://dequeuniversity.com/rules/axe/4.1.1-daisy/identical-links-same-purpose?application=RuleDescription) | Ensure that links with the same accessible name serve a similar purpose | Minor | cat.semantics, wcag2aaa, wcag249, best-practice | needs review | -| [image-redundant-alt](https://dequeuniversity.com/rules/axe/4.1.1-daisy/image-redundant-alt?application=RuleDescription) | Ensure image alternative is not repeated as text | Minor | cat.text-alternatives, best-practice | failure | -| [label-title-only](https://dequeuniversity.com/rules/axe/4.1.1-daisy/label-title-only?application=RuleDescription) | Ensures that every form element is not solely labeled using the title or aria-describedby attributes | Serious | cat.forms, best-practice | failure | -| [landmark-banner-is-top-level](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-banner-is-top-level?application=RuleDescription) | Ensures the banner landmark is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-complementary-is-top-level](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-complementary-is-top-level?application=RuleDescription) | Ensures the complementary landmark or aside is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-contentinfo-is-top-level](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-contentinfo-is-top-level?application=RuleDescription) | Ensures the contentinfo landmark is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-main-is-top-level](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-main-is-top-level?application=RuleDescription) | Ensures the main landmark is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-no-duplicate-banner](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-no-duplicate-banner?application=RuleDescription) | Ensures the document has at most one banner landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-no-duplicate-contentinfo](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-no-duplicate-contentinfo?application=RuleDescription) | Ensures the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-no-duplicate-main](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-no-duplicate-main?application=RuleDescription) | Ensures the document has at most one main landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-one-main](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-one-main?application=RuleDescription) | Ensures the document has a main landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-unique](https://dequeuniversity.com/rules/axe/4.1.1-daisy/landmark-unique?application=RuleDescription) | Landmarks must have a unique role or role/label/title (i.e. accessible name) combination | Moderate | cat.semantics, best-practice | failure | -| [meta-viewport-large](https://dequeuniversity.com/rules/axe/4.1.1-daisy/meta-viewport-large?application=RuleDescription) | Ensures <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | failure | -| [meta-viewport](https://dequeuniversity.com/rules/axe/4.1.1-daisy/meta-viewport?application=RuleDescription) | Ensures <meta name="viewport"> does not disable text scaling and zooming | Critical | cat.sensory-and-visual-cues, best-practice, ACT | failure | -| [page-has-heading-one](https://dequeuniversity.com/rules/axe/4.1.1-daisy/page-has-heading-one?application=RuleDescription) | Ensure that the page, or at least one of its frames contains a level-one heading | Moderate | cat.semantics, best-practice | failure | -| [presentation-role-conflict](https://dequeuniversity.com/rules/axe/4.1.1-daisy/presentation-role-conflict?application=RuleDescription) | Flags elements whose role is none or presentation and which cause the role conflict resolution to trigger. | Minor | cat.aria, best-practice | failure | -| [region](https://dequeuniversity.com/rules/axe/4.1.1-daisy/region?application=RuleDescription) | Ensures all page content is contained by landmarks | Moderate | cat.keyboard, best-practice | failure | -| [scope-attr-valid](https://dequeuniversity.com/rules/axe/4.1.1-daisy/scope-attr-valid?application=RuleDescription) | Ensures the scope attribute is used correctly on tables | Moderate, Critical | cat.tables, best-practice | failure | -| [skip-link](https://dequeuniversity.com/rules/axe/4.1.1-daisy/skip-link?application=RuleDescription) | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice | failure, needs review | -| [tabindex](https://dequeuniversity.com/rules/axe/4.1.1-daisy/tabindex?application=RuleDescription) | Ensures tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | failure | -| [table-duplicate-name](https://dequeuniversity.com/rules/axe/4.1.1-daisy/table-duplicate-name?application=RuleDescription) | Ensure that tables do not have the same summary and caption | Minor | cat.tables, best-practice | failure | +| [accesskeys](https://dequeuniversity.com/rules/axe/4.1.2-daisy/accesskeys?application=RuleDescription) | Ensures every accesskey attribute value is unique | Serious | cat.keyboard, best-practice | failure | +| [aria-allowed-role](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-allowed-role?application=RuleDescription) | Ensures role attribute has an appropriate value for the element | Minor | cat.aria, best-practice | failure, needs review | +| [aria-dialog-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-dialog-name?application=RuleDescription) | Ensures every ARIA dialog and alertdialog node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | +| [aria-treeitem-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-treeitem-name?application=RuleDescription) | Ensures every ARIA treeitem node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | +| [empty-heading](https://dequeuniversity.com/rules/axe/4.1.2-daisy/empty-heading?application=RuleDescription) | Ensures headings have discernible text | Minor | cat.name-role-value, best-practice | failure, needs review | +| [frame-tested](https://dequeuniversity.com/rules/axe/4.1.2-daisy/frame-tested?application=RuleDescription) | Ensures <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, review-item, best-practice | failure, needs review | +| [frame-title-unique](https://dequeuniversity.com/rules/axe/4.1.2-daisy/frame-title-unique?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, best-practice | failure | +| [heading-order](https://dequeuniversity.com/rules/axe/4.1.2-daisy/heading-order?application=RuleDescription) | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | failure | +| [identical-links-same-purpose](https://dequeuniversity.com/rules/axe/4.1.2-daisy/identical-links-same-purpose?application=RuleDescription) | Ensure that links with the same accessible name serve a similar purpose | Minor | cat.semantics, wcag2aaa, wcag249, best-practice | needs review | +| [image-redundant-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/image-redundant-alt?application=RuleDescription) | Ensure image alternative is not repeated as text | Minor | cat.text-alternatives, best-practice | failure | +| [label-title-only](https://dequeuniversity.com/rules/axe/4.1.2-daisy/label-title-only?application=RuleDescription) | Ensures that every form element is not solely labeled using the title or aria-describedby attributes | Serious | cat.forms, best-practice | failure | +| [landmark-banner-is-top-level](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-banner-is-top-level?application=RuleDescription) | Ensures the banner landmark is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-complementary-is-top-level](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-complementary-is-top-level?application=RuleDescription) | Ensures the complementary landmark or aside is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-contentinfo-is-top-level](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-contentinfo-is-top-level?application=RuleDescription) | Ensures the contentinfo landmark is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-main-is-top-level](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-main-is-top-level?application=RuleDescription) | Ensures the main landmark is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-no-duplicate-banner](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-no-duplicate-banner?application=RuleDescription) | Ensures the document has at most one banner landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-no-duplicate-contentinfo](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-no-duplicate-contentinfo?application=RuleDescription) | Ensures the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-no-duplicate-main](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-no-duplicate-main?application=RuleDescription) | Ensures the document has at most one main landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-one-main](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-one-main?application=RuleDescription) | Ensures the document has a main landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-unique](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-unique?application=RuleDescription) | Landmarks must have a unique role or role/label/title (i.e. accessible name) combination | Moderate | cat.semantics, best-practice | failure | +| [meta-viewport-large](https://dequeuniversity.com/rules/axe/4.1.2-daisy/meta-viewport-large?application=RuleDescription) | Ensures <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | failure | +| [meta-viewport](https://dequeuniversity.com/rules/axe/4.1.2-daisy/meta-viewport?application=RuleDescription) | Ensures <meta name="viewport"> does not disable text scaling and zooming | Critical | cat.sensory-and-visual-cues, best-practice, ACT | failure | +| [page-has-heading-one](https://dequeuniversity.com/rules/axe/4.1.2-daisy/page-has-heading-one?application=RuleDescription) | Ensure that the page, or at least one of its frames contains a level-one heading | Moderate | cat.semantics, best-practice | failure | +| [presentation-role-conflict](https://dequeuniversity.com/rules/axe/4.1.2-daisy/presentation-role-conflict?application=RuleDescription) | Flags elements whose role is none or presentation and which cause the role conflict resolution to trigger. | Minor | cat.aria, best-practice | failure | +| [region](https://dequeuniversity.com/rules/axe/4.1.2-daisy/region?application=RuleDescription) | Ensures all page content is contained by landmarks | Moderate | cat.keyboard, best-practice | failure | +| [scope-attr-valid](https://dequeuniversity.com/rules/axe/4.1.2-daisy/scope-attr-valid?application=RuleDescription) | Ensures the scope attribute is used correctly on tables | Moderate, Critical | cat.tables, best-practice | failure | +| [skip-link](https://dequeuniversity.com/rules/axe/4.1.2-daisy/skip-link?application=RuleDescription) | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice | failure, needs review | +| [tabindex](https://dequeuniversity.com/rules/axe/4.1.2-daisy/tabindex?application=RuleDescription) | Ensures tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | failure | +| [table-duplicate-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/table-duplicate-name?application=RuleDescription) | Ensure that tables do not have the same summary and caption | Minor | cat.tables, best-practice | failure | ## Experimental Rules @@ -114,15 +114,15 @@ Rules we are still testing and developing. They are not enabled by default in ax | Rule ID | Description | Impact | Tags | Issue Type | | :--------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------- | :------------------------- | -| [css-orientation-lock](https://dequeuniversity.com/rules/axe/4.1.1-daisy/css-orientation-lock?application=RuleDescription) | Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations | Serious | cat.structure, wcag134, wcag21aa, experimental | failure, needs review | -| [focus-order-semantics](https://dequeuniversity.com/rules/axe/4.1.1-daisy/focus-order-semantics?application=RuleDescription) | Ensures elements in the focus order have an appropriate role | Minor | cat.keyboard, best-practice, experimental | failure | -| [hidden-content](https://dequeuniversity.com/rules/axe/4.1.1-daisy/hidden-content?application=RuleDescription) | Informs users about hidden content. | Minor | cat.structure, experimental, review-item, best-practice | failure, needs review | -| [label-content-name-mismatch](https://dequeuniversity.com/rules/axe/4.1.1-daisy/label-content-name-mismatch?application=RuleDescription) | Ensures that elements labelled through their content must have their visible text as part of their accessible name | Serious | cat.semantics, wcag21a, wcag253, experimental | failure | -| [link-in-text-block](https://dequeuniversity.com/rules/axe/4.1.1-daisy/link-in-text-block?application=RuleDescription) | Links can be distinguished without relying on color | Serious | cat.color, experimental, wcag2a, wcag141 | failure, needs review | -| [no-autoplay-audio](https://dequeuniversity.com/rules/axe/4.1.1-daisy/no-autoplay-audio?application=RuleDescription) | Ensures <video> or <audio> elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio | Moderate | cat.time-and-media, wcag2a, wcag142, experimental | failure, needs review | -| [p-as-heading](https://dequeuniversity.com/rules/axe/4.1.1-daisy/p-as-heading?application=RuleDescription) | Ensure p elements are not used to style headings | Serious | cat.semantics, wcag2a, wcag131, experimental | failure | -| [table-fake-caption](https://dequeuniversity.com/rules/axe/4.1.1-daisy/table-fake-caption?application=RuleDescription) | Ensure that tables with a caption use the <caption> element. | Serious | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | -| [td-has-header](https://dequeuniversity.com/rules/axe/4.1.1-daisy/td-has-header?application=RuleDescription) | Ensure that each non-empty data cell in a large table has one or more table headers | Critical | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | +| [css-orientation-lock](https://dequeuniversity.com/rules/axe/4.1.2-daisy/css-orientation-lock?application=RuleDescription) | Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations | Serious | cat.structure, wcag134, wcag21aa, experimental | failure, needs review | +| [focus-order-semantics](https://dequeuniversity.com/rules/axe/4.1.2-daisy/focus-order-semantics?application=RuleDescription) | Ensures elements in the focus order have an appropriate role | Minor | cat.keyboard, best-practice, experimental | failure | +| [hidden-content](https://dequeuniversity.com/rules/axe/4.1.2-daisy/hidden-content?application=RuleDescription) | Informs users about hidden content. | Minor | cat.structure, experimental, review-item, best-practice | failure, needs review | +| [label-content-name-mismatch](https://dequeuniversity.com/rules/axe/4.1.2-daisy/label-content-name-mismatch?application=RuleDescription) | Ensures that elements labelled through their content must have their visible text as part of their accessible name | Serious | cat.semantics, wcag21a, wcag253, experimental | failure | +| [link-in-text-block](https://dequeuniversity.com/rules/axe/4.1.2-daisy/link-in-text-block?application=RuleDescription) | Links can be distinguished without relying on color | Serious | cat.color, experimental, wcag2a, wcag141 | failure, needs review | +| [no-autoplay-audio](https://dequeuniversity.com/rules/axe/4.1.2-daisy/no-autoplay-audio?application=RuleDescription) | Ensures <video> or <audio> elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio | Moderate | cat.time-and-media, wcag2a, wcag142, experimental | failure, needs review | +| [p-as-heading](https://dequeuniversity.com/rules/axe/4.1.2-daisy/p-as-heading?application=RuleDescription) | Ensure p elements are not used to style headings | Serious | cat.semantics, wcag2a, wcag131, experimental | failure | +| [table-fake-caption](https://dequeuniversity.com/rules/axe/4.1.2-daisy/table-fake-caption?application=RuleDescription) | Ensure that tables with a caption use the <caption> element. | Serious | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | +| [td-has-header](https://dequeuniversity.com/rules/axe/4.1.2-daisy/td-has-header?application=RuleDescription) | Ensure that each non-empty data cell in a large table has one or more table headers | Critical | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | ## Deprecated Rules From e04a57a715251f12d601183e19ded57e6ff79bdb Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Thu, 18 Feb 2021 12:58:04 +0000 Subject: [PATCH 10/20] ignore epub:type --- lib/commons/aria/get-element-unallowed-roles.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/commons/aria/get-element-unallowed-roles.js b/lib/commons/aria/get-element-unallowed-roles.js index d76b6767bf..7bf0a1a198 100644 --- a/lib/commons/aria/get-element-unallowed-roles.js +++ b/lib/commons/aria/get-element-unallowed-roles.js @@ -37,13 +37,14 @@ function getRoleSegments(node) { roles = roles.concat(nodeRoles); } - if (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type')) { - const epubRoles = tokenList( - node.getAttributeNS('http://www.idpf.org/2007/ops', 'type').toLowerCase() - ).map(role => `doc-${role}`); - - roles = roles.concat(epubRoles); - } + // EPUB epub:type should be ignored + // if (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type')) { + // const epubRoles = tokenList( + // node.getAttributeNS('http://www.idpf.org/2007/ops', 'type').toLowerCase() + // ).map(role => `doc-${role}`); + + // roles = roles.concat(epubRoles); + // } // filter invalid roles roles = roles.filter(role => isValidRole(role)); From 161d97e06c91b39e10ac4f92ea553d57de49e689 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 10 Mar 2021 12:08:00 +0000 Subject: [PATCH 11/20] Unit tests require package.json version without canary or arbitrary extension (e.g. 4.1.3-daisy.0) --- doc/rule-descriptions.md | 200 +++++++++++++++++++-------------------- package.json | 2 +- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 7a420605fd..4f143435d6 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -10,119 +10,119 @@ ## WCAG 2.0 Level A & AA Rules -| Rule ID | Description | Impact | Tags | Issue Type | -| :--------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ | :---------------- | :----------------------------------------------------------------------------------------- | :------------------------- | -| [area-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | -| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-command-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | -| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | -| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | -| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | -| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-required-children](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | -| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | -| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-roles](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure | -| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | -| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | failure, needs review | -| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | -| [audio-caption](https://dequeuniversity.com/rules/axe/4.1.2-daisy/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | -| [blink](https://dequeuniversity.com/rules/axe/4.1.2-daisy/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | -| [button-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | -| [bypass](https://dequeuniversity.com/rules/axe/4.1.2-daisy/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | failure | -| [color-contrast](https://dequeuniversity.com/rules/axe/4.1.2-daisy/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | -| [definition-list](https://dequeuniversity.com/rules/axe/4.1.2-daisy/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | -| [dlitem](https://dequeuniversity.com/rules/axe/4.1.2-daisy/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | -| [document-title](https://dequeuniversity.com/rules/axe/4.1.2-daisy/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | -| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.1.2-daisy/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | -| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.1.2-daisy/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | -| [duplicate-id](https://dequeuniversity.com/rules/axe/4.1.2-daisy/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | -| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.1.2-daisy/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | -| [frame-title](https://dequeuniversity.com/rules/axe/4.1.2-daisy/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a non-empty title attribute | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | -| [html-has-lang](https://dequeuniversity.com/rules/axe/4.1.2-daisy/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | -| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.1.2-daisy/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | -| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.1.2-daisy/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | -| [image-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [input-button-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | -| [input-image-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [label](https://dequeuniversity.com/rules/axe/4.1.2-daisy/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | -| [link-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | -| [list](https://dequeuniversity.com/rules/axe/4.1.2-daisy/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | -| [listitem](https://dequeuniversity.com/rules/axe/4.1.2-daisy/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | -| [marquee](https://dequeuniversity.com/rules/axe/4.1.2-daisy/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | -| [meta-refresh](https://dequeuniversity.com/rules/axe/4.1.2-daisy/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag2aaa, wcag221, wcag224, wcag325 | failure | -| [object-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | -| [role-img-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.1.2-daisy/scrollable-region-focusable?application=RuleDescription) | Elements that have scrollable content should be accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | -| [select-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | -| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.1.2-daisy/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | -| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/svg-img-alt?application=RuleDescription) | Ensures svg elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | -| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.1.2-daisy/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table using the headers refers to another cell in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | -| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.1.2-daisy/th-has-data-cells?application=RuleDescription) | Ensure that each table header in a data table refers to data cells | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | -| [valid-lang](https://dequeuniversity.com/rules/axe/4.1.2-daisy/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | -| [video-caption](https://dequeuniversity.com/rules/axe/4.1.2-daisy/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | +| Rule ID | Description | Impact | Tags | Issue Type | +| :------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ | :---------------- | :----------------------------------------------------------------------------------------- | :------------------------- | +| [area-alt](https://dequeuniversity.com/rules/axe/4.1/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | +| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.1/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-command-name](https://dequeuniversity.com/rules/axe/4.1/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.1/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.1/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | +| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.1/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | +| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.1/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | +| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.1/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | +| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.1/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-required-children](https://dequeuniversity.com/rules/axe/4.1/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | +| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.1/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | +| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.1/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-roles](https://dequeuniversity.com/rules/axe/4.1/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure | +| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.1/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | +| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.1/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.1/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | failure, needs review | +| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.1/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | +| [audio-caption](https://dequeuniversity.com/rules/axe/4.1/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | +| [blink](https://dequeuniversity.com/rules/axe/4.1/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | +| [button-name](https://dequeuniversity.com/rules/axe/4.1/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | +| [bypass](https://dequeuniversity.com/rules/axe/4.1/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | failure | +| [color-contrast](https://dequeuniversity.com/rules/axe/4.1/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | +| [definition-list](https://dequeuniversity.com/rules/axe/4.1/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | +| [dlitem](https://dequeuniversity.com/rules/axe/4.1/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | +| [document-title](https://dequeuniversity.com/rules/axe/4.1/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | +| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.1/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | +| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.1/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | +| [duplicate-id](https://dequeuniversity.com/rules/axe/4.1/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | +| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.1/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | +| [frame-title](https://dequeuniversity.com/rules/axe/4.1/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a non-empty title attribute | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | +| [html-has-lang](https://dequeuniversity.com/rules/axe/4.1/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | +| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.1/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | +| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.1/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | +| [image-alt](https://dequeuniversity.com/rules/axe/4.1/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [input-button-name](https://dequeuniversity.com/rules/axe/4.1/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | +| [input-image-alt](https://dequeuniversity.com/rules/axe/4.1/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [label](https://dequeuniversity.com/rules/axe/4.1/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | +| [link-name](https://dequeuniversity.com/rules/axe/4.1/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | +| [list](https://dequeuniversity.com/rules/axe/4.1/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | +| [listitem](https://dequeuniversity.com/rules/axe/4.1/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | +| [marquee](https://dequeuniversity.com/rules/axe/4.1/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | +| [meta-refresh](https://dequeuniversity.com/rules/axe/4.1/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag2aaa, wcag221, wcag224, wcag325 | failure | +| [object-alt](https://dequeuniversity.com/rules/axe/4.1/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | +| [role-img-alt](https://dequeuniversity.com/rules/axe/4.1/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.1/scrollable-region-focusable?application=RuleDescription) | Elements that have scrollable content should be accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | +| [select-name](https://dequeuniversity.com/rules/axe/4.1/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | +| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.1/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | +| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.1/svg-img-alt?application=RuleDescription) | Ensures svg elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | +| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.1/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table using the headers refers to another cell in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | +| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.1/th-has-data-cells?application=RuleDescription) | Ensure that each table header in a data table refers to data cells | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | +| [valid-lang](https://dequeuniversity.com/rules/axe/4.1/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | +| [video-caption](https://dequeuniversity.com/rules/axe/4.1/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | ## WCAG 2.1 Level A & AA Rules -| Rule ID | Description | Impact | Tags | Issue Type | -| :------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :------ | :-------------------------------- | :--------- | -| [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.1.2-daisy/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | failure | -| [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.1.2-daisy/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412 | failure | +| Rule ID | Description | Impact | Tags | Issue Type | +| :----------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :------ | :-------------------------------- | :--------- | +| [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.1/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | failure | +| [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.1/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412 | failure | ## Best Practices Rules Rules that do not necessarily conform to WCAG success criterion but are industry accepted practices that improve the user experience. -| Rule ID | Description | Impact | Tags | Issue Type | -| :------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- | :----------------- | :---------------------------------------------- | :------------------------- | -| [accesskeys](https://dequeuniversity.com/rules/axe/4.1.2-daisy/accesskeys?application=RuleDescription) | Ensures every accesskey attribute value is unique | Serious | cat.keyboard, best-practice | failure | -| [aria-allowed-role](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-allowed-role?application=RuleDescription) | Ensures role attribute has an appropriate value for the element | Minor | cat.aria, best-practice | failure, needs review | -| [aria-dialog-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-dialog-name?application=RuleDescription) | Ensures every ARIA dialog and alertdialog node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | -| [aria-treeitem-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/aria-treeitem-name?application=RuleDescription) | Ensures every ARIA treeitem node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | -| [empty-heading](https://dequeuniversity.com/rules/axe/4.1.2-daisy/empty-heading?application=RuleDescription) | Ensures headings have discernible text | Minor | cat.name-role-value, best-practice | failure, needs review | -| [frame-tested](https://dequeuniversity.com/rules/axe/4.1.2-daisy/frame-tested?application=RuleDescription) | Ensures <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, review-item, best-practice | failure, needs review | -| [frame-title-unique](https://dequeuniversity.com/rules/axe/4.1.2-daisy/frame-title-unique?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, best-practice | failure | -| [heading-order](https://dequeuniversity.com/rules/axe/4.1.2-daisy/heading-order?application=RuleDescription) | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | failure | -| [identical-links-same-purpose](https://dequeuniversity.com/rules/axe/4.1.2-daisy/identical-links-same-purpose?application=RuleDescription) | Ensure that links with the same accessible name serve a similar purpose | Minor | cat.semantics, wcag2aaa, wcag249, best-practice | needs review | -| [image-redundant-alt](https://dequeuniversity.com/rules/axe/4.1.2-daisy/image-redundant-alt?application=RuleDescription) | Ensure image alternative is not repeated as text | Minor | cat.text-alternatives, best-practice | failure | -| [label-title-only](https://dequeuniversity.com/rules/axe/4.1.2-daisy/label-title-only?application=RuleDescription) | Ensures that every form element is not solely labeled using the title or aria-describedby attributes | Serious | cat.forms, best-practice | failure | -| [landmark-banner-is-top-level](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-banner-is-top-level?application=RuleDescription) | Ensures the banner landmark is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-complementary-is-top-level](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-complementary-is-top-level?application=RuleDescription) | Ensures the complementary landmark or aside is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-contentinfo-is-top-level](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-contentinfo-is-top-level?application=RuleDescription) | Ensures the contentinfo landmark is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-main-is-top-level](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-main-is-top-level?application=RuleDescription) | Ensures the main landmark is at top level | Moderate | cat.semantics, best-practice | failure | -| [landmark-no-duplicate-banner](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-no-duplicate-banner?application=RuleDescription) | Ensures the document has at most one banner landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-no-duplicate-contentinfo](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-no-duplicate-contentinfo?application=RuleDescription) | Ensures the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-no-duplicate-main](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-no-duplicate-main?application=RuleDescription) | Ensures the document has at most one main landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-one-main](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-one-main?application=RuleDescription) | Ensures the document has a main landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-unique](https://dequeuniversity.com/rules/axe/4.1.2-daisy/landmark-unique?application=RuleDescription) | Landmarks must have a unique role or role/label/title (i.e. accessible name) combination | Moderate | cat.semantics, best-practice | failure | -| [meta-viewport-large](https://dequeuniversity.com/rules/axe/4.1.2-daisy/meta-viewport-large?application=RuleDescription) | Ensures <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | failure | -| [meta-viewport](https://dequeuniversity.com/rules/axe/4.1.2-daisy/meta-viewport?application=RuleDescription) | Ensures <meta name="viewport"> does not disable text scaling and zooming | Critical | cat.sensory-and-visual-cues, best-practice, ACT | failure | -| [page-has-heading-one](https://dequeuniversity.com/rules/axe/4.1.2-daisy/page-has-heading-one?application=RuleDescription) | Ensure that the page, or at least one of its frames contains a level-one heading | Moderate | cat.semantics, best-practice | failure | -| [presentation-role-conflict](https://dequeuniversity.com/rules/axe/4.1.2-daisy/presentation-role-conflict?application=RuleDescription) | Flags elements whose role is none or presentation and which cause the role conflict resolution to trigger. | Minor | cat.aria, best-practice | failure | -| [region](https://dequeuniversity.com/rules/axe/4.1.2-daisy/region?application=RuleDescription) | Ensures all page content is contained by landmarks | Moderate | cat.keyboard, best-practice | failure | -| [scope-attr-valid](https://dequeuniversity.com/rules/axe/4.1.2-daisy/scope-attr-valid?application=RuleDescription) | Ensures the scope attribute is used correctly on tables | Moderate, Critical | cat.tables, best-practice | failure | -| [skip-link](https://dequeuniversity.com/rules/axe/4.1.2-daisy/skip-link?application=RuleDescription) | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice | failure, needs review | -| [tabindex](https://dequeuniversity.com/rules/axe/4.1.2-daisy/tabindex?application=RuleDescription) | Ensures tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | failure | -| [table-duplicate-name](https://dequeuniversity.com/rules/axe/4.1.2-daisy/table-duplicate-name?application=RuleDescription) | Ensure that tables do not have the same summary and caption | Minor | cat.tables, best-practice | failure | +| Rule ID | Description | Impact | Tags | Issue Type | +| :----------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- | :----------------- | :---------------------------------------------- | :------------------------- | +| [accesskeys](https://dequeuniversity.com/rules/axe/4.1/accesskeys?application=RuleDescription) | Ensures every accesskey attribute value is unique | Serious | cat.keyboard, best-practice | failure | +| [aria-allowed-role](https://dequeuniversity.com/rules/axe/4.1/aria-allowed-role?application=RuleDescription) | Ensures role attribute has an appropriate value for the element | Minor | cat.aria, best-practice | failure, needs review | +| [aria-dialog-name](https://dequeuniversity.com/rules/axe/4.1/aria-dialog-name?application=RuleDescription) | Ensures every ARIA dialog and alertdialog node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | +| [aria-treeitem-name](https://dequeuniversity.com/rules/axe/4.1/aria-treeitem-name?application=RuleDescription) | Ensures every ARIA treeitem node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | +| [empty-heading](https://dequeuniversity.com/rules/axe/4.1/empty-heading?application=RuleDescription) | Ensures headings have discernible text | Minor | cat.name-role-value, best-practice | failure, needs review | +| [frame-tested](https://dequeuniversity.com/rules/axe/4.1/frame-tested?application=RuleDescription) | Ensures <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, review-item, best-practice | failure, needs review | +| [frame-title-unique](https://dequeuniversity.com/rules/axe/4.1/frame-title-unique?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, best-practice | failure | +| [heading-order](https://dequeuniversity.com/rules/axe/4.1/heading-order?application=RuleDescription) | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | failure | +| [identical-links-same-purpose](https://dequeuniversity.com/rules/axe/4.1/identical-links-same-purpose?application=RuleDescription) | Ensure that links with the same accessible name serve a similar purpose | Minor | cat.semantics, wcag2aaa, wcag249, best-practice | needs review | +| [image-redundant-alt](https://dequeuniversity.com/rules/axe/4.1/image-redundant-alt?application=RuleDescription) | Ensure image alternative is not repeated as text | Minor | cat.text-alternatives, best-practice | failure | +| [label-title-only](https://dequeuniversity.com/rules/axe/4.1/label-title-only?application=RuleDescription) | Ensures that every form element is not solely labeled using the title or aria-describedby attributes | Serious | cat.forms, best-practice | failure | +| [landmark-banner-is-top-level](https://dequeuniversity.com/rules/axe/4.1/landmark-banner-is-top-level?application=RuleDescription) | Ensures the banner landmark is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-complementary-is-top-level](https://dequeuniversity.com/rules/axe/4.1/landmark-complementary-is-top-level?application=RuleDescription) | Ensures the complementary landmark or aside is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-contentinfo-is-top-level](https://dequeuniversity.com/rules/axe/4.1/landmark-contentinfo-is-top-level?application=RuleDescription) | Ensures the contentinfo landmark is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-main-is-top-level](https://dequeuniversity.com/rules/axe/4.1/landmark-main-is-top-level?application=RuleDescription) | Ensures the main landmark is at top level | Moderate | cat.semantics, best-practice | failure | +| [landmark-no-duplicate-banner](https://dequeuniversity.com/rules/axe/4.1/landmark-no-duplicate-banner?application=RuleDescription) | Ensures the document has at most one banner landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-no-duplicate-contentinfo](https://dequeuniversity.com/rules/axe/4.1/landmark-no-duplicate-contentinfo?application=RuleDescription) | Ensures the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-no-duplicate-main](https://dequeuniversity.com/rules/axe/4.1/landmark-no-duplicate-main?application=RuleDescription) | Ensures the document has at most one main landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-one-main](https://dequeuniversity.com/rules/axe/4.1/landmark-one-main?application=RuleDescription) | Ensures the document has a main landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-unique](https://dequeuniversity.com/rules/axe/4.1/landmark-unique?application=RuleDescription) | Landmarks must have a unique role or role/label/title (i.e. accessible name) combination | Moderate | cat.semantics, best-practice | failure | +| [meta-viewport-large](https://dequeuniversity.com/rules/axe/4.1/meta-viewport-large?application=RuleDescription) | Ensures <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | failure | +| [meta-viewport](https://dequeuniversity.com/rules/axe/4.1/meta-viewport?application=RuleDescription) | Ensures <meta name="viewport"> does not disable text scaling and zooming | Critical | cat.sensory-and-visual-cues, best-practice, ACT | failure | +| [page-has-heading-one](https://dequeuniversity.com/rules/axe/4.1/page-has-heading-one?application=RuleDescription) | Ensure that the page, or at least one of its frames contains a level-one heading | Moderate | cat.semantics, best-practice | failure | +| [presentation-role-conflict](https://dequeuniversity.com/rules/axe/4.1/presentation-role-conflict?application=RuleDescription) | Flags elements whose role is none or presentation and which cause the role conflict resolution to trigger. | Minor | cat.aria, best-practice | failure | +| [region](https://dequeuniversity.com/rules/axe/4.1/region?application=RuleDescription) | Ensures all page content is contained by landmarks | Moderate | cat.keyboard, best-practice | failure | +| [scope-attr-valid](https://dequeuniversity.com/rules/axe/4.1/scope-attr-valid?application=RuleDescription) | Ensures the scope attribute is used correctly on tables | Moderate, Critical | cat.tables, best-practice | failure | +| [skip-link](https://dequeuniversity.com/rules/axe/4.1/skip-link?application=RuleDescription) | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice | failure, needs review | +| [tabindex](https://dequeuniversity.com/rules/axe/4.1/tabindex?application=RuleDescription) | Ensures tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | failure | +| [table-duplicate-name](https://dequeuniversity.com/rules/axe/4.1/table-duplicate-name?application=RuleDescription) | Ensure that tables do not have the same summary and caption | Minor | cat.tables, best-practice | failure | ## Experimental Rules Rules we are still testing and developing. They are not enabled by default in axe-core, but are enabled for the axe browser extensions. -| Rule ID | Description | Impact | Tags | Issue Type | -| :--------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------- | :------------------------- | -| [css-orientation-lock](https://dequeuniversity.com/rules/axe/4.1.2-daisy/css-orientation-lock?application=RuleDescription) | Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations | Serious | cat.structure, wcag134, wcag21aa, experimental | failure, needs review | -| [focus-order-semantics](https://dequeuniversity.com/rules/axe/4.1.2-daisy/focus-order-semantics?application=RuleDescription) | Ensures elements in the focus order have an appropriate role | Minor | cat.keyboard, best-practice, experimental | failure | -| [hidden-content](https://dequeuniversity.com/rules/axe/4.1.2-daisy/hidden-content?application=RuleDescription) | Informs users about hidden content. | Minor | cat.structure, experimental, review-item, best-practice | failure, needs review | -| [label-content-name-mismatch](https://dequeuniversity.com/rules/axe/4.1.2-daisy/label-content-name-mismatch?application=RuleDescription) | Ensures that elements labelled through their content must have their visible text as part of their accessible name | Serious | cat.semantics, wcag21a, wcag253, experimental | failure | -| [link-in-text-block](https://dequeuniversity.com/rules/axe/4.1.2-daisy/link-in-text-block?application=RuleDescription) | Links can be distinguished without relying on color | Serious | cat.color, experimental, wcag2a, wcag141 | failure, needs review | -| [no-autoplay-audio](https://dequeuniversity.com/rules/axe/4.1.2-daisy/no-autoplay-audio?application=RuleDescription) | Ensures <video> or <audio> elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio | Moderate | cat.time-and-media, wcag2a, wcag142, experimental | failure, needs review | -| [p-as-heading](https://dequeuniversity.com/rules/axe/4.1.2-daisy/p-as-heading?application=RuleDescription) | Ensure p elements are not used to style headings | Serious | cat.semantics, wcag2a, wcag131, experimental | failure | -| [table-fake-caption](https://dequeuniversity.com/rules/axe/4.1.2-daisy/table-fake-caption?application=RuleDescription) | Ensure that tables with a caption use the <caption> element. | Serious | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | -| [td-has-header](https://dequeuniversity.com/rules/axe/4.1.2-daisy/td-has-header?application=RuleDescription) | Ensure that each non-empty data cell in a large table has one or more table headers | Critical | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | +| Rule ID | Description | Impact | Tags | Issue Type | +| :------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------- | :------------------------- | +| [css-orientation-lock](https://dequeuniversity.com/rules/axe/4.1/css-orientation-lock?application=RuleDescription) | Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations | Serious | cat.structure, wcag134, wcag21aa, experimental | failure, needs review | +| [focus-order-semantics](https://dequeuniversity.com/rules/axe/4.1/focus-order-semantics?application=RuleDescription) | Ensures elements in the focus order have an appropriate role | Minor | cat.keyboard, best-practice, experimental | failure | +| [hidden-content](https://dequeuniversity.com/rules/axe/4.1/hidden-content?application=RuleDescription) | Informs users about hidden content. | Minor | cat.structure, experimental, review-item, best-practice | failure, needs review | +| [label-content-name-mismatch](https://dequeuniversity.com/rules/axe/4.1/label-content-name-mismatch?application=RuleDescription) | Ensures that elements labelled through their content must have their visible text as part of their accessible name | Serious | cat.semantics, wcag21a, wcag253, experimental | failure | +| [link-in-text-block](https://dequeuniversity.com/rules/axe/4.1/link-in-text-block?application=RuleDescription) | Links can be distinguished without relying on color | Serious | cat.color, experimental, wcag2a, wcag141 | failure, needs review | +| [no-autoplay-audio](https://dequeuniversity.com/rules/axe/4.1/no-autoplay-audio?application=RuleDescription) | Ensures <video> or <audio> elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio | Moderate | cat.time-and-media, wcag2a, wcag142, experimental | failure, needs review | +| [p-as-heading](https://dequeuniversity.com/rules/axe/4.1/p-as-heading?application=RuleDescription) | Ensure p elements are not used to style headings | Serious | cat.semantics, wcag2a, wcag131, experimental | failure | +| [table-fake-caption](https://dequeuniversity.com/rules/axe/4.1/table-fake-caption?application=RuleDescription) | Ensure that tables with a caption use the <caption> element. | Serious | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | +| [td-has-header](https://dequeuniversity.com/rules/axe/4.1/td-has-header?application=RuleDescription) | Ensure that each non-empty data cell in a large table has one or more table headers | Critical | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | failure | ## Deprecated Rules diff --git a/package.json b/package.json index 6232d36cb5..177a586270 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@daisy/axe-core-for-ace", "description": "Accessibility engine for automated Web UI testing", - "version": "4.1.3-daisy.0", + "version": "4.1.3", "license": "MPL-2.0", "engines": { "node": ">=4" From 2a6ab7e75adaf45438dcff81ed910a573aea6253 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 10 Mar 2021 18:20:24 +0000 Subject: [PATCH 12/20] landmark-one-main now with page-no-duplicate-main in addition to page-has-main (DAISY Ace) --- lib/rules/landmark-one-main.json | 6 +-- .../frames/level1-fail1.html | 15 ++++++ .../landmark-one-main-fail.js | 4 +- .../landmark-one-main-fail1.html | 29 ++++++++++++ .../landmark-one-main-fail1.js | 47 +++++++++++++++++++ .../landmark-one-main-fail2.html | 34 ++++++++++++++ .../landmark-one-main-fail2.js | 47 +++++++++++++++++++ .../landmark-one-main-pass1.js | 2 +- .../landmark-one-main-pass2.js | 2 +- .../landmark-one-main-pass3.js | 2 +- 10 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 test/integration/full/landmark-one-main/frames/level1-fail1.html create mode 100644 test/integration/full/landmark-one-main/landmark-one-main-fail1.html create mode 100644 test/integration/full/landmark-one-main/landmark-one-main-fail1.js create mode 100644 test/integration/full/landmark-one-main/landmark-one-main-fail2.html create mode 100644 test/integration/full/landmark-one-main/landmark-one-main-fail2.js diff --git a/lib/rules/landmark-one-main.json b/lib/rules/landmark-one-main.json index 533cae06e9..22b9f486ba 100644 --- a/lib/rules/landmark-one-main.json +++ b/lib/rules/landmark-one-main.json @@ -3,10 +3,10 @@ "selector": "html", "tags": ["cat.semantics", "best-practice"], "metadata": { - "description": "Ensures the document has a main landmark", - "help": "Document must have one main landmark" + "description": "Ensures the document has a unique main landmark", + "help": "Document must have one unique main landmark" }, - "all": ["page-has-main"], + "all": ["page-has-main", "page-no-duplicate-main"], "any": [], "none": [] } diff --git a/test/integration/full/landmark-one-main/frames/level1-fail1.html b/test/integration/full/landmark-one-main/frames/level1-fail1.html new file mode 100644 index 0000000000..e2e2899da4 --- /dev/null +++ b/test/integration/full/landmark-one-main/frames/level1-fail1.html @@ -0,0 +1,15 @@ + + + + + + + +
+

Main landmark 1 created with main tag

+
+
+

Main landmark 2 created with main tag

+
+ + diff --git a/test/integration/full/landmark-one-main/landmark-one-main-fail.js b/test/integration/full/landmark-one-main/landmark-one-main-fail.js index 8bac6b994e..7af7f36de8 100644 --- a/test/integration/full/landmark-one-main/landmark-one-main-fail.js +++ b/test/integration/full/landmark-one-main/landmark-one-main-fail.js @@ -15,11 +15,11 @@ describe('landmark-one-main test failure', function() { }); describe('violations', function() { - it('should find 1', function() { + it('should find 2', function() { assert.lengthOf(results.violations[0].nodes, 2); }); - it('should find #frame1', function() { + it('should find #fail1', function() { assert.deepEqual(results.violations[0].nodes[0].target, ['#fail1']); }); diff --git a/test/integration/full/landmark-one-main/landmark-one-main-fail1.html b/test/integration/full/landmark-one-main/landmark-one-main-fail1.html new file mode 100644 index 0000000000..37d3a2999b --- /dev/null +++ b/test/integration/full/landmark-one-main/landmark-one-main-fail1.html @@ -0,0 +1,29 @@ + + + + + + + + + + + +

No main content here

+ +
+ + + + + diff --git a/test/integration/full/landmark-one-main/landmark-one-main-fail1.js b/test/integration/full/landmark-one-main/landmark-one-main-fail1.js new file mode 100644 index 0000000000..d31bc95b7b --- /dev/null +++ b/test/integration/full/landmark-one-main/landmark-one-main-fail1.js @@ -0,0 +1,47 @@ +describe('landmark-one-main test failure 1', function() { + 'use strict'; + var results; + before(function(done) { + axe.testUtils.awaitNestedLoad(function() { + axe.run( + { runOnly: { type: 'rule', values: ['landmark-one-main'] } }, + function(err, r) { + assert.isNull(err); + results = r; + done(); + } + ); + }); + }); + + describe('violations', function() { + it('should find 1', function() { + assert.lengthOf(results.violations[0].nodes, 1); + }); + + it('should find #frame1, #violation2', function() { + assert.deepEqual(results.violations[0].nodes[0].target, [ + '#frame1', + '#violation2' + ]); + }); + }); + + describe('passes', function() { + it('should find 1', function() { + assert.lengthOf(results.passes[0].nodes, 1); + }); + + it('should find #pass1', function() { + assert.deepEqual(results.passes[0].nodes[0].target, ['#pass1']); + }); + }); + + it('should find 0 inapplicable', function() { + assert.lengthOf(results.inapplicable, 0); + }); + + it('should find 0 incomplete', function() { + assert.lengthOf(results.incomplete, 0); + }); +}); diff --git a/test/integration/full/landmark-one-main/landmark-one-main-fail2.html b/test/integration/full/landmark-one-main/landmark-one-main-fail2.html new file mode 100644 index 0000000000..ef1dabaa64 --- /dev/null +++ b/test/integration/full/landmark-one-main/landmark-one-main-fail2.html @@ -0,0 +1,34 @@ + + + + + + + + + + + +
+

Main landmark 1 created with main tag

+
+
+

Main landmark 2 created with main tag

+
+ +
+ + + + + diff --git a/test/integration/full/landmark-one-main/landmark-one-main-fail2.js b/test/integration/full/landmark-one-main/landmark-one-main-fail2.js new file mode 100644 index 0000000000..8b56a4f975 --- /dev/null +++ b/test/integration/full/landmark-one-main/landmark-one-main-fail2.js @@ -0,0 +1,47 @@ +describe('landmark-one-main test failure 2', function() { + 'use strict'; + var results; + before(function(done) { + axe.testUtils.awaitNestedLoad(function() { + axe.run( + { runOnly: { type: 'rule', values: ['landmark-one-main'] } }, + function(err, r) { + assert.isNull(err); + results = r; + done(); + } + ); + }); + }); + + describe('violations', function() { + it('should find 1', function() { + assert.lengthOf(results.violations[0].nodes, 1); + }); + + it('should find #fail1', function() { + assert.deepEqual(results.violations[0].nodes[0].target, ['#fail1']); + }); + }); + + describe('passes', function() { + it('should find 1', function() { + assert.lengthOf(results.passes[0].nodes, 1); + }); + + it('should find #frame1 #pass3', function() { + assert.deepEqual(results.passes[0].nodes[0].target, [ + '#frame1', + '#pass3' + ]); + }); + }); + + it('should find 0 inapplicable', function() { + assert.lengthOf(results.inapplicable, 0); + }); + + it('should find 0 incomplete', function() { + assert.lengthOf(results.incomplete, 0); + }); +}); diff --git a/test/integration/full/landmark-one-main/landmark-one-main-pass1.js b/test/integration/full/landmark-one-main/landmark-one-main-pass1.js index 3e5eab4640..5c20e0f648 100644 --- a/test/integration/full/landmark-one-main/landmark-one-main-pass1.js +++ b/test/integration/full/landmark-one-main/landmark-one-main-pass1.js @@ -1,4 +1,4 @@ -describe('landmark-one-main test pass', function() { +describe('landmark-one-main test pass 1', function() { 'use strict'; var results; before(function(done) { diff --git a/test/integration/full/landmark-one-main/landmark-one-main-pass2.js b/test/integration/full/landmark-one-main/landmark-one-main-pass2.js index e18612ebb1..964aaa7efc 100644 --- a/test/integration/full/landmark-one-main/landmark-one-main-pass2.js +++ b/test/integration/full/landmark-one-main/landmark-one-main-pass2.js @@ -1,4 +1,4 @@ -describe('landmark-one-main test pass', function() { +describe('landmark-one-main test pass 2', function() { 'use strict'; var results; before(function(done) { diff --git a/test/integration/full/landmark-one-main/landmark-one-main-pass3.js b/test/integration/full/landmark-one-main/landmark-one-main-pass3.js index e18612ebb1..5105a5ba5c 100644 --- a/test/integration/full/landmark-one-main/landmark-one-main-pass3.js +++ b/test/integration/full/landmark-one-main/landmark-one-main-pass3.js @@ -1,4 +1,4 @@ -describe('landmark-one-main test pass', function() { +describe('landmark-one-main test pass 3', function() { 'use strict'; var results; before(function(done) { From dae726f57480f8799cc1098a7d4fb31d10472820 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 10 Mar 2021 18:24:40 +0000 Subject: [PATCH 13/20] doc: landmark-one-main now with page-no-duplicate-main in addition to page-has-main (DAISY Ace) --- doc/rule-descriptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 4f143435d6..7da8f17bd9 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -96,7 +96,7 @@ Rules that do not necessarily conform to WCAG success criterion but are industry | [landmark-no-duplicate-banner](https://dequeuniversity.com/rules/axe/4.1/landmark-no-duplicate-banner?application=RuleDescription) | Ensures the document has at most one banner landmark | Moderate | cat.semantics, best-practice | failure | | [landmark-no-duplicate-contentinfo](https://dequeuniversity.com/rules/axe/4.1/landmark-no-duplicate-contentinfo?application=RuleDescription) | Ensures the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | failure | | [landmark-no-duplicate-main](https://dequeuniversity.com/rules/axe/4.1/landmark-no-duplicate-main?application=RuleDescription) | Ensures the document has at most one main landmark | Moderate | cat.semantics, best-practice | failure | -| [landmark-one-main](https://dequeuniversity.com/rules/axe/4.1/landmark-one-main?application=RuleDescription) | Ensures the document has a main landmark | Moderate | cat.semantics, best-practice | failure | +| [landmark-one-main](https://dequeuniversity.com/rules/axe/4.1/landmark-one-main?application=RuleDescription) | Ensures the document has a unique main landmark | Moderate | cat.semantics, best-practice | failure | | [landmark-unique](https://dequeuniversity.com/rules/axe/4.1/landmark-unique?application=RuleDescription) | Landmarks must have a unique role or role/label/title (i.e. accessible name) combination | Moderate | cat.semantics, best-practice | failure | | [meta-viewport-large](https://dequeuniversity.com/rules/axe/4.1/meta-viewport-large?application=RuleDescription) | Ensures <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | failure | | [meta-viewport](https://dequeuniversity.com/rules/axe/4.1/meta-viewport?application=RuleDescription) | Ensures <meta name="viewport"> does not disable text scaling and zooming | Critical | cat.sensory-and-visual-cues, best-practice, ACT | failure | From 2b5bb2d1f990644d731109f37a921cc3bba449c1 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 10 Mar 2021 18:26:17 +0000 Subject: [PATCH 14/20] intermediary commit (Axe hook seems to stash things in the working copy ... so I need to test a full commit) --- build/test/get-test-urls.js | 46 ++++++++++--------- .../aria/aria-required-children-evaluate.js | 21 ++++++--- lib/checks/lists/listitem-evaluate.js | 12 +++-- lib/checks/lists/only-listitems-evaluate.js | 12 +++-- .../aria/get-element-unallowed-roles.js | 2 +- 5 files changed, 56 insertions(+), 37 deletions(-) diff --git a/build/test/get-test-urls.js b/build/test/get-test-urls.js index d267895db8..07eb3e782a 100644 --- a/build/test/get-test-urls.js +++ b/build/test/get-test-urls.js @@ -2,33 +2,35 @@ const globby = require('globby'); const getTestUrls = async (host = `localhost`, port = `9876`) => { const urls = [ - /** - * Unit tests -> Core - */ - `http://${host}:${port}/test/core/`, - /** - * Unit tests -> Checks - */ - `http://${host}:${port}/test/checks/`, - /** - * Unit tests -> Matches - */ - `http://${host}:${port}/test/rule-matches/`, - /** - * Unit tests -> Commons - */ - `http://${host}:${port}/test/commons/`, - /** - * Integration tests -> rules - */ - `http://${host}:${port}/test/integration/rules`, + // /** + // * Unit tests -> Core + // */ + // `http://${host}:${port}/test/core/`, + // /** + // * Unit tests -> Checks + // */ + // `http://${host}:${port}/test/checks/`, + // /** + // * Unit tests -> Matches + // */ + // `http://${host}:${port}/test/rule-matches/`, + // /** + // * Unit tests -> Commons + // */ + // `http://${host}:${port}/test/commons/`, + // /** + // * Integration tests -> rules + // */ + // `http://${host}:${port}/test/integration/rules`, /** * Integration tests -> full */ ...( await globby([ - 'test/integration/full/**/*.html', - '!test/integration/full/**/frames/**/*.html' + 'test/integration/full/landmark-one-main/**/*.html', + '!test/integration/full/landmark-one-main/**/frames/**/*.html' + // 'test/integration/full/**/*.html', + // '!test/integration/full/**/frames/**/*.html' ]) ).map(file => `http://${host}:${port}/${file}`) ]; diff --git a/lib/checks/aria/aria-required-children-evaluate.js b/lib/checks/aria/aria-required-children-evaluate.js index fdce5b330b..859f54c5b5 100644 --- a/lib/checks/aria/aria-required-children-evaluate.js +++ b/lib/checks/aria/aria-required-children-evaluate.js @@ -10,22 +10,29 @@ import { hasContentVirtual, idrefs } from '../../commons/dom'; * Get all owned roles of an element */ function getOwnedRoles(virtualNode) { - const parentRole = getRole(virtualNode, { dpub: true }); + // DAISY-AXE + // const parentRole = getRole(virtualNode, { dpub: true }); const ownedRoles = []; const ownedElements = getOwnedVirtual(virtualNode); for (let i = 0; i < ownedElements.length; i++) { let ownedElement = ownedElements[i]; - let role = getRole(ownedElement, { dpub: true }); + + // DAISY-AXE + // let role = getRole(ownedElement, { dpub: true }); + let role = getRole(ownedElement); // if owned node has no role or is presentational we keep // parsing the descendant tree. this means intermediate roles // between a required parent and child will fail the check - if ( - ['presentation', 'none', null].includes(role) || - (['list'].includes(role) && - ['doc-bibliography', 'doc-endnotes'].includes(parentRole)) - ) { + + // DAISY-AXE + // if ( + // ['presentation', 'none', null].includes(role) || + // (['list'].includes(role) && + // ['doc-bibliography', 'doc-endnotes'].includes(parentRole)) + // ) { + if (['presentation', 'none', null].includes(role)) { ownedElements.push(...ownedElement.children); } else if (role) { ownedRoles.push(role); diff --git a/lib/checks/lists/listitem-evaluate.js b/lib/checks/lists/listitem-evaluate.js index b00c140276..bcfdc3b5d1 100644 --- a/lib/checks/lists/listitem-evaluate.js +++ b/lib/checks/lists/listitem-evaluate.js @@ -1,5 +1,8 @@ import { getComposedParent } from '../../commons/dom'; -import { getRoleType, isValidRole } from '../../commons/aria'; + +// DAISY-AXE +// import { getRoleType, isValidRole } from '../../commons/aria'; +import { isValidRole } from '../../commons/aria'; function listitemEvaluate(node) { const parent = getComposedParent(node); @@ -16,9 +19,10 @@ function listitemEvaluate(node) { } if (parentRole && isValidRole(parentRole)) { - if (getRoleType(parentRole) === 'list') { - return true; - } + // DAISY-AXE + // if (getRoleType(parentRole) === 'list') { + // return true; + // } this.data({ messageKey: 'roleNotValid' diff --git a/lib/checks/lists/only-listitems-evaluate.js b/lib/checks/lists/only-listitems-evaluate.js index 1e76ef6ada..1906a2e637 100644 --- a/lib/checks/lists/only-listitems-evaluate.js +++ b/lib/checks/lists/only-listitems-evaluate.js @@ -1,5 +1,8 @@ import { isVisible } from '../../commons/dom'; -import { getRole, getRoleType } from '../../commons/aria'; + +// DAISY-AXE +// import { getRole, getRoleType } from '../../commons/aria'; +import { getRole } from '../../commons/aria'; function onlyListitemsEvaluate(node, options, virtualNode) { let hasNonEmptyTextNode = false; @@ -24,8 +27,11 @@ function onlyListitemsEvaluate(node, options, virtualNode) { isEmpty = false; const isLi = actualNode.nodeName.toUpperCase() === 'LI'; const role = getRole(vNode); - const isListItemRole = - role === 'listitem' || getRoleType(role) === 'listitem'; + + // DAISY-AXE + // const isListItemRole = + // role === 'listitem' || getRoleType(role) === 'listitem'; + const isListItemRole = role === 'listitem'; if (!isLi && !isListItemRole) { badNodes.push(actualNode); diff --git a/lib/commons/aria/get-element-unallowed-roles.js b/lib/commons/aria/get-element-unallowed-roles.js index 7bf0a1a198..d15f75db05 100644 --- a/lib/commons/aria/get-element-unallowed-roles.js +++ b/lib/commons/aria/get-element-unallowed-roles.js @@ -37,7 +37,7 @@ function getRoleSegments(node) { roles = roles.concat(nodeRoles); } - // EPUB epub:type should be ignored + // DAISY-AXE (EPUB epub:type should be ignored) // if (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type')) { // const epubRoles = tokenList( // node.getAttributeNS('http://www.idpf.org/2007/ops', 'type').toLowerCase() From 6121f22de8e2d2dd9ea18bb6dc7553db10a4a74a Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 10 Mar 2021 18:36:21 +0000 Subject: [PATCH 15/20] main element and div with role --- .../full/landmark-one-main/frames/level1-fail1.html | 6 +++--- .../full/landmark-one-main/landmark-one-main-fail2.html | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/integration/full/landmark-one-main/frames/level1-fail1.html b/test/integration/full/landmark-one-main/frames/level1-fail1.html index e2e2899da4..1ad1fa5aff 100644 --- a/test/integration/full/landmark-one-main/frames/level1-fail1.html +++ b/test/integration/full/landmark-one-main/frames/level1-fail1.html @@ -8,8 +8,8 @@

Main landmark 1 created with main tag

-
-

Main landmark 2 created with main tag

-
+
+

Main landmark 2 created with main role

+
diff --git a/test/integration/full/landmark-one-main/landmark-one-main-fail2.html b/test/integration/full/landmark-one-main/landmark-one-main-fail2.html index ef1dabaa64..d76ea3fd5e 100644 --- a/test/integration/full/landmark-one-main/landmark-one-main-fail2.html +++ b/test/integration/full/landmark-one-main/landmark-one-main-fail2.html @@ -19,9 +19,9 @@ -
-

Main landmark 1 created with main tag

-
+
+

Main landmark 2 created with main role

+

Main landmark 2 created with main tag

From 10be613bfc67dcd95901e23afd5b43d92b16bd7b Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 10 Mar 2021 18:47:21 +0000 Subject: [PATCH 16/20] added unit test for landmark-no-duplicate-main to pass content with no main landmark at all --- build/test/get-test-urls.js | 4 +- .../frames/level1-1.html | 10 +++++ .../landmark-no-duplicate-main-pass1.html | 29 +++++++++++++++ .../landmark-no-duplicate-main-pass1.js | 37 +++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 test/integration/full/landmark-no-duplicate-main/frames/level1-1.html create mode 100644 test/integration/full/landmark-no-duplicate-main/landmark-no-duplicate-main-pass1.html create mode 100644 test/integration/full/landmark-no-duplicate-main/landmark-no-duplicate-main-pass1.js diff --git a/build/test/get-test-urls.js b/build/test/get-test-urls.js index 07eb3e782a..db08288bf2 100644 --- a/build/test/get-test-urls.js +++ b/build/test/get-test-urls.js @@ -28,7 +28,9 @@ const getTestUrls = async (host = `localhost`, port = `9876`) => { ...( await globby([ 'test/integration/full/landmark-one-main/**/*.html', - '!test/integration/full/landmark-one-main/**/frames/**/*.html' + '!test/integration/full/landmark-one-main/**/frames/**/*.html', + 'test/integration/full/landmark-no-duplicate-main/**/*.html', + '!test/integration/full/landmark-no-duplicate-main/**/frames/**/*.html' // 'test/integration/full/**/*.html', // '!test/integration/full/**/frames/**/*.html' ]) diff --git a/test/integration/full/landmark-no-duplicate-main/frames/level1-1.html b/test/integration/full/landmark-no-duplicate-main/frames/level1-1.html new file mode 100644 index 0000000000..a0c3273e51 --- /dev/null +++ b/test/integration/full/landmark-no-duplicate-main/frames/level1-1.html @@ -0,0 +1,10 @@ + + + + + + + +

No main landmarks

+ + diff --git a/test/integration/full/landmark-no-duplicate-main/landmark-no-duplicate-main-pass1.html b/test/integration/full/landmark-no-duplicate-main/landmark-no-duplicate-main-pass1.html new file mode 100644 index 0000000000..7659fe192c --- /dev/null +++ b/test/integration/full/landmark-no-duplicate-main/landmark-no-duplicate-main-pass1.html @@ -0,0 +1,29 @@ + + + + + + + + + + + +

No main landmarks

+ +
+ + + + + diff --git a/test/integration/full/landmark-no-duplicate-main/landmark-no-duplicate-main-pass1.js b/test/integration/full/landmark-no-duplicate-main/landmark-no-duplicate-main-pass1.js new file mode 100644 index 0000000000..cdbeb398b3 --- /dev/null +++ b/test/integration/full/landmark-no-duplicate-main/landmark-no-duplicate-main-pass1.js @@ -0,0 +1,37 @@ +describe('landmark-no-duplicate-main test pass 1', function() { + 'use strict'; + var results; + before(function(done) { + axe.testUtils.awaitNestedLoad(function() { + axe.run( + { runOnly: { type: 'rule', values: ['landmark-no-duplicate-main'] } }, + function(err, r) { + assert.isNull(err); + results = r; + done(); + } + ); + }); + }); + + describe('violations', function() { + it('should find 0', function() { + assert.lengthOf(results.violations, 0); + }); + }); + + describe('passes', function() { + it('should find 0', function() { + assert.lengthOf(results.passes, 0); + }); + }); + + it('should find 1 inapplicable', function() { + assert.lengthOf(results.inapplicable, 1); + assert.lengthOf(results.inapplicable[0].nodes, 0); + }); + + it('should find 0 incomplete', function() { + assert.lengthOf(results.incomplete, 0); + }); +}); From 72707cf6121f9aef0d2e74676edaf882f428c8e3 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 10 Mar 2021 19:53:11 +0000 Subject: [PATCH 17/20] matching-aria-role check port (untranslated) --- lib/core/public/configure.js | 182 +++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/lib/core/public/configure.js b/lib/core/public/configure.js index be3eb58c28..904bd21ca1 100644 --- a/lib/core/public/configure.js +++ b/lib/core/public/configure.js @@ -1,5 +1,8 @@ import { hasReporter } from './reporter'; import { configureStandards } from '../../standards'; +import matchesSelector from '../../core/utils/element-matches'; +import { tokenList } from '../../core/utils'; +import { getRole } from '../../commons/aria'; function configure(spec) { var audit; @@ -44,6 +47,185 @@ function configure(spec) { audit.reporter = spec.reporter; } + // DAISY-AXE + if (!spec.checks) { + spec.checks = []; + } + spec.checks.push({ + id: 'matching-aria-role', + // eslint-disable-next-line no-unused-vars + evaluate: function evaluate(node, options, virtualNode, context) { + // https://idpf.github.io/epub-guides/epub-aria-authoring/#sec-mappings + // https://www.w3.org/TR/dpub-aam-1.0/#mapping_role_table + // https://w3c.github.io/publ-cg/guides/aria-mapping.html#mapping-table + const mappings = new Map([ + ['abstract', 'doc-abstract'], + ['acknowledgments', 'doc-acknowledgments'], + ['afterword', 'doc-afterword'], + // ['answer', '??'], + // ['answers', '??'], + ['appendix', 'doc-appendix'], + // ['assessment', '??'], + // ['assessments', '??'], + // ['backmatter', '??'], + // ['balloon', '??'], + // ['backlink', 'doc-backlink'], // ?? + ['biblioentry', 'doc-biblioentry'], + ['bibliography', 'doc-bibliography'], + ['biblioref', 'doc-biblioref'], + // ['bodymatter', '??'], + // ['bridgehead', '??'], + // ['case-study', '??'], + ['chapter', 'doc-chapter'], + ['colophon', 'doc-colophon'], + // ['concluding-sentence', '??'], + ['conclusion', 'doc-conclusion'], + // ['contributors', '??'], + // ['copyright-page', '??'], + // ['cover', '??'], + // ['cover-image', 'doc-cover'], // ?? + // ['covertitle', '??'], + ['credit', 'doc-credit'], + ['credits', 'doc-credits'], + ['dedication', 'doc-dedication'], + // ['division', '??'], + ['endnote', 'doc-endnote'], + ['endnotes', 'doc-endnotes'], + ['epigraph', 'doc-epigraph'], + ['epilogue', 'doc-epilogue'], + ['errata', 'doc-errata'], + // ['example', 'doc-example'], + // ['feedback', '??'], + ['figure', 'figure'], // ARIA + // ['fill-in-the-blank-problem', '??'], + ['footnote', 'doc-footnote'], + // ['footnotes', '??'], + ['foreword', 'doc-foreword'], + // ['frontmatter', '??'], + // ['fulltitle', '??'], + // ['general-problem', '??'], + ['glossary', 'doc-glossary'], + ['glossdef', 'definition'], // ARIA + ['glossref', 'doc-glossref'], + ['glossterm', 'term'], // ARIA + // ['halftitle', '??'], + // ['halftitlepage', '??'], + // ['imprimatur', '??'], + // ['imprint', '??'], + ['help', 'doc-tip'], // ?? + ['index', 'doc-index'], + // ['index-editor-note', '??'], + // ['index-entry', '??'], + // ['index-entry-list', '??'], + // ['index-group', '??'], + // ['index-headnotes', '??'], + // ['index-legend', '??'], + // ['index-locator', '??'], + // ['index-locator-list', '??'], + // ['index-locator-range', '??'], + // ['index-term', '??'], + // ['index-term-categories', '??'], + // ['index-term-category', '??'], + // ['index-xref-preferred', '??'], + // ['index-xref-related', '??'], + ['introduction', 'doc-introduction'], + // ['keyword', '??'], + // ['keywords', '??'], + // ['label', '??'], + ['landmarks', 'directory'], // ARIA + // ['learning-objective', '??'], + // ['learning-objectives', '??'], + // ['learning-outcome', '??'], + // ['learning-outcomes', '??'], + // ['learning-resource', '??'], + // ['learning-resources', '??'], + // ['learning-standard', '??'], + // ['learning-standards', '??'], + ['list', 'list'], // ARIA + ['list-item', 'listitem'], // ARIA + // ['loa', '??'], + // ['loi', '??'], + // ['lot', '??'], + // ['lov', '??'], + // ['match-problem', '??'], + // ['multiple-choice-problem', '??'], + ['noteref', 'doc-noteref'], + ['notice', 'doc-notice'], + // ['ordinal', '??'], + // ['other-credits', '??'], + ['page-list', 'doc-pagelist'], + ['pagebreak', 'doc-pagebreak'], + // ['panel', '??'], + // ['panel-group', '??'], + ['part', 'doc-part'], + // ['practice', '??'], + // ['practices', '??'], + // ['preamble', '??'], + ['preface', 'doc-preface'], + ['prologue', 'doc-prologue'], + ['pullquote', 'doc-pullquote'], + ['qna', 'doc-qna'], + // ['question', '??'], + ['referrer', 'doc-backlink'], + // ['revision-history', '??'], + // ['seriespage', '??'], + // ['sound-area', '??'], + // ['subchapter', '??'], + ['subtitle', 'doc-subtitle'], + ['table', 'table'], + ['table-cell', 'cell'], + ['table-row', 'row'], + // ['text-area', '??'], + ['tip', 'doc-tip'], + // ['title', '??'], + // ['titlepage', '??'], + ['toc', 'doc-toc'] + // ['toc-brief', '??'], + // ['topic-sentence', '??'], + // ['true-false-problem', '??'], + // ['volume', '??'], + ]); + + if (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type')) { + // abort if descendant of landmarks nav (nav with epub:type=landmarks) + if (matchesSelector(node, 'nav[*|type~="landmarks"] *')) { + return true; + } + + // iterate for each epub:type value + var types = tokenList( + node.getAttributeNS('http://www.idpf.org/2007/ops', 'type') + ); + for (const type of types) { + // If there is a 1-1 mapping, check that the role is set (best practice) + if (mappings.has(type)) { + // Note: using axe’s `getRole` util returns the effective role of the element + // (either explicitly set with the role attribute or implicit) + // So this works for types mapping to core ARIA roles (eg. glossref/glossterm). + return mappings.get(type) === getRole(node, { dpub: true }); + } + } + } + + return true; + }, + metadata: { + impact: 'minor', + messages: { + // eslint-disable-next-line no-unused-vars + pass: function anonymous(it) { + return 'Element has an ARIA role matching its epub:type'; + }, + // eslint-disable-next-line no-unused-vars + fail: function anonymous(it) { + return 'Element has no ARIA role matching its epub:type'; + }, + incomplete: '' + } + } + }); + // DAISY-AXE + if (spec.checks) { if (!Array.isArray(spec.checks)) { throw new TypeError('Checks property must be an array'); From 45529c184a42926334595ec88718bd59f046dd4a Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 10 Mar 2021 20:13:16 +0000 Subject: [PATCH 18/20] epub-type-has-matching-role pagebreak-label ported from Ace (translated now) --- lib/core/public/configure.js | 44 ++++++++++++++++++++++++++++++++++++ locales/da.json | 11 +++++++++ locales/de.json | 11 +++++++++ locales/es.json | 11 +++++++++ locales/eu.json | 11 +++++++++ locales/fr.json | 11 +++++++++ locales/ja.json | 11 +++++++++ locales/ko.json | 11 +++++++++ locales/nl.json | 11 +++++++++ locales/pt_BR.json | 11 +++++++++ 10 files changed, 143 insertions(+) diff --git a/lib/core/public/configure.js b/lib/core/public/configure.js index 904bd21ca1..0a89f08b92 100644 --- a/lib/core/public/configure.js +++ b/lib/core/public/configure.js @@ -245,6 +245,50 @@ function configure(spec) { }); } + // DAISY-AXE + if (!spec.rules) { + spec.rules = []; + } + spec.rules.push({ + id: 'pagebreak-label', + // selector: '[*|type~="pagebreak"], [role~="doc-pagebreak"]', + // eslint-disable-next-line no-unused-vars + matches: function matches(node, virtualNode, context) { + return ( + (node.hasAttribute('role') && + node + .getAttribute('role') + .match(/\S+/g) + .includes('doc-pagebreak')) || + (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type') && + node + .getAttributeNS('http://www.idpf.org/2007/ops', 'type') + .match(/\S+/g) + .includes('pagebreak')) + ); + }, + any: ['aria-label', 'non-empty-title'], + metadata: { + description: 'Ensure page markers have an accessible label' + }, + tags: ['cat.epub'] + }); + spec.rules.push({ + id: 'epub-type-has-matching-role', + // selector: '[*|type]', + // eslint-disable-next-line no-unused-vars + matches: function matches(node, virtualNode, context) { + return node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type'); + }, + any: ['matching-aria-role'], + metadata: { + help: 'ARIA role should be used in addition to epub:type', + description: 'Ensure the element has an ARIA role matching its epub:type' + }, + tags: ['best-practice'] + }); + // DAISY-AXE + const modifiedRules = []; if (spec.rules) { if (!Array.isArray(spec.rules)) { diff --git a/locales/da.json b/locales/da.json index 7a448b218a..93bf26c535 100644 --- a/locales/da.json +++ b/locales/da.json @@ -1,6 +1,13 @@ { "lang": "da", "rules": { + "epub-type-has-matching-role": { + "desc": "Sikrer at elementet har en ARIA rolle, som matcher 'epub:type'", + "help": "ARIA rolle skal være til stede og matche den angivne 'epub:type'" + }, + "pagebreak-label": { + "desc": "Sikrer at sidemarkører har en tilgængelig etiket ('label')" + }, "accesskeys": { "description": "", "help": "Værdien for attributten 'accesskey' skal være unik" @@ -323,6 +330,10 @@ } }, "checks": { + "matching-aria-role": { + "fail": "Elementet har ingen ARIA rolle, som matcher 'epub:type'", + "pass": "Elementet har en ARIA rolle, som matcher 'epub:type'" + }, "abstractrole": { "pass": "Abstrakte roller er ikke brugt", "fail": "Abstrakte roller bør ikke bruges" diff --git a/locales/de.json b/locales/de.json index 1fc1101019..1b694ba730 100644 --- a/locales/de.json +++ b/locales/de.json @@ -1,6 +1,13 @@ { "lang": "de", "rules": { + "epub-type-has-matching-role": { + "desc": "Ensure the element has an ARIA role matching its epub:type", + "help": "ARIA role should be used in addition to epub:type" + }, + "pagebreak-label": { + "desc": "Ensure page markers have an accessible label" + }, "accesskeys": { "description": "", "help": "Der Wert des accesskey-Attributes muss einzigartig sein." @@ -251,6 +258,10 @@ } }, "checks": { + "matching-aria-role": { + "pass": "Element has an ARIA role matching its epub:type", + "fail": "Element has no ARIA role matching its epub:type" + }, "abstractrole": { "pass": "", "fail": "Abstrakte ARIA-Rollen dürfen nicht direkt verwendet werden." diff --git a/locales/es.json b/locales/es.json index a9ccac15c5..e4a6e27775 100644 --- a/locales/es.json +++ b/locales/es.json @@ -1,6 +1,13 @@ { "lang": "es", "rules": { + "epub-type-has-matching-role": { + "desc": "Asegurarse de que el elemento tiene un rol ARIA que corresponda a su epub:type", + "help": "Debería usarse ARIA role, además de epub:type" + }, + "pagebreak-label": { + "desc": "Garantizar que los marcadores de página tienen una etiqueta accesible" + }, "accesskeys": { "description": "Garantiza que cada valor para el atributo accesskey es único", "help": "El valor del atributo accesskey debe ser único" @@ -319,6 +326,10 @@ } }, "checks": { + "matching-aria-role": { + "fail": "El elemento no tiene un rol ARIA que corresponda a su epub:type", + "pass": "El elemento tiene un rol ARIA que corresponde a su epub:type" + }, "abstractrole": { "pass": "No se usan 'abstract roles'", "fail": "Los 'abstract roles' no se pueden usar directamente" diff --git a/locales/eu.json b/locales/eu.json index 6f56607816..e71a882a63 100644 --- a/locales/eu.json +++ b/locales/eu.json @@ -1,6 +1,13 @@ { "lang": "eu", "rules": { + "epub-type-has-matching-role": { + "desc": "Ensure the element has an ARIA role matching its epub:type", + "help": "ARIA role should be used in addition to epub:type" + }, + "pagebreak-label": { + "desc": "Ensure page markers have an accessible label" + }, "accesskeys": { "description": "Accesskey atributurako balio bakoitza bakarra dela bermatzen du", "help": "Accesskey atributuaren balioak bakarra izan behar du" @@ -319,6 +326,10 @@ } }, "checks": { + "matching-aria-role": { + "pass": "Element has an ARIA role matching its epub:type", + "fail": "Element has no ARIA role matching its epub:type" + }, "abstractrole": { "pass": "Ez dira 'abstract rolak' erabiltzen", "fail": "'abstract rolak 'ezin dira zuzenean erabili" diff --git a/locales/fr.json b/locales/fr.json index 1073752acd..63d116a036 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -1,6 +1,13 @@ { "lang": "fr", "rules": { + "epub-type-has-matching-role": { + "desc": "Vérifie qu’un élément a un rôle ARIA correspondant à son epub:type", + "help": "Un rôle ARIA devrait être spécifié en plus de l’epub:type" + }, + "pagebreak-label": { + "desc": "Vérifie que les sauts de page ont un label accessible" + }, "accesskeys": { "description": "Vérifier que chaque valeur de l’attribut accesskey est unique", "help": "La valeur de l’attribut accesskey doit être unique" @@ -327,6 +334,10 @@ } }, "checks": { + "matching-aria-role": { + "fail": "L’élément n’a pas de rôle ARIA correspondant à son epub:type", + "pass": "L’élément a un rôle ARIA correspondant à son epub:type" + }, "abstractrole": { "pass": "Les rôles abstraits ne sont pas utilisés", "fail": "Les rôles abstraits ne peuvent pas être utilisés directement" diff --git a/locales/ja.json b/locales/ja.json index b70492b99a..c41d43c445 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -1,6 +1,13 @@ { "lang": "ja", "rules": { + "epub-type-has-matching-role": { + "desc": "Ensure the element has an ARIA role matching its epub:type", + "help": "ARIA role should be used in addition to epub:type" + }, + "pagebreak-label": { + "desc": "Ensure page markers have an accessible label" + }, "accesskeys": { "description": "すべてのaccesskey属性値が一意であることを確認します", "help": "accesskey属性値は一意でなければなりません" @@ -339,6 +346,10 @@ } }, "checks": { + "matching-aria-role": { + "pass": "Element has an ARIA role matching its epub:type", + "fail": "Element has no ARIA role matching its epub:type" + }, "abstractrole": { "pass": "抽象ロールは使用されていません", "fail": { diff --git a/locales/ko.json b/locales/ko.json index ee904e5619..08c16a2fd2 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -1,6 +1,13 @@ { "lang": "ko", "rules": { + "epub-type-has-matching-role": { + "desc": "Ensure the element has an ARIA role matching its epub:type", + "help": "ARIA role should be used in addition to epub:type" + }, + "pagebreak-label": { + "desc": "Ensure page markers have an accessible label" + }, "accesskeys": { "description": "모든 accesskey 속성 값이 고유한지 확인합니다.", "help": "accesskey 속성 값은 고유해야 합니다." @@ -319,6 +326,10 @@ } }, "checks": { + "matching-aria-role": { + "pass": "Element has an ARIA role matching its epub:type", + "fail": "Element has no ARIA role matching its epub:type" + }, "abstractrole": { "pass": "추상 역할은 직접 사용하지 않습니다.", "fail": "추상 역할은 직접 사용할 수 없습니다." diff --git a/locales/nl.json b/locales/nl.json index 407ef62618..fb02c8054d 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -1,6 +1,10 @@ { "lang": "nl", "checks": { + "matching-aria-role": { + "pass": "Element has an ARIA role matching its epub:type", + "fail": "Element has no ARIA role matching its epub:type" + }, "abstractrole": { "pass": "Er zijn geen abstracte rollen (role) gebruikt", "fail": "Gebruik geen abstracte rollen (role)" @@ -19,6 +23,13 @@ } }, "rules": { + "epub-type-has-matching-role": { + "desc": "Ensure the element has an ARIA role matching its epub:type", + "help": "ARIA role should be used in addition to epub:type" + }, + "pagebreak-label": { + "desc": "Ensure page markers have an accessible label" + }, "aria-required-attr": { "description": "Zorg dat elementen met ARIA rollen (role) de vereiste ARIA attributen hebben", "help": "Voorzien de vereiste ARIA attributen" diff --git a/locales/pt_BR.json b/locales/pt_BR.json index 940536274c..3d965ab0c4 100644 --- a/locales/pt_BR.json +++ b/locales/pt_BR.json @@ -1,6 +1,13 @@ { "lang": "pt_BR", "rules": { + "epub-type-has-matching-role": { + "desc": "Certifique-se de que o elemento tem um ARIA 'role' correspondente ao seu epub:type", + "help": "Um ARIA 'role' deve ser usado em conjunto com o epub:type" + }, + "pagebreak-label": { + "desc": "Certifique-se de que os marcadores de páginas tenham um rótulo acessível" + }, "accesskeys": { "description": "Certifique-se de que cada valor do atributo 'acesskey' é único", "help": "O valor do atributo 'accesskey' deve ser único" @@ -339,6 +346,10 @@ } }, "checks": { + "matching-aria-role": { + "fail": "O elemento não tem um ARIA 'role' correspondente ao seu epub:type", + "pass": "O elemento tem um ARIA 'role' correspondente ao seu epub:type" + }, "abstractrole": { "pass": "As funções abstratas não são utilizadas", "fail": { From 5e5e6a7b220ca99d4d3e67668ae701f8a74c2b06 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Thu, 11 Mar 2021 09:48:49 +0000 Subject: [PATCH 19/20] working XHTML unit tests for EPUB in Axe! (port from Ace) --- Gruntfile.js | 5 +- build/tasks/testconfig.js | 8 +- build/test/config.js | 1 + build/test/get-test-urls.js | 56 +++-- doc/examples/qunit/Gruntfile.js | 2 +- doc/rule-descriptions.md | 2 + .../aria/matching-aria-role-evaluate.js | 185 ++++++++++++++ lib/checks/aria/matching-aria-role.json | 11 + lib/core/base/metadata-function-map.js | 10 +- lib/core/public/configure.js | 232 +----------------- .../epub-type-has-matching-role-matches.js | 19 ++ lib/rules/epub-type-has-matching-role.json | 12 + lib/rules/pagebreak-label-matches.js | 19 ++ lib/rules/pagebreak-label.json | 12 + test/core/utils/get-selector.js | 2 +- .../content__.xhtml | 65 +++++ .../epub-type-has-matching-role-nav.js | 47 ++++ .../epub-type-has-matching-role.js | 62 +++++ .../epub-type-has-matching-role/nav__.xhtml | 39 +++ .../epub-type-has-matching-role.json | 15 ++ .../epub-type-has-matching-role.xhtml | 50 ++++ test/integration/rules/runner.js | 2 + test/runner.tmpl | 2 +- 23 files changed, 600 insertions(+), 258 deletions(-) create mode 100644 lib/checks/aria/matching-aria-role-evaluate.js create mode 100644 lib/checks/aria/matching-aria-role.json create mode 100644 lib/rules/epub-type-has-matching-role-matches.js create mode 100644 lib/rules/epub-type-has-matching-role.json create mode 100644 lib/rules/pagebreak-label-matches.js create mode 100644 lib/rules/pagebreak-label.json create mode 100644 test/integration/full/epub-type-has-matching-role/content__.xhtml create mode 100644 test/integration/full/epub-type-has-matching-role/epub-type-has-matching-role-nav.js create mode 100644 test/integration/full/epub-type-has-matching-role/epub-type-has-matching-role.js create mode 100644 test/integration/full/epub-type-has-matching-role/nav__.xhtml create mode 100644 test/integration/rules/epub-type-has-matching-role/epub-type-has-matching-role.json create mode 100644 test/integration/rules/epub-type-has-matching-role/epub-type-has-matching-role.xhtml diff --git a/Gruntfile.js b/Gruntfile.js index e11bcfa238..337f47f05a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -242,7 +242,10 @@ module.exports = function(grunt) { tasks: ['build', 'notify'] }, tests: { - files: ['test/**/*.js', 'test/integration/**/!(index).{html,json}'], + files: [ + 'test/**/*.js', + 'test/integration/**/!(index).{xhtml,html,json}' + ], tasks: ['clean:tests', 'testconfig', 'fixture'] } }, diff --git a/build/tasks/testconfig.js b/build/tasks/testconfig.js index 9834cd1a0c..08d24a6f0d 100644 --- a/build/tasks/testconfig.js +++ b/build/tasks/testconfig.js @@ -14,7 +14,13 @@ module.exports = function(grunt) { this.files.forEach(function(f) { f.src.forEach(function(filepath) { var config = grunt.file.readJSON(filepath); - config.content = grunt.file.read(filepath.replace(/json$/, 'html')); + try { + config.content = grunt.file.read(filepath.replace(/json$/, 'html')); + } catch (e) { + config.content = grunt.file.read( + filepath.replace(/json$/, 'xhtml') + ); + } result.tests[config.rule] = result.tests[config.rule] || []; result.tests[config.rule].push(config); }); diff --git a/build/test/config.js b/build/test/config.js index 54bf24ba85..eac1e4db9c 100644 --- a/build/test/config.js +++ b/build/test/config.js @@ -46,6 +46,7 @@ exports = module.exports = function(grunt, options) { log: true, urls: mapToUrl( [ + 'test/integration/full/**/*__.xhtml', 'test/integration/full/**/*.html', '!test/integration/full/**/frames/**/*.html' ], diff --git a/build/test/get-test-urls.js b/build/test/get-test-urls.js index db08288bf2..22b49b8d01 100644 --- a/build/test/get-test-urls.js +++ b/build/test/get-test-urls.js @@ -2,37 +2,41 @@ const globby = require('globby'); const getTestUrls = async (host = `localhost`, port = `9876`) => { const urls = [ - // /** - // * Unit tests -> Core - // */ - // `http://${host}:${port}/test/core/`, - // /** - // * Unit tests -> Checks - // */ - // `http://${host}:${port}/test/checks/`, - // /** - // * Unit tests -> Matches - // */ - // `http://${host}:${port}/test/rule-matches/`, - // /** - // * Unit tests -> Commons - // */ - // `http://${host}:${port}/test/commons/`, - // /** - // * Integration tests -> rules - // */ - // `http://${host}:${port}/test/integration/rules`, + /** + * Unit tests -> Core + */ + `http://${host}:${port}/test/core/`, + /** + * Unit tests -> Checks + */ + `http://${host}:${port}/test/checks/`, + /** + * Unit tests -> Matches + */ + `http://${host}:${port}/test/rule-matches/`, + /** + * Unit tests -> Commons + */ + `http://${host}:${port}/test/commons/`, + /** + * Integration tests -> rules + */ + `http://${host}:${port}/test/integration/rules`, /** * Integration tests -> full */ ...( await globby([ - 'test/integration/full/landmark-one-main/**/*.html', - '!test/integration/full/landmark-one-main/**/frames/**/*.html', - 'test/integration/full/landmark-no-duplicate-main/**/*.html', - '!test/integration/full/landmark-no-duplicate-main/**/frames/**/*.html' - // 'test/integration/full/**/*.html', - // '!test/integration/full/**/frames/**/*.html' + // 'test/integration/full/landmark-one-main/**/*.html', + // '!test/integration/full/landmark-one-main/**/frames/**/*.html', + // 'test/integration/full/landmark-no-duplicate-main/**/*.html', + // '!test/integration/full/landmark-no-duplicate-main/**/frames/**/*.html' + + // 'test/integration/full/epub-type-has-matching-role/**/*.xhtml', + + 'test/integration/full/**/*__.xhtml', + 'test/integration/full/**/*.html', + '!test/integration/full/**/frames/**/*.html' ]) ).map(file => `http://${host}:${port}/${file}`) ]; diff --git a/doc/examples/qunit/Gruntfile.js b/doc/examples/qunit/Gruntfile.js index b08c53082d..3f71195903 100644 --- a/doc/examples/qunit/Gruntfile.js +++ b/doc/examples/qunit/Gruntfile.js @@ -5,7 +5,7 @@ module.exports = function(grunt) { grunt.initConfig({ qunit: { - all: ['test/**/*.html'] + all: ['test/**/*.html', 'test/**/*__.xhtml'] } }); }; diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 7da8f17bd9..00e2f8209c 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -71,6 +71,7 @@ | :----------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :------ | :-------------------------------- | :--------- | | [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.1/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | failure | | [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.1/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412 | failure | +| [pagebreak-label](https://dequeuniversity.com/rules/axe/4.1/pagebreak-label?application=RuleDescription) | Ensure page markers have an accessible label | Serious | cat.epub | failure | ## Best Practices Rules @@ -83,6 +84,7 @@ Rules that do not necessarily conform to WCAG success criterion but are industry | [aria-dialog-name](https://dequeuniversity.com/rules/axe/4.1/aria-dialog-name?application=RuleDescription) | Ensures every ARIA dialog and alertdialog node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | | [aria-treeitem-name](https://dequeuniversity.com/rules/axe/4.1/aria-treeitem-name?application=RuleDescription) | Ensures every ARIA treeitem node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | | [empty-heading](https://dequeuniversity.com/rules/axe/4.1/empty-heading?application=RuleDescription) | Ensures headings have discernible text | Minor | cat.name-role-value, best-practice | failure, needs review | +| [epub-type-has-matching-role](https://dequeuniversity.com/rules/axe/4.1/epub-type-has-matching-role?application=RuleDescription) | Ensure the element has an ARIA role matching its epub:type | Minor | best-practice, cat.aria | failure | | [frame-tested](https://dequeuniversity.com/rules/axe/4.1/frame-tested?application=RuleDescription) | Ensures <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, review-item, best-practice | failure, needs review | | [frame-title-unique](https://dequeuniversity.com/rules/axe/4.1/frame-title-unique?application=RuleDescription) | Ensures <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, best-practice | failure | | [heading-order](https://dequeuniversity.com/rules/axe/4.1/heading-order?application=RuleDescription) | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | failure | diff --git a/lib/checks/aria/matching-aria-role-evaluate.js b/lib/checks/aria/matching-aria-role-evaluate.js new file mode 100644 index 0000000000..65963155f1 --- /dev/null +++ b/lib/checks/aria/matching-aria-role-evaluate.js @@ -0,0 +1,185 @@ +import { tokenList } from '../../core/utils'; +import { getRole } from '../../commons/aria'; +import matchesSelector from '../../core/utils/element-matches'; + +function matchingAriaRoleEvaluate(node) { + // https://idpf.github.io/epub-guides/epub-aria-authoring/#sec-mappings + // https://www.w3.org/TR/dpub-aam-1.0/#mapping_role_table + // https://w3c.github.io/publ-cg/guides/aria-mapping.html#mapping-table + const mappings = new Map([ + ['abstract', 'doc-abstract'], + ['acknowledgments', 'doc-acknowledgments'], + ['afterword', 'doc-afterword'], + // ['answer', '??'], + // ['answers', '??'], + ['appendix', 'doc-appendix'], + // ['assessment', '??'], + // ['assessments', '??'], + // ['backmatter', '??'], + // ['balloon', '??'], + // ['backlink', 'doc-backlink'], // ?? + ['biblioentry', 'doc-biblioentry'], + ['bibliography', 'doc-bibliography'], + ['biblioref', 'doc-biblioref'], + // ['bodymatter', '??'], + // ['bridgehead', '??'], + // ['case-study', '??'], + ['chapter', 'doc-chapter'], + ['colophon', 'doc-colophon'], + // ['concluding-sentence', '??'], + ['conclusion', 'doc-conclusion'], + // ['contributors', '??'], + // ['copyright-page', '??'], + // ['cover', '??'], + // ['cover-image', 'doc-cover'], // ?? + // ['covertitle', '??'], + ['credit', 'doc-credit'], + ['credits', 'doc-credits'], + ['dedication', 'doc-dedication'], + // ['division', '??'], + ['endnote', 'doc-endnote'], + ['endnotes', 'doc-endnotes'], + ['epigraph', 'doc-epigraph'], + ['epilogue', 'doc-epilogue'], + ['errata', 'doc-errata'], + // ['example', 'doc-example'], + // ['feedback', '??'], + ['figure', 'figure'], // ARIA + // ['fill-in-the-blank-problem', '??'], + ['footnote', 'doc-footnote'], + // ['footnotes', '??'], + ['foreword', 'doc-foreword'], + // ['frontmatter', '??'], + // ['fulltitle', '??'], + // ['general-problem', '??'], + ['glossary', 'doc-glossary'], + ['glossdef', 'definition'], // ARIA + ['glossref', 'doc-glossref'], + ['glossterm', 'term'], // ARIA + // ['halftitle', '??'], + // ['halftitlepage', '??'], + // ['imprimatur', '??'], + // ['imprint', '??'], + ['help', 'doc-tip'], // ?? + ['index', 'doc-index'], + // ['index-editor-note', '??'], + // ['index-entry', '??'], + // ['index-entry-list', '??'], + // ['index-group', '??'], + // ['index-headnotes', '??'], + // ['index-legend', '??'], + // ['index-locator', '??'], + // ['index-locator-list', '??'], + // ['index-locator-range', '??'], + // ['index-term', '??'], + // ['index-term-categories', '??'], + // ['index-term-category', '??'], + // ['index-xref-preferred', '??'], + // ['index-xref-related', '??'], + ['introduction', 'doc-introduction'], + // ['keyword', '??'], + // ['keywords', '??'], + // ['label', '??'], + // ['landmarks', 'directory'], // ARIA (SKIPPED! NavDoc) + // ['learning-objective', '??'], + // ['learning-objectives', '??'], + // ['learning-outcome', '??'], + // ['learning-outcomes', '??'], + // ['learning-resource', '??'], + // ['learning-resources', '??'], + // ['learning-standard', '??'], + // ['learning-standards', '??'], + ['list', 'list'], // ARIA + ['list-item', 'listitem'], // ARIA + // ['loa', '??'], + // ['loi', '??'], + // ['lot', '??'], + // ['lov', '??'], + // ['match-problem', '??'], + // ['multiple-choice-problem', '??'], + ['noteref', 'doc-noteref'], + ['notice', 'doc-notice'], + // ['ordinal', '??'], + // ['other-credits', '??'], + ['page-list', 'doc-pagelist'], + ['pagebreak', 'doc-pagebreak'], + // ['panel', '??'], + // ['panel-group', '??'], + ['part', 'doc-part'], + // ['practice', '??'], + // ['practices', '??'], + // ['preamble', '??'], + ['preface', 'doc-preface'], + ['prologue', 'doc-prologue'], + ['pullquote', 'doc-pullquote'], + ['qna', 'doc-qna'], + // ['question', '??'], + ['referrer', 'doc-backlink'], + // ['revision-history', '??'], + // ['seriespage', '??'], + // ['sound-area', '??'], + // ['subchapter', '??'], + ['subtitle', 'doc-subtitle'], + ['table', 'table'], + ['table-cell', 'cell'], + ['table-row', 'row'], + // ['text-area', '??'], + ['tip', 'doc-tip'], + // ['title', '??'], + // ['titlepage', '??'], + ['toc', 'doc-toc'] + // ['toc-brief', '??'], + // ['topic-sentence', '??'], + // ['true-false-problem', '??'], + // ['volume', '??'], + ]); + + const hasXmlEpubType = node.hasAttributeNS( + 'http://www.idpf.org/2007/ops', + 'type' + ); + if ( + hasXmlEpubType || + node.hasAttribute('epub:type') // for unit tests that are not XML-aware due to fixture.innerHTML + ) { + // abort if descendant of landmarks nav (nav with epub:type=landmarks) + if ( + (hasXmlEpubType && matchesSelector(node, 'nav[*|type~="landmarks"] *')) || + matchesSelector(node, 'nav[epub\\:type~="landmarks"] *') + ) { + // console.log('BREAKPOINT'); + // throw new Error('BREAKPOINT'); + return true; + } + + // iterate for each epub:type value + var types = tokenList( + hasXmlEpubType + ? node.getAttributeNS('http://www.idpf.org/2007/ops', 'type') + : node.getAttribute('epub:type') + ); + for (const type of types) { + // If there is a 1-1 mapping, check that the role is set (best practice) + if (mappings.has(type)) { + // Note: using axe’s `getRole` util returns the effective role of the element + // (either explicitly set with the role attribute or implicit) + // So this works for types mapping to core ARIA roles (eg. glossref/glossterm). + const mappedRole = mappings.get(type); + const role = getRole(node, { dpub: true }); + // if (mappedRole !== role) { + // console.log('BREAKPOINT: ', type, mappedRole, role); + // // throw new Error('BREAKPOINT'); + // } + return mappedRole === role; + } else { + // e.g. cover, landmarks + // console.log('BREAKPOINT: ', type); + // throw new Error('BREAKPOINT'); + } + } + } + + return true; +} + +export default matchingAriaRoleEvaluate; diff --git a/lib/checks/aria/matching-aria-role.json b/lib/checks/aria/matching-aria-role.json new file mode 100644 index 0000000000..b8996c7e10 --- /dev/null +++ b/lib/checks/aria/matching-aria-role.json @@ -0,0 +1,11 @@ +{ + "id": "matching-aria-role", + "evaluate": "matching-aria-role-evaluate", + "metadata": { + "impact": "minor", + "messages": { + "pass": "Element has an ARIA role matching its epub:type", + "fail": "Element has no ARIA role matching its epub:type" + } + } +} diff --git a/lib/core/base/metadata-function-map.js b/lib/core/base/metadata-function-map.js index c197b0d776..69762cbc08 100644 --- a/lib/core/base/metadata-function-map.js +++ b/lib/core/base/metadata-function-map.js @@ -164,6 +164,10 @@ import svgNamespaceMatches from '../../rules/svg-namespace-matches'; import windowIsTopMatches from '../../rules/window-is-top-matches'; import xmlLangMismatchMatches from '../../rules/xml-lang-mismatch-matches'; +import epubTypeHasMatchingRoleMatches from '../../rules/epub-type-has-matching-role-matches'; +import pagebreakLabelMatches from '../../rules/pagebreak-label-matches'; +import matchingAriaRoleEvaluate from '../../checks/aria/matching-aria-role-evaluate'; + const metadataFunctionMap = { // aria 'abstractrole-evaluate': abstractroleEvaluate, @@ -331,7 +335,11 @@ const metadataFunctionMap = { 'skip-link-matches': skipLinkMatches, 'svg-namespace-matches': svgNamespaceMatches, 'window-is-top-matches': windowIsTopMatches, - 'xml-lang-mismatch-matches': xmlLangMismatchMatches + 'xml-lang-mismatch-matches': xmlLangMismatchMatches, + + 'epub-type-has-matching-role-matches': epubTypeHasMatchingRoleMatches, + 'pagebreak-label-matches': pagebreakLabelMatches, + 'matching-aria-role-evaluate': matchingAriaRoleEvaluate }; export default metadataFunctionMap; diff --git a/lib/core/public/configure.js b/lib/core/public/configure.js index 0a89f08b92..03a2209c9f 100644 --- a/lib/core/public/configure.js +++ b/lib/core/public/configure.js @@ -1,10 +1,13 @@ import { hasReporter } from './reporter'; import { configureStandards } from '../../standards'; -import matchesSelector from '../../core/utils/element-matches'; -import { tokenList } from '../../core/utils'; -import { getRole } from '../../commons/aria'; + +// import matchesSelector from '../../core/utils/element-matches'; +// import { tokenList } from '../../core/utils'; +// import { getRole } from '../../commons/aria'; function configure(spec) { + // throw new Error("DAISY ACE BREAKPOINT AXE CONFIGURE"); + var audit; audit = axe._audit; @@ -47,185 +50,6 @@ function configure(spec) { audit.reporter = spec.reporter; } - // DAISY-AXE - if (!spec.checks) { - spec.checks = []; - } - spec.checks.push({ - id: 'matching-aria-role', - // eslint-disable-next-line no-unused-vars - evaluate: function evaluate(node, options, virtualNode, context) { - // https://idpf.github.io/epub-guides/epub-aria-authoring/#sec-mappings - // https://www.w3.org/TR/dpub-aam-1.0/#mapping_role_table - // https://w3c.github.io/publ-cg/guides/aria-mapping.html#mapping-table - const mappings = new Map([ - ['abstract', 'doc-abstract'], - ['acknowledgments', 'doc-acknowledgments'], - ['afterword', 'doc-afterword'], - // ['answer', '??'], - // ['answers', '??'], - ['appendix', 'doc-appendix'], - // ['assessment', '??'], - // ['assessments', '??'], - // ['backmatter', '??'], - // ['balloon', '??'], - // ['backlink', 'doc-backlink'], // ?? - ['biblioentry', 'doc-biblioentry'], - ['bibliography', 'doc-bibliography'], - ['biblioref', 'doc-biblioref'], - // ['bodymatter', '??'], - // ['bridgehead', '??'], - // ['case-study', '??'], - ['chapter', 'doc-chapter'], - ['colophon', 'doc-colophon'], - // ['concluding-sentence', '??'], - ['conclusion', 'doc-conclusion'], - // ['contributors', '??'], - // ['copyright-page', '??'], - // ['cover', '??'], - // ['cover-image', 'doc-cover'], // ?? - // ['covertitle', '??'], - ['credit', 'doc-credit'], - ['credits', 'doc-credits'], - ['dedication', 'doc-dedication'], - // ['division', '??'], - ['endnote', 'doc-endnote'], - ['endnotes', 'doc-endnotes'], - ['epigraph', 'doc-epigraph'], - ['epilogue', 'doc-epilogue'], - ['errata', 'doc-errata'], - // ['example', 'doc-example'], - // ['feedback', '??'], - ['figure', 'figure'], // ARIA - // ['fill-in-the-blank-problem', '??'], - ['footnote', 'doc-footnote'], - // ['footnotes', '??'], - ['foreword', 'doc-foreword'], - // ['frontmatter', '??'], - // ['fulltitle', '??'], - // ['general-problem', '??'], - ['glossary', 'doc-glossary'], - ['glossdef', 'definition'], // ARIA - ['glossref', 'doc-glossref'], - ['glossterm', 'term'], // ARIA - // ['halftitle', '??'], - // ['halftitlepage', '??'], - // ['imprimatur', '??'], - // ['imprint', '??'], - ['help', 'doc-tip'], // ?? - ['index', 'doc-index'], - // ['index-editor-note', '??'], - // ['index-entry', '??'], - // ['index-entry-list', '??'], - // ['index-group', '??'], - // ['index-headnotes', '??'], - // ['index-legend', '??'], - // ['index-locator', '??'], - // ['index-locator-list', '??'], - // ['index-locator-range', '??'], - // ['index-term', '??'], - // ['index-term-categories', '??'], - // ['index-term-category', '??'], - // ['index-xref-preferred', '??'], - // ['index-xref-related', '??'], - ['introduction', 'doc-introduction'], - // ['keyword', '??'], - // ['keywords', '??'], - // ['label', '??'], - ['landmarks', 'directory'], // ARIA - // ['learning-objective', '??'], - // ['learning-objectives', '??'], - // ['learning-outcome', '??'], - // ['learning-outcomes', '??'], - // ['learning-resource', '??'], - // ['learning-resources', '??'], - // ['learning-standard', '??'], - // ['learning-standards', '??'], - ['list', 'list'], // ARIA - ['list-item', 'listitem'], // ARIA - // ['loa', '??'], - // ['loi', '??'], - // ['lot', '??'], - // ['lov', '??'], - // ['match-problem', '??'], - // ['multiple-choice-problem', '??'], - ['noteref', 'doc-noteref'], - ['notice', 'doc-notice'], - // ['ordinal', '??'], - // ['other-credits', '??'], - ['page-list', 'doc-pagelist'], - ['pagebreak', 'doc-pagebreak'], - // ['panel', '??'], - // ['panel-group', '??'], - ['part', 'doc-part'], - // ['practice', '??'], - // ['practices', '??'], - // ['preamble', '??'], - ['preface', 'doc-preface'], - ['prologue', 'doc-prologue'], - ['pullquote', 'doc-pullquote'], - ['qna', 'doc-qna'], - // ['question', '??'], - ['referrer', 'doc-backlink'], - // ['revision-history', '??'], - // ['seriespage', '??'], - // ['sound-area', '??'], - // ['subchapter', '??'], - ['subtitle', 'doc-subtitle'], - ['table', 'table'], - ['table-cell', 'cell'], - ['table-row', 'row'], - // ['text-area', '??'], - ['tip', 'doc-tip'], - // ['title', '??'], - // ['titlepage', '??'], - ['toc', 'doc-toc'] - // ['toc-brief', '??'], - // ['topic-sentence', '??'], - // ['true-false-problem', '??'], - // ['volume', '??'], - ]); - - if (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type')) { - // abort if descendant of landmarks nav (nav with epub:type=landmarks) - if (matchesSelector(node, 'nav[*|type~="landmarks"] *')) { - return true; - } - - // iterate for each epub:type value - var types = tokenList( - node.getAttributeNS('http://www.idpf.org/2007/ops', 'type') - ); - for (const type of types) { - // If there is a 1-1 mapping, check that the role is set (best practice) - if (mappings.has(type)) { - // Note: using axe’s `getRole` util returns the effective role of the element - // (either explicitly set with the role attribute or implicit) - // So this works for types mapping to core ARIA roles (eg. glossref/glossterm). - return mappings.get(type) === getRole(node, { dpub: true }); - } - } - } - - return true; - }, - metadata: { - impact: 'minor', - messages: { - // eslint-disable-next-line no-unused-vars - pass: function anonymous(it) { - return 'Element has an ARIA role matching its epub:type'; - }, - // eslint-disable-next-line no-unused-vars - fail: function anonymous(it) { - return 'Element has no ARIA role matching its epub:type'; - }, - incomplete: '' - } - } - }); - // DAISY-AXE - if (spec.checks) { if (!Array.isArray(spec.checks)) { throw new TypeError('Checks property must be an array'); @@ -245,50 +69,6 @@ function configure(spec) { }); } - // DAISY-AXE - if (!spec.rules) { - spec.rules = []; - } - spec.rules.push({ - id: 'pagebreak-label', - // selector: '[*|type~="pagebreak"], [role~="doc-pagebreak"]', - // eslint-disable-next-line no-unused-vars - matches: function matches(node, virtualNode, context) { - return ( - (node.hasAttribute('role') && - node - .getAttribute('role') - .match(/\S+/g) - .includes('doc-pagebreak')) || - (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type') && - node - .getAttributeNS('http://www.idpf.org/2007/ops', 'type') - .match(/\S+/g) - .includes('pagebreak')) - ); - }, - any: ['aria-label', 'non-empty-title'], - metadata: { - description: 'Ensure page markers have an accessible label' - }, - tags: ['cat.epub'] - }); - spec.rules.push({ - id: 'epub-type-has-matching-role', - // selector: '[*|type]', - // eslint-disable-next-line no-unused-vars - matches: function matches(node, virtualNode, context) { - return node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type'); - }, - any: ['matching-aria-role'], - metadata: { - help: 'ARIA role should be used in addition to epub:type', - description: 'Ensure the element has an ARIA role matching its epub:type' - }, - tags: ['best-practice'] - }); - // DAISY-AXE - const modifiedRules = []; if (spec.rules) { if (!Array.isArray(spec.rules)) { diff --git a/lib/rules/epub-type-has-matching-role-matches.js b/lib/rules/epub-type-has-matching-role-matches.js new file mode 100644 index 0000000000..f4ceca0ba0 --- /dev/null +++ b/lib/rules/epub-type-has-matching-role-matches.js @@ -0,0 +1,19 @@ +function epubTypeHasMatchingRoleMatches(node) { + // selector: '[*|type]', + return ( + node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type') || + node.hasAttribute('epub:type') // for unit tests that are not XML-aware due to fixture.innerHTML + ); + + // console.log('node.nodeName: ', node.nodeName); + // const attrs = Array.from(getNodeAttributes(node)); + // console.log(attrs.length); + // attrs.forEach((attr) => { + // console.log('\n====='); + // console.log(JSON.stringify(attr)); + // console.log('attr.nodeName: ', attr.nodeName); + // console.log('attr.namespaceURI: ', attr.namespaceURI); + // }); +} + +export default epubTypeHasMatchingRoleMatches; diff --git a/lib/rules/epub-type-has-matching-role.json b/lib/rules/epub-type-has-matching-role.json new file mode 100644 index 0000000000..f49753c50b --- /dev/null +++ b/lib/rules/epub-type-has-matching-role.json @@ -0,0 +1,12 @@ +{ + "id": "epub-type-has-matching-role", + "matches": "epub-type-has-matching-role-matches", + "tags": ["best-practice", "cat.aria"], + "metadata": { + "description": "Ensure the element has an ARIA role matching its epub:type", + "help": "ARIA role should be used in addition to epub:type" + }, + "all": [], + "any": ["matching-aria-role"], + "none": [] +} diff --git a/lib/rules/pagebreak-label-matches.js b/lib/rules/pagebreak-label-matches.js new file mode 100644 index 0000000000..b4ec36e195 --- /dev/null +++ b/lib/rules/pagebreak-label-matches.js @@ -0,0 +1,19 @@ +function pagebreakLabelMatches(node) { + // selector: '[*|type~="pagebreak"], [role~="doc-pagebreak"]', + return ( + (node.hasAttribute('role') && + node + .getAttribute('role') + .match(/\S+/g) + .includes('doc-pagebreak')) || + (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type') && + node + .getAttributeNS('http://www.idpf.org/2007/ops', 'type') + .match(/\S+/g) + .includes('pagebreak')) + ); + + return false; +} + +export default pagebreakLabelMatches; diff --git a/lib/rules/pagebreak-label.json b/lib/rules/pagebreak-label.json new file mode 100644 index 0000000000..1ff408ec22 --- /dev/null +++ b/lib/rules/pagebreak-label.json @@ -0,0 +1,12 @@ +{ + "id": "pagebreak-label", + "matches": "pagebreak-label-matches", + "tags": ["cat.epub"], + "metadata": { + "description": "Ensure page markers have an accessible label", + "help": "Page markers should have an accessible label" + }, + "all": [], + "any": ["aria-label", "non-empty-title"], + "none": [] +} diff --git a/test/core/utils/get-selector.js b/test/core/utils/get-selector.js index c98a52cdec..5e9daca0c5 100644 --- a/test/core/utils/get-selector.js +++ b/test/core/utils/get-selector.js @@ -38,7 +38,7 @@ function makeNonuniqueLongAttributes(fixture) { return node; } -describe('axe.utils.getSelector', function() { +describe('axe.utils.getSelector (core)', function() { 'use strict'; var fixture = document.getElementById('fixture'); diff --git a/test/integration/full/epub-type-has-matching-role/content__.xhtml b/test/integration/full/epub-type-has-matching-role/content__.xhtml new file mode 100644 index 0000000000..2ca87358c0 --- /dev/null +++ b/test/integration/full/epub-type-has-matching-role/content__.xhtml @@ -0,0 +1,65 @@ + + + + epub-type-has-matching-role test + + + + + + + + + +

Loomings

+

Call me Ishmael.

+ +
+ A beautiful cover +
+ + + +
    +
  1. item 1
  2. +
+ +
notice
+ +
hello
+ +
definition
+definition +
+ + + +
notice
+ +
notice
+ +
notice
+ + + +
+ + + + + diff --git a/test/integration/full/epub-type-has-matching-role/epub-type-has-matching-role-nav.js b/test/integration/full/epub-type-has-matching-role/epub-type-has-matching-role-nav.js new file mode 100644 index 0000000000..ffd252977e --- /dev/null +++ b/test/integration/full/epub-type-has-matching-role/epub-type-has-matching-role-nav.js @@ -0,0 +1,47 @@ +describe('epub-type-has-matching-role-nav test pass', function() { + // Checks that `epub:type` have matching ARIA roles + // Ensure the element has an ARIA role matching its epub:type + // ARIA role should be used in addition to epub:type + + 'use strict'; + var results; + before(function(done) { + axe.testUtils.awaitNestedLoad(function() { + // axe.configure({}); // DAISY ACE BREAKPOINT AXE CONFIGURE + + axe.run( + { runOnly: { type: 'rule', values: ['epub-type-has-matching-role'] } }, + function(err, r) { + assert.isNull(err); + results = r; + done(); + } + ); + }); + }); + + describe('violations', function() { + it('should find 0', function() { + assert.lengthOf(results.violations, 0); + }); + }); + + describe('passes', function() { + it('should find 1', function() { + assert.lengthOf(results.passes, 1); + }); + + it('should find #id-toc', function() { + assert.deepEqual(results.passes[0].nodes[0].target, ['#id-toc']); + }); + }); + + it('should find 0 inapplicable', function() { + assert.lengthOf(results.inapplicable, 0); + // assert.lengthOf(results.inapplicable[0].nodes, 0); + }); + + it('should find 0 incomplete', function() { + assert.lengthOf(results.incomplete, 0); + }); +}); diff --git a/test/integration/full/epub-type-has-matching-role/epub-type-has-matching-role.js b/test/integration/full/epub-type-has-matching-role/epub-type-has-matching-role.js new file mode 100644 index 0000000000..98bd4aa0d5 --- /dev/null +++ b/test/integration/full/epub-type-has-matching-role/epub-type-has-matching-role.js @@ -0,0 +1,62 @@ +describe('epub-type-has-matching-role test fail', function() { + // Checks that `epub:type` have matching ARIA roles + // Ensure the element has an ARIA role matching its epub:type + // ARIA role should be used in addition to epub:type + + 'use strict'; + var results; + before(function(done) { + axe.testUtils.awaitNestedLoad(function() { + // axe.configure({}); // DAISY ACE BREAKPOINT AXE CONFIGURE + + axe.run( + { runOnly: { type: 'rule', values: ['epub-type-has-matching-role'] } }, + function(err, r) { + assert.isNull(err); + results = r; + done(); + } + ); + }); + }); + + describe('violations', function() { + it('should find 1', function() { + // console.log(JSON.stringify(results.violations, null, 4)); + assert.lengthOf(results.violations, 1); + }); + + it('should find #fail1 #fail2 #fail3', function() { + assert.deepEqual(results.violations[0].nodes[0].target, ['#fail1']); + assert.deepEqual(results.violations[0].nodes[1].target, ['#fail2']); + assert.deepEqual(results.violations[0].nodes[2].target, ['#fail3']); + }); + }); + + describe('passes', function() { + it('should find 1', function() { + // console.log(JSON.stringify(results.passes, null, 4)); + assert.lengthOf(results.passes, 1); + }); + + it('should find section #pass1-6', function() { + assert.deepEqual(results.passes[0].nodes[0].target, ['section']); + assert.deepEqual(results.passes[0].nodes[1].target, ['#pass2']); + assert.deepEqual(results.passes[0].nodes[2].target, ['#pass3']); + assert.deepEqual(results.passes[0].nodes[3].target, ['#pass4']); + assert.deepEqual(results.passes[0].nodes[4].target, ['#pass6']); + assert.deepEqual(results.passes[0].nodes[5].target, ['#pass5']); + assert.deepEqual(results.passes[0].nodes[6].target, ['#id-landmarks']); + assert.deepEqual(results.passes[0].nodes[7].target, ['#pass0']); + }); + }); + + it('should find 0 inapplicable', function() { + assert.lengthOf(results.inapplicable, 0); + // assert.lengthOf(results.inapplicable[0].nodes, 0); + }); + + it('should find 0 incomplete', function() { + assert.lengthOf(results.incomplete, 0); + }); +}); diff --git a/test/integration/full/epub-type-has-matching-role/nav__.xhtml b/test/integration/full/epub-type-has-matching-role/nav__.xhtml new file mode 100644 index 0000000000..db1c928406 --- /dev/null +++ b/test/integration/full/epub-type-has-matching-role/nav__.xhtml @@ -0,0 +1,39 @@ + + + epub-type-has-matching-role cover test + + + + + + + + + + + +
+ + + + + diff --git a/test/integration/rules/epub-type-has-matching-role/epub-type-has-matching-role.json b/test/integration/rules/epub-type-has-matching-role/epub-type-has-matching-role.json new file mode 100644 index 0000000000..5a7e09deb6 --- /dev/null +++ b/test/integration/rules/epub-type-has-matching-role/epub-type-has-matching-role.json @@ -0,0 +1,15 @@ +{ + "description": "epub-type-has-matching-role test", + "rule": "epub-type-has-matching-role", + "violations": [["#fail1"], ["#fail2"], ["#fail3"]], + "passes": [ + ["section"], + ["#pass2"], + ["#pass3"], + ["#pass4"], + ["#pass6"], + ["#pass5"], + ["#id-landmarks"], + ["#pass0"] + ] +} diff --git a/test/integration/rules/epub-type-has-matching-role/epub-type-has-matching-role.xhtml b/test/integration/rules/epub-type-has-matching-role/epub-type-has-matching-role.xhtml new file mode 100644 index 0000000000..fa168ccb99 --- /dev/null +++ b/test/integration/rules/epub-type-has-matching-role/epub-type-has-matching-role.xhtml @@ -0,0 +1,50 @@ + + + + epub-type-has-matching-role test + + + + + + +

Loomings

+

Call me Ishmael.

+ +
+ A beautiful cover +
+ + + +
    +
  1. item 1
  2. +
+ +
notice
+ +
hello
+ +
definition
+ definition +
+ + + +
notice
+ +
notice
+ +
notice
+ + + + + diff --git a/test/integration/rules/runner.js b/test/integration/rules/runner.js index bee2797b66..9b0a217bcd 100644 --- a/test/integration/rules/runner.js +++ b/test/integration/rules/runner.js @@ -2,6 +2,8 @@ (function() { 'use strict'; + // axe.configure({}); // DAISY ACE BREAKPOINT AXE CONFIGURE + function flattenResult(results) { return { passes: results.passes[0], diff --git a/test/runner.tmpl b/test/runner.tmpl index d673adba45..172df2891c 100644 --- a/test/runner.tmpl +++ b/test/runner.tmpl @@ -25,7 +25,7 @@ mocha.setup({ timeout: 20000, ui: 'bdd', - bail: true, + // bail: true, }); var assert = chai.assert; From e460f1d0196ce961cff0e86edcd3820f0126c9fc Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Thu, 11 Mar 2021 10:49:27 +0000 Subject: [PATCH 20/20] page-break label test (check) --- build/test/get-test-urls.js | 3 +- .../full/pagebreak-label/content__.xhtml | 37 +++++++++++++ .../full/pagebreak-label/pagebreak-label.js | 55 +++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 test/integration/full/pagebreak-label/content__.xhtml create mode 100644 test/integration/full/pagebreak-label/pagebreak-label.js diff --git a/build/test/get-test-urls.js b/build/test/get-test-urls.js index 22b49b8d01..6fb3649c84 100644 --- a/build/test/get-test-urls.js +++ b/build/test/get-test-urls.js @@ -32,7 +32,8 @@ const getTestUrls = async (host = `localhost`, port = `9876`) => { // 'test/integration/full/landmark-no-duplicate-main/**/*.html', // '!test/integration/full/landmark-no-duplicate-main/**/frames/**/*.html' - // 'test/integration/full/epub-type-has-matching-role/**/*.xhtml', + // 'test/integration/full/epub-type-has-matching-role/**/*__.xhtml', + // 'test/integration/full/pagebreak-label/**/*__.xhtml', 'test/integration/full/**/*__.xhtml', 'test/integration/full/**/*.html', diff --git a/test/integration/full/pagebreak-label/content__.xhtml b/test/integration/full/pagebreak-label/content__.xhtml new file mode 100644 index 0000000000..53a5d7fd8b --- /dev/null +++ b/test/integration/full/pagebreak-label/content__.xhtml @@ -0,0 +1,37 @@ + + + + pagebreak-label test + + + + + + + + + +

Loomings

+

Call me Ishmael.

+ + + + + + +
+ + + + + diff --git a/test/integration/full/pagebreak-label/pagebreak-label.js b/test/integration/full/pagebreak-label/pagebreak-label.js new file mode 100644 index 0000000000..ccb320857b --- /dev/null +++ b/test/integration/full/pagebreak-label/pagebreak-label.js @@ -0,0 +1,55 @@ +describe('pagebreak-label test fail', function() { + // Checks that `epub:type` have matching ARIA roles + // Ensure the element has an ARIA role matching its epub:type + // ARIA role should be used in addition to epub:type + + 'use strict'; + var results; + before(function(done) { + axe.testUtils.awaitNestedLoad(function() { + // axe.configure({}); // DAISY ACE BREAKPOINT AXE CONFIGURE + + axe.run( + { runOnly: { type: 'rule', values: ['pagebreak-label'] } }, + function(err, r) { + assert.isNull(err); + results = r; + done(); + } + ); + }); + }); + + describe('violations', function() { + it('should find 1', function() { + // console.log(JSON.stringify(results.violations, null, 4)); + assert.lengthOf(results.violations, 1); + }); + + it('should find #p3 #p4', function() { + assert.deepEqual(results.violations[0].nodes[0].target, ['#p3']); + assert.deepEqual(results.violations[0].nodes[1].target, ['#p4']); + }); + }); + + describe('passes', function() { + it('should find 1', function() { + // console.log(JSON.stringify(results.passes, null, 4)); + assert.lengthOf(results.passes, 1); + }); + + it('should find section #p1 #p2', function() { + assert.deepEqual(results.passes[0].nodes[0].target, ['#p1']); + assert.deepEqual(results.passes[0].nodes[1].target, ['#p2']); + }); + }); + + it('should find 0 inapplicable', function() { + assert.lengthOf(results.inapplicable, 0); + // assert.lengthOf(results.inapplicable[0].nodes, 0); + }); + + it('should find 0 incomplete', function() { + assert.lengthOf(results.incomplete, 0); + }); +});