18F/node-continua11y-acceptance

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# node-continua11y-acceptance

[![Build Status](https://travis-ci.org/18F/node-continua11y-acceptance.svg?branch=master)](https://travis-ci.org/18F/node-continua11y-acceptance) [![Test Coverage](https://codeclimate.com/github/18F/node-continua11y-acceptance/badges/coverage.svg)](https://codeclimate.com/github/18F/node-continua11y-acceptance/coverage) [![Code Climate](https://codeclimate.com/github/18F/node-continua11y-acceptance/badges/gpa.svg)](https://codeclimate.com/github/18F/node-continua11y-acceptance)

Accessibility is important. Mobile first development is also important.
This is an acceptance test framework designed to make it easy to test
accessibility as part of your build process. It also makes it easy to
test in a variety of sizes.

Under the covers, this package is using the great [pa11y
library](https://githubs.com/pa11y/pa11y). Configuration from this
framework is passed down to pa11y.

## Usage

This tool is meant to be used programmatically and has assertions via
`assert` built in. These are acceptance and not unit tests, and the
tests run against a node http server.

With `express` the server is returned from the call to listen:

    let server = app.listen(3344, () => { /* a great place for test setup!*/ });

This is just a vanilla server generated by node's `http` module with the
function `createServer`.

Using it with the `continua11y-acceptance` module aims to be as easy as
possible.

Here is an example that uses the mocha framework to take advantage of
before and after blocks:

    let accessibilityTest;
    let config = { /* */ }

    before((done) => {
      server = app.listen(3344, () => {
        accessibilityTest = contintua11yAcceptance(config).test(server);
        done();
      });
    });

    it('should have no accessibility errors', (done) => {
      accessibilityTest.run('/my-great-path', (err, results) {
        if (err) { return done(err); }

        results.assertNoErrors(); // raises an assertion error, like assert
      });
    });

Test callbacks have the arguments:

*`err`: any error that happened during the page examination process.
*`results`: a [Result object](https://github.com/18F/node-continua11y-acceptance/blob/master/lib/results.js) with both data and built in assertions.

### Configuration

All the configuration options available in
[pa11y](https://github.com/pa11y/pa11y#configuration) are passed down.
In addition, there are easy size configurations for testing
accessibility in mobile, tablet, desktop or other custom viewports:

    let accessibility = contintua11yAcceptance({
      sizes: {
        mobile: {width: 320, height: 480},
        mobileLandscape: {width: 480, height: 320}
      }
    });

    let test = accessibility.test(server, 'mobileLandscape');

    test.run('/my-great-page', (err, results) => {
      // assertions
    });

### Assertions

The `results` object passed into an accessibility test comes with
assertions, built in. Under the cover these use the `assert` module to
raise an assertion error.

* `assertNoErrors`: raises an `assert.AssertionError` if the number of
errors is not zero.
* `assertErrorsLessThan`: raises an `assert.AssertionError` if the number of
errors is greater than, or equal to the number passed in as an argument.
* `assertWarningsLessThan`: raises an `assert.AssertionError` if the number of
warnings is greater than, or equal to the number passed in as an argument.
* `assertNoticesLessThan`: raises an `assert.AssertionError` if the number of
notices is greater than, or equal to the number passed in as an argument.

#### Need more flexibility with assertions?

The `results` object passed into the test callback comes with the
underlying data, available as a series of methods.

* `errors`
* `warnings`
* `notices`

Each packs a data format that comes from pa11y's json format and has the
keys:

* `code`: the identifier for the underlying accessibility issue
* `context`: a snippet of html code where the issue occured
* `message`: a description of the accessibility issues
* `selector`: a CSS selector for the element causing problems
* `type`: either 'error', 'notice', or 'warning'
* `typeCode`: ??, if you know, please make a pull request!

Here is an example data for a missing/empty title tag.

    {
      code: 'WCAG2AA.Principle2.Guideline2_4.2_4_2.H25.1.NoTitleEl',
      context: '<head>\n    <meta charset="utf-8">\n\n  ...</head>',
      message: 'A title should be provided for the document, using a non-empty title element in the head section.',
      selector: 'html > head',
      type: 'error',
      typeCode: 1
    }

### Reporting

The library by default writes reports about each url in each size that
it runs to `/accessibility`. Reporting can be turned off in
configration.

You will likely want to update your `.gitignore` to ignore accessibility
reports. These are effemeral artifacts that should not be
part of the repository.

You can turn off configuration via options that include this:
    {
      report: false
    }

To send the report to an alternate directory use this configuration:

    {
      report: '/my-special/directory'
    }

Environmental valiables can be used to override whether reporting
happens:

    CONTINUA11Y_REPORTING=false
    # or
    CONTINUA11Y_REPORTING=true

The main purpose of this flag is to reduce test time in local
development environments. Therefore, directory specifications
are only available via json configuration.

It makes sense to clear the report directory before generating new
reports via acceptance tests. The object returned from configuring the
library has a method `clearReport`, that will destroy the report
directory. You will want to hook this into the beginning of your test
run in some way:

    let accessibilityAcceptance = require('continua11y-acceptance')(config);
    accessibilityAcceptance.clearReport((err) => {
      if (err) { throw err; }
      // do something now that test setup is finished
    });

Currently reporting is only available as json, one file per path and
size. The goal of reporting is to allow CI processes to aggregate this
data and send it to a reporting dashboard.

## Contributing

See [CONTRIBUTING](CONTRIBUTING.md) for additional information.

## Public domain

This project is in the worldwide [public domain](LICENSE.md). As stated in [CONTRIBUTING](CONTRIBUTING.md):

> This project is in the public domain within the United States, and copyright and related rights in the work worldwide are waived through the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/).
>
> All contributions to this project will be released under the CC0 dedication. By submitting a pull request, you are agreeing to comply with this waiver of copyright interest.