Automated Accessibility Testing with Rspec

At MAPC we have been thinking more about making our web applications accessible to all our users. Unfortunately standard web frameworks and tools do not bake this functionality in. Accessibility is its own specialization with code and nuances that software developers have to learn on top of everything else they do. The good news is that as this issue has become more prominent tools are emerging to make it easier to automate making your application accessible. One tool I started experimenting with is the axe-matchers gem from Deque.

In order to use this tool you should add gem axe-matchers to your test group in your Gemfile, then require 'axe/rspec' in spec_helper.rb. After that it is as simple as adding a test to your Rspec test suite:

  it "is accessible", js: true do
    create(:page)
    visit "/"
    expect(page).to be_accessible
  end

There are methods to get granular with different parts of your pages if you want to break it up. The nice thing is that axe-matchers provides specific actionable feedback with links that explain the rationale for the rules. Example output is below:

3) link-name: Links must have discernible text (serious)
   https://dequeuniversity.com/rules/axe/3.1/link-name?application=axeAPI
   The following 3 nodes violate this rule:

       Selector: .footer-right > a:nth-child(1)
       HTML: <a href="https://twitter.com/mapcmetroboston"><i class="fa fa-twitter"></i></a>
       Fix all of the following:
       - Element is in tab order and does not have accessible text
       Fix any of the following:
       - Element does not have text that is visible to screen readers
       - aria-label attribute does not exist or is empty
       - aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty
       - Element's default semantics were not overridden with role="presentation"
       - Element's default semantics were not overridden with role="none"

       Selector: .footer-right > a:nth-child(2)
       HTML: <a href="https://www.instagram.com/mapcmetroboston"><i class="fa fa-instagram"></i></a>
       Fix all of the following:
       - Element is in tab order and does not have accessible text
       Fix any of the following:
       - Element does not have text that is visible to screen readers
       - aria-label attribute does not exist or is empty
       - aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty
       - Element's default semantics were not overridden with role="presentation"
       - Element's default semantics were not overridden with role="none"

       Selector: a:nth-child(3)
       HTML: <a href="https://www.facebook.com/mapcmetroboston"><i class="fa fa-facebook"></i></a>
       Fix all of the following:
       - Element is in tab order and does not have accessible text
       Fix any of the following:
       - Element does not have text that is visible to screen readers
       - aria-label attribute does not exist or is empty
       - aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty
       - Element's default semantics were not overridden with role="presentation"
       - Element's default semantics were not overridden with role="none

As a developer using an automated test that provides specific feedback and suggested remedies makes implementing accessibility best practices much easier. Given how easy this was to implement, trying this out is an easy win for any Rails developer.

Growing Code for Boston

This week is looking to be the highest number of RSVPs we’ve ever had at Code for Boston. Instead of the usual 30–40 people we are going to have over seventy people attend our Meetup. This trend started a few weeks ago and I have raised our Meetup cap to compensate for the increased interest. Despite this, we still have a waitlist. After a year of steady attendance it looks like we may quickly hit a new level of participation.

I am not sure why we are growing but I am hopeful that this growth is not accidental. Over the past year we have made a few changes to attempt to improve projects and new member experiences. We made a video to show new members what Code for Boston is like. We changed orientation to have project liaisons pitch their projects at the end of it. We also have refined our project intake process to better find fit for new projects and prepare project proposers to engage the community. This includes sending out an email with information on a project and a Google Form so members that have not attended can express interest.

The thing I like most is that this growth is a reward. It validates the time I spend on Code for Boston and shows people find it to be a worthwhile activity. It also enables us to have a bigger impact. The more people and projects we have, the more good we can do for the greater Boston community, and I think that is amazing.

Building a Legislative Bill Tracking Site

A year ago I started work on bills.ctnewsjunkie.com, a place where people can express their opinions on bills before the Connecticut General Assembly. The nice thing about bills.ctnewsjunkie.com is its pretty simple. All you need to do is vote up or down a bill depending on if you like it. Then we display those votes so readers know how popular a bill before the Connecticut General Assembly is with the rest of readership.

The surprising thing is how well this has taken off. Last year we launched the site and it was not popular. We did not see a lot of voting. This year the participation in voting has been explosive. We are seeing lots of traffic to the site and more votes than we ever imagined being cast to show support or opposition to bills. It is exciting because it shows people do care about issues at the state level and want to share their opinions on them.

RSpec, Capybara and Headless Chrome

I spent yesterday getting headless Chrome working with RSpec and Capybara on one our projects at MAPC. The reason for doing this is many of our website visitors use the chrome browser, and the new headless version of Chrome allows us to run an automated test suite on our application that uses it in a way our users do. Writing these automated tests that focus on features, called system tests in Rails, can increase our confidence that we are not breaking our application with new code.

The first step to testing with headless chrome is installing the appropriate gems. You will need to install the following in order to make headless chrome work well with your Ruby on Rails application:

gem "puma"
group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15', '< 4.0'
  gem 'selenium-webdriver'
  gem 'capybara-screenshot'
end

You will need to replace unicorn with puma in your local environment if you want screenshots to work well. The capybara-screenshot gem is one I use to automatically take screenshots of failing tests. On macOS you will also need to install chromedriver using homebrew. I added this simple script to my bin/setup to automatically do this for developers that run setup on a macOS machine:

if RUBY_PLATFORM =~ /darwin/
  unless system('brew cask ls --versions chromedriver')
	system('brew cask install chromedriver')
  end
else
  puts 'You will need to install Chromedriver before using the automated test suite.'
end

I then proceeded to update my RSpec configuration first by including the following line in spec/rails_helper.rb:

require 'support/chromedriver'

Then spec/spec_helper.rb should include:

require 'capybara/rspec'

The difference between spec_helper.rb and rails_helper.rb is that spec_helper.rb is for requirements that involve testing anything, and rails_helper.rb are for requirements and configuration that are specific to tests that interact with Ruby on Rails.

Finally just add spec/support/chromedriver.rb

require 'selenium/webdriver'
require 'capybara-screenshot/rspec'
Capybara.javascript_driver = :selenium_chrome_headless

Capybara::Screenshot.register_driver(:selenium_chrome_headless) do |driver, path|
  driver.browser.save_screenshot(path)
end

At this point you should be ready to run RSpec system tests with Capybara. One gotcha with system tests (as opposed to typical RSpec feature tests) is they override the default Capybara driver. While this is documented in some places, this drove me bonkers. Eventually I fixed this by adding:

RSpec.configure do |config|
	config.before(:each, type: :system) do
		driven_by(:rack_test)
	end
	
	config.before(:each, type: :system, js: true) do
		driven_by(:selenium_chrome_headless)
	end
end

to my spec/rails_helper.rb file. As long as I do not use the Capybara keywords for feature tests, and mark my tests appropriately as system tests, they will now run using rack_test (for non-Javascript tests) and headless Chrome for javascript tests denoted with js: true.

Credit where credit is due, much of the original instruction I got was from this post on Thoughtbot’s blog. However there were a few gotchas around system tests and some updates to configuration I discovered yesterday that I thought merited re-hashing this subject for future readers.

Starting 2019 with Arduino

I began 2019 by taking a hiatus from the blog to focus on some New Years resolutions. One of them was to finally start learning how to use the Arduino system that I received for Christmas. What is Arduino? It is an electronics prototype platform. You can buy small parts and combine them to form your own gadgets. In many ways it is a more complex version of Legos. It is interesting, rewarding, and also quite challenging.

The first challenge with Arduino is the number of things you can do with it are infinite. Whenever I start with a new thing the first thing I do is try an example tutorial or program to have a goal to aim for while I surmount the inevitable obstacles along the way. For Arduino I chose to try and build a temperature logging sensor.

The second challenge with Arduino is you can have problems in both hardware and software. If you run a program and it fails, the issue could be with how the software is written but it could also be with how your hardware is constructed or how you tell your program your hardware is constructed. For example I switched temperature sensors to get more accurate readings and when it failed I learned the new module had the data and power pins in different spots. The specific module I had did not have its own documentation, so I had to learn this through empirical analysis.

The biggest challenge with Arduino is that its behavior can be erratic or random. I had been trying to use an SD card shield to log my temperature and was telling it to use pin 10 to read and write from my SD card. I later learned my board had the SD Card read and write on pin 9, but for some reason pin 10 worked intermittently. This lead me to believe 10 was the correct pin (along with online documentation suggesting pin 10 was the usual one).

Despite these challenges it has been enjoyable learning about the world of hardware and what is possible with inexpensive components. Arduino lets you rapidly prototype hardware and then acquire components to inexpensively produce a small number of what you have prototyped. I just wonder how I can use these devices to improve civic life. Let me know if you have ideas, we might use them in the upcoming Code for Boston Hackathon in April.

This work by Matt Zagaja is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.