From da2deae1bd863ebe518ca39e86246c06ba690758 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 19 Jan 2021 17:31:36 +0000 Subject: [PATCH 01/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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); + }); +}); From 908db3da9746c584d6828262119916940e81d544 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 6 Apr 2021 17:35:21 +0100 Subject: [PATCH 21/46] fixed semantic versioning handling (major.minor.patch-prerelease.buildmetadata) --- .gitignore | 1 + build/configure.js | 6 ++---- build/tasks/update-help.js | 2 +- lib/core/base/audit.js | 3 ++- package-lock.json | 8 ++++---- package.json | 2 +- test/core/base/audit.js | 3 ++- test/core/public/configure.js | 3 ++- test/core/public/get-rules.js | 3 ++- test/core/public/run-rules.js | 3 ++- test/runner.tmpl | 2 +- test/test-rule-help-version.js | 2 +- test/version.js | 2 +- 13 files changed, 22 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 0681de529b..9168d18e45 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ typings/axe-core/axe-core-tests.js # doc doc/rule-descriptions.*.md +.history \ No newline at end of file diff --git a/build/configure.js b/build/configure.js index ed69c17d9a..2cc081afb1 100644 --- a/build/configure.js +++ b/build/configure.js @@ -10,10 +10,8 @@ var entities = new (require('html-entities').AllHtmlEntities)(); var packageJSON = require('../package.json'); var dotRegex = /\{\{.+?\}\}/g; -var axeVersion = packageJSON.version.substring( - 0, - packageJSON.version.lastIndexOf('.') -); +var _v = packageJSON.version.replace(/-\w+\.\w+$/, ''); +var axeVersion = _v.substring(0, _v.lastIndexOf('.')); var descriptionTableHeader = '| Rule ID | Description | Impact | Tags | Issue Type |\n| :------- | :------- | :------- | :------- | :------- |\n'; diff --git a/build/tasks/update-help.js b/build/tasks/update-help.js index d418867c7f..79d9fc3790 100644 --- a/build/tasks/update-help.js +++ b/build/tasks/update-help.js @@ -9,7 +9,7 @@ module.exports = function(grunt) { var options = this.options({ version: '1.0.0' }); - var v = options.version.split('.'); + var v = options.version.replace(/-\w+\.\w+$/, '').split('.'); v.pop(); var baseUrl = 'https://dequeuniversity.com/rules/axe/' + v.join('.') + '/'; diff --git a/lib/core/base/audit.js b/lib/core/base/audit.js index c790dc0b60..ff7dcba23f 100644 --- a/lib/core/base/audit.js +++ b/lib/core/base/audit.js @@ -710,11 +710,12 @@ function getDefferedRule(rule, context, options) { * For all the rules, create the helpUrl and add it to the data for that rule */ function getHelpUrl({ brand, application, lang }, ruleId, version) { + var _v = version ? version : axe.version.replace(/-\w+\.\w+$/, ''); return ( constants.helpUrlBase + brand + '/' + - (version || axe.version.substring(0, axe.version.lastIndexOf('.'))) + + (version || _v.substring(0, _v.lastIndexOf('.'))) + '/' + ruleId + '?application=' + diff --git a/package-lock.json b/package-lock.json index 7409a36d31..b09c15cdc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@daisy/axe-core-for-ace", - "version": "4.1.4-daisy.0", + "version": "4.1.4-canary.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2041,9 +2041,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001096", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001096.tgz", - "integrity": "sha512-PFTw9UyVfbkcMEFs82q8XVlRayj7HKvnhu5BLcmjGpv+SNyiWasCcWXPGJuO0rK0dhLRDJmtZcJ+LHUfypbw1w==", + "version": "1.0.30001207", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001207.tgz", + "integrity": "sha512-UPQZdmAsyp2qfCTiMU/zqGSWOYaY9F9LL61V8f+8MrubsaDGpaHD9HRV/EWZGULZn0Hxu48SKzI5DgFwTvHuYw==", "dev": true }, "caseless": { diff --git a/package.json b/package.json index 4eaf36a2d8..ce56c035ee 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.4", + "version": "4.1.4-canary.0", "license": "MPL-2.0", "engines": { "node": ">=4" diff --git a/test/core/base/audit.js b/test/core/base/audit.js index 7d51a70e23..c0888ae278 100644 --- a/test/core/base/audit.js +++ b/test/core/base/audit.js @@ -4,7 +4,8 @@ describe('Audit', function() { var Audit = axe._thisWillBeDeletedDoNotUse.base.Audit; var Rule = axe._thisWillBeDeletedDoNotUse.base.Rule; - var ver = axe.version.substring(0, axe.version.lastIndexOf('.')); + var _v = axe.version.replace(/-\w+\.\w+$/, ''); + var ver = _v.substring(0, _v.lastIndexOf('.')); var a, getFlattenedTree; var isNotCalled = function(err) { throw err || new Error('Reject should not be called'); diff --git a/test/core/public/configure.js b/test/core/public/configure.js index 8ab54650cb..557172bdd0 100644 --- a/test/core/public/configure.js +++ b/test/core/public/configure.js @@ -4,7 +4,8 @@ describe('axe.configure', function() { // var Check = axe._thisWillBeDeletedDoNotUse.base.Check; var fixture = document.getElementById('fixture'); var axeVersion = axe.version; - var ver = axe.version.substring(0, axe.version.lastIndexOf('.')); + var _v = axe.version.replace(/-\w+\.\w+$/, ''); + var ver = _v.substring(0, _v.lastIndexOf('.')); afterEach(function() { fixture.innerHTML = ''; diff --git a/test/core/public/get-rules.js b/test/core/public/get-rules.js index 775d62693d..ffcf2f7bed 100644 --- a/test/core/public/get-rules.js +++ b/test/core/public/get-rules.js @@ -1,6 +1,7 @@ describe('axe.getRules', function() { 'use strict'; - var ver = axe.version.substring(0, axe.version.lastIndexOf('.')); + var _v = axe.version.replace(/-\w+\.\w+$/, ''); + var ver = _v.substring(0, _v.lastIndexOf('.')); beforeEach(function() { axe._load({ diff --git a/test/core/public/run-rules.js b/test/core/public/run-rules.js index c039b99195..d34a61b88d 100644 --- a/test/core/public/run-rules.js +++ b/test/core/public/run-rules.js @@ -1,6 +1,7 @@ describe('runRules', function() { 'use strict'; - var ver = axe.version.substring(0, axe.version.lastIndexOf('.')); + var _v = axe.version.replace(/-\w+\.\w+$/, ''); + var ver = _v.substring(0, _v.lastIndexOf('.')); // These tests can sometimes be flaky in IE, allow for up to 3 retries if (axe.testUtils.isIE11) { diff --git a/test/runner.tmpl b/test/runner.tmpl index 172df2891c..d673adba45 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; diff --git a/test/test-rule-help-version.js b/test/test-rule-help-version.js index 018b455f5d..59fe93a424 100644 --- a/test/test-rule-help-version.js +++ b/test/test-rule-help-version.js @@ -3,7 +3,7 @@ var path = require('path'); var assert = require('assert'); var packageJSON = require(path.join(__dirname, '../package.json')); -var versions = packageJSON.version.split('.'); +var versions = packageJSON.version.replace(/-\w+\.\w+$/, '').split('.'); var version = versions[0] + '.' + versions[1]; it( diff --git a/test/version.js b/test/version.js index d9f2c3a116..14eb097219 100644 --- a/test/version.js +++ b/test/version.js @@ -1,2 +1,2 @@ // This is temporary as the tests still need to use this file -axe.version = '4.1.4'; +axe.version = '4.1.4-canary.0'; From 9d649630ca747a9b60cfa63ec6bdbe573559c0b7 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 6 Apr 2021 20:26:39 +0100 Subject: [PATCH 22/46] fixed dd, dt, dl, dfn lookup table --- lib/commons/aria/lookup-table.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/commons/aria/lookup-table.js b/lib/commons/aria/lookup-table.js index a198feee71..59981992a8 100644 --- a/lib/commons/aria/lookup-table.js +++ b/lib/commons/aria/lookup-table.js @@ -489,7 +489,7 @@ lookupTable.role = { owned: null, nameFrom: ['author'], context: null, - implicit: ['dd', 'dfn'], + implicit: ['dd'], // DAISY-AXE: remove 'dfn' which has implicit 'term' role, see https://www.w3.org/TR/html-aria/#docconformance unsupported: false }, dialog: { @@ -1163,7 +1163,7 @@ lookupTable.role = { }, nameFrom: ['author'], context: null, - implicit: ['ol', 'ul', 'dl'], + implicit: ['ol', 'ul'], // DAISY-AXE: remove 'dl' which has no implicit role, see https://www.w3.org/TR/html-aria/#docconformance unsupported: false }, listbox: { @@ -1202,7 +1202,7 @@ lookupTable.role = { owned: null, nameFrom: ['author', 'contents'], context: ['list'], - implicit: ['li', 'dt'], + implicit: ['li'], // DAISY-AXE: remove 'dt' which has implicit 'term' role, see https://www.w3.org/TR/html-aria/#docconformance unsupported: false }, log: { @@ -1944,7 +1944,7 @@ lookupTable.role = { owned: null, nameFrom: ['author', 'contents'], context: null, - implicit: ['dt'], + implicit: ['dt', 'dfn'], // DAISY-AXE: add 'dfn' which has implicit 'term' role, see https://www.w3.org/TR/html-aria/#docconformance unsupported: false }, textbox: { From 2565b38dd135d2585fc2833580f3e4cc3a4162b6 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 6 Apr 2021 21:05:23 +0100 Subject: [PATCH 23/46] re-instated DAISY mods --- lib/checks/aria/aria-required-children-evaluate.js | 14 +++++++------- lib/checks/lists/listitem-evaluate.js | 10 +++++----- lib/checks/lists/only-listitems-evaluate.js | 10 +++++----- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/checks/aria/aria-required-children-evaluate.js b/lib/checks/aria/aria-required-children-evaluate.js index 859f54c5b5..973a2f2b29 100644 --- a/lib/checks/aria/aria-required-children-evaluate.js +++ b/lib/checks/aria/aria-required-children-evaluate.js @@ -11,7 +11,7 @@ import { hasContentVirtual, idrefs } from '../../commons/dom'; */ function getOwnedRoles(virtualNode) { // DAISY-AXE - // const parentRole = getRole(virtualNode, { dpub: true }); + const parentRole = getRole(virtualNode, { dpub: true }); const ownedRoles = []; const ownedElements = getOwnedVirtual(virtualNode); @@ -27,12 +27,12 @@ function getOwnedRoles(virtualNode) { // between a required parent and child will fail the check // DAISY-AXE - // if ( - // ['presentation', 'none', null].includes(role) || - // (['list'].includes(role) && - // ['doc-bibliography', 'doc-endnotes'].includes(parentRole)) - // ) { - if (['presentation', 'none', null].includes(role)) { + 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 bcfdc3b5d1..ad8c2085f1 100644 --- a/lib/checks/lists/listitem-evaluate.js +++ b/lib/checks/lists/listitem-evaluate.js @@ -1,8 +1,8 @@ import { getComposedParent } from '../../commons/dom'; // DAISY-AXE -// import { getRoleType, isValidRole } from '../../commons/aria'; -import { isValidRole } from '../../commons/aria'; +import { getRoleType, isValidRole } from '../../commons/aria'; +// import { isValidRole } from '../../commons/aria'; function listitemEvaluate(node) { const parent = getComposedParent(node); @@ -20,9 +20,9 @@ function listitemEvaluate(node) { if (parentRole && isValidRole(parentRole)) { // DAISY-AXE - // if (getRoleType(parentRole) === 'list') { - // return true; - // } + 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 1906a2e637..9a9dac4860 100644 --- a/lib/checks/lists/only-listitems-evaluate.js +++ b/lib/checks/lists/only-listitems-evaluate.js @@ -1,8 +1,8 @@ import { isVisible } from '../../commons/dom'; // DAISY-AXE -// import { getRole, getRoleType } from '../../commons/aria'; -import { getRole } from '../../commons/aria'; +import { getRole, getRoleType } from '../../commons/aria'; +// import { getRole } from '../../commons/aria'; function onlyListitemsEvaluate(node, options, virtualNode) { let hasNonEmptyTextNode = false; @@ -29,9 +29,9 @@ function onlyListitemsEvaluate(node, options, virtualNode) { const role = getRole(vNode); // DAISY-AXE - // const isListItemRole = - // role === 'listitem' || getRoleType(role) === 'listitem'; - const isListItemRole = role === 'listitem'; + const isListItemRole = + role === 'listitem' || getRoleType(role) === 'listitem'; + // const isListItemRole = role === 'listitem'; if (!isLi && !isListItemRole) { badNodes.push(actualNode); From d61e3dd3c2fb4d563555de64b74fad9d810a1209 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 6 Apr 2021 21:44:46 +0100 Subject: [PATCH 24/46] DAISY landmark-one-main rule really is "has a unique main landmark ... if it has one (optional)" --- lib/rules/landmark-one-main.json | 3 +- .../landmark-one-main-fail.js | 43 ++++++++++++++----- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/lib/rules/landmark-one-main.json b/lib/rules/landmark-one-main.json index 22b9f486ba..a1b2f29eab 100644 --- a/lib/rules/landmark-one-main.json +++ b/lib/rules/landmark-one-main.json @@ -6,7 +6,8 @@ "description": "Ensures the document has a unique main landmark", "help": "Document must have one unique main landmark" }, - "all": ["page-has-main", "page-no-duplicate-main"], + "// DAISY-AXE all": ["page-has-main", "page-no-duplicate-main"], + "all": ["page-no-duplicate-main"], "any": [], "none": [] } 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 7af7f36de8..7c1eb84213 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,26 +15,47 @@ describe('landmark-one-main test failure', function() { }); describe('violations', function() { - it('should find 2', function() { - assert.lengthOf(results.violations[0].nodes, 2); + // DAISY-AXE disables page-has-main + it('should find 0', function() { + assert.lengthOf(results.violations, 0); }); + // it('should find 2', function() { + // assert.lengthOf(results.violations[0].nodes, 2); + // }); + + // it('should find #fail1', function() { + // assert.deepEqual(results.violations[0].nodes[0].target, ['#fail1']); + // }); + + // it('should find #frame1, #violation2', function() { + // assert.deepEqual(results.violations[0].nodes[1].target, [ + // '#frame1', + // '#violation2' + // ]); + // }); + }); + + describe('passes', function() { + // DAISY-AXE disables page-has-main + it('should find 1', function() { + assert.lengthOf(results.passes, 1); + }); + it('should find 2', function() { + assert.lengthOf(results.passes[0].nodes, 2); + }); it('should find #fail1', function() { - assert.deepEqual(results.violations[0].nodes[0].target, ['#fail1']); + assert.deepEqual(results.passes[0].nodes[0].target, ['#fail1']); }); - it('should find #frame1, #violation2', function() { - assert.deepEqual(results.violations[0].nodes[1].target, [ + assert.deepEqual(results.passes[0].nodes[1].target, [ '#frame1', '#violation2' ]); }); - }); - - describe('passes', function() { - it('should find 0', function() { - assert.lengthOf(results.passes, 0); - }); + // it('should find 0', function() { + // assert.lengthOf(results.passes, 0); + // }); }); it('should find 0 inapplicable', function() { From e8e5645c204a560cb981f2b110cfcd103bddc878 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 6 Apr 2021 22:50:28 +0100 Subject: [PATCH 25/46] get role type is super class role now (DAISY patch) --- lib/checks/lists/listitem-evaluate.js | 4 ++-- lib/checks/lists/only-listitems-evaluate.js | 4 ++-- lib/commons/aria/get-super-class-role.js | 21 +++++++++++++++++++++ lib/commons/aria/index.js | 1 + 4 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 lib/commons/aria/get-super-class-role.js diff --git a/lib/checks/lists/listitem-evaluate.js b/lib/checks/lists/listitem-evaluate.js index ad8c2085f1..87a3953837 100644 --- a/lib/checks/lists/listitem-evaluate.js +++ b/lib/checks/lists/listitem-evaluate.js @@ -1,7 +1,7 @@ import { getComposedParent } from '../../commons/dom'; // DAISY-AXE -import { getRoleType, isValidRole } from '../../commons/aria'; +import { getSuperClassRole, isValidRole } from '../../commons/aria'; // import { isValidRole } from '../../commons/aria'; function listitemEvaluate(node) { @@ -20,7 +20,7 @@ function listitemEvaluate(node) { if (parentRole && isValidRole(parentRole)) { // DAISY-AXE - if (getRoleType(parentRole) === 'list') { + if (getSuperClassRole(parentRole) === 'list') { return true; } diff --git a/lib/checks/lists/only-listitems-evaluate.js b/lib/checks/lists/only-listitems-evaluate.js index 9a9dac4860..4cead051c0 100644 --- a/lib/checks/lists/only-listitems-evaluate.js +++ b/lib/checks/lists/only-listitems-evaluate.js @@ -1,7 +1,7 @@ import { isVisible } from '../../commons/dom'; // DAISY-AXE -import { getRole, getRoleType } from '../../commons/aria'; +import { getRole, getSuperClassRole } from '../../commons/aria'; // import { getRole } from '../../commons/aria'; function onlyListitemsEvaluate(node, options, virtualNode) { @@ -30,7 +30,7 @@ function onlyListitemsEvaluate(node, options, virtualNode) { // DAISY-AXE const isListItemRole = - role === 'listitem' || getRoleType(role) === 'listitem'; + role === 'listitem' || getSuperClassRole(role) === 'listitem'; // const isListItemRole = role === 'listitem'; if (!isLi && !isListItemRole) { diff --git a/lib/commons/aria/get-super-class-role.js b/lib/commons/aria/get-super-class-role.js new file mode 100644 index 0000000000..cc753cb64d --- /dev/null +++ b/lib/commons/aria/get-super-class-role.js @@ -0,0 +1,21 @@ +import standards from '../../standards'; + +/** + * Get the "superclassRole" of role + * @method getSuperClassRole + * @memberof axe.commons.aria + * @instance + * @param {String} role The role to check + * @return {Mixed} String if a matching role and its superclassRole are found, otherwise `null` + */ +function getSuperClassRole(role) { + const roleDef = standards.ariaRoles[role]; + + if (!roleDef) { + return null; + } + + return roleDef.superclassRole; +} + +export default getSuperClassRole; diff --git a/lib/commons/aria/index.js b/lib/commons/aria/index.js index 14de4ebc0c..d249a29111 100644 --- a/lib/commons/aria/index.js +++ b/lib/commons/aria/index.js @@ -11,6 +11,7 @@ export { default as getElementUnallowedRoles } from './get-element-unallowed-rol export { default as getExplicitRole } from './get-explicit-role'; export { default as getOwnedVirtual } from './get-owned-virtual'; export { default as getRoleType } from './get-role-type'; +export { default as getSuperClassRole } from './get-super-class-role'; export { default as getRole } from './get-role'; export { default as getRolesByType } from './get-roles-by-type'; export { default as getRolesWithNameFromContents } from './get-roles-with-name-from-contents'; From 20748a7732f59b3a59bee8ec3b7e440565242ef1 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 6 Apr 2021 23:15:56 +0100 Subject: [PATCH 26/46] super class role checks --- lib/checks/lists/listitem-evaluate.js | 3 ++- lib/checks/lists/only-listitems-evaluate.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/checks/lists/listitem-evaluate.js b/lib/checks/lists/listitem-evaluate.js index 87a3953837..776a0c1631 100644 --- a/lib/checks/lists/listitem-evaluate.js +++ b/lib/checks/lists/listitem-evaluate.js @@ -20,7 +20,8 @@ function listitemEvaluate(node) { if (parentRole && isValidRole(parentRole)) { // DAISY-AXE - if (getSuperClassRole(parentRole) === 'list') { + const sup = getSuperClassRole(parentRole); + if (sup && sup.includes('list')) { return true; } diff --git a/lib/checks/lists/only-listitems-evaluate.js b/lib/checks/lists/only-listitems-evaluate.js index 4cead051c0..a06ac30c23 100644 --- a/lib/checks/lists/only-listitems-evaluate.js +++ b/lib/checks/lists/only-listitems-evaluate.js @@ -29,8 +29,9 @@ function onlyListitemsEvaluate(node, options, virtualNode) { const role = getRole(vNode); // DAISY-AXE + const sup = getSuperClassRole(role); const isListItemRole = - role === 'listitem' || getSuperClassRole(role) === 'listitem'; + role === 'listitem' || (sup && sup.includes('listitem')); // const isListItemRole = role === 'listitem'; if (!isLi && !isListItemRole) { From 3ce80408cf8d8f7d4e41f65327d6c83f12db1fd3 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 00:02:15 +0100 Subject: [PATCH 27/46] owned roles fix for biblioentry and doc-endnote --- .../aria/aria-required-children-evaluate.js | 4 ++-- .../aria-required-children.html | 10 ++++++++++ .../aria-required-children.json | 4 +++- test/integration/rules/runner.js | 17 ++++++++++++++--- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/checks/aria/aria-required-children-evaluate.js b/lib/checks/aria/aria-required-children-evaluate.js index 973a2f2b29..063fd80887 100644 --- a/lib/checks/aria/aria-required-children-evaluate.js +++ b/lib/checks/aria/aria-required-children-evaluate.js @@ -19,8 +19,8 @@ function getOwnedRoles(virtualNode) { let ownedElement = ownedElements[i]; // DAISY-AXE - // let role = getRole(ownedElement, { dpub: true }); - let role = getRole(ownedElement); + 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 diff --git a/test/integration/rules/aria-required-children/aria-required-children.html b/test/integration/rules/aria-required-children/aria-required-children.html index 25cca78769..0494180ba3 100644 --- a/test/integration/rules/aria-required-children/aria-required-children.html +++ b/test/integration/rules/aria-required-children/aria-required-children.html @@ -25,6 +25,16 @@
+
+
    +
  • +
+
+
+
    +
  • +
+
diff --git a/test/integration/rules/aria-required-children/aria-required-children.json b/test/integration/rules/aria-required-children/aria-required-children.json index 31500091ff..d85803d7c7 100644 --- a/test/integration/rules/aria-required-children/aria-required-children.json +++ b/test/integration/rules/aria-required-children/aria-required-children.json @@ -26,7 +26,9 @@ ["#pass13"], ["#pass14"], ["#pass15"], - ["#pass16"] + ["#pass16"], + ["#pass17"], + ["#pass18"] ], "incomplete": [ ["#incomplete1"], diff --git a/test/integration/rules/runner.js b/test/integration/rules/runner.js index 9b0a217bcd..219aa696d8 100644 --- a/test/integration/rules/runner.js +++ b/test/integration/rules/runner.js @@ -97,9 +97,20 @@ it('should not return other results', function() { if (typeof nodes !== 'undefined') { - var targets = nodes.map(function(node) { - return node.target; - }); + var targets = nodes + .filter(function(node) { + return node.impact !== null; + }) + .map(function(node) { + return node.target; + }); + if (targets && targets.length) { + console.log( + JSON.stringify(results[collection]), + ' ---- ', + JSON.stringify(test[collection]) + ); + } // check that all nodes are removed assert.equal(JSON.stringify(targets), '[]'); } else { From 4140347ef976f4eae9337eeba56dd24266053dad Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 01:03:01 +0100 Subject: [PATCH 28/46] DPUB ARIA 1.1 align https://w3c.github.io/dpub-aria/#changelog --- lib/commons/aria/lookup-table.js | 7 ++++--- lib/standards/dpub-roles.js | 7 +++---- test/commons/standards/get-aria-roles-by-type.js | 3 ++- .../rules/aria-allowed-role/aria-allowed-role.html | 1 + .../rules/aria-allowed-role/aria-allowed-role.json | 1 + 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/commons/aria/lookup-table.js b/lib/commons/aria/lookup-table.js index 59981992a8..bd003c400f 100644 --- a/lib/commons/aria/lookup-table.js +++ b/lib/commons/aria/lookup-table.js @@ -776,7 +776,7 @@ lookupTable.role = { allowedElements: ['section'] }, 'doc-example': { - type: 'section', + type: 'structure', attributes: { allowed: ['aria-expanded', 'aria-errormessage'] }, @@ -813,7 +813,6 @@ lookupTable.role = { attributes: { allowed: ['aria-expanded', 'aria-errormessage'] }, - owned: ['term', 'definition'], namefrom: ['author'], context: null, unsupported: false, @@ -895,6 +894,7 @@ lookupTable.role = { }, owned: null, namefrom: ['author'], + nameFromContent: true, context: null, unsupported: false, allowedElements: ['hr'] @@ -944,7 +944,7 @@ lookupTable.role = { allowedElements: ['section'] }, 'doc-pullquote': { - type: 'none', + type: 'section', attributes: { allowed: ['aria-expanded'] }, @@ -972,6 +972,7 @@ lookupTable.role = { }, owned: null, namefrom: ['author'], + nameFromContent: true, context: null, unsupported: false, allowedElements: { diff --git a/lib/standards/dpub-roles.js b/lib/standards/dpub-roles.js index 4d5ff06828..2dd277388e 100644 --- a/lib/standards/dpub-roles.js +++ b/lib/standards/dpub-roles.js @@ -117,9 +117,9 @@ const dpubRoles = { superclassRole: ['landmark'] }, 'doc-example': { - type: 'section', + type: 'structure', allowedAttrs: ['aria-expanded'], - superclassRole: ['section'] + superclassRole: ['figure'] }, 'doc-footnote': { type: 'section', @@ -133,7 +133,6 @@ const dpubRoles = { }, 'doc-glossary': { type: 'landmark', - requiredOwned: ['definition', 'term'], allowedAttrs: ['aria-expanded'], superclassRole: ['landmark'] }, @@ -190,7 +189,7 @@ const dpubRoles = { superclassRole: ['landmark'] }, 'doc-pullquote': { - type: 'none', + type: 'section', superclassRole: ['none'] }, 'doc-qna': { diff --git a/test/commons/standards/get-aria-roles-by-type.js b/test/commons/standards/get-aria-roles-by-type.js index a83ffe528e..9671e98e1b 100644 --- a/test/commons/standards/get-aria-roles-by-type.js +++ b/test/commons/standards/get-aria-roles-by-type.js @@ -49,7 +49,8 @@ describe('standards.getAriaRolesByType', function() { 'term', 'time', 'toolbar', - 'tooltip' + 'tooltip', + 'doc-example' ]); }); diff --git a/test/integration/rules/aria-allowed-role/aria-allowed-role.html b/test/integration/rules/aria-allowed-role/aria-allowed-role.html index 1342927aae..60df8caed8 100644 --- a/test/integration/rules/aria-allowed-role/aria-allowed-role.html +++ b/test/integration/rules/aria-allowed-role/aria-allowed-role.html @@ -9,6 +9,7 @@
  • +
    ok
      diff --git a/test/integration/rules/aria-allowed-role/aria-allowed-role.json b/test/integration/rules/aria-allowed-role/aria-allowed-role.json index feefed99c2..0f5365dfc0 100644 --- a/test/integration/rules/aria-allowed-role/aria-allowed-role.json +++ b/test/integration/rules/aria-allowed-role/aria-allowed-role.json @@ -11,6 +11,7 @@ ["#pass-section-role-doc-bib"], ["#pass-li-role-doc-biblioentry"], ["#pass-aside-doc-example"], + ["#pass-figure-doc-example"], ["#pass-div-valid-role"], ["#pass-ol-valid-role"], ["#pass-nav-role-doc-index"], From 05d072659ad60486f82035f3d20202339e09dafa Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 01:19:13 +0100 Subject: [PATCH 29/46] DPUB ARIA 1.1. deprecate doc-biblioentry and doc-endnote --- lib/commons/aria/lookup-table.js | 12 ++++++------ lib/standards/dpub-roles.js | 4 ++-- .../aria-required-children.html | 10 ++++++++++ .../aria-required-children.json | 6 +++--- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/commons/aria/lookup-table.js b/lib/commons/aria/lookup-table.js index bd003c400f..c29a3b72eb 100644 --- a/lib/commons/aria/lookup-table.js +++ b/lib/commons/aria/lookup-table.js @@ -611,9 +611,9 @@ lookupTable.role = { attributes: { allowed: ['aria-expanded', 'aria-errormessage'] }, - owned: { - one: ['doc-biblioentry'] - }, + // owned: { + // one: ['doc-biblioentry'] + // }, nameFrom: ['author'], context: null, unsupported: false, @@ -735,9 +735,9 @@ lookupTable.role = { attributes: { allowed: ['aria-expanded', 'aria-errormessage'] }, - owned: { - one: ['doc-endnote'] - }, + // owned: { + // one: ['doc-endnote'] + // }, namefrom: ['author'], context: null, unsupported: false, diff --git a/lib/standards/dpub-roles.js b/lib/standards/dpub-roles.js index 2dd277388e..d5288f4dd7 100644 --- a/lib/standards/dpub-roles.js +++ b/lib/standards/dpub-roles.js @@ -39,7 +39,7 @@ const dpubRoles = { }, 'doc-bibliography': { type: 'landmark', - requiredOwned: ['doc-biblioentry'], + // requiredOwned: ['doc-biblioentry'], allowedAttrs: ['aria-expanded'], superclassRole: ['landmark'] }, @@ -97,7 +97,7 @@ const dpubRoles = { }, 'doc-endnotes': { type: 'landmark', - requiredOwned: ['doc-endnote'], + // requiredOwned: ['doc-endnote'], allowedAttrs: ['aria-expanded'], superclassRole: ['landmark'] }, diff --git a/test/integration/rules/aria-required-children/aria-required-children.html b/test/integration/rules/aria-required-children/aria-required-children.html index 0494180ba3..eeb8f7eb1e 100644 --- a/test/integration/rules/aria-required-children/aria-required-children.html +++ b/test/integration/rules/aria-required-children/aria-required-children.html @@ -35,6 +35,16 @@
    1. +
      +
        +
      • +
      +
      +
      +
        +
      • +
      +
      diff --git a/test/integration/rules/aria-required-children/aria-required-children.json b/test/integration/rules/aria-required-children/aria-required-children.json index d85803d7c7..5b559a05bb 100644 --- a/test/integration/rules/aria-required-children/aria-required-children.json +++ b/test/integration/rules/aria-required-children/aria-required-children.json @@ -28,7 +28,9 @@ ["#pass15"], ["#pass16"], ["#pass17"], - ["#pass18"] + ["#pass18"], + ["#pass19"], + ["#pass20"] ], "incomplete": [ ["#incomplete1"], @@ -39,8 +41,6 @@ ["#incomplete6"], ["#incomplete7"], ["#incomplete8"], - ["#incomplete9"], - ["#incomplete10"], ["#incomplete11"] ] } From c5005bafe6a618bfcdea215eecabdad6377ebe7c Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 01:56:01 +0100 Subject: [PATCH 30/46] further relaxation of doc-endnote and doc-biblioentry (deprecated in DPUB ARIA 1.1) --- lib/commons/aria/get-element-unallowed-roles.js | 4 ++-- lib/commons/aria/lookup-table.js | 4 ++-- lib/standards/dpub-roles.js | 8 ++++---- test/commons/standards/get-aria-roles-by-type.js | 3 +++ .../rules/aria-allowed-role/aria-allowed-role.html | 9 +++++++++ .../rules/aria-allowed-role/aria-allowed-role.json | 11 +++++++---- 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/lib/commons/aria/get-element-unallowed-roles.js b/lib/commons/aria/get-element-unallowed-roles.js index d15f75db05..ba3e58419d 100644 --- a/lib/commons/aria/get-element-unallowed-roles.js +++ b/lib/commons/aria/get-element-unallowed-roles.js @@ -8,10 +8,10 @@ import { tokenList, isHtmlElement, matchesSelector } from '../../core/utils'; // HTML elements (img, link, etc.) const dpubRoles = [ 'doc-backlink', - 'doc-biblioentry', + // 'doc-biblioentry', 'doc-biblioref', 'doc-cover', - 'doc-endnote', + // 'doc-endnote', 'doc-glossref', 'doc-noteref' ]; diff --git a/lib/commons/aria/lookup-table.js b/lib/commons/aria/lookup-table.js index c29a3b72eb..0cf3a3243d 100644 --- a/lib/commons/aria/lookup-table.js +++ b/lib/commons/aria/lookup-table.js @@ -590,7 +590,7 @@ lookupTable.role = { ] }, 'doc-biblioentry': { - type: 'listitem', + type: 'structure', attributes: { allowed: [ 'aria-expanded', @@ -714,7 +714,7 @@ lookupTable.role = { allowedElements: ['section'] }, 'doc-endnote': { - type: 'listitem', + type: 'structure', attributes: { allowed: [ 'aria-expanded', diff --git a/lib/standards/dpub-roles.js b/lib/standards/dpub-roles.js index d5288f4dd7..0cb7070a44 100644 --- a/lib/standards/dpub-roles.js +++ b/lib/standards/dpub-roles.js @@ -27,7 +27,7 @@ const dpubRoles = { superclassRole: ['link'] }, 'doc-biblioentry': { - type: 'listitem', + type: 'structure', requiredContext: ['doc-bibliography'], allowedAttrs: [ 'aria-expanded', @@ -35,7 +35,7 @@ const dpubRoles = { 'aria-posinset', 'aria-setsize' ], - superclassRole: ['listitem'] + superclassRole: ['none'] }, 'doc-bibliography': { type: 'landmark', @@ -85,7 +85,7 @@ const dpubRoles = { superclassRole: ['section'] }, 'doc-endnote': { - type: 'listitem', + type: 'structure', requiredContext: ['doc-endnotes'], allowedAttrs: [ 'aria-expanded', @@ -93,7 +93,7 @@ const dpubRoles = { 'aria-posinset', 'aria-setsize' ], - superclassRole: ['listitem'] + superclassRole: ['none'] }, 'doc-endnotes': { type: 'landmark', diff --git a/test/commons/standards/get-aria-roles-by-type.js b/test/commons/standards/get-aria-roles-by-type.js index 9671e98e1b..4014f2fb6f 100644 --- a/test/commons/standards/get-aria-roles-by-type.js +++ b/test/commons/standards/get-aria-roles-by-type.js @@ -12,6 +12,7 @@ describe('standards.getAriaRolesByType', function() { it('should return a list of role names by type', function() { // Source: https://www.w3.org/TR/wai-aria-1.1/#document_structure_roles var structureRoles = getAriaRolesByType('structure'); + // console.log(JSON.stringify(structureRoles, null, 4)); assert.deepEqual(structureRoles, [ 'article', 'blockquote', @@ -50,6 +51,8 @@ describe('standards.getAriaRolesByType', function() { 'time', 'toolbar', 'tooltip', + 'doc-biblioentry', + 'doc-endnote', 'doc-example' ]); }); diff --git a/test/integration/rules/aria-allowed-role/aria-allowed-role.html b/test/integration/rules/aria-allowed-role/aria-allowed-role.html index 60df8caed8..bf4fc6fac7 100644 --- a/test/integration/rules/aria-allowed-role/aria-allowed-role.html +++ b/test/integration/rules/aria-allowed-role/aria-allowed-role.html @@ -8,6 +8,15 @@
      +

      + +

      +
        +
      • +
      +

      + +

      diff --git a/test/integration/rules/aria-allowed-role/aria-allowed-role.json b/test/integration/rules/aria-allowed-role/aria-allowed-role.json index 0f5365dfc0..66784320cd 100644 --- a/test/integration/rules/aria-allowed-role/aria-allowed-role.json +++ b/test/integration/rules/aria-allowed-role/aria-allowed-role.json @@ -9,6 +9,9 @@ ["#pass-object-role-document"], ["#pass-section-role-doc-afterword"], ["#pass-section-role-doc-bib"], + ["#pass-li-role-doc-biblioentry2"], + ["#pass-li-role-doc-endnote2"], + ["#pass-li-role-doc-endnote"], ["#pass-li-role-doc-biblioentry"], ["#pass-aside-doc-example"], ["#pass-figure-doc-example"], @@ -67,7 +70,9 @@ ["#pass-dpub-6"], ["#pass-dpub-7"], ["#hr-presentation"], - ["#hr-none"] + ["#hr-none"], + ["#fail-dpub-6"], + ["#fail-dpub-7"] ], "violations": [ ["#fail-dd-no-role"], @@ -87,9 +92,7 @@ ["#fail-dpub-2"], ["#fail-dpub-3"], ["#fail-dpub-4"], - ["#fail-dpub-5"], - ["#fail-dpub-6"], - ["#fail-dpub-7"] + ["#fail-dpub-5"] ], "incomplete": [["#incomplete1"], ["#incomplete2"]] } From 7673aaa4702d532711629082fb3cf3ad5437b761 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 02:08:32 +0100 Subject: [PATCH 31/46] version bump and URL update --- bower.json | 2 +- package-lock.json | 2 +- package.json | 6 +++--- test/version.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bower.json b/bower.json index ac86ac3ded..b95180a205 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "axe-core", - "version": "4.1.4", + "version": "4.1.4-canary.1", "contributors": [ { "name": "David Sturley", diff --git a/package-lock.json b/package-lock.json index b09c15cdc3..4b0de84033 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@daisy/axe-core-for-ace", - "version": "4.1.4-canary.0", + "version": "4.1.4-canary.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ce56c035ee..643e61a2b3 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.4-canary.0", + "version": "4.1.4-canary.1", "license": "MPL-2.0", "engines": { "node": ">=4" @@ -34,10 +34,10 @@ "url": "http://deque.com/" } ], - "homepage": "https://www.deque.com/axe/", + "homepage": "https://github.com/daisy/axe-core/pull/4", "repository": { "type": "git", - "url": "https://github.com/dequelabs/axe-core.git" + "url": "https://github.com/daisy/axe-core.git" }, "keywords": [ "Accessibility", diff --git a/test/version.js b/test/version.js index 14eb097219..8e797a4609 100644 --- a/test/version.js +++ b/test/version.js @@ -1,2 +1,2 @@ // This is temporary as the tests still need to use this file -axe.version = '4.1.4-canary.0'; +axe.version = '4.1.4-canary.1'; From 1a8dd7a516927850a44d87004ce25456c58c1404 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 03:26:01 +0100 Subject: [PATCH 32/46] fixes landmark-unique (DPUB roles) https://github.com/daisy/ace/issues/341 --- .../landmarks/landmark-is-unique-evaluate.js | 2 +- .../rules/heading-order/frame.html | 2 +- .../landmark-unique-pass_.json | 5 ++++ .../landmark-unique-pass_.xhtml | 18 +++++++++++++ test/integration/rules/runner.js | 25 +++++++++++++++++-- 5 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 test/integration/rules/landmark-unique/landmark-unique-pass_.json create mode 100644 test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml diff --git a/lib/checks/landmarks/landmark-is-unique-evaluate.js b/lib/checks/landmarks/landmark-is-unique-evaluate.js index 83aa04c77e..3dd658b56b 100644 --- a/lib/checks/landmarks/landmark-is-unique-evaluate.js +++ b/lib/checks/landmarks/landmark-is-unique-evaluate.js @@ -2,7 +2,7 @@ import { getRole } from '../../commons/aria'; import { accessibleTextVirtual } from '../../commons/text'; function landmarkIsUniqueEvaluate(node, options, virtualNode) { - var role = getRole(node); + var role = getRole(node, { dpub: true }); var accessibleText = accessibleTextVirtual(virtualNode); accessibleText = accessibleText ? accessibleText.toLowerCase() : null; this.data({ role: role, accessibleText: accessibleText }); diff --git a/test/integration/rules/heading-order/frame.html b/test/integration/rules/heading-order/frame.html index a28abfdeb7..fc46b81dd5 100644 --- a/test/integration/rules/heading-order/frame.html +++ b/test/integration/rules/heading-order/frame.html @@ -2,7 +2,7 @@ - landmark-unique test + heading order test diff --git a/test/integration/rules/landmark-unique/landmark-unique-pass_.json b/test/integration/rules/landmark-unique/landmark-unique-pass_.json new file mode 100644 index 0000000000..e86c01cfd2 --- /dev/null +++ b/test/integration/rules/landmark-unique/landmark-unique-pass_.json @@ -0,0 +1,5 @@ +{ + "description": "landmark-unique-pass_ tests", + "rule": "landmark-unique", + "passes": [["#pass-nav-toc"], ["#pass-nav-nav"], ["#pass-nav-pagelist"]] +} diff --git a/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml b/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml new file mode 100644 index 0000000000..ff4eb26b9f --- /dev/null +++ b/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml @@ -0,0 +1,18 @@ + + + diff --git a/test/integration/rules/runner.js b/test/integration/rules/runner.js index 219aa696d8..3295143938 100644 --- a/test/integration/rules/runner.js +++ b/test/integration/rules/runner.js @@ -63,6 +63,11 @@ test[collection].forEach(function(selector) { it('should find ' + JSON.stringify(selector), function() { if (!nodes) { + console.log( + JSON.stringify(results, null, 4), + ' ---- ', + JSON.stringify(test[collection], null, 4) + ); assert(false, 'there are no ' + collection); return; } @@ -81,10 +86,20 @@ }); if (matches.length === 0) { + console.log( + JSON.stringify(results, null, 4), + ' ---- ', + JSON.stringify(test[collection], null, 4) + ); assert(false, 'Element not found'); } else if (matches.length === 1) { assert(true, 'Element found'); } else { + console.log( + JSON.stringify(results, null, 4), + ' ---- ', + JSON.stringify(test[collection], null, 4) + ); assert( false, 'Found ' + @@ -106,14 +121,20 @@ }); if (targets && targets.length) { console.log( - JSON.stringify(results[collection]), + JSON.stringify(results, null, 4), ' ---- ', - JSON.stringify(test[collection]) + JSON.stringify(test[collection], null, 4) ); } // check that all nodes are removed assert.equal(JSON.stringify(targets), '[]'); } else { + console.log( + JSON.stringify(results, null, 4), + ' ---- ', + JSON.stringify(test[collection], null, 4) + ); + assert(false, 'there are no ' + collection); } }); From d159e5142a277467f4315c1d5e8e6de30d861dc4 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 05:46:30 +0100 Subject: [PATCH 33/46] version bump --- bower.json | 2 +- package-lock.json | 2 +- package.json | 2 +- test/version.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bower.json b/bower.json index b95180a205..0e7b7784bc 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "axe-core", - "version": "4.1.4-canary.1", + "version": "4.1.4-canary.2", "contributors": [ { "name": "David Sturley", diff --git a/package-lock.json b/package-lock.json index 4b0de84033..a3d0349072 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@daisy/axe-core-for-ace", - "version": "4.1.4-canary.1", + "version": "4.1.4-canary.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 643e61a2b3..da829ab478 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.4-canary.1", + "version": "4.1.4-canary.2", "license": "MPL-2.0", "engines": { "node": ">=4" diff --git a/test/version.js b/test/version.js index 8e797a4609..5bc0e8b5f3 100644 --- a/test/version.js +++ b/test/version.js @@ -1,2 +1,2 @@ // This is temporary as the tests still need to use this file -axe.version = '4.1.4-canary.1'; +axe.version = '4.1.4-canary.2'; From 09b6abe592f7a5c7ffde15f59177a97d36136dc6 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 10:50:52 +0100 Subject: [PATCH 34/46] Axe landmark unique fixes (weird DOM parser bug ignores some element names) --- .../landmarks/landmark-is-unique-after.js | 14 +++- .../landmarks/landmark-is-unique-evaluate.js | 33 +++++++- lib/commons/aria/lookup-table.js | 2 + .../landmarks/landmark-is-unique-after.js | 43 +++++++---- test/checks/landmarks/landmark-is-unique.js | 2 + .../landmark-unique-pass_.json | 12 ++- .../landmark-unique-pass_.xhtml | 76 ++++++++++++++++--- test/integration/rules/runner.js | 10 +-- 8 files changed, 156 insertions(+), 36 deletions(-) diff --git a/lib/checks/landmarks/landmark-is-unique-after.js b/lib/checks/landmarks/landmark-is-unique-after.js index 5ccceac3aa..7b5cbaeba0 100644 --- a/lib/checks/landmarks/landmark-is-unique-after.js +++ b/lib/checks/landmarks/landmark-is-unique-after.js @@ -1,11 +1,20 @@ function landmarkIsUniqueAfter(results) { + // console.log("landmarkIsUniqueAfter results: ", JSON.stringify(results, null, 4)); + var uniqueLandmarks = []; // filter out landmark elements that share the same role and accessible text // so every non-unique landmark isn't reported as a failure (just the first) - return results.filter(currentResult => { + var filtered = results.filter(currentResult => { + if (!currentResult.data) { + // console.log('landmarkIsUniqueAfterlandmarkIsUniqueAfter NO DATA???!!!'); + return false; + } + var findMatch = someResult => { return ( + currentResult.data.isLandmark && + someResult.data.isLandmark && currentResult.data.role === someResult.data.role && currentResult.data.accessibleText === someResult.data.accessibleText ); @@ -22,6 +31,9 @@ function landmarkIsUniqueAfter(results) { currentResult.relatedNodes = []; return true; }); + + // console.log("landmarkIsUniqueAfter filtered: ", JSON.stringify(filtered, null, 4)); + return filtered; } export default landmarkIsUniqueAfter; diff --git a/lib/checks/landmarks/landmark-is-unique-evaluate.js b/lib/checks/landmarks/landmark-is-unique-evaluate.js index 3dd658b56b..c962c0f640 100644 --- a/lib/checks/landmarks/landmark-is-unique-evaluate.js +++ b/lib/checks/landmarks/landmark-is-unique-evaluate.js @@ -1,11 +1,38 @@ -import { getRole } from '../../commons/aria'; +import { getRole, getRoleType } from '../../commons/aria'; import { accessibleTextVirtual } from '../../commons/text'; +import { getAriaRolesByType } from '../../commons/standards'; function landmarkIsUniqueEvaluate(node, options, virtualNode) { - var role = getRole(node, { dpub: true }); + var role = getRole(node, { dpub: true }); // fallback: true + if (!role) { + // this.data({ role: '', accessibleText: '', isLandmark: null }); + // console.log('landmarkIsUniqueEvaluate landmarkIsUniqueEvaluate landmarkIsUniqueEvaluate NO ROLE???!!!'); + return false; + } + + var landmarks = getAriaRolesByType('landmark'); + var roleType = getRoleType(role); + var isLandmark = + roleType === 'landmark' || + landmarks.includes(roleType) || + landmarks.includes(role); + + // if (!isLandmark) { + // // this.data({ role: '', accessibleText: '', isLandmark: null }); + // return false; + // } + // throw new Error('BREAK'); + var accessibleText = accessibleTextVirtual(virtualNode); + + // console.log('\n\n', virtualNode.props ? virtualNode.props.nodeName : '!virtualNode.props', role, roleType, JSON.stringify(landmarks), isLandmark, " [[" + accessibleText + "]]") + accessibleText = accessibleText ? accessibleText.toLowerCase() : null; - this.data({ role: role, accessibleText: accessibleText }); + this.data({ + role: role, + accessibleText: accessibleText, + isLandmark: isLandmark + }); this.relatedNodes([node]); return true; diff --git a/lib/commons/aria/lookup-table.js b/lib/commons/aria/lookup-table.js index 0cf3a3243d..6da5bcd5aa 100644 --- a/lib/commons/aria/lookup-table.js +++ b/lib/commons/aria/lookup-table.js @@ -611,6 +611,7 @@ lookupTable.role = { attributes: { allowed: ['aria-expanded', 'aria-errormessage'] }, + owned: null, // owned: { // one: ['doc-biblioentry'] // }, @@ -735,6 +736,7 @@ lookupTable.role = { attributes: { allowed: ['aria-expanded', 'aria-errormessage'] }, + owned: null, // owned: { // one: ['doc-endnote'] // }, diff --git a/test/checks/landmarks/landmark-is-unique-after.js b/test/checks/landmarks/landmark-is-unique-after.js index c626ba5e3c..d2bd9ee25d 100644 --- a/test/checks/landmarks/landmark-is-unique-after.js +++ b/test/checks/landmarks/landmark-is-unique-after.js @@ -29,54 +29,65 @@ describe('landmark-is-unique-after', function() { it('should update duplicate landmarks with failed result', function() { var result = checks['landmark-is-unique'].after([ createResultWithSameRelatedNodes(true, { - role: 'some role', - accessibleText: 'some accessibleText' + role: 'doc-afterword', + accessibleText: 'some accessibleText', + isLandmark: true // truthy }), createResultWithSameRelatedNodes(true, { - role: 'some role', - accessibleText: 'some accessibleText' + role: 'doc-afterword', + accessibleText: 'some accessibleText', + isLandmark: 111 // truthy }), createResultWithSameRelatedNodes(true, { - role: 'different role', - accessibleText: 'some accessibleText' + role: 'alertdialog', + accessibleText: 'some accessibleText', + isLandmark: false // falsy }), createResultWithSameRelatedNodes(true, { - role: 'some role', - accessibleText: 'different accessibleText' + role: 'doc-afterword', + accessibleText: 'different accessibleText', + isLandmark: 'true' // truthy }) ]); + // console.log("result: ", JSON.stringify(result, null, 4)); var expectedResult = [ createResultWithProvidedRelatedNodes( false, { - role: 'some role', - accessibleText: 'some accessibleText' + role: 'doc-afterword', + accessibleText: 'some accessibleText', + isLandmark: true // truthy }, [ createResult(true, { - role: 'some role', - accessibleText: 'some accessibleText' + role: 'doc-afterword', + accessibleText: 'some accessibleText', + isLandmark: 111 // truthy }) ] ), createResultWithProvidedRelatedNodes( true, { - role: 'different role', - accessibleText: 'some accessibleText' + role: 'alertdialog', + accessibleText: 'some accessibleText', + isLandmark: false // falsy }, [] ), createResultWithProvidedRelatedNodes( true, { - role: 'some role', - accessibleText: 'different accessibleText' + role: 'doc-afterword', + accessibleText: 'different accessibleText', + isLandmark: 'true' // truthy }, [] ) ]; + // console.log("expectedResult: ", JSON.stringify(expectedResult, null, 4)); + assert.deepEqual(result, expectedResult); }); }); diff --git a/test/checks/landmarks/landmark-is-unique.js b/test/checks/landmarks/landmark-is-unique.js index 049615deee..e9d90ecbce 100644 --- a/test/checks/landmarks/landmark-is-unique.js +++ b/test/checks/landmarks/landmark-is-unique.js @@ -20,6 +20,7 @@ describe('landmark-is-unique', function() { var node = fixture.querySelector('div'); var expectedData = { accessibleText: null, + isLandmark: true, role: 'main' }; axe._tree = axe.utils.getFlattenedTree(fixture); @@ -38,6 +39,7 @@ describe('landmark-is-unique', function() { var node = fixture.querySelector('div'); var expectedData = { accessibleText: 'test text', + isLandmark: true, role: 'main' }; axe._tree = axe.utils.getFlattenedTree(fixture); diff --git a/test/integration/rules/landmark-unique/landmark-unique-pass_.json b/test/integration/rules/landmark-unique/landmark-unique-pass_.json index e86c01cfd2..c78d917d4d 100644 --- a/test/integration/rules/landmark-unique/landmark-unique-pass_.json +++ b/test/integration/rules/landmark-unique/landmark-unique-pass_.json @@ -1,5 +1,15 @@ { "description": "landmark-unique-pass_ tests", "rule": "landmark-unique", - "passes": [["#pass-nav-toc"], ["#pass-nav-nav"], ["#pass-nav-pagelist"]] + "violations": [["#header-notes"]], + "passes": [ + ["#pass-nav-toc"], + ["#pass-nav-nav"], + ["#pass-nav-pagelist"], + ["#pass-nav-pagelist-other"], + ["#pass-epi"], + ["#pass-biblio"], + ["#pass-aside-footnote1"], + ["#pass-aside-footnote2"] + ] } diff --git a/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml b/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml index ff4eb26b9f..b5997c2a74 100644 --- a/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml +++ b/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml @@ -1,18 +1,74 @@ + + + + landmark-unique pass test + + + + + + +

      Loomings

      +

      Call me Ishmael.

      + + role="doc-toc">1 - + + role="doc-pagelist">3 + + + + + +

      tmp1

      + +
      n text
      +
      +

      n txt1

      +
      +
      +

      n txt2

      +
      + +
      text
      + + + + + diff --git a/test/integration/rules/runner.js b/test/integration/rules/runner.js index 3295143938..dd713e13b6 100644 --- a/test/integration/rules/runner.js +++ b/test/integration/rules/runner.js @@ -66,7 +66,7 @@ console.log( JSON.stringify(results, null, 4), ' ---- ', - JSON.stringify(test[collection], null, 4) + JSON.stringify(test, null, 4) ); assert(false, 'there are no ' + collection); return; @@ -89,7 +89,7 @@ console.log( JSON.stringify(results, null, 4), ' ---- ', - JSON.stringify(test[collection], null, 4) + JSON.stringify(test, null, 4) ); assert(false, 'Element not found'); } else if (matches.length === 1) { @@ -98,7 +98,7 @@ console.log( JSON.stringify(results, null, 4), ' ---- ', - JSON.stringify(test[collection], null, 4) + JSON.stringify(test, null, 4) ); assert( false, @@ -123,7 +123,7 @@ console.log( JSON.stringify(results, null, 4), ' ---- ', - JSON.stringify(test[collection], null, 4) + JSON.stringify(test, null, 4) ); } // check that all nodes are removed @@ -132,7 +132,7 @@ console.log( JSON.stringify(results, null, 4), ' ---- ', - JSON.stringify(test[collection], null, 4) + JSON.stringify(test, null, 4) ); assert(false, 'there are no ' + collection); From a8d882a9b0bf00d08eeb3677e4cee50a9dacc2d3 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 12:13:40 +0100 Subject: [PATCH 35/46] added unit test for landmark unique (broken DOM parser it seems) --- .../rules/landmark-unique/landmark-unique-pass_.json | 3 ++- .../landmark-unique/landmark-unique-pass_.xhtml | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/test/integration/rules/landmark-unique/landmark-unique-pass_.json b/test/integration/rules/landmark-unique/landmark-unique-pass_.json index c78d917d4d..3c0f07e6fe 100644 --- a/test/integration/rules/landmark-unique/landmark-unique-pass_.json +++ b/test/integration/rules/landmark-unique/landmark-unique-pass_.json @@ -10,6 +10,7 @@ ["#pass-epi"], ["#pass-biblio"], ["#pass-aside-footnote1"], - ["#pass-aside-footnote2"] + ["#pass-aside-footnote2"], + ["#pass-aside-footnote3"] ] } diff --git a/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml b/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml index b5997c2a74..d66c22f593 100644 --- a/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml +++ b/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml @@ -54,13 +54,13 @@
      text
      - + +
      +

      txt3

      +
      From 491abc8aad60a45900b68c851fc6e1cc182e336b Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 7 Apr 2021 14:49:51 +0100 Subject: [PATCH 36/46] final round of fixes for landmark unique (rule filter takes precedence over check filters, of course) --- .../landmarks/landmark-is-unique-after.js | 4 +-- .../landmarks/landmark-is-unique-evaluate.js | 22 ++++++------- lib/rules/landmark-unique-matches.js | 20 +++++++++--- .../landmarks/landmark-is-unique-after.js | 32 +++++++++---------- test/checks/landmarks/landmark-is-unique.js | 4 +-- .../landmark-unique-pass_.json | 6 ++-- .../landmark-unique-pass_.xhtml | 2 ++ 7 files changed, 51 insertions(+), 39 deletions(-) diff --git a/lib/checks/landmarks/landmark-is-unique-after.js b/lib/checks/landmarks/landmark-is-unique-after.js index 7b5cbaeba0..0cc943fca3 100644 --- a/lib/checks/landmarks/landmark-is-unique-after.js +++ b/lib/checks/landmarks/landmark-is-unique-after.js @@ -13,8 +13,8 @@ function landmarkIsUniqueAfter(results) { var findMatch = someResult => { return ( - currentResult.data.isLandmark && - someResult.data.isLandmark && + // currentResult.data.isLandmark && + // someResult.data.isLandmark && currentResult.data.role === someResult.data.role && currentResult.data.accessibleText === someResult.data.accessibleText ); diff --git a/lib/checks/landmarks/landmark-is-unique-evaluate.js b/lib/checks/landmarks/landmark-is-unique-evaluate.js index c962c0f640..8f543a180e 100644 --- a/lib/checks/landmarks/landmark-is-unique-evaluate.js +++ b/lib/checks/landmarks/landmark-is-unique-evaluate.js @@ -1,6 +1,6 @@ -import { getRole, getRoleType } from '../../commons/aria'; +import { getRole } from '../../commons/aria'; // getRoleType import { accessibleTextVirtual } from '../../commons/text'; -import { getAriaRolesByType } from '../../commons/standards'; +// import { getAriaRolesByType } from '../../commons/standards'; function landmarkIsUniqueEvaluate(node, options, virtualNode) { var role = getRole(node, { dpub: true }); // fallback: true @@ -10,12 +10,12 @@ function landmarkIsUniqueEvaluate(node, options, virtualNode) { return false; } - var landmarks = getAriaRolesByType('landmark'); - var roleType = getRoleType(role); - var isLandmark = - roleType === 'landmark' || - landmarks.includes(roleType) || - landmarks.includes(role); + // var landmarks = getAriaRolesByType('landmark'); + // var roleType = getRoleType(role); + // var isLandmark = + // roleType === 'landmark' || + // landmarks.includes(roleType) || + // landmarks.includes(role); // if (!isLandmark) { // // this.data({ role: '', accessibleText: '', isLandmark: null }); @@ -25,13 +25,13 @@ function landmarkIsUniqueEvaluate(node, options, virtualNode) { var accessibleText = accessibleTextVirtual(virtualNode); - // console.log('\n\n', virtualNode.props ? virtualNode.props.nodeName : '!virtualNode.props', role, roleType, JSON.stringify(landmarks), isLandmark, " [[" + accessibleText + "]]") + // console.log('\n\n ))))) ', virtualNode.props ? virtualNode.props.nodeName : '!virtualNode.props', role, roleType, JSON.stringify(landmarks), isLandmark, " [[" + accessibleText + "]]") accessibleText = accessibleText ? accessibleText.toLowerCase() : null; this.data({ role: role, - accessibleText: accessibleText, - isLandmark: isLandmark + accessibleText: accessibleText + // isLandmark: isLandmark }); this.relatedNodes([node]); diff --git a/lib/rules/landmark-unique-matches.js b/lib/rules/landmark-unique-matches.js index 94e3564fb7..bfa6ccbf96 100644 --- a/lib/rules/landmark-unique-matches.js +++ b/lib/rules/landmark-unique-matches.js @@ -1,5 +1,5 @@ import { findUpVirtual, isVisible } from '../commons/dom'; -import { getRole } from '../commons/aria'; +import { getRole, getRoleType } from '../commons/aria'; import { getAriaRolesByType } from '../commons/standards'; import { accessibleTextVirtual } from '../commons/text'; @@ -26,22 +26,34 @@ function landmarkUniqueMatches(node, virtualNode) { function isLandmarkVirtual(virtualNode) { var { actualNode } = virtualNode; var landmarkRoles = getAriaRolesByType('landmark'); - var role = getRole(actualNode); + + var role = getRole(actualNode, { dpub: true }); if (!role) { return false; } + // console.log('\n\n isLandmarkVirtual 1>> ', actualNode.nodeName, role); var nodeName = actualNode.nodeName.toUpperCase(); if (nodeName === 'HEADER' || nodeName === 'FOOTER') { - return isHeaderFooterLandmark(virtualNode); + var v = isHeaderFooterLandmark(virtualNode); + // console.log('\n\n isLandmarkVirtual 2>> ', v); + return v; } if (nodeName === 'SECTION' || nodeName === 'FORM') { var accessibleText = accessibleTextVirtual(virtualNode); + // console.log('\n\n isLandmarkVirtual 3>> ', !!accessibleText); return !!accessibleText; } - return landmarkRoles.indexOf(role) >= 0 || role === 'region'; + var roleType = getRoleType(role); + // console.log('\n\n isLandmarkVirtual 4>> ', roleType); + return ( + role === 'region' || + roleType === 'landmark' || + landmarkRoles.includes(roleType) || + landmarkRoles.indexOf(role) >= 0 + ); } return isLandmarkVirtual(virtualNode) && isVisible(node, true); diff --git a/test/checks/landmarks/landmark-is-unique-after.js b/test/checks/landmarks/landmark-is-unique-after.js index d2bd9ee25d..fef990103a 100644 --- a/test/checks/landmarks/landmark-is-unique-after.js +++ b/test/checks/landmarks/landmark-is-unique-after.js @@ -30,23 +30,23 @@ describe('landmark-is-unique-after', function() { var result = checks['landmark-is-unique'].after([ createResultWithSameRelatedNodes(true, { role: 'doc-afterword', - accessibleText: 'some accessibleText', - isLandmark: true // truthy + accessibleText: 'some accessibleText' + // isLandmark: true // truthy }), createResultWithSameRelatedNodes(true, { role: 'doc-afterword', - accessibleText: 'some accessibleText', - isLandmark: 111 // truthy + accessibleText: 'some accessibleText' + // isLandmark: 111 // truthy }), createResultWithSameRelatedNodes(true, { role: 'alertdialog', - accessibleText: 'some accessibleText', - isLandmark: false // falsy + accessibleText: 'some accessibleText' + // isLandmark: false // falsy }), createResultWithSameRelatedNodes(true, { role: 'doc-afterword', - accessibleText: 'different accessibleText', - isLandmark: 'true' // truthy + accessibleText: 'different accessibleText' + // isLandmark: 'true' // truthy }) ]); // console.log("result: ", JSON.stringify(result, null, 4)); @@ -56,14 +56,14 @@ describe('landmark-is-unique-after', function() { false, { role: 'doc-afterword', - accessibleText: 'some accessibleText', - isLandmark: true // truthy + accessibleText: 'some accessibleText' + // isLandmark: true // truthy }, [ createResult(true, { role: 'doc-afterword', - accessibleText: 'some accessibleText', - isLandmark: 111 // truthy + accessibleText: 'some accessibleText' + // isLandmark: 111 // truthy }) ] ), @@ -71,8 +71,8 @@ describe('landmark-is-unique-after', function() { true, { role: 'alertdialog', - accessibleText: 'some accessibleText', - isLandmark: false // falsy + accessibleText: 'some accessibleText' + // isLandmark: false // falsy }, [] ), @@ -80,8 +80,8 @@ describe('landmark-is-unique-after', function() { true, { role: 'doc-afterword', - accessibleText: 'different accessibleText', - isLandmark: 'true' // truthy + accessibleText: 'different accessibleText' + // isLandmark: 'true' // truthy }, [] ) diff --git a/test/checks/landmarks/landmark-is-unique.js b/test/checks/landmarks/landmark-is-unique.js index e9d90ecbce..5de5b32a61 100644 --- a/test/checks/landmarks/landmark-is-unique.js +++ b/test/checks/landmarks/landmark-is-unique.js @@ -20,7 +20,7 @@ describe('landmark-is-unique', function() { var node = fixture.querySelector('div'); var expectedData = { accessibleText: null, - isLandmark: true, + // isLandmark: true, role: 'main' }; axe._tree = axe.utils.getFlattenedTree(fixture); @@ -39,7 +39,7 @@ describe('landmark-is-unique', function() { var node = fixture.querySelector('div'); var expectedData = { accessibleText: 'test text', - isLandmark: true, + // isLandmark: true, role: 'main' }; axe._tree = axe.utils.getFlattenedTree(fixture); diff --git a/test/integration/rules/landmark-unique/landmark-unique-pass_.json b/test/integration/rules/landmark-unique/landmark-unique-pass_.json index 3c0f07e6fe..7c3f6c8868 100644 --- a/test/integration/rules/landmark-unique/landmark-unique-pass_.json +++ b/test/integration/rules/landmark-unique/landmark-unique-pass_.json @@ -1,7 +1,7 @@ { "description": "landmark-unique-pass_ tests", "rule": "landmark-unique", - "violations": [["#header-notes"]], + "violations": [["#header-notes"], ["#pass-aside-footnote1"]], "passes": [ ["#pass-nav-toc"], ["#pass-nav-nav"], @@ -9,8 +9,6 @@ ["#pass-nav-pagelist-other"], ["#pass-epi"], ["#pass-biblio"], - ["#pass-aside-footnote1"], - ["#pass-aside-footnote2"], - ["#pass-aside-footnote3"] + ["#section-notes"] ] } diff --git a/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml b/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml index d66c22f593..618e6a0708 100644 --- a/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml +++ b/test/integration/rules/landmark-unique/landmark-unique-pass_.xhtml @@ -36,6 +36,8 @@

      tmp1

      +

      tmp3

      +
      n text
      Date: Wed, 7 Apr 2021 14:53:27 +0100 Subject: [PATCH 37/46] version bump --- bower.json | 2 +- package-lock.json | 2 +- package.json | 2 +- test/version.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bower.json b/bower.json index 0e7b7784bc..f5cd787461 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "axe-core", - "version": "4.1.4-canary.2", + "version": "4.1.4-canary.3", "contributors": [ { "name": "David Sturley", diff --git a/package-lock.json b/package-lock.json index a3d0349072..f1cf2f830b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@daisy/axe-core-for-ace", - "version": "4.1.4-canary.2", + "version": "4.1.4-canary.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index da829ab478..e20cd90cd5 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.4-canary.2", + "version": "4.1.4-canary.3", "license": "MPL-2.0", "engines": { "node": ">=4" diff --git a/test/version.js b/test/version.js index 5bc0e8b5f3..583ae39d5f 100644 --- a/test/version.js +++ b/test/version.js @@ -1,2 +1,2 @@ // This is temporary as the tests still need to use this file -axe.version = '4.1.4-canary.2'; +axe.version = '4.1.4-canary.3'; From 3c08e8cb2b289475b93d3876e749a7319df09422 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 23 Jun 2021 09:55:29 +0100 Subject: [PATCH 38/46] added missing NPM publish files --- package.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/package.json b/package.json index e979667d0d..11f5d3f57a 100644 --- a/package.json +++ b/package.json @@ -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 6cf8250f53d3858bb21faa47ee93ce08d7e6d078 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 23 Jun 2021 10:35:41 +0100 Subject: [PATCH 39/46] removed unnecessary files --- build/tasks/testconfig.js | 37 ---------------------- build/test/config.js | 63 ------------------------------------- build/test/get-test-urls.js | 47 --------------------------- test/version.js | 2 -- 4 files changed, 149 deletions(-) delete mode 100644 build/tasks/testconfig.js delete mode 100644 build/test/config.js delete mode 100644 build/test/get-test-urls.js delete mode 100644 test/version.js diff --git a/build/tasks/testconfig.js b/build/tasks/testconfig.js deleted file mode 100644 index 8fd09f2a53..0000000000 --- a/build/tasks/testconfig.js +++ /dev/null @@ -1,37 +0,0 @@ -/*eslint-env node */ -'use strict'; - -module.exports = function(grunt) { - grunt.registerMultiTask( - 'testconfig', - 'This task creates a file with all the source test config and HTML fixtures in a single JS object `tests`', - function() { - var result = { - tests: {}, - urls: [] - }; - - this.files.forEach(function(f) { - f.src.forEach(function(filepath) { - var config = grunt.file.readJSON(filepath); - 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); - }); - grunt.config(['testconfig', 'options', 'data'], result); - if (f.dest) { - grunt.file.write( - f.dest, - 'var tests = ' + JSON.stringify(result.tests) - ); - } - }); - } - ); -}; diff --git a/build/test/config.js b/build/test/config.js deleted file mode 100644 index 033a63a309..0000000000 --- a/build/test/config.js +++ /dev/null @@ -1,63 +0,0 @@ -exports = module.exports = function(grunt, options) { - var host = 'localhost'; - - if (process.env.REMOTE_TESTSERVER_HOST) { - host = process.env.REMOTE_TESTSERVER_HOST; - } - - function mapToUrl(files, port) { - return grunt.file.expand(files).map(function(file) { - return 'http://' + host + ':' + port + '/' + file; - }); - } - - return { - options: options, - unit: { - options: { - logErrors: true, - log: true, - urls: [ - 'http://' + host + ':<%= connect.test.options.port %>/test/core/', - 'http://' + host + ':<%= connect.test.options.port %>/test/checks/', - 'http://' + - host + - ':<%= connect.test.options.port %>/test/rule-matches/', - 'http://' + host + ':<%= connect.test.options.port %>/test/commons/', - 'http://' + - host + - ':<%= connect.test.options.port %>/test/integration/rules/', - 'http://' + - host + - ':<%= connect.test.options.port %>/test/integration/api/external/', - 'http://' + - host + - ':<%= connect.test.options.port %>/test/integration/virtual-rules/' - ], - run: true, - growlOnSuccess: false, - mocha: { - grep: grunt.option('grep') - } - } - }, - integration: { - options: { - log: true, - urls: mapToUrl( - [ - 'test/integration/full/**/*__.xhtml', - 'test/integration/full/**/*.html', - '!test/integration/full/**/frames/**/*.html' - ], - '<%= connect.test.options.port %>' - ), - run: true, - growlOnSuccess: false, - mocha: { - grep: grunt.option('grep') - } - } - } - }; -}; diff --git a/build/test/get-test-urls.js b/build/test/get-test-urls.js deleted file mode 100644 index 1a087c1f26..0000000000 --- a/build/test/get-test-urls.js +++ /dev/null @@ -1,47 +0,0 @@ -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`, - /** - * 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/epub-type-has-matching-role/**/*__.xhtml', - // 'test/integration/full/pagebreak-label/**/*__.xhtml', - - 'test/integration/full/**/*__.xhtml', - 'test/integration/full/**/*.html', - '!test/integration/full/**/frames/**/*.html' - ]) - ).map(file => `http://${host}:${port}/${file}`) - ]; - return urls; -}; - -module.exports = getTestUrls; diff --git a/test/version.js b/test/version.js deleted file mode 100644 index 583ae39d5f..0000000000 --- a/test/version.js +++ /dev/null @@ -1,2 +0,0 @@ -// This is temporary as the tests still need to use this file -axe.version = '4.1.4-canary.3'; From 81440485d6167b4afef68706c52c073b978fac31 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 23 Jun 2021 10:44:05 +0100 Subject: [PATCH 40/46] removed another useless file --- test/runner.tmpl | 74 ------------------------------------------------ 1 file changed, 74 deletions(-) delete mode 100644 test/runner.tmpl diff --git a/test/runner.tmpl b/test/runner.tmpl deleted file mode 100644 index d673adba45..0000000000 --- a/test/runner.tmpl +++ /dev/null @@ -1,74 +0,0 @@ - - - - - <%=data.title%> - - - - - - - - <% files.forEach(function (file) { %> - - <% }); %> - - - - - -
      -
      - - <% tests.forEach(function (file) { %> - - <% }); %> - - - - - From 205efb08d669631cc80ed204539648eef89d6eb3 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 23 Jun 2021 11:00:06 +0100 Subject: [PATCH 41/46] dpub roles were not taken into account for aria-label prohibited attribute rule/check --- lib/checks/aria/aria-prohibited-attr-evaluate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checks/aria/aria-prohibited-attr-evaluate.js b/lib/checks/aria/aria-prohibited-attr-evaluate.js index ff843065fd..823f4100bd 100644 --- a/lib/checks/aria/aria-prohibited-attr-evaluate.js +++ b/lib/checks/aria/aria-prohibited-attr-evaluate.js @@ -52,7 +52,7 @@ function ariaProhibitedAttrEvaluate(node, options = {}, virtualNode) { } function listProhibitedAttrs(virtualNode, elementsAllowedAriaLabel) { - const role = getRole(virtualNode, { chromium: true }); + const role = getRole(virtualNode, { dpub: true, chromium: true }); const roleSpec = standards.ariaRoles[role]; if (roleSpec) { return roleSpec.prohibitedAttrs || []; From 73d2cd94fbf3631f97842e13fa320e3914da1809 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Wed, 23 Jun 2021 11:01:35 +0100 Subject: [PATCH 42/46] version bump --- bower.json | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bower.json b/bower.json index 836e59c400..f8b655d9c8 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "axe-core", - "version": "4.2.3-canary.1", + "version": "4.2.3-canary.2", "contributors": [ { "name": "David Sturley", diff --git a/package-lock.json b/package-lock.json index 74a05208a8..f485818abf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@daisy/axe-core-for-ace", - "version": "4.2.3-canary.1", + "version": "4.2.3-canary.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 11f5d3f57a..32eb1f7522 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.2.3-canary.1", + "version": "4.2.3-canary.2", "license": "MPL-2.0", "engines": { "node": ">=4" From 19dd52c78469ac1a9b70750b67247d0ec34a0e16 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Mon, 30 Aug 2021 19:22:52 +0100 Subject: [PATCH 43/46] doc update (auto-gen) --- doc/rule-descriptions.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 372def1e2b..78f82a3961 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -74,6 +74,7 @@ | [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.3/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | failure | [73f2c2](https://act-rules.github.io/rules/73f2c2) | | [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.3/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 | | | [empty-table-header](https://dequeuniversity.com/rules/axe/4.3/empty-table-header?application=RuleDescription) | Ensures table headers have discernible text | Minor | wcag131, cat.aria | needs review | | +| [pagebreak-label](https://dequeuniversity.com/rules/axe/4.3/pagebreak-label?application=RuleDescription) | Ensure page markers have an accessible label | Serious | cat.epub | failure | | ## Best Practices Rules @@ -87,6 +88,7 @@ Rules that do not necessarily conform to WCAG success criterion but are industry | [aria-text](https://dequeuniversity.com/rules/axe/4.3/aria-text?application=RuleDescription) | Ensures "role=text" is used on elements with no focusable descendants | Serious | cat.aria, best-practice | failure, needs review | | | [aria-treeitem-name](https://dequeuniversity.com/rules/axe/4.3/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.3/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.3/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.3/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.3/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.3/heading-order?application=RuleDescription) | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | failure, needs review | | @@ -100,7 +102,7 @@ Rules that do not necessarily conform to WCAG success criterion but are industry | [landmark-no-duplicate-banner](https://dequeuniversity.com/rules/axe/4.3/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.3/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.3/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.3/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.3/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.3/landmark-unique?application=RuleDescription) | Landmarks should 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.3/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.3/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 | [b4f0c3](https://act-rules.github.io/rules/b4f0c3) | From 6b68cb184c532c8c7d14b1d00512b3df487d6588 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Mon, 30 Aug 2021 20:18:56 +0100 Subject: [PATCH 44/46] ChromeDriver version update (90 -> 92) --- package-lock.json | 14 +++++++------- package.json | 4 +++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 070ade2d8c..783c77f157 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "axe-core", + "name": "@daisy/axe-core-for-ace", "version": "4.3.3-canary.1", "lockfileVersion": 1, "requires": true, @@ -1302,9 +1302,9 @@ "dev": true }, "@types/yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", "dev": true, "optional": true, "requires": { @@ -1941,9 +1941,9 @@ } }, "chromedriver": { - "version": "90.0.1", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-90.0.1.tgz", - "integrity": "sha512-jvyhin0I/Bacxfet7eg29B1j+5mKR35XwWGbgcCOUALeE3mqcCKJY8xUW9cVrqVqTK9/iUOq8/kar7qrTVshPA==", + "version": "92.0.1", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-92.0.1.tgz", + "integrity": "sha512-LptlDVCs1GgyFNVbRoHzzy948JDVzTgGiVPXjNj385qXKQP3hjAVBIgyvb/Hco0xSEW8fjwJfsm1eQRmu6t4pQ==", "dev": true, "requires": { "@testim/chrome-version": "^1.0.7", diff --git a/package.json b/package.json index 98ae2235fd..c3ebb9c576 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,8 @@ "api-docs": "jsdoc --configure .jsdoc.json", "build": "grunt", "eslint": "eslint --color --format stylish '{lib,test,build,doc}/**/*.js' 'Gruntfile.js'", + "test:chrome": "npm run test -- --browsers Chrome && npm run test:integration:chrome", + "test:firefox": "npm run test -- --browsers Firefox && npm run test:integration:firefox", "test": "npm run test:tsc && run-s \"test:unit:* -- {@}\" --", "test:tsc": "tsc", "test:unit": "karma start test/karma.conf.js", @@ -117,7 +119,7 @@ "aria-query": "^3.0.0", "chai": "~4.2.0", "chalk": "^4.1.0", - "chromedriver": "^90.0.0", + "chromedriver": "^92.0.1", "clone": "^2.1.2", "conventional-commits-parser": "^3.1.0", "css-selector-parser": "^1.3.0", From 327b8c050f2e97a2b2fcb762d6765aa4f2080345 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 14 Sep 2021 17:55:25 +0100 Subject: [PATCH 45/46] 'null' origin fix, see https://github.com/daisy/ace/issues/358#issuecomment-919311084 --- lib/core/base/audit.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/core/base/audit.js b/lib/core/base/audit.js index c02c1b4fbe..1dca98108c 100644 --- a/lib/core/base/audit.js +++ b/lib/core/base/audit.js @@ -19,11 +19,19 @@ const dotRegex = /\{\{.+?\}\}/g; function getDefaultOrigin() { // @see https://html.spec.whatwg.org/multipage/webappapis.html#dom-origin-dev // window.origin does not exist in ie11 - if (window.origin) { + + // 'null' origin skipped, see: + // https://github.com/daisy/ace/issues/358#issuecomment-919311084 + + if (window.origin && window.origin !== 'null') { return window.origin; } // window.location does not exist in node when we run the build - if (window.location && window.location.origin) { + if ( + window.location && + window.location.origin && + window.location.origin !== 'null' + ) { return window.location.origin; } } From 4b0dd53f9e8a71c34dcd2c2b5f637ef2092f3f06 Mon Sep 17 00:00:00 2001 From: Daniel Weck Date: Tue, 14 Sep 2021 17:56:04 +0100 Subject: [PATCH 46/46] version bump to 4.3.3-canary.2 --- bower.json | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bower.json b/bower.json index 7034bef218..0ad5bc6391 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "axe-core", - "version": "4.3.3-canary.1", + "version": "4.3.3-canary.2", "contributors": [ { "name": "David Sturley", diff --git a/package-lock.json b/package-lock.json index 783c77f157..e1ade5c249 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@daisy/axe-core-for-ace", - "version": "4.3.3-canary.1", + "version": "4.3.3-canary.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c3ebb9c576..7962837660 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.3.3-canary.1", + "version": "4.3.3-canary.2", "license": "MPL-2.0", "engines": { "node": ">=4"