Skip to content

Commit

Permalink
Add pa11y scanner
Browse files Browse the repository at this point in the history
Previously, we did accessibility scanning for every file in every
push / build / PR, which took > 25 mins each run.

Now, we more carefully curate the files that need to be scanned, to
limit the scan time.

This commit:

- Adds `npm run pa11y:list-files` command which runs a site build and
  outputs the files to be scanned for the current changeset
- Adds a per-page pa11y scan, which lists pages that have changed or
  whose layouts have changed
- Adds a site-wide pa11y scan: if files that affect the whole site
  change, take a sample of files from across the site to check
- Incidentally deletes an unused layout
- Moves _plugins/ to lib/ and ignores lib/ in the 11ty build
- Pins the glob package to 8, because 9 and higher breaks something
  with the SVG Sprite package

The code reads a little weird, and one more refactor could help.
  • Loading branch information
beechnut committed Jun 19, 2024
1 parent cd682b7 commit 7f5c57d
Show file tree
Hide file tree
Showing 13 changed files with 514 additions and 417 deletions.
3 changes: 3 additions & 0 deletions .eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const { postsCollection, servicesCollection, tagsCollection } = require('./confi
const { headingLinks } = require('./config/headingLinks');
const { contrastRatio, humanReadableContrastRatio } = require('./config/wcagColorContrast');
const privateLinks = require ('./config/privateLinksList');
const { pa11yScan } = require('./lib/pa11y')

const { imageShortcode, imageWithClassShortcode } = require('./config');

Expand Down Expand Up @@ -321,6 +322,8 @@ module.exports = function (config) { /* eslint-disable-line func-names */
ghostMode: false,
});

config.on('eleventy.after', pa11yScan);

// Set image shortcodes
config.addLiquidShortcode('image', imageShortcode);
config.addLiquidShortcode('image_with_class', imageWithClassShortcode);
Expand Down
1 change: 1 addition & 0 deletions .eleventyignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ README.md
config
docs
spec
lib
24 changes: 0 additions & 24 deletions _includes/layouts/wide.html

This file was deleted.

185 changes: 0 additions & 185 deletions _plugins/pa11y.rb

This file was deleted.

11 changes: 11 additions & 0 deletions lib/commit_differ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { Differ } = require('./differ');

// Lists files that were modified in the last commit
// Used for CI pa11y checks, to check the last commit
class CommitDiffer extends Differ {
command = 'git diff-tree --no-commit-id --name-only -r $(git rev-parse HEAD)';
}

module.exports = {
CommitDiffer,
}
File renamed without changes.
16 changes: 16 additions & 0 deletions lib/differ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const {execSync} = require('child_process');

// Lists files that have been modified since the last commit
// Used in local development, to check accessibility prior to
// committing changes
class Differ {
command = 'git ls-files --modified';

changedFiles() {
return String(execSync(this.command)).split(/\n/).filter(x => x !== '')
}
}

module.exports = {
Differ,
}
47 changes: 47 additions & 0 deletions lib/document.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const {execSync} = require('child_process');

// Takes an 11ty "result" (a post or page), the dir (folder/config),
// and a list of changed files from the appropriate differ class.
//
// A Document knows whether or not it's in the list of changed files,
// and Document#shouldScan returns true if it should be included in
// the next pa11y check.
class Document {
constructor(result, dir, changedFiles) {
this.result = result;
this.dir = dir;
this.layout = this.layoutName();
this.changedFiles = changedFiles;
}

shouldScan() {
return this.didSourceChange() || this.didLayoutChange()
}

// Returns whether the input (source) file was modified
// The slice(2) is to remove the "./" at the beginning of the path
didSourceChange() {
return this.changedFiles.includes(this.result.inputPath.slice(2))
}

// Returns whether this file's layout changed
didLayoutChange() {
return this.changedFiles.includes(`${this.dir.layouts}${this.layout}`)
}

// Gets the name of the layout for this file. If there's no layout,
// assume it uses the "default" layout.
// @todo Change this from system `grep` to parsing the YAML frontmatter
// @todo Assuming the "default" may not be a safe assumption
//
layoutName() {
let maybeMatch;
const layoutMatcher = `grep -i "^\s*layout: " "${this.result.inputPath}"` /* eslint-disable-line no-useless-escape */
try { maybeMatch = execSync(layoutMatcher) } catch { return 'default' }
return String(maybeMatch).trim().split(/layout: /)[1]
}
}

module.exports = {
Document,
}
File renamed without changes.
Loading

0 comments on commit 7f5c57d

Please sign in to comment.