Git Product home page Git Product logo

capybara_accessibility_audit's Introduction

CapybaraAccessibilityAudit

Extend your Capybara-powered System Tests to automatically audit the page for WCAG Stardards-based accessibility violations.

Usage

Failure:
Found 1 accessibility violation:

1) label: Form elements must have labels (critical)
    https://dequeuniversity.com/rules/axe/4.4/label?application=axeAPI
    The following 1 node violate this rule:

        Selector: input
        HTML: <input>
        Fix any of the following:
        - Form element does not have an implicit (wrapped) <label>
        - Form element does not have an explicit <label>
        - 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 has no placeholder attribute
        - Element's default semantics were not overridden with role="none" or role="presentation"

Invocation: axe.run({:exclude=>[]}, {}, callback);

Installing the gem will automatically configure your System Tests to audit for accessibility violations after common actions, including:

Under the hood, capybara_accessibility_audit relies on axe-core-rspec, which uses aXe to audit for accessibility violations. To configure which options are passed to the be_axe_clean matcher, override the class-level accessibility_audit_options. Supported keys include:

To override the class-level setting, wrap code in calls to the with_accessibility_audit_options method:

with_accessibility_audit_options according_to: :wcag21aaa do
  visit page_with_violations_path
end

Frequently Asked Questions

My application already exists, automated accessibility audits are uncovering violations left and right. Do I have to fix them all at once?

Your suite has control over which rules are skipped and which rules are enforced through the accessibility_audit_options configuration.

Configuration overrides can occur at any scope, ranging from class-wide to block-wide.

For example, to skip a rule at the suite-level, override it in your ApplicationSystemTestCase:

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  accessibility_audit_options.skipping = %w[label button-name image-alt]
end

To skip a rule at the test-level, wrap the test in a with_accessibility_audit_options block:

class MySystemTest < ApplicationSystemTestCase
  test "with overridden accessibility audit options" do
    with_accessibility_audit_options skipping: %w[label button-name image-alt] do
      visit examples_path
      # ...
    end
  end
end

To skip a rule at the block-level, wrap the code in a with_accessibility_audit_options block:

class MySystemTest < ApplicationSystemTestCase
  test "with overridden accessibility audit options" do
    visit examples_path

    with_accessibility_audit_options skipping: %w[label button-name image-alt] do
      click_on "A link to a page with a violation"
    end

    # ...
  end
end

As you resolve the violations, you can remove entries from the list of skipped rules.

I've implemented a custom Capybara action to toggle a disclosure element. How can I automatically audit for violations after it's called?

You can add the method to the list of methods that will initiate an automated audit:

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  def toggle_disclosure(locator)
    # ...
  end

  accessibility_audit_after :toggle_disclosure
end

How can I turn off auditing for the entire suite?

You can disable automated auditing within your ApplicationSystemTestCase:

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  self.accessibility_audit_enabled = false
end

How can I turn off auditing for a block of code?

You can disable automated auditing temporarily by wrapping code in a skip_accessibility_audits block:

class MySystemTest < ApplicationSystemTestCase
  test "with overridden accessibility audit options" do
    skip_accessibility_audits do
      visit a_page_with_violations_path

      click_on "A link to a page with a violation"
    end

    # ...
  end
end

How can I turn off auditing hooks for a method?

You can remove the method from the test's Set of accessibility_audit_after_methods configuration by calling skip_accessibility_audit_after:

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  skip_accessibility_audit_after :visit
end

How can I turn off auditing for a test file?

You can disable automated auditing at the class-level:

class MySystemTest < ApplicationSystemTestCase
  self.accessibility_audit_enabled = false
end

As you gradually address violations, you can re-enable audits within with_accessibility_audits blocks:

class MySystemTest < ApplicationSystemTestCase
  self.accessibility_audit_enabled = false

  test "a test with a violation" do
    visit examples_path

    with_accessibility_audits do
      click_on "A link to a page with violations"
    end
  end
end

Installation

Add this line to your application's Gemfile:

gem "capybara_accessibility_audit"

And then execute:

$ bundle

Contributing

Please read CONTRIBUTING.md.

License

The gem is available as open source under the terms of the MIT License.

capybara_accessibility_audit's People

Contributors

mfonism avatar seanpdoyle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

mfonism emilford

capybara_accessibility_audit's Issues

Add min dependency of rails 7 to gemspec

Gemfile specifies this is rails 7, and rails 6.1+ nicities are used.

     NoMethodError:
       undefined method `compact_blank!' for {}:Hash
       Did you mean?  compact!

Worth adding this to the .gemspec

Audit failures should not stop the test from running

I've observed that if a test fails because a page is not accessible, the remainder of the test block does not run. This results in issues being reported for a single page, but not for any other pages loaded in a test block.

Expected behavior:
The test should run to the end (barring other non-accessibility failures), even if a few of the pages visited fail the accessibility audit. Audit errors should be reported across all pages visited.

Actual behavior:
The test halts on the first accessibility error that it finds

Example:

RSpec.describe "Playbook", type: :system do
  around do |example|
    with_accessibility_audit_options do
      example.run
    end
  end

  it "renders all pages without error" do
    visit "/playbook"

    playbook_links = all(".application-main-content a[href^='/playbook']").map do |link|
      link[:href]
    end
    playbook_links.each do |url|
     # the first page visited that has an accessibility error will end the test
      visit url
    end
  end
end

I do realize that this issue/suggestion goes against the default behavior of Capybara - Capybara normally does not run the entire test if an assertion fails, or if it fails to visit a page. But it would be a great enhancement.

wrong number of arguments (given 2, expected 1) (v0.1.1)

Backtrace:

  1) Admin - Users #show with default calendar view shows user details
     Failure/Error: visit(path)
     
     ArgumentError:
       wrong number of arguments (given 2, expected 1)
     
     
     [Screenshot]: /home/clintel/Clintel/careright/tmp/screenshots/failures_r_spec_example_groups_admin_users_show_with_default_calendar_view_shows_user_details_12.png

     
     
     # /home/clintel/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/capybara-3.36.0/lib/capybara/session.rb:258:in `visit'
     # /home/clintel/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/capybara-3.36.0/lib/capybara/dsl.rb:58:in `block (2 levels) in <module:DSL>'
     # /home/clintel/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/capybara_accessibility_audit-0.1.1/lib/capybara_accessibility_audit/audit_system_test_extensions.rb:39:in `block (2 levels) in accessibility_audit_after'

For interest

def login_as(user, path = "/")
    reset_session!
    visit(path)
    expect(page).to have_current_path("/users/sign_in")
end

is what is invoking it.

Not really clear why two arguments are passed to visit, it's only got 1x param (https://github.com/teamcapybara/capybara/blob/master/lib/capybara/session.rb#L260 + our older version)

https://github.com/thoughtbot/capybara_accessibility_audit/blob/main/lib/capybara_accessibility_audit/audit_system_test_extensions.rb#L39

From: /home/clintel/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/capybara_accessibility_audit-0.1.1/lib/capybara_accessibility_audit/audit_system_test_extensions.rb:40 RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView#visit:

    38: define_method method do |*arguments, **options, &block|
    39:   require "pry"
 => 40:   binding.pry
    41:   super(*arguments, **options, &block).tap { Auditor.new(self).audit!(method) }
    42: end

[1] pry(#<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView>)> arguments
=> ["/admin/users"]
[2] pry(#<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView>)> method
=> :visit
[3] pry(#<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView>)> options
=> {}
[4] pry(#<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView>)> block
=> nil
[5] pry(#<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView>)> *arguments
SyntaxError: unexpected '\n', expecting '='
[5] pry(#<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView>)> puts *arguments.inspect
["/admin/users"]
=> nil

[2] pry(#<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView>)> method(:visit)
=> #<Method: #<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView "shows user details" (./spec/system/admin/users_spec.rb:12)>.visit>
[3] pry(#<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView>)> method(:visit).super_method
=> #<Method: Capybara::DSL#visit>
[4] pry(#<RSpec::ExampleGroups::AdminUsers::Show::WithDefaultCalendarView>)> puts method(:visit).super_method.source
        define_method method do |*args, &block|
          page.send method, *args, &block
        end
=> nil

If its just something funky with older ruby, maybe adding in some min versions might be worht doing.

Confirmation of alert box is not working

Problem:
When using the accept_confirm or accept_alert methods along with the capybara_accessibility_audit gem, a Selenium::WebDriver::Error::UnexpectedAlertOpenError error is raised during the test execution.

Expected Behavior:
The test should run without any errors when using the accept_confirm or accept_alert methods, even with the capybara_accessibility_audit gem enabled.

Actual Behavior:
The test is raising a Selenium::WebDriver::Error::UnexpectedAlertOpenError when using the accept_confirm or accept_alert methods with the capybara_accessibility_audit gem.

Steps to Reproduce:
I've created a GitHub repository that demonstrates the issue. The repository contains a simple system spec (system/root_spec.rb) utilising the accept_confirm method:

require "rails_helper"

describe "Root" do
  around do |example|
    with_accessibility_audit_options skipping: %w[
    html-has-lang
    landmark-one-main
    page-has-heading-one
    region
    ] do
      example.run
    end
  end

  it "raises an error", js: true do
    visit root_path

    accept_confirm do
      click_on "Alert"
    end

    expect(page).to have_content("Root Show")
  end
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.