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

@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

Made with Slides.com