Skip to content

Commit

Permalink
feat(valid-lang): add option for which attributes to look at (#2240)
Browse files Browse the repository at this point in the history
  • Loading branch information
straker authored May 20, 2020
1 parent 7088c7a commit ffee19e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 139 deletions.
20 changes: 9 additions & 11 deletions lib/checks/language/valid-lang-evaluate.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import { validLangs, getBaseLang } from '../../core/utils';

function validLangEvaluate(node, options) {
var langs, invalid;
function validLangEvaluate(node, options, virtualNode) {
const langs = (options.value ? options.value : validLangs()).map(getBaseLang);

langs = (options.value ? options.value : validLangs()).map(getBaseLang);

invalid = ['lang', 'xml:lang'].reduce(function(invalid, langAttr) {
var langVal = node.getAttribute(langAttr);
const invalid = [];
options.attributes.forEach(langAttr => {
const langVal = virtualNode.attr(langAttr);
if (typeof langVal !== 'string') {
return invalid;
return;
}

var baselangVal = getBaseLang(langVal);
const baselangVal = getBaseLang(langVal);

// Edge sets lang to an empty string when xml:lang is set
// so we need to ignore empty strings here
if (baselangVal !== '' && langs.indexOf(baselangVal) === -1) {
invalid.push(langAttr + '="' + node.getAttribute(langAttr) + '"');
invalid.push(langAttr + '="' + virtualNode.attr(langAttr) + '"');
}
return invalid;
}, []);
});

if (invalid.length) {
this.data(invalid);
Expand Down
3 changes: 3 additions & 0 deletions lib/checks/language/valid-lang.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"id": "valid-lang",
"evaluate": "valid-lang-evaluate",
"options": {
"attributes": ["lang", "xml:lang"]
},
"metadata": {
"impact": "serious",
"messages": {
Expand Down
166 changes: 38 additions & 128 deletions test/checks/language/valid-lang.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,159 +2,69 @@ describe('valid-lang', function() {
'use strict';

var fixture = document.getElementById('fixture');

var checkSetup = axe.testUtils.checkSetup;
var checkContext = axe.testUtils.MockCheckContext();
var validLangEvaluate = axe.testUtils.getCheckEvaluate('valid-lang');

afterEach(function() {
fixture.innerHTML = '';
checkContext.reset();
});

describe('lang', function() {
it('should return false if a lang attribute is present in options', function() {
var node = document.createElement('div');
node.setAttribute('lang', 'woohoo');
fixture.appendChild(node);

assert.isFalse(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, ['blah', 'blah', 'woohoo'])
);
it('should return false if a lang attribute is present in options', function() {
var params = checkSetup('<div id="target" lang="woohoo"></div>', {
value: ['blah', 'blah', 'woohoo']
});

it('should lowercase options and attribute first', function() {
var node = document.createElement('div');
node.setAttribute('lang', 'wooHOo');
fixture.appendChild(node);
assert.isFalse(validLangEvaluate.apply(checkContext, params));
});

assert.isFalse(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, ['blah', 'blah', 'wOohoo'])
);
it('should lowercase options and attribute first', function() {
var params = checkSetup('<div id="target" lang="wooHOo"></div>', {
value: ['blah', 'blah', 'wOohoo']
});

it('should return true if a lang attribute is not present in options', function() {
var node = document.createElement('div');
node.setAttribute('lang', 'en-FOO');
fixture.appendChild(node);

assert.isTrue(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, [])
);
assert.deepEqual(checkContext._data, ['lang="en-FOO"']);
});
assert.isFalse(validLangEvaluate.apply(checkContext, params));
});

it('should return false (and not throw) when given no options', function() {
var node = document.createElement('div');
node.setAttribute('lang', 'en-US');
fixture.appendChild(node);
it('should return true if a lang attribute is not present in options', function() {
var params = checkSetup('<div id="target" lang="FOO"></div>');

assert.isFalse(
axe.testUtils.getCheckEvaluate('valid-lang').call(checkContext, node)
);
});

it('should return true if the language is badly formatted', function() {
var node = document.createElement('div');
node.setAttribute('lang', 'en_US');
fixture.appendChild(node);

assert.isTrue(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, ['en'])
);
assert.deepEqual(checkContext._data, ['lang="en_US"']);
});
assert.isTrue(validLangEvaluate.apply(checkContext, params));
assert.deepEqual(checkContext._data, ['lang="FOO"']);
});

it('should return false if it matches a substring proceeded by -', function() {
var node = document.createElement('div');
node.setAttribute('lang', 'en-LOL');
fixture.appendChild(node);
it('should return false (and not throw) when given no present in options', function() {
var params = checkSetup('<div id="target" lang="en"></div>');

assert.isFalse(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, ['en'])
);
});
assert.isFalse(validLangEvaluate.apply(checkContext, params));
});

describe('xml:lang', function() {
it('should return false if a lang attribute is present in options', function() {
var node = document.createElement('div');
node.setAttribute('xml:lang', 'woohoo');
fixture.appendChild(node);

assert.isFalse(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, ['blah', 'blah', 'woohoo'])
);
});
it('should return true if the language is badly formatted', function() {
var params = checkSetup('<div id="target" lang="en_US"></div>');

it('should lowercase options and attribute first', function() {
var node = document.createElement('div');
node.setAttribute('xml:lang', 'wooHOo');
fixture.appendChild(node);
assert.isTrue(validLangEvaluate.apply(checkContext, params));
assert.deepEqual(checkContext._data, ['lang="en_US"']);
});

assert.isFalse(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, ['blah', 'blah', 'wOohoo'])
);
});
it('should return false if it matches a substring proceeded by -', function() {
var params = checkSetup('<div id="target" lang="en-LOL"></div>');

it('should return true if a lang attribute is not present in options', function() {
var node = document.createElement('div');
node.setAttribute('xml:lang', 'en-FOO');
fixture.appendChild(node);

assert.isTrue(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, [])
);
assert.deepEqual(checkContext._data, ['xml:lang="en-FOO"']);
});
assert.isFalse(validLangEvaluate.apply(checkContext, params));
});

it('should return false (and not throw) when given no options', function() {
var node = document.createElement('div');
node.setAttribute('xml:lang', 'en-US');
fixture.appendChild(node);
it('should work with xml:lang', function() {
var params = checkSetup('<div id="target" xml:lang="en-LOL"></div>');

assert.isFalse(
axe.testUtils.getCheckEvaluate('valid-lang').call(checkContext, node)
);
});
assert.isFalse(validLangEvaluate.apply(checkContext, params));
});

it('should return true if the language is badly formatted', function() {
var node = document.createElement('div');
node.setAttribute('xml:lang', 'en_US');
fixture.appendChild(node);

assert.isTrue(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, ['en'])
);
assert.deepEqual(checkContext._data, ['xml:lang="en_US"']);
it('should accept options.attributes', function() {
var params = checkSetup('<div id="target" custom-lang="en_US"></div>', {
attributes: ['custom-lang']
});

it('should return false if it matches a substring proceeded by -', function() {
var node = document.createElement('div');
node.setAttribute('xml:lang', 'en-LOL');
fixture.appendChild(node);

assert.isFalse(
axe.testUtils
.getCheckEvaluate('valid-lang')
.call(checkContext, node, ['en'])
);
});
assert.isTrue(validLangEvaluate.apply(checkContext, params));
assert.deepEqual(checkContext._data, ['custom-lang="en_US"']);
});
});

0 comments on commit ffee19e

Please sign in to comment.