aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Benjamin Jones <bjones@galois.com>2013-07-24 18:18:03 -0700
committerGravatar Benjamin Jones <bjones@galois.com>2013-07-24 18:18:03 -0700
commit5d0167e9bb639e58698ad6d2c9d279f2d2474dbe (patch)
tree72bf1fb30dc2d1c70d947f2a405bb2799e5ab611
parent960c8b96da9218eafa369db9a1f4bea9f737f0df (diff)
parentc3c96bff28172fab02ba70191c386b89b6946314 (diff)
Merge branch 'master' into new-ui-severity
-rw-r--r--guidelines/WCAG-1.0/guideline-5.js34
-rw-r--r--src/js/fiveui/injected/jquery-plugins.js64
-rw-r--r--src/js/tests/README.md9
-rw-r--r--src/js/tests/specs/jquery-plugins.js62
-rw-r--r--src/js/tests/specs/rules.js8
5 files changed, 133 insertions, 44 deletions
diff --git a/guidelines/WCAG-1.0/guideline-5.js b/guidelines/WCAG-1.0/guideline-5.js
index 48feb49..c8decd7 100644
--- a/guidelines/WCAG-1.0/guideline-5.js
+++ b/guidelines/WCAG-1.0/guideline-5.js
@@ -7,28 +7,32 @@ exports.rule = function(report) {
* For data tables, identify row and column headers.
*/
- $('table').each(function () {
- if ($(this).find('th').length == 0) {
- report.error('Table does not have column headers <TH>', this);
- }
+ $5('table').noSubElt('th').each(function () {
+ report.error('Table does not have column headers <TH>', this);
});
-
/* Checkpoint 5.5 ***********************************************************
*
* Provide summaries for tables.
*/
- $('table').each(function () {
- var $cap = $(this).find('caption');
- var title = $.trim($(this).attr('title'));
- var sum = $.trim($(this).attr('summary'));
- if ($cap.length == 0 && (title === undefined || title == '')) {
- report.error('Table has no caption or title attribute', this);
- }
- if (sum === undefined || sum == '') {
- report.error('Table has no summary attribute', this);
- }
+ $5('table').noSubElt('caption')
+ .noAttr('title')
+ .each(function () {
+ report.warning('Table has no caption or title attribute', this);
+ });
+
+ $('table').noAttr('summary').each(function () {
+ report.warning('Table has no summary attribute', this);
+ });
+
+ /* Checkpoint 5.6 ***********************************************************
+ *
+ * Provide `abbr` attributes to table headers <TH>
+ */
+
+ $5('th').noAttr('abbr').each(function () {
+ report.advisory('<TH> has no abbrevation attribute', this);
});
};
diff --git a/src/js/fiveui/injected/jquery-plugins.js b/src/js/fiveui/injected/jquery-plugins.js
index a8c99f2..309c566 100644
--- a/src/js/fiveui/injected/jquery-plugins.js
+++ b/src/js/fiveui/injected/jquery-plugins.js
@@ -45,7 +45,8 @@ fiveui.jquery.hasText = function (text) {
};
/**
- * Filter for elements which lack of the given attribute.
+ * Filter for elements which lack of the given attribute. (see also
+ * fiveui.jquery.attrFilter)
*
* Example:
*
@@ -103,6 +104,27 @@ fiveui.jquery.notColorSet = function (cset) {
});
};
+
+fiveui.jquery._makeCss = function (pos) {
+ return function (prop, set, fn) {
+ var allowable = {};
+ fn = fn || function (x) { return x; }; // default is Id
+ if (typeof set === "string") {
+ allowable[fn(set)] = true;
+ }
+ else { // assume `set` is an array of strings
+ // array -> object
+ for (var i = 0; i < set.length; i += 1) {
+ allowable[fn(set[i])] = true;
+ }
+ }
+ return this.filter(function (index) {
+ var cssProp = fn($(this).css(prop));
+ return pos ? (cssProp in allowable) : !(cssProp in allowable);
+ });
+ };
+};
+
/**
* General CSS propetry checker plugin
*
@@ -112,25 +134,31 @@ fiveui.jquery.notColorSet = function (cset) {
* browser returns so they can be compared to values in `cset`.
*
* @param {String} prop CSS property selector
- * @param {String|String[]} set allowable values (either a string or an array of strings)
- * @param {function(String):String} [fn] Function to apply to return values of $(this).css(prop), fn defaults to the identity function.
+ * @param {String|String[]} set allowable values (either a string or an array
+ * of strings)
+ * @param {function(String):String} [fn] Function to apply to return values
+ * of $(this).css(prop), fn defaults to
+ * the identity function.
* @returns {Object} jQuery object
*/
-fiveui.jquery.cssIsNot = function (prop, set, fn) {
- var allowable = {};
- fn = fn || function (x) { return x; }; // default is Id
- if (typeof set === "string") {
- allowable[fn(set)] = true;
- }
- else { // assume `set` is an array of strings
- // array -> object
- for (var i = 0; i < set.length; i += 1) {
- allowable[fn(set[i])] = true;
- }
- }
- return this.filter(function (index) {
- var cssProp = fn($(this).css(prop));
- return !(cssProp in allowable);
+fiveui.jquery.cssIs = fiveui.jquery._makeCss(true);
+fiveui.jquery.cssIsNot = fiveui.jquery._makeCss(false);
+
+/**
+ * General attribute filter
+ *
+ * @description This plugin filters for elements whose attribute `a` pass
+ * the predicate `fn`, which should take a string and return true or false.
+ * Elements that don't have the attribute are automatically filtered out.
+ *
+ * @param {String} a element attribute name
+ * @param {Function} fn a predicate to run on the element attribute
+ * @returns {Object} jQuery object
+ */
+fiveui.jquery.attrFilter = function (a, fn) {
+ return this.filter(function () {
+ var x = $(this).attr(a);
+ return x != undefined && fn(x);
});
}
diff --git a/src/js/tests/README.md b/src/js/tests/README.md
index dbd8435..1127a70 100644
--- a/src/js/tests/README.md
+++ b/src/js/tests/README.md
@@ -9,7 +9,7 @@ In Browser
----------
Start a local webserver at the FiveUI project root ($FIVEUI_ROOT) and load
-`contexts/data/tests/SpecRunner.html`.
+`src/js/tests/SpecRunner.html`.
Headless
--------
@@ -22,9 +22,8 @@ Install [phantomjs](http://phantomjs.org/) on your system.
Run:
- $ cd contexts/data
- $ phantomjs lib/phantomjs_jasmine/phantomjs_jasminexml_runner.js \
- tests/PhantomJSJasmineRunner.html tests/reports/
+ $ phantomjs ../lib/phantomjs_jasmine/phantomjs_jasminexml_runner.js \
+ PhantomJSJasmineRunner.html reports/
XML test reports will be generated in
-`$FIVEUI_ROOT/contexts/data/tests/reports/`.
+`$FIVEUI_ROOT/src/js/tests/reports/`.
diff --git a/src/js/tests/specs/jquery-plugins.js b/src/js/tests/specs/jquery-plugins.js
index 7fc196b..2f33b1a 100644
--- a/src/js/tests/specs/jquery-plugins.js
+++ b/src/js/tests/specs/jquery-plugins.js
@@ -86,7 +86,34 @@ describe('jQuery plugins', function () {
});
it('filters out everything', function () {
- expect($t.notColorSet(['#ffffff', '#000000', '#e1e1e1']).length).toEqual(0);
+ expect(
+ $t.notColorSet(['#ffffff', '#000000', '#e1e1e1']).length).toEqual(0
+ );
+ });
+ });
+
+ describe('fiveui.jquery.cssIs', function () {
+ var htm = '<p style="color: #000000; background-color: #232323">foo</p>' +
+ '<p style="color: #ffffff; font-size: 5em">foo</p>' +
+ '<p style="color: #e1e1e1; background-color: #141414">foo</p>' +
+ '<p style="color: #ffffff">foo</p>' +
+ '<h1 style="color: #ffffff; font-size: 5em">big</h1>';
+ var $t = $(htm);
+
+ it('filters out colors', function () {
+ expect($t.cssIs('color',
+ ['#ffffff', '#000000'],
+ fiveui.color.colorToHexWithDefault).length).toEqual(4);
+ });
+
+ it('filters out background-colors', function () {
+ expect($t.cssIs('background-color',
+ ['#141414', '#232323'],
+ fiveui.color.colorToHexWithDefault).length).toEqual(2);
+ });
+
+ it('filters out elements of different type', function () {
+ expect($t.cssIs('font-size', ['5em']).length).toEqual(2);
});
});
@@ -99,11 +126,15 @@ describe('jQuery plugins', function () {
var $t = $(htm);
it('filters out colors', function () {
- expect($t.cssIsNot('color', ['#ffffff', '#000000'], fiveui.color.colorToHexWithDefault).length).toEqual(1);
+ expect($t.cssIsNot('color',
+ ['#ffffff', '#000000'],
+ fiveui.color.colorToHexWithDefault).length).toEqual(1);
});
it('filters out background-colors', function () {
- expect($t.cssIsNot('background-color', ['#141414', '#232323'], fiveui.color.colorToHexWithDefault).length).toEqual(3);
+ expect($t.cssIsNot('background-color',
+ ['#141414', '#232323'],
+ fiveui.color.colorToHexWithDefault).length).toEqual(3);
});
it('filters out elements of different type', function () {
@@ -111,6 +142,31 @@ describe('jQuery plugins', function () {
});
});
+ describe('fiveui.jquery.attrFilter', function () {
+ var isEmpty = function (s) { return $.trim(s) == ""; };
+
+ it('filters for zero elements with empty alt', function () {
+ var $elt = $('<a href="foo" alt="bar"><a href="beel" alt="bar">');
+ expect($elt.attrFilter('alt', isEmpty).length).toEqual(0);
+ });
+
+ it('filters for one element with empty alt', function () {
+ var $elt = $('<a href="foo" alt=""><a href="beel" alt="bar">');
+ expect($elt.attrFilter('alt', isEmpty).length).toEqual(1);
+ });
+
+ it('filters out elements that don\'t have the attribute', function () {
+ var $elt = $('<a href="foo"><a href="beel">');
+ expect($elt.attrFilter('alt', isEmpty).length).toEqual(0);
+ });
+
+ it('filters for elements with alt containing foo', function () {
+ var hasFoo = function (s) { return /foo/.test(s); };
+ var $elt = $('<a href="foo" alt="barfoo"><a href="beel" alt="bar">');
+ expect($elt.attrFilter('alt', hasFoo).length).toEqual(1);
+ });
+ });
+
describe('fiveui.jquery.linksTo', function () {
it('filters out elements with no href', function () {
expect($('<p>foo</p>').linksTo('bar').length).toEqual(0);
diff --git a/src/js/tests/specs/rules.js b/src/js/tests/specs/rules.js
index 518cfc9..b863037 100644
--- a/src/js/tests/specs/rules.js
+++ b/src/js/tests/specs/rules.js
@@ -3,7 +3,7 @@ describe('fiveui.Rules', function() {
it('round trips via JSON', function() {
- var ruleIn = new fiveui.Rule({
+ var ruleIn = new fiveui.RuleSet({
id: 42,
name: 'testRule',
description: 'see: http://test.description/',
@@ -11,7 +11,7 @@ describe('fiveui.Rules', function() {
var jsonRule = JSON.stringify(ruleIn);
- var ruleOut = fiveui.Rule.fromJSON(JSON.parse(jsonRule));
+ var ruleOut = fiveui.RuleSet.fromJSON(42, JSON.parse(jsonRule));
expect(ruleOut.id).toBe(ruleIn.id);
expect(ruleOut.name).toBe(ruleIn.name);
@@ -50,7 +50,9 @@ describe('fiveui.RuleSet', function() {
var ruleSet = new fiveui.RuleSet({
id: 42,
name: 'rule set',
- description: 'desc', [rule1, rule2],
+ description: 'desc',
+ rules: ['rule1', 'rule2'],
+ dependencies: ['dep1', 'dep2']
});
var jsonSet = JSON.stringify(ruleSet);