Automated accessibility testing for Elixir web applications
Axe is an accessibility testing engine for websites and other HTML-based user interfaces. You can use it as a Chrome extension, Firefox extension, VSCode extension, as part of Google Lighthouse, and in many other ways.
All of those methods are good, but you need to remember to use them, and also all of your teammates need to remember to use them. Wouldn’t it be great if accessibility checks could run automatically on CI?
To achieve that, I wrote an Elixir library called A11yAudit that integrates axe-core into ExUnit assertions, which you can use in your browser-based tests.
#Installation
The library can be installed by adding a11y_audit to your list of dependencies in mix.exs:
def deps do
[
{:a11y_audit, "~> 0.1.0", only: :test}
]
end
#Usage
A11yAudit provides assertions for browser-based tests. It has no-setup-required assertions for the two most popular browser testing tools in Elixir, Wallaby and Hound.
A11yAudit does not crawl your website. Instead, it relies on you adding the assertions to your tests in the right places. Ideally, you would run the assertion on each page at least once. On pages that can be modified by user interaction with JavaScript or LiveView, you might want to run the assertion more than once.
#Usage with Wallaby
Call A11yAudit.Wallaby.assert_no_violations/1 in your Wallaby tests.
defmodule MyAppWeb.HomeTest do
use ExUnit.Case, async: true
use Wallaby.Feature
feature "home page", %{session: session} do
session
|> visit("/")
|> assert_has(Query.css("h1", text: "My App"))
|> A11yAudit.Wallaby.assert_no_violations()
end
end
#Usage with Hound
Call A11yAudit.Hound.assert_no_violations/0 in your Hound tests.
defmodule MyAppWeb.HomeTest do
use ExUnit.Case
use Hound.Helpers
test "home page" do
navigate_to("#{MyAppWeb.Endpoint.url()}/")
heading = find_element(:css, "h1")
assert inner_text(heading) == "My App"
A11yAudit.Hound.assert_no_violations()
end
end
#For other environments
If you’re running browser-based tests in Elixir without using Wallaby or Hound, you can still use A11yAudit. You will need a way to execute JavaScript snippets, and to get their return values back into your Elixir code. Assuming you have an execute_script function that can do that, you can use the test assertions like so:
get_audit_result =
fn ->
execute_script(A11yAudit.JS.axe_core())
axe_result_map = execute_script(A11yAudit.JS.await_audit_results())
A11yAudit.Results.from_json(axe_result_map)
end
A11yAudit.Assertions.assert_no_violations(get_audit_result.())
#Feedback welcome
Please create a GitHub issue if you’re having trouble with using this library, found a bug, or have suggestions for improvements. I’m looking forward to your feedback!
#Disclaimer
There are two kinds of accessibility issues, objective and subjective, and automated testing can only detect the first kind. Thus, it should always be used together with manual testing.
#Need more?
If you’re looking for more automated quality assurance for your Elixir web apps, check out my Elixir client for the W3C HTML validator.
If you’re looking for more high-quality information about web accessibility, check out The A11y Project.