Skip to content

Commit 2e18f0c

Browse files
committed
fix: add noHtml to axe.configure
1 parent 39f1052 commit 2e18f0c

File tree

11 files changed

+240
-16
lines changed

11 files changed

+240
-16
lines changed

axe.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ declare module axe {
7979
},
8080
reporter?: ReporterVersion,
8181
checks?: Check[],
82-
rules?: Rule[]
82+
rules?: Rule[],
83+
noHtml?: boolean
8384
}
8485
interface Check {
8586
id: string,

doc/API.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ axe.configure({
145145
},
146146
reporter: "option",
147147
checks: [Object],
148-
rules: [Object]});
148+
rules: [Object],
149+
noHtml: Boolean});
149150
```
150151

151152
#### Parameters
@@ -179,6 +180,7 @@ axe.configure({
179180
* `tags` - array(optional, default `[]`). A list if the tags that "classify" the rule. In practice, you must supply some valid tags or the default evaluation will not invoke the rule. The convention is to include the standard (WCAG 2 and/or section 508), the WCAG 2 level, Section 508 paragraph, and the WCAG 2 success criteria. Tags are constructed by converting all letters to lower case, removing spaces and periods and concatinating the result. E.g. WCAG 2 A success criteria 1.1.1 would become ["wcag2a", "wcag111"]
180181
* `matches` - string(optional, default `*`). A filtering CSS selector that will exclude elements that do not match the CSS selector.
181182
* `disableOtherRules` - Disables all rules not included in the `rules` property.
183+
* `noHtml` - Disables the HTML output of nodes from rules.
182184

183185
**Returns:** Nothing
184186

lib/core/base/audit.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ function getDefaultConfiguration(audit) {
1414
}
1515

1616
config.reporter = config.reporter || null;
17+
config.noHtml = config.noHtml || false;
1718
config.rules = config.rules || [];
1819
config.checks = config.checks || [];
1920
config.data = Object.assign({
@@ -58,7 +59,7 @@ Audit.prototype._init = function () {
5859
this.commands = {};
5960
this.rules = [];
6061
this.checks = {};
61-
62+
this.noHtml = audit.noHtml;
6263
unpackToObject(audit.rules, this, 'addRule');
6364
unpackToObject(audit.checks, this, 'addCheck');
6465

lib/core/public/configure.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* global reporters */
22
function configureChecksRulesAndBranding(spec) {
3-
/*eslint max-statements: ["error",20]*/
3+
/*eslint max-statements: ["error",21]*/
44
'use strict';
55
var audit;
66

@@ -44,6 +44,10 @@ function configureChecksRulesAndBranding(spec) {
4444
if (spec.tagExclude) {
4545
audit.tagExclude = spec.tagExclude;
4646
}
47+
48+
if (spec.noHtml) {
49+
audit.noHtml = true;
50+
}
4751
}
4852

4953
axe.configure = configureChecksRulesAndBranding;

lib/core/utils/dq-element.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,13 @@ function DqElement(element, options, spec) {
3737
* The generated HTML source code of the element
3838
* @type {String}
3939
*/
40-
this.source = this.spec.source !== undefined ? this.spec.source : getSource(element);
40+
if (axe._audit && axe._audit.noHtml) {
41+
this.source = null;
42+
} else if (this.spec.source !== undefined) {
43+
this.source = this.spec.source;
44+
} else {
45+
this.source = getSource(element);
46+
}
4147

4248
/**
4349
* The element which this object is based off or the containing frame, used for sorting.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,5 @@
9999
"selenium-webdriver": "~3.6.0",
100100
"sri-toolbox": "^0.2.0",
101101
"standard-version": "^4.2.0"
102-
},
103-
"dependencies": {}
102+
}
104103
}

test/core/base/audit.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ describe('Audit', function () {
7676
assert.isFunction(Audit);
7777
});
7878

79+
describe('defaults', function() {
80+
it('should set noHtml', function() {
81+
var audit = new Audit();
82+
assert.isFalse(audit.noHtml);
83+
});
84+
});
85+
7986
describe('Audit#_constructHelpUrls', function () {
8087
it('should create default help URLS', function () {
8188
var audit = new Audit();
@@ -337,6 +344,13 @@ describe('Audit', function () {
337344
audit.resetRulesAndChecks();
338345
assert.equal(audit.checks.target, undefined);
339346
});
347+
348+
it('should reset noHtml', function() {
349+
var audit = new Audit();
350+
audit.noHtml = true;
351+
audit.resetRulesAndChecks();
352+
assert.isFalse(audit.noHtml);
353+
});
340354
});
341355

342356
describe('Audit#addCheck', function () {

test/core/public/configure.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,12 @@ describe('axe.configure', function() {
222222
assert.equal(axe._audit.rules[3].id, 'black-panther');
223223
assert.equal(axe._audit.rules[3].enabled, true);
224224
});
225+
226+
it('should allow overriding an audit\'s noHtml', function() {
227+
axe._load({});
228+
assert.isFalse(axe._audit.noHtml);
229+
230+
axe.configure({ noHtml: true });
231+
assert.isTrue(axe._audit.noHtml);
232+
});
225233
});

test/core/utils/dq-element.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ describe('DqElement', function () {
55
var fixture = document.getElementById('fixture');
66
var fixtureSetup = axe.testUtils.fixtureSetup;
77

8+
beforeEach(function() {
9+
axe._load({});
10+
});
11+
812
afterEach(function () {
913
fixture.innerHTML = '';
1014
axe._tree = undefined;
@@ -82,6 +86,26 @@ describe('DqElement', function () {
8286
});
8387
assert.equal(result.source, 'woot');
8488
});
89+
90+
it('should return null if audit.noHtml is set', function() {
91+
axe.configure({ noHtml: true });
92+
fixture.innerHTML = '<div class="bar" id="foo">Hello!</div>';
93+
var result = new DqElement(fixture.firstChild);
94+
assert.isNull(result.source);
95+
});
96+
97+
it('should not use spec object over passed element if audit.noHtml is set', function() {
98+
axe.configure({ noHtml: true });
99+
fixture.innerHTML = '<div id="foo" class="bar">Hello!</div>';
100+
var result = new DqElement(
101+
fixture.firstChild,
102+
{},
103+
{
104+
source: 'woot'
105+
}
106+
);
107+
assert.isNull(result.source);
108+
});
85109
});
86110

87111
describe('selector', function () {

test/integration/full/configure-options/configure-options.js

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
describe('Configure Options', function() {
22
'use strict';
33

4+
var target = document.querySelector('#target');
5+
46
afterEach(function () {
57
axe.reset();
8+
target.innerHTML = '';
69
});
710

811
describe('Check', function() {
912

10-
var target = document.querySelector('#target');
1113
describe('aria-allowed-attr', function() {
1214
it('should allow an attribute supplied in options', function(done) {
1315
target.setAttribute('role', 'separator');
@@ -21,9 +23,9 @@ describe('Configure Options', function() {
2123
});
2224
axe.run(target, {
2325
runOnly: {
24-
type: 'rule',
25-
values: [ 'aria-allowed-attr' ]
26-
}
26+
type: 'rule',
27+
values: [ 'aria-allowed-attr' ]
28+
}
2729
}, function(error, results) {
2830
assert.lengthOf(results.violations, 0, 'violations');
2931
done();
@@ -42,9 +44,9 @@ describe('Configure Options', function() {
4244
});
4345
axe.run('#target', {
4446
runOnly: {
45-
type: 'rule',
46-
values: [ 'aria-required-attr' ]
47-
}
47+
type: 'rule',
48+
values: [ 'aria-required-attr' ]
49+
}
4850
}, function(error, results) {
4951
assert.lengthOf(results.violations, 1, 'violations');
5052
assert.sameMembers(results.violations[0].nodes[0].any[0].data, ['aria-valuemax', 'aria-valuemin', 'aria-snuggles']);
@@ -54,8 +56,8 @@ describe('Configure Options', function() {
5456
});
5557
});
5658

57-
describe('disableOtherRules', function (done) {
58-
it('disables rules that are not in the `rules` array', function () {
59+
describe('disableOtherRules', function () {
60+
it('disables rules that are not in the `rules` array', function (done) {
5961
axe.configure({
6062
disableOtherRules: true,
6163
rules: [{
@@ -79,4 +81,115 @@ describe('Configure Options', function() {
7981
});
8082
});
8183
});
84+
85+
describe('noHtml', function() {
86+
it('prevents html property on nodes', function(done) {
87+
target.setAttribute('role', 'slider');
88+
axe.configure({
89+
noHtml: true,
90+
checks: [
91+
{
92+
id: 'aria-required-attr',
93+
options: { slider: ['aria-snuggles'] }
94+
}
95+
]
96+
});
97+
axe.run(
98+
'#target',
99+
{
100+
runOnly: {
101+
type: 'rule',
102+
values: ['aria-required-attr']
103+
}
104+
},
105+
function(error, results) {
106+
try {
107+
assert.isNull(results.violations[0].nodes[0].html);
108+
done();
109+
} catch (e) {
110+
done(e);
111+
}
112+
}
113+
);
114+
});
115+
116+
it('prevents html property on nodes from iframes', function(done) {
117+
axe.configure({
118+
noHtml: true,
119+
rules: [
120+
{
121+
id: 'div#target',
122+
// purposefully don't match so the first result is from
123+
// the iframe
124+
selector: 'foo'
125+
}
126+
]
127+
});
128+
129+
var iframe = document.createElement('iframe');
130+
iframe.src = '/test/mock/frames/context.html';
131+
iframe.onload = function() {
132+
axe.run(
133+
'#target',
134+
{
135+
runOnly: {
136+
type: 'rule',
137+
values: ['div#target']
138+
}
139+
},
140+
function(error, results) {
141+
try {
142+
assert.deepEqual(results.passes[0].nodes[0].target, [
143+
'iframe',
144+
'#target'
145+
]);
146+
assert.isNull(results.passes[0].nodes[0].html);
147+
done();
148+
} catch (e) {
149+
done(e);
150+
}
151+
}
152+
);
153+
};
154+
target.appendChild(iframe);
155+
});
156+
157+
it('prevents html property in postMesage', function(done) {
158+
axe.configure({
159+
noHtml: true,
160+
rules: [
161+
{
162+
id: 'div#target',
163+
// purposefully don't match so the first result is from
164+
// the iframe
165+
selector: 'foo'
166+
}
167+
]
168+
});
169+
170+
var iframe = document.createElement('iframe');
171+
iframe.src = '/test/mock/frames/noHtml-config.html';
172+
iframe.onload = function() {
173+
axe.run('#target', {
174+
runOnly: {
175+
type: 'rule',
176+
values: ['div#target']
177+
}
178+
});
179+
};
180+
target.appendChild(iframe);
181+
182+
window.addEventListener('message', function(e) {
183+
var data = JSON.parse(e.data);
184+
if (Array.isArray(data.message)) {
185+
try {
186+
assert.isNull(data.message[0].nodes[0].node.source);
187+
done();
188+
} catch (e) {
189+
done(e);
190+
}
191+
}
192+
});
193+
});
194+
});
82195
});

0 commit comments

Comments
 (0)