Skip to content

Commit

Permalink
fix: add noHtml to axe.configure
Browse files Browse the repository at this point in the history
  • Loading branch information
straker committed Apr 29, 2021
1 parent 39f1052 commit 2e18f0c
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 16 deletions.
3 changes: 2 additions & 1 deletion axe.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ declare module axe {
},
reporter?: ReporterVersion,
checks?: Check[],
rules?: Rule[]
rules?: Rule[],
noHtml?: boolean
}
interface Check {
id: string,
Expand Down
4 changes: 3 additions & 1 deletion doc/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ axe.configure({
},
reporter: "option",
checks: [Object],
rules: [Object]});
rules: [Object],
noHtml: Boolean});
```

#### Parameters
Expand Down Expand Up @@ -179,6 +180,7 @@ axe.configure({
* `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"]
* `matches` - string(optional, default `*`). A filtering CSS selector that will exclude elements that do not match the CSS selector.
* `disableOtherRules` - Disables all rules not included in the `rules` property.
* `noHtml` - Disables the HTML output of nodes from rules.

**Returns:** Nothing

Expand Down
3 changes: 2 additions & 1 deletion lib/core/base/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ function getDefaultConfiguration(audit) {
}

config.reporter = config.reporter || null;
config.noHtml = config.noHtml || false;
config.rules = config.rules || [];
config.checks = config.checks || [];
config.data = Object.assign({
Expand Down Expand Up @@ -58,7 +59,7 @@ Audit.prototype._init = function () {
this.commands = {};
this.rules = [];
this.checks = {};

this.noHtml = audit.noHtml;
unpackToObject(audit.rules, this, 'addRule');
unpackToObject(audit.checks, this, 'addCheck');

Expand Down
6 changes: 5 additions & 1 deletion lib/core/public/configure.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* global reporters */
function configureChecksRulesAndBranding(spec) {
/*eslint max-statements: ["error",20]*/
/*eslint max-statements: ["error",21]*/
'use strict';
var audit;

Expand Down Expand Up @@ -44,6 +44,10 @@ function configureChecksRulesAndBranding(spec) {
if (spec.tagExclude) {
audit.tagExclude = spec.tagExclude;
}

if (spec.noHtml) {
audit.noHtml = true;
}
}

axe.configure = configureChecksRulesAndBranding;
8 changes: 7 additions & 1 deletion lib/core/utils/dq-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ function DqElement(element, options, spec) {
* The generated HTML source code of the element
* @type {String}
*/
this.source = this.spec.source !== undefined ? this.spec.source : getSource(element);
if (axe._audit && axe._audit.noHtml) {
this.source = null;
} else if (this.spec.source !== undefined) {
this.source = this.spec.source;
} else {
this.source = getSource(element);
}

/**
* The element which this object is based off or the containing frame, used for sorting.
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,5 @@
"selenium-webdriver": "~3.6.0",
"sri-toolbox": "^0.2.0",
"standard-version": "^4.2.0"
},
"dependencies": {}
}
}
14 changes: 14 additions & 0 deletions test/core/base/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ describe('Audit', function () {
assert.isFunction(Audit);
});

describe('defaults', function() {
it('should set noHtml', function() {
var audit = new Audit();
assert.isFalse(audit.noHtml);
});
});

describe('Audit#_constructHelpUrls', function () {
it('should create default help URLS', function () {
var audit = new Audit();
Expand Down Expand Up @@ -337,6 +344,13 @@ describe('Audit', function () {
audit.resetRulesAndChecks();
assert.equal(audit.checks.target, undefined);
});

it('should reset noHtml', function() {
var audit = new Audit();
audit.noHtml = true;
audit.resetRulesAndChecks();
assert.isFalse(audit.noHtml);
});
});

describe('Audit#addCheck', function () {
Expand Down
8 changes: 8 additions & 0 deletions test/core/public/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,12 @@ describe('axe.configure', function() {
assert.equal(axe._audit.rules[3].id, 'black-panther');
assert.equal(axe._audit.rules[3].enabled, true);
});

it('should allow overriding an audit\'s noHtml', function() {
axe._load({});
assert.isFalse(axe._audit.noHtml);

axe.configure({ noHtml: true });
assert.isTrue(axe._audit.noHtml);
});
});
24 changes: 24 additions & 0 deletions test/core/utils/dq-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ describe('DqElement', function () {
var fixture = document.getElementById('fixture');
var fixtureSetup = axe.testUtils.fixtureSetup;

beforeEach(function() {
axe._load({});
});

afterEach(function () {
fixture.innerHTML = '';
axe._tree = undefined;
Expand Down Expand Up @@ -82,6 +86,26 @@ describe('DqElement', function () {
});
assert.equal(result.source, 'woot');
});

it('should return null if audit.noHtml is set', function() {
axe.configure({ noHtml: true });
fixture.innerHTML = '<div class="bar" id="foo">Hello!</div>';
var result = new DqElement(fixture.firstChild);
assert.isNull(result.source);
});

it('should not use spec object over passed element if audit.noHtml is set', function() {
axe.configure({ noHtml: true });
fixture.innerHTML = '<div id="foo" class="bar">Hello!</div>';
var result = new DqElement(
fixture.firstChild,
{},
{
source: 'woot'
}
);
assert.isNull(result.source);
});
});

describe('selector', function () {
Expand Down
131 changes: 122 additions & 9 deletions test/integration/full/configure-options/configure-options.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
describe('Configure Options', function() {
'use strict';

var target = document.querySelector('#target');

afterEach(function () {
axe.reset();
target.innerHTML = '';
});

describe('Check', function() {

var target = document.querySelector('#target');
describe('aria-allowed-attr', function() {
it('should allow an attribute supplied in options', function(done) {
target.setAttribute('role', 'separator');
Expand All @@ -21,9 +23,9 @@ describe('Configure Options', function() {
});
axe.run(target, {
runOnly: {
type: 'rule',
values: [ 'aria-allowed-attr' ]
}
type: 'rule',
values: [ 'aria-allowed-attr' ]
}
}, function(error, results) {
assert.lengthOf(results.violations, 0, 'violations');
done();
Expand All @@ -42,9 +44,9 @@ describe('Configure Options', function() {
});
axe.run('#target', {
runOnly: {
type: 'rule',
values: [ 'aria-required-attr' ]
}
type: 'rule',
values: [ 'aria-required-attr' ]
}
}, function(error, results) {
assert.lengthOf(results.violations, 1, 'violations');
assert.sameMembers(results.violations[0].nodes[0].any[0].data, ['aria-valuemax', 'aria-valuemin', 'aria-snuggles']);
Expand All @@ -54,8 +56,8 @@ describe('Configure Options', function() {
});
});

describe('disableOtherRules', function (done) {
it('disables rules that are not in the `rules` array', function () {
describe('disableOtherRules', function () {
it('disables rules that are not in the `rules` array', function (done) {
axe.configure({
disableOtherRules: true,
rules: [{
Expand All @@ -79,4 +81,115 @@ describe('Configure Options', function() {
});
});
});

describe('noHtml', function() {
it('prevents html property on nodes', function(done) {
target.setAttribute('role', 'slider');
axe.configure({
noHtml: true,
checks: [
{
id: 'aria-required-attr',
options: { slider: ['aria-snuggles'] }
}
]
});
axe.run(
'#target',
{
runOnly: {
type: 'rule',
values: ['aria-required-attr']
}
},
function(error, results) {
try {
assert.isNull(results.violations[0].nodes[0].html);
done();
} catch (e) {
done(e);
}
}
);
});

it('prevents html property on nodes from iframes', function(done) {
axe.configure({
noHtml: true,
rules: [
{
id: 'div#target',
// purposefully don't match so the first result is from
// the iframe
selector: 'foo'
}
]
});

var iframe = document.createElement('iframe');
iframe.src = '/test/mock/frames/context.html';
iframe.onload = function() {
axe.run(
'#target',
{
runOnly: {
type: 'rule',
values: ['div#target']
}
},
function(error, results) {
try {
assert.deepEqual(results.passes[0].nodes[0].target, [
'iframe',
'#target'
]);
assert.isNull(results.passes[0].nodes[0].html);
done();
} catch (e) {
done(e);
}
}
);
};
target.appendChild(iframe);
});

it('prevents html property in postMesage', function(done) {
axe.configure({
noHtml: true,
rules: [
{
id: 'div#target',
// purposefully don't match so the first result is from
// the iframe
selector: 'foo'
}
]
});

var iframe = document.createElement('iframe');
iframe.src = '/test/mock/frames/noHtml-config.html';
iframe.onload = function() {
axe.run('#target', {
runOnly: {
type: 'rule',
values: ['div#target']
}
});
};
target.appendChild(iframe);

window.addEventListener('message', function(e) {
var data = JSON.parse(e.data);
if (Array.isArray(data.message)) {
try {
assert.isNull(data.message[0].nodes[0].node.source);
done();
} catch (e) {
done(e);
}
}
});
});
});
});
52 changes: 52 additions & 0 deletions test/mock/frames/noHtml-config.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Context Fixture</title>
</head>
<body>
<div id="foo">
<div id="bar"></div>
</div>
<div id="target"></div>
<script src="/axe.js"></script>
<script>
axe._load({
rules: [
{
id: 'div#target',
selector: '#target',
any: ['has-target']
},
{
id: 'first-div',
selector: 'div',
any: ['first-div']
}
],
checks: [
{
id: 'has-target',
evaluate: function() {
return true;
}
},
{
id: 'first-div',
evaluate: function(node) {
this.relatedNodes([node]);
return false;
},
after: function(results) {
if (results.length) {
results[0].result = true;
}
return [results[0]];
}
}
],
messages: {}
});
axe.configure({ noHtml: true });
</script>
</body>
</html>

0 comments on commit 2e18f0c

Please sign in to comment.