Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get develop-2x up to date with support docs #635

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ axe.*.js
npm-shrinkwrap.json
typings/axe-core/axe-core-tests.js
doc/rule-descriptions.*.md
package-lock.json
package-lock.json
.DS_Store
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Contributor License Agreement

In order to contribute, you must accept the [contributor licence agreement](https://cla-assistant.io/dequelabs/axe-core) (CLA). Acceptance of this agreement will be checked automatically and pull requests without a CLA cannot be merged.
In order to contribute, you must accept the [contributor license agreement](https://cla-assistant.io/dequelabs/axe-core) (CLA). Acceptance of this agreement will be checked automatically and pull requests without a CLA cannot be merged.

## Contribution Guidelines

Expand Down
12 changes: 6 additions & 6 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ module.exports = function (grunt) {
]
}
},
retire: {
retire: {
options: {
/** list of files to ignore **/
ignorefile: '.retireignore.json' //or '.retireignore.json'
},
js: ['lib/*.js'], /** Which js-files to scan. **/
node: ['./'] /** Which node directories to scan (containing package.json). **/
},
},
clean: ['dist', 'tmp', 'axe.js', 'axe.*.js'],
babel: {
options: {
Expand Down Expand Up @@ -94,15 +94,15 @@ module.exports = function (grunt) {
},
concat: {
engine: {
options: {
process: true
},
coreFiles: [
'tmp/core/index.js',
'tmp/core/*/index.js',
'tmp/core/**/index.js',
'tmp/core/**/*.js'
],
options: {
process: true
},
files: langs.map(function (lang, i) {
return {
src: [
Expand All @@ -112,7 +112,7 @@ module.exports = function (grunt) {
'<%= configure.rules.files[' + i + '].dest.auto %>',
'lib/outro.stub'
],
dest: 'axe' + lang + '.js',
dest: 'axe' + lang + '.js'
};
})
},
Expand Down
12 changes: 10 additions & 2 deletions doc/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,15 @@ This will either be null or an object which is an instance of Error. If you are

#### Results Object

The callback function passed in as the third parameter of `axe.a11yCheck` runs on the results object. This object has two components – a passes array and a violations array. The passes array keeps track of all the passed tests, along with detailed information on each one. This leads to more efficient testing, especially when used in conjunction with manual testing, as the user can easily find out what tests have already been passed. Similarly, the violations array keeps track of all the failed tests, along with detailed information on each one.
The callback function passed in as the third parameter of `axe.run` runs on the results object. This object has four components – a `passes` array, a `violations` array, an `incomplete` array and an `inapplicable` array.

The `passes` array keeps track of all the passed tests, along with detailed information on each one. This leads to more efficient testing, especially when used in conjunction with manual testing, as the user can easily find out what tests have already been passed.

Similarly, the `violations` array keeps track of all the failed tests, along with detailed information on each one.

The `incomplete` array (also referred to as the "review items") indicates which nodes could neither be determined to definitively pass or definitively fail. They are separated out in order that a user interface can display these to the user for manual review (hence the term "review items").

The `inapplicable` array lists all the rules for which no matching elements were found on the page.

###### `url`

Expand All @@ -487,7 +495,7 @@ Each object returned in these arrays have the following properties:
* `helpUrl` - URL that provides more information about the specifics of the violation. Links to a page on the Deque University site.
* `id` - Unique identifier for the rule; [see the list of rules](rule-descriptions.md)
* `impact` - How serious the violation is. Can be one of "minor", "moderate", "serious", or "critical" if the Rule failed or `null` if the check passed
* `tags` - Array of tags that this rule is assigned. These tags can be used in the option structure to select which rules are run ([see `axe.a11yCheck` parameters below for more information](#a11ycheck-parameters)).
* `tags` - Array of tags that this rule is assigned. These tags can be used in the option structure to select which rules are run ([see `axe.run` parameters for more information](#parameters-axerun)).
* `nodes` - Array of all elements the Rule tested
* `html` - Snippet of HTML of the Element
* `impact` - How serious the violation is. Can be one of "minor", "moderate", "serious", or "critical" if the test failed or `null` if the check passed
Expand Down
45 changes: 41 additions & 4 deletions doc/developer-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

aXe runs a series of tests to check for accessibility of content and functionality on a website. A test is made up of a series of Rules which are, themselves, made up of Checks. aXe executes these Rules asynchronously and, when the Rules are finished running, runs a callback function which is passed a Result structure. Since some Rules run on the page level while others do not, tests will also run in one of two ways. If a document is specified, the page level rules will run, otherwise they will not.

1. [Getting Started](#getting-started)
1. [Architecture Overview](#architecture-overview)
1. [Rules](#rules)
1. [Checks](#checks)
1. [Common Functions](#common-functions)
1. [Core Utilities](#core-utilities)
1. [Test Utilities](#test-utilities)
1. [Test Util Name: axe.testUtils.MockCheckContext](#test-util-name-axetestutilsmockcheckcontext)
1. [Test Util Name: axe.testUtils.fixtureSetup](#test-util-name-axetestutilsfixturesetup)

## Getting Started

### Environment Pre-requisites
Expand All @@ -16,9 +26,9 @@ To build axe.js, simply run `grunt build`. axe.js and axe.min.js are placed int

### Running Tests

To run all tests from the command line you can run `grunt test`, which will run all unit and integration tests using PhantomJS.
To run all tests from the command line you can run `grunt test`, which will run all unit and integration tests using PhantomJS and Selenium Webdriver.

You can also load tests in any supported browser, which is helpful for debugging. Tests require a local server to run, you must first start a local server to serve files. You can use Grunt to start one by running `grunt connect watch`. Once your local server is running you can load the following pages in any browser to run tests:
You can also load tests in any supported browser, which is helpful for debugging. Tests require a local server to run, you must first start a local server to serve files. You can use Grunt to start one by running `grunt dev`. Once your local server is running you can load the following pages in any browser to run tests:


1. [Core Tests](../test/core/)
Expand Down Expand Up @@ -78,6 +88,7 @@ Similar to Rules, Checks are defined by JSON files in the [lib/checks directory]
* `messages` - `Object` These messages are displayed when the Check passes or fails
* `pass` - `String` [doT.js](http://olado.github.io/doT/) template string displayed when the Check passes
* `fail` - `String` [doT.js](http://olado.github.io/doT/) template string displayed when the Check fails
* `incomplete` – `String|Object` – [doT.js](http://olado.github.io/doT/) template string displayed when the Check is incomplete OR an object with `missingData` on why it returned incomplete. Refer to [rules.md](./rules.md).

#### Check `evaluate`

Expand Down Expand Up @@ -115,9 +126,20 @@ return results.filter(function (r) {
});
```

#### Pass and Fail Templates
#### Pass, Fail and Incomplete Templates

Occasionally, you may want to add additional information about why a Check passed, failed or returned undefined into its message. For example, the [aria-valid-attr](../lib/checks/aria/valid-attr.json) will add information about any invalid ARIA attributes to its fail message. The message uses the [doT.js](http://olado.github.io/doT/) and is compiled to a JavaScript function at build-time. In the Check message, you have access to the `CheckResult` as `it`.

```javascript
// aria-valid-attr check
"messages": {
"pass": "ARIA attributes are used correctly for the defined role",
"fail": "ARIA attribute{{=it.data && it.data.length > 1 ? 's are' : ' is'}} not allowed:{{~it.data:value}} {{=value}}{{~}}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have an incomplete example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably, although I just took what was on jsdoc/develop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WilcoFiers the previous sentence mentions the rule-development doc, which has thorough instructions for incomplete messages. I'd prefer not to have it in multiple places.

}
```

Occasionally, you may want to add additional information about why a Check passed or failed into its message. For example, the [aria-valid-attr](../lib/checks/aria/valid-attr.json) will add information about any invalid ARIA attributes to its fail message. The message uses the [doT.js](http://olado.github.io/doT/) and is compiled to a JavaScript function at build-time. In the Check message, you have access to the `CheckResult` as `it`.
See [Developing Axe-core Rules](./rule-development.md) for more information
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section made it in twice somehow. Will remove.

on writing rules and checks, including incomplete results.

See [Developing Axe-core Rules](./rule-development.md) for more information
on writing rules and checks, including incomplete results.
Expand All @@ -140,6 +162,21 @@ Common functions are an internal library used by the rules and checks. If you h

Core Utilities are an internal library that provides aXe with functionality used throughout its core processes. Most notably among these are the queue function and the DqElement constructor.

#### ARIA Lookup Tables

axe.commons.aria provides a namespace for ARIA-related utilities, including a lookupTable for attributes and roles.

* `axe.commons.aria.lookupTable.attributes`
* `axe.commons.aria.lookupTable.globalAttributes`
* `axe.commons.aria.lookupTable.role`

#### Common Utility Functions

In addition to the ARIA lookupTable, there are also utility functions on the axe.commons.aria and axe.commons.dom namespaces:

* `axe.commons.aria.implicitRole` - Get the implicit role for a given node
* `axe.commons.aria.label` - Gets the accessible ARIA label text of a given element
* `axe.commons.dom.isVisible` - Determine whether an element is visible

#### Queue Function

Expand Down
3 changes: 2 additions & 1 deletion doc/projects.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ Add your project/integration to this file and submit a pull request.
1. [Vorlon.js Remote Debugger](https://github.com/MicrosoftDX/Vorlonjs)
1. [Selenium IDE aXe Extension](https://github.com/bkardell/selenium-ide-axe)
1. [gulp-axe-webdriver](https://github.com/felixzapata/gulp-axe-webdriver)
1. [AccessLint](https://accesslint.com/)
1. [Lighthouse](https://github.com/GoogleChrome/lighthouse)
1. [Axegrinder](https://github.com/claflamme/axegrinder)
1. [Ghost-Axe](https://www.npmjs.com/package/ghost-axe)
Expand All @@ -30,3 +29,5 @@ Add your project/integration to this file and submit a pull request.
1. [Rocket Validator](https://rocketvalidator.com)
1. [aXe Reports](https://github.com/louis-reed/axe-reports)
1. [aXe-TestCafe](https://github.com/helen-dikareva/axe-testcafe)
1. [Web Audit University of Nebraska-Lincoln](https://webaudit.unl.edu/)
1. [Ace, by DAISY](https://daisy.github.io/ace)
66 changes: 56 additions & 10 deletions doc/rule-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,62 @@ The actual testing of elements in axe-core is done by checks. A rule has one or
| enabled | Does the rule run by default
| tags | Grouping for the rule, such as wcag2a, best-practice
| metadata.description | Description of what a rule does
| metadata.help | Description of how to resolve an issue
| metadata.help | Short description of a violation, used in the aXe extension sidebar

## Check Properties

| Prop. Name | Description
|-----------------|-----------------
| id | Unique identifier for the check
| evaluate | Evaluating function, returning a boolean value
| options | Configurable value for the check
| after | Cleanup function, run after check is done
| metadata impact | "minor", "serious", "critical"
| metadata pass | Describes why the check passed
| metadata fail | Describes why the check failed
| Prop. Name | Description
|--------------------|-----------------
| id | Unique identifier for the check
| evaluate | Evaluating function, returning a boolean value
| options | Configurable value for the check
| after | Cleanup function, run after check is done
| metadata impact | "minor", "serious", "critical"
| metadata pass | Describes why the check passed
| metadata fail | Describes why the check failed
| metadata incomplete| Describes why the check didn’t complete

Incomplete results occur when axe-core can’t produce a clear pass or fail result,
giving users the opportunity to review it manually. Incomplete messages can take
the form of a string, or an object with arbitrary keys matching the data returned
from the check.

A pass message is required, while fail and incomplete are dependent on the check result.

### Incomplete message string

As one example, the audio and video caption checks return an incomplete string:
```
messages: {
pass: 'Why the check passed',
fail: 'Why the check failed',
incomplete: 'Why the check returned undefined'
}
```

### Incomplete message object with missingData

As another example, the color-contrast check returns missingData to aid in
remediation. Here’s the message format:

```
messages: {
pass: 'Why the check passed',
fail: 'Why the check failed',
incomplete: {
bgImage: 'The background color could not be determined due to a background image',
default: 'fallback string'
}
}
```

To wire up an incomplete message with a specific reason it returned undefined,
the check needs matching data. Otherwise, it will fall back to the `default` message.
Reasons are arbitrary for the check (such as 'bgImage') but they must match the
data returned:

```
this.data({
missingData: 'bgImage'
});
```
3 changes: 2 additions & 1 deletion lib/checks/color/color-contrast.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ var data = {
contrastRatio: cr ? truncatedResult : undefined,
fontSize: (fontSize * 72 / 96).toFixed(1) + 'pt',
fontWeight: bold ? 'bold' : 'normal',
missingData: missing
missingData: missing,
expectedContrastRatio: cr.expectedContrastRatio + ':1'
};

this.data(data);
Expand Down
2 changes: 1 addition & 1 deletion lib/checks/color/color-contrast.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"impact": "serious",
"messages": {
"pass": "Element has sufficient color contrast of {{=it.data.contrastRatio}}",
"fail": "Element has insufficient color contrast of {{=it.data.contrastRatio}} (foreground color: {{=it.data.fgColor}}, background color: {{=it.data.bgColor}}, font size: {{=it.data.fontSize}}, font weight: {{=it.data.fontWeight}})",
"fail": "Element has insufficient color contrast of {{=it.data.contrastRatio}} (foreground color: {{=it.data.fgColor}}, background color: {{=it.data.bgColor}}, font size: {{=it.data.fontSize}}, font weight: {{=it.data.fontWeight}}). Expected contrast ratio of {{=it.data.expectedContrastRatio}}",
"incomplete": {
"bgImage": "Element's background color could not be determined due to a background image",
"bgGradient": "Element's background color could not be determined due to a background gradient",
Expand Down
4 changes: 2 additions & 2 deletions lib/checks/color/link-in-text-block.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* global axe*/
var color = axe.commons.color;
const { color } = axe.commons;

function getContrast(color1, color2) {
var c1lum = color1.getRelativeLuminance();
var c2lum = color2.getRelativeLuminance();
return (Math.max(c1lum, c2lum) + 0.05) / (Math.min(c1lum, c2lum) + 0.05);
}

var blockLike = ['block', 'list-item', 'table', 'flex', 'grid', 'inline-block'];
const blockLike = ['block', 'list-item', 'table', 'flex', 'grid', 'inline-block'];
function isBlock(elm) {
var display = window.getComputedStyle(elm).getPropertyValue('display');
return (blockLike.indexOf(display) !== -1 ||
Expand Down
13 changes: 9 additions & 4 deletions lib/checks/forms/fieldset.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,20 @@ function runCheck(element) {
if (matchingNodes.length < 2) {
return true;
}
var fieldset = axe.commons.dom.findUp(element, 'fieldset');
var group = axe.commons.dom.findUp(element, '[role="group"]' + (node.type === 'radio' ? ',[role="radiogroup"]' : ''));
const fieldset = axe.commons.dom.findUp(element, 'fieldset');
const group = axe.commons.dom.findUp(element, '[role="group"]' +
(node.type === 'radio' ? ',[role="radiogroup"]' : ''));

if (!group && !fieldset) {
failureCode = 'no-group';
self.relatedNodes(spliceCurrentNode(matchingNodes, element));
return false;
}
return fieldset ? checkFieldset(fieldset, name) : checkARIAGroup(group, name);

} else if (fieldset) {
return checkFieldset(fieldset, name);
} else {
return checkARIAGroup(group, name);
}
}

var data = {
Expand Down
2 changes: 1 addition & 1 deletion lib/checks/navigation/href-no-hash.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var href = node.getAttribute('href');

if(href === '#'){
if (href === '#') {
return false;
}

Expand Down
Loading