From 328ca2c26924b44b81a209ea05159f451984c49f Mon Sep 17 00:00:00 2001 From: Marcy Sutton Date: Tue, 4 Dec 2018 08:23:22 -0800 Subject: [PATCH] feat: new rule landmark-complementary-is-top-level (#1239) * feat: new rule landmark-complementary-is-top-level Best practice requiring asides and complementary landmarks to be top level, in line with the ARIA Authoring Practices Guide. Closes https://github.com/dequelabs/axe-core/issues/795 * fix: remove matches from top-level aside rule The first version of this rule included a body context check copied over from the top-level-banner-landmark rule, and it made very flaky iframe tests. It wasn't really necessary since aside doesn't have the same behavior as header/role=banner. * test: improve readability of landmark check --- doc/aria-supported.md | 2 +- doc/rule-descriptions.md | 153 +++++++++--------- .../landmark-complementary-is-top-level.json | 17 ++ lib/rules/landmark-has-body-context.js | 2 +- test/checks/keyboard/landmark-is-top-level.js | 79 +++++---- .../frames/level1-fail.html | 15 ++ .../frames/level1.html | 27 ++++ .../frames/level2.html | 13 ++ ...dmark-complementary-is-top-level-fail.html | 29 ++++ ...andmark-complementary-is-top-level-fail.js | 45 ++++++ ...dmark-complementary-is-top-level-pass.html | 42 +++++ ...andmark-complementary-is-top-level-pass.js | 41 +++++ 12 files changed, 344 insertions(+), 121 deletions(-) create mode 100644 lib/rules/landmark-complementary-is-top-level.json create mode 100644 test/integration/full/landmark-complementary-is-top-level/frames/level1-fail.html create mode 100644 test/integration/full/landmark-complementary-is-top-level/frames/level1.html create mode 100644 test/integration/full/landmark-complementary-is-top-level/frames/level2.html create mode 100644 test/integration/full/landmark-complementary-is-top-level/landmark-complementary-is-top-level-fail.html create mode 100644 test/integration/full/landmark-complementary-is-top-level/landmark-complementary-is-top-level-fail.js create mode 100644 test/integration/full/landmark-complementary-is-top-level/landmark-complementary-is-top-level-pass.html create mode 100644 test/integration/full/landmark-complementary-is-top-level/landmark-complementary-is-top-level-pass.js diff --git a/doc/aria-supported.md b/doc/aria-supported.md index 285d5b1a6f..445a40cb0b 100644 --- a/doc/aria-supported.md +++ b/doc/aria-supported.md @@ -18,4 +18,4 @@ For a detailed description about how accessibility support is decided, see [How | -------------------- | ---------------- | | aria-describedat | No | | aria-details | No | -| aria-roledescription | No | +| aria-roledescription | No | \ No newline at end of file diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 9cb57158f7..a2f378329a 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -1,76 +1,77 @@ -| Rule ID | Description | Impact | Tags | Enabled by default | -| :-------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | :----------------- | :--------------------------------------------------------------------------- | :----------------- | -| accesskeys | Ensures every accesskey attribute value is unique | Serious | best-practice, cat.keyboard | true | -| area-alt | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | -| aria-allowed-attr | Ensures ARIA attributes are allowed for an element's role | Critical | cat.aria, wcag2a, wcag412 | true | -| aria-allowed-role | Ensures role attribute has an appropriate value for the element | Minor | cat.aria, best-practice | true | -| aria-dpub-role-fallback | Ensures unsupported DPUB roles are only used on elements with implicit fallback roles | Moderate | cat.aria, wcag2a, wcag131 | true | -| aria-hidden-body | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | true | -| aria-required-attr | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | true | -| aria-required-children | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | true | -| aria-required-parent | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | true | -| aria-roles | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | true | -| aria-valid-attr-value | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | true | -| aria-valid-attr | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | true | -| audio-caption | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | false | -| autocomplete-valid | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | true | -| blink | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | true | -| button-name | Ensures buttons have discernible text | Serious, Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | true | -| bypass | 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 | true | -| checkboxgroup | Ensures related <input type="checkbox"> elements have a group and that the group designation is consistent | Critical | cat.forms, best-practice | true | -| color-contrast | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | true | -| css-orientation-lock | Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations | Serious | cat.structure, wcag262, wcag21aa, experimental | true | -| definition-list | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | true | -| dlitem | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | true | -| document-title | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242 | true | -| duplicate-id-active | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | true | -| duplicate-id-aria | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | true | -| duplicate-id | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | true | -| empty-heading | Ensures headings have discernible text | Minor | cat.name-role-value, best-practice | true | -| focus-order-semantics | Ensures elements in the focus order have an appropriate role | Minor | cat.keyboard, best-practice, experimental | true | -| form-field-multiple-labels | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | true | -| frame-tested | Ensures <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, review-item | true | -| frame-title-unique | Ensures <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, best-practice | true | -| frame-title | Ensures <iframe> and <frame> elements contain a non-empty title attribute | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | true | -| heading-order | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | true | -| hidden-content | Informs users about hidden content. | Minor | cat.structure, experimental, review-item | true | -| html-has-lang | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311 | true | -| html-lang-valid | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311 | true | -| html-xml-lang-mismatch | 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 | true | -| image-alt | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | -| image-redundant-alt | Ensure button and link text is not repeated as image alternative | Minor | cat.text-alternatives, best-practice | true | -| input-image-alt | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | -| label-title-only | Ensures that every form element is not solely labeled using the title or aria-describedby attributes | Serious | cat.forms, best-practice | true | -| label | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag332, wcag131, section508, section508.22.n | true | -| landmark-banner-is-top-level | Ensures the banner landmark is at top level | Moderate | cat.semantics, best-practice | true | -| landmark-contentinfo-is-top-level | Ensures the contentinfo landmark is at top level | Moderate | cat.semantics, best-practice | true | -| landmark-main-is-top-level | Ensures the main landmark is at top level | Moderate | cat.semantics, best-practice | true | -| landmark-no-duplicate-banner | Ensures the document has at most one banner landmark | Moderate | cat.semantics, best-practice | true | -| landmark-no-duplicate-contentinfo | Ensures the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | true | -| landmark-one-main | Ensures the document has only one main landmark and each iframe in the page has at most one main landmark | Moderate | cat.semantics, best-practice | true | -| layout-table | Ensures presentational <table> elements do not use <th>, <caption> elements or the summary attribute | Serious | cat.semantics, wcag2a, wcag131 | true | -| link-in-text-block | Links can be distinguished without relying on color | Serious | cat.color, experimental, wcag2a, wcag141 | true | -| link-name | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a | true | -| list | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | true | -| listitem | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | true | -| marquee | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | true | -| meta-refresh | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time, wcag2a, wcag2aaa, wcag221, wcag224, wcag325 | true | -| meta-viewport-large | Ensures <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | true | -| meta-viewport | Ensures <meta name="viewport"> does not disable text scaling and zooming | Critical | cat.sensory-and-visual-cues, wcag2aa, wcag144 | true | -| object-alt | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | -| p-as-heading | Ensure p elements are not used to style headings | Serious | cat.semantics, wcag2a, wcag131, experimental | true | -| page-has-heading-one | Ensure that the page, or at least one of its frames contains a level-one heading | Moderate | cat.semantics, best-practice | true | -| radiogroup | Ensures related <input type="radio"> elements have a group and that the group designation is consistent | Critical | cat.forms, best-practice | true | -| region | Ensures all page content is contained by landmarks | Moderate | cat.keyboard, best-practice | true | -| scope-attr-valid | Ensures the scope attribute is used correctly on tables | Moderate, Critical | cat.tables, best-practice | true | -| server-side-image-map | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | true | -| skip-link | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice | true | -| tabindex | Ensures tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | true | -| table-duplicate-name | Ensure that tables do not have the same summary and caption | Minor | cat.tables, best-practice | true | -| table-fake-caption | Ensure that tables with a caption use the <caption> element. | Serious | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | true | -| td-has-header | 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 | true | -| td-headers-attr | 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 | true | -| th-has-data-cells | Ensure that each table header in a data table refers to data cells | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | true | -| valid-lang | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | true | -| video-caption | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | true | -| video-description | Ensures <video> elements have audio descriptions | Critical | cat.text-alternatives, wcag2aa, wcag125, section508, section508.22.b | true | +| Rule ID | Description | Impact | Tags | Enabled by default | +| :------- | :------- | :------- | :------- | :------- | +| accesskeys | Ensures every accesskey attribute value is unique | Serious | best-practice, cat.keyboard | true | +| area-alt | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | +| aria-allowed-attr | Ensures ARIA attributes are allowed for an element's role | Critical | cat.aria, wcag2a, wcag412 | true | +| aria-allowed-role | Ensures role attribute has an appropriate value for the element | Minor | cat.aria, best-practice | true | +| aria-dpub-role-fallback | Ensures unsupported DPUB roles are only used on elements with implicit fallback roles | Moderate | cat.aria, wcag2a, wcag131 | true | +| aria-hidden-body | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | true | +| aria-required-attr | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | true | +| aria-required-children | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | true | +| aria-required-parent | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | true | +| aria-roles | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | true | +| aria-valid-attr-value | Ensures all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412 | true | +| aria-valid-attr | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | true | +| audio-caption | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | false | +| autocomplete-valid | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135 | true | +| blink | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | true | +| button-name | Ensures buttons have discernible text | Serious, Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | true | +| bypass | 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 | true | +| checkboxgroup | Ensures related <input type="checkbox"> elements have a group and that the group designation is consistent | Critical | cat.forms, best-practice | true | +| color-contrast | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | true | +| css-orientation-lock | Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations | Serious | cat.structure, wcag262, wcag21aa, experimental | true | +| definition-list | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | true | +| dlitem | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | true | +| document-title | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242 | true | +| duplicate-id-active | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | true | +| duplicate-id-aria | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | true | +| duplicate-id | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | true | +| empty-heading | Ensures headings have discernible text | Minor | cat.name-role-value, best-practice | true | +| focus-order-semantics | Ensures elements in the focus order have an appropriate role | Minor | cat.keyboard, best-practice, experimental | true | +| form-field-multiple-labels | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | true | +| frame-tested | Ensures <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, review-item | true | +| frame-title-unique | Ensures <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, best-practice | true | +| frame-title | Ensures <iframe> and <frame> elements contain a non-empty title attribute | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | true | +| heading-order | Ensures the order of headings is semantically correct | Moderate | cat.semantics, best-practice | true | +| hidden-content | Informs users about hidden content. | Minor | cat.structure, experimental, review-item | true | +| html-has-lang | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311 | true | +| html-lang-valid | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311 | true | +| html-xml-lang-mismatch | 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 | true | +| image-alt | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | +| image-redundant-alt | Ensure button and link text is not repeated as image alternative | Minor | cat.text-alternatives, best-practice | true | +| input-image-alt | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | +| label-title-only | Ensures that every form element is not solely labeled using the title or aria-describedby attributes | Serious | cat.forms, best-practice | true | +| label | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag332, wcag131, section508, section508.22.n | true | +| landmark-banner-is-top-level | Ensures the banner landmark is at top level | Moderate | cat.semantics, best-practice | true | +| landmark-complementary-is-top-level | Ensures the complementary landmark or aside is at top level | Moderate | cat.semantics, best-practice | true | +| landmark-contentinfo-is-top-level | Ensures the contentinfo landmark is at top level | Moderate | cat.semantics, best-practice | true | +| landmark-main-is-top-level | Ensures the main landmark is at top level | Moderate | cat.semantics, best-practice | true | +| landmark-no-duplicate-banner | Ensures the document has at most one banner landmark | Moderate | cat.semantics, best-practice | true | +| landmark-no-duplicate-contentinfo | Ensures the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | true | +| landmark-one-main | Ensures the document has only one main landmark and each iframe in the page has at most one main landmark | Moderate | cat.semantics, best-practice | true | +| layout-table | Ensures presentational <table> elements do not use <th>, <caption> elements or the summary attribute | Serious | cat.semantics, wcag2a, wcag131 | true | +| link-in-text-block | Links can be distinguished without relying on color | Serious | cat.color, experimental, wcag2a, wcag141 | true | +| link-name | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a | true | +| list | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | true | +| listitem | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | true | +| marquee | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | true | +| meta-refresh | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time, wcag2a, wcag2aaa, wcag221, wcag224, wcag325 | true | +| meta-viewport-large | Ensures <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | true | +| meta-viewport | Ensures <meta name="viewport"> does not disable text scaling and zooming | Critical | cat.sensory-and-visual-cues, wcag2aa, wcag144 | true | +| object-alt | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | true | +| p-as-heading | Ensure p elements are not used to style headings | Serious | cat.semantics, wcag2a, wcag131, experimental | true | +| page-has-heading-one | Ensure that the page, or at least one of its frames contains a level-one heading | Moderate | cat.semantics, best-practice | true | +| radiogroup | Ensures related <input type="radio"> elements have a group and that the group designation is consistent | Critical | cat.forms, best-practice | true | +| region | Ensures all page content is contained by landmarks | Moderate | cat.keyboard, best-practice | true | +| scope-attr-valid | Ensures the scope attribute is used correctly on tables | Moderate, Critical | cat.tables, best-practice | true | +| server-side-image-map | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | true | +| skip-link | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice | true | +| tabindex | Ensures tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | true | +| table-duplicate-name | Ensure that tables do not have the same summary and caption | Minor | cat.tables, best-practice | true | +| table-fake-caption | Ensure that tables with a caption use the <caption> element. | Serious | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g | true | +| td-has-header | 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 | true | +| td-headers-attr | 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 | true | +| th-has-data-cells | Ensure that each table header in a data table refers to data cells | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | true | +| valid-lang | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | true | +| video-caption | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | true | +| video-description | Ensures <video> elements have audio descriptions | Critical | cat.text-alternatives, wcag2aa, wcag125, section508, section508.22.b | true | \ No newline at end of file diff --git a/lib/rules/landmark-complementary-is-top-level.json b/lib/rules/landmark-complementary-is-top-level.json new file mode 100644 index 0000000000..c06f1347e1 --- /dev/null +++ b/lib/rules/landmark-complementary-is-top-level.json @@ -0,0 +1,17 @@ +{ + "id": "landmark-complementary-is-top-level", + "selector": "aside:not([role]), [role=complementary]", + "tags": [ + "cat.semantics", + "best-practice" + ], + "metadata": { + "description": "Ensures the complementary landmark or aside is at top level", + "help": "Aside must not be contained in another landmark" + }, + "all": [], + "any": [ + "landmark-is-top-level" + ], + "none": [] +} diff --git a/lib/rules/landmark-has-body-context.js b/lib/rules/landmark-has-body-context.js index f5fd6bc0f2..4e399710e5 100644 --- a/lib/rules/landmark-has-body-context.js +++ b/lib/rules/landmark-has-body-context.js @@ -1,7 +1,7 @@ const nativeScopeFilter = 'article, aside, main, nav, section'; // Filter elements that, within certain contexts, don't map their role. -// e.g. a