-
Notifications
You must be signed in to change notification settings - Fork 146
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
Run aXe on a few pages during CI #344
Conversation
Hmm, so this is a fair bit of code, as the Chrome DevTools Protocol is fairly low-level. There might be a higher-level wrapper available that could reduce the size of our code, though I'm not sure if it'd necessarily meet our particular needs or not. Even axe-core's own PhantomJS wrapper didn't meet all the needs for the a11y-metrics dashboard so I had to write my own. |
} | ||
|
||
module.exports = () => { | ||
return new Promise((resolve, reject) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need a rejection handler somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah good CATCH, will add!
const chromeHost = chrome.host || 'localhost'; | ||
console.log(`Static file server is listening at ${server.url}.`); | ||
console.log(`Chrome is debuggable on http://${chromeHost}:${chrome.port}.`); | ||
console.log(`Running aXe on:`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was there more text that was supposed to go here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
config/run-axe.js
Outdated
console.log(`Running aXe on:`); | ||
|
||
CDP({ | ||
host: chrome.host, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Above, it sounds like chrome.host
may not exist. Should this be chromeHost
? Why wouldn't chrome.host
not exist anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, it will just be undefined
if it doesn't exit, which CDP just then defaults to localhost--but I agree, I think it'd be less confusing / more explicit if we just passed chromeHost
here.
I was hoping that the API for chrome
would set host
to whatever the ultimate "resolved" value was, whether that was localhost
(in the case where Chrome is launched locally) or something explicit (in the case where we connect to a remote Chrome in e.g. a different Docker container). However, that wasn't the case--in the case where Chrome is launched locally, host
isn't set at all, so I had to manually default it to localhost
via that chromeHost
variable. It's a bit annoying because the APIs that connect all these different Chrome packages isn't quite as consistent as I'd hoped, and this is a workaround for that.
} else { | ||
const page = pagesLeft.pop(); | ||
const url = `${server.url}${page}`; | ||
process.stdout.write(` ${page} `); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this doing? Why isn't it a simple console.log
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Page.enable(), | ||
Network.enable(), | ||
]).then(() => { | ||
Network.responseReceived(({response}) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this when any page resource is received? Or just the main HTML document?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it's when any page resource is received. So this effectively overlaps a bit with our crawler from #321. It was easier to do it that way than it was to check the URL and see if it matched the page we were requesting, but I could add such a conditional if you think it'd be better that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems OK to have this extra check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, so I thought about it a bit, and realized that maybe it's actually good that it's counting any sub-resource failure as a 404 too. For example, if it's 404'ing on CSS or JS, then that changes the accessibility profile of the page--calculated color contrast ratios may be incorrect, or certain ARIA attributes may not be present on the evaluated page.
Another thing is that the crawler from #321 isn't actually 100% accurate--the library we're using uses regular expressions to "scrape" resources for URLs, so it's actually possible that it might miss sub-resources that are noticed by actually loading a page in Chrome. So it might still be good to hard fail on sub-resource failures for the sake of redundancy, too.
What do you think? At the very least, I think we should log warnings on sub-resource fails.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea I agree that it's good to consider sub-resource 404s as failures.
config/run-axe.js
Outdated
}); | ||
Page.loadEventFired(() => { | ||
Runtime.evaluate({ | ||
expression: AXE_JS + ';(' + runAxe.toString() + ')()', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this possible to write using a template string so it's easier to parse?
config/run-axe.js
Outdated
errorFound = true; | ||
} | ||
} else { | ||
console.log('Unexpected result from CDP!'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's CDP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, it stands for Chrome DevTools Protocol... I'll expand it to just say that!
Ok, I think I addressed all your issues, though I had second thoughts about ignoring sub-resource loading failures, which I commented on above. |
Hooray, thanks! 💃 |
Fixes #326.
This runs axe-core on a few pages of the standards during CI and
npm test
runs. In future PRs we can add support for running it on more pages.A successful run looks something like this:
It requires that Chrome/Chromium v59 or higher be installed on the host system. I decided on headless Chrome because:
chrome-launcher
ensures that it will be found, regardless of host OS.To do:
docker-uswds
can run this too.crawl.js
to usestatic-server.js
to prevent duplication of code.