Skip to content

Commit bf5c1e1

Browse files
committed
Improve exclusions and known false positives mechanism.
1 parent a66964f commit bf5c1e1

2 files changed

Lines changed: 47 additions & 21 deletions

File tree

‎tests/e2e/specs/accessibility.spec.js‎

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,22 @@ const ignoresAndknownFalsePositives = require( '../utils/accessibility-ignores-a
77
* Global accessibility scan rules.
88
* Applied to all pages defined in utils/accessibility-pages.
99
*
10+
* See the Axe Options parameter documentation.
1011
* See: https://github.com/dequelabs/axe-core/blob/master/doc/API.md#options-parameter
1112
*/
1213
const globalRules = {
1314
runOnly: [ 'wcag2a', 'wcag2aa', 'best-practice' ],
15+
absolutePaths: true, // Report the absolute CSS target selector for better exclusions mechanism.
1416
};
1517

1618
/**
1719
* Filters violations to remove violations we want to intentionally ignore and known false positives.
1820
* Only returns violations for nodes that don't match excluded selectors.
1921
*
20-
* SELECTOR MATCHING: Uses substring matching. An exclusion pattern matches a violation's
21-
* target selector if the pattern appears as a substring. For example:
22-
* - A violation reports a Target Selector: "th[aria-label="Privacy Policy"] > strong > .row-title".
23-
* - Pattern ".row-title" MATCHES (substring found).
24-
* - Pattern "strong > .row-title" MATCHES (substring found).
25-
* - Pattern ".column-title .row-title" does NOT match (not a substring).
22+
* See more details in tests/e2e/utils/accessibility-ignores-and-false-positives.js.
2623
*
2724
* @param {Object} results Axe results object.
28-
* @param {Object} exclusions Known false positives config (rule ID → selectors[]).
25+
* @param {Object} exclusions Explicit exclusions and known false positives config (rule ID → selectors[]).
2926
* @return {Object} Filtered results.
3027
*/
3128
function filterIgnoresAndFalsePositives( results, exclusions ) {
@@ -39,9 +36,20 @@ function filterIgnoresAndFalsePositives( results, exclusions ) {
3936
// Filter out nodes matching excluded selectors.
4037
violation.nodes = violation.nodes.filter( ( node ) => {
4138
const targetSelector = node.target[ 0 ];
42-
return ! excludedSelectors.some( ( excluded ) =>
43-
targetSelector?.includes( excluded )
44-
);
39+
40+
// Check if target selector matches any excluded selector pattern.
41+
const isExcluded = excludedSelectors.some( ( excluded ) => {
42+
const selectors = excluded.trim().split( ' ' ).filter( s => s.length > 0 );
43+
return selectors.every( selector => {
44+
// Escape special regex chars, then replace \* with .* for wildcard matching
45+
const escaped = selector.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' );
46+
const wildcard = escaped.replace( /\\\*/g, '.*' );
47+
const pattern = `(?:^| )${ wildcard }(?=[\\s>+~\\[]|$)`;
48+
return new RegExp( pattern ).test( targetSelector );
49+
} );
50+
} );
51+
52+
return ! isExcluded;
4553
} );
4654

4755
return violation;

‎tests/e2e/utils/accessibility-ignores-and-false-positives.js‎

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,48 @@
11
/**
2-
* Ignores and known false positives after human inspection.
2+
* Explicit exclusions and known false positives after human inspection.
33
*
4-
* Maps rule IDs to an array of CSS selectors that should be excluded from violations.
4+
* Maps rule IDs to CSS selectors that should be excluded from the reported violations.
55
* These are instances where axe-core flags a violation, but after human review,
66
* the pattern is acceptable or represents a known limitation of the automated check.
77
*
8-
* SELECTOR MATCHING: Uses substring matching. An exclusion pattern matches a violation's
9-
* target selector if the pattern appears as a substring. For example:
10-
* - A violation reports a Target Selector: "th[aria-label="Privacy Policy"] > strong > .row-title".
11-
* - Pattern ".row-title" MATCHES (substring found).
12-
* - Pattern "strong > .row-title" MATCHES (substring found).
13-
* - Pattern ".column-title .row-title" does NOT match (not a substring).
8+
* SELECTOR MATCHING:
9+
* Uses space-separated selector tokens. An exclusion pattern matches a violation's
10+
* target selector if all selector tokens appear in order (but not necessarily
11+
* consecutively). Intermediate selectors can be skipped.
12+
* For example:
13+
* - Violation Target Selector: "html > body > #__wp-uploader > .attachments-browser > .attachments-wrapper > li[aria-label="image-1"]".
14+
* - Pattern ".attachments-browser li" MATCHES (skips .attachments-wrapper; all tokens found in order).
15+
* - Pattern ".attachments-browser .attachments-wrapper" MATCHES (all tokens found).
16+
* - Pattern ".attachments-browserxyz" does NOT match (selector token boundary prevents partial matches).
17+
* - Attributes on target selectors are ignored: "li[aria-label="..."]" matches pattern "li".
18+
*
19+
* WILDCARD SUPPORT:
20+
* Use an asterisk * to match any characters in a selector token. For example:
21+
* - Pattern "#wp-admin-bar-*" matches "#wp-admin-bar-site-name", "#wp-admin-bar-updates", etc.
22+
* - Pattern "#wpadminbar #wp-toolbar #wp-admin-bar-*" matches full descendant chains with variable final selectors.
23+
*
24+
* CONSTRAINTS:
25+
* Exclusion patterns must be space-separated tokens only (e.g., '#id .class li').
26+
* Do not use attribute selectors, pseudo-classes, or explicit combinators (>, +, ~) in patterns.
27+
* Spaces implicitly represent descendant relationships (any number of intermediate selectors).
28+
*
29+
* NOTE:
30+
* The passed pattern isn't meant to be a meaningful CSS selector. It's only used
31+
* to match the Axe-core target selector of a violation. Just use a space-separated
32+
* list of tokens that appear in the 'Target Selector' entry of the reported violation.
1433
*/
1534

1635
module.exports = {
1736
'link-in-text-block': [
1837
// Post title links in list tables may have surrounding text and are only distinguished by color.
1938
// We consider this acceptable as these links can be distinguished by the context.
20-
'strong > .row-title',
21-
'a[aria-label="Edit',
39+
'.wp-list-table strong .row-title',
2240
],
2341
'aria-allowed-role': [
2442
// The "group" role for the admin bar list items is flagged as invalid by axe-core.
2543
// This is a known false positive in axe-core and can be ignored. Note
2644
// that the 'aria-allowed-role' rule is part of the 'best-practice' rules group.
27-
'#wp-admin-bar-',
45+
'#wp-toolbar #wp-admin-bar-*',
2846
],
2947
'region': [
3048
// Visually hidden text that clarifies what the ARIA live regions are about.

0 commit comments

Comments
 (0)