This repository has been archived by the owner on Feb 26, 2024. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2389e92
Showing
22 changed files
with
1,086 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules/ | ||
npm-debug.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
testapp/ | ||
spec/ | ||
test.js | ||
test_util.js | ||
.npmignore | ||
npm-debug.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
The MIT License | ||
|
||
Copyright (c) 2010-2015 Google, Inc. | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
Accessibility Plugin | ||
==================== | ||
|
||
Protractor comes with support for two accessibility testing options: | ||
* Accessibility Developer Tools | ||
* Tenon.io | ||
|
||
Protractor will run each set of audits (depending on your configuration) on your existing end-to-end | ||
tests to ensure your site is free of obvious errors. In this kind of testing, there is no concept of | ||
"warnings"–only pass or fail. In your configuration, you can decide whether warnings should | ||
pass or fail your build. | ||
|
||
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/) | | ||
|
||
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) | ||
locally by injecting the Dev Tools script into WebDriver pages, and it can diagnose issues including | ||
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. | ||
|
||
[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 | ||
Tenon with introspection services like ngrok or localtunnel to securely | ||
test local web servers. Protractor takes the [options you provide](http://tenon.io/documentation/understanding-request-parameters.php) in the plugin configuration and sends them | ||
with the page source to the Tenon API. One limitation of this approach is that all scripts must be reachable from the page source as a string, for example, by using a CDN. | ||
For projects with an MIT license, Tenon is free but with a limited | ||
daily API limit. Paid subscriptions are available for enterprise and commercial projects. | ||
|
||
Enable this plugin in your config file: | ||
```js | ||
// Chrome Accessibility Dev Tools only: | ||
exports.config = { | ||
... | ||
plugins: [{ | ||
chromeA11YDevTools: { | ||
treatWarningsAsFailures: true | ||
}, | ||
path: 'node_modules/protractor/plugins/accessibility' | ||
}] | ||
} | ||
``` | ||
```js | ||
// Tenon.io only: | ||
exports.config = { | ||
... | ||
plugins: [{ | ||
tenonIO: { | ||
options: { | ||
// See http://tenon.io/documentation/understanding-request-parameters.php | ||
// options.src will be added by the test. | ||
}, | ||
printAll: false, // whether the plugin should log API response | ||
}, | ||
chromeA11YDevTools: true, | ||
path: 'node_modules/protractor/plugins/accessibility' | ||
}] | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
var q = require('q'), | ||
fs = require('fs'), | ||
path = require('path'), | ||
_ = require('lodash'); | ||
request = require('request'), | ||
Entities = require('html-entities').XmlEntities; | ||
|
||
/** | ||
* You can audit your website against the Chrome Accessibility Developer Tools, | ||
* Tenon.io, or both by enabling this plugin in your config file: | ||
* | ||
* // Chrome Accessibility Developer Tools: | ||
* exports.config = { | ||
* ... | ||
* plugins: [{ | ||
* chromeA11YDevTools: { | ||
* treatWarningsAsFailures: true | ||
* }, | ||
* path: 'node_modules/protractor.plugins/accessiblity' | ||
* }] | ||
* } | ||
* | ||
* // Tenon.io: | ||
* | ||
* // Read about the Tenon.io settings and API requirements: | ||
* // -http://tenon.io/documentation/overview.php | ||
* | ||
* exports.config = { | ||
* ... | ||
* plugins: [{ | ||
* tenonIO: { | ||
* options: { | ||
* // See http://tenon.io/documentation/understanding-request-parameters.php | ||
* // options.src will be added by the test. | ||
* }, | ||
* printAll: false, // whether the plugin should log API response | ||
* }, | ||
* chromeA11YDevTools: false, | ||
* path: 'node_modules/protractor/plugins/accessiblity' | ||
* }] | ||
* } | ||
* | ||
*/ | ||
|
||
var AUDIT_FILE = require.resolve('accessibility-developer-tools/dist/js/axs_testing.js'); | ||
var TENON_URL = 'http://www.tenon.io/api/'; | ||
|
||
/** | ||
* Checks the information returned by the accessibility audit(s) and | ||
* displays passed/failed results as console output. | ||
* | ||
* @this {Object} The plugin context object | ||
* @return {q.Promise} A promise which resolves when all audits are finished | ||
* @public | ||
*/ | ||
function teardown() { | ||
|
||
var audits = []; | ||
|
||
if (this.config.chromeA11YDevTools) { | ||
audits.push(runChromeDevTools(this)); | ||
} | ||
// check for Tenon config and an actual API key, not the placeholder | ||
if (this.config.tenonIO && /[A-Za-z][0-9]/.test( | ||
this.config.tenonIO.options.key)) { | ||
audits.push(runTenonIO(this)); | ||
} | ||
return q.all(audits); | ||
} | ||
|
||
var entities = new Entities(); | ||
|
||
/** | ||
* Audits page source against the Tenon API, if configured. Requires an API key: | ||
* more information about licensing and configuration available at | ||
* http://tenon.io/documentation/overview.php. | ||
* | ||
* @param {Object} context The plugin context object | ||
* @return {q.Promise} A promise which resolves when the audit is finished | ||
* @private | ||
*/ | ||
function runTenonIO(context) { | ||
|
||
return browser.driver.getPageSource().then(function(source) { | ||
|
||
var options = _.assign(context.config.tenonIO.options, {src: source}); | ||
|
||
// setup response as a deferred promise | ||
var deferred = q.defer(); | ||
request.post({ | ||
url: TENON_URL, | ||
form: options | ||
}, | ||
function(err, httpResponse, body) { | ||
if (err) { return resolve.reject(new Error(err)); } | ||
else { return deferred.resolve(JSON.parse(body)); } | ||
}); | ||
|
||
return deferred.promise.then(function(response) { | ||
return processTenonResults(response); | ||
}); | ||
}); | ||
|
||
function processTenonResults(response) { | ||
|
||
var testHeader = 'Tenon.io - '; | ||
|
||
if (!response.resultSet) { | ||
if (response.code === 'daily_limit_reached') { | ||
console.log(testHeader, 'Daily limit reached'); | ||
console.log(response.moreInfo); | ||
} | ||
else { | ||
console.log('Tenon.io error'); | ||
} | ||
return; | ||
} | ||
|
||
var numResults = response.resultSet.length; | ||
|
||
if (numResults === 0) { | ||
context.addSuccess(); | ||
return; | ||
} | ||
|
||
if (context.config.tenonIO.printAll) { | ||
console.log('\x1b[32m', testHeader + 'API response', '\x1b[39m'); | ||
console.log(response); | ||
} | ||
|
||
return response.resultSet.forEach(function(result) { | ||
var ref = (result.ref === null) ? '' : result.ref; | ||
|
||
context.addFailure(result.errorDescription + '\n\n' + | ||
'\t\t' +entities.decode(result.errorSnippet) + | ||
'\n\n\t\t' + ref, {specName: testHeader + result.errorTitle}); | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* Audits page source against the Chrome Accessibility Developer Tools, if configured. | ||
* | ||
* @param {Object} context The plugin context object | ||
* @return {q.Promise} A promise which resolves when the audit is finished | ||
* @private | ||
*/ | ||
function runChromeDevTools(context) { | ||
|
||
var data = fs.readFileSync(AUDIT_FILE, 'utf-8'); | ||
data = data + ' return axs.Audit.run();'; | ||
|
||
var elementPromises = [], | ||
elementStringLength = 200; | ||
|
||
function trimText(text) { | ||
if (text.length > elementStringLength) { | ||
return text.substring(0, elementStringLength / 2) + ' ... ' | ||
+ text.substring(text.length - elementStringLength / 2); | ||
} else { | ||
return text; | ||
} | ||
} | ||
|
||
var testHeader = 'Chrome A11Y - '; | ||
|
||
return browser.executeScript_(data, 'a11y developer tool rules').then(function(results) { | ||
|
||
var audit = results.map(function(result) { | ||
var DOMElements = result.elements; | ||
if (DOMElements !== undefined) { | ||
|
||
DOMElements.forEach(function(elem) { | ||
// get elements from WebDriver, add to promises array | ||
elementPromises.push( | ||
elem.getOuterHtml().then(function(text) { | ||
return { | ||
code: result.rule.code, | ||
list: trimText(text) | ||
}; | ||
}, | ||
function(reason){ | ||
return { | ||
code: result.rule.code, | ||
list: reason | ||
}; | ||
}) | ||
); | ||
}); | ||
result.elementCount = DOMElements.length; | ||
} | ||
return result; | ||
}); | ||
|
||
// Wait for element names to be fetched | ||
return q.all(elementPromises).then(function(elementFailures) { | ||
|
||
return audit.forEach(function(result, index) { | ||
if (result.result === 'FAIL') { | ||
var label = result.elementCount === 1 ? ' element ' : ' elements '; | ||
if (result.rule.severity !== 'Warning' | ||
|| context.config.chromeA11YDevTools.treatWarningsAsFailures) { | ||
result.warning = false; | ||
} else { | ||
result.warning = true; | ||
result.rule.heading = '\x1b[33m(WARNING) ' | ||
+ result.rule.heading + ' (' + result.elementCount | ||
+ label + 'failed)'; | ||
} | ||
result.output = '\n\t\t' + result.elementCount + label + 'failed:'; | ||
|
||
// match elements returned via promises | ||
// by their failure codes | ||
elementFailures.forEach(function(element, index) { | ||
if (element.code === result.rule.code) { | ||
result.output += '\n\t\t' + elementFailures[index].list; | ||
} | ||
}); | ||
result.output += '\n\n\t\t' + result.rule.url; | ||
(result.warning ? context.addWarning : context.addFailure)( | ||
result.output, {specName: testHeader + result.rule.heading}); | ||
} | ||
else { | ||
context.addSuccess({specName: testHeader + result.rule.heading}); | ||
} | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
// Export | ||
exports.teardown = teardown; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
{ | ||
"name": "protractor-accessibility-plugin", | ||
"version": "0.1.0", | ||
"description": "Runs a set of accessibility audits", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "./node_modules/httpster/bin/httpster -d testapp/ -p `node -p 'process.env.HTTP_PORT || require(\"./spec/environment\").webServerDefaultPort'`", | ||
"test": "node test.js" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/angular/protractor-accessibility-plugin" | ||
}, | ||
"keywords": [ | ||
"angular", | ||
"test", | ||
"testing", | ||
"webdriver", | ||
"webdriverjs", | ||
"selenium", | ||
"protractor", | ||
"protractor-plugin" | ||
], | ||
"author": "Marcy Sutton (marcy@substantial.com)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/angular/protractor-accessibility-plugin/issues" | ||
}, | ||
"homepage": "https://github.com/angular/protractor-accessibility-plugin", | ||
"dependencies": { | ||
"accessibility-developer-tools": "^2.9.0-rc.0", | ||
"html-entities": "^1.2.0", | ||
"lodash": "^3.10.1", | ||
"q": "^1.4.1", | ||
"request": "^2.65.0" | ||
}, | ||
"devDependencies": { | ||
"httpster": "^1.0.1", | ||
"protractor": "^2.5.1" | ||
} | ||
} |
Oops, something went wrong.