axe-core
Version:
Accessibility engine for automated Web UI testing
973 lines (845 loc) • 21.8 kB
JavaScript
/*global Rule, Check */
describe('Rule', function() {
'use strict';
var fixture = document.getElementById('fixture');
var noop = function () {};
var isNotCalled = function (err) {
throw err || new Error('Reject should not be called');
};
afterEach(function() {
fixture.innerHTML = '';
});
it('should be a function', function() {
assert.isFunction(Rule);
});
it('should accept two parameters', function() {
assert.lengthOf(Rule, 2);
});
describe('prototype', function() {
describe('gather', function() {
it('should gather nodes which match the selector', function() {
var node = document.createElement('div');
node.id = 'monkeys';
fixture.appendChild(node);
var rule = new Rule({
selector: '#monkeys'
}),
nodes = rule.gather({
include: [axe.utils.getFlattenedTree(fixture)[0]],
exclude: [],
frames: []
});
assert.lengthOf(nodes, 1);
assert.equal(nodes[0].actualNode, node);
node.id = 'bananas';
nodes = rule.gather({
include: [axe.utils.getFlattenedTree(fixture)[0]],
exclude: [],
frames: []
});
assert.lengthOf(nodes, 0);
});
it('should return a real array', function() {
var rule = new Rule({
selector: 'div'
}),
result = rule.gather({
include: [axe.utils.getFlattenedTree(fixture)[0]],
exclude: [],
frames: []
});
assert.isArray(result);
});
it('should take a context parameter', function() {
var node = document.createElement('div');
fixture.appendChild(node);
var rule = new Rule({
selector: 'div'
}),
nodes = rule.gather({
include: [axe.utils.getFlattenedTree(document.getElementById('fixture').firstChild)[0]]
});
assert.deepEqual(nodes.map(function (n) {return n.actualNode;}), [node]);
});
it('should default to all nodes if selector is not specified', function() {
var nodes = [fixture],
node = document.createElement('div');
fixture.appendChild(node);
nodes.push(node);
node = document.createElement('div');
fixture.appendChild(node);
nodes.push(node);
var rule = new Rule({}),
result = rule.gather({
include: [axe.utils.getFlattenedTree(document.getElementById('fixture'))[0]]
});
assert.lengthOf(result, 3);
assert.sameMembers(result.map(function (n) { return n.actualNode; }),
nodes);
});
it('should exclude hidden elements', function() {
fixture.innerHTML = '<div style="display: none"><span>HEHEHE</span></div>';
var rule = new Rule({}),
result = rule.gather({
include: [axe.utils.getFlattenedTree(document.getElementById('fixture').firstChild)[0]]
});
assert.lengthOf(result, 0);
});
it('should include hidden elements if excludeHidden is false', function() {
fixture.innerHTML = '<div style="display: none"></div>';
var rule = new Rule({
excludeHidden: false
}),
result = rule.gather({
include: [axe.utils.getFlattenedTree(document.getElementById('fixture').firstChild)[0]]
});
assert.deepEqual(result.map(function (n) { return n.actualNode; }), [fixture.firstChild]);
});
});
describe('run', function() {
it('should be a function', function() {
assert.isFunction(Rule.prototype.run);
});
it('should run #matches', function(done) {
var div = document.createElement('div');
fixture.appendChild(div);
var success = false,
rule = new Rule({
matches: function(node) {
assert.equal(node, div);
success = true;
return [];
}
});
rule.run({
include: [axe.utils.getFlattenedTree(div)[0]]
}, {}, function() {
assert.isTrue(success);
done();
}, isNotCalled);
});
it('should pass a virtualNode to #matches', function(done) {
var div = document.createElement('div');
fixture.appendChild(div);
var success = false,
rule = new Rule({
matches: function(node, virtualNode) {
assert.equal(virtualNode.actualNode, div);
success = true;
return [];
}
});
rule.run({
include: [axe.utils.getFlattenedTree(div)[0]]
}, {}, function() {
assert.isTrue(success);
done();
}, isNotCalled);
});
it('should handle an error in #matches', function(done) {
var div = document.createElement('div');
div.setAttribute('style', '#fff');
fixture.appendChild(div);
var success = false,
rule = new Rule({
matches: function() {
throw new Error('this is an error');
}
});
rule.run({
include: [axe.utils.getFlattenedTree(div)[0]]
}, {}, isNotCalled, function() {
assert.isFalse(success);
done();
});
});
it('should execute Check#run on its child checks - any', function(done) {
fixture.innerHTML = '<blink>Hi</blink>';
var success = false;
var rule = new Rule({
any: ['cats']
}, {
checks: {
cats: {
run: function (node, options, resolve) {
success = true;
resolve(true);
}
}
}
});
rule.run({
include: [axe.utils.getFlattenedTree(fixture)[0]]
}, {}, function() {
assert.isTrue(success);
done();
}, isNotCalled);
});
it('should execute Check#run on its child checks - all', function(done) {
fixture.innerHTML = '<blink>Hi</blink>';
var success = false;
var rule = new Rule({
all: ['cats']
}, {
checks: {
cats: {
run: function (node, options, resolve) {
success = true;
resolve(true);
}
}
}
});
rule.run({
include: [axe.utils.getFlattenedTree(fixture)[0]]
}, {}, function() {
assert.isTrue(success);
done();
}, isNotCalled);
});
it('should execute Check#run on its child checks - none', function(done) {
fixture.innerHTML = '<blink>Hi</blink>';
var success = false;
var rule = new Rule({
none: ['cats']
}, {
checks: {
cats: {
run: function (node, options, resolve) {
success = true;
resolve(true);
}
}
}
}, isNotCalled);
rule.run({
include: [axe.utils.getFlattenedTree(fixture)[0]]
}, {}, function() {
assert.isTrue(success);
done();
}, isNotCalled);
});
it('should pass the matching option to check.run', function(done) {
fixture.innerHTML = '<blink>Hi</blink>';
var options = {
checks: {
cats: {
enabled: 'bananas',
options: 'minkeys'
}
}
};
var rule = new Rule({
none: ['cats']
}, {
checks: {
cats: {
id: 'cats',
run: function (node, options, resolve) {
assert.equal(options.enabled, 'bananas');
assert.equal(options.options, 'minkeys');
resolve(true);
}
}
}
});
rule.run({
include: [axe.utils.getFlattenedTree(document)[0]]
}, options, function() {
done();
}, isNotCalled);
});
it('should pass the matching option to check.run defined on the rule over global', function(done) {
fixture.innerHTML = '<blink>Hi</blink>';
var options = {
rules: {
cats: {
checks: {
cats: {
enabled: 'apples',
options: 'apes'
}
}
}
},
checks: {
cats: {
enabled: 'bananas',
options: 'minkeys'
}
}
};
var rule = new Rule({
id: 'cats',
any: [{
id: 'cats'
}]
}, {
checks: {
cats: {
id: 'cats',
run: function (node, options, resolve) {
assert.equal(options.enabled, 'apples');
assert.equal(options.options, 'apes');
resolve(true);
}
}
}
});
rule.run({
include: [axe.utils.getFlattenedTree(document)[0]]
}, options, function() {
done();
}, isNotCalled);
});
it('should filter out null results', function() {
var rule = new Rule({
selector: '#fixture',
any: ['cats']
}, {
checks: {
cats: {
id: 'cats',
run: function() {}
}
}
});
rule.run({
include: [axe.utils.getFlattenedTree(document)[0]]
}, {}, function(r) {
assert.lengthOf(r.nodes, 0);
}, isNotCalled);
});
describe('DqElement', function() {
var origDqElement;
var isDqElementCalled;
beforeEach(function() {
isDqElementCalled = false;
origDqElement = axe.utils.DqElement;
axe.utils.DqElement = function() {
isDqElementCalled = true;
};
fixture.innerHTML = '<blink>Hi</blink>';
});
afterEach(function() {
axe.utils.DqElement = origDqElement;
});
it('is created for matching nodes', function(done) {
var rule = new Rule({
all: ['cats']
}, {
checks: {
cats: new Check({
id: 'cats',
enabled: true,
evaluate: function() {
return true;
},
matches: function() {
return true;
}
})
}
});
rule.run({
include: [axe.utils.getFlattenedTree(fixture)[0]]
}, {}, function() {
assert.isTrue(isDqElementCalled);
done();
}, isNotCalled);
});
it('is not created for disabled checks', function(done) {
var rule = new Rule({
all: ['cats']
}, {
checks: {
cats: new Check({
id: 'cats',
enabled: false,
evaluate: function() {},
matches: function() {
return true;
}
})
}
});
rule.run({
include: [axe.utils.getFlattenedTree(fixture)[0]]
}, {}, function() {
assert.isFalse(isDqElementCalled);
done();
}, isNotCalled);
});
it('is created for matching nodes', function(done) {
var rule = new Rule({
all: ['cats']
}, {
checks: {
cats: new Check({
id: 'cats',
enabled: true,
evaluate: function() {
return true;
}
})
}
});
rule.run({
include: [axe.utils.getFlattenedTree(fixture)[0]]
}, {}, function() {
assert.isTrue(isDqElementCalled);
done();
}, isNotCalled);
});
it('is not created for disabled checks', function(done) {
var rule = new Rule({
all: ['cats']
}, {
checks: {
cats: new Check({
id: 'cats',
enabled: false,
evaluate: function() {}
})
}
});
rule.run({
include: [axe.utils.getFlattenedTree(fixture)[0]]
}, {}, function() {
assert.isFalse(isDqElementCalled);
done();
}, isNotCalled);
});
});
it('should pass thrown errors to the reject param', function (done) {
fixture.innerHTML = '<blink>Hi</blink>';
var rule = new Rule({
none: ['cats']
}, {
checks: {
cats: {
run: function () {
throw new Error('Holy hand grenade');
}
}
}
});
rule.run({
include: [axe.utils.getFlattenedTree(fixture)[0]]
}, {}, noop, function(err) {
assert.equal(err.message, 'Holy hand grenade');
done();
}, isNotCalled);
});
it('should pass reject calls to the reject param', function (done) {
fixture.innerHTML = '<blink>Hi</blink>';
var rule = new Rule({
none: ['cats']
}, {
checks: {
cats: {
run: function (nope, options, resolve, reject) {
reject(new Error('your reality'));
}
}
}
});
rule.run({
include: [axe.utils.getFlattenedTree(fixture)[0]]
}, {}, noop, function(err) {
assert.equal(err.message, 'your reality');
done();
}, isNotCalled);
});
describe('NODE rule', function() {
it('should create a RuleResult', function() {
var orig = window.RuleResult;
var success = false;
window.RuleResult = function(r) {
this.nodes = [];
assert.equal(rule, r);
success = true;
};
var rule = new Rule({
any: [{
evaluate: function() {},
id: 'cats'
}]
}, {
checks: {
cats: {
run: function (node, options, resolve) {
success = true;
resolve(true);
}
}
}
});
rule.run({
include: [axe.utils.getFlattenedTree(document)[0]]
}, {}, noop, isNotCalled);
assert.isTrue(success);
window.RuleResult = orig;
});
it('should execute rule callback', function() {
var success = false;
var rule = new Rule({
any: [{
evaluate: function() {},
id: 'cats'
}]
}, {
checks: {
cats: {
run: function (node, options, resolve) {
success = true;
resolve(true);
}
}
}
});
rule.run({
include: [axe.utils.getFlattenedTree(document)[0]]
}, {}, function() {
success = true;
}, isNotCalled);
assert.isTrue(success);
});
});
});
describe('after', function() {
it('should execute Check#after with options', function() {
var success = false;
var rule = new Rule({
id: 'cats',
any: ['cats']
}, {
checks: {
cats: {
id: 'cats',
enabled: true,
after: function(results, options) {
assert.deepEqual(options, {
enabled: true,
options: { dogs: true },
absolutePaths: undefined
});
success = true;
return results;
}
}
}
});
rule.after({
id: 'cats',
nodes: [{
all: [],
none: [],
any: [{
id: 'cats',
result: true
}]
}]
}, { checks: { cats: { options: { dogs: true } }} });
assert.isTrue(success);
});
it('should filter removed checks', function () {
var rule = new Rule({
id: 'cats',
any: ['cats']
}, {
checks: {
cats: {
id: 'cats',
after: function(results) {
return [results[0]];
}
}
}
});
var result = rule.after({
id: 'cats',
nodes: [{
any: [],
none: [],
all: [{
id: 'cats',
result: true
}]
}, {
any: [],
none: [],
all: [{
id: 'cats',
result: false
}]
}]
}, { checks: { cats: { options: { dogs: true } }} });
assert.lengthOf(result.nodes, 1);
assert.equal(result.nodes[0].all[0].id, 'cats');
assert.isTrue(result.nodes[0].all[0].result);
});
it('should combine all checks for pageLevel rules', function () {
var rule = new Rule({});
var result = rule.after({
id: 'cats',
pageLevel: true,
nodes: [{
any: [],
none: [],
all: [{
id: 'cats',
result: false
}]
}, {
any: [],
none: [{
id: 'dogs',
result: false
}],
all: []
}, {
any: [{
id: 'monkeys',
result: false
}],
none: [],
all: []
}]
}, { checks: { cats: { options: { dogs: true } }} });
assert.lengthOf(result.nodes, 1);
});
});
});
describe('spec object', function() {
describe('.selector', function() {
it('should be set', function() {
var spec = {
selector: '#monkeys'
};
assert.equal(new Rule(spec).selector, spec.selector);
});
it('should default to *', function() {
var spec = {};
assert.equal(new Rule(spec).selector, '*');
});
});
describe('.enabled', function() {
it('should be set', function() {
var spec = {
enabled: false
};
assert.equal(new Rule(spec).enabled, spec.enabled);
});
it('should default to true', function() {
var spec = {};
assert.isTrue(new Rule(spec).enabled);
});
it('should default to true if given a bad value', function() {
var spec = {
enabled: 'monkeys'
};
assert.isTrue(new Rule(spec).enabled);
});
});
describe('.excludeHidden', function() {
it('should be set', function() {
var spec = {
excludeHidden: false
};
assert.equal(new Rule(spec).excludeHidden, spec.excludeHidden);
});
it('should default to true', function() {
var spec = {};
assert.isTrue(new Rule(spec).excludeHidden);
});
it('should default to true if given a bad value', function() {
var spec = {
excludeHidden: 'monkeys'
};
assert.isTrue(new Rule(spec).excludeHidden);
});
});
describe('.pageLevel', function() {
it('should be set', function() {
var spec = {
pageLevel: false
};
assert.equal(new Rule(spec).pageLevel, spec.pageLevel);
});
it('should default to false', function() {
var spec = {};
assert.isFalse(new Rule(spec).pageLevel);
});
it('should default to false if given a bad value', function() {
var spec = {
pageLevel: 'monkeys'
};
assert.isFalse(new Rule(spec).pageLevel);
});
});
describe('.id', function() {
it('should be set', function() {
var spec = {
id: 'monkeys'
};
assert.equal(new Rule(spec).id, spec.id);
});
it('should have no default', function() {
var spec = {};
assert.equal(new Rule(spec).id, spec.id);
});
});
describe('.any', function() {
it('should be set', function() {
var spec = {
any: [{
name: 'monkeys'
}, {
name: 'bananas'
}, {
name: 'pajamas'
}]
};
assert.property(new Rule(spec), 'any');
});
});
describe('.all', function() {
it('should be set', function() {
var spec = {
all: [{
name: 'monkeys'
}, {
name: 'bananas'
}, {
name: 'pajamas'
}]
};
assert.property(new Rule(spec), 'all');
});
});
describe('.none', function() {
it('should be set', function() {
var spec = {
none: [{
name: 'monkeys'
}, {
name: 'bananas'
}, {
name: 'pajamas'
}]
};
assert.property(new Rule(spec), 'none');
});
});
describe('.matches', function() {
it('should be set', function() {
var spec = {
matches: function() {}
};
assert.equal(new Rule(spec).matches, spec.matches);
});
it('should default to prototype', function() {
var spec = {};
assert.equal(new Rule(spec).matches, Rule.prototype.matches);
});
it('should turn a string into a function', function () {
var spec = {
matches: 'function() {return "blah";}'
};
assert.equal(new Rule(spec).matches(), 'blah');
});
});
describe('.tags', function() {
it('should be set', function() {
var spec = {
tags: ['foo', 'bar']
};
assert.deepEqual(new Rule(spec).tags, spec.tags);
});
it('should default to empty array', function() {
var spec = {};
assert.deepEqual(new Rule(spec).tags, []);
});
});
});
describe('configure', function () {
beforeEach(function () {
Rule.prototype._get = function (attr) {
return this[attr];
};
});
afterEach(function () {
delete Rule.prototype._get;
});
it('should be a function that takes one argument', function() {
assert.isFunction(Rule.prototype.configure);
assert.lengthOf(new Rule({}).configure, 1);
});
it('should NOT override the id', function () {
var rule = new Rule({id: 'foo'});
assert.equal(rule._get('id'), 'foo');
rule.configure({id: 'fong'});
assert.equal(rule._get('id'), 'foo');
});
it('should NOT override a random property', function () {
var rule = new Rule({id: 'foo'});
rule.configure({fong: 'fong'});
assert.equal(rule._get('fong'), undefined);
});
it('should override the selector', function () {
var rule = new Rule({selector: 'foo'});
assert.equal(rule._get('selector'), 'foo');
rule.configure({selector: 'fong'});
assert.equal(rule._get('selector'), 'fong');
});
it('should override excludeHidden', function () {
var rule = new Rule({excludeHidden: false});
assert.equal(rule._get('excludeHidden'), false);
rule.configure({excludeHidden: true});
assert.equal(rule._get('excludeHidden'), true);
});
it('should override enabled', function () {
var rule = new Rule({enabled: false});
assert.equal(rule._get('enabled'), false);
rule.configure({enabled: true});
assert.equal(rule._get('enabled'), true);
});
it('should override pageLevel', function () {
var rule = new Rule({pageLevel: false});
assert.equal(rule._get('pageLevel'), false);
rule.configure({pageLevel: true});
assert.equal(rule._get('pageLevel'), true);
});
it('should override any', function () {
var rule = new Rule({any: ['one', 'two']});
assert.deepEqual(rule._get('any'), ['one', 'two']);
rule.configure({any: []});
assert.deepEqual(rule._get('any'), []);
});
it('should override all', function () {
var rule = new Rule({all: ['one', 'two']});
assert.deepEqual(rule._get('all'), ['one', 'two']);
rule.configure({all: []});
assert.deepEqual(rule._get('all'), []);
});
it('should override none', function () {
var rule = new Rule({none: ['none', 'two']});
assert.deepEqual(rule._get('none'), ['none', 'two']);
rule.configure({none: []});
assert.deepEqual(rule._get('none'), []);
});
it('should override tags', function () {
var rule = new Rule({tags: ['tags', 'two']});
assert.deepEqual(rule._get('tags'), ['tags', 'two']);
rule.configure({tags: []});
assert.deepEqual(rule._get('tags'), []);
});
it('should override matches', function () {
var rule = new Rule({matches: 'function () {return "matches";}'});
assert.equal(rule._get('matches')(), 'matches');
rule.configure({matches: 'function () {return "does not match";}'});
assert.equal(rule._get('matches')(), 'does not match');
});
});
});