From Code to Compliance: Accessibility Testing in Rails Applications

From Code to Compliance: Accessibility Testing in Rails Applications

In a previous blog post, How Do You Know When Your App is Not Compliant? opens a new window , I briefly discussed the importance of the accessibility standards of Web Content Accessibility Guidelines or WCAG opens a new window , to ensure that everyone, including those with disabilities, can use web applications effectively. In this blog, we are going to further explore the importance of maintaining accessibility compliance, what it means to users, as well as how to use the axe-core-gems opens a new window for automated accessibility testing to help identify and resolve any gaps that may be currently present in a project.

Accessibility Compliance

The WCAG is a set of recommendations that act as a guideline to help make software more accessible and address the needs of users with ranging disabilities.

Following these guidelines will make content more accessible to a wider range of people with disabilities, including accommodations for blindness and low vision, deafness and hearing loss, limited movement, speech disabilities, photosensitivity, and combinations of these, and some accommodation for learning disabilities and cognitive limitations; but will not address every user need for people with these disabilities.

 

Web Content Accessibility Guidelines (WCAG) 2.1 opens a new window

The foundation and success criteria for accessibility compliance is defined by a set of 4 principles opens a new window

  • Perceivable: This is to ensure that all information as well as user interface components are sensitive and visible to all of the end users senses.
  • Operable: This means that all parts of the web content and application are easily operable and address the different needs of their users while interacting with the web application.
  • Understandable: The goal here is to make sure that websites operate and share information in ways that users are able to understand and navigate efficiently.
  • Robust: It is important to make sure that content creation is robust enough to be interpreted in a reliable way by a wide variety of user agents, including assistive technologies.

So why is accessibility compliance important?

  1. There are now legal requirements and standards, for example, the Americans with Disabilities Act (ADA) opens a new window in the U.S., that aims to help protect people with disabilities from discrimination and mandate accessibility for digital content.
  2. Being compliant with the accessibility guidelines means that your web content is more inclusive while promoting a positive user experience and can help your website reach a larger audience.

Axe-core-gems

axe-core is an open-source project by Deque Systems that can help provide checks for web accessibility violations currently present in a project, and help any team identify areas that should be addressed to ensure that the application is compliant with standards such as WCAG.

The project repository contains 6 gems:

Getting Started

To get started, determine and configure a webdriver the application will use along with a test framework and choose the 2 respective gems listed above.

For our FastRuby.io application, we use both RSpec and Capybara.

The following gems will be added to the Gemfile:

# Gemfile
group :test do
  gem 'axe-core-rspec'
  gem 'axe-core-capybara'
end

Run bundle to install the gems.

Add the following library to the rails_helper or spec_helper file:

# rails_helper.rb
require 'axe-rspec'

This will extend RSpec with the custom matcher BeAxeClean.

To test this out, I added a new feature test for our home page that will use the be_axe_clean matcher with the goal to test that our home page is accessible and identify any current violations:

# spec/features/home_page_spec.rb
require "rails_helper"

RSpec.describe "HomePage", js: true do
  context "when accessing home page" do
    it 'has no accessibility violations' do
      visit "/"

      expect(page).to be_axe_clean
    end
  end
end

Running the test produces the following output:

Failures:

  1) HomePage when accessing home page has no accessibility violations
     Failure/Error: expect(page).to be_axe_clean

       Found 4 accessibility violations:

       1) aria-prohibited-attr: Elements must only use permitted ARIA attributes (serious)
           https://dequeuniversity.com/rules/axe/4.9/aria-prohibited-attr?application=axeAPI
           The following 1 node violate this rule:

               Selector: #map
               HTML: <picture id="map" aria-label="Map of our office in Philadelphia (by Google Maps)">
               Fix all of the following:
               - aria-label attribute cannot be used on a picture with no valid role attribute.

       2) color-contrast: Elements must meet minimum color contrast ratio thresholds (serious)
           https://dequeuniversity.com/rules/axe/4.9/color-contrast?application=axeAPI
           The following 4 nodes violate this rule:

               Selector: .scrollto[href$="#contactus"][role="button"]
               HTML: <a role="button" class="btn scrollto" href="#contactus">We should talk!</a>
               Fix any of the following:
               - Element has insufficient color contrast of 1.92 (foreground color: #f8f8f8, background color: #00d242, font size: 12.0pt (16px), font weight: bold). Expected contrast ratio of 4.5:1

               Selector: .submit
               HTML: <input type="submit" name="commit" value="SEND MESSAGE" class="btn submit" data-disable-with="SEND MESSAGE">
               Fix any of the following:
               - Element has insufficient color contrast of 1.92 (foreground color: #f8f8f8, background color: #00d242, font size: 12.0pt (16px), font weight: bold). Expected contrast ratio of 4.5:1

               Selector: a[href="https://g.page/OmbuLabs?share"]
               HTML: <a href="https://g.page/OmbuLabs?share" target="_blank" class="btn">Get directions</a>
               Fix any of the following:
               - Element has insufficient color contrast of 1.92 (foreground color: #f8f8f8, background color: #00d242, font size: 12.0pt (16px), font weight: normal). Expected contrast ratio of 4.5:1

               Selector: .btn-newsletter
               HTML: <a class="btn btn-newsletter" href="/newsletter#newsletter-form">Newsletter</a>
               Fix any of the following:
               - Element has insufficient color contrast of 1.92 (foreground color: #f8f8f8, background color: #00d242, font size: 12.0pt (16px), font weight: bold). Expected contrast ratio of 4.5:1

       3) heading-order: Heading levels should only increase by one (moderate)
           https://dequeuniversity.com/rules/axe/4.9/heading-order?application=axeAPI
           The following 1 node violate this rule:

               Selector: h5
               HTML: <h5>Our Office</h5>
               Fix any of the following:
               - Heading order invalid

       4) image-alt: Images must have alternate text (critical)
           https://dequeuniversity.com/rules/axe/4.9/image-alt?application=axeAPI
           The following 1 node violate this rule:

               Selector: #map > img[loading="lazy"]
               HTML: <img loading="lazy" src="/assets/map-l-5a5b70d81baf3f49d809329aeea17d4234bf0592f5b733414f126377940f9548.png">
               Fix any of the following:
               - Element does not have an alt attribute
               - 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 has no title attribute
               - Element's default semantics were not overridden with role="none" or role="presentation"

       Invocation: axe.run({:exclude=>[]}, {}, callback);
     # ./spec/features/home_page_spec.rb:8:in `block (3 levels) in <top (required)>'

Finished in 4.79 seconds (files took 4.98 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/features/home_page_spec.rb:5 # HomePage when accessing home page has no accessibility violations

This is good information that will help our team lay out a plan to make this web page more accessible and we can use these tests to identify any other areas that could use improvement in our application.

Getting specific

We can also use clauses allowed with the be_axe_clean matcher to get more granular with the areas of a web page that should be tested. There are several clauses that can be included in the test such as:

within

  • This is an inclusion clause that will require a valid CSS selector as an argument to target a specific element on a page. It also accepts an array of selectors, or a hash describing iframes with selectors:
  context "when accessing the map on the home page" do
    it 'has no accessibility violations' do
      visit "/"

      expect(page).to be_axe_clean.within "#map"
    end
  end

Will produce:

Failures:

  1) HomePage when accessing the map on the home page has no accessibility violations
     Failure/Error: expect(page).to be_axe_clean.within "#map"

       Found 2 accessibility violations:

       1) aria-prohibited-attr: Elements must only use permitted ARIA attributes (serious)
           https://dequeuniversity.com/rules/axe/4.9/aria-prohibited-attr?application=axeAPI
           The following 1 node violate this rule:

               Selector: #map
               HTML: <picture id="map" aria-label="Map of our office in Philadelphia (by Google Maps)">
               Fix all of the following:
               - aria-label attribute cannot be used on a picture with no valid role attribute.

       2) image-alt: Images must have alternate text (critical)
           https://dequeuniversity.com/rules/axe/4.9/image-alt?application=axeAPI
           The following 1 node violate this rule:

               Selector: #map > img[loading="lazy"]
               HTML: <img loading="lazy" src="/assets/map-l-5a5b70d81baf3f49d809329aeea17d4234bf0592f5b733414f126377940f9548.png">
               Fix any of the following:
               - Element does not have an alt attribute
               - 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 has no title attribute
               - Element's default semantics were not overridden with role="none" or role="presentation"

       Invocation: axe.run({"include"=>[["#map"]]}, {}, callback);
     # ./spec/features/home_page_spec.rb:8:in `block (3 levels) in <top (required)>'

Finished in 3.51 seconds (files took 4.74 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/features/home_page_spec.rb:5 # HomePage when accessing the map on the home page has no accessibility violations

according_to

  • This is a tag clause that can target a specific accessibility standard to test against. Argument options can be a single tag or an array of tags.
      expect(page).to be_axe_clean.according_to :wcag2a

There are many other clauses that can be used in combination with the be_axe_clean matcher to find very specific instances of violations. More information can be found in the matches section of the gem’s README. opens a new window

Conclusion

Accessibility testing is an important part of Rails application development that ensures your software is usable by everyone, regardless of their abilities. With the help of automated testing tools, you can identify and resolve accessibility issues early in the development process. Prioritizing accessibility not only improves user experience but also demonstrates a commitment to inclusivity and equal access.

Need help making your Rails application accessible? Let us help! opens a new window

Happy Coding!

Get the book