Skip to content
This repository was archived by the owner on Dec 7, 2022. It is now read-only.

Commit 55f83ba

Browse files
author
Alice
committed
Merge pull request #244 from alice/ignore-selectors-fix
Ignore selectors fix
2 parents dbdd65e + b302614 commit 55f83ba

7 files changed

Lines changed: 42 additions & 22 deletions

src/js/AuditRule.js

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,23 @@ axs.AuditRule.prototype.addElement = function(elements, element) {
125125
* @param {Node} scope
126126
* @param {function(Element): boolean} matcher
127127
* @param {Array.<Element>} collection
128+
* @param {Array.<string>=} opt_ignoreSelectors
128129
*/
129-
axs.AuditRule.collectMatchingElements = function(scope, matcher, collection) {
130+
axs.AuditRule.collectMatchingElements = function(scope, matcher, collection, opt_ignoreSelectors) {
131+
/**
132+
* @param {!Element} element
133+
* @return boolean
134+
*/
130135
function relevantElementCollector(element) {
136+
if (opt_ignoreSelectors) {
137+
for (var i = 0; i < opt_ignoreSelectors.length; i++) {
138+
if (axs.browserUtils.matchSelector(element, opt_ignoreSelectors[i]))
139+
return false;
140+
}
141+
}
131142
if (matcher(element))
132143
collection.push(element);
144+
return true;
133145
}
134146
axs.dom.composedTreeSearch(scope, null, { preorder: relevantElementCollector });
135147
};
@@ -149,30 +161,21 @@ axs.AuditRule.collectMatchingElements = function(scope, matcher, collection) {
149161
*/
150162
axs.AuditRule.prototype.run = function(options) {
151163
options = options || {};
152-
var ignoreSelectors = 'ignoreSelectors' in options ? options['ignoreSelectors'] : [];
153164
var scope = 'scope' in options ? options['scope'] : document;
154165
var maxResults = 'maxResults' in options ? options['maxResults'] : null;
155166

156167
var relevantElements = [];
157-
axs.AuditRule.collectMatchingElements(scope, this.relevantElementMatcher_, relevantElements);
168+
axs.AuditRule.collectMatchingElements(scope, this.relevantElementMatcher_, relevantElements, options['ignoreSelectors']);
158169

159170
var failingElements = [];
160171

161-
function ignored(element) {
162-
for (var i = 0; i < ignoreSelectors.length; i++) {
163-
if (axs.browserUtils.matchSelector(element, ignoreSelectors[i]))
164-
return true;
165-
}
166-
return false;
167-
}
168-
169172
if (!relevantElements.length)
170173
return { result: axs.constants.AuditResult.NA };
171174
for (var i = 0; i < relevantElements.length; i++) {
172175
if (maxResults != null && failingElements.length >= maxResults)
173176
break;
174177
var element = relevantElements[i];
175-
if (!ignored(element) && this.test_(element, options.config))
178+
if (this.test_(element, options.config))
176179
this.addElement(failingElements, element);
177180
}
178181
var result = failingElements.length ? axs.constants.AuditResult.FAIL : axs.constants.AuditResult.PASS;

src/js/DOMUtils.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,12 @@ axs.dom.asElement = function(node) {
108108
* Recursively walk the composed tree from |node|, aborting if |end| is encountered.
109109
* @param {Node} node
110110
* @param {?Node} end
111-
* @param {{preorder: (function (Node)|undefined),
111+
* @param {{preorder: (function (Node):boolean|undefined),
112112
* postorder: (function (Node)|undefined)}} callbacks
113113
* Callbacks to be called for each element traversed, excluding
114114
* |end|. Possible callbacks are |preorder|, called before descending into
115115
* child nodes, and |postorder| called after all child nodes have been
116+
* traversed. If |preorder| returns false, its child nodes will not be
116117
* traversed.
117118
* @param {ShadowRoot=} opt_shadowRoot The nearest ShadowRoot ancestor, if any.
118119
* @return {boolean} Whether |end| was found, if provided.
@@ -124,11 +125,13 @@ axs.dom.composedTreeSearch = function(node, end, callbacks, opt_shadowRoot) {
124125
if (node.nodeType == Node.ELEMENT_NODE)
125126
var element = /** @type {Element} */ (node);
126127

127-
if (element && callbacks.preorder)
128-
callbacks.preorder(element);
129-
130128
var found = false;
131129

130+
if (element && callbacks.preorder) {
131+
if (!callbacks.preorder(element))
132+
return found;
133+
}
134+
132135
// Descend into node:
133136
// If it has a ShadowRoot, ignore all child elements - these will be picked
134137
// up by the <content> or <shadow> elements. Descend straight into the

test/audits/aria-on-reserved-element-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
var widget = fixture.appendChild(document.createElement('meta'));
7979
var ignoreSelectors = ['#' + (widget.id = 'ignoreMe')];
8080
widget.setAttribute('aria-hidden', 'false'); // global
81-
var expected = { elements: [], result: axs.constants.AuditResult.PASS };
81+
var expected = { result: axs.constants.AuditResult.NA };
8282
deepEqual(rule.run({ scope: fixture, ignoreSelectors: ignoreSelectors }), expected, 'ignoreSelectors should skip this failing element');
8383
});
8484

test/audits/aria-owns-descendant-test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@
8686
var result = rule.run({
8787
ignoreSelectors: ignoreSelectors,
8888
scope: fixture });
89-
equal(result.result, axs.constants.AuditResult.PASS);
90-
deepEqual(result.elements, []);
89+
equal(result.result, axs.constants.AuditResult.NA);
9190
});
9291
})();

test/audits/multiple-aria-owners-test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@
104104
var result = rule.run({
105105
ignoreSelectors: ignoreSelectors,
106106
scope: fixture });
107-
equal(result.result, axs.constants.AuditResult.PASS);
108-
deepEqual(result.elements, []);
107+
equal(result.result, axs.constants.AuditResult.NA);
109108
});
110109
})();

test/audits/non-existent-aria-related-element-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,6 @@ module('NonExistentAriaRelatedElement');
115115
var rule = axs.AuditRules.getRule('nonExistentAriaRelatedElement');
116116
var ignoreSelectors = ['#labelledbyElement2'];
117117
var result = rule.run({ ignoreSelectors: ignoreSelectors, scope: fixture });
118-
equal(result.result, axs.constants.AuditResult.PASS);
118+
equal(result.result, axs.constants.AuditResult.NA);
119119
});
120120
});

test/js/audit-rule-test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
for (var i = 0; i < DIV_COUNT; i++) {
2929
var element = document.createElement("div");
3030
element.className = "test";
31+
element.id = "test-" + i;
3132
result.appendChild(element);
3233
}
3334
return result;
@@ -41,6 +42,21 @@
4142
equal(matched.length, DIV_COUNT);
4243
});
4344

45+
test("Simple DOM with an ignored selector", function () {
46+
var container = document.getElementById('qunit-fixture');
47+
container.appendChild(buildTestDom());
48+
var fooElement = document.createElement('div');
49+
fooElement.className = 'foo';
50+
container.appendChild(fooElement);
51+
var fooTest = document.createElement('div');
52+
fooTest.className = 'test';
53+
fooElement.appendChild(fooTest);
54+
var matched = [];
55+
var ignoredSelectors = ['.foo'];
56+
axs.AuditRule.collectMatchingElements(container, matcher, matched, ignoredSelectors);
57+
equal(matched.length, DIV_COUNT);
58+
});
59+
4460
test("With shadow DOM with no content insertion point", function () {
4561
var container = document.getElementById('qunit-fixture');
4662
container.appendChild(buildTestDom());

0 commit comments

Comments
 (0)