Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

  • Blog Navigation
Testing accessibility with RSpec and Capybara

Edit 04/07/13: See the followup article for an alternative to using skip navigation links.

An exploration in automated accessibility testing

Today Grant Hutchins and I took on several stories to enhance the accessibility of a site. One of them was to add a skip-navigation link to the application.

To understand why skip-nav links are important, visit Jim Thatcher’s explanation.

Our immediate inclination was to write a request spec with Capybara to drive out the solution. We came up with the following.

The Test

require "spec_helper"

feature "Keyboard Navigation" do
  scenario "hidden skip navigation link shows when focused and jumps to content", js: true do
    visit root_path

    skip_link = page.find("#skip-navigation a")
    skip_link.should have_content "Skip navigation"
    skip_link.native.location.y.should be < 0

    body_element = page.find("body")
    skip_link.native.location.y.should == 0

    skip_link.native.location.y.should be < 0

    current_url.should match(/#content$/)

The Markup

    %p= link_to "Skip navigation", "#content", tabindex: 0

The Styles

body {
  #skip-navigation {
    a, a:hover, a:visited {

    a:active, a:focus {

What’s happening here?

We are asserting that the “hidden skip navigation link shows when focused and jumps to content” when clicked.

The most important aspect of what we did was emulating keyboard navigation. We’re using js: true so we have access to Selenium’s native methods and thus the send_keys method. This allows us to send keypress messages to the browser.

Since we’ve used positioning to hide the element, we also have an assertion around that property.

Problems in CI!

The application behaved as expected and the tests passed locally.

When we ran the tests in CI however, the tests failed. The reason is that _the browser must retain foremost focus in the OS in order for the :focus css pseudo-selector to fire on the skip-nav element. Without the :focus style rules applied, the skip-nav element remained invisible, and the tests failed.

We tried a workaround using within_window and forcing browser focus, but couldn’t get it to work. We’ve got a few more tricks up our sleeve that we’re going to try, and will report back here.

We added within_window to the test to force focus on the browser. This makes the test less brittle locally (because it won’t fail if you click out of the window).

window = page.driver.browser.window_handles.last
page.within_window(window) do
  skip_link.native.location.y.should == 0
Share This