Uncharted Territory
Using aXe to Forge a Path
Madalyn Parker
@madalynrose
Madalyn Parker
Frontend Developer
Mental Health Advocate
Web a11y
Disclaimer: NOT an expert
Coffee drinker
Rabbit owner
@madalynrose




Why Web Accessibility?
@madalynrose
Laws
Statistics
$$$
Code Quality
@madalynrose
Laws
Statistics
$$$
Code Quality
Everyone should be able to use the web
@madalynrose
<
What is Web Accessibility About?
@madalynrose
Before
- Meeting Standards (WCAG 2.0)
- dichotomy: either it's compliant or it isn't
- aria attributes
- Tab indexes
- Working with every screen reader/OS/browser
@madalynrose
Okay where do I start?
@madalynrose

Take Stock
- What is a reasonable scope given my resources?
- What isn't accessible about my app?
- What technologies am I using?
- What tools can best supplement my resources?
@madalynrose
Scoping
Which part of your application do you start with?
Start Small
What could benefit the most?
What has the furthest reach?
@madalynrose
Problem Areas
Where are the accessibility gaps?
@madalynrose


@madalynrose


What does the user need?
-
They need to know the chat box is there. -
They need to know whether a person is available to chat or not. -
They need to see the call to action text.
-
They need to know which messages in the chat belong to whom. -
They need to know when messages come in and what they say. -
They need to be able to end the chat.
-
They need to be able to request a transcript of the chat.
-
They need to be able to leave feedback about their chat. -
They need to be able to upload files. They need to know if there are errors and what those errors are.
@madalynrose
Accessibility Gaps
- Navigation
- Live areas
- JS hidden elements
- Superfluous elements
@madalynrose
Resources
- me
- 1 month
- browser audit tools
- consultants
- web a11y community
- node modules
- axe-core
- react-a11y
@madalynrose
@madalynrose

Deque Systems
Game Plan
- Get axe-core working with testing stack
- Run test audits on all frontend components
- Address audit results
- Manual testing
- Address results
@madalynrose
Why Tests?
- Find low hanging fruit easily
- Make repeatable steps baked in
- Make accessibility easy to implement
@madalynrose
Desired Testing Workflow
assert = require('assert')
React = require('react')
{ shallow } = require('enzyme')
ImageComponent = require('../src/myProject/components/ImageComponent.cjsx')
/*
ImageComponent = ({ url, altText }) ->
<img src={url} alt={altText} />
*/
describe '<ImageComponent />', =>
it 'should have no accessibility errors', ->
url = 'https://mywebsite.com/some/path/to/an/image.jpg'
wrapper = shallow(<ImageComponent url={url} altText="my awesome picture"/>)
//assert passes axe-core audit
@madalynrose
Testing Constraints
- sandboxing tests
- using axe-core with CoffeeScript, mocha, enzyme
- traversing callback hell
@madalynrose
Fresh DOM
jsdom = require('jsdom').jsdom
module.exports = class DOMContext
constructor: ->
@document = jsdom('')
getDocument: ->
return @document
getWindow: ->
return @document.defaultView
destroy: ->
@getWindow().close()
@madalynrose

Cleaning Up
cleanUpA11yMount: (div, dom) =>
dom.getDocument().body.removeChild(div)
dom.destroy()
@madalynrose

a11yHelper audit
runAudit: (node, config) =>
oldNode = global.Node
global.Node = node.ownerDocument.defaultView.Node
return new Promise((resolve, reject) =>
axeCore.run(node, config, (err, results) =>
global.Node = oldNode
if err
reject(err)
else
try
assert.equal AxeCoreResults.hasViolations(results), false
assert.equal AxeCoreResults.getViolationsList(results).length, 0
resolve()
catch e
reject(e)
)
)
@madalynrose
a11yHelper components
mountForA11yTest: (component) =>
dom = new DOMContext()
doc = dom.getDocument()
div = doc.createElement('div')
doc.body.appendChild(div)
wrapper = mount(component, { attachTo: div })
return { wrapper: wrapper, div: div, dom: dom }
testRawComponent: (component) =>
mounted = @mountForA11yTest(component)
return @testMountedComponent(mounted.wrapper)
.then(() =>
@cleanUpA11yMount(mounted.div, mounted.dom)
)
testMountedComponent: (wrapper) =>
node = findDOMNode(wrapper.component)
return @runAudit(node, {})
@madalynrose
Testing Flow
/*
ImageComponent = ({ url, altText }) ->
<img src={url} alt={altText} />
*/
describe '<ImageComponent />', =>
it 'should have no accessibility errors', ->
url = 'https://mywebsite.com/some/path/to/an/image.jpg'
//return passesA11yTest(<ImageComponent url={url} altText={""}/>
@madalynrose
Success!
tests caught a lot of surface-level problems
@madalynrose
The Big Stuff
@madalynrose
Pruning
What can go?

@madalynrose
Navigation
making linear manageable
@madalynrose
The Announcer
@madalynrose
The Power of Live Regions
- announce dynamic changes to an element
- incredibly customizable:
- control how polite it should be with aria-live attribute
- assertive, polite, off
- control whether it should present the region as a whole or only announce changes with aria-atomic
- select which types of changes to the element should be announced
- additions, removals, text, all
- specify what type of region it is
- alert, log, marquee
- control how polite it should be with aria-live attribute
@madalynrose
Olark's Announcer
- aria-live=assertive
- role=alert
- control region changes in state based on chat box focus
- our chat box is pretty assertive so it makes sense to provide an equivalent experience

@madalynrose
Olark's Announcer
control region changes in state based on chat box focus
if(chat box is focused)
add event to list of announcements
join list of announcements with periods
dump list of announcements into announcer
else
# chat box will already play a notification
# sound if it is not focused
add event to list of announcements
@madalynrose


I Learned Things!
@madalynrose
@madalynrose
After
- Usability
- Establishing and Sticking to patterns
- Equivalent experiences
- Starting somewhere
Before
- Meeting Standards (WCAG 2.0)
- dichotomy: either it's compliant or it isn't
- aria attributes
- Tab indexes
- Working with every screen reader/OS/browser
Resources
Copy of Uncharted Territory
By Madalyn Parker
Copy of Uncharted Territory
- 596