-
-
Save jtomaszewski/c3e033c1672908b0b2de703a0a1fe340 to your computer and use it in GitHub Desktop.
aXe based a11y checks in your CI for Storybook
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
/* eslint-disable no-await-in-loop */ | |
/* eslint-disable no-restricted-syntax */ | |
// eslint-disable-next-line import/no-extraneous-dependencies | |
const puppeteer = require('puppeteer'); | |
const { green, red, cyan, grey, bold } = require('chalk'); | |
const url = 'http://localhost:9001/iframe.html'; | |
function runAxe() { | |
return new Promise((resolve, reject) => | |
// eslint-disable-next-line no-undef | |
axe.run('#root', { runOnly: ['wcag2a'] }, (error, result) => | |
error ? reject(error) : resolve(result), | |
), | |
); | |
} | |
/* eslint-disable no-underscore-dangle,no-undef */ | |
function getExamples() { | |
const storyStore = __STORYBOOK_CLIENT_API__._storyStore; | |
const result = []; | |
for (const story of __STORYBOOK_CLIENT_API__.getStorybook()) { | |
const { kind } = story; | |
for (const example of story.stories) { | |
const { name } = example; | |
let enabled = true; | |
if (storyStore.getStoryAndParameters) { | |
const { parameters } = storyStore.getStoryAndParameters( | |
story.kind, | |
name, | |
); | |
// To disable axe tests for the given story, | |
// Use `.addParameters({ axe: { enabled: false } })` | |
if ( | |
parameters && | |
parameters.axe && | |
parameters.axe.enabled !== undefined && | |
!parameters.axe.enabled | |
) { | |
enabled = false; | |
} | |
} | |
if (enabled) { | |
result.push({ | |
kind, | |
name, | |
}); | |
} | |
} | |
} | |
return result; | |
} | |
/* eslint-enable no-underscore-dangle,no-undef */ | |
puppeteer.launch().then(async browser => { | |
const page = await browser.newPage(); | |
await page.goto(url); | |
const stories = await page.evaluate(getExamples); | |
const errors = []; | |
for (const { kind, name } of stories) { | |
const storyUrl = `${url}?${`selectedKind=${encodeURIComponent( | |
kind, | |
)}`}&${`selectedStory=${encodeURIComponent(name)}`}`; | |
console.log(`Running ${kind}/${name} ...`); | |
await page.goto(storyUrl); | |
const { violations } = await page.evaluate(runAxe); | |
if (violations.length) { | |
errors.push({ kind, name, violations }); | |
} | |
} | |
await browser.close(); | |
if (errors.length) { | |
errors.forEach(({ kind, name, violations }) => { | |
console.error(bold(`Error(s) in ${red(`${kind}/${name}`)}:`)); | |
violations.forEach(({ description, nodes }) => { | |
console.error(`${description} (${grey(`${nodes.length} times`)})`); | |
}); | |
console.error(''); | |
}); | |
const sum = errors.reduce((acc, error) => acc + error.violations.length, 0); | |
console.error(`${red('✖')} Found ${red(sum)} error(s)!\n`); | |
console.error( | |
`Open ${cyan( | |
'http://localhost:9001', | |
)} and visit the mentioned stories to find out more about where the problems happen and how they can be fixed.\n`, | |
); | |
process.exitCode = 1; | |
} else { | |
console.log(`${green('✔')} Everything is WCAG2A compatible!`); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment