From 7da6bec1dd50918c75c2fe1399d5b82607a7e3ff Mon Sep 17 00:00:00 2001 From: Gagan Meena Date: Tue, 9 Dec 2025 01:24:30 +0530 Subject: [PATCH 01/10] Phase 1: Adding New Rules --- CHANGELOG.md | 108 ++ doc/rule-descriptions.md | 142 ++- lib/rules/css-orientation-lock.json | 4 +- lib/rules/focus-order-semantics.json | 10 +- lib/rules/hidden-content.json | 2 +- lib/rules/summary-name.json | 29 + lib/rules/table-fake-caption.json | 4 +- lib/rules/td-has-header.json | 4 +- locales/de.json | 73 +- locales/ja.json | 265 ++-- locales/ko.json | 8 +- locales/pt_PT.json | 1123 ++++++++++++++++ locales/ru.json | 1127 +++++++++++++++++ .../focus-order-semantics.html | 11 + .../focus-order-semantics.json | 12 +- .../rules/summary-name/summary-name.html | 86 ++ .../rules/summary-name/summary-name.json | 24 + .../integration/virtual-rules/summary-name.js | 95 ++ .../inserted-into-focus-order-matches.js | 16 +- .../summary-interactive-matches.js | 112 ++ 20 files changed, 3074 insertions(+), 181 deletions(-) create mode 100644 lib/rules/summary-name.json create mode 100644 locales/pt_PT.json create mode 100644 locales/ru.json create mode 100644 test/integration/rules/summary-name/summary-name.html create mode 100644 test/integration/rules/summary-name/summary-name.json create mode 100644 test/integration/virtual-rules/summary-name.js create mode 100644 test/rule-matches/summary-interactive-matches.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 3523aebf7..e1efdf286 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,114 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [4.11.0](https://github.com/dequelabs/axe-core/compare/v4.10.3...v4.11.0) (2025-10-07) + +### Features + +- add RGAA tags to rules ([#4862](https://github.com/dequelabs/axe-core/issues/4862)) ([53a925a](https://github.com/dequelabs/axe-core/commit/53a925a31bb2bf4a1584252fa7a58c0662225320)) +- **aria-prohibited-attr:** add support for fallback roles ([#4325](https://github.com/dequelabs/axe-core/issues/4325)) ([62a19a9](https://github.com/dequelabs/axe-core/commit/62a19a9f753f8c49885dafbab7a2a9468eb6571d)) +- **axe.d.ts:** add nodeSerializer typings ([#4551](https://github.com/dequelabs/axe-core/issues/4551)) ([a2f3a48](https://github.com/dequelabs/axe-core/commit/a2f3a485d5e02993c0f35762cd9d80a6ce4ced5f)), closes [#4093](https://github.com/dequelabs/axe-core/issues/4093) +- **DqElement:** deprecate fromFrame function ([#4881](https://github.com/dequelabs/axe-core/issues/4881)) ([374c376](https://github.com/dequelabs/axe-core/commit/374c376d0b4a043e8beaa7cc9a47521314eee02c)), closes [#4093](https://github.com/dequelabs/axe-core/issues/4093) +- **DqElement:** Truncate large `html` strings when the element has a large outerHTML string ([#4796](https://github.com/dequelabs/axe-core/issues/4796)) ([404a4fb](https://github.com/dequelabs/axe-core/commit/404a4fb24a156dc433ac9c70dbefe415d41ca980)), closes [#4544](https://github.com/dequelabs/axe-core/issues/4544) +- **get-xpath:** return proper relative selector for id ([#4846](https://github.com/dequelabs/axe-core/issues/4846)) ([1035f9e](https://github.com/dequelabs/axe-core/commit/1035f9ef134cbfc02c91c37f881eb5759f602bf3)), closes [#4845](https://github.com/dequelabs/axe-core/issues/4845) +- **i18n:** Add Portugal Portuguese translation ([#4725](https://github.com/dequelabs/axe-core/issues/4725)) ([5b6a65a](https://github.com/dequelabs/axe-core/commit/5b6a65a103188251568862f46020488cf7fd8a94)) +- incomplete with node on which an error occurred ([#4863](https://github.com/dequelabs/axe-core/issues/4863)) ([32ed8da](https://github.com/dequelabs/axe-core/commit/32ed8daad1111772559f6e1cf6c8171e83c0f299)) +- **locale:** Added ru locale ([#4565](https://github.com/dequelabs/axe-core/issues/4565)) ([067b01d](https://github.com/dequelabs/axe-core/commit/067b01d66db1d2c276f26743a8d13d5d60d33446)) +- **tap:** some best practice rules map to RGAA ([#4895](https://github.com/dequelabs/axe-core/issues/4895)) ([bc33f4c](https://github.com/dequelabs/axe-core/commit/bc33f4cf5d4d384118c08d8be1afc0c4fc9272ec)) +- **td-headers-attr:** report headers attribute referencing other elements as unsupported ([#4589](https://github.com/dequelabs/axe-core/issues/4589)) ([ec7c6c8](https://github.com/dequelabs/axe-core/commit/ec7c6c8875970388c4fe2c73147a3dd43497161e)), closes [#3987](https://github.com/dequelabs/axe-core/issues/3987) + +### Bug Fixes + +- **aria-allowed-role:** add form to allowed roles of form element ([#4588](https://github.com/dequelabs/axe-core/issues/4588)) ([8aa47ac](https://github.com/dequelabs/axe-core/commit/8aa47ac01f9959b9d47ac24dcd2fd8c88c9279f7)), closes [/github.com/dequelabs/axe-core/blob/develop/lib/standards/html-elms.js#L264](https://github.com/dequelabs//github.com/dequelabs/axe-core/blob/develop/lib/standards/html-elms.js/issues/L264) +- **aria-allowed-role:** Add math to allowed roles for img element ([#4658](https://github.com/dequelabs/axe-core/issues/4658)) ([95b6c18](https://github.com/dequelabs/axe-core/commit/95b6c184872cf70c7f54a96aa813a9e8bc2c066d)), closes [#4657](https://github.com/dequelabs/axe-core/issues/4657) +- **autocomplete-valid :** Ignore readonly autocomplete field ([#4721](https://github.com/dequelabs/axe-core/issues/4721)) ([491f4ec](https://github.com/dequelabs/axe-core/commit/491f4ecdbbb79d019daa63debc03ac0efb47adf8)), closes [#4708](https://github.com/dequelabs/axe-core/issues/4708) +- **autocomplete-valid:** treat values "xon" and "xoff" as non-WCAG-violations ([#4878](https://github.com/dequelabs/axe-core/issues/4878)) ([52bc611](https://github.com/dequelabs/axe-core/commit/52bc61162aa170a30a38246ade099ba3fc10cc2a)), closes [#4877](https://github.com/dequelabs/axe-core/issues/4877) +- **axe.d.ts:** add typings for preload options object ([#4543](https://github.com/dequelabs/axe-core/issues/4543)) ([cfd2974](https://github.com/dequelabs/axe-core/commit/cfd297498c0e34edd5ff7e62935060bb9dda4db7)) +- **button-name,input-button-name,input-img-alt:** allow label to give accessible name ([#4607](https://github.com/dequelabs/axe-core/issues/4607)) ([a9710d7](https://github.com/dequelabs/axe-core/commit/a9710d757c6ca6ee0ce5d26be3427bab54b87a7a)), closes [#4472](https://github.com/dequelabs/axe-core/issues/4472) [#3696](https://github.com/dequelabs/axe-core/issues/3696) [#3696](https://github.com/dequelabs/axe-core/issues/3696) +- **captions:** fix grammar in captions check incomplete message ([#4661](https://github.com/dequelabs/axe-core/issues/4661)) ([11de515](https://github.com/dequelabs/axe-core/commit/11de515858a7c10a3d7400163fc2b834715152fc)) +- **color-contrast:** do not run on elements with font-size: 0 ([#4822](https://github.com/dequelabs/axe-core/issues/4822)) ([d77c885](https://github.com/dequelabs/axe-core/commit/d77c8854c847573597eccf54c00091a4a2134cfd)), closes [#4820](https://github.com/dequelabs/axe-core/issues/4820) +- consistently parse tabindex, following HTML 5 spec ([#4637](https://github.com/dequelabs/axe-core/issues/4637)) ([645a850](https://github.com/dequelabs/axe-core/commit/645a850f601f4f3f18cc4aaca399aad18a9fa5d2)), closes [#4632](https://github.com/dequelabs/axe-core/issues/4632) +- **core:** measure perf for async checks ([#4609](https://github.com/dequelabs/axe-core/issues/4609)) ([7e9bacf](https://github.com/dequelabs/axe-core/commit/7e9bacf1ecb8c53404fac3eeed087e370e2a9cfa)) +- fix grammar when using "alternative text" in a sentence ([#4811](https://github.com/dequelabs/axe-core/issues/4811)) ([237a586](https://github.com/dequelabs/axe-core/commit/237a5861b0fb044c885b154436696279deca7a13)), closes [#4394](https://github.com/dequelabs/axe-core/issues/4394) +- **get-ancestry:** add nth-child selector for multiple siblings of shadow root ([#4606](https://github.com/dequelabs/axe-core/issues/4606)) ([1cdd6c3](https://github.com/dequelabs/axe-core/commit/1cdd6c3e698a6a4c28604448284993c4c20ca272)), closes [#4563](https://github.com/dequelabs/axe-core/issues/4563) +- **get-ancestry:** don't error when there is no parent ([#4617](https://github.com/dequelabs/axe-core/issues/4617)) ([a005703](https://github.com/dequelabs/axe-core/commit/a0057039072f68bd605e8bacdca64692d57f612e)) +- **locale:** fix typos in japanese (ja) locale ([#4856](https://github.com/dequelabs/axe-core/issues/4856)) ([3462cc5](https://github.com/dequelabs/axe-core/commit/3462cc57e8480334c125c38b7ecb42344b405dd4)) +- **locale:** fixed typos in german (DE) locale ([#4631](https://github.com/dequelabs/axe-core/issues/4631)) ([b7736de](https://github.com/dequelabs/axe-core/commit/b7736deae9ec14a4e81182adb53be73f3cce9894)) +- **locale:** proofread and updated de.json ([#4643](https://github.com/dequelabs/axe-core/issues/4643)) ([8060ada](https://github.com/dequelabs/axe-core/commit/8060ada737a23cdf68bb5b4c95b8c0e2cca45dad)) +- **meta-viewport:** lower impact to moderate ([#4887](https://github.com/dequelabs/axe-core/issues/4887)) ([2f32aa5](https://github.com/dequelabs/axe-core/commit/2f32aa5bada78ffcfc965ed2b64be533263c6bd5)), closes [#4714](https://github.com/dequelabs/axe-core/issues/4714) +- **no-autoplay-audio:** don't timeout for preload=none media elements ([#4684](https://github.com/dequelabs/axe-core/issues/4684)) ([cdc871e](https://github.com/dequelabs/axe-core/commit/cdc871e68f3dbc6acbfed12d3ec63ea4da1a4065)) +- **performanceTimer:** throwing in axe catch clause ([#4852](https://github.com/dequelabs/axe-core/issues/4852)) ([a4ade04](https://github.com/dequelabs/axe-core/commit/a4ade04bc2ba93dcad8a24094fb0dc5edb6da8b2)), closes [/github.com/dequelabs/axe-core/blob/e7dae4ec48cbfef74de9f833fdcfb178c1002985/lib/core/base/rule.js#L297-L300](https://github.com/dequelabs//github.com/dequelabs/axe-core/blob/e7dae4ec48cbfef74de9f833fdcfb178c1002985/lib/core/base/rule.js/issues/L297-L300) +- **performanceTimer:** work in frames ([#4834](https://github.com/dequelabs/axe-core/issues/4834)) ([d7dfebc](https://github.com/dequelabs/axe-core/commit/d7dfebc0271d2970c0937024ce693a771885002c)) +- **rules:** Change "alternate text" to "alternative text" ([#4582](https://github.com/dequelabs/axe-core/issues/4582)) ([b03ada3](https://github.com/dequelabs/axe-core/commit/b03ada3dd3b6490bb88e366bf807b10e1a4038a4)) +- **target-size:** do not treat focusable tabpanels as targets ([#4702](https://github.com/dequelabs/axe-core/issues/4702)) ([60d11f2](https://github.com/dequelabs/axe-core/commit/60d11f2d01b9e859e54a15ae0232b8b5d1c48d35)), closes [#4421](https://github.com/dequelabs/axe-core/issues/4421) [#4701](https://github.com/dequelabs/axe-core/issues/4701) +- **type:** correct RuleError type ([#4893](https://github.com/dequelabs/axe-core/issues/4893)) ([d1aa8e2](https://github.com/dequelabs/axe-core/commit/d1aa8e2094031159b041a3e9cf2c796a26b3daba)) +- **types:** correct raw types ([#4903](https://github.com/dequelabs/axe-core/issues/4903)) ([3eade11](https://github.com/dequelabs/axe-core/commit/3eade110a7ac173e3537e8eb18dd0db026f13c75)) + +### [4.10.3](https://github.com/dequelabs/axe-core/compare/v4.10.2...v4.10.3) (2025-03-04) + +### Bug Fixes + +- **aria-allowed-role:** Add math to allowed roles for img element ([#4658](https://github.com/dequelabs/axe-core/issues/4658)) ([f6dddd9](https://github.com/dequelabs/axe-core/commit/f6dddd905bb86d2073d760d4c1ff39996e59a4f4)), closes [#4657](https://github.com/dequelabs/axe-core/issues/4657) +- **captions:** fix grammar in captions check incomplete message ([#4661](https://github.com/dequelabs/axe-core/issues/4661)) ([3ef7058](https://github.com/dequelabs/axe-core/commit/3ef7058d3a16a6898eaed718e39b34b45f9ed74f)) +- consistently parse tabindex, following HTML5 spec ([#4637](https://github.com/dequelabs/axe-core/issues/4637)) ([3b0a361](https://github.com/dequelabs/axe-core/commit/3b0a3619d5e6147d8885725cce196868dac89f7f)), closes [#4632](https://github.com/dequelabs/axe-core/issues/4632) +- **core:** measure perf for async checks ([#4609](https://github.com/dequelabs/axe-core/issues/4609)) ([e7dc26e](https://github.com/dequelabs/axe-core/commit/e7dc26e6cbaf9089611853805e05216b6529e1f9)) +- **locale:** fixed typos in german (DE) locale ([#4631](https://github.com/dequelabs/axe-core/issues/4631)) ([0740980](https://github.com/dequelabs/axe-core/commit/07409802115c199a68f58dcaf7467e35b4867140)) +- **locale:** proofread and updated de.json ([#4643](https://github.com/dequelabs/axe-core/issues/4643)) ([910cdb2](https://github.com/dequelabs/axe-core/commit/910cdb20702ce116c781d58f021adc05095ffcbb)) +- **no-autoplay-audio:** don't timeout for preload=none media elements ([#4684](https://github.com/dequelabs/axe-core/issues/4684)) ([b7f1ad1](https://github.com/dequelabs/axe-core/commit/b7f1ad1ccf719b7149a5ef1805b405707a474e31)) +- **target-size:** do not treat focusable tabpanels as targets ([#4702](https://github.com/dequelabs/axe-core/issues/4702)) ([67d4e4f](https://github.com/dequelabs/axe-core/commit/67d4e4f7d0d0b803b66f216ff86f401649ed024f)), closes [#4421](https://github.com/dequelabs/axe-core/issues/4421) [#4701](https://github.com/dequelabs/axe-core/issues/4701) + +### [4.10.2](https://github.com/dequelabs/axe-core/compare/v4.10.1...v4.10.2) (2024-10-21) + +### Bug Fixes + +- **get-ancestry:** don't error when there is no parent ([#4617](https://github.com/dequelabs/axe-core/issues/4617)) ([6c07102](https://github.com/dequelabs/axe-core/commit/6c07102b1d29145b8dc5f1d96229f3d0b8b38068)) + +### [4.10.1](https://github.com/dequelabs/axe-core/compare/v4.10.0...v4.10.1) (2024-10-16) + +### Bug Fixes + +- **aria-allowed-role:** add form to allowed roles of form element ([#4588](https://github.com/dequelabs/axe-core/issues/4588)) ([d462d67](https://github.com/dequelabs/axe-core/commit/d462d674bb7de0848ce2695f80b95d677c5016e0)), closes [/github.com/dequelabs/axe-core/blob/develop/lib/standards/html-elms.js#L264](https://github.com/dequelabs//github.com/dequelabs/axe-core/blob/develop/lib/standards/html-elms.js/issues/L264) +- **axe.d.ts:** add typings for preload options object ([#4543](https://github.com/dequelabs/axe-core/issues/4543)) ([72e269f](https://github.com/dequelabs/axe-core/commit/72e269f1e6d6039e70e614005f04ebfd3fe5aca5)) +- **button-name,input-button-name,input-img-alt:** allow label to give accessible name ([#4607](https://github.com/dequelabs/axe-core/issues/4607)) ([364eb72](https://github.com/dequelabs/axe-core/commit/364eb72bb8f20b0ffc31be24cc96cbd349c301cb)), closes [#4472](https://github.com/dequelabs/axe-core/issues/4472) [#3696](https://github.com/dequelabs/axe-core/issues/3696) [#3696](https://github.com/dequelabs/axe-core/issues/3696) +- **get-ancestry:** add nth-child selector for multiple siblings of shadow root ([#4606](https://github.com/dequelabs/axe-core/issues/4606)) ([bdd94a2](https://github.com/dequelabs/axe-core/commit/bdd94a227a95cd5b9f8e2a1e0fd259ddd702810c)), closes [#4563](https://github.com/dequelabs/axe-core/issues/4563) +- **rules:** Change "alternate text" to "alternative text" ([#4582](https://github.com/dequelabs/axe-core/issues/4582)) ([31e0f61](https://github.com/dequelabs/axe-core/commit/31e0f61ca871b3df86468577c449a02c8ece12f0)) + +## [4.10.0](https://github.com/dequelabs/axe-core/compare/v4.9.1...v4.10.0) (2024-07-29) + +### Features + +- **new-rule:** summary elements must have an accessible name ([#4511](https://github.com/dequelabs/axe-core/issues/4511)) ([0d8a99e](https://github.com/dequelabs/axe-core/commit/0d8a99eadd8d49e5d3ea0f11ad77be732148431e)), closes [#4510](https://github.com/dequelabs/axe-core/issues/4510) + +### Bug Fixes + +- **aria-allowed-attr:** allow aria-multiline=false for element with contenteditable ([#4537](https://github.com/dequelabs/axe-core/issues/4537)) ([f019068](https://github.com/dequelabs/axe-core/commit/f0190685722495d00be644cabb1c9741d74acdea)) +- **aria-allowed-attr:** allow aria-required=false when normally not allowed ([#4532](https://github.com/dequelabs/axe-core/issues/4532)) ([2e242e1](https://github.com/dequelabs/axe-core/commit/2e242e146929902c97e181e41fa45e656cf3eb51)) +- **aria-prohibited-attr:** allow aria-label/ledby on descendants of widget ([#4541](https://github.com/dequelabs/axe-core/issues/4541)) ([07c5d91](https://github.com/dequelabs/axe-core/commit/07c5d91c658bda6bcd2743950bf70f25abd1f9ae)) +- **aria-roledescription:** keep disabled with { runOnly: 'wcag2a' } ([#4526](https://github.com/dequelabs/axe-core/issues/4526)) ([5b4cb9d](https://github.com/dequelabs/axe-core/commit/5b4cb9d7992a4c07745e64708040777de64874bd)), closes [#4523](https://github.com/dequelabs/axe-core/issues/4523) +- **autocomplete-valid:** incomplete for invalid but safe values ([#4500](https://github.com/dequelabs/axe-core/issues/4500)) ([e31a974](https://github.com/dequelabs/axe-core/commit/e31a974de395845c08af345f9458a8091e2b1c4b)), closes [#4492](https://github.com/dequelabs/axe-core/issues/4492) +- **build:** limit locales to valid files when using the --all-lang option ([#4486](https://github.com/dequelabs/axe-core/issues/4486)) ([d3db593](https://github.com/dequelabs/axe-core/commit/d3db593991261ad44eef1c142d8a4646edde93fa)), closes [#4485](https://github.com/dequelabs/axe-core/issues/4485) +- Prevent errors when loading axe in Angular + Jest ([#4456](https://github.com/dequelabs/axe-core/issues/4456)) ([3ef9353](https://github.com/dequelabs/axe-core/commit/3ef93531a574c2be76a92d59599d978714cca9d0)), closes [#4400](https://github.com/dequelabs/axe-core/issues/4400) +- Minor grammatical fixes for some rules and checks ([#4499](https://github.com/dequelabs/axe-core/issues/4499)) ([11fad59](https://github.com/dequelabs/axe-core/commit/11fad598c25eadd29f35ef6be382d907057d4537)) +- **landmark-unique:** follow spec, aside -> landmark ([#4469](https://github.com/dequelabs/axe-core/issues/4469)) ([e32f803](https://github.com/dequelabs/axe-core/commit/e32f8034246a92e4132dc04f6310e2b414d6d43f)), closes [#4460](https://github.com/dequelabs/axe-core/issues/4460) +- **required-attr:** allow aria-valuetext on slider instead of valuenow ([#4518](https://github.com/dequelabs/axe-core/issues/4518)) ([135898b](https://github.com/dequelabs/axe-core/commit/135898b38d5eb46c42170527a0ac9add425c5c3d)), closes [#4515](https://github.com/dequelabs/axe-core/issues/4515) + +### [4.9.1](https://github.com/dequelabs/axe-core/compare/v4.9.0...v4.9.1) (2024-05-06) + +### Bug Fixes + +- Prevent errors when loading axe in a page with prototype.js +- **aria-allowed-attr:** allow meter role allowed aria-\* attributes on meter element ([#4435](https://github.com/dequelabs/axe-core/issues/4435)) ([7ac6392](https://github.com/dequelabs/axe-core/commit/7ac63921e7fab21f3359dcfc8affa7585bc9c25b)) +- **aria-allowed-role:** add gridcell, separator, slider and treeitem to allowed roles of button element ([#4398](https://github.com/dequelabs/axe-core/issues/4398)) ([4788bf8](https://github.com/dequelabs/axe-core/commit/4788bf8d6fd963d7b017dad950b122ffcea8d151)) +- **aria-roles:** correct abstract roles (types) for aria-roles([#4421](https://github.com/dequelabs/axe-core/pull/4421)) +- **aria-valid-attr-value:** aria-controls & aria-haspopup incomplete ([#4418](https://github.com/dequelabs/axe-core/pull/4418)) +- fix building axe-core translation files with region locales ([#4396](https://github.com/dequelabs/axe-core/issues/4396)) ([5c318f3](https://github.com/dequelabs/axe-core/commit/5c318f3537056be5779cb53374bc6f4785947c91)), closes [#4388](https://github.com/dequelabs/axe-core/issues/4388) +- **invalidrole:** allow upper and mixed case role names ([#4358](https://github.com/dequelabs/axe-core/issues/4358)) ([105016c](https://github.com/dequelabs/axe-core/commit/105016cfe9d82876cfed2ff5c656a7842c5b3761)), closes [#2695](https://github.com/dequelabs/axe-core/issues/2695) +- **isVisibleOnScreen:** account for position: absolute elements inside overflow container ([#4405](https://github.com/dequelabs/axe-core/issues/4405)) ([2940f6e](https://github.com/dequelabs/axe-core/commit/2940f6ee36ba52d8cf089be2a3c8e7c516c81dd6)), closes [#4016](https://github.com/dequelabs/axe-core/issues/4016) +- **label-content-name-mismatch:** better dismiss and wysiwyg symbolic text characters ([#4402](https://github.com/dequelabs/axe-core/issues/4402)) +- **region:** Decorative images ignored by region rule ([#4412](https://github.com/dequelabs/axe-core/pull/4412)) +- **target-size:** ignore descendant elements in shadow dom ([#4410](https://github.com/dequelabs/axe-core/issues/4410)) ([6091367](https://github.com/dequelabs/axe-core/commit/6091367a20f70e536fc7e8d77eae4fa7232bc7c0)) +- **target-size:** pass for element that has nearby elements that are obscured ([#4422](https://github.com/dequelabs/axe-core/issues/4422)) ([3a90bb7](https://github.com/dequelabs/axe-core/commit/3a90bb70c8db087b2f03cc30a4aee756995c311c)), closes [#4387](https://github.com/dequelabs/axe-core/issues/4387) + ## [4.9.0](https://github.com/dequelabs/axe-core/compare/v4.8.4...v4.9.0) (2024-03-25) ### Features diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index a6dff6ff0..b1356f605 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -14,6 +14,7 @@ ## WCAG 2.0 Level A & AA Rules +<<<<<<< HEAD | Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | | :------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [area-alt](https://dequeuniversity.com/rules/axe/4.9/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag244, wcag412, section508, section508.22.a, TTv5, TT6.a, EN-301-549, EN-9.2.4.4, EN-9.4.1.2, ACT | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | @@ -83,19 +84,90 @@ | [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.9/autocomplete-valid?application=RuleDescription) | Ensure that the necessary form fields use the autocomplete attribute with a valid input. | Moderate | cat.forms, wcag21aa, wcag135, EN-301-549, EN-9.1.3.5, ACT, a11y-engine, a11y-engine-experimental | failure | [73f2c2](https://act-rules.github.io/rules/73f2c2) | | [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.9/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412, EN-301-549, EN-9.1.4.12, ACT | failure | [24afc2](https://act-rules.github.io/rules/24afc2), [9e45ec](https://act-rules.github.io/rules/9e45ec), [78fd32](https://act-rules.github.io/rules/78fd32) | | [label-content-name-mismatch](https://dequeuniversity.com/rules/axe/4.9/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, EN-301-549, EN-9.2.5.3, a11y-engine, a11y-engine-experimental | failure, needs review | [2ee8b8](https://act-rules.github.io/rules/2ee8b8) | +======= +| Rule ID | Description | Impact | Tags | Issue Type | [ACT Rules](https://www.w3.org/WAI/standards-guidelines/act/rules/) | +| :-------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [area-alt](https://dequeuniversity.com/rules/axe/4.11/area-alt?application=RuleDescription) | Ensure <area> elements of image maps have alternative text | Critical | cat.text-alternatives, wcag2a, wcag244, wcag412, section508, section508.22.a, TTv5, TT6.a, EN-301-549, EN-9.2.4.4, EN-9.4.1.2, ACT, RGAAv4, RGAA-1.1.2 | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | +| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.11/aria-allowed-attr?application=RuleDescription) | Ensure an element's role supports its ARIA attributes | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea) | +| [aria-braille-equivalent](https://dequeuniversity.com/rules/axe/4.11/aria-braille-equivalent?application=RuleDescription) | Ensure aria-braillelabel and aria-brailleroledescription have a non-braille equivalent | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | needs review | | +| [aria-command-name](https://dequeuniversity.com/rules/axe/4.11/aria-command-name?application=RuleDescription) | Ensure every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412, TTv5, TT6.a, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-11.9.1 | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1) | +| [aria-conditional-attr](https://dequeuniversity.com/rules/axe/4.11/aria-conditional-attr?application=RuleDescription) | Ensure ARIA attributes are used as described in the specification of the element's role | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure | [5c01ea](https://act-rules.github.io/rules/5c01ea) | +| [aria-deprecated-role](https://dequeuniversity.com/rules/axe/4.11/aria-deprecated-role?application=RuleDescription) | Ensure elements do not use deprecated roles | Minor | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure | [674b10](https://act-rules.github.io/rules/674b10) | +| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.11/aria-hidden-body?application=RuleDescription) | Ensure aria-hidden="true" is not present on the document body. | Critical | cat.aria, wcag2a, wcag131, wcag412, EN-301-549, EN-9.1.3.1, EN-9.4.1.2, RGAAv4, RGAA-10.8.1 | failure | | +| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.11/aria-hidden-focus?application=RuleDescription) | Ensure aria-hidden elements are not focusable nor contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, TTv5, TT6.a, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-10.8.1 | failure, needs review | [6cfa84](https://act-rules.github.io/rules/6cfa84) | +| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.11/aria-input-field-name?application=RuleDescription) | Ensure every ARIA input field has an accessible name | Serious | cat.aria, wcag2a, wcag412, TTv5, TT5.c, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-11.1.1 | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | +| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.11/aria-meter-name?application=RuleDescription) | Ensure every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111, EN-301-549, EN-9.1.1.1, RGAAv4, RGAA-11.1.1 | failure, needs review | | +| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.11/aria-progressbar-name?application=RuleDescription) | Ensure every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111, EN-301-549, EN-9.1.1.1, RGAAv4, RGAA-11.1.1 | failure, needs review | | +| [aria-prohibited-attr](https://dequeuniversity.com/rules/axe/4.11/aria-prohibited-attr?application=RuleDescription) | Ensure ARIA attributes are not prohibited for an element's role | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea) | +| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.11/aria-required-attr?application=RuleDescription) | Ensure elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure | [4e8ab6](https://act-rules.github.io/rules/4e8ab6) | +| [aria-required-children](https://dequeuniversity.com/rules/axe/4.11/aria-required-children?application=RuleDescription) | Ensure elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-9.3.1 | failure, needs review | [bc4a75](https://act-rules.github.io/rules/bc4a75), [ff89c9](https://act-rules.github.io/rules/ff89c9) | +| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.11/aria-required-parent?application=RuleDescription) | Ensure elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-9.3.1 | failure | [ff89c9](https://act-rules.github.io/rules/ff89c9) | +| [aria-roles](https://dequeuniversity.com/rules/axe/4.11/aria-roles?application=RuleDescription) | Ensure all elements with a role attribute use a valid value | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure | [674b10](https://act-rules.github.io/rules/674b10) | +| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.11/aria-toggle-field-name?application=RuleDescription) | Ensure every ARIA toggle field has an accessible name | Serious | cat.aria, wcag2a, wcag412, TTv5, TT5.c, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-7.1.1 | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | +| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.11/aria-tooltip-name?application=RuleDescription) | Ensure every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure, needs review | | +| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.11/aria-valid-attr-value?application=RuleDescription) | Ensure all ARIA attributes have valid values | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure, needs review | [6a7281](https://act-rules.github.io/rules/6a7281) | +| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.11/aria-valid-attr?application=RuleDescription) | Ensure attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure | [5f99a7](https://act-rules.github.io/rules/5f99a7) | +| [blink](https://dequeuniversity.com/rules/axe/4.11/blink?application=RuleDescription) | Ensure <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j, TTv5, TT2.b, EN-301-549, EN-9.2.2.2, RGAAv4, RGAA-13.8.1 | failure | | +| [button-name](https://dequeuniversity.com/rules/axe/4.11/button-name?application=RuleDescription) | Ensure buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, TTv5, TT6.a, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-11.9.1 | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1), [m6b1q3](https://act-rules.github.io/rules/m6b1q3) | +| [bypass](https://dequeuniversity.com/rules/axe/4.11/bypass?application=RuleDescription) | Ensure 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, TTv5, TT9.a, EN-301-549, EN-9.2.4.1, RGAAv4, RGAA-12.7.1 | needs review | [cf77f2](https://act-rules.github.io/rules/cf77f2), [047fe0](https://act-rules.github.io/rules/047fe0), [b40fd1](https://act-rules.github.io/rules/b40fd1), [3e12e1](https://act-rules.github.io/rules/3e12e1), [ye5d6e](https://act-rules.github.io/rules/ye5d6e) | +| [color-contrast](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=RuleDescription) | Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143, TTv5, TT13.c, EN-301-549, EN-9.1.4.3, ACT, RGAAv4, RGAA-3.2.1 | failure, needs review | [afw4f7](https://act-rules.github.io/rules/afw4f7), [09o5cg](https://act-rules.github.io/rules/09o5cg) | +| [definition-list](https://dequeuniversity.com/rules/axe/4.11/definition-list?application=RuleDescription) | Ensure <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-9.3.3 | failure | | +| [dlitem](https://dequeuniversity.com/rules/axe/4.11/dlitem?application=RuleDescription) | Ensure <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-9.3.3 | failure | | +| [document-title](https://dequeuniversity.com/rules/axe/4.11/document-title?application=RuleDescription) | Ensure each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, TTv5, TT12.a, EN-301-549, EN-9.2.4.2, ACT, RGAAv4, RGAA-8.5.1 | failure | [2779a5](https://act-rules.github.io/rules/2779a5) | +| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.11/duplicate-id-aria?application=RuleDescription) | Ensure every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-8.2.1 | needs review | [3ea0c8](https://act-rules.github.io/rules/3ea0c8) | +| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.11/form-field-multiple-labels?application=RuleDescription) | Ensure form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332, TTv5, TT5.c, EN-301-549, EN-9.3.3.2, RGAAv4, RGAA-11.2.1 | needs review | | +| [frame-focusable-content](https://dequeuniversity.com/rules/axe/4.11/frame-focusable-content?application=RuleDescription) | Ensure <frame> and <iframe> elements with focusable content do not have tabindex=-1 | Serious | cat.keyboard, wcag2a, wcag211, TTv5, TT4.a, EN-301-549, EN-9.2.1.1, RGAAv4, RGAA-7.3.2 | failure, needs review | [akn7bn](https://act-rules.github.io/rules/akn7bn) | +| [frame-title-unique](https://dequeuniversity.com/rules/axe/4.11/frame-title-unique?application=RuleDescription) | Ensure <iframe> and <frame> elements contain a unique title attribute | Serious | cat.text-alternatives, wcag2a, wcag412, TTv5, TT12.d, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-2.2.1 | needs review | [4b1c6c](https://act-rules.github.io/rules/4b1c6c) | +| [frame-title](https://dequeuniversity.com/rules/axe/4.11/frame-title?application=RuleDescription) | Ensure <iframe> and <frame> elements have an accessible name | Serious | cat.text-alternatives, wcag2a, wcag412, section508, section508.22.i, TTv5, TT12.d, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-2.1.1 | failure, needs review | [cae760](https://act-rules.github.io/rules/cae760) | +| [html-has-lang](https://dequeuniversity.com/rules/axe/4.11/html-has-lang?application=RuleDescription) | Ensure every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, TTv5, TT11.a, EN-301-549, EN-9.3.1.1, ACT, RGAAv4, RGAA-8.3.1 | failure | [b5c3f8](https://act-rules.github.io/rules/b5c3f8) | +| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.11/html-lang-valid?application=RuleDescription) | Ensure the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, TTv5, TT11.a, EN-301-549, EN-9.3.1.1, ACT, RGAAv4, RGAA-8.4.1 | failure | [bf051a](https://act-rules.github.io/rules/bf051a) | +| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.11/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, EN-301-549, EN-9.3.1.1, ACT, RGAAv4, RGAA-8.3.1 | failure | [5b7ae0](https://act-rules.github.io/rules/5b7ae0) | +| [image-alt](https://dequeuniversity.com/rules/axe/4.11/image-alt?application=RuleDescription) | Ensure <img> elements have alternative text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, TTv5, TT7.a, TT7.b, EN-301-549, EN-9.1.1.1, ACT, RGAAv4, RGAA-1.1.1 | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | +| [input-button-name](https://dequeuniversity.com/rules/axe/4.11/input-button-name?application=RuleDescription) | Ensure input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, TTv5, TT5.c, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-11.9.1 | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1) | +| [input-image-alt](https://dequeuniversity.com/rules/axe/4.11/input-image-alt?application=RuleDescription) | Ensure <input type="image"> elements have alternative text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag412, section508, section508.22.a, TTv5, TT7.a, EN-301-549, EN-9.1.1.1, EN-9.4.1.2, ACT, RGAAv4, RGAA-1.1.3 | failure, needs review | [59796f](https://act-rules.github.io/rules/59796f) | +| [label](https://dequeuniversity.com/rules/axe/4.11/label?application=RuleDescription) | Ensure every form element has a label | Critical | cat.forms, wcag2a, wcag412, section508, section508.22.n, TTv5, TT5.c, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-11.1.1 | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | +| [link-in-text-block](https://dequeuniversity.com/rules/axe/4.11/link-in-text-block?application=RuleDescription) | Ensure links are distinguished from surrounding text in a way that does not rely on color | Serious | cat.color, wcag2a, wcag141, TTv5, TT13.a, EN-301-549, EN-9.1.4.1, RGAAv4, RGAA-10.6.1 | failure, needs review | | +| [link-name](https://dequeuniversity.com/rules/axe/4.11/link-name?application=RuleDescription) | Ensure links have discernible text | Serious | cat.name-role-value, wcag2a, wcag244, wcag412, section508, section508.22.a, TTv5, TT6.a, EN-301-549, EN-9.2.4.4, EN-9.4.1.2, ACT, RGAAv4, RGAA-6.2.1 | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | +| [list](https://dequeuniversity.com/rules/axe/4.11/list?application=RuleDescription) | Ensure that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-9.3.1 | failure | | +| [listitem](https://dequeuniversity.com/rules/axe/4.11/listitem?application=RuleDescription) | Ensure <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-9.3.1 | failure | | +| [marquee](https://dequeuniversity.com/rules/axe/4.11/marquee?application=RuleDescription) | Ensure <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222, TTv5, TT2.b, EN-301-549, EN-9.2.2.2, RGAAv4, RGAA-13.8.1 | failure | | +| [meta-refresh](https://dequeuniversity.com/rules/axe/4.11/meta-refresh?application=RuleDescription) | Ensure <meta http-equiv="refresh"> is not used for delayed refresh | Critical | cat.time-and-media, wcag2a, wcag221, TTv5, TT8.a, EN-301-549, EN-9.2.2.1, RGAAv4, RGAA-13.1.2 | failure | [bc659a](https://act-rules.github.io/rules/bc659a), [bisz58](https://act-rules.github.io/rules/bisz58) | +| [meta-viewport](https://dequeuniversity.com/rules/axe/4.11/meta-viewport?application=RuleDescription) | Ensure <meta name="viewport"> does not disable text scaling and zooming | Moderate | cat.sensory-and-visual-cues, wcag2aa, wcag144, EN-301-549, EN-9.1.4.4, ACT, RGAAv4, RGAA-10.4.2 | failure | [b4f0c3](https://act-rules.github.io/rules/b4f0c3) | +| [nested-interactive](https://dequeuniversity.com/rules/axe/4.11/nested-interactive?application=RuleDescription) | Ensure interactive controls are not nested as they are not always announced by screen readers or can cause focus problems for assistive technologies | Serious | cat.keyboard, wcag2a, wcag412, TTv5, TT6.a, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure, needs review | [307n5z](https://act-rules.github.io/rules/307n5z) | +| [no-autoplay-audio](https://dequeuniversity.com/rules/axe/4.11/no-autoplay-audio?application=RuleDescription) | Ensure <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, TTv5, TT2.a, EN-301-549, EN-9.1.4.2, ACT, RGAAv4, RGAA-4.10.1 | needs review | [80f0bf](https://act-rules.github.io/rules/80f0bf) | +| [object-alt](https://dequeuniversity.com/rules/axe/4.11/object-alt?application=RuleDescription) | Ensure <object> elements have alternative text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, EN-301-549, EN-9.1.1.1, RGAAv4, RGAA-1.1.6 | failure, needs review | [8fc3b6](https://act-rules.github.io/rules/8fc3b6) | +| [role-img-alt](https://dequeuniversity.com/rules/axe/4.11/role-img-alt?application=RuleDescription) | Ensure [role="img"] elements have alternative text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, TTv5, TT7.a, EN-301-549, EN-9.1.1.1, ACT, RGAAv4, RGAA-1.1.1 | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | +| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.11/scrollable-region-focusable?application=RuleDescription) | Ensure elements that have scrollable content are accessible by keyboard | Serious | cat.keyboard, wcag2a, wcag211, wcag213, TTv5, TT4.a, EN-301-549, EN-9.2.1.1, EN-9.2.1.3, RGAAv4, RGAA-7.3.2 | failure | [0ssw9k](https://act-rules.github.io/rules/0ssw9k) | +| [select-name](https://dequeuniversity.com/rules/axe/4.11/select-name?application=RuleDescription) | Ensure select element has an accessible name | Critical | cat.forms, wcag2a, wcag412, section508, section508.22.n, TTv5, TT5.c, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-11.1.1 | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | +| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.11/server-side-image-map?application=RuleDescription) | Ensure that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f, TTv5, TT4.a, EN-301-549, EN-9.2.1.1, RGAAv4, RGAA-1.1.4 | needs review | | +| [summary-name](https://dequeuniversity.com/rules/axe/4.11/summary-name?application=RuleDescription) | Ensure summary elements have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, TTv5, TT6.a, EN-301-549, EN-9.4.1.2 | failure, needs review | | +| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.11/svg-img-alt?application=RuleDescription) | Ensure <svg> elements with an img, graphics-document or graphics-symbol role have accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, TTv5, TT7.a, EN-301-549, EN-9.1.1.1, ACT, RGAAv4, RGAA-1.1.5 | failure, needs review | [7d6734](https://act-rules.github.io/rules/7d6734) | +| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.11/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table that uses the headers attribute refers only to other <th> elements in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g, TTv5, TT14.b, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-5.7.4 | failure, needs review | [a25f45](https://act-rules.github.io/rules/a25f45) | +| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.11/th-has-data-cells?application=RuleDescription) | Ensure that <th> elements and elements with role=columnheader/rowheader have data cells they describe | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g, TTv5, TT14.b, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-5.7.1 | failure, needs review | [d0f69e](https://act-rules.github.io/rules/d0f69e) | +| [valid-lang](https://dequeuniversity.com/rules/axe/4.11/valid-lang?application=RuleDescription) | Ensure lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312, TTv5, TT11.b, EN-301-549, EN-9.3.1.2, ACT, RGAAv4, RGAA-8.8.1 | failure | [de46e4](https://act-rules.github.io/rules/de46e4) | +| [video-caption](https://dequeuniversity.com/rules/axe/4.11/video-caption?application=RuleDescription) | Ensure <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a, TTv5, TT17.a, EN-301-549, EN-9.1.2.2, RGAAv4, RGAA-4.3.1 | needs review | [eac66b](https://act-rules.github.io/rules/eac66b) | + +## WCAG 2.1 Level A & AA Rules + +| Rule ID | Description | Impact | Tags | Issue Type | [ACT Rules](https://www.w3.org/WAI/standards-guidelines/act/rules/) | +| :------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------- | :------ | :------------------------------------------------------------------------------ | :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [autocomplete-valid](https://dequeuniversity.com/rules/axe/4.11/autocomplete-valid?application=RuleDescription) | Ensure the autocomplete attribute is correct and suitable for the form field | Serious | cat.forms, wcag21aa, wcag135, EN-301-549, EN-9.1.3.5, ACT, RGAAv4, RGAA-11.13.1 | failure, needs review | [73f2c2](https://act-rules.github.io/rules/73f2c2) | +| [avoid-inline-spacing](https://dequeuniversity.com/rules/axe/4.11/avoid-inline-spacing?application=RuleDescription) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | Serious | cat.structure, wcag21aa, wcag1412, EN-301-549, EN-9.1.4.12, ACT | failure | [24afc2](https://act-rules.github.io/rules/24afc2), [9e45ec](https://act-rules.github.io/rules/9e45ec), [78fd32](https://act-rules.github.io/rules/78fd32) | +>>>>>>> e997880ebbfefc634caf535727afe2d5efd212f3 ## WCAG 2.2 Level A & AA Rules These rules are disabled by default, until WCAG 2.2 is more widely adopted and required. -| Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | -| :----------------------------------------------------------------------------------------------- | :------------------------------------------------- | :------ | :--------------------------------------------- | :------------------------- | :-------- | -| [target-size](https://dequeuniversity.com/rules/axe/4.9/target-size?application=RuleDescription) | Ensure touch target have sufficient size and space | Serious | cat.sensory-and-visual-cues, wcag22aa, wcag258 | failure, needs review | | +| Rule ID | Description | Impact | Tags | Issue Type | [ACT Rules](https://www.w3.org/WAI/standards-guidelines/act/rules/) | +| :------------------------------------------------------------------------------------------------ | :-------------------------------------------------- | :------ | :--------------------------------------------- | :------------------------- | :------------------------------------------------------------------ | +| [target-size](https://dequeuniversity.com/rules/axe/4.11/target-size?application=RuleDescription) | Ensure touch targets have sufficient size and space | Serious | cat.sensory-and-visual-cues, wcag22aa, wcag258 | failure, needs review | | ## Best Practices Rules Rules that do not necessarily conform to WCAG success criterion but are industry accepted practices that improve the user experience. +<<<<<<< HEAD | Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | | :----------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :----------------------------------------- | :------------------------- | :------------------------------------------------- | | [accesskeys](https://dequeuniversity.com/rules/axe/4.9/accesskeys?application=RuleDescription) | Ensures every accesskey attribute value is unique | Serious | cat.keyboard, best-practice | failure | | @@ -125,22 +197,63 @@ Rules that do not necessarily conform to WCAG success criterion but are industry | [skip-link](https://dequeuniversity.com/rules/axe/4.9/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.9/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.9/table-duplicate-name?application=RuleDescription) | Ensure the <caption> element does not contain the same text as the summary attribute | Minor | cat.tables, best-practice | failure, needs review | | +======= +| Rule ID | Description | Impact | Tags | Issue Type | [ACT Rules](https://www.w3.org/WAI/standards-guidelines/act/rules/) | +| :------------------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :----------------------------------------------- | :------------------------- | :------------------------------------------------------------------ | +| [accesskeys](https://dequeuniversity.com/rules/axe/4.11/accesskeys?application=RuleDescription) | Ensure every accesskey attribute value is unique | Serious | cat.keyboard, best-practice | failure | | +| [aria-allowed-role](https://dequeuniversity.com/rules/axe/4.11/aria-allowed-role?application=RuleDescription) | Ensure 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.11/aria-dialog-name?application=RuleDescription) | Ensure every ARIA dialog and alertdialog node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | | +| [aria-text](https://dequeuniversity.com/rules/axe/4.11/aria-text?application=RuleDescription) | Ensure 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.11/aria-treeitem-name?application=RuleDescription) | Ensure every ARIA treeitem node has an accessible name | Serious | cat.aria, best-practice | failure, needs review | | +| [empty-heading](https://dequeuniversity.com/rules/axe/4.11/empty-heading?application=RuleDescription) | Ensure headings have discernible text | Minor | cat.name-role-value, best-practice | failure, needs review | [ffd0e9](https://act-rules.github.io/rules/ffd0e9) | +| [empty-table-header](https://dequeuniversity.com/rules/axe/4.11/empty-table-header?application=RuleDescription) | Ensure table headers have discernible text | Minor | cat.name-role-value, best-practice | failure, needs review | | +| [frame-tested](https://dequeuniversity.com/rules/axe/4.11/frame-tested?application=RuleDescription) | Ensure <iframe> and <frame> elements contain the axe-core script | Critical | cat.structure, best-practice, review-item | failure, needs review | | +| [heading-order](https://dequeuniversity.com/rules/axe/4.11/heading-order?application=RuleDescription) | Ensure the order of headings is semantically correct | Moderate | cat.semantics, best-practice | failure, needs review | | +| [image-redundant-alt](https://dequeuniversity.com/rules/axe/4.11/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.11/label-title-only?application=RuleDescription) | Ensure that every form element has a visible label and is not solely labeled using hidden labels, or the title or aria-describedby attributes | Serious | cat.forms, best-practice | failure | | +| [landmark-banner-is-top-level](https://dequeuniversity.com/rules/axe/4.11/landmark-banner-is-top-level?application=RuleDescription) | Ensure the banner landmark is at top level | Moderate | cat.semantics, best-practice | failure | | +| [landmark-complementary-is-top-level](https://dequeuniversity.com/rules/axe/4.11/landmark-complementary-is-top-level?application=RuleDescription) | Ensure 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.11/landmark-contentinfo-is-top-level?application=RuleDescription) | Ensure the contentinfo landmark is at top level | Moderate | cat.semantics, best-practice | failure | | +| [landmark-main-is-top-level](https://dequeuniversity.com/rules/axe/4.11/landmark-main-is-top-level?application=RuleDescription) | Ensure the main landmark is at top level | Moderate | cat.semantics, best-practice | failure | | +| [landmark-no-duplicate-banner](https://dequeuniversity.com/rules/axe/4.11/landmark-no-duplicate-banner?application=RuleDescription) | Ensure the document has at most one banner landmark | Moderate | cat.semantics, best-practice | failure | | +| [landmark-no-duplicate-contentinfo](https://dequeuniversity.com/rules/axe/4.11/landmark-no-duplicate-contentinfo?application=RuleDescription) | Ensure the document has at most one contentinfo landmark | Moderate | cat.semantics, best-practice | failure | | +| [landmark-no-duplicate-main](https://dequeuniversity.com/rules/axe/4.11/landmark-no-duplicate-main?application=RuleDescription) | Ensure the document has at most one main landmark | Moderate | cat.semantics, best-practice | failure | | +| [landmark-one-main](https://dequeuniversity.com/rules/axe/4.11/landmark-one-main?application=RuleDescription) | Ensure the document has a main landmark | Moderate | cat.semantics, best-practice | failure | | +| [landmark-unique](https://dequeuniversity.com/rules/axe/4.11/landmark-unique?application=RuleDescription) | Ensure landmarks are unique | Moderate | cat.semantics, best-practice | failure | | +| [meta-viewport-large](https://dequeuniversity.com/rules/axe/4.11/meta-viewport-large?application=RuleDescription) | Ensure <meta name="viewport"> can scale a significant amount | Minor | cat.sensory-and-visual-cues, best-practice | failure | | +| [page-has-heading-one](https://dequeuniversity.com/rules/axe/4.11/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.11/presentation-role-conflict?application=RuleDescription) | Ensure elements marked as presentational do not have global ARIA or tabindex so that all screen readers ignore them | Minor | cat.aria, best-practice, ACT | failure | [46ca7f](https://act-rules.github.io/rules/46ca7f) | +| [region](https://dequeuniversity.com/rules/axe/4.11/region?application=RuleDescription) | Ensure all page content is contained by landmarks | Moderate | cat.keyboard, best-practice, RGAAv4, RGAA-9.2.1 | failure | | +| [scope-attr-valid](https://dequeuniversity.com/rules/axe/4.11/scope-attr-valid?application=RuleDescription) | Ensure the scope attribute is used correctly on tables | Moderate | cat.tables, best-practice | failure | | +| [skip-link](https://dequeuniversity.com/rules/axe/4.11/skip-link?application=RuleDescription) | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice, RGAAv4, RGAA-12.7.1 | failure, needs review | | +| [tabindex](https://dequeuniversity.com/rules/axe/4.11/tabindex?application=RuleDescription) | Ensure tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | failure | | +| [table-duplicate-name](https://dequeuniversity.com/rules/axe/4.11/table-duplicate-name?application=RuleDescription) | Ensure the <caption> element does not contain the same text as the summary attribute | Minor | cat.tables, best-practice, RGAAv4, RGAA-5.2.1 | failure, needs review | | +>>>>>>> e997880ebbfefc634caf535727afe2d5efd212f3 ## WCAG 2.x level AAA rules Rules that check for conformance to WCAG AAA success criteria that can be fully automated. These are disabled by default in axe-core. +<<<<<<< HEAD | Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | | :--------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | :------- | :----------------------------------------------------------------------- | :------------------------- | :------------------------------------------------- | | [color-contrast-enhanced](https://dequeuniversity.com/rules/axe/4.9/color-contrast-enhanced?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AAA enhanced contrast ratio thresholds | Serious | cat.color, wcag2aaa, wcag146, ACT | failure, needs review | [09o5cg](https://act-rules.github.io/rules/09o5cg) | | [heading-order](https://dequeuniversity.com/rules/axe/4.9/heading-order?application=RuleDescription) | Ensures the order of headings is semantically correct | Moderate | cat.structure, wcag2aaa, wcag2410, a11y-engine, a11y-engine-experimental | failure, needs review | | | [identical-links-same-purpose](https://dequeuniversity.com/rules/axe/4.9/identical-links-same-purpose?application=RuleDescription) | Ensure that links with the same accessible name serve a similar purpose | Minor | cat.semantics, wcag2aaa, wcag249 | needs review | [b20e66](https://act-rules.github.io/rules/b20e66) | | [meta-refresh-no-exceptions](https://dequeuniversity.com/rules/axe/4.9/meta-refresh-no-exceptions?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used for delayed refresh | Minor | cat.time-and-media, wcag2aaa, wcag224, wcag325 | failure | [bisz58](https://act-rules.github.io/rules/bisz58) | +======= +| Rule ID | Description | Impact | Tags | Issue Type | [ACT Rules](https://www.w3.org/WAI/standards-guidelines/act/rules/) | +| :---------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------- | :------ | :--------------------------------------------- | :------------------------- | :------------------------------------------------------------------ | +| [color-contrast-enhanced](https://dequeuniversity.com/rules/axe/4.11/color-contrast-enhanced?application=RuleDescription) | Ensure the contrast between foreground and background colors meets WCAG 2 AAA enhanced contrast ratio thresholds | Serious | cat.color, wcag2aaa, wcag146, ACT | failure, needs review | [09o5cg](https://act-rules.github.io/rules/09o5cg) | +| [identical-links-same-purpose](https://dequeuniversity.com/rules/axe/4.11/identical-links-same-purpose?application=RuleDescription) | Ensure that links with the same accessible name serve a similar purpose | Minor | cat.semantics, wcag2aaa, wcag249 | needs review | [b20e66](https://act-rules.github.io/rules/b20e66) | +| [meta-refresh-no-exceptions](https://dequeuniversity.com/rules/axe/4.11/meta-refresh-no-exceptions?application=RuleDescription) | Ensure <meta http-equiv="refresh"> is not used for delayed refresh | Minor | cat.time-and-media, wcag2aaa, wcag224, wcag325 | failure | [bisz58](https://act-rules.github.io/rules/bisz58) | +>>>>>>> e997880ebbfefc634caf535727afe2d5efd212f3 ## Experimental Rules Rules we are still testing and developing. They are disabled by default in axe-core, but are enabled for the axe browser extensions. +<<<<<<< HEAD | Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | | :------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | :------- | :----------------------------------------------------------------------------------------------------------- | :------------------------- | :------------------------------------------------- | | [css-orientation-lock](https://dequeuniversity.com/rules/axe/4.9/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, EN-301-549, EN-9.1.3.4, experimental | failure, needs review | [b33eff](https://act-rules.github.io/rules/b33eff) | @@ -148,14 +261,25 @@ Rules we are still testing and developing. They are disabled by default in axe-c | [hidden-content](https://dequeuniversity.com/rules/axe/4.9/hidden-content?application=RuleDescription) | Informs users about hidden content. | Minor | cat.structure, best-practice, experimental, review-item | failure, needs review | | | [table-fake-caption](https://dequeuniversity.com/rules/axe/4.9/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, EN-301-549, EN-9.1.3.1 | failure | | | [td-has-header](https://dequeuniversity.com/rules/axe/4.9/td-has-header?application=RuleDescription) | Ensure that each non-empty data cell in a <table> larger than 3 by 3 has one or more table headers | Critical | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g, TTv5, TT14.b, EN-301-549, EN-9.1.3.1 | failure | | +======= +| Rule ID | Description | Impact | Tags | Issue Type | [ACT Rules](https://www.w3.org/WAI/standards-guidelines/act/rules/) | +| :-------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------ | :------- | :------------------------------------------------------------------------------------------------------------------------------- | :------------------------- | :------------------------------------------------------------------ | +| [css-orientation-lock](https://dequeuniversity.com/rules/axe/4.11/css-orientation-lock?application=RuleDescription) | Ensure content is not locked to any specific display orientation, and the content is operable in all display orientations | Serious | cat.structure, wcag134, wcag21aa, EN-301-549, EN-9.1.3.4, RGAAv4, RGAA-13.9.1, experimental | failure, needs review | [b33eff](https://act-rules.github.io/rules/b33eff) | +| [focus-order-semantics](https://dequeuniversity.com/rules/axe/4.11/focus-order-semantics?application=RuleDescription) | Ensure elements in the focus order have a role appropriate for interactive content | Minor | cat.keyboard, best-practice, RGAAv4, RGAA-12.8.1, experimental | failure | | +| [hidden-content](https://dequeuniversity.com/rules/axe/4.11/hidden-content?application=RuleDescription) | Inform users about hidden content. | Minor | cat.structure, best-practice, experimental, review-item | failure, needs review | | +| [label-content-name-mismatch](https://dequeuniversity.com/rules/axe/4.11/label-content-name-mismatch?application=RuleDescription) | Ensure that elements labelled through their content must have their visible text as part of their accessible name | Serious | cat.semantics, wcag21a, wcag253, EN-301-549, EN-9.2.5.3, RGAAv4, RGAA-6.1.5, experimental | failure | [2ee8b8](https://act-rules.github.io/rules/2ee8b8) | +| [p-as-heading](https://dequeuniversity.com/rules/axe/4.11/p-as-heading?application=RuleDescription) | Ensure bold, italic text and font-size is not used to style <p> elements as a heading | Serious | cat.semantics, wcag2a, wcag131, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-9.1.3, experimental | failure, needs review | | +| [table-fake-caption](https://dequeuniversity.com/rules/axe/4.11/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, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-5.4.1 | failure | | +| [td-has-header](https://dequeuniversity.com/rules/axe/4.11/td-has-header?application=RuleDescription) | Ensure that each non-empty data cell in a <table> larger than 3 by 3 has one or more table headers | Critical | cat.tables, experimental, wcag2a, wcag131, section508, section508.22.g, TTv5, TT14.b, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-5.7.4 | failure | | +>>>>>>> e997880ebbfefc634caf535727afe2d5efd212f3 ## Deprecated Rules Deprecated rules are disabled by default and will be removed in the next major release. -| Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | -| :----------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------------------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------- | -| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.9/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, deprecated | failure, needs review | | -| [audio-caption](https://dequeuniversity.com/rules/axe/4.9/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, EN-301-549, EN-9.1.2.1, section508, section508.22.a, deprecated | needs review | [2eb176](https://act-rules.github.io/rules/2eb176), [afb423](https://act-rules.github.io/rules/afb423) | -| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.9/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a-obsolete, wcag411, deprecated | failure | [3ea0c8](https://act-rules.github.io/rules/3ea0c8) | -| [duplicate-id](https://dequeuniversity.com/rules/axe/4.9/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a-obsolete, wcag411, deprecated | failure | [3ea0c8](https://act-rules.github.io/rules/3ea0c8) | +| Rule ID | Description | Impact | Tags | Issue Type | [ACT Rules](https://www.w3.org/WAI/standards-guidelines/act/rules/) | +| :------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------------------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------- | +| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.11/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, deprecated | failure, needs review | | +| [audio-caption](https://dequeuniversity.com/rules/axe/4.11/audio-caption?application=RuleDescription) | Ensure <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, EN-301-549, EN-9.1.2.1, section508, section508.22.a, deprecated | needs review | [2eb176](https://act-rules.github.io/rules/2eb176), [afb423](https://act-rules.github.io/rules/afb423) | +| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.11/duplicate-id-active?application=RuleDescription) | Ensure every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a-obsolete, wcag411, deprecated | failure | [3ea0c8](https://act-rules.github.io/rules/3ea0c8) | +| [duplicate-id](https://dequeuniversity.com/rules/axe/4.11/duplicate-id?application=RuleDescription) | Ensure every id attribute value is unique | Minor | cat.parsing, wcag2a-obsolete, wcag411, deprecated | failure | [3ea0c8](https://act-rules.github.io/rules/3ea0c8) | diff --git a/lib/rules/css-orientation-lock.json b/lib/rules/css-orientation-lock.json index ddbf7857d..ed7f7e6cb 100644 --- a/lib/rules/css-orientation-lock.json +++ b/lib/rules/css-orientation-lock.json @@ -8,11 +8,13 @@ "wcag21aa", "EN-301-549", "EN-9.1.3.4", + "RGAAv4", + "RGAA-13.9.1", "experimental" ], "actIds": ["b33eff"], "metadata": { - "description": "Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations", + "description": "Ensure content is not locked to any specific display orientation, and the content is operable in all display orientations", "help": "CSS Media queries must not lock display orientation" }, "all": ["css-orientation-lock"], diff --git a/lib/rules/focus-order-semantics.json b/lib/rules/focus-order-semantics.json index 8c73c2b9f..d0a08f21f 100644 --- a/lib/rules/focus-order-semantics.json +++ b/lib/rules/focus-order-semantics.json @@ -3,9 +3,15 @@ "impact": "minor", "selector": "div, h1, h2, h3, h4, h5, h6, [role=heading], p, span", "matches": "inserted-into-focus-order-matches", - "tags": ["cat.keyboard", "best-practice", "experimental"], + "tags": [ + "cat.keyboard", + "best-practice", + "RGAAv4", + "RGAA-12.8.1", + "experimental" + ], "metadata": { - "description": "Ensures elements in the focus order have a role appropriate for interactive content", + "description": "Ensure elements in the focus order have a role appropriate for interactive content", "help": "Elements in the focus order should have an appropriate role" }, "all": [], diff --git a/lib/rules/hidden-content.json b/lib/rules/hidden-content.json index 05323aca1..719113ccd 100644 --- a/lib/rules/hidden-content.json +++ b/lib/rules/hidden-content.json @@ -5,7 +5,7 @@ "excludeHidden": false, "tags": ["cat.structure", "best-practice", "experimental", "review-item"], "metadata": { - "description": "Informs users about hidden content.", + "description": "Inform users about hidden content.", "help": "Hidden content on the page should be analyzed" }, "all": [], diff --git a/lib/rules/summary-name.json b/lib/rules/summary-name.json new file mode 100644 index 000000000..a56d230ac --- /dev/null +++ b/lib/rules/summary-name.json @@ -0,0 +1,29 @@ +{ + "id": "summary-name", + "impact": "serious", + "selector": "summary", + "matches": "summary-interactive-matches", + "tags": [ + "cat.name-role-value", + "wcag2a", + "wcag412", + "section508", + "section508.22.a", + "TTv5", + "TT6.a", + "EN-301-549", + "EN-9.4.1.2" + ], + "metadata": { + "description": "Ensure summary elements have discernible text", + "help": "Summary elements must have discernible text" + }, + "all": [], + "any": [ + "has-visible-text", + "aria-label", + "aria-labelledby", + "non-empty-title" + ], + "none": [] +} diff --git a/lib/rules/table-fake-caption.json b/lib/rules/table-fake-caption.json index 4561ebc50..5e3fa88b5 100644 --- a/lib/rules/table-fake-caption.json +++ b/lib/rules/table-fake-caption.json @@ -11,7 +11,9 @@ "section508", "section508.22.g", "EN-301-549", - "EN-9.1.3.1" + "EN-9.1.3.1", + "RGAAv4", + "RGAA-5.4.1" ], "metadata": { "description": "Ensure that tables with a caption use the element.", diff --git a/lib/rules/td-has-header.json b/lib/rules/td-has-header.json index 1e1880f27..47adc3f4e 100644 --- a/lib/rules/td-has-header.json +++ b/lib/rules/td-has-header.json @@ -13,7 +13,9 @@ "TTv5", "TT14.b", "EN-301-549", - "EN-9.1.3.1" + "EN-9.1.3.1", + "RGAAv4", + "RGAA-5.7.4" ], "metadata": { "description": "Ensure that each non-empty data cell in a larger than 3 by 3 has one or more table headers", diff --git a/locales/de.json b/locales/de.json index cab4da906..b98a53382 100644 --- a/locales/de.json +++ b/locales/de.json @@ -66,7 +66,7 @@ "help": "Erforderliche ARIA-Attribute müssen bereitgestellt werden." }, "aria-required-children": { - "description": "Stellt sicher, dass Elemente mit einer ARIA-Rolle, welche bestimmte untergeordnete Rollen voraussetzten auch diese enthalten.", + "description": "Stellt sicher, dass Elemente mit einer ARIA-Rolle, welche bestimmte untergeordnete Rollen voraussetzten diese auch enthalten.", "help": "Bestimmte ARIA-Rollen müssen spezifische, untergeordnete Kind-Rollen enthalten." }, "aria-required-parent": { @@ -167,7 +167,7 @@ }, "empty-heading": { "description": "Stellt sicher, dass Überschriften einen wahrnehmbaren Text beinhalten.", - "help": "Überschriften dürfen nichtleer sein." + "help": "Überschriften dürfen nicht leer sein." }, "empty-table-header": { "description": "Stellt sicher, dass Tabellenkopfzeilen einen wahrnehmbaren Text beinhalten.", @@ -282,8 +282,8 @@ "help": "Seite muss eine main landmark enthalten." }, "landmark-unique": { - "help": "Stellt sicher, dass landmarks einzigartig sind.", - "description": "Landmarks müssen eine einzigartige role oder role/label/title Kombination (bzw. zugänglicher Name / accessible name) besitzen." + "description": "Stellt sicher, dass landmarks einzigartig sind.", + "help": "Landmarks müssen eine einzigartige role oder role/label/title Kombination (bzw. zugänglicher Name / accessible name) besitzen." }, "link-in-text-block": { "description": "Stellt sicher, dass Links vom umgebenden Text nicht allein durch die Farbe unterschieden werden können.", @@ -342,8 +342,8 @@ "help": "Die Seite muss eine Überschrift der ersten Ebene enthalten." }, "presentation-role-conflict": { - "description": "Markiert Elemente welche eine Rolle besitzen, die none oder presentation ist und die eine Rollenauflösung benötigen.", - "help": "Elemente mit Rolle none oder presentation dürfen mit anderen Rollen nicht in Konflikt stehen." + "description": "Elemente mit role=\"none\" oder role=\"presentation\" sollten kein globales ARIA-Attribute besitzen oder fokussierbar sein, damit sie von Screenreadern ignoriert werden.", + "help": "Elemente mit \"role=none\" oder \"role=presentation\" sollen von Screenreadern ignoriert werden." }, "region": { "description": "Stellt sicher, dass jeglicher Inhalt in einer landmark region enthalten ist.", @@ -373,6 +373,10 @@ "description": "Stellt sicher, dass alle Skip-Links ein fokussierbares Ziel enthalten.", "help": "Das Ziel eines Skip-Links sollte existieren und fokussierbar sein." }, + "summary-name": { + "description": "Stellt sicher, dass die summary-Elemente einen erkennbaren Text haben", + "help": "summary-Elemente müssen einen erkennbaren Text haben" + }, "svg-img-alt": { "description": "Stellt sicher, dass Elemente mit einer img, graphics-document oder graphics-symbol Rolle einen zugänglichen Namen (accessible name) besitzen.", "help": " Elemente mit einer img Rolle sollten einen Alternativtext besitzen." @@ -461,7 +465,7 @@ "hidden": "aria-errormessage Wert `${data.values}` kann nicht auf ein verstecktes Element verweisen." }, "incomplete": { - "singular": "Stellt sicher, dass aria-errormessage Wert `${data.values}` zu einem existierendem Element verweist.", + "singular": "Stellt sicher, dass aria-errormessage Wert `${data.values}` auf ein existierendes Element verweist.", "plural": "Stellt sicher, dass aria-errormessage Werte `${data.values}` zu existierenden Elementen verweisen.", "idrefs": "Es konnte nicht festgestellt werden, ob das Element aria-errormessage auf der Seite existiert: ${data.values}" } @@ -498,7 +502,8 @@ }, "aria-required-children": { "pass": { - "default": "Alle benötigten ARIA Kinder sind vorhanden." + "default": "Alle benötigten ARIA Kinder sind vorhanden.", + "aria-busy": "Element hat ein aria-busy-Attribut, daher ist es erlaubt, erforderliche ARIA Kinder wegzulassen" }, "fail": { "singular": "Benötigte ARIA Kindrolle nicht vorhanden: ${data.values}", @@ -524,7 +529,7 @@ }, "aria-unsupported-attr": { "pass": "ARIA Attribut wird unterstützt", - "fail": "ARIA Attribut ist nicht wirklich in Screenreadern und anderen assistiven Technologien unterstützt: ${data.values}" + "fail": "ARIA Attribut ist nicht allgemein in Screenreadern und anderen assistiven Technologien unterstützt: ${data.values}" }, "aria-valid-attr-value": { "pass": "ARIA Attributwerte sind gültig.", @@ -537,7 +542,8 @@ "noIdShadow": "ARIA-Attribut Element-ID existiert nicht auf der Seite oder ist ein Nachkomme (descendant) eines anderen Schatten-DOM-tree: ${data.needsReview}", "ariaCurrent": "Folgendes ARIA Attributwert ist ungültig und wird wie \"aria-current=true\" gesehen: ${data.needsReview}", "idrefs": "Es konnte nicht festgestellt werden, ob das ARIA-Attribut element ID auf der Seite existiert: ${data.needsReview}", - "empty": "ARIA-Attributwert wird ignoriert, wenn leer: ${data.needsReview}" + "empty": "ARIA-Attributwert wird ignoriert, wenn leer: ${data.needsReview}", + "controlsWithinPopup": "Bei der Verwendung von aria-haspopup konnte nicht festgestellt werden, ob die von aria-controls referenzierte ID auf der Seite existiert: ${data.needsReview}" } }, "aria-valid-attr": { @@ -596,7 +602,7 @@ }, "unsupportedrole": { "pass": "ARIA Rolle wird unterstützt.", - "fail": "Folgende Rollen werden nicht wirklich in Screenreadern und assistiven Technologien unterstützt: ${data.values}" + "fail": "Folgende Rollen werden nicht allgemein in Screenreadern und assistiven Technologien unterstützt: ${data.values}" }, "valid-scrollable-semantics": { "pass": "Das Element hat eine gültige Semantik für ein Element in der Fokusreihenfolge.", @@ -628,7 +634,7 @@ "color-contrast": { "pass": { "default": "Das Element hat einen ausreichenden Kontrast von ${data.contrastRatio}.", - "hidden": "Das Element ist verstec" + "hidden": "Das Element ist versteckt." }, "fail": { "default": "Das Element hat einen unzureichenden Kontrast von ${data.contrastRatio} (Vordergrundfarbe: ${data.fgColor}, Hintergrundfarbe: ${data.bgColor}, Schriftgröße: ${data.fontSize}, Schriftstärke: ${data.fontWeight}). Erwartetes Kontrastverhältnis von ${data.expectedContrastRatio}", @@ -681,7 +687,8 @@ }, "autocomplete-valid": { "pass": "Der Wert des autocomplete Attributes ist korrekt formatiert.", - "fail": "Der Wert des autocomplete Attributes ist inkorrekt formatiert." + "fail": "Der Wert des autocomplete Attributes ist inkorrekt formatiert.", + "incomplete": "Der Wert des autocomplete Attributes hat einen Nicht-Standardwert. Prüfe, ob stattdessen ein Standardwert verwendet werden kann." }, "accesskeys": { "pass": "Alle accesskey-Attribute sind einzigartig.", @@ -702,7 +709,7 @@ }, "focusable-modal-open": { "pass": "Keine fokussierbaren Elemente während ein modaler Dialog offen ist.", - "incomplete": "Üerprüfe ob Elemente fokussierbar während des derzeitigen Status sind." + "incomplete": "Überprüfe ob Elemente während des derzeitigen Status fokussierbar sind." }, "focusable-no-name": { "pass": "Das Element befindet sich nicht in der Tabreihenfolge und enthält keinen zugänglichen Text.", @@ -788,15 +795,15 @@ }, "multiple-label": { "pass": "Das
-Element besitzt keine multiplen
als auch
-Elemente, falls es nichtleer sein sollte.", + "pass": "Das Definitionslisten-Element enthält sowohl
als auch
-Elemente, falls es nicht leer sein sollte.", "fail": "Das Definitionslisten-Element enthält kein
-Element, welches von keinem
-Element gefolgt wird." }, "caption": { @@ -864,17 +871,22 @@ "fail": "Die viewport-Einstellungen im -Tag blockieren das Zoomen auf mobilen Geräten." }, "target-offset": { - "pass": "Das Ziel hat genügend Abstand zu seinen nächsten Nachbarn. Der sichere klickbare Bereich hat einen Durchmesser von ${data.closestOffset}px, der mindestens ${data.minOffset}px beträgt.", + "pass": { + "default": "Das Ziel hat genügend Abstand zu seinen nächsten Nachbarn. Der sichere klickbare Bereich hat einen Durchmesser von ${data.closestOffset}px, der mindestens ${data.minOffset}px beträgt.", + "large": "Das Ziel überschreitet bei weitem die Mindestgröße von ${data.minOffset}px." + }, "fail": "Das Ziel hat nicht genügend Abstand zu seinen nächsten Nachbarn. Der sichere klickbare Bereich hat einen Durchmesser von ${data.closestOffset}px statt mindestens ${data.minOffset}px.", "incomplete": { "default": "Element mit negativem Tabindex hat nicht genügend Abstand zu seinen nächsten Nachbarn. Der sichere klickbare Bereich hat einen Durchmesser von ${data.closestOffset}px statt mindestens ${data.minOffset}px. Ist dies ein Ziel?", - "nonTabbableNeighbor": "Das Ziel hat nicht genügend Abstand zu seinen nächsten Nachbarn. Der sichere klickbare Bereich hat einen Durchmesser von ${data.closestOffset}px statt mindestens ${data.minOffset}px. Ist der Nachbar ein Ziel?" + "nonTabbableNeighbor": "Das Ziel hat nicht genügend Abstand zu seinen nächsten Nachbarn. Der sichere klickbare Bereich hat einen Durchmesser von ${data.closestOffset}px statt mindestens ${data.minOffset}px. Ist der Nachbar ein Ziel?", + "tooManyRects": "Die Zielgröße konnte nicht ermittelt werden, da zu viele überlappende Elemente vorhanden sind." } }, "target-size": { "pass": { "default": "Das Steuerelement hat eine ausreichende Größe (${data.width}px x ${data.height}px, sollte mindestens ${data.minSize}px x ${data.minSize}px sein).", - "obscured": "Das Steuerelement wird ignoriert, da es vollständig verdeckt ist und daher nicht angeklickt werden kann." + "obscured": "Das Steuerelement wird ignoriert, da es vollständig verdeckt ist und daher nicht angeklickt werden kann.", + "large": "Das Ziel überschreitet bei weitem die Mindestgröße von ${data.minSize}px." }, "fail": { "default": "Das Ziel hat eine unzureichende Größe (${data.width}px x ${data.height}px, sollte mindestens ${data.minSize}px x ${data.minSize}px sein).", @@ -884,7 +896,8 @@ "default": "Element mit negativem Tabindex hat unzureichende Größe (${data.width}px mal ${data.height}px, sollte mindestens ${data.minSize}px mal ${data.minSize}px sein). Ist dies ein Ziel?", "contentOverflow": "Elementgröße konnte aufgrund von Überlaufinhalten nicht genau bestimmt werden", "partiallyObscured": "Element mit negativem Tabindex hat unzureichende Größe, weil es teilweise verdeckt ist (kleinster Platz ist ${data.width}px mal ${data.height}px, sollte mindestens ${data.minSize}px mal ${data.minSize}px sein). Ist dies ein Ziel?", - "partiallyObscuredNonTabbable": "Das Ziel hat eine unzureichende Größe, weil es teilweise von einem Nachbarn mit negativem Tabindex verdeckt wird (der kleinste Platz ist ${data.width}px mal ${data.height}px, sollte mindestens ${data.minSize}px mal ${data.minSize}px sein). Ist der Nachbar ein Ziel?" + "partiallyObscuredNonTabbable": "Das Ziel hat eine unzureichende Größe, weil es teilweise von einem Nachbarn mit negativem Tabindex verdeckt wird (der kleinste Platz ist ${data.width}px mal ${data.height}px, sollte mindestens ${data.minSize}px mal ${data.minSize}px sein). Ist der Nachbar ein Ziel?", + "tooManyRects": "Die Zielgröße konnte nicht ermittelt werden, da zu viele überlappende Elemente vorhanden sind." } }, "header-present": { @@ -947,7 +960,7 @@ "fail": "Das Dokument besitzt mehrere Elemente mit demselben id-Attributwert: ${data}." }, "aria-label": { - "pass": "Das aria-label-Attribut existiert und ist nichtleer.", + "pass": "Das aria-label-Attribut existiert und ist nicht leer.", "fail": "Es existiert kein aria-label-Attribut oder das Attribut ist leer." }, "aria-labelledby": { @@ -968,7 +981,7 @@ "incomplete": "Ob das Element über Kindelemente bzw. textuelle Inhalte verfügt, kann nicht ermittelt werden." }, "doc-has-title": { - "pass": "Test", + "pass": "Das Dokument besitzt ein nichtleeres -Element.", "fail": "Das Dokument besitzt kein <title>-Element oder das <title>-Element ist leer." }, "exists": { @@ -1083,9 +1096,13 @@ "fail": "Nicht alle (nichtleeren) Datenzellen haben eine Tabellenkopfzelle." }, "td-headers-attr": { - "pass": "Das headers-Attribut wird ausschließlich dafür verwendet, um auf andere Zellen in der Tabelle zu verweisen.", + "pass": "Das headers-Attribut wird ausschließlich dafür verwendet, um auf andere Kopfzellen in der Tabelle zu verweisen.", "incomplete": "Das headers-Attribut ist leer.", - "fail": "Das headers-Attribut wird nicht ausschließlich dafür verwendet, um auf andere Zellen in der Tabelle zu verweisen." + "fail": { + "cell-header-not-in-table": "Das headers-Attribut wird nicht ausschließlich dafür verwendet, um auf andere Kopfzellen in der Tabelle zu verweisen.", + "cell-header-not-th": "Das headers-Attribut muss auf Kopfzellen verweisen, nicht auf Datenzellen.", + "header-refs-self": "Das Element mit dem headers-Attribut verweist auf sich selbst." + } }, "th-has-data-cells": { "pass": "Alle Tabellenkopfzellen beziehen sich auf Datenzellen.", @@ -1095,7 +1112,7 @@ "hidden-content": { "pass": "Jeglicher Inhalt der Seite wurde analysiert.", "fail": "Beim Analysieren der Inhalte auf dieser Seite sind Probleme aufgetreten.", - "incomplete": "Auf der Seite befinden sich versteckte Inhalte, die nicht analysiert werden konnten. Um den Inhalt analysieren zu können, müssen Sie die Anzeige auslösen." + "incomplete": "Auf der Seite befinden sich versteckte Inhalte, die nicht analysiert werden konnten. Um den Inhalt analysieren zu können, müssen Sie die Anzeige dieser Inhalte auslösen." } }, "failureSummaries": { @@ -1106,5 +1123,5 @@ "failureMessage": "Korrigiere alle der folgenden Punkte:{{~it:value}}\n {{=value.split('\\n').join('\\n ')}}{{~}}" } }, - "incompleteFallbackMessage": "" + "incompleteFallbackMessage": "axe konnte den Grund nicht ermitteln. Versuchen Sie es mit dem Element Inspector." } diff --git a/locales/ja.json b/locales/ja.json index 161fdba32..19caad999 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -2,415 +2,419 @@ "lang": "ja", "rules": { "accesskeys": { - "description": "すべてのaccesskey属性の値が一意であることを確認します", + "description": "すべてのaccesskey属性の値が一意であることを確認してください", "help": "accesskey属性の値は一意でなければなりません" }, "area-alt": { - "description": "イメージマップの<area>要素に代替テキストが存在することを確認します", + "description": "イメージマップの<area>要素に代替テキストが存在することを確認してください", "help": "アクティブな<area>要素には代替テキストが存在しなければなりません" }, "aria-allowed-attr": { - "description": "要素のロールがARIA属性をサポートしていることを確認します", + "description": "要素のロールがARIA属性をサポートしていることを確認してください", "help": "要素にはサポートされているARIA属性のみを使用しなければなりません" }, "aria-allowed-role": { - "description": "role属性の値が要素に対して適切であることを確認します", + "description": "role属性の値が要素に対して適切であることを確認してください", "help": "ARIAロールは要素に対して適切でなければなりません" }, "aria-braille-equivalent": { - "description": "aria-braillelabelとaria-brailleroledescriptionには、点字以外の同等のものが存在することを確認します", - "help": "aria-braille属性には、点じ以外の同等のものがなければなりません " + "description": "aria-braillelabelとaria-brailleroledescriptionには、点字以外の同等のものが存在することを確認してください", + "help": "aria-braille属性には、点字以外の同等のものがなければなりません" }, "aria-command-name": { - "description": "すべてのARIA button、link、menuitemにアクセシブルな名前があることを確認します", + "description": "すべてのARIA button、link、menuitemにアクセシブルな名前があることを確認してください", "help": "ARIAコマンドにはアクセシブルな名前がなければなりません" }, "aria-conditional-attr": { - "description": "ARIA属性が要素のロールの仕様に従って使用されていることを確認します", + "description": "ARIA属性が要素のロールの仕様に従って使用されていることを確認してください", "help": "ARIA属性は要素のロールの仕様に従って使用しなければなりません" }, "aria-deprecated-role": { - "description": "要素に非推奨のロールが使用されていないことを確認します", + "description": "要素に非推奨のロールが使用されていないことを確認してください", "help": "非推奨のARIAロールを使用してはなりません" }, "aria-dialog-name": { - "description": "すべてのARIA dialog、alertdialogノードにアクセシブルな名前があることを確認します", + "description": "すべてのARIA dialog、alertdialogノードにアクセシブルな名前があることを確認してください", "help": "ARIA dialogとalertdialogノードにはアクセシブルな名前がなければなりません" }, "aria-hidden-body": { - "description": "ドキュメント本体にaria-hidden=\"true\"が存在しないことを確認します", + "description": "ドキュメント本体にaria-hidden=\"true\"が存在しないことを確認してください", "help": "ドキュメント本体にaria-hidden=\"true\"が存在してはなりません" }, "aria-hidden-focus": { - "description": "aria-hiddenが指定されている要素にフォーカスできないこと、その要素にフォーカス可能な要素が含まれていないことを確認します", + "description": "aria-hiddenが指定されている要素にフォーカスできないこと、その要素にフォーカス可能な要素が含まれていないことを確認してください", "help": "aria-hiddenが指定されている要素は、フォーカス可能であったり、フォーカス可能な要素を含んでいたりしてはなりません" }, "aria-input-field-name": { - "description": "すべてのARIA入力欄にアクセシブルな名前があることを確認します", + "description": "すべてのARIA入力欄にアクセシブルな名前があることを確認してください", "help": "ARIA入力欄にはアクセシブルな名前がなければなりません" }, "aria-meter-name": { - "description": "すべてのARIA meterノードにアクセシブルな名前があることを確認します", + "description": "すべてのARIA meterノードにアクセシブルな名前があることを確認してください", "help": "ARIA meterノードにはアクセシブルな名前がなければなりません" }, "aria-progressbar-name": { - "description": "すべてのARIA progressbarノードにアクセシブルな名前があることを確認します", + "description": "すべてのARIA progressbarノードにアクセシブルな名前があることを確認してください", "help": "ARIA progressbarノードにはアクセシブルな名前がなければなりません" }, "aria-prohibited-attr": { - "description": "要素のロールでARIA属性が禁止されていないことを確認します", + "description": "要素のロールでARIA属性が禁止されていないことを確認してください", "help": "要素には禁止されているARIA属性を使用してはなりません" }, "aria-required-attr": { - "description": "ARIAロールのある要素にすべての必須ARIA属性が存在することを確認します", + "description": "ARIAロールのある要素にすべての必須ARIA属性が存在することを確認してください", "help": "必須のARIA属性が提供されていなければなりません" }, "aria-required-children": { - "description": "子ロールを必須とするARIAロールが指定された要素に、それらが含まれていることを確認します", + "description": "子ロールを必須とするARIAロールが指定された要素に、それらが含まれていることを確認してください", "help": "特定のARIAロールには特定の子が含まれていなければなりません" }, "aria-required-parent": { - "description": "親ロールを必須とするARIAロールが指定された要素に、それらが含まれていることを確認します", + "description": "親ロールを必須とするARIAロールが指定された要素に、それらが含まれていることを確認してください", "help": "特定のARIAロールは特定の親に含まれていなければなりません" }, "aria-roledescription": { - "description": "aria-roledescriptionが暗黙的もしくは明示的なロールを持った要素に使用されていることを確認します", + "description": "aria-roledescriptionが暗黙的もしくは明示的なロールを持った要素に使用されていることを確認してください", "help": "aria-roledescriptionはセマンティックなロールを持った要素に使用しなければなりません" }, "aria-roles": { - "description": "すべてのrole属性が指定された要素で、有効な値が使用されていることを確認します", + "description": "すべてのrole属性が指定された要素で、有効な値が使用されていることを確認してください", "help": "使用されているARIAロールは有効な値に一致しなければなりません" }, "aria-text": { - "description": "role=\"text\"が指定されている要素にフォーカス可能な子孫がないことを確認します", + "description": "role=\"text\"が指定されている要素にフォーカス可能な子孫がないことを確認してください", "help": "\"role=text\"が指定されている要素には、フォーカス可能な子孫が含まれていてはなりません" }, "aria-toggle-field-name": { - "description": "すべてのARIAトグル欄にアクセシブルな名前があることを確認します", + "description": "すべてのARIAトグル欄にアクセシブルな名前があることを確認してください", "help": "ARIAトグル欄にはアクセシブルな名前がなければなりません" }, "aria-tooltip-name": { - "description": "すべてのARIA tooltipノードにアクセシブルな名前があることを確認します", + "description": "すべてのARIA tooltipノードにアクセシブルな名前があることを確認してください", "help": "ARIA tooltipノードにはアクセシブルな名前がなければなりません" }, "aria-treeitem-name": { - "description": "すべてのARIA treeitemノードにアクセシブルな名前があることを確認します", + "description": "すべてのARIA treeitemノードにアクセシブルな名前があることを確認してください", "help": "ARIA treeitemノードにはアクセシブルな名前がなければなりません" }, "aria-valid-attr-value": { - "description": "すべてのARIA属性に有効な値が存在することを確認します", + "description": "すべてのARIA属性に有効な値が存在することを確認してください", "help": "ARIA属性は有効な値に一致しなければなりません" }, "aria-valid-attr": { - "description": "aria- で始まる属性が有効なARIA属性であることを確認します", + "description": "aria- で始まる属性が有効なARIA属性であることを確認してください", "help": "ARIA属性は有効な名前に一致しなければなりません" }, "audio-caption": { - "description": "<audio>要素にキャプションが存在することを確認します", + "description": "<audio>要素にキャプションが存在することを確認してください", "help": "<audio>要素にはキャプショントラックが存在しなければなりません" }, "autocomplete-valid": { - "description": "autocomplete属性が正しく、かつフォームフィールドに対して適切であることを確認します", + "description": "autocomplete属性が正しく、かつフォームフィールドに対して適切であることを確認してください", "help": "autocomplete属性は正しく使用しなければなりません" }, "avoid-inline-spacing": { - "description": "style属性で指定されたテキストの間隔は、カスタムスタイルシートにより調整可能であることを確認します", + "description": "style属性で指定されたテキストの間隔は、カスタムスタイルシートにより調整可能であることを確認してください", "help": "インラインのテキスト間隔設定はカスタムスタイルシートによって調整可能でなければなりません" }, "blink": { - "description": "<blink>要素が使用されていないことを確認します", + "description": "<blink>要素が使用されていないことを確認してください", "help": "<blink>要素の使用は非推奨で、使用するべきではありません" }, "button-name": { - "description": "ボタンに認識可能なテキストが存在することを確認します", + "description": "ボタンに認識可能なテキストが存在することを確認してください", "help": "ボタンには認識可能なテキストが存在しなければなりません" }, "bypass": { - "description": "各ページに少なくとも1つ、ユーザーがナビゲーション部分をスキップして直接本文へ移動できるメカニズムが存在することを確認します", + "description": "各ページに少なくとも1つ、ユーザーがナビゲーション部分をスキップして直接本文へ移動できるメカニズムが存在することを確認してください", "help": "ページには繰り返されるブロックをスキップする手段が存在しなければなりません" }, "color-contrast-enhanced": { - "description": "前景色と背景色のコントラストがWCAG 2のAAAコントラスト比(高度)のしきい値を満たすことを確認します", + "description": "前景色と背景色のコントラストがWCAG 2のAAAコントラスト比(高度)のしきい値を満たすことを確認してください", "help": "要素は色のコントラスト比(高度)の閾値を満たしていなければなりません" }, "color-contrast": { - "description": "前景色と背景色のコントラストがWCAG 2のAAコントラスト比(最低限)のしきい値を満たすことを確認します", + "description": "前景色と背景色のコントラストがWCAG 2のAAコントラスト比(最低限)のしきい値を満たすことを確認してください", "help": "要素は色のコントラスト比(最低限)の閾値を満たしていなければなりません" }, "css-orientation-lock": { - "description": "コンテンツが特定のディスプレイの向きに固定されていないこと、およびコンテンツがすべてのディスプレイの向きで操作可能なことを確認します", + "description": "コンテンツが特定のディスプレイの向きに固定されていないこと、およびコンテンツがすべてのディスプレイの向きで操作可能なことを確認してください", "help": "CSSメディアクエリーはディスプレイの向きを固定するために使用してはなりません" }, "definition-list": { - "description": "<dl>要素の構造が正しいことを確認します", + "description": "<dl>要素の構造が正しいことを確認してください", "help": "<dl>要素は、適切な順序で並べられた<dt>および<dd>のグループ、<script>要素、<template>要素またはdiv要素のみを直接含んでいなければなりません" }, "dlitem": { - "description": "<dt>および<dd>要素が<dl>に含まれていることを確認します", + "description": "<dt>および<dd>要素が<dl>に含まれていることを確認してください", "help": "<dt>および<dd>要素は<dl>に含まれていなければなりません" }, "document-title": { - "description": "各HTMLドキュメントに空ではない<title>要素が含まれていることを確認します", + "description": "各HTMLドキュメントに空ではない<title>要素が含まれていることを確認してください", "help": "ドキュメントにはナビゲーションを補助するために<title>要素がなければなりません" }, "duplicate-id-active": { - "description": "アクティブな要素のid属性の値が一意であることを確認します", + "description": "アクティブな要素のid属性の値が一意であることを確認してください", "help": "アクティブな要素のIDは一意でなければなりません" }, "duplicate-id-aria": { - "description": "ARIAおよびラベルに使用されているすべてのid属性の値が一意であることを確認します", + "description": "ARIAおよびラベルに使用されているすべてのid属性の値が一意であることを確認してください", "help": "ARIAおよびラベルに使用されているIDは一意でなければなりません" }, "duplicate-id": { - "description": "すべてのid属性の値が一意であることを確認します", + "description": "すべてのid属性の値が一意であることを確認してください", "help": "id属性の値は一意でなければなりません" }, "empty-heading": { - "description": "見出しに認識可能なテキストが存在することを確認します", + "description": "見出しに認識可能なテキストが存在することを確認してください", "help": "見出しは空にしてはなりません" }, "empty-table-header": { - "description": "テーブルのヘッダーに認識可能なテキストが存在することを確認します", + "description": "テーブルのヘッダーに認識可能なテキストが存在することを確認してください", "help": "テーブルのヘッダーは空にしてはなりません" }, "focus-order-semantics": { - "description": "フォーカス順序に含まれる要素にインタラクティブコンテンツに適したロールがあることを確認します", + "description": "フォーカス順序に含まれる要素にインタラクティブコンテンツに適したロールがあることを確認してください", "help": "フォーカス順序に含まれる要素には、適切なロールがなければなりません" }, "form-field-multiple-labels": { - "description": "フォームフィールドに複数のlabel要素が存在しないことを確認します", - "help": "フォームフィールドに複数のlabel要素を付与してはなりりません" + "description": "フォームフィールドに複数のlabel要素が存在しないことを確認してください", + "help": "フォームフィールドに複数のlabel要素を付与してはなりません" }, "frame-focusable-content": { - "description": "フォーカス可能な<frame>と<iframe>要素に、tabindex=-1が指定されていないことを確認します", + "description": "フォーカス可能な<frame>と<iframe>要素に、tabindex=-1が指定されていないことを確認してください", "help": "フォーカス可能なコンテンツを含むフレームには、tabindex=-1が指定されていてはなりません" }, "frame-tested": { - "description": "<iframe>および<frame>要素にaxe-coreスクリプトが含まれていることを確認します", + "description": "<iframe>および<frame>要素にaxe-coreスクリプトが含まれていることを確認してください", "help": "フレームはaxe-coreでテストしなければなりません" }, "frame-title-unique": { - "description": "<iframe>および<frame>要素に一意のtitle属性が含まれていることを確認します", + "description": "<iframe>および<frame>要素に一意のtitle属性が含まれていることを確認してください", "help": "フレームには一意のtitle属性がなければなりません" }, "frame-title": { - "description": "<iframe>および<frame>要素にアクセシブルな名前が存在することを確認します", + "description": "<iframe>および<frame>要素にアクセシブルな名前が存在することを確認してください", "help": "フレームにはアクセシブルな名前がなければなりません" }, "heading-order": { - "description": "見出しの順序が意味的に正しいことを確認します", + "description": "見出しの順序が意味的に正しいことを確認してください", "help": "見出しのレベルは1つずつ増加させなければなりません" }, "hidden-content": { - "description": "隠れているコンテンツについてユーザーに通知します", + "description": "隠れているコンテンツについてユーザーに通知してください", "help": "ページ上の隠れているコンテンツは分析されなければなりません" }, "html-has-lang": { - "description": "すべてのHTMLドキュメントにlang属性が存在することを確認します", + "description": "すべてのHTMLドキュメントにlang属性が存在することを確認してください", "help": "<html>要素にはlang属性がなければなりません" }, "html-lang-valid": { - "description": "<html>要素のlang属性に有効な値があることを確認します", + "description": "<html>要素のlang属性に有効な値があることを確認してください", "help": "<html>要素のlang属性には有効な値がなければなりません" }, "html-xml-lang-mismatch": { - "description": "HTML要素に指定された有効なlangおよびxml:lang属性の両方がページの基本言語と一致することを確認します", + "description": "HTML要素に指定された有効なlangおよびxml:lang属性の両方がページの基本言語と一致することを確認してください", "help": "HTML要素に指定されたlangおよびxml:lang属性は同じ基本言語を持たなければなりません" }, "identical-links-same-purpose": { - "description": "同じアクセシブルな名前を持つ複数のリンクが類似した目的を果たすことを確認します", + "description": "同じアクセシブルな名前を持つ複数のリンクが類似した目的を果たすことを確認してください", "help": "同じ名前を持つ複数のリンクは類似した目的を持っていなければなりません" }, "image-alt": { - "description": "<img>要素に代替テキストが存在する、またはnoneまたはpresentationのロールが存在することを確認します", + "description": "<img>要素に代替テキストが存在する、またはnoneまたはpresentationのロールが存在することを確認してください", "help": "画像には代替テキストがなければなりません" }, "image-redundant-alt": { - "description": "画像の代替がテキストとして繰り返されていないことを確認します", + "description": "画像の代替がテキストとして繰り返されていないことを確認してください", "help": "画像の代替テキストはテキストとして繰り返されるべきではありません" }, "input-button-name": { - "description": "入力ボタンに認識可能なテキストが存在することを確認します", + "description": "入力ボタンに認識可能なテキストが存在することを確認してください", "help": "入力ボタンには認識可能なテキストが存在しなければなりません" }, "input-image-alt": { - "description": "<input type=\"image\">要素に代替テキストが存在することを確認します", + "description": "<input type=\"image\">要素に代替テキストが存在することを確認してください", "help": "画像ボタンには代替テキストがなければなりません" }, "label-content-name-mismatch": { - "description": "コンテンツによってラベル付けされた要素は、それらの視認できるテキストがアクセシブルな名前の一部になっていることを確認します", + "description": "コンテンツによってラベル付けされた要素は、それらの視認できるテキストがアクセシブルな名前の一部になっていることを確認してください", "help": "要素の視認できるテキストはそれらのアクセシブルな名前の一部でなければなりません" }, "label-title-only": { - "description": "すべてのフォーム要素に視認できるラベルがあり、非表示のラベル、titleまたはaria-describedby属性のみを使用してラベル付けされていないことを確認します", + "description": "すべてのフォーム要素に視認できるラベルがあり、非表示のラベル、titleまたはaria-describedby属性のみを使用してラベル付けされていないことを確認してください", "help": "フォーム要素には視認できるラベルがなければなりません" }, "label": { - "description": "すべてのフォーム要素にラベルが存在することを確認します", + "description": "すべてのフォーム要素にラベルが存在することを確認してください", "help": "フォーム要素にはラベルがなければなりません" }, "landmark-banner-is-top-level": { - "description": "bannerランドマークがトップレベルにあることを確認します", + "description": "bannerランドマークがトップレベルにあることを確認してください", "help": "bannerランドマークは他のランドマークに含まれるべきではありません" }, "landmark-complementary-is-top-level": { - "description": "complementaryランドマークあるいはasideがトップレベルにあることを確認します", + "description": "complementaryランドマークあるいはasideがトップレベルにあることを確認してください", "help": "asideは他の要素に含まれるべきではありません" }, "landmark-contentinfo-is-top-level": { - "description": "contentinfoランドマークがトップレベルにあることを確認します", + "description": "contentinfoランドマークがトップレベルにあることを確認してください", "help": "contentinfoランドマークは他のランドマークに含まれるべきではありません" }, "landmark-main-is-top-level": { - "description": "mainランドマークがトップレベルにあることを確認します", + "description": "mainランドマークがトップレベルにあることを確認してください", "help": "mainランドマークは他のランドマークに含まれるべきではありません" }, "landmark-no-duplicate-banner": { - "description": "ドキュメント内のbannerランドマークが最大で1つのみであることを確認します", + "description": "ドキュメント内のbannerランドマークが最大で1つのみであることを確認してください", "help": "ドキュメントに複数のbannerランドマークが存在してはなりません" }, "landmark-no-duplicate-contentinfo": { - "description": "ドキュメント内のcontentinfoランドマークが最大で1つのみであることを確認します", + "description": "ドキュメント内のcontentinfoランドマークが最大で1つのみであることを確認してください", "help": "ドキュメントに複数のcontentinfoランドマークが存在してはなりません" }, "landmark-no-duplicate-main": { - "description": "ドキュメント内のmainランドマークが最大で1つのみであることを確認します", + "description": "ドキュメント内のmainランドマークが最大で1つのみであることを確認してください", "help": "ドキュメントに複数のmainランドマークが存在してはなりません" }, "landmark-one-main": { - "description": "ドキュメントにmainランドマークが含まれていることを確認します", + "description": "ドキュメントにmainランドマークが含まれていることを確認してください", "help": "ドキュメントにはmainランドマークが1つ含まれていなければなりません" }, "landmark-unique": { - "help": "ランドマークが一意であることを確認します", - "description": "ランドマークには一意のロール又はロール/ラベル/タイトル (すなわちアクセシブルな名前) の組み合わせがなければなりません" + "description": "ランドマークが一意であることを確認してください", + "help": "ランドマークには一意のロール又はロール/ラベル/タイトル (すなわちアクセシブルな名前) の組み合わせがなければなりません" }, "link-in-text-block": { - "description": "リンクが色に依存しない形で周囲のテキストと区別できることを確認します", + "description": "リンクが色に依存しない形で周囲のテキストと区別できることを確認してください", "help": "リンクは色に依存しない形で区別できなければなりません" }, "link-name": { - "description": "リンクに認識可能なテキストが存在することを確認します", + "description": "リンクに認識可能なテキストが存在することを確認してください", "help": "リンクには認識可能なテキストがなければなりません" }, "list": { - "description": "リストが正しく構造化されていることを確認します", + "description": "リストが正しく構造化されていることを確認してください", "help": "<ul>および<ol>の直下には<li>、<script>または<template>要素のみを含まなければなりません" }, "listitem": { - "description": "<li>要素がセマンティックに使用されていることを確認します", + "description": "<li>要素がセマンティックに使用されていることを確認してください", "help": "<li>要素は<ul>または<ol>内に含まれていなければなりません" }, "marquee": { - "description": "<marquee>要素が使用されていないことを確認します", + "description": "<marquee>要素が使用されていないことを確認してください", "help": "<marquee>要素は非推奨のため、使用してはなりません" }, "meta-refresh-no-exceptions": { - "description": "一定時間経過後のページの自動リロードのために<meta http-equiv=\"refresh\">が使用されていないことを確認します", + "description": "一定時間経過後のページの自動リロードのために<meta http-equiv=\"refresh\">が使用されていないことを確認してください", "help": "一定時間経過後のページの自動リロードを使用してはなりません" }, "meta-refresh": { - "description": "一定時間経過後のページの自動リロードのために<meta http-equiv=\"refresh\">が使用されていないことを確認します", + "description": "一定時間経過後のページの自動リロードのために<meta http-equiv=\"refresh\">が使用されていないことを確認してください", "help": "20時間より短い時間経過後のページの自動リロードを使用してはなりません" }, "meta-viewport-large": { - "description": "<meta name=\"viewport\">で大幅に拡大縮小できることを確認します", + "description": "<meta name=\"viewport\">で大幅に拡大縮小できることを確認してください", "help": "ユーザーがズームをしてテキストを最大500%まで拡大できなければなりません" }, "meta-viewport": { - "description": "<meta name=\"viewport\">がテキストのサイズ変更やズームを無効化しないことを確認します", + "description": "<meta name=\"viewport\">がテキストのサイズ変更やズームを無効化しないことを確認してください", "help": "ズーム機能やテキストのサイズ変更は無効にしてはなりません" }, "nested-interactive": { - "description": "スクリーン・リーダーで必ずしもよみあげられなかったり支援技術のフォーカスに関する問題を引き起こす可能性があったりするため、対話的なコントロールがネストされていないことを確認します", + "description": "スクリーン・リーダーで必ずしもよみあげられなかったり支援技術のフォーカスに関する問題を引き起こす可能性があったりするため、対話的なコントロールがネストされていないことを確認してください", "help": "対話的なコントロールはネストされていてはなりません" }, "no-autoplay-audio": { - "description": "<video> または <audio> 要素が音声を停止またはミュートするコントロールなしに音声を3秒より長く自動再生しないことを確認します", + "description": "<video> または <audio> 要素が音声を停止またはミュートするコントロールなしに音声を3秒より長く自動再生しないことを確認してください", "help": "<video> または <audio> 要素は音声を自動再生してはなりません" }, "object-alt": { - "description": "<object>要素に代替テキストが存在することを確認します", + "description": "<object>要素に代替テキストが存在することを確認してください", "help": "<object>要素には代替テキストがなければなりません" }, "p-as-heading": { - "description": "<p>要素を見出しとしてスタイル付けするために太字、イタリック体、およびフォントサイズが使用されていないことを確認します", + "description": "<p>要素を見出しとしてスタイル付けするために太字、イタリック体、およびフォントサイズが使用されていないことを確認してください", "help": "スタイル付けした<p>要素を見出しとして使用してはなりません" }, "page-has-heading-one": { - "description": "ページ、またはそのページ中のフレームの少なくとも1つにはレベル1の見出しが含まれていることを確認します", + "description": "ページ、またはそのページ中のフレームの少なくとも1つにはレベル1の見出しが含まれていることを確認してください", "help": "ページにはレベル1の見出しが含まれていなければなりません" }, "presentation-role-conflict": { - "description": "すべてのスクリーン・リーダーに確実に無視させるために、プレゼンテーション目的とされている要素にはグローバルなARIAまたはtabindexが指定されていてはなりません", - "help": "プレゼンテーション目的とされている要素が一貫して無視されることを確認します" + "description": "プレゼンテーション目的とされている要素には、グローバルなARIAまたはtabindexが指定されておらず、すべてのスクリーン・リーダーが無視するようになっていることを確認してください", + "help": "プレゼンテーション目的とされている要素は一貫して無視されなければなりません" }, "region": { - "description": "ページのすべてのコンテンツがlandmarkに含まれていることを確認します", + "description": "ページのすべてのコンテンツがlandmarkに含まれていることを確認してください", "help": "ページのすべてのコンテンツはlandmarkに含まれていなければなりません" }, "role-img-alt": { - "description": "[role=\"img\"] の要素に代替テキストが存在することを確認します", + "description": "[role=\"img\"] の要素に代替テキストが存在することを確認してください", "help": "[role=\"img\"] の要素には代替テキストがなければなりません" }, "scope-attr-valid": { - "description": "scope属性がテーブルで正しく使用されていることを確認します", + "description": "scope属性がテーブルで正しく使用されていることを確認してください", "help": "scope属性は正しく使用されなければなりません" }, "scrollable-region-focusable": { - "description": "スクロール可能なコンテンツを持つ要素がキーボードでアクセスできることを確認します", + "description": "スクロール可能なコンテンツを持つ要素がキーボードでアクセスできることを確認してください", "help": "スクロール可能な領域はキーボードでアクセスできなければなりません" }, "select-name": { - "description": "select要素にはアクセシブルな名前があることを確認します", + "description": "select要素にはアクセシブルな名前があることを確認してください", "help": "select要素にはアクセシブルな名前がなければなりません" }, "server-side-image-map": { - "description": "サーバーサイドのイメージマップが使用されていないことを確認します", + "description": "サーバーサイドのイメージマップが使用されていないことを確認してください", "help": "サーバーサイドのイメージマップを使用してはなりません" }, "skip-link": { - "description": "すべてのスキップリンクにフォーカス可能なターゲットがあることを確認します", + "description": "すべてのスキップリンクにフォーカス可能なターゲットがあることを確認してください", "help": "スキップリンクのターゲットが存在し、フォーカス可能でなければなりません" }, + "summary-name": { + "description": "summary要素に認識可能なテキストが存在することを確認してください", + "help": "summary要素には認識可能なテキストがなければなりません" + }, "svg-img-alt": { - "description": "img、graphics-documentまたはgraphics-symbolロールを持つsvg要素にアクセシブルなテキストがあることを確認します", + "description": "img、graphics-documentまたはgraphics-symbolロールを持つsvg要素にアクセシブルなテキストがあることを確認してください", "help": "imgロールを持つ<svg>要素には代替テキストが存在しなければなりません" }, "tabindex": { - "description": "tabindex属性値が0より大きくないことを確認します", + "description": "tabindex属性値が0より大きくないことを確認してください", "help": "要素に指定するtabindexは0より大きい値であってはなりません" }, "table-duplicate-name": { - "description": "<caption>要素の内用がsummary属性のテキストと同一ではないことを確認します", + "description": "<caption>要素の内容がsummary属性のテキストと同一ではないことを確認してください", "help": "テーブルのキャプションとサマリーは同一であってはなりません" }, "table-fake-caption": { - "description": "キャプション付きのテーブルが<caption>要素を用いていることを確認します", + "description": "キャプション付きのテーブルが<caption>要素を用いていることを確認してください", "help": "データテーブルにキャプションをつけるためにデータまたはヘッダーセルを用いてはなりません" }, "target-size": { - "description": "タッチターゲットのサイズとスペースが十分にあることを確認します", + "description": "タッチターゲットのサイズとスペースが十分にあることを確認してください", "help": "すべてのタッチターゲットは24pxの大きさか、十分なスペースがなければなりません" }, "td-has-header": { - "description": "3×3より大きい<table>の空ではないデータセルにはそれぞれ1つ以上のテーブルヘッダーが存在することを確認します", + "description": "3×3より大きい<table>の空ではないデータセルにはそれぞれ1つ以上のテーブルヘッダーが存在することを確認してください", "help": "大きい<table>の空ではない<td>要素は対応するテーブルヘッダーと関連づけられていなければなりません" }, "td-headers-attr": { - "description": "テーブルでheaders属性を使用している各セルの参照先が同じテーブル内の他のセルであることを確認します", - "help": "テーブルのheaders属性を使用するすべてのセルは同じ表内の他のセルのみを参照しなければなりません" + "description": "テーブルでheaders属性を使用している各セルの参照先が、同じテーブル内の他の<th>要素であることを確認してください", + "help": "テーブルのheaders属性を使用するすべてのセルは、同じ表内の他の<th>要素を参照しなければなりません" }, "th-has-data-cells": { - "description": "すべての<th>要素およびrole=columnheader/rowheaderを持つ要素にはそれらが説明するデータセルがあることを確認します", + "description": "すべての<th>要素およびrole=columnheader/rowheaderを持つ要素にはそれらが説明するデータセルがあることを確認してください", "help": "データテーブルのテーブルヘッダーはデータセルを参照していなければなりません" }, "valid-lang": { - "description": "lang属性に有効な値が存在することを確認します", + "description": "lang属性に有効な値が存在することを確認してください", "help": "lang属性には有効な値がなければなりません" }, "video-caption": { - "description": "<video>要素にキャプションが存在することを確認します", + "description": "<video>要素にキャプションが存在することを確認してください", "help": "<video>要素にはキャプションがなければなりません" } }, @@ -498,7 +502,8 @@ }, "aria-required-children": { "pass": { - "default": "必須のARIA子ロールが存在します" + "default": "必須のARIA子ロールが存在します", + "aria-busy": "要素にはaria-busy属性が指定されているため、必要な子要素を省略することが許可されています" }, "fail": { "singular": "必須のARIA子ロールが提供されていません: ${data.values}", @@ -537,7 +542,8 @@ "noIdShadow": "ARIA属性で指定されている要素のIDがページ上に存在しないか、別のshadow DOMツリーの小要素です: ${data.needsReview}", "ariaCurrent": "ARIA属性値が無効であるため、\"aria-current=true\"として扱われます: ${data.needsReview}", "idrefs": "ARIA属性で指定されている要素のIDがページ上に存在するかどうか判定できません: ${data.needsReview}", - "empty": "ARIA属性値が空のときは無視されます: ${data.needsReview}" + "empty": "ARIA属性値が空のときは無視されます: ${data.needsReview}", + "controlsWithinPopup": "aria-haspopupを使用している際にaria-controlsが参照するIDがページ上に存在するかどうかを判断できません: ${data.needsReview}" } }, "aria-valid-attr": { @@ -681,7 +687,8 @@ }, "autocomplete-valid": { "pass": "autocomplete属性は正しくフォーマットされています", - "fail": "autocomplete属性は誤ってフォーマットされています" + "fail": "autocomplete属性は誤ってフォーマットされています", + "incomplete": "autocomplete属性に、標準的ではない値が指定されています。代わりに指定できる標準的な値がないか確認してください。" }, "accesskeys": { "pass": "accesskey属性の値は一意です", @@ -764,8 +771,8 @@ "fail": "要素が既存のテキストと重複した代替テキストの存在する<img>要素を含んでいます" }, "explicit-label": { - "pass": "フォームの要素に明示的な<label>が存在します", - "fail": "フォームの要素に明示的な<label>が存在しません", + "pass": "要素に明示的な<label>が存在します", + "fail": "要素に明示的な<label>が存在しません", "incomplete": "フォームの要素に明示的な <label> があるか判定できませんでした" }, "help-same-as-label": { @@ -778,8 +785,8 @@ "incomplete": "フォームの要素に明示的で非表示の <label> があるか判定できませんでした" }, "implicit-label": { - "pass": "フォームの要素に暗黙の(包含された)<label>が存在します", - "fail": "フォームの要素に暗黙の(包含された)<label>が存在しません", + "pass": "要素に暗黙の(包含された)<label>が存在します", + "fail": "要素に暗黙の(包含された)<label>が存在しません", "incomplete": "フォームの要素に暗黙の(包含された)<label>が存在するか判定できません" }, "label-content-name-mismatch": { @@ -821,7 +828,7 @@ "pass": "リスト項目に<ul>、<ol>、またはrole=\"list\"の親要素が存在します", "fail": { "default": "リスト項目に <ul>、<ol> 親要素が存在しません", - "roleNotValid": "リスト項目にroleが指定されていない<ul>や<ol>親要素、またはrole=\"list\"の親要素が存在しません" + "roleNotValid": "リスト項目の親要素に、role=\"list\"以外のロールが指定されています" } }, "only-dlitems": { @@ -846,7 +853,7 @@ "incomplete": "iframeはまだaxe-coreでテストする必要があります" }, "no-autoplay-audio": { - "pass": "<video> または <audio> は許可された時間より長く音声を出力しない、もしくはコントールするメカニズムを持っています", + "pass": "<video> または <audio> は許可された時間より長く音声を出力しない、もしくはコントロールするメカニズムを持っています", "fail": "<video> または <audio> は許可された時間より長く音声を出力し、かつコントロールするメカニズムを持っていません", "incomplete": "<video> または <audio> が許可された時間より長く音声を出力しない、またはコントロールするメカニズムを提供していることを確認しましょう" }, @@ -864,17 +871,22 @@ "fail": "<meta>タグの${data}がモバイルデバイスでの拡大を無効にします" }, "target-offset": { - "pass": "ターゲットに最も近い隣接要素との間の空白の大きさは十分です。クリッカブルな領域として十分な大きさは、直径${data.minOffset}pxで、${data.minOffset}px以上です。", + "pass": { + "default": "ターゲットは最も近い隣接する要素との間に充分な大きさの空白があります。クリッカブルな領域として十分な大きさは、${data.minOffset}px以上で直径${data.closestOffset}pxです。", + "large": "ターゲットの大きさは、最低${data.minOffset}pxの基準を大きく上回っています。" + }, "fail": "ターゲットに最も近い隣接要素との間の空白の大きさが不十分です。クリッカブルな領域として十分な大きさは、${data.minOffset}px以上ではなく、直径${data.closestOffset}pxです。", "incomplete": { "default": "tabindexが負の要素において、最も近い隣接要素との間の空白の大きさが不十分です。クリッカブルな領域として十分な大きさは、${data.minOffset}px以上ではなく、直径${data.closestOffset}pxです。これがターゲットであるか確認しましょう。", - "nonTabbableNeighbor": "ターゲットに最も近い隣接要素との間の空白の大きさが不十分です。クリッカブルな領域として十分な大きさは、${data.minOffset}px以上ではなく、直径${data.closestOffset}pxです。隣接要素がターゲットであるか確認しましょう。" + "nonTabbableNeighbor": "ターゲットに最も近い隣接要素との間の空白の大きさが不十分です。クリッカブルな領域として十分な大きさは、${data.minOffset}px以上ではなく、直径${data.closestOffset}pxです。隣接要素がターゲットであるか確認しましょう。", + "tooManyRects": "重複する要素が多すぎるため、ターゲットの大きさを取得できません。" } }, "target-size": { "pass": { "default": "コントロールには十分なサイズがあります (${data.width}px x ${data.height}pxであり、${data.minSize}px x ${data.minSize}px以上です)", - "obscured": "コントロールは完全に隠されていてクリックできないため無視されます" + "obscured": "コントロールは完全に隠されていてクリックできないため無視されます", + "large": "ターゲットの大きさは、最低${data.minSize}pxの基準を大きく上回っています。" }, "fail": { "default": "ターゲットのサイズが不十分です (${data.width}px x ${data.height}pxですが、${data.minSize}px x ${data.minSize}px以上でなければなりません)", @@ -884,7 +896,8 @@ "default": "tabindexが負の要素のサイズが不十分です (${data.width}px x ${data.height}pxですが、${data.minSize}px x ${data.minSize}px以上でなければなりません)。これがターゲットであるか確認しましょう", "contentOverflow": "コンテンツがオーバーフローしたため、要素のサイズを正確に決定できませんでした", "partiallyObscured": "tabindexが負の要素は、部分的に隠れているためサイズが不十分です (最小のスペースは${data.width}px x ${data.height}pxですが、${data.minSize}px x ${data.minSize}px以上でなければなりません)。これがターゲットであるか確認しましょう", - "partiallyObscuredNonTabbable": "ターゲットのサイズが不十分です。これはtabindexが負の隣接オブジェクトによって部分的に隠されているためです (最小のスペースは${data.width}px x ${data.height}pxですが、${data.minSize}px x ${data.minSize}px以上でなければなりません)。隣接要素がターゲットであるか確認しましょう" + "partiallyObscuredNonTabbable": "ターゲットのサイズが不十分です。これはtabindexが負の隣接オブジェクトによって部分的に隠されているためです (最小のスペースは${data.width}px x ${data.height}pxですが、${data.minSize}px x ${data.minSize}px以上でなければなりません)。隣接要素がターゲットであるか確認しましょう", + "tooManyRects": "重複する要素が多すぎるため、ターゲットの大きさを取得できません。" } }, "header-present": { @@ -1041,7 +1054,7 @@ "default": "要素のデフォルトのセマンティクスはrole=\"none\"またはrole=\"presentation\"で上書きされませんでした", "globalAria": "要素にはグローバルなARIA属性が指定されているため、role=\"none\"またはrole=\"presentation\"にはなりません", "focusable": "要素がフォーカス可能なため、role=\"none\"またはrole=\"presentation\"にはなりません", - "both": "要素にはグローバナルARIA属性が指定されており、フォーカス可能なため、role=\"none\"またはrole=\"presentation\"にはなりません", + "both": "要素にはグローバルなARIA属性が指定されており、フォーカス可能なため、role=\"none\"またはrole=\"presentation\"にはなりません", "iframe": "プレゼンテーション用のロールを指定した${data.nodeName}要素に'title'属性を使用すると、スクリーンリーダー間で動作が一貫しません" } }, @@ -1083,9 +1096,13 @@ "fail": "いくつかの空ではないデータセルにテーブルヘッダーが存在しません" }, "td-headers-attr": { - "pass": "headers属性はテーブル内の他のセルを参照するためだけに使用されています", + "pass": "headers属性はテーブル内の他のヘッダーセルを参照するためだけに使用されています", "incomplete": "headers属性が空です", - "fail": "headers属性がテーブル内の他のセルを参照するためだけに使用されていません" + "fail": { + "cell-header-not-in-table": "headers属性がテーブル内の他のヘッダーセルのみを参照するために使用されていません", + "cell-header-not-th": "headers属性はデータセルではなく、ヘッダーセルを参照しなければなりません", + "header-refs-self": "headers属性を持つ要素が自分自身を参照しています" + } }, "th-has-data-cells": { "pass": "すべてのテーブルヘッダーセルがデータセルを参照しています", diff --git a/locales/ko.json b/locales/ko.json index 9c304d1d7..52cad43ad 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -166,7 +166,7 @@ "help": "form 필드는 반드시 여러 개의 레이블 엘리먼트를 가지지 않아야 합니다." }, "frame-focusable-content": { - "description": "초점을 얻을 수 있는(focusable) 콘텐츠를 가진 <frame>과 <iframe> 엘리먼트에 tabindex=-1이 없게 하세요", + "description": "초점을 얻을 수 있는(focusable) 콘텐츠를 가진 <frame>과 <iframe> 엘리먼트에 tabindex=-1이 없게 하세요.", "help": "초점을 얻을 수 있는(focusable) 콘텐츠를 가진 프레임에는 반드시 tabindex=-1 이 없어야 합니다." }, "frame-tested": { @@ -262,7 +262,7 @@ "help": "문서는 하나를 초과하는 main 랜드마크를 가지지 않아야 합니다." }, "landmark-one-main": { - "description": "문서가 main 랜드마크를 가지고 있는지 확인하세요,", + "description": "문서가 main 랜드마크를 가지고 있는지 확인하세요.", "help": "문서는 하나의 main 랜드마크를 가져야 합니다." }, "landmark-unique": { @@ -610,7 +610,7 @@ } }, "autocomplete-appropriate": { - "pass": "autocomplete 값이 적절한 엘리먼트에 있습니다", + "pass": "autocomplete 값이 적절한 엘리먼트에 있습니다.", "fail": "autocomplete 값은 이 유형의 입력에는 적절하지 않습니다." }, "autocomplete-valid": { @@ -635,7 +635,7 @@ }, "focusable-modal-open": { "pass": "modal이 열려 있는 동안 초점을 얻을 수 있는(focusable) 엘리먼트가 없습니다.", - "incomplete": "현재 상태에서 초점을 얻을 수 있는(focusable) 엘리먼트가 키보드로 초점을 얻을 수(tabbable) 없는지 확인하세요" + "incomplete": "현재 상태에서 초점을 얻을 수 있는(focusable) 엘리먼트가 키보드로 초점을 얻을 수(tabbable) 없는지 확인하세요." }, "focusable-no-name": { "pass": "엘리먼트가 탭 순서(tab order)에 없거나 접근 가능한 텍스트를 가지고 있습니다.", diff --git a/locales/pt_PT.json b/locales/pt_PT.json new file mode 100644 index 000000000..47ee235c2 --- /dev/null +++ b/locales/pt_PT.json @@ -0,0 +1,1123 @@ +{ + "lang": "pt_PT", + "rules": { + "accesskeys": { + "description": "Garantir que cada valor do atributo 'accesskey' seja único", + "help": "O valor do atributo 'accesskey' deve ser único" + }, + "area-alt": { + "description": "Garantir que os elementos <area> dos mapas de imagem tenham texto alternativo", + "help": "Os elementos <area> ativos devem ter texto alternativo" + }, + "aria-allowed-attr": { + "description": "Garantir que a função de um elemento suporte os seus atributos ARIA", + "help": "Os elementos devem usar apenas atributos ARIA suportados" + }, + "aria-allowed-role": { + "description": "Garantir que o atributo 'role' tenha um valor apropriado para o elemento", + "help": "A 'role' ARIA deve ser apropriada para o elemento" + }, + "aria-braille-equivalent": { + "description": "Garantir que 'aria-braillelabel' e 'aria-brailleroledescription' tenham um equivalente não braile", + "help": "Os atributos 'aria-braille' devem ter um equivalente não braile" + }, + "aria-command-name": { + "description": "Garantir que cada botão, link e item de menu ARIA tenha um nome acessível", + "help": "Os comandos ARIA devem ter um nome acessível" + }, + "aria-conditional-attr": { + "description": "Garantir que os atributos ARIA sejam usados conforme descrito na especificação da função do elemento", + "help": "Os atributos ARIA devem ser usados conforme especificado para a função do elemento" + }, + "aria-deprecated-role": { + "description": "Garantir que os elementos não usem funções obsoletas", + "help": "Não se devem usar funções ARIA obsoletas" + }, + "aria-dialog-name": { + "description": "Garantir que cada diálogo e diálogo de alerta ARIA tenha um nome acessível", + "help": "Os nós de diálogo e diálogo de alerta ARIA devem ter um nome acessível" + }, + "aria-hidden-body": { + "description": "Garantir que 'aria-hidden=\"true\"' não esteja presente no corpo do documento.", + "help": "'aria-hidden=\"true\"' não deve estar presente no corpo do documento" + }, + "aria-hidden-focus": { + "description": "Garantir que elementos com 'aria-hidden' não sejam focáveis nem contenham elementos focáveis", + "help": "Um elemento oculto por ARIA não deve ser focável nem conter elementos focáveis" + }, + "aria-input-field-name": { + "description": "Garantir que cada campo de entrada ARIA tenha um nome acessível", + "help": "Os campos de entrada ARIA devem ter um nome acessível" + }, + "aria-meter-name": { + "description": "Garantir que cada nó de medidor ARIA tenha um nome acessível", + "help": "Os nós de medidor ARIA devem ter um nome acessível" + }, + "aria-progressbar-name": { + "description": "Garantir que cada nó de barra de progresso ARIA tenha um nome acessível", + "help": "Os nós de barra de progresso ARIA devem ter um nome acessível" + }, + "aria-prohibited-attr": { + "description": "Garantir que os atributos ARIA não sejam proibidos para a função de um elemento", + "help": "Os elementos devem usar apenas atributos ARIA permitidos" + }, + "aria-required-attr": { + "description": "Garantir que os elementos com funções ARIA tenham todos os atributos ARIA obrigatórios", + "help": "Devem ser fornecidos os atributos ARIA obrigatórios" + }, + "aria-required-children": { + "description": "Garantir que os elementos com uma função ARIA que requer funções filhas as contenham", + "help": "Certas funções ARIA devem conter determinados elementos filhos" + }, + "aria-required-parent": { + "description": "Garantir que os elementos com uma função ARIA que requer funções parentais estejam contidos por estes", + "help": "Certas funções ARIA devem estar contidas em pais específicos" + }, + "aria-roledescription": { + "description": "Garantir que 'aria-roledescription' seja usado apenas em elementos com uma função implícita ou explícita", + "help": "'aria-roledescription' deve estar em elementos com uma função semântica" + }, + "aria-roles": { + "description": "Garantir que todos os elementos com o atributo 'role' usem um valor válido", + "help": "As funções 'roles' ARIA utilizadas devem corresponder a valores válidos" + }, + "aria-text": { + "description": "Garantir que 'role=\"text\"' seja usado em elementos sem descendentes focáveis", + "help": "'\"role=text\"' não deve ter descendentes focáveis" + }, + "aria-toggle-field-name": { + "description": "Garantir que cada campo de alternância ARIA tenha um nome acessível", + "help": "Os campos de alternância ARIA devem ter um nome acessível" + }, + "aria-tooltip-name": { + "description": "Garantir que cada nó de 'tooltip' ARIA tenha um nome acessível", + "help": "Os nós de 'tooltip' ARIA devem ter um nome acessível" + }, + "aria-treeitem-name": { + "description": "Garantir que cada nó de 'treeitem' ARIA tenha um nome acessível", + "help": "Os nós de 'treeitem' ARIA devem ter um nome acessível" + }, + "aria-valid-attr-value": { + "description": "Garantir que todos os atributos ARIA tenham valores válidos", + "help": "Os atributos ARIA devem corresponder a valores válidos" + }, + "aria-valid-attr": { + "description": "Garantir que os atributos que começam com 'aria-' sejam atributos ARIA válidos", + "help": "Os atributos ARIA devem corresponder a nomes válidos" + }, + "audio-caption": { + "description": "Garantir que os elementos <audio> tenham legendas", + "help": "Os elementos <audio> devem ter uma pista de legendas" + }, + "autocomplete-valid": { + "description": "Garantir que o atributo 'autocomplete' esteja correto e seja adequado para o campo de formulário", + "help": "O atributo 'autocomplete' deve ser utilizado corretamente" + }, + "avoid-inline-spacing": { + "description": "Garantir que o espaçamento do texto definido através de atributos de estilo possa ser ajustado com folhas de estilo personalizadas", + "help": "O espaçamento do texto 'inline' deve ser ajustável com folhas de estilo personalizadas" + }, + "blink": { + "description": "Garantir que os elementos <blink> não sejam usados", + "help": "Os elementos <blink> estão obsoletos e não devem ser usados" + }, + "button-name": { + "description": "Garantir que os botões tenham texto discernível", + "help": "Os botões devem ter texto discernível" + }, + "bypass": { + "description": "Garantir que cada página tenha pelo menos um mecanismo para o utilizador contornar a navegação e saltar diretamente para o conteúdo", + "help": "A página deve ter meios para contornar blocos repetitivos" + }, + "color-contrast-enhanced": { + "description": "Garantir que o contraste entre as cores de primeiro plano e de fundo cumpra os limites de razão de contraste aprimorada, WCAG 2 AAA", + "help": "Os elementos devem cumprir os limites de razão de contraste aprimorada" + }, + "color-contrast": { + "description": "Garantir que o contraste entre as cores de primeiro plano e de fundo cumpra os limites mínimos de razão de contraste, WCAG 2 AA", + "help": "Os elementos devem cumprir os limites mínimos de razão de contraste" + }, + "css-orientation-lock": { + "description": "Garantir que o conteúdo não esteja bloqueado a uma orientação de ecrã específica, e que seja operativo em todas as orientações de ecrã", + "help": "As media queries CSS não devem bloquear a orientação do ecrã" + }, + "definition-list": { + "description": "Garantir que os elementos <dl> estejam estruturados corretamente", + "help": "Os elementos <dl> devem conter apenas grupos de <dt> e <dd> ordenados corretamente, ou elementos <script>, <template> ou <div>" + }, + "dlitem": { + "description": "Garantir que os elementos <dt> e <dd> estejam contidos num <dl>", + "help": "Os elementos <dt> e <dd> devem estar contidos num <dl>" + }, + "document-title": { + "description": "Garantir que cada documento HTML contenha um elemento <title> não vazio", + "help": "Os documentos devem ter um elemento <title> para ajudar na navegação" + }, + "duplicate-id-active": { + "description": "Garantir que cada valor do atributo 'id' dos elementos ativos seja único", + "help": "Os IDs dos elementos ativos devem ser únicos" + }, + "duplicate-id-aria": { + "description": "Garantir que cada valor do atributo 'id' utilizado em ARIA e em etiquetas seja único", + "help": "Os IDs usados em ARIA e etiquetas devem ser únicos" + }, + "duplicate-id": { + "description": "Garantir que cada valor do atributo 'id' seja único", + "help": "O valor do atributo 'id' deve ser único" + }, + "empty-heading": { + "description": "Garantir que os cabeçalhos tenham texto discernível", + "help": "Os cabeçalhos não devem estar vazios" + }, + "empty-table-header": { + "description": "Garantir que os cabeçalhos de tabelas tenham texto discernível", + "help": "O texto dos cabeçalhos de tabela não deve estar vazio" + }, + "focus-order-semantics": { + "description": "Garantir que os elementos na ordem de foco tenham uma função apropriada para conteúdo interativo", + "help": "Os elementos na ordem de foco devem ter uma função apropriada" + }, + "form-field-multiple-labels": { + "description": "Garantir que o campo de formulário não possua múltiplos elementos 'label'", + "help": "O campo de formulário não deve ter múltiplos elementos 'label'" + }, + "frame-focusable-content": { + "description": "Garantir que os elementos <frame> e <iframe> com conteúdo focável não tenham tabindex=-1", + "help": "Os frames com conteúdo focável não devem ter tabindex=-1" + }, + "frame-tested": { + "description": "Garantir que os elementos <iframe> e <frame> contenham o script axe-core", + "help": "Os frames devem ser testados com axe-core" + }, + "frame-title-unique": { + "description": "Garantir que os elementos <iframe> e <frame> contenham um atributo 'title' único", + "help": "Os frames devem ter um atributo 'title' único" + }, + "frame-title": { + "description": "Garantir que os elementos <iframe> e <frame> tenham um atributo 'title' acessível", + "help": "Os frames devem ter um atributo 'title' acessível" + }, + "heading-order": { + "description": "Garantir que a ordem dos cabeçalhos seja semanticamente correta", + "help": "Os níveis de cabeçalho devem aumentar apenas de um em um" + }, + "hidden-content": { + "description": "Informa os utilizadores sobre conteúdo oculto.", + "help": "O conteúdo oculto na página deve ser analisado" + }, + "html-has-lang": { + "description": "Garantir que cada documento HTML tenha um atributo 'lang'", + "help": "O elemento <html> deve ter um atributo 'lang'" + }, + "html-lang-valid": { + "description": "Garantir que o atributo 'lang' do elemento <html> tenha um valor válido", + "help": "O elemento <html> deve ter um valor válido para o atributo 'lang'" + }, + "html-xml-lang-mismatch": { + "description": "Garantir que os elementos HTML com atributos 'lang' e 'xml:lang' válidos concordem na língua base da página", + "help": "Os elementos HTML com 'lang' e 'xml:lang' devem ter a mesma língua base" + }, + "identical-links-same-purpose": { + "description": "Garantir que links com o mesmo nome acessível tenham um propósito semelhante", + "help": "Links com o mesmo nome devem ter um propósito semelhante" + }, + "image-alt": { + "description": "Garantir que os elementos <img> tenham texto alternativo ou um 'role' igual a 'none' ou 'presentation'", + "help": "As imagens devem ter texto alternativo" + }, + "image-redundant-alt": { + "description": "Garantir que o texto alternativo da imagem não seja repetido como texto", + "help": "O texto alternativo das imagens não deve ser repetido como texto" + }, + "input-button-name": { + "description": "Garantir que os botões de 'input' tenham texto discernível", + "help": "Os botões de 'input' devem ter texto discernível" + }, + "input-image-alt": { + "description": "Garantir que os elementos <input type=\"image\"> tenham texto alternativo", + "help": "Os botões de imagem devem ter texto alternativo" + }, + "label-content-name-mismatch": { + "description": "Garantir que os elementos etiquetados através do seu conteúdo incluam o texto visível como parte do seu nome acessível", + "help": "Os elementos devem incluir o seu texto visível como parte do nome acessível" + }, + "label-title-only": { + "description": "Garantir que cada elemento de formulário tenha uma etiqueta visível e não seja etiquetado apenas através de etiquetas ocultas, ou dos atributos 'title' ou 'aria-describedby'", + "help": "Os elementos de formulário devem ter uma etiqueta visível" + }, + "label": { + "description": "Garantir que cada elemento de formulário tenha uma etiqueta", + "help": "Os elementos de formulário devem ter etiquetas" + }, + "landmark-banner-is-top-level": { + "description": "Garantir que o marco de 'banner' esteja no nível principal", + "help": "O marco de 'banner' não deve estar contido noutro marco" + }, + "landmark-complementary-is-top-level": { + "description": "Garantir que o marco 'complementary' ou 'aside' estejam no nível principal", + "help": "O 'aside' não deve estar contido noutro marco" + }, + "landmark-contentinfo-is-top-level": { + "description": "Garantir que o marco 'contentinfo' esteja no nível principal", + "help": "O marco 'contentinfo' não deve estar contido noutro marco" + }, + "landmark-main-is-top-level": { + "description": "Garantir que o marco 'main' esteja no nível principal", + "help": "O marco 'main' não deve estar contido noutro marco" + }, + "landmark-no-duplicate-banner": { + "description": "Garantir que o documento tenha, no máximo, um marco de 'banner'", + "help": "O documento não deve ter mais do que um marco de 'banner'" + }, + "landmark-no-duplicate-contentinfo": { + "description": "Garantir que o documento tenha, no máximo, um marco 'contentinfo'", + "help": "O documento não deve ter mais do que um marco 'contentinfo'" + }, + "landmark-no-duplicate-main": { + "description": "Garantir que o documento tenha, no máximo, um marco 'main'", + "help": "O documento não deve ter mais do que um marco 'main'" + }, + "landmark-one-main": { + "description": "Garantir que o documento tenha um marco 'main'", + "help": "O documento deve ter um marco 'main'" + }, + "landmark-unique": { + "description": "Garantir que os marcos sejam únicos", + "help": "Os marcos devem ter uma combinação única de 'role' ou 'role'/'label'/'title' (ou seja, nome acessível)" + }, + "link-in-text-block": { + "description": "Garantir que os links se distingam do texto circundante de forma que não dependa da cor", + "help": "Os links devem ser distinguíveis sem depender da cor" + }, + "link-name": { + "description": "Garantir que os links tenham texto discernível", + "help": "Os links devem ter texto discernível" + }, + "list": { + "description": "Garantir que as listas estejam estruturadas corretamente", + "help": "Os elementos <ul> e <ol> devem conter diretamente apenas elementos <li>, <script> ou <template>" + }, + "listitem": { + "description": "Garantir que os elementos <li> sejam usados de forma semântica", + "help": "Os elementos <li> devem estar contidos num <ul> ou <ol>" + }, + "marquee": { + "description": "Garantir que os elementos <marquee> não sejam usados", + "help": "Os elementos <marquee> estão obsoletos e não devem ser usados" + }, + "meta-refresh-no-exceptions": { + "description": "Garantir que <meta http-equiv=\"refresh\"> não seja usado para atualização com atraso", + "help": "Não se deve usar atualização com atraso" + }, + "meta-refresh": { + "description": "Garantir que <meta http-equiv=\"refresh\"> não seja usado para atualização com atraso", + "help": "Não se deve usar atualização com atraso inferior a 20 horas" + }, + "meta-viewport-large": { + "description": "Garantir que <meta name=\"viewport\"> permita uma ampliação significativa", + "help": "Os utilizadores devem ser capazes de ampliar e escalar o texto até 500%" + }, + "meta-viewport": { + "description": "Garantir que <meta name=\"viewport\"> não desative a escalabilidade e ampliação do texto", + "help": "A ampliação e escalabilidade não devem ser desativadas" + }, + "nested-interactive": { + "description": "Garantir que os controles interativos não estejam aninhados, pois nem sempre são anunciados pelos leitores de ecrã ou podem causar problemas de foco para tecnologias assistivas", + "help": "Os controles interativos não devem estar aninhados" + }, + "no-autoplay-audio": { + "description": "Garantir que os elementos <video> ou <audio> não reproduzam áudio automaticamente por mais de 3 segundos sem um mecanismo de controlo para parar ou silenciar o áudio", + "help": "Os elementos <video> ou <audio> não devem reproduzir automaticamente" + }, + "object-alt": { + "description": "Garantir que os elementos <object> tenham texto alternativo", + "help": "Os elementos <object> devem ter texto alternativo" + }, + "p-as-heading": { + "description": "Garantir que texto em negrito, itálico e tamanho de fonte não sejam usados para estilizar elementos <p> como cabeçalhos", + "help": "Os elementos <p> estilizados não devem ser usados como cabeçalhos" + }, + "page-has-heading-one": { + "description": "Garantir que a página, ou pelo menos um dos seus 'frames', contenha um cabeçalho de nível 1", + "help": "A página deve conter um cabeçalho de nível 1" + }, + "presentation-role-conflict": { + "description": "Os elementos marcados como 'none' ou 'presentation' não devem ter ARIA global ou 'tabindex', para garantir que todos os leitores de ecrã os ignorem", + "help": "Garantir que os elementos marcados como 'none' ou 'presentation' sejam consistentemente ignorados" + }, + "region": { + "description": "Garantir que todo o conteúdo da página esteja contido em marcos (landmarks)", + "help": "Todo o conteúdo da página deve estar contido em marcos (landmarks)" + }, + "role-img-alt": { + "description": "Garantir que os elementos com 'role=\"img\"' tenham texto alternativo", + "help": "Os elementos com 'role=\"img\"' devem ter um texto alternativo" + }, + "scope-attr-valid": { + "description": "Garantir que o atributo 'scope' seja usado corretamente em tabelas", + "help": "O atributo 'scope' deve ser usado corretamente" + }, + "scrollable-region-focusable": { + "description": "Garantir que os elementos com conteúdo rolável sejam acessíveis por teclado", + "help": "A região rolável deve ser acessível por teclado" + }, + "select-name": { + "description": "Garantir que o elemento 'select' tenha um nome acessível", + "help": "O elemento 'select' deve ter um nome acessível" + }, + "server-side-image-map": { + "description": "Garantir que os mapas de imagem do lado do servidor não sejam usados", + "help": "Os mapas de imagem do lado do servidor não devem ser usados" + }, + "skip-link": { + "description": "Garantir que todos os links de salto tenham um destino focável", + "help": "O destino do link de salto deve existir e ser focável" + }, + "summary-name": { + "description": "Garantir que os elementos 'summary' tenham texto discernível", + "help": "Os elementos 'summary' devem ter texto discernível" + }, + "svg-img-alt": { + "description": "Garantir que os elementos <svg> com uma função 'img', 'graphics-document' ou 'graphics-symbol' tenham um texto acessível", + "help": "Os elementos <svg> com a função 'img' devem ter um texto alternativo" + }, + "tabindex": { + "description": "Garantir que os valores do atributo 'tabindex' não sejam superiores a 0", + "help": "Os elementos não devem ter 'tabindex' superior a zero" + }, + "table-duplicate-name": { + "description": "Garantir que o elemento <caption> não contenha o mesmo texto que o atributo 'summary'", + "help": "As tabelas não devem ter o mesmo 'summary' e <caption>" + }, + "table-fake-caption": { + "description": "Garantir que as tabelas com caption utilizem o elemento <caption>.", + "help": "Não se devem usar células de dados ou de cabeçalho para dar caption a uma tabela de dados." + }, + "target-size": { + "description": "Garantir que os alvos tácteis tenham tamanho e espaço suficientes", + "help": "Todos os alvos tácteis devem ter 24px de dimensão ou deixar espaço suficiente" + }, + "td-has-header": { + "description": "Garantir que cada célula de dados não vazia numa tabela maior do que 3x3 tenha um ou mais cabeçalhos", + "help": "Os elementos <td> não vazios em tabelas maiores devem ter um cabeçalho associado" + }, + "td-headers-attr": { + "description": "Garantir que cada célula numa tabela que usa o atributo 'headers' se refira apenas a outras células nessa tabela", + "help": "As células de tabela que usam o atributo 'headers' devem referir-se apenas a células na mesma tabela" + }, + "th-has-data-cells": { + "description": "Garantir que os elementos <th> e os elementos com 'role=columnheader/rowheader' tenham células de dados que descrevem", + "help": "Os cabeçalhos de tabela numa tabela de dados devem referir-se às células de dados" + }, + "valid-lang": { + "description": "Garantir que os atributos 'lang' tenham valores válidos", + "help": "O atributo 'lang' deve ter um valor válido" + }, + "video-caption": { + "description": "Garantir que os elementos <video> tenham legendas", + "help": "Os elementos <video> devem ter legendas" + } + }, + "checks": { + "abstractrole": { + "pass": "Funções abstratas não são utilizadas", + "fail": { + "singular": "A função abstrata não pode ser usada diretamente: ${data.values}", + "plural": "As funções abstratas não podem ser usadas diretamente: ${data.values}" + } + }, + "aria-allowed-attr": { + "pass": "Os atributos ARIA são usados corretamente para a função definida", + "fail": { + "singular": "Atributo ARIA não é permitido: ${data.values}", + "plural": "Atributos ARIA não são permitidos: ${data.values}" + }, + "incomplete": "Verifique se não há problemas se o atributo ARIA for ignorado neste elemento: ${data.values}" + }, + "aria-allowed-role": { + "pass": "A função ARIA é permitida para o elemento", + "fail": { + "singular": "A função ARIA ${data.values} não é permitida para o elemento", + "plural": "As funções ARIA ${data.values} não são permitidas para o elemento" + }, + "incomplete": { + "singular": "A função ARIA ${data.values} deve ser removida quando o elemento se tornar visível, pois não é permitida para o elemento", + "plural": "As funções ARIA ${data.values} devem ser removidas quando o elemento se tornar visível, pois não são permitidas para o elemento" + } + }, + "aria-busy": { + "pass": "O elemento tem o atributo 'aria-busy'", + "fail": "O elemento utiliza 'aria-busy=\"true\"' enquanto mostra um carregador" + }, + "aria-conditional-attr": { + "pass": "O atributo ARIA é permitido", + "fail": { + "checkbox": "Remova aria-checked, ou defina-o como '\"${data.checkState}\"' para corresponder ao estado real da caixa de seleção", + "rowSingular": "Este atributo é suportado em linhas de 'treegrid', mas não em ${data.ownerRole}: ${data.invalidAttrs}", + "rowPlural": "Estes atributos são suportados em linhas de 'treegrid', mas não em ${data.ownerRole}: ${data.invalidAttrs}" + } + }, + "aria-errormessage": { + "pass": "'aria-errormessage' existe e referencia elementos visíveis para leitores de ecrã que utilizam uma técnica suportada de 'aria-errormessage'", + "fail": { + "singular": "O valor de 'aria-errormessage' `${data.values}` deve utilizar uma técnica para anunciar a mensagem (por exemplo, aria-live, aria-describedby, role=alert, etc.)", + "plural": "Os valores de 'aria-errormessage' `${data.values}` devem utilizar uma técnica para anunciar a mensagem (por exemplo, aria-live, aria-describedby, role=alert, etc.)", + "hidden": "O valor de 'aria-errormessage' `${data.values}` não pode referenciar um elemento oculto" + }, + "incomplete": { + "singular": "Assegure que o valor de 'aria-errormessage' `${data.values}` referencia um elemento existente", + "plural": "Assegure que os valores de 'aria-errormessage' `${data.values}` referenciem elementos existentes", + "idrefs": "Não foi possível determinar se o elemento 'aria-errormessage' existe na página: ${data.values}" + } + }, + "aria-hidden-body": { + "pass": "Não há nenhum atributo 'aria-hidden' no corpo do documento", + "fail": "'aria-hidden=true' não deve estar presente no corpo do documento" + }, + "aria-level": { + "pass": "Os valores de 'aria-level' são válidos", + "incomplete": "Valores de 'aria-level' superiores a 6 não são suportados em todas as combinações de leitores de ecrã e navegadores" + }, + "aria-prohibited-attr": { + "pass": "O atributo ARIA é permitido", + "fail": { + "hasRolePlural": "Os atributos ${data.prohibited} não podem ser usados com a função '\"${data.role}\"'.", + "hasRoleSingular": "O atributo ${data.prohibited} não pode ser usado com a função '\"${data.role}\"'.", + "noRolePlural": "Os atributos ${data.prohibited} não podem ser usados num ${data.nodeName} sem um atributo 'role' válido.", + "noRoleSingular": "O atributo ${data.prohibited} não pode ser usado num ${data.nodeName} sem um atributo 'role' válido." + }, + "incomplete": { + "hasRoleSingular": "O atributo ${data.prohibited} não é bem suportado com a função '\"${data.role}\"'.", + "hasRolePlural": "Os atributos ${data.prohibited} não são bem suportados com a função '\"${data.role}\"'.", + "noRoleSingular": "O atributo ${data.prohibited} não é bem suportado num ${data.nodeName} sem um atributo 'role' válido.", + "noRolePlural": "Os atributos ${data.prohibited} não são bem suportados num ${data.nodeName} sem um atributo 'role' válido." + } + }, + "aria-required-attr": { + "pass": "Todos os atributos ARIA obrigatórios estão presentes", + "fail": { + "singular": "Atributo ARIA obrigatório não está presente: ${data.values}", + "plural": "Atributos ARIA obrigatórios não estão presentes: ${data.values}" + } + }, + "aria-required-children": { + "pass": { + "default": "Os elementos filhos ARIA obrigatórios estão presentes", + "aria-busy": "O elemento tem o atributo 'aria-busy', pelo que é permitido omitir os elementos filhos obrigatórios" + }, + "fail": { + "singular": "A função ARIA de filho obrigatório não está presente: ${data.values}", + "plural": "A função ARIA de filhos obrigatórios não está presente: ${data.values}", + "unallowed": "O elemento tem filhos que não são permitidos: ${data.values}" + }, + "incomplete": { + "singular": "Espera-se que seja adicionada a função ARIA de filho: ${data.values}", + "plural": "Espera-se que sejam adicionadas as funções ARIA de filhos: ${data.values}" + } + }, + "aria-required-parent": { + "pass": "A função ARIA parental obrigatória está presente", + "fail": { + "singular": "A função ARIA parental obrigatória não está presente: ${data.values}", + "plural": "As funções ARIA parentais obrigatórias não estão presentes: ${data.values}" + } + }, + "aria-roledescription": { + "pass": "'aria-roledescription' é utilizado numa função semântica suportada", + "incomplete": "Verifique se o 'aria-roledescription' é anunciado por leitores de ecrã suportados", + "fail": "Atribua ao elemento uma função que suporte 'aria-roledescription'" + }, + "aria-unsupported-attr": { + "pass": "O atributo ARIA é suportado", + "fail": "O atributo ARIA não é amplamente suportado em leitores de ecrã e tecnologias assistivas: ${data.values}" + }, + "aria-valid-attr-value": { + "pass": "Os valores dos atributos ARIA são válidos", + "fail": { + "singular": "Valor de atributo ARIA inválido: ${data.values}", + "plural": "Valores de atributo ARIA inválidos: ${data.values}" + }, + "incomplete": { + "noId": "O ID do elemento do atributo ARIA não existe na página: ${data.needsReview}", + "noIdShadow": "O ID do elemento do atributo ARIA não existe na página ou é descendente de uma shadow DOM tree diferente: ${data.needsReview}", + "ariaCurrent": "O valor do atributo ARIA é inválido e será tratado como '\"aria-current=true\"': ${data.needsReview}", + "idrefs": "Não foi possível determinar se o ID do elemento do atributo ARIA existe na página: ${data.needsReview}", + "empty": "O valor do atributo ARIA é ignorado quando está vazio: ${data.needsReview}", + "controlsWithinPopup": "Não foi possível determinar se o ID referenciado por 'aria-controls existe' na página enquanto se utiliza 'aria-haspopup': ${data.needsReview}" + } + }, + "aria-valid-attr": { + "pass": "O nome do atributo ARIA é válido", + "fail": { + "singular": "Nome de atributo ARIA inválido: ${data.values}", + "plural": "Nomes de atributos ARIA inválidos: ${data.values}" + } + }, + "braille-label-equivalent": { + "pass": "'aria-braillelabel' é utilizado num elemento com texto acessível", + "fail": "'aria-braillelabel' é utilizado num elemento sem texto acessível", + "incomplete": "Não foi possível calcular o texto acessível" + }, + "braille-roledescription-equivalent": { + "pass": "'aria-brailleroledescription' é utilizado num elemento com aria-roledescription", + "fail": { + "noRoleDescription": "'aria-brailleroledescription' é utilizado num elemento sem 'aria-roledescription'", + "emptyRoleDescription": "'aria-brailleroledescription' é utilizado num elemento com 'aria-roledescription' vazio" + } + }, + "deprecatedrole": { + "pass": "A função ARIA não está obsoleta", + "fail": "A função utilizada está obsoleta: ${data}" + }, + "fallbackrole": { + "pass": "Foi utilizado apenas um valor de 'role'", + "fail": "Utilize apenas um valor de 'role', pois as funções de 'fallback' não são suportadas em navegadores mais antigos", + "incomplete": "Utilize apenas o role 'presentation' ou 'none', pois são sinónimos." + }, + "has-global-aria-attribute": { + "pass": { + "singular": "O elemento tem o atributo ARIA global: ${data.values}", + "plural": "O elemento tem os atributos ARIA globais: ${data.values}" + }, + "fail": "O elemento não tem atributo ARIA global" + }, + "has-widget-role": { + "pass": "O elemento tem uma função de 'widget'.", + "fail": "O elemento não tem uma função de 'widget'." + }, + "invalidrole": { + "pass": "A função ARIA é válida", + "fail": { + "singular": "A função deve ser uma das funções ARIA válidas: ${data.values}", + "plural": "As funções devem ser uma das funções ARIA válidas: ${data.values}" + } + }, + "is-element-focusable": { + "pass": "O elemento é focável.", + "fail": "O elemento não é focável." + }, + "no-implicit-explicit-label": { + "pass": "Não há discrepância entre uma <label> e o nome acessível", + "incomplete": "Verifique se a <label> não precisa fazer parte do nome do campo ARIA ${data}" + }, + "unsupportedrole": { + "pass": "A função ARIA é suportada", + "fail": "A função utilizada não é amplamente suportada em leitores de ecrã e tecnologias assistivas: ${data}" + }, + "valid-scrollable-semantics": { + "pass": "O elemento tem semântica válida para um elemento na ordem de foco.", + "fail": "O elemento tem semântica inválida para um elemento na ordem de foco." + }, + "color-contrast-enhanced": { + "pass": "O elemento tem um contraste de cor suficiente de ${data.contrastRatio}", + "fail": { + "default": "O elemento tem um contraste de cor insuficiente de ${data.contrastRatio} (cor de primeiro plano: ${data.fgColor}, cor de fundo: ${data.bgColor}, tamanho da fonte: ${data.fontSize}, peso da fonte: ${data.fontWeight}). Esperava-se uma razão de contraste de ${data.expectedContrastRatio}", + "fgOnShadowColor": "O elemento tem um contraste de cor insuficiente de ${data.contrastRatio} entre a cor de primeiro plano e a cor da sombra (cor de primeiro plano: ${data.fgColor}, cor do text-shadow: ${data.shadowColor}, tamanho da fonte: ${data.fontSize}, peso da fonte: ${data.fontWeight}). Esperava-se uma razão de contraste de ${data.expectedContrastRatio}", + "shadowOnBgColor": "O elemento tem um contraste de cor insuficiente de ${data.contrastRatio} entre a cor da sombra e a cor de fundo (cor do text-shadow: ${data.shadowColor}, cor de fundo: ${data.bgColor}, tamanho da fonte: ${data.fontSize}, peso da fonte: ${data.fontWeight}). Esperava-se uma razão de contraste de ${data.expectedContrastRatio}" + }, + "incomplete": { + "default": "Não foi possível determinar a razão de contraste", + "bgImage": "A cor de fundo do elemento não pôde ser determinada devido a uma imagem de fundo", + "bgGradient": "A cor de fundo do elemento não pôde ser determinada devido a um gradiente de fundo", + "imgNode": "A cor de fundo do elemento não pôde ser determinada porque o elemento contém um nó de imagem", + "bgOverlap": "A cor de fundo do elemento não pôde ser determinada porque está sobreposto por outro elemento", + "fgAlpha": "A cor de primeiro plano do elemento não pôde ser determinada devido à transparência alfa", + "elmPartiallyObscured": "A cor de fundo do elemento não pôde ser determinada porque está parcialmente encoberta por outro elemento", + "elmPartiallyObscuring": "A cor de fundo do elemento não pôde ser determinada porque se sobrepõe parcialmente a outros elementos", + "outsideViewport": "A cor de fundo do elemento não pôde ser determinada porque está fora da área visível", + "equalRatio": "O elemento tem uma razão de contraste 1:1 com o fundo", + "shortTextContent": "O conteúdo do elemento é demasiado curto para determinar se é realmente conteúdo textual", + "nonBmp": "O conteúdo do elemento contém apenas caracteres não textuais", + "pseudoContent": "A cor de fundo do elemento não pôde ser determinada devido a um pseudo-elemento" + } + }, + "color-contrast": { + "pass": { + "default": "O elemento tem um contraste de cor suficiente de ${data.contrastRatio}", + "hidden": "O elemento está oculto" + }, + "fail": { + "default": "O elemento tem um contraste de cor insuficiente de ${data.contrastRatio} (cor de primeiro plano: ${data.fgColor}, cor de fundo: ${data.bgColor}, tamanho da fonte: ${data.fontSize}, peso da fonte: ${data.fontWeight}). Esperava-se uma razão de contraste de ${data.expectedContrastRatio}", + "fgOnShadowColor": "O elemento tem um contraste de cor insuficiente de ${data.contrastRatio} entre a cor de primeiro plano e a cor da sombra (cor de primeiro plano: ${data.fgColor}, cor do text-shadow: ${data.shadowColor}, tamanho da fonte: ${data.fontSize}, peso da fonte: ${data.fontWeight}). Esperava-se uma razão de contraste de ${data.expectedContrastRatio}", + "shadowOnBgColor": "O elemento tem um contraste de cor insuficiente de ${data.contrastRatio} entre a cor da sombra e a cor de fundo (cor do text-shadow: ${data.shadowColor}, cor de fundo: ${data.bgColor}, tamanho da fonte: ${data.fontSize}, peso da fonte: ${data.fontWeight}). Esperava-se uma razão de contraste de ${data.expectedContrastRatio}" + }, + "incomplete": { + "default": "Não foi possível determinar a razão de contraste", + "bgImage": "A cor de fundo do elemento não pôde ser determinada devido a uma imagem de fundo", + "bgGradient": "A cor de fundo do elemento não pôde ser determinada devido a um gradiente de fundo", + "imgNode": "A cor de fundo do elemento não pôde ser determinada porque o elemento contém um nó de imagem", + "bgOverlap": "A cor de fundo do elemento não pôde ser determinada porque está sobreposto por outro elemento", + "complexTextShadows": "Não foi possível determinar o contraste do elemento porque utiliza sombras de texto complexas", + "fgAlpha": "A cor de primeiro plano do elemento não pôde ser determinada devido à transparência alfa", + "elmPartiallyObscured": "A cor de fundo do elemento não pôde ser determinada porque está parcialmente encoberta por outro elemento", + "elmPartiallyObscuring": "A cor de fundo do elemento não pôde ser determinada porque se sobrepõe parcialmente a outros elementos", + "outsideViewport": "A cor de fundo do elemento não pôde ser determinada porque está fora da área visível", + "equalRatio": "O elemento tem uma razão de contraste 1:1 com o fundo", + "shortTextContent": "O conteúdo do elemento é demasiado curto para determinar se é realmente texto", + "nonBmp": "O conteúdo do elemento contém apenas caracteres não textuais", + "pseudoContent": "A cor de fundo do elemento não pôde ser determinada devido a um pseudo-elemento" + } + }, + "link-in-text-block-style": { + "pass": "Os links podem ser distinguidos do texto circundante através de estilos visuais", + "incomplete": { + "default": "Verifique se o link necessita de estilos para se distinguir do texto próximo", + "pseudoContent": "Verifique se o pseudo-estilo do link é suficiente para o distinguir do texto circundante" + }, + "fail": "O link não tem estilos (como sublinhado) para se distinguir do texto circundante" + }, + "link-in-text-block": { + "pass": "Os links podem ser distinguidos do texto circundante de alguma forma que não seja pela cor", + "fail": { + "fgContrast": "O link tem um contraste de cor insuficiente de ${data.contrastRatio}:1 com o texto circundante. (O contraste mínimo é ${data.requiredContrastRatio}:1, cor do link: ${data.nodeColor}, cor do texto circundante: ${data.parentColor})", + "bgContrast": "O fundo do link tem um contraste de cor insuficiente de ${data.contrastRatio} (o contraste mínimo é ${data.requiredContrastRatio}:1, cor de fundo do link: ${data.nodeBackgroundColor}, cor de fundo circundante: ${data.parentBackgroundColor})" + }, + "incomplete": { + "default": "Não foi possível determinar a razão de contraste do primeiro plano do elemento", + "bgContrast": "Não foi possível determinar a razão de contraste do fundo do elemento", + "bgImage": "Não foi possível determinar a razão de contraste do elemento devido a uma imagem de fundo", + "bgGradient": "Não foi possível determinar a razão de contraste do elemento devido a um gradiente de fundo", + "imgNode": "Não foi possível determinar a razão de contraste do elemento porque contém um nó de imagem", + "bgOverlap": "Não foi possível determinar a razão de contraste do elemento devido à sobreposição de elementos" + } + }, + "autocomplete-appropriate": { + "pass": "O valor de 'autocomplete' está num elemento apropriado", + "fail": "O valor de 'autocomplete' é inapropriado para este tipo de entrada" + }, + "autocomplete-valid": { + "pass": "o atributo 'autocomplete' está formatado corretamente", + "fail": "o atributo 'autocomplete' está formatado incorretamente", + "incomplete": "o atributo 'autocomplete' tem um valor não padrão. Verifique se poderia ser utilizado algum valor padrão." + }, + "accesskeys": { + "pass": "O valor do atributo 'accesskey' é único", + "fail": "O documento tem múltiplos elementos com o mesmo 'accesskey'" + }, + "focusable-content": { + "pass": "O elemento contém elementos focáveis", + "fail": "O elemento deveria ter conteúdo focável" + }, + "focusable-disabled": { + "pass": "Não há elementos focáveis contidos no elemento", + "incomplete": "Verifique se os elementos focáveis movem imediatamente o indicador de foco", + "fail": "O conteúdo focável deve ser desativado ou removido do DOM" + }, + "focusable-element": { + "pass": "O elemento é focável", + "fail": "O elemento deveria ser focável" + }, + "focusable-modal-open": { + "pass": "Não há elementos focáveis enquanto um modal está aberto", + "incomplete": "Verifique se os elementos focáveis não são tabuláveis no estado atual" + }, + "focusable-no-name": { + "pass": "O elemento não está na ordem de tabulação ou tem texto acessível", + "fail": "O elemento está na ordem de tabulação e não tem texto acessível", + "incomplete": "Não foi possível determinar se o elemento tem um nome acessível" + }, + "focusable-not-tabbable": { + "pass": "Não há elementos focáveis contidos no elemento", + "incomplete": "Verifique se os elementos focáveis movem imediatamente o indicador de foco", + "fail": "O conteúdo focável deve ter 'tabindex=\"-1\"' ou ser removido do DOM" + }, + "frame-focusable-content": { + "pass": "O elemento não tem descendentes focáveis", + "fail": "O elemento tem descendentes focáveis", + "incomplete": "Não foi possível determinar se o elemento tem descendentes" + }, + "landmark-is-top-level": { + "pass": "O marco ${data.role} está no nível principal.", + "fail": "O marco ${data.role} está contido noutro marco." + }, + "no-focusable-content": { + "pass": "O elemento não tem descendentes focáveis", + "fail": { + "default": "O elemento tem descendentes focáveis", + "notHidden": "Utilizar um tabindex negativo num elemento dentro de um controlo interativo não impede que as tecnologias assistivas foquem o elemento (mesmo com aria-hidden=\"true\")" + }, + "incomplete": "Não foi possível determinar se o elemento tem descendentes" + }, + "page-has-heading-one": { + "pass": "A página tem pelo menos um cabeçalho de nível 1", + "fail": "A página deve ter um cabeçalho de nível 1" + }, + "page-has-main": { + "pass": "O documento tem pelo menos um marco 'main'", + "fail": "O documento não tem um marco 'main'" + }, + "page-no-duplicate-banner": { + "pass": "O documento não tem mais do que um marco de 'banner'", + "fail": "O documento tem mais do que um marco de 'banner'" + }, + "page-no-duplicate-contentinfo": { + "pass": "O documento não tem mais do que um marco 'contentinfo'", + "fail": "O documento tem mais do que um marco 'contentinfo'" + }, + "page-no-duplicate-main": { + "pass": "O documento não tem mais do que um marco 'main'", + "fail": "O documento tem mais do que um marco 'main'" + }, + "tabindex": { + "pass": "O elemento não tem um 'tabindex' superior a 0", + "fail": "O elemento tem um 'tabindex' superior a 0" + }, + "alt-space-value": { + "pass": "O elemento tem um valor válido para o atributo 'alt'", + "fail": "O elemento tem um atributo 'alt' que contém apenas um espaço, o qual não é ignorado por todos os leitores de ecrã" + }, + "duplicate-img-label": { + "pass": "O elemento não duplica o texto existente no atributo 'alt' da <img>", + "fail": "O elemento contém uma <img> com texto 'alt' que duplica texto existente" + }, + "explicit-label": { + "pass": "O elemento tem uma <label> explícita", + "fail": "O elemento não tem uma <label> explícita", + "incomplete": "Não foi possível determinar se o elemento de formulário tem uma <label> explícita" + }, + "help-same-as-label": { + "pass": "O texto de ajuda (title ou aria-describedby) não duplica o texto da etiqueta", + "fail": "O texto de ajuda (title ou aria-describedby) é igual ao texto da etiqueta" + }, + "hidden-explicit-label": { + "pass": "O elemento de formulário tem uma <label> explícita visível", + "fail": "O elemento de formulário tem uma <label> explícita que está oculta", + "incomplete": "Não foi possível determinar se o elemento de formulário tem uma <label> explícita oculta" + }, + "implicit-label": { + "pass": "O elemento tem uma <label> implícita (envolvida)", + "fail": "O elemento não tem uma <label> implícita (envolvida)", + "incomplete": "Não foi possível determinar se o elemento de formulário tem uma <label> implícita (envolvida)" + }, + "label-content-name-mismatch": { + "pass": "O elemento contém texto visível como parte do seu nome acessível", + "fail": "O texto dentro do elemento não está incluído no nome acessível" + }, + "multiple-label": { + "pass": "O campo de formulário não tem múltiplos <label>", + "incomplete": "Múltiplos <label> não são amplamente suportadas em tecnologias assistivas. Assegure que a primeira etiqueta contém toda a informação necessária." + }, + "title-only": { + "pass": "O elemento de formulário não utiliza apenas o atributo 'title' para a sua etiqueta", + "fail": "Apenas o 'title' é usado para gerar a etiqueta do elemento de formulário" + }, + "landmark-is-unique": { + "pass": "Os marcos devem ter uma combinação única de 'role' ou 'role'/'label'/'title' (ou seja, nome acessível)", + "fail": "O marco deve ter um 'aria-label', 'aria-labelledby' ou 'title' únicos para torná-lo distinguível" + }, + "has-lang": { + "pass": "O elemento <html> tem um atributo 'lang'", + "fail": { + "noXHTML": "O atributo 'xml:lang' não é válido em páginas HTML, use o atributo 'lang'.", + "noLang": "O elemento <html> não tem um atributo 'lang'" + } + }, + "valid-lang": { + "pass": "O valor do atributo 'lang' está incluído na lista de línguas válidas", + "fail": "O valor do atributo 'lang' não está incluído na lista de línguas válidas" + }, + "xml-lang-mismatch": { + "pass": "Os atributos 'lang' e 'xml:lang' têm a mesma língua base", + "fail": "Os atributos 'lang' e 'xml:lang' não têm a mesma língua base" + }, + "dlitem": { + "pass": "O item de lista de descrições tem um elemento pai <dl>", + "fail": "O item de lista de descrições não tem um elemento pai <dl>" + }, + "listitem": { + "pass": "O item de lista tem um elemento pai <ul>, <ol> ou 'role=\"list\"'", + "fail": { + "default": "O item de lista não tem um elemento pai <ul> ou <ol>", + "roleNotValid": "O elemento pai do item de lista tem uma role que não é 'role=\"list\"'" + } + }, + "only-dlitems": { + "pass": "O elemento <dl> tem apenas filhos diretos permitidos: <dt>, <dd> ou <div>", + "fail": "O elemento <dl> tem filhos diretos não permitidos: ${data.values}" + }, + "only-listitems": { + "pass": "O elemento de lista tem apenas filhos diretos permitidos, que devem ser <li>", + "fail": "O elemento de lista tem filhos diretos não permitidos: ${data.values}" + }, + "structured-dlitems": { + "pass": "Quando não está vazio, o elemento tem tanto <dt> como <dd>", + "fail": "Quando não está vazio, o elemento não tem pelo menos um elemento <dt> seguido de pelo menos um <dd>" + }, + "caption": { + "pass": "O elemento multimédia tem uma pista de legendas", + "incomplete": "Verifique se as legendas estão disponíveis para o elemento" + }, + "frame-tested": { + "pass": "O 'iframe' foi testado com axe-core", + "fail": "O 'iframe' não pôde ser testado com axe-core", + "incomplete": "O 'iframe' ainda tem de ser testado com axe-core" + }, + "no-autoplay-audio": { + "pass": "<video> ou <audio> não reproduzem áudio por mais do que a duração permitida ou têm um mecanismo de controlo", + "fail": "<video> ou <audio> reproduzem áudio por mais do que a duração permitida e não têm um mecanismo de controlo", + "incomplete": "Verifique se o <video> ou <audio> não reproduzem áudio por mais do que a duração permitida ou fornecem um mecanismo de controlo" + }, + "css-orientation-lock": { + "pass": "O ecrã é operativo, e não existe bloqueio de orientação", + "fail": "O bloqueio de orientação CSS está aplicado e torna o ecrã inoperável", + "incomplete": "Não é possível determinar o bloqueio de orientação CSS" + }, + "meta-viewport-large": { + "pass": "A tag <meta> não impede uma ampliação significativa em dispositivos móveis", + "fail": "A tag <meta> limita a ampliação em dispositivos móveis" + }, + "meta-viewport": { + "pass": "A tag <meta> não desativa a ampliação em dispositivos móveis", + "fail": "${data} na tag <meta> desativa a ampliação em dispositivos móveis" + }, + "target-offset": { + "pass": { + "default": "O alvo tem espaço suficiente dos seus vizinhos mais próximos. O espaço clicável seguro tem um diâmetro de ${data.closestOffset}px, que é, no mínimo, ${data.minOffset}px.", + "large": "O alvo excede largamente o tamanho mínimo de ${data.minOffset}px." + }, + "fail": "O alvo tem espaço insuficiente em relação aos vizinhos mais próximos. O espaço clicável seguro tem um diâmetro de ${data.closestOffset}px, em vez de, pelo menos, ${data.minOffset}px.", + "incomplete": { + "default": "O elemento com tabindex negativo tem espaço insuficiente em relação aos seus vizinhos mais próximos. O espaço clicável seguro tem um diâmetro de ${data.closestOffset}px, em vez de, pelo menos, ${data.minOffset}px. É este um alvo?", + "nonTabbableNeighbor": "O alvo tem espaço insuficiente em relação aos seus vizinhos mais próximos. O espaço clicável seguro tem um diâmetro de ${data.closestOffset}px, em vez de, pelo menos, ${data.minOffset}px. Será que o vizinho é um alvo?", + "tooManyRects": "Não foi possível obter o tamanho do alvo porque há elementos sobrepostos em excesso" + } + }, + "target-size": { + "pass": { + "default": "O controlo tem um tamanho suficiente (${data.width}px por ${data.height}px, devendo ter pelo menos ${data.minSize}px por ${data.minSize}px)", + "obscured": "O controlo é ignorado porque está totalmente encoberto e, por isso, não é clicável", + "large": "O alvo excede largamente o tamanho mínimo de ${data.minSize}px." + }, + "fail": { + "default": "O alvo tem um tamanho insuficiente (${data.width}px por ${data.height}px, devendo ter pelo menos ${data.minSize}px por ${data.minSize}px)", + "partiallyObscured": "O alvo tem um tamanho insuficiente porque está parcialmente encoberto (o menor espaço é de ${data.width}px por ${data.height}px, devendo ser pelo menos ${data.minSize}px por ${data.minSize}px)" + }, + "incomplete": { + "default": "O elemento com 'tabindex' negativo tem um tamanho insuficiente (${data.width}px por ${data.height}px, devendo ser pelo menos ${data.minSize}px por ${data.minSize}px). É este um alvo?", + "contentOverflow": "O tamanho do elemento não pôde ser determinado com precisão devido ao conteúdo com overflow", + "partiallyObscured": "O elemento com 'tabindex' negativo tem um tamanho insuficiente porque está parcialmente encoberto (o menor espaço é de ${data.width}px por ${data.height}px, devendo ser pelo menos ${data.minSize}px por ${data.minSize}px). É este um alvo?", + "partiallyObscuredNonTabbable": "O alvo tem um tamanho insuficiente porque está parcialmente encoberto por um vizinho com 'tabindex' negativo (o menor espaço é de ${data.width}px por ${data.height}px, devendo ser pelo menos ${data.minSize}px por ${data.minSize}px). Será que o vizinho é um alvo?", + "tooManyRects": "Não foi possível obter o tamanho do alvo porque há elementos sobrepostos em excesso" + } + }, + "header-present": { + "pass": "A página tem um cabeçalho", + "fail": "A página não tem um cabeçalho" + }, + "heading-order": { + "pass": "Ordem dos cabeçalhos válida", + "fail": "Ordem dos cabeçalhos inválida", + "incomplete": "Não foi possível determinar o cabeçalho anterior" + }, + "identical-links-same-purpose": { + "pass": "Não existem outros links com o mesmo nome que direcionem para uma URL diferente", + "incomplete": "Verifique se os links têm o mesmo propósito ou se são intencionalmente ambíguos." + }, + "internal-link-present": { + "pass": "Foi encontrado um link de salto válido", + "fail": "Não foi encontrado um link de salto válido" + }, + "landmark": { + "pass": "A página tem uma região de marco", + "fail": "A página não tem uma região de marco" + }, + "meta-refresh-no-exceptions": { + "pass": "A tag <meta> não atualiza imediatamente a página", + "fail": "A tag <meta> força a atualização da página com temporização" + }, + "meta-refresh": { + "pass": "A tag <meta> não atualiza imediatamente a página", + "fail": "A tag <meta> força a atualização da página com temporização (inferior a 20 horas)" + }, + "p-as-heading": { + "pass": "Os elementos <p> não estão estilizados como cabeçalhos", + "fail": "Deveriam ser usados elementos de cabeçalho em vez de elementos <p> estilizados", + "incomplete": "Não foi possível determinar se os elementos <p> estão estilizados como cabeçalhos" + }, + "region": { + "pass": "Todo o conteúdo da página está contido em marcos", + "fail": "Algum conteúdo da página não está contido em marcos" + }, + "skip-link": { + "pass": "O destino do link de salto existe", + "incomplete": "O destino do link de salto deve tornar-se visível na ativação", + "fail": "Não há destino para o link de salto" + }, + "unique-frame-title": { + "pass": "O atributo 'title' do elemento é único", + "fail": "O atributo 'title' do elemento não é único" + }, + "duplicate-id-active": { + "pass": "O documento não tem elementos ativos que partilhem o mesmo atributo 'id'", + "fail": "O documento tem elementos ativos com o mesmo atributo 'id': ${data}" + }, + "duplicate-id-aria": { + "pass": "O documento não tem elementos referenciados com ARIA ou etiquetas que partilhem o mesmo atributo 'id'", + "fail": "O documento tem múltiplos elementos referenciados com ARIA com o mesmo atributo 'id': ${data}" + }, + "duplicate-id": { + "pass": "O documento não tem elementos estáticos que partilhem o mesmo atributo 'id'", + "fail": "O documento tem múltiplos elementos estáticos com o mesmo atributo 'id': ${data}" + }, + "aria-label": { + "pass": "O atributo 'aria-label' existe e não está vazio", + "fail": "O atributo 'aria-label' não existe ou está vazio" + }, + "aria-labelledby": { + "pass": "O atributo 'aria-labelledby' existe e referencia elementos visíveis para leitores de ecrã", + "fail": "O atributo 'aria-labelledby' não existe, referencia elementos que não existem ou que estão vazios", + "incomplete": "Assegure que 'aria-labelledby' referencia um elemento existente" + }, + "avoid-inline-spacing": { + "pass": "Não foram especificados estilos 'inline' com '!important' que afetem o espaçamento do texto", + "fail": { + "singular": "Remova '!important' do estilo 'inline' ${data.values}, pois a sua sobreposição não é suportada pela maioria dos navegadores", + "plural": "Remova '!important' dos estilos 'inline' ${data.values}, pois a sua sobreposição não é suportada pela maioria dos navegadores" + } + }, + "button-has-visible-text": { + "pass": "O elemento tem texto interno que é visível para leitores de ecrã", + "fail": "O elemento não tem texto interno que seja visível para leitores de ecrã", + "incomplete": "Não foi possível determinar se o elemento tem filhos" + }, + "doc-has-title": { + "pass": "O documento tem um elemento <title> não vazio", + "fail": "O documento não tem um elemento <title> não vazio" + }, + "exists": { + "pass": "O elemento não existe", + "incomplete": "O elemento existe" + }, + "has-alt": { + "pass": "O elemento tem um atributo 'alt'", + "fail": "O elemento não tem um atributo 'alt'" + }, + "has-visible-text": { + "pass": "O elemento tem texto que é visível para leitores de ecrã", + "fail": "O elemento não tem texto que seja visível para leitores de ecrã", + "incomplete": "Não foi possível determinar se o elemento tem filhos" + }, + "important-letter-spacing": { + "pass": "O espaçamento entre letras no atributo 'style' não está definido como !important, ou cumpre o mínimo", + "fail": "O espaçamento entre letras no atributo 'style' não deve usar !important, ou ter ${data.minValue}em (atualmente ${data.value}em)" + }, + "important-line-height": { + "pass": "A altura da linha no atributo 'style' não está definida como !important, ou cumpre o mínimo", + "fail": "A altura da linha no atributo 'style' não deve usar !important, ou ter ${data.minValue}em (atualmente ${data.value}em)" + }, + "important-word-spacing": { + "pass": "O espaçamento entre palavras no atributo 'style' não está definido como !important, ou cumpre o mínimo", + "fail": "O espaçamento entre palavras no atributo 'style' não deve usar !important, ou ter ${data.minValue}em (atualmente ${data.value}em)" + }, + "is-on-screen": { + "pass": "O elemento não está visível", + "fail": "O elemento está visível" + }, + "non-empty-alt": { + "pass": "O elemento tem um atributo 'alt' não vazio", + "fail": { + "noAttr": "O elemento não tem um atributo 'alt'", + "emptyAttr": "O elemento tem um atributo 'alt' vazio" + } + }, + "non-empty-if-present": { + "pass": { + "default": "O elemento não tem um atributo 'value'", + "has-label": "O elemento tem um atributo 'value' não vazio" + }, + "fail": "O elemento tem um atributo 'value' e este está vazio" + }, + "non-empty-placeholder": { + "pass": "O elemento tem um atributo 'placeholder'", + "fail": { + "noAttr": "O elemento não tem um atributo 'placeholder'", + "emptyAttr": "O elemento tem um atributo 'placeholder' vazio" + } + }, + "non-empty-title": { + "pass": "O elemento tem um atributo 'title'", + "fail": { + "noAttr": "O elemento não tem um atributo 'title'", + "emptyAttr": "O elemento tem um atributo 'title' vazio" + } + }, + "non-empty-value": { + "pass": "O elemento tem um atributo 'value' não vazio", + "fail": { + "noAttr": "O elemento não tem um atributo 'value'", + "emptyAttr": "O elemento tem um atributo 'value' vazio" + } + }, + "presentational-role": { + "pass": "A semântica por defeito do elemento foi substituída por 'role=\"${data.role}\"'", + "fail": { + "default": "A semântica por defeito do elemento não foi substituída por 'role=\"none\"' ou 'role=\"presentation\"'", + "globalAria": "A função do elemento não é de apresentação porque tem um atributo ARIA global", + "focusable": "A função do elemento não é de apresentação porque é focável", + "both": "A função do elemento não é de apresentação porque tem um atributo ARIA global e é focável", + "iframe": "Utilizar o atributo '\"title\"' num elemento ${data.nodeName} com uma função de apresentação comporta-se de forma inconsistente entre os leitores de ecrã" + } + }, + "role-none": { + "pass": "A semântica por defeito do elemento foi substituída por 'role=\"none\"'", + "fail": "A semântica por defeito do elemento não foi substituída por 'role=\"none\"'" + }, + "role-presentation": { + "pass": "A semântica por defeito do elemento foi substituída por 'role=\"presentation\"'", + "fail": "A semântica por defeito do elemento não foi substituída por 'role=\"presentation\"'" + }, + "svg-non-empty-title": { + "pass": "O elemento tem um filho que é um título", + "fail": { + "noTitle": "O elemento não tem um filho que seja um título", + "emptyTitle": "O título do filho do elemento está vazio" + }, + "incomplete": "Não foi possível determinar se o elemento tem um filho que seja um título" + }, + "caption-faked": { + "pass": "A primeira linha de uma tabela não é utilizada como <caption>", + "fail": "O primeiro filho da tabela deveria ser um caption em vez de uma célula" + }, + "html5-scope": { + "pass": "O atributo scope é usado apenas em elementos de cabeçalho de tabela (<th>)", + "fail": "No HTML 5, os atributos scope só podem ser usados em elementos de cabeçalho de tabela (<th>)" + }, + "same-caption-summary": { + "pass": "O conteúdo do atributo 'summary' e do <caption> não está duplicado", + "fail": "O conteúdo do atributo 'summary' e do elemento <caption> são idênticos", + "incomplete": "Não foi possível determinar se o elemento <table> tem um caption" + }, + "scope-value": { + "pass": "O atributo 'scope' é usado corretamente", + "fail": "O valor do atributo 'scope' só pode ser 'row' ou 'col'" + }, + "td-has-header": { + "pass": "Todas as células de dados não vazias têm cabeçalhos de tabela", + "fail": "Algumas células de dados não vazias não têm cabeçalhos de tabela" + }, + "td-headers-attr": { + "pass": "O atributo 'headers' é usado exclusivamente para referir-se a outras células da tabela", + "incomplete": "O atributo 'headers' está vazio", + "fail": "O atributo 'headers' não é usado exclusivamente para referir-se a outras células da tabela" + }, + "th-has-data-cells": { + "pass": "Todos os cabeçalhos de tabela numa tabela de dados referem-se às células de dados", + "fail": "Nem todas as células de cabeçalho de tabela referem-se a células de dados", + "incomplete": "Faltam células de dados na tabela ou estão vazias" + }, + "hidden-content": { + "pass": "Todo o conteúdo da página foi analisado.", + "fail": "Houve problemas na análise do conteúdo desta página.", + "incomplete": "Existe conteúdo oculto na página que não foi analisado. Será necessário acionar a sua exibição para o analisar." + } + }, + "failureSummaries": { + "any": { + "failureMessage": "Corrija qualquer um dos seguintes:{{~it:value}}\n {{=value.split('\\n').join('\\n ')}}{{~}}" + }, + "none": { + "failureMessage": "Corrija todos os seguintes:{{~it:value}}\n {{=value.split('\\n').join('\\n ')}}{{~}}" + } + }, + "incompleteFallbackMessage": "O axe não conseguiu identificar a razão. Hora de recorrer ao inspetor de elementos!" +} diff --git a/locales/ru.json b/locales/ru.json new file mode 100644 index 000000000..29c80cee5 --- /dev/null +++ b/locales/ru.json @@ -0,0 +1,1127 @@ +{ + "lang": "ru", + "rules": { + "accesskeys": { + "description": "Убедитесь, что значение атрибута accesskey является уникальным", + "help": "Значение атрибута accesskey должно быть уникальным" + }, + "area-alt": { + "description": "Убедитесь, что элементы <area> карт изображений имеют альтернативный текст", + "help": "Активные элементы <area> должны иметь альтернативный текст" + }, + "aria-allowed-attr": { + "description": "Убедитесь, что роль элемента поддерживает его ARIA атрибуты", + "help": "Элементы должны использовать только поддерживаемые ARIA атрибуты" + }, + "aria-allowed-role": { + "description": "Убедитесь, что атрибут role имеет допустимое значение для элемента", + "help": "ARIA роль должна быть подходящей для элемента" + }, + "aria-braille-equivalent": { + "description": "Убедитесь, что aria-braillelabel и aria-brailleroledescription имеют эквивалентный текст не для шрифта Брайля", + "help": "Атрибуты aria-braille должны иметь эквивалентный текст не для шрифта Брайля" + }, + "aria-command-name": { + "description": "Убедитесь, что каждая ARIA кнопка, ссылка и пункт меню имеет доступное имя", + "help": "ARIA команды должны иметь доступное имя" + }, + "aria-conditional-attr": { + "description": "Убедитесь, что ARIA атрибуты используются в соответствии со спецификацией роли элемента", + "help": "ARIA атрибуты должны использоваться в соответствии с ролью элемента" + }, + "aria-deprecated-role": { + "description": "Убедитесь, что элементы не используют устаревшие роли", + "help": "Устаревшие ARIA роли не должны использоваться" + }, + "aria-dialog-name": { + "description": "Убедитесь, что каждая ARIA диалоговая форма и alertdialog узел имеют доступное имя", + "help": "ARIA диалоговые формы и alertdialog узлы должны иметь доступное имя" + }, + "aria-hidden-body": { + "description": "Убедитесь, что aria-hidden=\"true\" отсутствует на теле документа.", + "help": "aria-hidden=\"true\" не должно присутствовать на теле документа" + }, + "aria-hidden-focus": { + "description": "Убедитесь, что aria-hidden элементы не могут быть сфокусированы и не содержат фокусируемых элементов", + "help": "ARIA скрытые элементы не должны быть фокусируемыми или содержать фокусируемые элементы" + }, + "aria-input-field-name": { + "description": "Убедитесь, что каждое ARIA поле ввода имеет доступное имя", + "help": "ARIA поля ввода должны иметь доступное имя" + }, + "aria-meter-name": { + "description": "Убедитесь, что каждый ARIA meter узел имеет доступное имя", + "help": "ARIA meter узлы должны иметь доступное имя" + }, + "aria-progressbar-name": { + "description": "Убедитесь, что каждый ARIA progressbar узел имеет доступное имя", + "help": "ARIA progressbar узлы должны иметь доступное имя" + }, + "aria-prohibited-attr": { + "description": "Убедитесь, что ARIA атрибуты не запрещены для роли элемента", + "help": "Элементы должны использовать только разрешенные ARIA атрибуты" + }, + "aria-required-attr": { + "description": "Убедитесь, что элементы с ARIA ролями имеют все необходимые ARIA атрибуты", + "help": "Необходимые ARIA атрибуты должны быть предоставлены" + }, + "aria-required-children": { + "description": "Убедитесь, что элементы с ARIA ролями, требующими дочерние роли, содержат их", + "help": "Некоторые ARIA роли должны содержать определенные дочерние роли" + }, + "aria-required-parent": { + "description": "Убедитесь, что элементы с ARIA ролями, требующими родительские роли, содержатся ими", + "help": "Некоторые ARIA роли должны содержаться в определенных родительских ролях" + }, + "aria-roledescription": { + "description": "Убедитесь, что aria-roledescription используется только на элементах с явной или неявной ролью", + "help": "aria-roledescription должен использоваться на элементах с семантической ролью" + }, + "aria-roles": { + "description": "Убедитесь, что все элементы с атрибутом role используют допустимое значение", + "help": "ARIA роли должны соответствовать допустимым значениям" + }, + "aria-text": { + "description": "Убедитесь, что роль=\"text\" используется на элементах без фокусируемых потомков", + "help": "\"роль=text\" не должна иметь фокусируемых потомков" + }, + "aria-toggle-field-name": { + "description": "Убедитесь, что каждое ARIA toggle поле имеет доступное имя", + "help": "ARIA toggle поля должны иметь доступное имя" + }, + "aria-tooltip-name": { + "description": "Убедитесь, что каждый ARIA tooltip узел имеет доступное имя", + "help": "ARIA tooltip узлы должны иметь доступное имя" + }, + "aria-treeitem-name": { + "description": "Убедитесь, что каждый ARIA treeitem узел имеет доступное имя", + "help": "ARIA treeitem узлы должны иметь доступное имя" + }, + "aria-valid-attr-value": { + "description": "Убедитесь, что все ARIA атрибуты имеют допустимые значения", + "help": "ARIA атрибуты должны соответствовать допустимым значениям" + }, + "aria-valid-attr": { + "description": "Убедитесь, что атрибуты, начинающиеся с aria-, являются допустимыми ARIA атрибутами", + "help": "ARIA атрибуты должны соответствовать допустимым именам" + }, + "audio-caption": { + "description": "Убедитесь, что элементы <audio> имеют субтитры", + "help": "Элементы <audio> должны иметь трек субтитров" + }, + "autocomplete-valid": { + "description": "Убедитесь, что атрибут autocomplete правильный и подходит для поля формы", + "help": "Атрибут autocomplete должен использоваться правильно" + }, + "avoid-inline-spacing": { + "description": "Убедитесь, что расстояние между текстом, установленное через атрибуты стиля, можно настроить с помощью пользовательских таблиц стилей", + "help": "Встроенное текстовое пространство должно быть регулируемым с помощью пользовательских таблиц стилей" + }, + "blink": { + "description": "Убедитесь, что элементы <blink> не используются", + "help": "Элементы <blink> устарели и не должны использоваться" + }, + "button-name": { + "description": "Убедитесь, что кнопки имеют различимый текст", + "help": "Кнопки должны иметь различимый текст" + }, + "bypass": { + "description": "Убедитесь, что на каждой странице есть хотя бы один механизм, позволяющий пользователю обходить навигацию и переходить непосредственно к содержимому", + "help": "На странице должен быть способ обойти повторяющиеся блоки" + }, + "color-contrast-enhanced": { + "description": "Убедитесь, что контраст между цветами переднего и заднего плана соответствует пороговым значениям улучшенной контрастности WCAG 2 AAA", + "help": "Элементы должны соответствовать пороговым значениям улучшенной контрастности цвета" + }, + "color-contrast": { + "description": "Убедитесь, что контраст между цветами переднего и заднего плана соответствует минимальным пороговым значениям контрастности WCAG 2 AA", + "help": "Элементы должны соответствовать минимальным пороговым значениям контрастности цвета" + }, + "css-orientation-lock": { + "description": "Убедитесь, что содержимое не привязано к определенной ориентации дисплея, и оно доступно во всех ориентациях дисплея", + "help": "Медиа-запросы CSS не должны блокировать ориентацию дисплея" + }, + "definition-list": { + "description": "Убедитесь, что элементы <dl> структурированы правильно", + "help": "Элементы <dl> должны содержать только группы <dt> и <dd>, <script>, <template> или <div> элементы" + }, + "dlitem": { + "description": "Убедитесь, что элементы <dt> и <dd> находятся внутри <dl>", + "help": "Элементы <dt> и <dd> должны быть размещены внутри <dl>" + }, + "document-title": { + "description": "Убедитесь, что каждый HTML-документ содержит непустой элемент <title>", + "help": "Документы должны иметь элемент <title> для навигации" + }, + "duplicate-id-active": { + "description": "Убедитесь, что каждое значение атрибута id активных элементов уникально", + "help": "Идентификаторы активных элементов должны быть уникальными" + }, + "duplicate-id-aria": { + "description": "Убедитесь, что каждое значение атрибута id, используемого в ARIA и метках, уникально", + "help": "Идентификаторы, используемые в ARIA и метках, должны быть уникальными" + }, + "duplicate-id": { + "description": "Убедитесь, что каждое значение атрибута id уникально", + "help": "Значение атрибута id должно быть уникальным" + }, + "empty-heading": { + "description": "Убедитесь, что заголовки содержат различимый текст", + "help": "Заголовки не должны быть пустыми" + }, + "empty-table-header": { + "description": "Убедитесь, что заголовки таблиц содержат различимый текст", + "help": "Текст заголовка таблицы не должен быть пустым" + }, + "focus-order-semantics": { + "description": "Убедитесь, что элементы в порядке фокуса имеют роль, соответствующую интерактивному содержимому", + "help": "Элементы в порядке фокуса должны иметь соответствующую роль" + }, + "form-field-multiple-labels": { + "description": "Убедитесь, что поле формы не имеет нескольких элементов label", + "help": "Поле формы не должно иметь несколько элементов label" + }, + "frame-focusable-content": { + "description": "Убедитесь, что элементы <frame> и <iframe> с фокусируемым содержимым не имеют tabindex=-1", + "help": "Фреймы с фокусируемым содержимым не должны иметь tabindex=-1" + }, + "frame-tested": { + "description": "Убедитесь, что элементы <iframe> и <frame> содержат скрипт axe-core", + "help": "Фреймы должны быть протестированы с помощью axe-core" + }, + "frame-title-unique": { + "description": "Убедитесь, что элементы <iframe> и <frame> содержат уникальный атрибут title", + "help": "Фреймы должны иметь уникальный атрибут title" + }, + "frame-title": { + "description": "Убедитесь, что элементы <iframe> и <frame> имеют доступное имя", + "help": "Фреймы должны иметь доступное имя" + }, + "heading-order": { + "description": "Убедитесь, что порядок заголовков соответствует семантической структуре", + "help": "Уровни заголовков должны увеличиваться на единицу" + }, + "hidden-content": { + "description": "Информирует пользователей о скрытом содержимом.", + "help": "Скрытое содержимое на странице должно быть проанализировано" + }, + "html-has-lang": { + "description": "Убедитесь, что каждый HTML-документ имеет атрибут lang", + "help": "Элемент <html> должен иметь атрибут lang" + }, + "html-lang-valid": { + "description": "Убедитесь, что атрибут lang элемента <html> имеет допустимое значение", + "help": "Элемент <html> должен иметь допустимое значение для атрибута lang" + }, + "html-xml-lang-mismatch": { + "description": "Убедитесь, что HTML элементы с атрибутами lang и xml:lang согласуются в базовом языке страницы", + "help": "HTML элементы с атрибутами lang и xml:lang должны согласоваться в базовом языке" + }, + "identical-links-same-purpose": { + "description": "Убедитесь, что ссылки с одинаковым доступным именем выполняют схожую цель", + "help": "Ссылки с одинаковым именем должны выполнять схожую цель" + }, + "image-alt": { + "description": "Убедитесь, что элементы <img> имеют альтернативный текст или роль \"none\" или \"presentation\"", + "help": "Изображения должны иметь альтернативный текст" + }, + "image-redundant-alt": { + "description": "Убедитесь, что альтернативный текст изображения не повторяется в тексте", + "help": "Альтернативный текст изображения не должен повторяться в тексте" + }, + "input-button-name": { + "description": "Убедитесь, что кнопки ввода имеют различимый текст", + "help": "Кнопки ввода должны иметь различимый текст" + }, + "input-image-alt": { + "description": "Убедитесь, что элементы <input type=\"image\"> имеют альтернативный текст", + "help": "Кнопки изображения должны иметь альтернативный текст" + }, + "label-content-name-mismatch": { + "description": "Убедитесь, что элементы, маркированные через их содержимое, содержат видимый текст как часть доступного имени", + "help": "Элементы должны содержать видимый текст как часть доступного имени" + }, + "label-title-only": { + "description": "Убедитесь, что каждый элемент формы имеет видимую метку и не маркируется исключительно скрытыми метками, или атрибутами title или aria-describedby", + "help": "Элементы формы должны иметь видимую метку" + }, + "label": { + "description": "Убедитесь, что каждый элемент формы имеет метку", + "help": "Элементы формы должны иметь метки" + }, + "landmark-banner-is-top-level": { + "description": "Убедитесь, что область баннера находится на верхнем уровне", + "help": "Область баннера не должна быть вложена в другую область" + }, + "landmark-complementary-is-top-level": { + "description": "Убедитесь, что дополнительная область или aside находятся на верхнем уровне", + "help": "Aside не должен быть вложен в другую область" + }, + "landmark-contentinfo-is-top-level": { + "description": "Убедитесь, что область contentinfo находится на верхнем уровне", + "help": "Область contentinfo не должна быть вложена в другую область" + }, + "landmark-main-is-top-level": { + "description": "Убедитесь, что область main находится на верхнем уровне", + "help": "Область main не должна быть вложена в другую область" + }, + "landmark-no-duplicate-banner": { + "description": "Убедитесь, что документ содержит не более одного баннера", + "help": "Документ не должен содержать более одного баннера" + }, + "landmark-no-duplicate-contentinfo": { + "description": "Убедитесь, что документ содержит не более одной области contentinfo", + "help": "Документ не должен содержать более одной области contentinfo" + }, + "landmark-no-duplicate-main": { + "description": "Убедитесь, что документ содержит не более одной области main", + "help": "Документ не должен содержать более одной области main" + }, + "landmark-one-main": { + "description": "Убедитесь, что документ содержит одну основную область", + "help": "Документ должен содержать одну основную область" + }, + "landmark-unique": { + "description": "Убедитесь, что области уникальны", + "help": "Области должны иметь уникальную роль или комбинацию роли/метки/названия (т.е. доступное имя)" + }, + "link-in-text-block": { + "description": "Убедитесь, что ссылки выделяются на фоне окружающего текста, не полагаясь только на цвет", + "help": "Ссылки должны быть различимы без использования цвета" + }, + "link-name": { + "description": "Убедитесь, что ссылки содержат различимый текст", + "help": "Ссылки должны содержать различимый текст" + }, + "list": { + "description": "Убедитесь, что списки структурированы правильно", + "help": "Элементы <ul> и <ol> должны содержать только элементы <li>, <script> или <template>" + }, + "listitem": { + "description": "Убедитесь, что элементы <li> используются семантически правильно", + "help": "Элементы <li> должны быть вложены в <ul> или <ol>" + }, + "marquee": { + "description": "Убедитесь, что элементы <marquee> не используются", + "help": "Элементы <marquee> устарели и не должны использоваться" + }, + "meta-refresh-no-exceptions": { + "description": "Убедитесь, что <meta http-equiv=\"refresh\"> не используется для отложенного обновления", + "help": "Отложенное обновление не должно использоваться" + }, + "meta-refresh": { + "description": "Убедитесь, что <meta http-equiv=\"refresh\"> не используется для отложенного обновления", + "help": "Отложенное обновление менее 20 часов не должно использоваться" + }, + "meta-viewport-large": { + "description": "Убедитесь, что <meta name=\"viewport\"> позволяет значительное масштабирование", + "help": "Пользователи должны иметь возможность увеличивать и масштабировать текст до 500%" + }, + "meta-viewport": { + "description": "Убедитесь, что <meta name=\"viewport\"> не отключает масштабирование и увеличение текста", + "help": "Масштабирование и увеличение текста не должны быть отключены" + }, + "nested-interactive": { + "description": "Убедитесь, что интерактивные элементы не вложены, так как они могут не озвучиваться экранными считывателями или вызывать проблемы с фокусом для вспомогательных технологий", + "help": "Интерактивные элементы не должны быть вложены" + }, + "no-autoplay-audio": { + "description": "Убедитесь, что элементы <video> или <audio> не воспроизводят аудио автоматически более 3 секунд без механизма для его остановки или отключения", + "help": "Элементы <video> или <audio> не должны воспроизводиться автоматически" + }, + "object-alt": { + "description": "Убедитесь, что элементы <object> имеют альтернативный текст", + "help": "Элементы <object> должны иметь альтернативный текст" + }, + "p-as-heading": { + "description": "Убедитесь, что текст, оформленный как жирный, курсивный или с измененным размером шрифта, не используется для оформления элементов <p> в качестве заголовков", + "help": "Оформленные элементы <p> не должны использоваться как заголовки" + }, + "page-has-heading-one": { + "description": "Убедитесь, что страница или хотя бы один из ее фреймов содержит заголовок первого уровня", + "help": "Страница должна содержать заголовок первого уровня" + }, + "presentation-role-conflict": { + "description": "Элементы, отмеченные как презентационные, не должны иметь глобальные ARIA атрибуты или tabindex, чтобы все экранные считыватели игнорировали их", + "help": "Убедитесь, что элементы, отмеченные как презентационные, последовательно игнорируются" + }, + "region": { + "description": "Убедитесь, что все содержимое страницы заключено в ориентиры", + "help": "Все содержимое страницы должно быть заключено в ориентиры" + }, + "role-img-alt": { + "description": "Убедитесь, что элементы с ролью [role=\"img\"] имеют альтернативный текст", + "help": "Элементы с ролью [role=\"img\"] должны иметь альтернативный текст" + }, + "scope-attr-valid": { + "description": "Убедитесь, что атрибут scope используется правильно в таблицах", + "help": "Атрибут scope должен использоваться правильно" + }, + "scrollable-region-focusable": { + "description": "Убедитесь, что элементы с прокручиваемым содержимым доступны с клавиатуры", + "help": "Прокручиваемая область должна быть доступна с клавиатуры" + }, + "select-name": { + "description": "Убедитесь, что элемент select имеет доступное имя", + "help": "Элемент select должен иметь доступное имя" + }, + "server-side-image-map": { + "description": "Убедитесь, что серверные карты изображений не используются", + "help": "Серверные карты изображений не должны использоваться" + }, + "skip-link": { + "description": "Убедитесь, что все ссылки для пропуска имеют фокусируемую цель", + "help": "Цель ссылки для пропуска должна существовать и быть фокусируемой" + }, + "summary-name": { + "description": "Убедитесь, что элементы summary содержат различимый текст", + "help": "Элементы summary должны содержать различимый текст" + }, + "svg-img-alt": { + "description": "Убедитесь, что элементы <svg> с ролью img, graphics-document или graphics-symbol имеют доступный текст", + "help": "Элементы <svg> с ролью img должны иметь альтернативный текст" + }, + "tabindex": { + "description": "Убедитесь, что значения атрибута tabindex не превышают 0", + "help": "Элементы не должны иметь tabindex больше нуля" + }, + "table-duplicate-name": { + "description": "Убедитесь, что элемент <caption> не содержит тот же текст, что и атрибут summary", + "help": "Таблицы не должны иметь одинаковый summary и caption" + }, + "table-fake-caption": { + "description": "Убедитесь, что таблицы с заголовком используют элемент <caption>", + "help": "Данные или заголовочные ячейки не должны использоваться для заголовка таблицы" + }, + "target-size": { + "description": "Убедитесь, что целевые элементы для касания имеют достаточный размер и пространство", + "help": "Все целевые элементы для касания должны быть не менее 24px или иметь достаточное пространство" + }, + "td-has-header": { + "description": "Убедитесь, что каждая непустая ячейка данных в таблице больше 3 на 3 имеет один или несколько заголовков таблицы", + "help": "Непустые элементы <td> в больших таблицах должны иметь связанные заголовки таблицы" + }, + "td-headers-attr": { + "description": "Убедитесь, что каждая ячейка в таблице, использующая атрибут headers, ссылается только на другие элементы <th> в этой таблице", + "help": "Атрибуты headers ячеек таблицы должны ссылаться на другие элементы <th> в той же таблице" + }, + "th-has-data-cells": { + "description": "Убедитесь, что элементы <th> и элементы с ролью columnheader/rowheader имеют ячейки данных, которые они описывают", + "help": "Заголовки таблицы в таблице данных должны ссылаться на ячейки данных" + }, + "valid-lang": { + "description": "Убедитесь, что атрибуты lang имеют допустимые значения", + "help": "Атрибут lang должен иметь допустимое значение" + }, + "video-caption": { + "description": "Убедитесь, что элементы <video> имеют субтитры", + "help": "Элементы <video> должны иметь субтитры" + } + }, + "checks": { + "abstractrole": { + "pass": "Абстрактные роли не используются", + "fail": { + "singular": "Абстрактная роль не может быть использована напрямую: ${data.values}", + "plural": "Абстрактные роли не могут быть использованы напрямую: ${data.values}" + } + }, + "aria-allowed-attr": { + "pass": "ARIA атрибуты используются правильно для заданной роли", + "fail": { + "singular": "ARIA атрибут не допускается: ${data.values}", + "plural": "ARIA атрибуты не допускаются: ${data.values}" + }, + "incomplete": "Проверьте, не возникает ли проблема, если атрибут ARIA будет проигнорирован на этом элементе: ${data.values}" + }, + "aria-allowed-role": { + "pass": "ARIA роль допустима для данного элемента", + "fail": { + "singular": "ARIA роль ${data.values} не допускается для данного элемента", + "plural": "ARIA роли ${data.values} не допускаются для данного элемента" + }, + "incomplete": { + "singular": "ARIA роль ${data.values} должна быть удалена, когда элемент становится видимым, так как она не допускается для элемента", + "plural": "ARIA роли ${data.values} должны быть удалены, когда элемент становится видимым, так как они не допускаются для элемента" + } + }, + "aria-busy": { + "pass": "Элемент имеет атрибут aria-busy", + "fail": "Элемент использует aria-busy=\"true\", пока отображается индикатор загрузки" + }, + "aria-conditional-attr": { + "pass": "ARIA атрибут допустим", + "fail": { + "checkbox": "Удалите aria-checked или установите его значение в \"${data.checkState}\", чтобы оно соответствовало фактическому состоянию флажка", + "rowSingular": "Этот атрибут поддерживается для строк treegrid, но не для ${data.ownerRole}: ${data.invalidAttrs}", + "rowPlural": "Эти атрибуты поддерживаются для строк treegrid, но не для ${data.ownerRole}: ${data.invalidAttrs}" + } + }, + "aria-errormessage": { + "pass": "aria-errormessage существует и ссылается на элементы, видимые для экранных считывателей, которые используют поддерживаемую технику aria-errormessage", + "fail": { + "singular": "Значение aria-errormessage `${data.values}` должно использовать технику для объявления сообщения (например, aria-live, aria-describedby, role=alert и т.д.)", + "plural": "Значения aria-errormessage `${data.values}` должны использовать технику для объявления сообщения (например, aria-live, aria-describedby, role=alert и т.д.)", + "hidden": "Значение aria-errormessage `${data.values}` не может ссылаться на скрытый элемент" + }, + "incomplete": { + "singular": "Убедитесь, что значение aria-errormessage `${data.values}` ссылается на существующий элемент", + "plural": "Убедитесь, что значения aria-errormessage `${data.values}` ссылаются на существующие элементы", + "idrefs": "Невозможно определить, существует ли элемент aria-errormessage на странице: ${data.values}" + } + }, + "aria-hidden-body": { + "pass": "Атрибут aria-hidden отсутствует на теле документа", + "fail": "aria-hidden=true не должно присутствовать на теле документа" + }, + "aria-level": { + "pass": "Значения aria-level допустимы", + "incomplete": "Значения aria-level больше 6 не поддерживаются всеми комбинациями экранных считывателей и браузеров" + }, + "aria-prohibited-attr": { + "pass": "ARIA атрибут допустим", + "fail": { + "hasRolePlural": "Атрибуты ${data.prohibited} не могут использоваться с ролью \"${data.role}\".", + "hasRoleSingular": "Атрибут ${data.prohibited} не может использоваться с ролью \"${data.role}\".", + "noRolePlural": "Атрибуты ${data.prohibited} не могут использоваться на ${data.nodeName} без допустимого атрибута role.", + "noRoleSingular": "Атрибут ${data.prohibited} не может использоваться на ${data.nodeName} без допустимого атрибута role." + }, + "incomplete": { + "hasRoleSingular": "Атрибут ${data.prohibited} не поддерживается с ролью \"${data.role}\".", + "hasRolePlural": "Атрибуты ${data.prohibited} не поддерживаются с ролью \"${data.role}\".", + "noRoleSingular": "Атрибут ${data.prohibited} не поддерживается на ${data.nodeName} без допустимого атрибута role.", + "noRolePlural": "Атрибуты ${data.prohibited} не поддерживаются на ${data.nodeName} без допустимого атрибута role." + } + }, + "aria-required-attr": { + "pass": "Все необходимые ARIA атрибуты присутствуют", + "fail": { + "singular": "Необходимый ARIA атрибут отсутствует: ${data.values}", + "plural": "Необходимые ARIA атрибуты отсутствуют: ${data.values}" + } + }, + "aria-required-children": { + "pass": { + "default": "Необходимые ARIA дочерние элементы присутствуют", + "aria-busy": "Элемент имеет атрибут aria-busy, поэтому разрешено пропускать необходимые дочерние элементы" + }, + "fail": { + "singular": "Необходимая ARIA дочерняя роль отсутствует: ${data.values}", + "plural": "Необходимые ARIA дочерние роли отсутствуют: ${data.values}", + "unallowed": "Элемент имеет недопустимые дочерние элементы: ${data.values}" + }, + "incomplete": { + "singular": "Ожидается добавление ARIA дочерней роли: ${data.values}", + "plural": "Ожидается добавление ARIA дочерних ролей: ${data.values}" + } + }, + "aria-required-parent": { + "pass": "Необходимая ARIA родительская роль присутствует", + "fail": { + "singular": "Необходимая ARIA родительская роль отсутствует: ${data.values}", + "plural": "Необходимые ARIA родительские роли отсутствуют: ${data.values}" + } + }, + "aria-roledescription": { + "pass": "aria-roledescription используется на поддерживаемой семантической роли", + "incomplete": "Проверьте, объявляется ли aria-roledescription поддерживаемыми экранными считывателями", + "fail": "Назначьте элементу роль, поддерживающую aria-roledescription" + }, + "aria-unsupported-attr": { + "pass": "ARIA атрибут поддерживается", + "fail": "ARIA атрибут не поддерживается в большинстве экранных считывателей и вспомогательных технологий: ${data.values}" + }, + "aria-valid-attr-value": { + "pass": "Значения ARIA атрибутов допустимы", + "fail": { + "singular": "Недопустимое значение ARIA атрибута: ${data.values}", + "plural": "Недопустимые значения ARIA атрибутов: ${data.values}" + }, + "incomplete": { + "noId": "Элемент ID атрибута ARIA не существует на странице: ${data.needsReview}", + "noIdShadow": "Элемент ID атрибута ARIA не существует на странице или является потомком другого дерева теневых DOM: ${data.needsReview}", + "ariaCurrent": "Значение атрибута ARIA недопустимо и будет трактоваться как \"aria-current=true\": ${data.needsReview}", + "idrefs": "Невозможно определить, существует ли элемент ID атрибута ARIA на странице: ${data.needsReview}", + "empty": "Значение атрибута ARIA игнорируется, если оно пустое: ${data.needsReview}", + "controlsWithinPopup": "Невозможно определить, существует ли ссылка на ID атрибута aria-controls на странице при использовании aria-haspopup: ${data.needsReview}" + } + }, + "aria-valid-attr": { + "pass": "Имя ARIA атрибута допустимо", + "fail": { + "singular": "Недопустимое имя ARIA атрибута: ${data.values}", + "plural": "Недопустимые имена ARIA атрибутов: ${data.values}" + } + }, + "braille-label-equivalent": { + "pass": "aria-braillelabel используется на элементе с доступным текстом", + "fail": "aria-braillelabel используется на элементе без доступного текста", + "incomplete": "Не удалось вычислить доступный текст" + }, + "braille-roledescription-equivalent": { + "pass": "aria-brailleroledescription используется на элементе с aria-roledescription", + "fail": { + "noRoleDescription": "aria-brailleroledescription используется на элементе без aria-roledescription", + "emptyRoleDescription": "aria-brailleroledescription используется на элементе с пустым aria-roledescription" + } + }, + "deprecatedrole": { + "pass": "ARIA роль не устарела", + "fail": "Используемая роль устарела: ${data}" + }, + "fallbackrole": { + "pass": "Используется только одно значение роли", + "fail": "Используйте только одно значение роли, так как резервные роли не поддерживаются в старых браузерах", + "incomplete": "Используйте только роль 'presentation' или 'none', так как они являются синонимами." + }, + "has-global-aria-attribute": { + "pass": { + "singular": "Элемент имеет глобальный ARIA атрибут: ${data.values}", + "plural": "Элемент имеет глобальные ARIA атрибуты: ${data.values}" + }, + "fail": "Элемент не имеет глобального ARIA атрибута" + }, + "has-widget-role": { + "pass": "Элемент имеет роль виджета.", + "fail": "Элемент не имеет роли виджета." + }, + "invalidrole": { + "pass": "ARIA роль допустима", + "fail": { + "singular": "Роль должна быть одной из допустимых ARIA ролей: ${data.values}", + "plural": "Роли должны быть одной из допустимых ARIA ролей: ${data.values}" + } + }, + "is-element-focusable": { + "pass": "Элемент может быть сфокусирован.", + "fail": "Элемент не может быть сфокусирован." + }, + "no-implicit-explicit-label": { + "pass": "Нет несоответствия между <label> и доступным именем", + "incomplete": "Проверьте, нужно ли, чтобы <label> был частью имени поля ARIA ${data}" + }, + "unsupportedrole": { + "pass": "ARIA роль поддерживается", + "fail": "Используемая роль не поддерживается большинством экранных считывателей и вспомогательных технологий: ${data}" + }, + "valid-scrollable-semantics": { + "pass": "Элемент имеет допустимую семантику для элемента в порядке фокусировки.", + "fail": "Элемент имеет недопустимую семантику для элемента в порядке фокусировки." + }, + "color-contrast-enhanced": { + "pass": "Элемент имеет достаточный цветовой контраст ${data.contrastRatio}", + "fail": { + "default": "Элемент имеет недостаточный цветовой контраст ${data.contrastRatio} (цвет переднего плана: ${data.fgColor}, цвет фона: ${data.bgColor}, размер шрифта: ${data.fontSize}, толщина шрифта: ${data.fontWeight}). Ожидаемый коэффициент контрастности ${data.expectedContrastRatio}", + "fgOnShadowColor": "Элемент имеет недостаточный цветовой контраст ${data.contrastRatio} между цветом переднего плана и тенью (цвет переднего плана: ${data.fgColor}, цвет текстовой тени: ${data.shadowColor}, размер шрифта: ${data.fontSize}, толщина шрифта: ${data.fontWeight}). Ожидаемый коэффициент контрастности ${data.expectedContrastRatio}", + "shadowOnBgColor": "Элемент имеет недостаточный цветовой контраст ${data.contrastRatio} между цветом тени и фоном (цвет текстовой тени: ${data.shadowColor}, цвет фона: ${data.bgColor}, размер шрифта: ${data.fontSize}, толщина шрифта: ${data.fontWeight}). Ожидаемый коэффициент контрастности ${data.expectedContrastRatio}" + }, + "incomplete": { + "default": "Невозможно определить коэффициент контрастности", + "bgImage": "Невозможно определить цвет фона элемента из-за изображения на фоне", + "bgGradient": "Невозможно определить цвет фона элемента из-за градиента на фоне", + "imgNode": "Невозможно определить цвет фона элемента, так как он содержит изображение", + "bgOverlap": "Невозможно определить цвет фона элемента, так как он перекрыт другим элементом", + "fgAlpha": "Невозможно определить цвет переднего плана элемента из-за прозрачности альфа-канала", + "elmPartiallyObscured": "Невозможно определить цвет фона элемента, так как он частично перекрыт другим элементом", + "elmPartiallyObscuring": "Невозможно определить цвет фона элемента, так как он частично перекрывает другие элементы", + "outsideViewport": "Невозможно определить цвет фона элемента, так как он находится за пределами видимой области", + "equalRatio": "Элемент имеет коэффициент контрастности 1:1 с фоном", + "shortTextContent": "Содержимое элемента слишком короткое, чтобы определить, является ли оно текстом", + "nonBmp": "Содержимое элемента содержит только не текстовые символы", + "pseudoContent": "Невозможно определить цвет фона элемента из-за псевдоэлемента" + } + }, + "color-contrast": { + "pass": { + "default": "Элемент имеет достаточный цветовой контраст ${data.contrastRatio}", + "hidden": "Элемент скрыт" + }, + "fail": { + "default": "Элемент имеет недостаточный цветовой контраст ${data.contrastRatio} (цвет переднего плана: ${data.fgColor}, цвет фона: ${data.bgColor}, размер шрифта: ${data.fontSize}, толщина шрифта: ${data.fontWeight}). Ожидаемый коэффициент контрастности ${data.expectedContrastRatio}", + "fgOnShadowColor": "Элемент имеет недостаточный цветовой контраст ${data.contrastRatio} между цветом переднего плана и тенью (цвет переднего плана: ${data.fgColor}, цвет текстовой тени: ${data.shadowColor}, размер шрифта: ${data.fontSize}, толщина шрифта: ${data.fontWeight}). Ожидаемый коэффициент контрастности ${data.expectedContrastRatio}", + "shadowOnBgColor": "Элемент имеет недостаточный цветовой контраст ${data.contrastRatio} между цветом тени и фоном (цвет текстовой тени: ${data.shadowColor}, цвет фона: ${data.bgColor}, размер шрифта: ${data.fontSize}, толщина шрифта: ${data.fontWeight}). Ожидаемый коэффициент контрастности ${data.expectedContrastRatio}" + }, + "incomplete": { + "default": "Невозможно определить коэффициент контрастности", + "bgImage": "Невозможно определить цвет фона элемента из-за изображения на фоне", + "bgGradient": "Невозможно определить цвет фона элемента из-за градиента на фоне", + "imgNode": "Невозможно определить цвет фона элемента, так как он содержит изображение", + "bgOverlap": "Невозможно определить цвет фона элемента, так как он перекрыт другим элементом", + "complexTextShadows": "Невозможно определить контрастность элемента из-за сложных теней текста", + "fgAlpha": "Невозможно определить цвет переднего плана элемента из-за прозрачности альфа-канала", + "elmPartiallyObscured": "Невозможно определить цвет фона элемента, так как он частично перекрыт другим элементом", + "elmPartiallyObscuring": "Невозможно определить цвет фона элемента, так как он частично перекрывает другие элементы", + "outsideViewport": "Невозможно определить цвет фона элемента, так как он находится за пределами видимой области", + "equalRatio": "Элемент имеет коэффициент контрастности 1:1 с фоном", + "shortTextContent": "Содержимое элемента слишком короткое, чтобы определить, является ли оно текстом", + "nonBmp": "Содержимое элемента содержит только не текстовые символы", + "pseudoContent": "Невозможно определить цвет фона элемента из-за псевдоэлемента" + } + }, + "link-in-text-block-style": { + "pass": "Ссылки могут быть выделены среди окружающего текста с помощью визуального стиля", + "incomplete": { + "default": "Проверьте, нужно ли оформлять ссылку, чтобы отличить её от окружающего текста", + "pseudoContent": "Проверьте, достаточно ли псевдо-стиля ссылки, чтобы отличить её от окружающего текста" + }, + "fail": "Ссылка не имеет стиля (например, подчеркивания), чтобы отличить её от окружающего текста" + }, + "link-in-text-block": { + "pass": "Ссылки можно отличить от окружающего текста каким-либо способом, кроме цвета", + "fail": { + "fgContrast": "У ссылки недостаточный цветовой контраст ${data.contrastRatio}:1 с окружающим текстом. (Минимальный контраст ${data.requiredContrastRatio}:1, текст ссылки: ${data.nodeColor}, окружающий текст: ${data.parentColor})", + "bgContrast": "Фон ссылки имеет недостаточный цветовой контраст ${data.contrastRatio} (Минимальный контраст ${data.requiredContrastRatio}:1, цвет фона ссылки: ${data.nodeBackgroundColor}, цвет фона окружающего текста: ${data.parentBackgroundColor})" + }, + "incomplete": { + "default": "Невозможно определить контрастность переднего плана элемента", + "bgContrast": "Невозможно определить контрастность фона элемента", + "bgImage": "Невозможно определить контрастность элемента из-за изображения на фоне", + "bgGradient": "Невозможно определить контрастность элемента из-за градиента на фоне", + "imgNode": "Невозможно определить контрастность элемента, так как он содержит изображение", + "bgOverlap": "Невозможно определить контрастность элемента, так как он перекрыт другим элементом" + } + }, + "autocomplete-appropriate": { + "pass": "Значение autocomplete подходит для данного элемента", + "fail": "Значение autocomplete не подходит для этого типа ввода" + }, + "autocomplete-valid": { + "pass": "Атрибут autocomplete правильно отформатирован", + "fail": "Атрибут autocomplete неправильно отформатирован", + "incomplete": "Атрибут autocomplete имеет нестандартное значение. Проверьте, можно ли использовать вместо него какое-либо стандартное значение." + }, + "accesskeys": { + "pass": "Значение атрибута accesskey уникально", + "fail": "Документ содержит несколько элементов с одинаковым значением accesskey" + }, + "focusable-content": { + "pass": "Элемент содержит фокусируемые элементы", + "fail": "Элемент должен содержать фокусируемое содержимое" + }, + "focusable-disabled": { + "pass": "Внутри элемента нет фокусируемых элементов", + "incomplete": "Проверьте, немедленно ли индикатор фокуса перемещается на фокусируемые элементы", + "fail": "Фокусируемое содержимое должно быть отключено или удалено из DOM" + }, + "focusable-element": { + "pass": "Элемент является фокусируемым", + "fail": "Элемент должен быть фокусируемым" + }, + "focusable-modal-open": { + "pass": "Нет фокусируемых элементов при открытии модального окна", + "incomplete": "Проверьте, что фокусируемые элементы не являются доступными в текущем состоянии" + }, + "focusable-no-name": { + "pass": "Элемент не находится в таб-ордре или имеет доступный текст", + "fail": "Элемент находится в таб-ордре и не имеет доступного текста", + "incomplete": "Невозможно определить, есть ли у элемента доступное имя" + }, + "focusable-not-tabbable": { + "pass": "Внутри элемента нет фокусируемых элементов", + "incomplete": "Проверьте, немедленно ли индикатор фокуса перемещается на фокусируемые элементы", + "fail": "Фокусируемое содержимое должно иметь tabindex=\"-1\" или быть удалено из DOM" + }, + "frame-focusable-content": { + "pass": "Элемент не имеет фокусируемых потомков", + "fail": "Элемент имеет фокусируемых потомков", + "incomplete": "Невозможно определить, есть ли у элемента потомки" + }, + "landmark-is-top-level": { + "pass": "${data.role} область находится на верхнем уровне.", + "fail": "${data.role} область содержится в другой области." + }, + "no-focusable-content": { + "pass": "Элемент не имеет фокусируемых потомков", + "fail": { + "default": "Элемент имеет фокусируемых потомков", + "notHidden": "Использование отрицательного tabindex на элементе внутри интерактивного управления не предотвращает фокусировку элемента вспомогательными технологиями (даже с aria-hidden=\"true\")" + }, + "incomplete": "Невозможно определить, есть ли у элемента потомки" + }, + "page-has-heading-one": { + "pass": "На странице есть хотя бы один заголовок первого уровня", + "fail": "На странице должен быть заголовок первого уровня" + }, + "page-has-main": { + "pass": "В документе есть хотя бы одна основная область", + "fail": "В документе нет основной области" + }, + "page-no-duplicate-banner": { + "pass": "В документе нет более одного баннера", + "fail": "В документе более одного баннера" + }, + "page-no-duplicate-contentinfo": { + "pass": "В документе нет более одной области contentinfo", + "fail": "В документе более одной области contentinfo" + }, + "page-no-duplicate-main": { + "pass": "В документе нет более одной основной области", + "fail": "В документе более одной основной области" + }, + "tabindex": { + "pass": "Элемент не имеет tabindex больше 0", + "fail": "Элемент имеет tabindex больше 0" + }, + "alt-space-value": { + "pass": "Элемент имеет допустимое значение атрибута alt", + "fail": "Элемент имеет атрибут alt, содержащий только пробельный символ, который не игнорируется всеми экранными считывателями" + }, + "duplicate-img-label": { + "pass": "Элемент не дублирует существующий текст в тексте атрибута alt <img>", + "fail": "Элемент содержит <img> с текстом атрибута alt, дублирующим существующий текст" + }, + "explicit-label": { + "pass": "Элемент формы имеет явную <label>", + "fail": "Элемент формы не имеет явной <label>", + "incomplete": "Невозможно определить, имеет ли элемент формы явную <label>" + }, + "help-same-as-label": { + "pass": "Текст помощи (title или aria-describedby) не дублирует текст метки", + "fail": "Текст помощи (title или aria-describedby) совпадает с текстом метки" + }, + "hidden-explicit-label": { + "pass": "Элемент формы имеет видимую явную <label>", + "fail": "Элемент формы имеет явную <label>, которая скрыта", + "incomplete": "Невозможно определить, имеет ли элемент формы явную <label>, которая скрыта" + }, + "implicit-label": { + "pass": "Элемент формы имеет неявную (обернутую) <label>", + "fail": "Элемент формы не имеет неявной (обернутой) <label>", + "incomplete": "Невозможно определить, имеет ли элемент формы неявную (обернутую) <label>" + }, + "label-content-name-mismatch": { + "pass": "Элемент содержит видимый текст как часть его доступного имени", + "fail": "Текст внутри элемента не включен в доступное имя" + }, + "multiple-label": { + "pass": "Поле формы не имеет нескольких элементов label", + "incomplete": "Использование нескольких элементов label не поддерживается большинством вспомогательных технологий. Убедитесь, что первый элемент label содержит всю необходимую информацию." + }, + "title-only": { + "pass": "Элемент формы не использует только атрибут title для своей метки", + "fail": "Для создания метки элемента формы используется только атрибут title" + }, + "landmark-is-unique": { + "pass": "Ориентиры должны иметь уникальную роль или комбинацию роли/метки/названия (т.е. доступное имя)", + "fail": "Ориентир должен иметь уникальный aria-label, aria-labelledby или title, чтобы сделать ориентиры различимыми" + }, + "has-lang": { + "pass": "Элемент <html> имеет атрибут lang", + "fail": { + "noXHTML": "Атрибут xml:lang недействителен на HTML страницах, используйте атрибут lang.", + "noLang": "Элемент <html> не имеет атрибута lang" + } + }, + "valid-lang": { + "pass": "Значение атрибута lang включено в список допустимых языков", + "fail": "Значение атрибута lang не включено в список допустимых языков" + }, + "xml-lang-mismatch": { + "pass": "Атрибуты lang и xml:lang имеют один и тот же базовый язык", + "fail": "Атрибуты lang и xml:lang не имеют один и тот же базовый язык" + }, + "dlitem": { + "pass": "Элемент описания списка имеет родительский элемент <dl>", + "fail": "Элемент описания списка не имеет родительского элемента <dl>" + }, + "listitem": { + "pass": "Элемент списка имеет родительский элемент <ul>, <ol> или роль=\"list\"", + "fail": { + "default": "Элемент списка не имеет родительского элемента <ul>, <ol>", + "roleNotValid": "Родительский элемент списка имеет роль, которая не является ролью=\"list\"" + } + }, + "only-dlitems": { + "pass": "Элемент dl содержит только допустимые дочерние элементы; <dt>, <dd> или <div> элементы", + "fail": "Элемент dl содержит недопустимые дочерние элементы: ${data.values}" + }, + "only-listitems": { + "pass": "Элемент списка содержит только допустимые дочерние элементы <li>", + "fail": "Элемент списка содержит недопустимые дочерние элементы: ${data.values}" + }, + "structured-dlitems": { + "pass": "Когда элемент не пустой, он имеет как минимум один элемент <dt> и один элемент <dd>", + "fail": "Когда элемент не пустой, он не содержит по крайней мере одного элемента <dt>, за которым следует по крайней мере один элемент <dd>" + }, + "caption": { + "pass": "Мультимедийный элемент имеет дорожку субтитров", + "incomplete": "Проверьте, доступны ли субтитры для элемента" + }, + "frame-tested": { + "pass": "Элемент iframe был протестирован с помощью axe-core", + "fail": "Не удалось протестировать элемент iframe с помощью axe-core", + "incomplete": "Элемент iframe все еще должен быть протестирован с помощью axe-core" + }, + "no-autoplay-audio": { + "pass": "<video> или <audio> не воспроизводит аудио более допустимой продолжительности или имеет механизмы управления", + "fail": "<video> или <audio> воспроизводит аудио более допустимой продолжительности и не имеет механизмов управления", + "incomplete": "Проверьте, не воспроизводит ли <video> или <audio> аудио более допустимой продолжительности или предоставляет ли механизмы управления" + }, + "css-orientation-lock": { + "pass": "Дисплей работает, блокировка ориентации отсутствует", + "fail": "CSS блокировка ориентации применяется и делает дисплей неработоспособным", + "incomplete": "Невозможно определить, применяется ли CSS блокировка ориентации" + }, + "meta-viewport-large": { + "pass": "Тег <meta> не предотвращает значительное масштабирование на мобильных устройствах", + "fail": "Тег <meta> ограничивает масштабирование на мобильных устройствах" + }, + "meta-viewport": { + "pass": "Тег <meta> не отключает масштабирование на мобильных устройствах", + "fail": "${data} на теге <meta> отключает масштабирование на мобильных устройствах" + }, + "target-offset": { + "pass": { + "default": "Целевой элемент имеет достаточное пространство от ближайших соседей. Безопасное кликабельное пространство имеет диаметр ${data.closestOffset}px, что не менее ${data.minOffset}px.", + "large": "Целевой элемент значительно превышает минимальный размер в ${data.minOffset}px." + }, + "fail": "Целевой элемент имеет недостаточное пространство до ближайших соседей. Безопасное кликабельное пространство имеет диаметр ${data.closestOffset}px вместо как минимум ${data.minOffset}px.", + "incomplete": { + "default": "Элемент с отрицательным tabindex имеет недостаточное пространство до ближайших соседей. Безопасное кликабельное пространство имеет диаметр ${data.closestOffset}px вместо как минимум ${data.minOffset}px. Является ли это целевым элементом?", + "nonTabbableNeighbor": "Целевой элемент имеет недостаточное пространство до ближайших соседей. Безопасное кликабельное пространство имеет диаметр ${data.closestOffset}px вместо как минимум ${data.minOffset}px. Является ли сосед целевым элементом?", + "tooManyRects": "Не удалось определить размер целевого элемента из-за слишком большого количества перекрывающихся элементов" + } + }, + "target-size": { + "pass": { + "default": "Контрол имеет достаточный размер (${data.width}px на ${data.height}px, должно быть как минимум ${data.minSize}px на ${data.minSize}px)", + "obscured": "Контрол игнорируется, так как он полностью скрыт и, следовательно, не кликабелен", + "large": "Целевой элемент значительно превышает минимальный размер в ${data.minSize}px." + }, + "fail": { + "default": "Целевой элемент имеет недостаточный размер (${data.width}px на ${data.height}px, должно быть как минимум ${data.minSize}px на ${data.minSize}px)", + "partiallyObscured": "Целевой элемент имеет недостаточный размер, так как он частично скрыт (наименьшее пространство ${data.width}px на ${data.height}px, должно быть как минимум ${data.minSize}px на ${data.minSize}px)" + }, + "incomplete": { + "default": "Элемент с отрицательным tabindex имеет недостаточный размер (${data.width}px на ${data.height}px, должно быть как минимум ${data.minSize}px на ${data.minSize}px). Является ли это целевым элементом?", + "contentOverflow": "Размер элемента не может быть точно определен из-за переполненного содержимого", + "partiallyObscured": "Элемент с отрицательным tabindex имеет недостаточный размер, так как он частично скрыт (наименьшее пространство ${data.width}px на ${data.height}px, должно быть как минимум ${data.minSize}px на ${data.minSize}px). Является ли это целевым элементом?", + "partiallyObscuredNonTabbable": "Целевой элемент имеет недостаточный размер, так как он частично скрыт соседом с отрицательным tabindex (наименьшее пространство ${data.width}px на ${data.height}px, должно быть как минимум ${data.minSize}px на ${data.minSize}px). Является ли сосед целевым элементом?", + "tooManyRects": "Не удалось определить размер целевого элемента из-за слишком большого количества перекрывающихся элементов" + } + }, + "header-present": { + "pass": "На странице есть заголовок", + "fail": "На странице нет заголовка" + }, + "heading-order": { + "pass": "Порядок заголовков корректен", + "fail": "Порядок заголовков некорректен", + "incomplete": "Невозможно определить предыдущий заголовок" + }, + "identical-links-same-purpose": { + "pass": "Нет других ссылок с тем же именем, которые ведут на другой URL", + "incomplete": "Проверьте, имеют ли ссылки одинаковую цель, или они намеренно неоднозначны." + }, + "internal-link-present": { + "pass": "Найдена допустимая ссылка для пропуска", + "fail": "Допустимая ссылка для пропуска не найдена" + }, + "landmark": { + "pass": "На странице есть область-ориентир", + "fail": "На странице нет области-ориентира" + }, + "meta-refresh-no-exceptions": { + "pass": "Тег <meta> не вызывает немедленное обновление страницы", + "fail": "Тег <meta> вызывает обновление страницы по таймеру" + }, + "meta-refresh": { + "pass": "Тег <meta> не вызывает немедленное обновление страницы", + "fail": "Тег <meta> вызывает обновление страницы по таймеру (менее 20 часов)" + }, + "p-as-heading": { + "pass": "Элементы <p> не оформлены как заголовки", + "fail": "Для заголовков должны использоваться элементы <h1> - <h6>, а не стилизованные <p>", + "incomplete": "Невозможно определить, оформлены ли элементы <p> как заголовки" + }, + "region": { + "pass": "Все содержимое страницы заключено в ориентиры", + "fail": "Некоторое содержимое страницы не заключено в ориентиры" + }, + "skip-link": { + "pass": "Целевая ссылка для пропуска существует", + "incomplete": "Целевая ссылка для пропуска должна стать видимой при активации", + "fail": "Целевая ссылка для пропуска не найдена" + }, + "unique-frame-title": { + "pass": "Атрибут title элемента является уникальным", + "fail": "Атрибут title элемента не является уникальным" + }, + "duplicate-id-active": { + "pass": "Документ не содержит активных элементов с одинаковым значением id атрибута", + "fail": "Документ содержит активные элементы с одинаковым значением id атрибута: ${data}" + }, + "duplicate-id-aria": { + "pass": "Документ не содержит элементов, ссылающихся на ARIA или метки с одинаковым значением id атрибута", + "fail": "Документ содержит несколько элементов, ссылающихся на ARIA, с одинаковым значением id атрибута: ${data}" + }, + "duplicate-id": { + "pass": "Документ не содержит статических элементов с одинаковым значением id атрибута", + "fail": "Документ содержит несколько статических элементов с одинаковым значением id атрибута: ${data}" + }, + "aria-label": { + "pass": "Атрибут aria-label существует и не пуст", + "fail": "Атрибут aria-label не существует или пуст" + }, + "aria-labelledby": { + "pass": "Атрибут aria-labelledby существует и ссылается на элементы, видимые для экранных считывателей", + "fail": "Атрибут aria-labelledby не существует, ссылается на несуществующие элементы или ссылается на пустые элементы", + "incomplete": "Убедитесь, что aria-labelledby ссылается на существующий элемент" + }, + "avoid-inline-spacing": { + "pass": "Внутренние стили с '!important', которые влияют на интервал текста, не указаны", + "fail": { + "singular": "Удалите '!important' из внутреннего стиля ${data.values}, так как переопределение этого стиля не поддерживается большинством браузеров", + "plural": "Удалите '!important' из внутренних стилей ${data.values}, так как переопределение этих стилей не поддерживается большинством браузеров" + } + }, + "button-has-visible-text": { + "pass": "Элемент содержит внутренний текст, видимый для экранных считывателей", + "fail": "Элемент не содержит внутренний текст, видимый для экранных считывателей", + "incomplete": "Невозможно определить, есть ли у элемента дочерние элементы" + }, + "doc-has-title": { + "pass": "Документ содержит непустой элемент <title>", + "fail": "Документ не содержит непустой элемент <title>" + }, + "exists": { + "pass": "Элемент не существует", + "incomplete": "Элемент существует" + }, + "has-alt": { + "pass": "Элемент имеет атрибут alt", + "fail": "Элемент не имеет атрибута alt" + }, + "has-visible-text": { + "pass": "Элемент содержит текст, видимый для экранных считывателей", + "fail": "Элемент не содержит текст, видимый для экранных считывателей", + "incomplete": "Невозможно определить, есть ли у элемента дочерние элементы" + }, + "important-letter-spacing": { + "pass": "Letter-spacing в атрибуте стиля не установлен на !important, либо соответствует минимальному значению", + "fail": "Letter-spacing в атрибуте стиля не должен использовать !important, или должен быть не менее ${data.minValue}em (текущее значение ${data.value}em)" + }, + "important-line-height": { + "pass": "Line-height в атрибуте стиля не установлен на !important, либо соответствует минимальному значению", + "fail": "Line-height в атрибуте стиля не должен использовать !important, или должен быть не менее ${data.minValue}em (текущее значение ${data.value}em)" + }, + "important-word-spacing": { + "pass": "Word-spacing в атрибуте стиля не установлен на !important, либо соответствует минимальному значению", + "fail": "Word-spacing в атрибуте стиля не должен использовать !important, или должен быть не менее ${data.minValue}em (текущее значение ${data.value}em)" + }, + "is-on-screen": { + "pass": "Элемент не виден", + "fail": "Элемент виден" + }, + "non-empty-alt": { + "pass": "Элемент имеет непустой атрибут alt", + "fail": { + "noAttr": "Элемент не имеет атрибута alt", + "emptyAttr": "Элемент имеет пустой атрибут alt" + } + }, + "non-empty-if-present": { + "pass": { + "default": "Элемент не имеет атрибута value", + "has-label": "Элемент имеет непустой атрибут value" + }, + "fail": "Элемент имеет атрибут value, и этот атрибут пуст" + }, + "non-empty-placeholder": { + "pass": "Элемент имеет атрибут placeholder", + "fail": { + "noAttr": "Элемент не имеет атрибута placeholder", + "emptyAttr": "Элемент имеет пустой атрибут placeholder" + } + }, + "non-empty-title": { + "pass": "Элемент имеет атрибут title", + "fail": { + "noAttr": "Элемент не имеет атрибута title", + "emptyAttr": "Элемент имеет пустой атрибут title" + } + }, + "non-empty-value": { + "pass": "Элемент имеет непустой атрибут value", + "fail": { + "noAttr": "Элемент не имеет атрибута value", + "emptyAttr": "Элемент имеет пустой атрибут value" + } + }, + "presentational-role": { + "pass": "Стандартная семантика элемента была переопределена с помощью role=\"${data.role}\"", + "fail": { + "default": "Стандартная семантика элемента не была переопределена с помощью role=\"none\" или role=\"presentation\"", + "globalAria": "Роль элемента не является презентационной, так как у него есть глобальный ARIA атрибут", + "focusable": "Роль элемента не является презентационной, так как он может быть сфокусирован", + "both": "Роль элемента не является презентационной, так как у него есть глобальный ARIA атрибут и он может быть сфокусирован", + "iframe": "Использование атрибута \"title\" на элементе ${data.nodeName} с презентационной ролью ведет себя непоследовательно между экранными считывателями" + } + }, + "role-none": { + "pass": "Стандартная семантика элемента была переопределена с помощью role=\"none\"", + "fail": "Стандартная семантика элемента не была переопределена с помощью role=\"none\"" + }, + "role-presentation": { + "pass": "Стандартная семантика элемента была переопределена с помощью role=\"presentation\"", + "fail": "Стандартная семантика элемента не была переопределена с помощью role=\"presentation\"" + }, + "svg-non-empty-title": { + "pass": "Элемент имеет дочерний элемент title", + "fail": { + "noTitle": "Элемент не имеет дочернего элемента title", + "emptyTitle": "Дочерний элемент title пуст" + }, + "incomplete": "Невозможно определить, имеет ли элемент дочерний элемент title" + }, + "caption-faked": { + "pass": "Первая строка таблицы не используется в качестве заголовка", + "fail": "Первый дочерний элемент таблицы должен быть заголовком, а не ячейкой таблицы" + }, + "html5-scope": { + "pass": "Атрибут scope используется только для элементов заголовков таблицы (<th>)", + "fail": "В HTML 5 атрибуты scope могут использоваться только для элементов заголовков таблицы (<th>)" + }, + "same-caption-summary": { + "pass": "Содержимое атрибута summary и элемента <caption> не дублируется", + "fail": "Содержимое атрибута summary и элемента <caption> идентично", + "incomplete": "Невозможно определить, есть ли у элемента <table> заголовок" + }, + "scope-value": { + "pass": "Атрибут scope используется правильно", + "fail": "Значение атрибута scope может быть только 'row' или 'col'" + }, + "td-has-header": { + "pass": "Все непустые ячейки данных имеют заголовки таблицы", + "fail": "Некоторые непустые ячейки данных не имеют заголовков таблицы" + }, + "td-headers-attr": { + "pass": "Атрибут headers используется исключительно для ссылки на другие ячейки таблицы", + "incomplete": "Атрибут headers пуст", + "fail": { + "cell-header-not-in-table": "Атрибут headers не используется исключительно для ссылки на другие заголовочные ячейки в таблице", + "cell-header-not-th": "Атрибут headers должен ссылаться на заголовочные ячейки, а не на ячейки с данными", + "header-refs-self": "Элемент с атрибутом headers ссылается на самого себя" + } + }, + "th-has-data-cells": { + "pass": "Все ячейки заголовков таблицы ссылаются на ячейки данных", + "fail": "Не все ячейки заголовков таблицы ссылаются на ячейки данных", + "incomplete": "Ячейки данных таблицы отсутствуют или пусты" + }, + "hidden-content": { + "pass": "Все содержимое страницы было проанализировано.", + "fail": "Возникли проблемы с анализом содержимого на этой странице.", + "incomplete": "На странице есть скрытое содержимое, которое не было проанализировано. Вам нужно будет включить отображение этого содержимого, чтобы его проанализировать." + } + }, + "failureSummaries": { + "any": { + "failureMessage": "Исправьте любое из следующего:{{~it:value}}\n {{=value.split('\\n').join('\\n ')}}{{~}}" + }, + "none": { + "failureMessage": "Исправьте все из следующего:{{~it:value}}\n {{=value.split('\\n').join('\\n ')}}{{~}}" + } + }, + "incompleteFallbackMessage": "axe не смог определить причину. Время использовать инспектор элементов!" +} diff --git a/test/integration/rules/focus-order-semantics/focus-order-semantics.html b/test/integration/rules/focus-order-semantics/focus-order-semantics.html index 7ac09790a..2648e15f4 100644 --- a/test/integration/rules/focus-order-semantics/focus-order-semantics.html +++ b/test/integration/rules/focus-order-semantics/focus-order-semantics.html @@ -19,6 +19,8 @@ <h4>Invalid landmark roles for scrollable containers</h4> <div> <div id="violation3" role="banner" tabindex="0"></div> <div id="violation4" role="search" tabindex="0"></div> + <div id="violation5" role="marquee" tabindex="0"></div> + <div id="violation6" role="timer" tabindex="0"></div> </div> <h4>Valid landmark roles for scrollable containers</h4> <div> @@ -31,6 +33,15 @@ <h4>Valid landmark roles for scrollable containers</h4> <div id="pass8" role="application" tabindex="0"></div> <div id="pass9" role="tooltip" tabindex="0"></div> <div id="pass10" role="article" tabindex="0"></div> + <div id="pass11" role="alert" tabindex="0"></div> + <div id="pass12" role="log" tabindex="0"></div> + <div id="pass13" role="status" tabindex="0"></div> + <div id="pass14" role="tabpanel" tabindex="0"></div> + </div> + <h4>Valid window roles for scrollable containers</h4> + <div> + <div id="pass15" role="alertdialog" tabindex="0"></div> + <div id="pass16" role="dialog" tabindex="0"></div> </div> <h4> Valid scrollable HTML tags for scrollable regions, not selected by this diff --git a/test/integration/rules/focus-order-semantics/focus-order-semantics.json b/test/integration/rules/focus-order-semantics/focus-order-semantics.json index dac1ba8f1..fe1f5d49e 100644 --- a/test/integration/rules/focus-order-semantics/focus-order-semantics.json +++ b/test/integration/rules/focus-order-semantics/focus-order-semantics.json @@ -11,12 +11,20 @@ ["#pass7"], ["#pass8"], ["#pass9"], - ["#pass10"] + ["#pass10"], + ["#pass11"], + ["#pass12"], + ["#pass13"], + ["#pass14"], + ["#pass15"], + ["#pass16"] ], "violations": [ ["#violation1"], ["#violation2"], ["#violation3"], - ["#violation4"] + ["#violation4"], + ["#violation5"], + ["#violation6"] ] } diff --git a/test/integration/rules/summary-name/summary-name.html b/test/integration/rules/summary-name/summary-name.html new file mode 100644 index 000000000..37009ac78 --- /dev/null +++ b/test/integration/rules/summary-name/summary-name.html @@ -0,0 +1,86 @@ +<details> + <summary id="empty-fail"></summary> + Hello world +</details> + +<details> + <summary id="text-pass">name</summary> + Hello world +</details> + +<details> + <summary id="aria-label-pass" aria-label="Name"></summary> + Hello world +</details> + +<details> + <summary id="aria-label-fail" aria-label=""></summary> + Hello world +</details> + +<details> + <summary id="aria-labelledby-pass" aria-labelledby="labeldiv"></summary> + Hello world +</details> + +<details> + <summary id="aria-labelledby-fail" aria-labelledby="nonexistent"></summary> + Hello world +</details> + +<details> + <summary id="aria-labelledby-empty-fail" aria-labelledby="emptydiv"></summary> + Hello world +</details> +<div id="labeldiv">summary label</div> +<div id="emptydiv"></div> + +<details> + <summary id="combo-pass" aria-label="Aria Name">Name</summary> + Hello world +</details> + +<details> + <summary id="title-pass" title="Title"></summary> + Hello world +</details> + +<details> + <summary id="presentation-role-fail" role="presentation"></summary> + Conflict resolution gets this to be ignored +</details> + +<details> + <summary id="none-role-fail" role="none"></summary> + Conflict resolution gets this to be ignored +</details> + +<details> + <summary id="heading-role-fail" role="heading"></summary> + Conflict resolution gets this to be ignored +</details> + +<details> + <summary id="button-role-fail" role="button"></summary> + Hello world +</details> + +<!-- Invalid naming methods --> + +<details> + <summary id="value-attr-fail" value="Button Name"></summary> + Not a valid method for giving a name +</details> + +<details> + <summary id="alt-attr-fail" alt="Button Name"></summary> + Not a valid method for giving a name +</details> + +<label> + <details> + <summary id="label-elm-fail"></summary> + Text here + </details> + Not a valid method for giving a name +</label> diff --git a/test/integration/rules/summary-name/summary-name.json b/test/integration/rules/summary-name/summary-name.json new file mode 100644 index 000000000..ef2b52545 --- /dev/null +++ b/test/integration/rules/summary-name/summary-name.json @@ -0,0 +1,24 @@ +{ + "description": "summary-name test", + "rule": "summary-name", + "violations": [ + ["#empty-fail"], + ["#aria-label-fail"], + ["#aria-labelledby-fail"], + ["#aria-labelledby-empty-fail"], + ["#presentation-role-fail"], + ["#none-role-fail"], + ["#heading-role-fail"], + ["#value-attr-fail"], + ["#alt-attr-fail"], + ["#label-elm-fail"], + ["#button-role-fail"] + ], + "passes": [ + ["#text-pass"], + ["#aria-label-pass"], + ["#aria-labelledby-pass"], + ["#combo-pass"], + ["#title-pass"] + ] +} diff --git a/test/integration/virtual-rules/summary-name.js b/test/integration/virtual-rules/summary-name.js new file mode 100644 index 000000000..1c711bd77 --- /dev/null +++ b/test/integration/virtual-rules/summary-name.js @@ -0,0 +1,95 @@ +function appendSerialChild(parent, child) { + if (child instanceof axe.SerialVirtualNode === false) { + child = new axe.SerialVirtualNode(child); + } + child.parent = parent; + parent.children ??= []; + parent.children.push(child); + return child; +} + +describe('summary-name virtual-rule', () => { + let vDetails; + beforeEach(() => { + vDetails = new axe.SerialVirtualNode({ + nodeName: 'details', + attributes: {} + }); + appendSerialChild(vDetails, { nodeName: '#text', nodeValue: 'text' }); + }); + + it('fails without children', () => { + const vSummary = new axe.SerialVirtualNode({ + nodeName: 'summary', + attributes: {} + }); + vSummary.children = []; + appendSerialChild(vDetails, vSummary); + const results = axe.runVirtualRule('summary-name', vSummary); + console.log(results); + assert.lengthOf(results.passes, 0); + assert.lengthOf(results.violations, 1); + assert.lengthOf(results.incomplete, 0); + }); + + it('passes with text content', () => { + const vSummary = new axe.SerialVirtualNode({ + nodeName: 'summary', + attributes: {} + }); + appendSerialChild(vSummary, { nodeName: '#text', nodeValue: 'text' }); + appendSerialChild(vDetails, vSummary); + + const results = axe.runVirtualRule('summary-name', vSummary); + assert.lengthOf(results.passes, 1); + assert.lengthOf(results.violations, 0); + assert.lengthOf(results.incomplete, 0); + }); + + it('passes with aria-label', () => { + const vSummary = new axe.SerialVirtualNode({ + nodeName: 'summary', + attributes: { 'aria-label': 'foobar' } + }); + appendSerialChild(vDetails, vSummary); + const results = axe.runVirtualRule('summary-name', vSummary); + assert.lengthOf(results.passes, 1); + assert.lengthOf(results.violations, 0); + assert.lengthOf(results.incomplete, 0); + }); + + it('passes with title', () => { + const vSummary = new axe.SerialVirtualNode({ + nodeName: 'summary', + attributes: { title: 'foobar' } + }); + appendSerialChild(vDetails, vSummary); + const results = axe.runVirtualRule('summary-name', vSummary); + assert.lengthOf(results.passes, 1); + assert.lengthOf(results.violations, 0); + assert.lengthOf(results.incomplete, 0); + }); + + it('incompletes with aria-labelledby', () => { + const vSummary = new axe.SerialVirtualNode({ + nodeName: 'summary', + attributes: { 'aria-labelledby': 'foobar' } + }); + appendSerialChild(vDetails, vSummary); + const results = axe.runVirtualRule('summary-name', vSummary); + assert.lengthOf(results.passes, 0); + assert.lengthOf(results.violations, 0); + assert.lengthOf(results.incomplete, 1); + }); + + it('throws without a parent', () => { + const vSummary = new axe.SerialVirtualNode({ + nodeName: 'summary', + attributes: { 'aria-labelledby': 'foobar' } + }); + vSummary.children = []; + assert.throws(() => { + axe.runVirtualRule('summary-name', vSummary); + }); + }); +}); diff --git a/test/rule-matches/inserted-into-focus-order-matches.js b/test/rule-matches/inserted-into-focus-order-matches.js index f9a56f3ed..ff7ec134f 100644 --- a/test/rule-matches/inserted-into-focus-order-matches.js +++ b/test/rule-matches/inserted-into-focus-order-matches.js @@ -1,9 +1,9 @@ describe('inserted-into-focus-order-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var flatTreeSetup = axe.testUtils.flatTreeSetup; - var rule; + const fixture = document.getElementById('fixture'); + const flatTreeSetup = axe.testUtils.flatTreeSetup; + let rule; beforeEach(function () { rule = axe.utils.getRule('focus-order-semantics'); @@ -16,35 +16,35 @@ describe('inserted-into-focus-order-matches', function () { it('should return true for a non-focusable element with tabindex > -1', function () { fixture.innerHTML = '<div tabindex="0"></div>'; flatTreeSetup(fixture); - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isTrue(rule.matches(node)); }); it('should return false for a non-focusable element with tabindex == -1', function () { fixture.innerHTML = '<div tabindex="-1"></div>'; flatTreeSetup(fixture); - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isFalse(rule.matches(node)); }); it('should return false for a native focusable element with tabindex > 0', function () { fixture.innerHTML = '<button tabindex="0"></button>'; flatTreeSetup(fixture); - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isFalse(rule.matches(node)); }); it('should return false for a native focusable element with no tabindex', function () { fixture.innerHTML = '<a href="#"></a>'; flatTreeSetup(fixture); - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isFalse(rule.matches(node)); }); it('should return false for non-numeric tabindex value', function () { fixture.innerHTML = '<div tabindex="abc"></div>'; flatTreeSetup(fixture); - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isFalse(rule.matches(node)); }); }); diff --git a/test/rule-matches/summary-interactive-matches.js b/test/rule-matches/summary-interactive-matches.js new file mode 100644 index 000000000..f23ce7384 --- /dev/null +++ b/test/rule-matches/summary-interactive-matches.js @@ -0,0 +1,112 @@ +describe('summary-interactive-matches', () => { + const rule = axe.utils.getRule('summary-name'); + const { queryFixture, queryShadowFixture, html } = axe.testUtils; + + it('is true for an interactive summary', () => { + const vNode = queryFixture(html` + <details> + <summary id="target">Summary</summary> + text + </details> + `); + assert.isTrue(rule.matches(null, vNode)); + }); + + it('is false for summary without a details parent', () => { + const vNode = queryFixture(html` + <summary id="target">Summary</summary> + text + `); + assert.isFalse(rule.matches(null, vNode)); + }); + + it('is false for summary with a details ancestor', () => { + const vNode = queryFixture(html` + <details> + <div> + <summary id="target">Summary</summary> + text + </div> + </details> + `); + assert.isFalse(rule.matches(null, vNode)); + }); + + it('is false for a non-first summary', () => { + const vNode = queryFixture(html` + <details> + <summary>Summary</summary> + <summary id="target">Summary</summary> + text + </details> + `); + assert.isFalse(rule.matches(null, vNode)); + }); + + it('is false for details parent in a different DOM tree', () => { + const vFixture = queryShadowFixture( + html` + <div id="shadow"> + <summary>Hello World</summary> + </div> + `, + html` + <details> + <slot></slot> + text + </details> + ` + ); + const vNode = axe.utils.querySelectorAll(vFixture, 'summary')[0]; + assert.isFalse(rule.matches(null, vNode)); + }); + + it('is true even if summary has role=none', () => { + const vNode = queryFixture(html` + <details> + <summary id="target" role="none">Summary</summary> + text + </details> + `); + assert.isTrue(rule.matches(null, vNode)); + }); + + it('is true the element has a widget role', () => { + const vNode = queryFixture(html` + <details> + <summary id="target" role="button">Summary</summary> + text + </details> + `); + assert.isTrue(rule.matches(null, vNode)); + }); + + it('is true the element has a non-interactive role', () => { + const vNode = queryFixture(html` + <details> + <summary id="target" role="heading">Summary</summary> + text + </details> + `); + assert.isTrue(rule.matches(null, vNode)); + }); + + it('is true even if summary has tabindex=-1', () => { + const vNode = queryFixture(html` + <details> + <summary id="target" tabindex="-1">Summary</summary> + text + </details> + `); + assert.isTrue(rule.matches(null, vNode)); + }); + + it('is true even if summary is the only child', () => { + const vNode = queryFixture(html` + <details> + <summary id="target">Summary</summary> + </details> + `); + assert.isTrue(rule.matches(null, vNode)); + }); +}); From bc346a3cf77f77ee59e65e0961007d8d90508374 Mon Sep 17 00:00:00 2001 From: Gagan Meena <gagan.m@browserstack.com> Date: Tue, 9 Dec 2025 18:56:05 +0530 Subject: [PATCH 02/10] Initial merge --- build/cherry-pick.js | 4 +- lib/checks/aria/aria-allowed-attr-evaluate.js | 26 ++- lib/checks/aria/aria-errormessage.json | 6 +- lib/checks/label/explicit-evaluate.js | 2 +- lib/checks/label/explicit.json | 4 +- .../label/help-same-as-label-evaluate.js | 6 +- .../label/hidden-explicit-label-evaluate.js | 2 +- lib/core/base/audit.js | 74 ++++---- test/integration/rules/runner.js | 61 ++++--- .../rule-matches/aria-allowed-attr-matches.js | 8 +- .../rule-matches/aria-allowed-role-matches.js | 12 +- test/rule-matches/aria-has-attr-matches.js | 12 +- .../rule-matches/aria-hidden-focus-matches.js | 20 +-- .../aria-required-children-matches.js | 10 +- .../aria-required-parent-matches.js | 10 +- test/rule-matches/autocomplete-matches.js | 65 +++++-- test/rule-matches/color-contrast-matches.js | 147 +++++++-------- test/rule-matches/data-table-matches.js | 12 +- .../duplicate-id-active-matches.js | 22 +-- .../rule-matches/duplicate-id-aria-matches.js | 22 +-- .../rule-matches/duplicate-id-misc-matches.js | 22 +-- .../frame-focusable-content-matches.js | 12 +- .../frame-title-has-text-matches.js | 10 +- .../has-implicit-chromium-role-matches.js | 14 +- test/rule-matches/heading-matches.js | 24 +-- test/rule-matches/html-namespace-matches.js | 30 ++-- test/rule-matches/html-xml-lang-mismatch.js | 18 +- .../identical-links-same-purpose-matches.js | 48 ++--- test/rule-matches/is-initiator-matches.js | 4 +- test/rule-matches/is-visible-matches.js | 6 +- .../label-content-name-mismatch-matches.js | 74 ++++---- test/rule-matches/label-matches.js | 16 +- .../rule-matches/landmark-has-body-context.js | 18 +- test/rule-matches/landmark-unique-matches.js | 170 ++++++++++++++---- test/rule-matches/layout-table-matches.js | 14 +- .../link-in-text-block-matches.js | 2 - .../nested-interactive-matches.js | 14 +- .../rule-matches/no-autoplay-audio-matches.js | 20 +-- test/rule-matches/no-empty-role-matches.js | 36 ++-- .../no-explicit-name-required-matches.js | 34 ++-- test/rule-matches/no-naming-method-matches.js | 56 +++--- test/rule-matches/no-negative-tabindex.js | 26 +-- test/rule-matches/object-is-loaded-matches.js | 2 +- test/rule-matches/p-as-heading-matches.js | 18 +- .../scrollable-region-focusable-matches.js | 88 ++++----- test/rule-matches/skip-link-matches.js | 4 +- test/rule-matches/svg-namespace-matches.js | 36 ++-- 47 files changed, 766 insertions(+), 575 deletions(-) mode change 100644 => 100755 build/cherry-pick.js diff --git a/build/cherry-pick.js b/build/cherry-pick.js old mode 100644 new mode 100755 index 2b3dc2afe..f8040807b --- a/build/cherry-pick.js +++ b/build/cherry-pick.js @@ -1,3 +1,5 @@ +#!/usr/bin/env node + const { execSync } = require('child_process'); const conventionalCommitsParser = require('conventional-commits-parser'); const chalk = require('chalk'); @@ -129,7 +131,7 @@ commitsToCherryPick.forEach(({ hash, type, scope, subject }) => { try { execSync(`git cherry-pick ${hash} -X theirs`); - } catch (e) { + } catch { console.error( chalk.red.bold('\nAborting cherry-pick and reseting to master') ); diff --git a/lib/checks/aria/aria-allowed-attr-evaluate.js b/lib/checks/aria/aria-allowed-attr-evaluate.js index a1049ef38..59d09e7e6 100644 --- a/lib/checks/aria/aria-allowed-attr-evaluate.js +++ b/lib/checks/aria/aria-allowed-attr-evaluate.js @@ -39,7 +39,11 @@ export default function ariaAllowedAttrEvaluate(node, options, virtualNode) { // Unknown ARIA attributes are tested in aria-valid-attr for (const attrName of virtualNode.attrNames) { - if (validateAttr(attrName) && !allowed.includes(attrName)) { + if ( + validateAttr(attrName) && + !allowed.includes(attrName) && + !ignoredAttrs(attrName, virtualNode.attr(attrName), virtualNode) + ) { invalid.push(attrName); } } @@ -57,3 +61,23 @@ export default function ariaAllowedAttrEvaluate(node, options, virtualNode) { } return false; } + +function ignoredAttrs(attrName, attrValue, vNode) { + // allow aria-required=false as screen readers consistently ignore it + // @see https://github.com/dequelabs/axe-core/issues/3756 + if (attrName === 'aria-required' && attrValue === 'false') { + return true; + } + + // allow aria-multiline=false when contenteditable is set + // @see https://github.com/dequelabs/axe-core/issues/4463 + if ( + attrName === 'aria-multiline' && + attrValue === 'false' && + vNode.hasAttr('contenteditable') + ) { + return true; + } + + return false; +} diff --git a/lib/checks/aria/aria-errormessage.json b/lib/checks/aria/aria-errormessage.json index 84901729a..e238d7f65 100644 --- a/lib/checks/aria/aria-errormessage.json +++ b/lib/checks/aria/aria-errormessage.json @@ -11,9 +11,9 @@ "hidden": "aria-errormessage value `${data.values}` cannot reference a hidden element" }, "incomplete": { - "singular": "ensure aria-errormessage value `${data.values}` references an existing element", - "plural": "ensure aria-errormessage values `${data.values}` reference existing elements", - "idrefs": "unable to determine if aria-errormessage element exists on the page: ${data.values}" + "singular": "Ensure aria-errormessage value `${data.values}` references an existing element", + "plural": "Ensure aria-errormessage values `${data.values}` reference existing elements", + "idrefs": "Unable to determine if aria-errormessage element exists on the page: ${data.values}" } } } diff --git a/lib/checks/label/explicit-evaluate.js b/lib/checks/label/explicit-evaluate.js index 585371989..59b0c123c 100644 --- a/lib/checks/label/explicit-evaluate.js +++ b/lib/checks/label/explicit-evaluate.js @@ -35,7 +35,7 @@ function explicitEvaluate(node, options, virtualNode) { return !!explicitLabel; } }); - } catch (e) { + } catch { return undefined; } } diff --git a/lib/checks/label/explicit.json b/lib/checks/label/explicit.json index ab765720f..0d4c4b099 100644 --- a/lib/checks/label/explicit.json +++ b/lib/checks/label/explicit.json @@ -4,8 +4,8 @@ "metadata": { "impact": "critical", "messages": { - "pass": "Form element has an explicit <label>", - "fail": "Form element does not have an explicit <label>", + "pass": "Element has an explicit <label>", + "fail": "Element does not have an explicit <label>", "incomplete": "Unable to determine if form element has an explicit <label>" } } diff --git a/lib/checks/label/help-same-as-label-evaluate.js b/lib/checks/label/help-same-as-label-evaluate.js index 61262e0fa..47b15769f 100644 --- a/lib/checks/label/help-same-as-label-evaluate.js +++ b/lib/checks/label/help-same-as-label-evaluate.js @@ -2,8 +2,8 @@ import { labelVirtual, accessibleText, sanitize } from '../../commons/text'; import { idrefs } from '../../commons/dom'; function helpSameAsLabelEvaluate(node, options, virtualNode) { - var labelText = labelVirtual(virtualNode), - check = node.getAttribute('title'); + const labelText = labelVirtual(virtualNode); + let check = node.getAttribute('title'); if (!labelText) { return false; @@ -13,7 +13,7 @@ function helpSameAsLabelEvaluate(node, options, virtualNode) { check = ''; if (node.getAttribute('aria-describedby')) { - var ref = idrefs(node, 'aria-describedby'); + const ref = idrefs(node, 'aria-describedby'); check = ref .map(thing => { return thing ? accessibleText(thing) : ''; diff --git a/lib/checks/label/hidden-explicit-label-evaluate.js b/lib/checks/label/hidden-explicit-label-evaluate.js index eafcc1409..f74f285f9 100644 --- a/lib/checks/label/hidden-explicit-label-evaluate.js +++ b/lib/checks/label/hidden-explicit-label-evaluate.js @@ -16,7 +16,7 @@ function hiddenExplicitLabelEvaluate(node, options, virtualNode) { let name; try { name = accessibleTextVirtual(virtualNode).trim(); - } catch (e) { + } catch { return undefined; } diff --git a/lib/core/base/audit.js b/lib/core/base/audit.js index 47b57f66d..3353545af 100644 --- a/lib/core/base/audit.js +++ b/lib/core/base/audit.js @@ -9,9 +9,10 @@ import { preload, findBy, ruleShouldRun, - performanceTimer + performanceTimer, + serializeError } from '../utils'; -import doT from '@deque/dot'; +import { doT } from '../imports'; import constants from '../constants'; const dotRegex = /\{\{.+?\}\}/g; @@ -183,7 +184,7 @@ export default class Audit { * Initializes the rules and checks */ _init() { - var audit = getDefaultConfiguration(this.defaultConfig); + const audit = getDefaultConfiguration(this.defaultConfig); this.lang = audit.lang || 'en'; this.reporter = audit.reporter; this.commands = {}; @@ -191,7 +192,7 @@ export default class Audit { this.checks = {}; this.brand = 'axe'; this.application = 'axeAPI'; - this.tagExclude = ['experimental']; + this.tagExclude = ['experimental', 'deprecated']; this.noHtml = audit.noHtml; this.allowedOrigins = audit.allowedOrigins; unpackToObject(audit.rules, this, 'addRule'); @@ -366,16 +367,26 @@ export default class Audit { * @param {Mixed} options Options object to pass into rules and/or disable rules or checks */ after(results, options) { - var rules = this.rules; + const rules = this.rules; return results.map(ruleResult => { - var rule = findBy(rules, 'id', ruleResult.id); + if (ruleResult.error) { + return ruleResult; + } + const rule = findBy(rules, 'id', ruleResult.id); if (!rule) { // If you see this, you're probably running the Mocha tests with the axe extension installed throw new Error( 'Result for unknown rule. You may be running mismatch axe-core versions' ); } - return rule.after(ruleResult, options); + try { + return rule.after(ruleResult, options); + } catch (err) { + if (options.debug) { + throw err; + } + return createIncompleteErrorResult(rule, err); + } }); } /** @@ -393,7 +404,7 @@ export default class Audit { * @return {Object} Validated options object */ normalizeOptions(options) { - var audit = this; + const audit = this; const tags = []; const ruleIds = []; audit.rules.forEach(rule => { @@ -498,7 +509,7 @@ export default class Audit { } _constructHelpUrls(previous = null) { // TODO: es-modules-version - var version = (axe.version.match(/^[1-9][0-9]*\.[0-9]+/) || ['x.y'])[0]; + const version = (axe.version.match(/^[1-9][0-9]*\.[0-9]+/) || ['x.y'])[0]; this.rules.forEach(rule => { if (!this.data.rules[rule.id]) { this.data.rules[rule.id] = {}; @@ -732,36 +743,37 @@ function getDefferedRule(rule, context, options) { rule.run( context, options, - // resolve callback for rule `run` - ruleResult => { - // resolve - resolve(ruleResult); - }, - // reject callback for rule `run` + ruleResult => resolve(ruleResult), err => { - // if debug - construct error details - if (!options.debug) { - const errResult = Object.assign(new RuleResult(rule), { - result: constants.CANTTELL, - description: 'An error occured while running this rule', - message: err.message, - stack: err.stack, - error: err, - // Add a serialized reference to the node the rule failed on for easier debugging. - // See https://github.com/dequelabs/axe-core/issues/1317. - errorNode: err.errorNode - }); - // resolve - resolve(errResult); - } else { - // reject + if (options.debug) { reject(err); + } else { + resolve(createIncompleteErrorResult(rule, err)); } } ); }; } +function createIncompleteErrorResult(rule, error) { + const { errorNode } = error; + const serialError = serializeError(error); + const none = [ + { + id: 'error-occurred', + result: undefined, + data: serialError, + relatedNodes: [] + } + ]; + const node = errorNode || new DqElement(document.documentElement); + return Object.assign(new RuleResult(rule), { + error: serialError, + result: constants.CANTTELL, + nodes: [{ any: [], all: [], none, node }] + }); +} + /** * For all the rules, create the helpUrl and add it to the data for that rule */ diff --git a/test/integration/rules/runner.js b/test/integration/rules/runner.js index 0110f03cd..a1234ffed 100644 --- a/test/integration/rules/runner.js +++ b/test/integration/rules/runner.js @@ -110,34 +110,39 @@ before(done => { fixture.innerHTML = testObj.content; waitForFrames(fixture, () => { - axe.run( - fixture, - { - /** - * The debug flag helps log errors in a fairly detailed fashion, - * when tests fail in webdriver - */ - debug: true, - performanceTimer: false, - runOnly: { type: 'rule', values: [ruleId] } - }, - (err, r) => { - // assert that there are no errors - if error exists a stack trace is logged. - const errStack = err && err.stack ? err.stack : ''; - assert.isNull(err, 'Error should be null. ' + errStack); - // assert that result is defined - assert.isDefined(r, 'Results are defined.'); - // assert that result has certain keys - assert.hasAnyKeys(r, ['incomplete', 'violations', 'passes']); - // assert incomplete(s) does not have error - r.incomplete.forEach(incomplete => { - assert.isUndefined(incomplete.error); - }); - // flatten results - results = flattenResult(r); - done(); - } - ); + // The setTimeout is a workaround for a Firefox bug. See: + // - https://github.com/dequelabs/axe-core/issues/4556 + // - https://bugzilla.mozilla.org/show_bug.cgi?id=1912115 + setTimeout(() => { + axe.run( + fixture, + { + /** + * The debug flag helps log errors in a fairly detailed fashion, + * when tests fail in webdriver + */ + debug: true, + performanceTimer: false, + runOnly: { type: 'rule', values: [ruleId] } + }, + (err, r) => { + // assert that there are no errors - if error exists a stack trace is logged. + const errStack = err && err.stack ? err.stack : ''; + assert.isNull(err, 'Error should be null. ' + errStack); + // assert that result is defined + assert.isDefined(r, 'Results are defined.'); + // assert that result has certain keys + assert.hasAnyKeys(r, ['incomplete', 'violations', 'passes']); + // assert incomplete(s) does not have error + r.incomplete.forEach(incomplete => { + assert.isUndefined(incomplete.error); + }); + // flatten results + results = flattenResult(r); + done(); + } + ); + }, 0); }); }); runTest(testObj, 'passes'); diff --git a/test/rule-matches/aria-allowed-attr-matches.js b/test/rule-matches/aria-allowed-attr-matches.js index 5b7dfb33a..e4177e0f7 100644 --- a/test/rule-matches/aria-allowed-attr-matches.js +++ b/test/rule-matches/aria-allowed-attr-matches.js @@ -1,8 +1,8 @@ describe('aria-allowed-attr-matches', function () { 'use strict'; - var queryFixture = axe.testUtils.queryFixture; - var rule; + const queryFixture = axe.testUtils.queryFixture; + let rule; beforeEach(function () { rule = axe.utils.getRule('aria-allowed-attr'); @@ -13,7 +13,7 @@ describe('aria-allowed-attr-matches', function () { }); it('should return true on elements that have aria attributes', function () { - var vNode = queryFixture( + const vNode = queryFixture( '<div role="button" id="target" aria-label="Thing 1" aria-mccheddarton="Unsupported thing 2"></div>' ); @@ -21,7 +21,7 @@ describe('aria-allowed-attr-matches', function () { }); it('should return false on elements that have no aria attributes', function () { - var vNode = queryFixture('<div role="button" id="target"></div>'); + const vNode = queryFixture('<div role="button" id="target"></div>'); assert.isFalse(rule.matches(null, vNode)); }); diff --git a/test/rule-matches/aria-allowed-role-matches.js b/test/rule-matches/aria-allowed-role-matches.js index 28992fde4..14769d0d7 100644 --- a/test/rule-matches/aria-allowed-role-matches.js +++ b/test/rule-matches/aria-allowed-role-matches.js @@ -1,27 +1,29 @@ describe('aria-allowed-role-matches', function () { 'use strict'; - var queryFixture = axe.testUtils.queryFixture; - var rule; + const queryFixture = axe.testUtils.queryFixture; + let rule; beforeEach(function () { rule = axe.utils.getRule('aria-allowed-role'); }); it('return false (no matches) for a <link> with a href to have any invalid role', function () { - var vNode = queryFixture( + const vNode = queryFixture( '<link id="target" href="/example.com" role="invalid-role"></link>' ); assert.isFalse(rule.matches(null, vNode)); }); it('return true for input with redundant role', function () { - var vNode = queryFixture('<input id="target" type="text" role="textbox"/>'); + const vNode = queryFixture( + '<input id="target" type="text" role="textbox"/>' + ); assert.isTrue(rule.matches(null, vNode)); }); it('return true for element with valid role', function () { - var vNode = queryFixture('<ol id="target" role="listbox"/>'); + const vNode = queryFixture('<ol id="target" role="listbox"/>'); assert.isTrue(rule.matches(null, vNode)); }); }); diff --git a/test/rule-matches/aria-has-attr-matches.js b/test/rule-matches/aria-has-attr-matches.js index c3e0adbb5..a724a68a0 100644 --- a/test/rule-matches/aria-has-attr-matches.js +++ b/test/rule-matches/aria-has-attr-matches.js @@ -1,9 +1,9 @@ describe('aria-has-attr-matches', function () { 'use strict'; - var queryFixture = axe.testUtils.queryFixture; - var fixtureSetup = axe.testUtils.fixtureSetup; - var rule; + const queryFixture = axe.testUtils.queryFixture; + const fixtureSetup = axe.testUtils.fixtureSetup; + let rule; beforeEach(function () { rule = axe.utils.getRule('aria-valid-attr-value'); @@ -14,16 +14,16 @@ describe('aria-has-attr-matches', function () { }); it('should return false if an element has no attributes', function () { - var vNode = fixtureSetup('<div></div>'); + const vNode = fixtureSetup('<div></div>'); assert.isFalse(rule.matches(null, vNode)); }); it('should return false if an element has no ARIA attributes', function () { - var vNode = queryFixture('<div id="target"></div>'); + const vNode = queryFixture('<div id="target"></div>'); assert.isFalse(rule.matches(null, vNode)); }); it('should return true if an element has ARIA attributes', function () { - var vNode = queryFixture('<div id="target" aria-bats="monkeys"></div>'); + const vNode = queryFixture('<div id="target" aria-bats="monkeys"></div>'); assert.isTrue(rule.matches(null, vNode)); }); }); diff --git a/test/rule-matches/aria-hidden-focus-matches.js b/test/rule-matches/aria-hidden-focus-matches.js index b770c8832..0a498004a 100644 --- a/test/rule-matches/aria-hidden-focus-matches.js +++ b/test/rule-matches/aria-hidden-focus-matches.js @@ -1,8 +1,8 @@ describe('aria-hidden-focus-matches', function () { 'use strict'; - var rule; - var queryFixture = axe.testUtils.queryFixture; + let rule; + const queryFixture = axe.testUtils.queryFixture; beforeEach(function () { rule = axe.utils.getRule('aria-hidden-focus'); @@ -13,24 +13,24 @@ describe('aria-hidden-focus-matches', function () { }); it('return true when there is no parent with aria-hidden', function () { - var vNode = queryFixture('<div id="target">' + '</div>'); - var actual = rule.matches(vNode.actualNode); + const vNode = queryFixture('<div id="target">' + '</div>'); + const actual = rule.matches(vNode.actualNode); assert.isTrue(actual); }); it('return false when has a parent element with aria-hidden', function () { - var vNode = queryFixture( + const vNode = queryFixture( '<div aria-hidden="true">' + '<div id="target" aria-hidden="true">' + '</div>' + '</div>' ); - var actual = rule.matches(vNode.actualNode); + const actual = rule.matches(vNode.actualNode); assert.isFalse(actual); }); it('return false when has any parent element with aria-hidden', function () { - var vNode = queryFixture( + const vNode = queryFixture( '<div aria-hidden="true">' + '<div>' + '<div id="target" aria-hidden="true">' + @@ -38,19 +38,19 @@ describe('aria-hidden-focus-matches', function () { '</div>' + '</div>' ); - var actual = rule.matches(vNode.actualNode); + const actual = rule.matches(vNode.actualNode); assert.isFalse(actual); }); it('return false when has any parent element with aria-hidden', function () { - var vNode = queryFixture( + const vNode = queryFixture( '<div aria-hidden="true">' + '<div aria-hidden="true">' + '<button id="target">btn</button>' + '</div>' + '</div>' ); - var actual = rule.matches(vNode.actualNode); + const actual = rule.matches(vNode.actualNode); assert.isFalse(actual); }); }); diff --git a/test/rule-matches/aria-required-children-matches.js b/test/rule-matches/aria-required-children-matches.js index 319e7845b..200b3c009 100644 --- a/test/rule-matches/aria-required-children-matches.js +++ b/test/rule-matches/aria-required-children-matches.js @@ -1,9 +1,9 @@ describe('aria-required-children-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var queryFixture = axe.testUtils.queryFixture; - var rule; + const fixture = document.getElementById('fixture'); + const queryFixture = axe.testUtils.queryFixture; + let rule; beforeEach(function () { rule = axe.utils.getRule('aria-required-children'); @@ -14,12 +14,12 @@ describe('aria-required-children-matches', function () { }); it('should return true for a role that requires children', function () { - var vNode = queryFixture('<div id="target" role="list"></div>'); + const vNode = queryFixture('<div id="target" role="list"></div>'); assert.isTrue(rule.matches(null, vNode)); }); it('should return false for a role that does not require children', function () { - var vNode = queryFixture('<div id="target" role="alert"></div>'); + const vNode = queryFixture('<div id="target" role="alert"></div>'); assert.isFalse(rule.matches(null, vNode)); }); }); diff --git a/test/rule-matches/aria-required-parent-matches.js b/test/rule-matches/aria-required-parent-matches.js index 53f380839..ceeb1bad5 100644 --- a/test/rule-matches/aria-required-parent-matches.js +++ b/test/rule-matches/aria-required-parent-matches.js @@ -1,9 +1,9 @@ describe('aria-required-parent-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var queryFixture = axe.testUtils.queryFixture; - var rule; + const fixture = document.getElementById('fixture'); + const queryFixture = axe.testUtils.queryFixture; + let rule; beforeEach(function () { rule = axe.utils.getRule('aria-required-parent'); @@ -14,12 +14,12 @@ describe('aria-required-parent-matches', function () { }); it('should return true for a role that requires parent', function () { - var vNode = queryFixture('<div id="target" role="listitem"></div>'); + const vNode = queryFixture('<div id="target" role="listitem"></div>'); assert.isTrue(rule.matches(null, vNode)); }); it('should return false for a role that does not require parent', function () { - var vNode = queryFixture('<div id="target" role="alert"></div>'); + const vNode = queryFixture('<div id="target" role="alert"></div>'); assert.isFalse(rule.matches(null, vNode)); }); }); diff --git a/test/rule-matches/autocomplete-matches.js b/test/rule-matches/autocomplete-matches.js index 73777cdc3..4f5de5de4 100644 --- a/test/rule-matches/autocomplete-matches.js +++ b/test/rule-matches/autocomplete-matches.js @@ -1,8 +1,8 @@ describe('autocomplete-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var queryFixture = axe.testUtils.queryFixture; - var rule = axe.utils.getRule('autocomplete-valid'); + const fixture = document.getElementById('fixture'); + const queryFixture = axe.testUtils.queryFixture; + const rule = axe.utils.getRule('autocomplete-valid'); afterEach(function () { fixture.innerHTML = ''; @@ -13,46 +13,52 @@ describe('autocomplete-matches', function () { }); it('returns true for input elements', function () { - var vNode = queryFixture('<input id="target" autocomplete="foo">'); + const vNode = queryFixture('<input id="target" autocomplete="foo">'); assert.isTrue(rule.matches(null, vNode)); }); it('returns true for select elements', function () { - var vNode = queryFixture('<select id="target" autocomplete="foo">'); + const vNode = queryFixture('<select id="target" autocomplete="foo">'); assert.isTrue(rule.matches(null, vNode)); }); it('returns true for textarea elements', function () { - var vNode = queryFixture('<textarea id="target" autocomplete="foo">'); + const vNode = queryFixture('<textarea id="target" autocomplete="foo">'); assert.isTrue(rule.matches(null, vNode)); }); it('returns false for buttons elements', function () { - var vNode = queryFixture('<button id="target" autocomplete="foo">'); + const vNode = queryFixture('<button id="target" autocomplete="foo">'); assert.isFalse(rule.matches(null, vNode)); }); it('should return false for non-form field elements', function () { - var vNode = queryFixture('<div id="target" autocomplete="foo">'); + const vNode = queryFixture('<div id="target" autocomplete="foo">'); assert.isFalse(rule.matches(null, vNode)); }); it('returns false for input buttons', function () { ['reset', 'submit', 'button'].forEach(function (type) { - var vNode = queryFixture( + const vNode = queryFixture( '<input id="target" type="' + type + '" autocomplete="foo">' ); assert.isFalse(rule.matches(null, vNode)); }); }); +<<<<<<< HEAD it('returns true for elements with an empty autocomplete', function () { var vNode = queryFixture('<input id="target" autocomplete=" ">'); assert.isTrue(rule.matches(null, vNode)); +======= + it('returns false for elements with an empty autocomplete', function () { + const vNode = queryFixture('<input id="target" autocomplete=" ">'); + assert.isFalse(rule.matches(null, vNode)); +>>>>>>> e997880ebbfefc634caf535727afe2d5efd212f3 }); it('returns false for intput[type=hidden]', function () { - var vNode = queryFixture( + const vNode = queryFixture( '<input id="target" type="hidden" autocomplete="foo">' ); assert.isFalse(rule.matches(null, vNode)); @@ -60,7 +66,7 @@ describe('autocomplete-matches', function () { it('returns false for disabled fields', function () { ['input', 'select', 'textarea'].forEach(function (tagName) { - var vNode = queryFixture( + const vNode = queryFixture( '<' + tagName + ' id="target" disabled autocomplete="foo">' ); assert.isFalse(rule.matches(null, vNode)); @@ -69,7 +75,7 @@ describe('autocomplete-matches', function () { it('returns false for aria-disabled=true fields', function () { ['input', 'select', 'textarea'].forEach(function (tagName) { - var vNode = queryFixture( + const vNode = queryFixture( '<' + tagName + ' id="target" aria-disabled="true" autocomplete="foo">' ); assert.isFalse(rule.matches(null, vNode)); @@ -78,7 +84,7 @@ describe('autocomplete-matches', function () { it('returns true for aria-disabled=false fields', function () { ['input', 'select', 'textarea'].forEach(function (tagName) { - var vNode = queryFixture( + const vNode = queryFixture( '<' + tagName + ' id="target" aria-disabled="false" autocomplete="foo">' ); assert.isTrue(rule.matches(null, vNode)); @@ -86,9 +92,9 @@ describe('autocomplete-matches', function () { }); it('returns false for non-widget roles with tabindex=-1', function () { - var nonWidgetRoles = ['application', 'fakerole', 'main']; + const nonWidgetRoles = ['application', 'fakerole', 'main']; nonWidgetRoles.forEach(function (role) { - var vNode = queryFixture( + const vNode = queryFixture( '<input id="target" role="' + role + '" tabindex="-1" autocomplete="foo">' @@ -101,9 +107,9 @@ describe('autocomplete-matches', function () { }); it('returns true for form fields with a widget role with tabindex=-1', function () { - var nonWidgetRoles = ['button', 'menuitem', 'slider']; + const nonWidgetRoles = ['button', 'menuitem', 'slider']; nonWidgetRoles.forEach(function (role) { - var vNode = queryFixture( + const vNode = queryFixture( '<input id="target" role="' + role + '" tabindex="-1" autocomplete="foo">' @@ -114,7 +120,7 @@ describe('autocomplete-matches', function () { it('returns true for form fields with tabindex=-1', function () { ['input', 'select', 'textarea'].forEach(function (tagName) { - var vNode = queryFixture( + const vNode = queryFixture( '<' + tagName + ' id="target" tabindex="-1" autocomplete="foo">' ); assert.isTrue(rule.matches(null, vNode)); @@ -122,11 +128,32 @@ describe('autocomplete-matches', function () { }); it('returns false for off screen and hidden form fields with tabindex=-1', function () { - var vNode = queryFixture( + const vNode = queryFixture( '<div aria-hidden="true">' + '<input id="target" tabindex="-1" style="position:absolute; top:-9999em" autocomplete="foo">' + '</div>' ); assert.isFalse(rule.matches(null, vNode)); }); + + it('returns false if readonly attribute is placed whether autocomplete is not valid', function () { + var vNode = queryFixture( + '<input readonly autocomplete="some invalid value" id="target" />' + ); + assert.isFalse(rule.matches(null, vNode)); + }); + + it('returns false if aria-readonly attribute is true whether autocomplete is not valid', function () { + var vNode = queryFixture( + '<input aria-readonly="true" autocomplete="some invalid value" id="target" />' + ); + assert.isFalse(rule.matches(null, vNode)); + }); + + it('returns true if aria-readonly attribute is false whether autocomplete is not valid', function () { + var vNode = queryFixture( + '<input aria-readonly="false" autocomplete="some invalid value" id="target" />' + ); + assert.isTrue(rule.matches(null, vNode)); + }); }); diff --git a/test/rule-matches/color-contrast-matches.js b/test/rule-matches/color-contrast-matches.js index fc41e301e..d85aee88b 100644 --- a/test/rule-matches/color-contrast-matches.js +++ b/test/rule-matches/color-contrast-matches.js @@ -1,10 +1,10 @@ describe('color-contrast-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var shadowSupport = + const fixture = document.getElementById('fixture'); + const shadowSupport = document.body && typeof document.body.attachShadow === 'function'; - var rule; + let rule; beforeEach(function () { rule = axe.utils.getRule('color-contrast'); @@ -23,7 +23,7 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div style="color: yellow; background-color: white;" id="target">' + ' </div>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -32,7 +32,7 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div style="color: yellow; background-color: white;" id="target">' + 'My text</div>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -41,7 +41,7 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div style="color: yellow; background-color: white;" id="target">' + '🌎</div>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -50,7 +50,7 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div style="color: yellow; background-color: white;" id="target">' + '‏</div>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -59,7 +59,7 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div style="color: yellow; background-color: white;" id="target">' + '◓</div>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -68,7 +68,7 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div style="color: yellow; text-indent: -9999px; background-color: white;" id="target">' + 'My text</div>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -76,7 +76,7 @@ describe('color-contrast-matches', function () { it('should not match input when there is text that is out of the container', function () { fixture.innerHTML = '<input style="text-indent: -9999px" type="submit" value="Search" />'; - var target = fixture.querySelector('input'); + const target = fixture.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -86,7 +86,7 @@ describe('color-contrast-matches', function () { '<select style="text-indent: -9999px">' + '<option selected>My text</option>' + '</select>'; - var target = fixture.querySelector('select'); + const target = fixture.querySelector('select'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -94,7 +94,7 @@ describe('color-contrast-matches', function () { it('should not match textarea when there is text that is out of the container', function () { fixture.innerHTML = '<textarea style="text-indent: -9999px">My text</textarea>'; - var target = fixture.querySelector('textarea'); + const target = fixture.querySelector('textarea'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -103,7 +103,7 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div style="color: yellow; width: 100px; overflow: hidden; text-indent: 200px; background-color: white;" id="target">' + 'text</div>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -112,7 +112,7 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div style="color: yellow; width: 100px; overflow: scroll; text-indent: 200px; background-color: white;" id="target">' + 'text</div>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -121,42 +121,42 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div style="color: yellow; text-indent: -20px; background-color: white;" id="target">' + 'My text</div>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should match <input type="text">', function () { fixture.innerHTML = '<input type="text">'; - var target = fixture.querySelector('input'); + const target = fixture.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match <input type="hidden">', function () { fixture.innerHTML = '<input type="hidden">'; - var target = fixture.querySelector('input'); + const target = fixture.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match <input type="checkbox">', function () { fixture.innerHTML = '<input type="checkbox">'; - var target = fixture.querySelector('input'); + const target = fixture.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match <input type="radio">', function () { fixture.innerHTML = '<input type="radio">'; - var target = fixture.querySelector('input'); + const target = fixture.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match <input type="color">', function () { fixture.innerHTML = '<input type="color">'; - var target = fixture.querySelector('input'); + const target = fixture.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); // Some browsers will fallback to type=text for unknown input types (looking at you IE) if (target.type === 'color') { @@ -166,7 +166,7 @@ describe('color-contrast-matches', function () { it('should not match <input type="range">', function () { fixture.innerHTML = '<input type="range">'; - var target = fixture.querySelector('input'); + const target = fixture.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); // Some browsers will fallback to type=text for unknown input types (looking at you IE) if (target.type === 'range') { @@ -176,35 +176,35 @@ describe('color-contrast-matches', function () { it('should match <select> with options', function () { fixture.innerHTML = '<select><option>Hello</option></select>'; - var target = fixture.querySelector('select'); + const target = fixture.querySelector('select'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match <select> with no options', function () { fixture.innerHTML = '<select></select>'; - var target = fixture.querySelector('select'); + const target = fixture.querySelector('select'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should match <textarea>', function () { fixture.innerHTML = '<textarea></textarea>'; - var target = fixture.querySelector('textarea'); + const target = fixture.querySelector('textarea'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match <option>', function () { fixture.innerHTML = '<select><option>hi</option></select>'; - var target = fixture.querySelector('option'); + const target = fixture.querySelector('option'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match inputs that are disabled', function () { fixture.innerHTML = '<input type="text" disabled>'; - var target = fixture.querySelector('input'); + const target = fixture.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -216,43 +216,43 @@ describe('color-contrast-matches', function () { '<span style="background-color:rgba(0, 0, 0, 0.26);display:inline-block;width: 1.5rem;height: 1.5rem;" aria-hidden="true"></span>' + '<span style="color:rgba(0, 0, 0, 0.38);" id="target">Baseball</span>' + '</label>'; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); axe.testUtils.flatTreeSetup(fixture); - var result = rule.matches(target, axe.utils.getNodeFromTree(target)); + const result = rule.matches(target, axe.utils.getNodeFromTree(target)); assert.isFalse(result); }); it('should not match <textarea disabled>', function () { fixture.innerHTML = '<textarea disabled></textarea>'; - var target = fixture.querySelector('textarea'); + const target = fixture.querySelector('textarea'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match <select> with options', function () { fixture.innerHTML = '<select disabled><option>Hello</option></select>'; - var target = fixture.querySelector('select'); + const target = fixture.querySelector('select'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should match <button>', function () { fixture.innerHTML = '<button>hi</button>'; - var target = fixture.querySelector('button'); + const target = fixture.querySelector('button'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match <button disabled>', function () { fixture.innerHTML = '<button disabled>hi</button>'; - var target = fixture.querySelector('button'); + const target = fixture.querySelector('button'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match <button disabled><span></span></button>', function () { fixture.innerHTML = '<button disabled><span>Hi</span></button>'; - var target = fixture.querySelector('button'); + const target = fixture.querySelector('button'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( rule.matches( @@ -264,7 +264,7 @@ describe('color-contrast-matches', function () { it('should not match <button disabled><span><i></i></span></button>', function () { fixture.innerHTML = '<button disabled><span><i>Hi</i></span></button>'; - var target = fixture.querySelector('button'); + const target = fixture.querySelector('button'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( rule.matches( @@ -276,7 +276,7 @@ describe('color-contrast-matches', function () { it('should not match <input type=image>', function () { fixture.innerHTML = '<input type="image">'; - var target = fixture.querySelector('input'); + const target = fixture.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -284,7 +284,7 @@ describe('color-contrast-matches', function () { it("should not match a disabled input's label - explicit label", function () { fixture.innerHTML = '<label for="t1">Test</label><input type="text" id="t1" disabled>'; - var target = fixture.querySelector('label'); + const target = fixture.querySelector('label'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -292,7 +292,7 @@ describe('color-contrast-matches', function () { it("should not match an aria-disabled input's label - explicit label", function () { fixture.innerHTML = '<label for="t1">Test</label><input type="text" id="t1" aria-disabled="true">'; - var target = fixture.querySelector('label'); + const target = fixture.querySelector('label'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -300,21 +300,21 @@ describe('color-contrast-matches', function () { it("should not match a parent aria-disabled input's label - explicit label", function () { fixture.innerHTML = '<label for="t1">Test</label><div aria-disabled="true"><input type="text" id="t1"></div>'; - var target = fixture.querySelector('label'); + const target = fixture.querySelector('label'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it("should not match a disabled input's label - implicit label (input)", function () { fixture.innerHTML = '<label>Test<input type="text" disabled></label>'; - var target = fixture.querySelector('label'); + const target = fixture.querySelector('label'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it("should not match a disabled input's label - implicit label (textarea)", function () { fixture.innerHTML = '<label>Test<textarea disabled>Hi</textarea></label>'; - var target = fixture.querySelector('label'); + const target = fixture.querySelector('label'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -322,7 +322,7 @@ describe('color-contrast-matches', function () { it("should not match a disabled input's label - implicit label (select)", function () { fixture.innerHTML = '<label>Test<select disabled><option>Test</option></select></label>'; - var target = fixture.querySelector('label'); + const target = fixture.querySelector('label'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -330,7 +330,7 @@ describe('color-contrast-matches', function () { it("should not match a disabled input's label - aria-labelledby", function () { fixture.innerHTML = '<div id="t1">Test</div><input type="text" aria-labelledby="bob t1 fred" disabled>'; - var target = fixture.querySelector('div'); + const target = fixture.querySelector('div'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -340,7 +340,7 @@ describe('color-contrast-matches', function () { '<div id="t1">Test</div>' + '<input type="text" aria-labelledby="t1" disabled />' + '<input type="text" aria-labelledby="t1" />'; - var target = fixture.querySelector('div'); + const target = fixture.querySelector('div'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -352,21 +352,21 @@ describe('color-contrast-matches', function () { '<input type="text" aria-labelledby="t1" />' + '<input type="text" aria-labelledby="t1" />' + '</fieldset>'; - var target = fixture.querySelector('div'); + const target = fixture.querySelector('div'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match aria-disabled=true', function () { fixture.innerHTML = '<div aria-disabled="true">hi</div>'; - var target = fixture.querySelector('div'); + const target = fixture.querySelector('div'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match a descendant of aria-disabled=true', function () { fixture.innerHTML = '<div aria-disabled="true"><span>hi</span></div>'; - var target = fixture.querySelector('span'); + const target = fixture.querySelector('span'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -375,7 +375,7 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div id="t1"><span>Test</span></div>' + '<div role="textbox" aria-labelledby="bob t1 fred" aria-disabled="true"></div>'; - var target = fixture.querySelector('span'); + const target = fixture.querySelector('span'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -383,7 +383,7 @@ describe('color-contrast-matches', function () { it('should not match a descendant of a disabled fieldset', function () { fixture.innerHTML = '<fieldset disabled><label>hi <input type="checkbox"></label></fieldset>'; - var target = fixture.querySelector('label'); + const target = fixture.querySelector('label'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -391,7 +391,7 @@ describe('color-contrast-matches', function () { it('should not match a descendant of an explicit label for a disabled input', function () { fixture.innerHTML = '<input id="input" type="checkbox" disabled><label for="input"><span>hi</span></label>'; - var target = fixture.querySelector('span'); + const target = fixture.querySelector('span'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -399,21 +399,21 @@ describe('color-contrast-matches', function () { it('should not match a descendant of an implicit label for a disabled input', function () { fixture.innerHTML = '<label for="input"><span>hi</span><input id="input" type="checkbox" disabled></label>'; - var target = fixture.querySelector('span'); + const target = fixture.querySelector('span'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match inert', function () { fixture.innerHTML = '<div inert>hi</div>'; - var target = fixture.querySelector('div'); + const target = fixture.querySelector('div'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); it('should not match a descendant of inert', function () { fixture.innerHTML = '<div inert><span>hi</span></div>'; - var target = fixture.querySelector('span'); + const target = fixture.querySelector('span'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -426,7 +426,14 @@ describe('color-contrast-matches', function () { </div> </div> `; - var target = fixture.querySelector('#target'); + const target = fixture.querySelector('#target'); + axe.testUtils.flatTreeSetup(fixture); + assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); + }); + + it('should not match text with font-size: 0', () => { + fixture.innerHTML = '<div style="font-size: 0">hi</div>'; + const target = fixture.querySelector('div'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target))); }); @@ -436,13 +443,13 @@ describe('color-contrast-matches', function () { fixture.innerHTML = '<div id="parent" style="background-color: #000;">' + '</div>'; - var shadowRoot = document + const shadowRoot = document .getElementById('parent') .attachShadow({ mode: 'open' }); shadowRoot.innerHTML = '<div id="shadowTarget" style="color: #333">Text</div>'; - var shadowTarget = + const shadowTarget = fixture.firstChild.shadowRoot.querySelector('#shadowTarget'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue( @@ -453,7 +460,7 @@ describe('color-contrast-matches', function () { it('should look at the correct root node when looking up an explicit label and disabled input', function () { fixture.innerHTML = '<div id="parent">' + '<input id="input">' + '</div>'; - var shadowRoot = document + const shadowRoot = document .getElementById('parent') .attachShadow({ mode: 'open' }); shadowRoot.innerHTML = @@ -462,7 +469,7 @@ describe('color-contrast-matches', function () { '<input id="input" disabled>' + '</div>'; - var shadowLabel = + const shadowLabel = fixture.firstChild.shadowRoot.querySelector('#shadowLabel'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( @@ -473,7 +480,7 @@ describe('color-contrast-matches', function () { it('should look at the correct root node when looking up implicit label and disabled input', function () { fixture.innerHTML = '<div id="parent">' + '<input>' + '</div>'; - var shadowRoot = document + const shadowRoot = document .getElementById('parent') .attachShadow({ mode: 'open' }); shadowRoot.innerHTML = @@ -481,7 +488,7 @@ describe('color-contrast-matches', function () { '<label id="shadowLabel">Label <input disabled></label>' + '</div>'; - var shadowLabel = + const shadowLabel = fixture.firstChild.shadowRoot.querySelector('#shadowLabel'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( @@ -492,7 +499,7 @@ describe('color-contrast-matches', function () { it("should look at the correct root node for a disabled control's label associated w/ aria-labelledby", function () { fixture.innerHTML = '<div id="parent">' + '<input id="input">' + '</div>'; - var shadowRoot = document + const shadowRoot = document .getElementById('parent') .attachShadow({ mode: 'open' }); shadowRoot.innerHTML = @@ -501,7 +508,7 @@ describe('color-contrast-matches', function () { '<input aria-labelledby="shadowLabel" disabled>' + '</div>'; - var shadowLabel = + const shadowLabel = fixture.firstChild.shadowRoot.querySelector('#shadowLabel'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( @@ -512,11 +519,11 @@ describe('color-contrast-matches', function () { it('should handle input/label spread across the shadow boundary', function () { fixture.innerHTML = '<label>Text <div id="firstChild"></div></label>'; - var container = document.getElementById('firstChild'); - var shadowRoot = container.attachShadow({ mode: 'open' }); + const container = document.getElementById('firstChild'); + const shadowRoot = container.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = '<input type="text" id="input" disabled />'; - var shadowTarget = container.shadowRoot.querySelector('#input'); + const shadowTarget = container.shadowRoot.querySelector('#input'); axe.testUtils.flatTreeSetup(fixture); assert.isFalse( rule.matches(shadowTarget, axe.utils.getNodeFromTree(shadowTarget)) @@ -529,14 +536,14 @@ describe('color-contrast-matches', function () { '<div id="firstChild" style="background-color: #ccc; color: #fff;"></div>' + '</div>'; - var shadowRoot = document + const shadowRoot = document .getElementById('firstChild') .attachShadow({ mode: 'open' }); shadowRoot.innerHTML = 'Some text' + '<p style="color: #fff;" id="shadowTarget">Other text</p>'; - var firstChild = fixture.querySelector('#firstChild'); + const firstChild = fixture.querySelector('#firstChild'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue( rule.matches(firstChild, axe.utils.getNodeFromTree(firstChild)) @@ -550,16 +557,16 @@ describe('color-contrast-matches', function () { '</span></label>'; function createContentSlotted() { - var group = document.createElement('span'); + const group = document.createElement('span'); group.innerHTML = '<slot></slot>'; return group; } - var slotted = fixture.querySelector('.slotted'); - var shadowRoot = slotted.attachShadow({ mode: 'open' }); + const slotted = fixture.querySelector('.slotted'); + const shadowRoot = slotted.attachShadow({ mode: 'open' }); shadowRoot.appendChild(createContentSlotted()); - var input = slotted.querySelector('input'); + const input = slotted.querySelector('input'); axe.testUtils.flatTreeSetup(fixture); assert.isTrue(rule.matches(input, axe.utils.getNodeFromTree(input))); }); diff --git a/test/rule-matches/data-table-matches.js b/test/rule-matches/data-table-matches.js index ab1e92523..24e0fff16 100644 --- a/test/rule-matches/data-table-matches.js +++ b/test/rule-matches/data-table-matches.js @@ -1,9 +1,9 @@ describe('data-table-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var fixtureSetup = axe.testUtils.fixtureSetup; - var rule; + const fixture = document.getElementById('fixture'); + const fixtureSetup = axe.testUtils.fixtureSetup; + let rule; beforeEach(function () { rule = axe.utils.getRule('th-has-data-cells'); @@ -25,7 +25,7 @@ describe('data-table-matches', function () { '</table>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'table')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'table')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); @@ -37,7 +37,7 @@ describe('data-table-matches', function () { '</table>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'table')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'table')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); @@ -50,7 +50,7 @@ describe('data-table-matches', function () { '</table>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'table')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'table')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); }); diff --git a/test/rule-matches/duplicate-id-active-matches.js b/test/rule-matches/duplicate-id-active-matches.js index 60bb45d3c..f34db28c6 100644 --- a/test/rule-matches/duplicate-id-active-matches.js +++ b/test/rule-matches/duplicate-id-active-matches.js @@ -1,9 +1,9 @@ describe('duplicate-id-active matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var fixtureSetup = axe.testUtils.fixtureSetup; - var rule; + const fixture = document.getElementById('fixture'); + const fixtureSetup = axe.testUtils.fixtureSetup; + let rule; beforeEach(function () { rule = axe.utils.getRule('duplicate-id-active'); @@ -19,31 +19,31 @@ describe('duplicate-id-active matches', function () { it('returns false if the ID is of an inactive non-referenced element', function () { fixtureSetup('<div id="foo"></div>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); it('returns false if the ID is of an inactive non-referenced element with a duplicate', function () { fixtureSetup('<div id="foo"></div><span id="foo"></span>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); it('returns true if the ID is of an active non-referenced element', function () { fixtureSetup('<button id="foo"></button>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); it('returns true if the ID is a duplicate of an active non-referenced element', function () { fixtureSetup('<div id="foo"></div>' + '<button id="foo"></button>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); it('returns false if the ID is of an inactive ARIA referenced element', function () { fixtureSetup('<div id="foo"></div>' + '<div aria-labelledby="foo"></div>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); @@ -53,7 +53,7 @@ describe('duplicate-id-active matches', function () { '<div aria-labelledby="foo"></div>' + '<span id="foo"></span>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); @@ -61,7 +61,7 @@ describe('duplicate-id-active matches', function () { fixtureSetup( '<button id="foo"></button>' + '<div aria-labelledby="foo"></div>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); @@ -71,7 +71,7 @@ describe('duplicate-id-active matches', function () { '<div aria-labelledby="foo"></div>' + '<span id="foo"></span>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); }); diff --git a/test/rule-matches/duplicate-id-aria-matches.js b/test/rule-matches/duplicate-id-aria-matches.js index 2ebd3a071..4ddf03f74 100644 --- a/test/rule-matches/duplicate-id-aria-matches.js +++ b/test/rule-matches/duplicate-id-aria-matches.js @@ -1,9 +1,9 @@ describe('duplicate-id-aria matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var fixtureSetup = axe.testUtils.fixtureSetup; - var rule; + const fixture = document.getElementById('fixture'); + const fixtureSetup = axe.testUtils.fixtureSetup; + let rule; beforeEach(function () { rule = axe.utils.getRule('duplicate-id-aria'); @@ -19,31 +19,31 @@ describe('duplicate-id-aria matches', function () { it('returns false if the ID is of an inactive non-referenced element', function () { fixtureSetup('<div id="foo"></div>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); it('returns false if the ID is of an inactive non-referenced element with a duplicate', function () { fixtureSetup('<div id="foo"></div><span id="foo"></span>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); it('returns false if the ID is of an active non-referenced element', function () { fixtureSetup('<button id="foo"></button>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); it('returns false if the ID is a duplicate of an active non-referenced element', function () { fixtureSetup('<div id="foo"></div>' + '<button id="foo"></button>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); it('returns true if the ID is of an inactive ARIA referenced element', function () { fixtureSetup('<div id="foo"></div>' + '<div aria-labelledby="foo"></div>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); @@ -53,7 +53,7 @@ describe('duplicate-id-aria matches', function () { '<div aria-labelledby="foo"></div>' + '<span id="foo"></span>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); @@ -61,7 +61,7 @@ describe('duplicate-id-aria matches', function () { fixtureSetup( '<button id="foo"></button>' + '<div aria-labelledby="foo"></div>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); @@ -71,7 +71,7 @@ describe('duplicate-id-aria matches', function () { '<div aria-labelledby="foo"></div>' + '<span id="foo"></span>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); }); diff --git a/test/rule-matches/duplicate-id-misc-matches.js b/test/rule-matches/duplicate-id-misc-matches.js index 77f2331b2..d44c94059 100644 --- a/test/rule-matches/duplicate-id-misc-matches.js +++ b/test/rule-matches/duplicate-id-misc-matches.js @@ -1,9 +1,9 @@ describe('duplicate-id-misc matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var fixtureSetup = axe.testUtils.fixtureSetup; - var rule; + const fixture = document.getElementById('fixture'); + const fixtureSetup = axe.testUtils.fixtureSetup; + let rule; beforeEach(function () { rule = axe.utils.getRule('duplicate-id'); @@ -19,31 +19,31 @@ describe('duplicate-id-misc matches', function () { it('returns true if the ID is of an inactive non-referenced element', function () { fixtureSetup('<div id="foo"></div>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); it('returns true if the ID is of an inactive non-referenced element with a duplicate', function () { fixtureSetup('<div id="foo"></div><span id="foo"></span>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); it('returns false if the ID is of an active non-referenced element', function () { fixtureSetup('<button id="foo"></button>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); it('returns false if the ID is a duplicate of an active non-referenced element', function () { fixtureSetup('<div id="foo"></div>' + '<button id="foo"></button>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); it('returns false if the ID is of an inactive ARIA referenced element', function () { fixtureSetup('<div id="foo"></div>' + '<div aria-labelledby="foo"></div>'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'div[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); @@ -53,7 +53,7 @@ describe('duplicate-id-misc matches', function () { '<div aria-labelledby="foo"></div>' + '<span id="foo"></span>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); @@ -61,7 +61,7 @@ describe('duplicate-id-misc matches', function () { fixtureSetup( '<button id="foo"></button>' + '<div aria-labelledby="foo"></div>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'button[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); @@ -71,7 +71,7 @@ describe('duplicate-id-misc matches', function () { '<div aria-labelledby="foo"></div>' + '<span id="foo"></span>' ); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'span[id=foo]')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); }); diff --git a/test/rule-matches/frame-focusable-content-matches.js b/test/rule-matches/frame-focusable-content-matches.js index 8adc9ef5b..996397bc2 100644 --- a/test/rule-matches/frame-focusable-content-matches.js +++ b/test/rule-matches/frame-focusable-content-matches.js @@ -1,13 +1,13 @@ describe('frame-focusable-content-matches', function () { 'use strict'; - var rule; + let rule; beforeEach(function () { rule = axe.utils.getRule('frame-focusable-content'); }); it('returns false for the top-level context', function () { - var result = rule.matches(null, null, { + const result = rule.matches(null, null, { initiator: true, focusable: false, size: { @@ -19,7 +19,7 @@ describe('frame-focusable-content-matches', function () { }); it('returns false for focusable iframes', function () { - var result = rule.matches(null, null, { + const result = rule.matches(null, null, { initiator: false, focusable: true, size: { @@ -31,7 +31,7 @@ describe('frame-focusable-content-matches', function () { }); it('returns false for non-focusable iframes that are too small (1x1)', function () { - var result = rule.matches(null, null, { + const result = rule.matches(null, null, { initiator: false, focusable: false, size: { @@ -43,7 +43,7 @@ describe('frame-focusable-content-matches', function () { }); it('returns false for non-focusable iframes that are too small (0x0)', function () { - var result = rule.matches(null, null, { + const result = rule.matches(null, null, { initiator: false, focusable: false, size: { @@ -55,7 +55,7 @@ describe('frame-focusable-content-matches', function () { }); it('returns true for non-focusable iframes', function () { - var result = rule.matches(null, null, { + const result = rule.matches(null, null, { initiator: false, focusable: false, size: { diff --git a/test/rule-matches/frame-title-has-text-matches.js b/test/rule-matches/frame-title-has-text-matches.js index cb9bbe42f..c72859888 100644 --- a/test/rule-matches/frame-title-has-text-matches.js +++ b/test/rule-matches/frame-title-has-text-matches.js @@ -1,8 +1,8 @@ describe('layout-table-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var rule; + const fixture = document.getElementById('fixture'); + let rule; beforeEach(function () { rule = axe.utils.getRule('frame-title-unique'); @@ -14,19 +14,19 @@ describe('layout-table-matches', function () { it('should return true if title attribute has text', function () { fixture.innerHTML = '<iframe title="hello"></iframe>'; - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isTrue(rule.matches(node)); }); it('should return false if title attribute is empty', function () { fixture.innerHTML = '<iframe title=""></iframe>'; - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isFalse(rule.matches(node)); }); it('should return false if title attribute contains only whitespace', function () { fixture.innerHTML = '<iframe title=" "></iframe>'; - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isFalse(rule.matches(node)); }); }); diff --git a/test/rule-matches/has-implicit-chromium-role-matches.js b/test/rule-matches/has-implicit-chromium-role-matches.js index 55c54807c..448cb2070 100644 --- a/test/rule-matches/has-implicit-chromium-role-matches.js +++ b/test/rule-matches/has-implicit-chromium-role-matches.js @@ -1,9 +1,9 @@ describe('has-implicit-chromium-role-matches', function () { 'use strict'; - var rule; - var fixture = document.getElementById('fixture'); - var queryFixture = axe.testUtils.queryFixture; + let rule; + const fixture = document.getElementById('fixture'); + const queryFixture = axe.testUtils.queryFixture; beforeEach(function () { rule = axe.utils.getRule('presentation-role-conflict'); @@ -18,22 +18,22 @@ describe('has-implicit-chromium-role-matches', function () { }); it('matches elements with an implicit role', function () { - var vNode = queryFixture('<main id="target"></main>'); + const vNode = queryFixture('<main id="target"></main>'); assert.isTrue(rule.matches(null, vNode)); }); it('does not match elements with no implicit role', function () { - var vNode = queryFixture('<div id="target"></div>'); + const vNode = queryFixture('<div id="target"></div>'); assert.isFalse(rule.matches(null, vNode)); }); it('matches elements with an implicit role in chromium', function () { - var vNode = queryFixture('<svg id="target"></svg>'); + const vNode = queryFixture('<svg id="target"></svg>'); assert.isTrue(rule.matches(null, vNode)); }); it('does not match elements with no implicit role even if they are focusable and have an explicit role', function () { - var vNode = queryFixture( + const vNode = queryFixture( '<div id="target" role="none" tabindex="1"></div>' ); assert.isFalse(rule.matches(null, vNode)); diff --git a/test/rule-matches/heading-matches.js b/test/rule-matches/heading-matches.js index 4939f16b9..59f825054 100644 --- a/test/rule-matches/heading-matches.js +++ b/test/rule-matches/heading-matches.js @@ -1,8 +1,8 @@ describe('heading-matches', function () { 'use strict'; - var queryFixture = axe.testUtils.queryFixture; - var fixtureSetup = axe.testUtils.fixtureSetup; - var rule; + const queryFixture = axe.testUtils.queryFixture; + const fixtureSetup = axe.testUtils.fixtureSetup; + let rule; beforeEach(function () { rule = axe.utils.getRule('empty-heading'); @@ -13,39 +13,41 @@ describe('heading-matches', function () { }); it('should return false on elements that are not headings', function () { - var vNode = fixtureSetup('<div></div>'); + const vNode = fixtureSetup('<div></div>'); assert.isFalse(rule.matches(null, vNode)); }); it('should return true on elements with role="heading"', function () { - var vNode = queryFixture('<div role="heading" id="target"></div>'); + const vNode = queryFixture('<div role="heading" id="target"></div>'); assert.isTrue(rule.matches(null, vNode)); }); it('should return true on regular headings without roles', function () { - for (var i = 1; i <= 6; i++) { - var vNode = queryFixture('<h' + i + ' id="target"></h' + i + '>'); + for (let i = 1; i <= 6; i++) { + const vNode = queryFixture('<h' + i + ' id="target"></h' + i + '>'); assert.isTrue(rule.matches(null, vNode)); } }); it('should return false on headings with their role changes', function () { - var vNode = queryFixture('<h1 role="banner" id="target"></h1>'); + const vNode = queryFixture('<h1 role="banner" id="target"></h1>'); assert.isFalse(rule.matches(null, vNode)); }); it('should return true on headings with their role changes to an invalid role', function () { - var vNode = queryFixture('<h1 role="bruce" id="target"></h1>'); + const vNode = queryFixture('<h1 role="bruce" id="target"></h1>'); assert.isTrue(rule.matches(null, vNode)); }); it('should return true on headings with their role changes to an abstract role', function () { - var vNode = queryFixture('<h1 role="widget" id="target"></h1>'); + const vNode = queryFixture('<h1 role="widget" id="target"></h1>'); assert.isTrue(rule.matches(null, vNode)); }); it('should return true on headings with explicit role="none" and an empty aria-label to account for presentation conflict resolution', function () { - var vNode = queryFixture('<h1 aria-label="" role="none" id="target"></h1>'); + const vNode = queryFixture( + '<h1 aria-label="" role="none" id="target"></h1>' + ); assert.isTrue(rule.matches(null, vNode)); }); }); diff --git a/test/rule-matches/html-namespace-matches.js b/test/rule-matches/html-namespace-matches.js index 48ff0a266..c6582e7ee 100644 --- a/test/rule-matches/html-namespace-matches.js +++ b/test/rule-matches/html-namespace-matches.js @@ -1,8 +1,8 @@ describe('html-namespace-matches', function () { 'use strict'; - var rule; - var fixture; - var axeFixtureSetup; + let rule; + let fixture; + let axeFixtureSetup; beforeEach(function () { fixture = document.getElementById('fixture'); @@ -16,22 +16,22 @@ describe('html-namespace-matches', function () { it('returns true when passed an HTML element', function () { axeFixtureSetup('<h1>Hello world</h1>'); - var node = fixture.querySelector('h1'); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const node = fixture.querySelector('h1'); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isTrue(rule.matches(node, virtualNode)); }); it('returns true when passed a custom HTML element', function () { axeFixtureSetup('<xx-heading>Hello world</xx-heading>'); - var node = fixture.querySelector('xx-heading'); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const node = fixture.querySelector('xx-heading'); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isTrue(rule.matches(node, virtualNode)); }); it('returns false when passed an SVG element', function () { axeFixtureSetup('<svg><title>Pretty picture'); - var node = fixture.querySelector('svg'); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const node = fixture.querySelector('svg'); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isFalse(rule.matches(node, virtualNode)); }); @@ -39,14 +39,14 @@ describe('html-namespace-matches', function () { axeFixtureSetup( 'Pretty picture' ); - var node = fixture.querySelector('circle'); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const node = fixture.querySelector('circle'); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isFalse(rule.matches(node, virtualNode)); }); describe('Serial Virtual Node', function () { it('returns true when passed an HTML element', function () { - var serialNode = new axe.SerialVirtualNode({ + const serialNode = new axe.SerialVirtualNode({ nodeName: 'h1' }); serialNode.parent = null; @@ -55,7 +55,7 @@ describe('html-namespace-matches', function () { }); it('returns true when passed a custom HTML element', function () { - var serialNode = new axe.SerialVirtualNode({ + const serialNode = new axe.SerialVirtualNode({ nodeName: 'xx-heading' }); serialNode.parent = null; @@ -64,10 +64,10 @@ describe('html-namespace-matches', function () { }); it('returns false when passed an SVG circle element', function () { - var serialNode = new axe.SerialVirtualNode({ + const serialNode = new axe.SerialVirtualNode({ nodeName: 'circle' }); - var parent = new axe.SerialVirtualNode({ + const parent = new axe.SerialVirtualNode({ nodeName: 'svg' }); serialNode.parent = parent; diff --git a/test/rule-matches/html-xml-lang-mismatch.js b/test/rule-matches/html-xml-lang-mismatch.js index b710aef5c..cbac5a1fd 100644 --- a/test/rule-matches/html-xml-lang-mismatch.js +++ b/test/rule-matches/html-xml-lang-mismatch.js @@ -3,9 +3,9 @@ describe('xml-lang-mismatch-matches', function () { // nested this on a per rule basis, for future-proofing writing tests for multiple rules using the same matches describe('for rule: html-xml-lang-mismatch', function () { - var rule; - var dom; - var fixture = document.getElementById('fixture'); + let rule; + let dom; + const fixture = document.getElementById('fixture'); beforeEach(function () { rule = axe.utils.getRule('html-xml-lang-mismatch'); @@ -17,33 +17,33 @@ describe('xml-lang-mismatch-matches', function () { }); it('is a function', function () { - var actual = rule.matches; + const actual = rule.matches; assert.isFunction(actual); }); it('returns false if the element does not contain lang or xml:lang attribute', function () { - var actual = rule.matches(dom); + const actual = rule.matches(dom); assert.isFalse(actual); }); it('returns false if the element contains either/ only one of the lang or xml:lang attribute', function () { dom.setAttribute('lang', 'nl'); - var actual = rule.matches(dom); + const actual = rule.matches(dom); assert.isFalse(actual); }); it('returns true if the element contains both lang and xml:lang attribute', function () { dom.setAttribute('lang', 'en'); dom.setAttribute('xml:lang', 'nl'); - var actual = rule.matches(dom); + const actual = rule.matches(dom); assert.isTrue(actual); }); it('returns false for element of type that is not HTML', function () { - var node = document.createElement('svg'); + const node = document.createElement('svg'); node.setAttribute('lang', ''); node.setAttribute('xml:lang', 'nl'); - var actual = rule.matches(node); + const actual = rule.matches(node); assert.isFalse(actual); }); }); diff --git a/test/rule-matches/identical-links-same-purpose-matches.js b/test/rule-matches/identical-links-same-purpose-matches.js index 9aa044bd0..7e130d8c8 100644 --- a/test/rule-matches/identical-links-same-purpose-matches.js +++ b/test/rule-matches/identical-links-same-purpose-matches.js @@ -1,9 +1,9 @@ describe('identical-links-same-purpose-matches tests', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var queryFixture = axe.testUtils.queryFixture; - var rule = axe.utils.getRule('identical-links-same-purpose'); + const fixture = document.getElementById('fixture'); + const queryFixture = axe.testUtils.queryFixture; + const rule = axe.utils.getRule('identical-links-same-purpose'); afterEach(function () { fixture.innerHTML = ''; @@ -11,79 +11,81 @@ describe('identical-links-same-purpose-matches tests', function () { }); it('returns false when native link without accessible name', function () { - var vNode = queryFixture(''); - var actual = rule.matches(vNode.actualNode, vNode); + const vNode = queryFixture(''); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false for ARIA link without accessible name', function () { - var vNode = queryFixture(''); - var actual = rule.matches(vNode.actualNode, vNode); + const vNode = queryFixture(''); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false for native link with a role !== link', function () { - var vNode = queryFixture( + const vNode = queryFixture( 'Go to Checkout' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false when `area` has no parent `map` element', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false when `area` has parent `map` that is not referred by `img[usemap]`', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' + '' + '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns true when native link without href', function () { - var vNode = queryFixture('Book Now'); - var actual = rule.matches(vNode.actualNode, vNode); + const vNode = queryFixture('Book Now'); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); it('returns true when ARIA link without href', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); it('returns true when native link has an accessible name', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); it('returns true for ARIA link has an accessible name', function () { - var vNode = queryFixture('Book Tour'); - var actual = rule.matches(vNode.actualNode, vNode); + const vNode = queryFixture( + 'Book Tour' + ); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); it('returns true when `area` has parent `map` that is referred by `img`', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' + '' + '' + 'MDN infographic' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); }); diff --git a/test/rule-matches/is-initiator-matches.js b/test/rule-matches/is-initiator-matches.js index 8007f1f56..91199ed24 100644 --- a/test/rule-matches/is-initiator-matches.js +++ b/test/rule-matches/is-initiator-matches.js @@ -1,14 +1,14 @@ describe('is-initiator-matches', function () { 'use strict'; - var rule; + let rule; beforeEach(function () { rule = axe.utils.getRule('html-has-lang'); }); afterEach(function () { - var fixture = document.getElementById('fixture'); + const fixture = document.getElementById('fixture'); fixture.innerHTML = ''; }); diff --git a/test/rule-matches/is-visible-matches.js b/test/rule-matches/is-visible-matches.js index 847b796c2..b86098684 100644 --- a/test/rule-matches/is-visible-matches.js +++ b/test/rule-matches/is-visible-matches.js @@ -1,12 +1,12 @@ describe('is-visible-matches', function () { 'use strict'; - var isVisibleMatches = + let isVisibleMatches = axe._thisWillBeDeletedDoNotUse.base.metadataFunctionMap[ 'is-visible-matches' ]; - var fixture = document.getElementById('fixture'); - var fixtureSetup = axe.testUtils.fixtureSetup; + let fixture = document.getElementById('fixture'); + let fixtureSetup = axe.testUtils.fixtureSetup; it('returns true for visible elements', function () { fixtureSetup('

Hello world

'); diff --git a/test/rule-matches/label-content-name-mismatch-matches.js b/test/rule-matches/label-content-name-mismatch-matches.js index b47d2847d..7252a98e8 100644 --- a/test/rule-matches/label-content-name-mismatch-matches.js +++ b/test/rule-matches/label-content-name-mismatch-matches.js @@ -1,9 +1,9 @@ describe('label-content-name-mismatch-matches tests', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var queryFixture = axe.testUtils.queryFixture; - var rule = axe.utils.getRule('label-content-name-mismatch'); + const fixture = document.getElementById('fixture'); + const queryFixture = axe.testUtils.queryFixture; + const rule = axe.utils.getRule('label-content-name-mismatch'); afterEach(function () { fixture.innerHTML = ''; @@ -11,145 +11,145 @@ describe('label-content-name-mismatch-matches tests', function () { }); it('returns false if given element has no role', function () { - var vNode = queryFixture( + const vNode = queryFixture( '
' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false if element role is not supported with name from contents', function () { - var vNode = queryFixture( + const vNode = queryFixture( '
20 %
' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false if implicit element role is overridden to a role that does not support name from contents', function () { - var vNode = queryFixture( + const vNode = queryFixture( '
Status message
' + '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false if element does not have accessible name attributes (`aria-label` or `aria-labelledby`)', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false if element has empty accessible name via `aria-label`', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns true if element has accessible name via `aria-label`', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); it('returns true if element has accessible name via `aria-labelledby`', function () { - var vNode = queryFixture( + const vNode = queryFixture( '
some content
' + '
Foo text
' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); it('returns false if element has empty accessible name (`aria-labelledby`)', function () { - var vNode = queryFixture( + const vNode = queryFixture( '
some content
' + '
' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false if element has empty accessible name (`aria-labelledby`) because idref does not exist', function () { - var vNode = queryFixture( + const vNode = queryFixture( '
some content
' + '
Right Label
' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns true if element has accessible name (`aria-labelledby`) - multiple refs', function () { - var vNode = queryFixture( + const vNode = queryFixture( '
some content
' + '
Foo
' + '
Bar
' + '
Baz
' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); it('returns false for non-widget role', function () { - var vNode = queryFixture( + const vNode = queryFixture( 'Content Information' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false for non-widget role that does support name from content', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false for empty text content', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false for non text content', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns false for hidden (non visible) text content', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isFalse(actual); }); it('returns true when visible text is combination of alphanumeric and emoji characters', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); it('returns true when visible text is combination of alphanumeric and punctuation characters', function () { - var vNode = queryFixture( + const vNode = queryFixture( '' ); - var actual = rule.matches(vNode.actualNode, vNode); + const actual = rule.matches(vNode.actualNode, vNode); assert.isTrue(actual); }); }); diff --git a/test/rule-matches/label-matches.js b/test/rule-matches/label-matches.js index 8dbdc304d..4e4058920 100644 --- a/test/rule-matches/label-matches.js +++ b/test/rule-matches/label-matches.js @@ -1,9 +1,9 @@ describe('label-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var queryFixture = axe.testUtils.queryFixture; - var rule; + const fixture = document.getElementById('fixture'); + const queryFixture = axe.testUtils.queryFixture; + let rule; beforeEach(function () { fixture.innerHTML = ''; @@ -11,25 +11,25 @@ describe('label-matches', function () { }); it('returns true for non-input elements', function () { - var vNode = queryFixture(''); + const vNode = queryFixture(''); assert.isTrue(rule.matches(null, vNode)); }); it('returns true for input elements without type', function () { - var vNode = queryFixture(''); + const vNode = queryFixture(''); assert.isTrue(rule.matches(null, vNode)); }); it('returns false for input buttons', function () { ['button', 'submit', 'image', 'reset'].forEach(function (type) { - var vNode = queryFixture(''); + const vNode = queryFixture(''); assert.isFalse(rule.matches(null, vNode)); }); }); it('returns false for input elements type=hidden', function () { - var vNode = queryFixture(''); + const vNode = queryFixture(''); assert.isFalse(rule.matches(null, vNode)); }); @@ -37,7 +37,7 @@ describe('label-matches', function () { it('returns true for other input types', function () { ['text', 'password', 'url', 'range', 'date', 'checkbox', 'radio'].forEach( function (type) { - var vNode = queryFixture(''); + const vNode = queryFixture(''); assert.isTrue(rule.matches(null, vNode)); } ); diff --git a/test/rule-matches/landmark-has-body-context.js b/test/rule-matches/landmark-has-body-context.js index 124ba3dc9..3afa72e0b 100644 --- a/test/rule-matches/landmark-has-body-context.js +++ b/test/rule-matches/landmark-has-body-context.js @@ -1,8 +1,8 @@ describe('landmark-has-body-context', function () { 'use strict'; - var fixtureSetup = axe.testUtils.fixtureSetup; - var rule; - var shadowSupport = axe.testUtils.shadowSupport.v1; + const fixtureSetup = axe.testUtils.fixtureSetup; + let rule; + const shadowSupport = axe.testUtils.shadowSupport.v1; beforeEach(function () { rule = axe.utils.getRule('landmark-banner-is-top-level'); @@ -11,21 +11,21 @@ describe('landmark-has-body-context', function () { it('returns true for elements with a role', function () { fixtureSetup('
'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); it('returns true for elements not contained in a landmark', function () { fixtureSetup('
'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); it('returns false for elements contained in a landmark', function () { fixtureSetup('
'); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); }); @@ -35,12 +35,12 @@ describe('landmark-has-body-context', function () { // Safari has a bug in 12.0 that throws an error when calling // attachShadow on
// @see https://bugs.webkit.org/show_bug.cgi?id=197726 - var article = document.createElement('article'); - var shadow = article.attachShadow({ mode: 'open' }); + const article = document.createElement('article'); + const shadow = article.attachShadow({ mode: 'open' }); shadow.innerHTML = '
'; fixtureSetup(article); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; assert.isFalse(rule.matches(vNode.actualNode, vNode)); } ); diff --git a/test/rule-matches/landmark-unique-matches.js b/test/rule-matches/landmark-unique-matches.js index 539d83769..cb3cef7bd 100644 --- a/test/rule-matches/landmark-unique-matches.js +++ b/test/rule-matches/landmark-unique-matches.js @@ -1,17 +1,13 @@ describe('landmark-unique-matches', function () { 'use strict'; - var rule; - var fixture; - var axeFixtureSetup; - var shadowSupport = axe.testUtils.shadowSupport.v1; - var excludedDescendantsForHeadersFooters = [ - 'article', - 'aside', - 'main', - 'nav', - 'section' - ]; - var headerFooterElements = ['header', 'footer']; + let rule; + let fixture; + let axeFixtureSetup; + const shadowSupport = axe.testUtils.shadowSupport.v1; + const sectioningContentElements = ['article', 'aside', 'nav', 'section']; + const excludedDescendantsForHeadersFooters = + sectioningContentElements.concat('main'); + const headerFooterElements = ['header', 'footer']; beforeEach(function () { fixture = document.getElementById('fixture'); @@ -21,30 +17,30 @@ describe('landmark-unique-matches', function () { it('should not match because not a landmark', function () { axeFixtureSetup('

some heading

'); - var node = fixture.querySelector('h1'); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const node = fixture.querySelector('h1'); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isFalse(rule.matches(node, virtualNode)); }); it('should pass because is a landmark', function () { axeFixtureSetup('
some banner
'); - var node = fixture.querySelector('div'); + const node = fixture.querySelector('div'); fixture.appendChild(node); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isTrue(rule.matches(node, virtualNode)); }); it('should not match because landmark is hidden', function () { axeFixtureSetup('
some banner
'); - var node = fixture.querySelector('div'); + const node = fixture.querySelector('div'); node.style.display = 'none'; fixture.appendChild(node); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isFalse(rule.matches(node, virtualNode)); }); describe('form and section elements must have accessible names to be matched', function () { - var sectionFormElements = ['section', 'form']; + const sectionFormElements = ['section', 'form']; sectionFormElements.forEach(function (elementType) { it( @@ -59,8 +55,8 @@ describe('landmark-unique-matches', function () { elementType + '>' ); - var node = fixture.querySelector(elementType); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const node = fixture.querySelector(elementType); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isTrue(rule.matches(node, virtualNode)); } ); @@ -77,8 +73,8 @@ describe('landmark-unique-matches', function () { elementType + '>' ); - var node = fixture.querySelector(elementType); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const node = fixture.querySelector(elementType); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isFalse(rule.matches(node, virtualNode)); } ); @@ -105,8 +101,8 @@ describe('landmark-unique-matches', function () { exclusionType + '>' ); - var node = fixture.querySelector(elementType); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const node = fixture.querySelector(elementType); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isFalse(rule.matches(node, virtualNode)); } ); @@ -120,28 +116,73 @@ describe('landmark-unique-matches', function () { axeFixtureSetup( '<' + elementType + '>an element' ); - var node = fixture.querySelector(elementType); - var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + const node = fixture.querySelector(elementType); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); assert.isTrue(rule.matches(node, virtualNode)); } ); }); }); + describe('aside should not match when scoped to a sectioning content element unless it has an accessible name', function () { + sectioningContentElements.forEach(function (exclusionType) { + it( + 'should not match because aside is scoped to ' + + exclusionType + + ' and has no label', + function () { + axeFixtureSetup( + '<' + + exclusionType + + '>' + ); + const node = fixture.querySelector('aside[data-test]'); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + assert.isFalse(rule.matches(node, virtualNode)); + } + ); + + it( + 'should match because aside within ' + exclusionType + ' has a label', + function () { + axeFixtureSetup( + '<' + + exclusionType + + '>' + ); + const node = fixture.querySelector('aside[data-test]'); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + assert.isTrue(rule.matches(node, virtualNode)); + } + ); + }); + + it('should match because aside is not scoped to a sectioning content element', function () { + axeFixtureSetup(''); + const node = fixture.querySelector('aside'); + const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node); + assert.isTrue(rule.matches(node, virtualNode)); + }); + }); + if (shadowSupport) { it('return true for landmarks contained within shadow dom', function () { - var container = document.createElement('div'); - var shadow = container.attachShadow({ mode: 'open' }); + const container = document.createElement('div'); + const shadow = container.attachShadow({ mode: 'open' }); shadow.innerHTML = '
'; axeFixtureSetup(container); - var vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; + const vNode = axe.utils.querySelectorAll(axe._tree[0], 'footer')[0]; assert.isTrue(rule.matches(vNode.actualNode, vNode)); }); describe('header/footers should only match when not inside the excluded descendants within shadow dom', function () { - var container; - var shadow; + let container; + let shadow; beforeEach(function () { container = document.createElement('div'); @@ -169,7 +210,7 @@ describe('landmark-unique-matches', function () { '>'; axeFixtureSetup(container); - var virtualNode = axe.utils.querySelectorAll( + const virtualNode = axe.utils.querySelectorAll( axe._tree[0], elementType )[0]; @@ -186,7 +227,7 @@ describe('landmark-unique-matches', function () { shadow.innerHTML = '<' + elementType + '>an element'; axeFixtureSetup(container); - var virtualNode = axe.utils.querySelectorAll( + const virtualNode = axe.utils.querySelectorAll( axe._tree[0], elementType )[0]; @@ -195,5 +236,66 @@ describe('landmark-unique-matches', function () { ); }); }); + + describe('aside should match inside shadow dom unless it is both within sectioning content and has no accessible name', function () { + let container; + let shadow; + + beforeEach(function () { + container = document.createElement('div'); + shadow = container.attachShadow({ mode: 'open' }); + }); + + sectioningContentElements.forEach(function (exclusionType) { + it( + 'should not match because aside is scoped to ' + + exclusionType + + ' and has no label', + function () { + shadow.innerHTML = + '<' + + exclusionType + + ' aria-label="sample label">'; + + axeFixtureSetup(container); + const virtualNode = axe.utils.querySelectorAll( + axe._tree[0], + 'aside[data-test]' + )[0]; + assert.isFalse(rule.matches(virtualNode.actualNode, virtualNode)); + } + ); + + it( + 'should match because aside within ' + exclusionType + ' has a label', + function () { + shadow.innerHTML = + '<' + + exclusionType + + '>'; + axeFixtureSetup(container); + const virtualNode = axe.utils.querySelectorAll( + axe._tree[0], + 'aside[data-test]' + )[0]; + assert.isTrue(rule.matches(virtualNode.actualNode, virtualNode)); + } + ); + }); + + it('should match because aside is not scoped to a sectioning content element', function () { + shadow.innerHTML = ''; + axeFixtureSetup(container); + const virtualNode = axe.utils.querySelectorAll( + axe._tree[0], + 'aside' + )[0]; + assert.isTrue(rule.matches(virtualNode.actualNode, virtualNode)); + }); + }); } }); diff --git a/test/rule-matches/layout-table-matches.js b/test/rule-matches/layout-table-matches.js index cae2b1ff7..c86cb5ac3 100644 --- a/test/rule-matches/layout-table-matches.js +++ b/test/rule-matches/layout-table-matches.js @@ -1,9 +1,9 @@ describe('layout-table-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var flatTreeSetup = axe.testUtils.flatTreeSetup; - var rule; + const fixture = document.getElementById('fixture'); + const flatTreeSetup = axe.testUtils.flatTreeSetup; + let rule; beforeEach(function () { axe.configure({ @@ -26,7 +26,7 @@ describe('layout-table-matches', function () { it('should return false for data table', function () { fixture.innerHTML = '
Hello>
'; flatTreeSetup(fixture); - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isFalse(rule.matches(node)); }); @@ -34,7 +34,7 @@ describe('layout-table-matches', function () { it('should return false if the table is focusable', function () { fixture.innerHTML = '
'; flatTreeSetup(fixture); - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isFalse(rule.matches(node)); }); @@ -42,7 +42,7 @@ describe('layout-table-matches', function () { it('should return true if table has role=presentation', function () { fixture.innerHTML = '
'; flatTreeSetup(fixture); - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isTrue(rule.matches(node)); }); @@ -50,7 +50,7 @@ describe('layout-table-matches', function () { it('should return true if table has role=none', function () { fixture.innerHTML = '
'; flatTreeSetup(fixture); - var node = fixture.firstChild; + const node = fixture.firstChild; assert.isTrue(rule.matches(node)); }); diff --git a/test/rule-matches/link-in-text-block-matches.js b/test/rule-matches/link-in-text-block-matches.js index e1740114d..871f2d9e7 100644 --- a/test/rule-matches/link-in-text-block-matches.js +++ b/test/rule-matches/link-in-text-block-matches.js @@ -1,6 +1,4 @@ describe('link-in-text-block-matches', () => { - 'use strict'; - const { fixtureSetup } = axe.testUtils; const rule = axe.utils.getRule('link-in-text-block'); diff --git a/test/rule-matches/nested-interactive-matches.js b/test/rule-matches/nested-interactive-matches.js index c4bebe514..9c76d7082 100644 --- a/test/rule-matches/nested-interactive-matches.js +++ b/test/rule-matches/nested-interactive-matches.js @@ -1,7 +1,7 @@ describe('nested-interactive-matches', function () { - var fixture = document.querySelector('#fixture'); - var queryFixture = axe.testUtils.queryFixture; - var rule; + const fixture = document.querySelector('#fixture'); + const queryFixture = axe.testUtils.queryFixture; + let rule; beforeEach(function () { rule = axe.utils.getRule('nested-interactive'); @@ -12,22 +12,22 @@ describe('nested-interactive-matches', function () { }); it('should match if element has children presentational', function () { - var vNode = queryFixture(''); + const vNode = queryFixture(''); assert.isTrue(rule.matches(null, vNode)); }); it('should match if aria element has children presentational', function () { - var vNode = queryFixture('
'); + const vNode = queryFixture('
'); assert.isTrue(rule.matches(null, vNode)); }); it('should not match if element does not have children presentational', function () { - var vNode = queryFixture(''); + const vNode = queryFixture(''); assert.isFalse(rule.matches(null, vNode)); }); it('should not match if element has no role', function () { - var vNode = queryFixture(''); + const vNode = queryFixture(''); assert.isFalse(rule.matches(null, vNode)); }); }); diff --git a/test/rule-matches/no-autoplay-audio-matches.js b/test/rule-matches/no-autoplay-audio-matches.js index 1769e3e89..037582cbf 100644 --- a/test/rule-matches/no-autoplay-audio-matches.js +++ b/test/rule-matches/no-autoplay-audio-matches.js @@ -1,10 +1,10 @@ describe('no-autoplay-audio-matches', function () { 'use strict'; - var fixture = document.getElementById('fixture'); - var queryFixture = axe.testUtils.queryFixture; - var preloadOptions = { preload: { assets: ['media'] } }; - var rule; + const fixture = document.getElementById('fixture'); + const queryFixture = axe.testUtils.queryFixture; + const preloadOptions = { preload: { assets: ['media'] } }; + let rule; beforeEach(function () { rule = axe.utils.getRule('no-autoplay-audio'); @@ -15,37 +15,37 @@ describe('no-autoplay-audio-matches', function () { }); it('returns false for