diff --git a/README.md b/README.md index 5690575..5494b3b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ Accessibility Plugin ==================== -Protractor comes with support for two accessibility testing options: +Protractor comes with support for three accessibility testing options: * Accessibility Developer Tools + * aXe Accessibility Engine * Tenon.io Protractor will run each set of audits (depending on your configuration) on your existing end-to-end @@ -14,8 +15,9 @@ To understand how each of these tools can be used, see this support matrix: | Testing Library | Pricing | API Key | External Request | No. of Tests | Info | |--------------------------------------|-------------------------------------------|---------|------------------|--------------|-------------------------------------------------------------------------| -| Chrome Accessibility Developer Tools | Free | No | No | 14 | [Github](https://github.com/GoogleChrome/accessibility-developer-tools) | -| Tenon.io | Free limited accounts, paid subscriptions | Yes | Yes | 63 | [Tenon.io](http://tenon.io/) | +| Chrome Accessibility Developer Tools | Free | No | No | 14 | [GitHub](https://github.com/GoogleChrome/accessibility-developer-tools) | +| aXe Accessibility Engine | Free | No | No | 53 | [GitHub](https://github.com/dequelabs/axe-core/) +| Tenon.io | Free limited accounts, paid subscriptions | Yes | Yes | 63 | [Tenon.io](http://tenon.io/) | | Protractor now supports the [Accessibility Developer Tools](https://github.com/GoogleChrome/accessibility-developer-tools), the same audit library used by the [Chrome browser extension](https://chrome.google.com/webstore/detail/accessibility-developer-t/fpkknkljclfencbdbgkenhalefipecmb?hl=en). Protractor [runs an audit](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules) @@ -23,6 +25,8 @@ locally by injecting the Dev Tools script into WebDriver pages, and it can diagn missing labels, incorrect ARIA attributes and color contrast. This is a great starting point if you can't send source code over the wire through an API. +[aXe](https://github.com/dequelabs/axe-core) operates similarly to Chrome's Accessibility Developer Tools by injecting axe-core into all frames and checking the content against 53 [accessibility rules](https://github.com/dequelabs/axe-core/blob/master/doc/rule-descriptions.md). + [Tenon.io](http://www.tenon.io) has a more robust set of tests to help you find accessibility issues, but it requires [registering](http://tenon.io/register.php) for an API key and making an external request for each test, which may not work for everyone. Some people use @@ -65,6 +69,16 @@ Enable this plugin in your config file: }] } ``` +```js + // aXe only: + exports.config = { + ... + plugins: [{ + axe: true, + package: 'protractor-accessibility-plugin' + }] + } +``` ```js // Tenon.io only: exports.config = { diff --git a/index.js b/index.js index 0d9749c..ac27f41 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ var q = require('q'), path = require('path'), _ = require('lodash'), request = require('request'), + AxeBuilder = require('axe-webdriverjs'), Entities = require('html-entities').XmlEntities; /** @@ -57,6 +58,10 @@ function teardown() { var audits = []; + if (this.config.axe) { + audits.push(runAxe(this)); + } + if (this.config.chromeA11YDevTools) { audits.push(runChromeDevTools(this)); } @@ -226,6 +231,54 @@ function runChromeDevTools(context) { }); }); }); + +} + +/** + * Audits page source against aXe: https://github.com/dequelabs/axe-core + * + * @param {Object} context The plugin context object + * @return {q.Promise} A promise which resolves when the audit is finished + * @private + */ +function runAxe(context) { + + var deferred = q.defer(); + + AxeBuilder(browser.driver) + .analyze(function(results) { + deferred.resolve(results); + }); + + return deferred.promise.then(function(results) { + return processAxeResults(results); + }); + + function processAxeResults(results) { + + var testHeader = 'aXe - ' + + var numResults = results.violations.length; + + if (numResults === 0) { + return context.addSuccess(); + } + + results.passes.forEach(function(result) { + context.addSuccess({specName: testHeader + result.help}); + }); + + return results.violations.forEach(function(result) { + var label = result.nodes.length === 1 ? ' element ' : ' elements '; + var msg = result.nodes.reduce(function(msg, node) { + return msg + '\t\t' + node.html + '\n'; + }, '\n'); + msg = '\n\t\t' + result.nodes.length + label + 'failed:' + msg + '\n\n\t\t' + result.helpUrl + context.addFailure(msg, {specName: testHeader + result.help}); + }); + + } + } // Export diff --git a/package.json b/package.json index 1637327..e5ff496 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ "homepage": "https://github.com/angular/protractor-accessibility-plugin", "dependencies": { "accessibility-developer-tools": "^2.9.0-rc.0", + "axe-core": "^2.0.5", + "axe-webdriverjs": "^0.2.0", "html-entities": "^1.2.0", "lodash": "^3.10.1", "q": "^1.4.1", diff --git a/spec/failureConfig.js b/spec/failureConfig.js index 8b6bb99..78f22cc 100644 --- a/spec/failureConfig.js +++ b/spec/failureConfig.js @@ -16,6 +16,7 @@ exports.config = { chromeA11YDevTools: { treatWarningsAsFailures: true }, + axe: true, path: '../index.js' }] }; diff --git a/test.js b/test.js index b80c3c0..b0bbd72 100755 --- a/test.js +++ b/test.js @@ -26,6 +26,15 @@ executor.addCommandlineTest( { message: '1 element failed:' }, + { + message: '1 element failed:' + }, + { + message: '3 elements failed:' + }, + { + message: '1 element failed:' + }, { message: '1 element failed:' }]);