<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Chris Lewis</title>
    <description>The latest articles on Forem by Chris Lewis (@chrislewis60).</description>
    <link>https://forem.com/chrislewis60</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F415903%2F4131c5b0-c7ff-4190-9154-d5b1785f0346.jpeg</url>
      <title>Forem: Chris Lewis</title>
      <link>https://forem.com/chrislewis60</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/chrislewis60"/>
    <language>en</language>
    <item>
      <title>Automated accessibility testing in Rails with RSpec and aXe.</title>
      <dc:creator>Chris Lewis</dc:creator>
      <pubDate>Sun, 05 Jul 2020 23:00:28 +0000</pubDate>
      <link>https://forem.com/chrislewis60/introducing-automated-accessibility-testing-in-rails-apps-with-rspec-and-axe-4hch</link>
      <guid>https://forem.com/chrislewis60/introducing-automated-accessibility-testing-in-rails-apps-with-rspec-and-axe-4hch</guid>
      <description>&lt;p&gt;We all love to make great looking websites, but we also have a responsibility to make our websites as accessible as possible for people with disabilities. &lt;/p&gt;

&lt;p&gt;However, checking that a website meets certain accessibility standards can often be a very time-consuming process, involving 3rd party tools and online validators.   &lt;/p&gt;

&lt;p&gt;Wouldn't it be great if we could automatically test accessibility as part of our normal testing and Continuous Integration (CI) processes? Some key benefits could be that: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;developers can immediately see when accessibility issues are introduced if checks are done every time code is pushed to the repository&lt;/li&gt;
&lt;li&gt;all developers would be exposed to accessibility checks, helping to develop a team-wide appreciation for the guidelines&lt;/li&gt;
&lt;li&gt;it helps to ensure that there are no accessibility regressions once a site has gone live
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  axe - The Standard in Accessibility Testing
&lt;/h2&gt;

&lt;p&gt;Thankfully, the awesome folk at &lt;a href="https://www.deque.com/axe/"&gt;Deque&lt;/a&gt; have developed a set of accessibility rules known as 'axe-core' that can be used to automatically test a wide range of web applications, including Rails apps. &lt;/p&gt;

&lt;p&gt;The main repository for Rails and RSpec integration can be found at:  &lt;a href="https://github.com/dequelabs/axe-core-gems/blob/develop/packages/axe-core-rspec/README.md"&gt;deque/axe-core-rspec&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser testing environment
&lt;/h2&gt;

&lt;p&gt;The accessibility tests need to be run in an instance of a web browser. For example, this could be an instance of Chrome, Firefox, or Chrome in a headless state (without a graphical display). But there are other browsers that can be used. &lt;/p&gt;

&lt;p&gt;This example is going to use a customised headless Chrome browser. &lt;/p&gt;

&lt;h2&gt;
  
  
  Example Rails and RSpec setup
&lt;/h2&gt;

&lt;p&gt;Start by creating a new Rails app, or open a pre-existing Rails project, and make sure the following gems are in &lt;code&gt;Gemfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;
&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rspec-rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 4.0.0'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'axe-core-rspec'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'capybara'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'selenium-webdriver'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'webdrivers'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;bundle&lt;/code&gt; to install the gems. &lt;/p&gt;

&lt;p&gt;If you haven't got &lt;a href="https://github.com/rspec/rspec-rails"&gt;RSpec&lt;/a&gt; set up, then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails generate rspec:install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Include the relevant libraries at the top of &lt;code&gt;spec_helper.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/spec_helper.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../../config/environment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rspec/rails'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'capybara/rspec'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'axe-rspec'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'webdrivers/chromedriver'&lt;/span&gt;

&lt;span class="c1"&gt;# This configuration seems to work well in CI environments:&lt;/span&gt;
&lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_driver&lt;/span&gt; &lt;span class="ss"&gt;:chrome_headless&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Selenium&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;WebDriver&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Chrome&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'--headless'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'--no-sandbox'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'--disable-dev-shm-usage'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'--window-size=1400,1400'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Selenium&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;browser: :chrome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;options: &lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Change default_driver to :selenium_chrome if you want to actually see the tests running in a browser locally. Should be :chrome_headless in CI though.&lt;/span&gt;
&lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:chrome_headless&lt;/span&gt;
&lt;span class="no"&gt;Capybara&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;javascript_driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:chrome_headless&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new welcome/index route (or find a controller and view you'd like to test):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails generate controller welcome index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding an integration test to your RSpec tests
&lt;/h2&gt;

&lt;p&gt;Create a new integration test to check that the welcome page is accessible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/integration/user_views_accessible_welcome_page_spec.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'spec_helper'&lt;/span&gt;

&lt;span class="n"&gt;feature&lt;/span&gt; &lt;span class="s1"&gt;'welcome'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;js: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;scenario&lt;/span&gt; &lt;span class="s1"&gt;'index is accessible'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;welcome_index_path&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_axe_clean&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And run the test with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle exec rspec spec/integration/user_views_accessible_welcome_page_spec.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default layout and view created by the Rails generator should have some accessibility failures. This is actually quite useful because you can immediately see that the tests are working. Some examples you might see include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found 3 accessibility violations:

 1) html-has-lang: &amp;lt;html&amp;gt; element must have a lang attribute (serious)
     https://dequeuniversity.com/rules/axe/3.5/html-has-lang?application=axeAPI
     The following 1 node violate this rule:

         Selector: html
         HTML: &amp;lt;html&amp;gt;
         Fix any of the following:
         - The &amp;lt;html&amp;gt; element does not have a lang attribute

 2) landmark-one-main: Document must have one main landmark (moderate)
     https://dequeuniversity.com/rules/axe/3.5/landmark-one-main?application=axeAPI
     The following 1 node violate this rule:

         Selector: html
         HTML: &amp;lt;html&amp;gt;
         Fix all of the following:
         - Document does not have a main landmark

 3) region: All page content must be contained by landmarks (moderate)
     https://dequeuniversity.com/rules/axe/3.5/region?application=axeAPI
     The following 2 nodes violate this rule:

         Selector: h1
         HTML: &amp;lt;h1&amp;gt;Axe matchers example Rails app (RSpec)&amp;lt;/h1&amp;gt;
         Fix any of the following:
                 - - Some page content is not contained by landmarks

         Selector: p
         HTML: &amp;lt;p&amp;gt;
         Fix any of the following:
                 - - Some page content is not contained by landmarks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What accessibility standards can be tested?
&lt;/h2&gt;

&lt;p&gt;You can target the following standards: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag Name&lt;/th&gt;
&lt;th&gt;Accessibility Standard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;wcag2a&lt;/td&gt;
&lt;td&gt;WCAG 2.0 Level A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;wcag2aa&lt;/td&gt;
&lt;td&gt;WCAG 2.0 Level AA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;section508&lt;/td&gt;
&lt;td&gt;Section 508&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;best-practice&lt;/td&gt;
&lt;td&gt;Best practices endorsed by Deque&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For example, to only test for Level WCAG 2.0 Level A accessibility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/integration/user_views_accessible_welcome_page_spec.rb&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_axe_clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;according_to&lt;/span&gt; &lt;span class="ss"&gt;:wcag2a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Does the whole page have to be tested?
&lt;/h2&gt;

&lt;p&gt;You can target certain parts of a page rather than testing the whole thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/integration/user_views_accessible_welcome_page_spec.rb&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_axe_clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;within&lt;/span&gt; &lt;span class="s1"&gt;'#selector1'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or exclude certain parts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/integration/user_views_accessible_welcome_page_spec.rb&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_axe_clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;excluding&lt;/span&gt; &lt;span class="s1"&gt;'#selector1'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many more options to help you customise the scope of your tests. The full range can be found on the &lt;a href="https://github.com/dequelabs/axe-core-gems/blob/develop/packages/axe-core-rspec/README.md"&gt;deque/axe-matchers-rspec&lt;/a&gt; page.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Automated accessibility testing can go a long way to improving a development team's knowledge and understanding of the accessibility guidelines. It also makes sure that accessibility is not forgotten about during any stage of the development process. By including these automated tests in the CI process, it's possible to get continuous feedback on accessibility compliance and it keeps everyone's focus on maintaining good accessibility standards. &lt;/p&gt;

&lt;p&gt;However, it would be prudent to also cross-reference these automated tests by testing sites using tools like &lt;a href="https://www.totalvalidator.com/"&gt;Total Validator&lt;/a&gt; from time to time. &lt;/p&gt;

&lt;p&gt;Plus, there's no substitute for actually opening up a site and making sure that it is usable, using screen readers like: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.freedomscientific.com/"&gt;Jaws&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nvaccess.org"&gt;NVDA&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy testing! &lt;/p&gt;

</description>
      <category>a11y</category>
      <category>rails</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
