From 5561fdf83dfbccd9b5ae6baf0bc934bf0d59f3c1 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Wed, 14 Aug 2024 20:14:54 -0700 Subject: [PATCH 1/7] Tidy up specs, commit a violation to ensure they work... --- .github/workflows/rspec.yml | 4 +- home.md | 2 +- spec/accessibility_spec.rb | 29 +++++++++----- spec/spec_helper.rb | 78 ++++-------------------------------- spec/support/jekyll.rb | 65 ++++++++++++++++++++++++++++++ spec/support/spec_summary.rb | 8 ++-- 6 files changed, 98 insertions(+), 88 deletions(-) create mode 100644 spec/support/jekyll.rb diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index 71b7867..b3b936d 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -18,11 +18,11 @@ jobs: with: # The Ruby version is determined by either a `.ruby-version` or a `.tool-versions` file in root of the repo. bundler-cache: true - - name: Run rspec tests + - name: Run a11y tests run: | bundle exec rspec - name: summary - if: always() + if: failure() run: ruby spec/support/spec_summary.rb - name: Keep screenshots from failed tests uses: actions/upload-artifact@v4 diff --git a/home.md b/home.md index 84ab9a7..9d24765 100644 --- a/home.md +++ b/home.md @@ -11,7 +11,7 @@ seo: # UC Berkeley Class Site Template

- +

diff --git a/spec/accessibility_spec.rb b/spec/accessibility_spec.rb index 1bb3a21..b24f0f2 100644 --- a/spec/accessibility_spec.rb +++ b/spec/accessibility_spec.rb @@ -6,37 +6,44 @@ # spec_helper ensures the webiste is built and can be served locally require 'spec_helper' -ALL_PAGES = load_site_urls -puts "Running tests on #{ALL_PAGES.count} pages." -puts " - #{ALL_PAGES.join("\n - ")}\n#{'=' * 72}\n\n" - # Axe-core test standards groups # See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#axe-core-tags -required_a11y_standards = %i[wcag2a wcag2aa] -complete_a11y_standards = %i[wcag21a wcag21 wcag22aa best-practice secion508] +# Tests are segmented in 2.0, 2.1 and 2.2+ +# In most places WCAG 2.1AA is the minimum requirement, but 2.2 is the current WCAG Standard. +required_a11y_standards = %i[wcag2a wcag2aa wcag21a wcag21aa] +complete_a11y_standards = %i[wcag22aa best-practice secion508] # axe-core rules that are not required to be accessible / do not apply +# You may temporarily want to add rules here during development. # See: https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md skipped_rules = [] # These are elements that are not required to be accessible +# It should be rare to add to this list. This disables all rules for an element. +# e.g. would pass even though it's missing alt text. excluded_elements = [ - '[data-a11y-external-errors="true"]' + '[data-a11y-errors="true"]' ] +# We must call this to ensure the build it up-to-date. +build_jekyll_site! +ALL_PAGES = load_sitemap +puts "Running tests on #{ALL_PAGES.count} pages." +puts " - #{ALL_PAGES.join("\n - ")}\n\n" + ALL_PAGES.each do |path| - describe 'page is accessible', :js, type: :feature do + describe "#{path} is accessible", :js, type: :feature do before do visit(path) end - it "#{path} meets WCAG 2.0" do + it "meets WCAG 2.1" do expect(page).to be_axe_clean - .according_to(*required_a11y_standards, "#{path} does NOT meet WCAG 2.0 AA") + .according_to(*required_a11y_standards) .skipping(*skipped_rules) .excluding(*excluded_elements) end - it "#{path} meets WCAG 2.2" do + it "meets WCAG 2.2" do expect(page).to be_axe_clean .according_to(*complete_a11y_standards) .skipping(*skipped_rules) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9d9a4af..a43a151 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,7 +16,6 @@ # # See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -require 'jekyll' require 'rspec' require 'rack' require 'yaml' @@ -31,80 +30,18 @@ require 'axe-rspec' require 'axe-capybara' -# ------------ -# Tools to build / compile the Jekyll site and extract the sitemap -def site_config - # TODO(template): We should standardize the build for specs - # Consider simplifying baseurl - # Consider forcing the desination folder - # Override the local URL too? Would it break the sitemap? - # Note: Config keys must be strings and thus use => style hashes. - @site_config ||= Jekyll.configuration({ - 'sass' => { 'quiet_deps' => true } - }) -end - -@site = Jekyll::Site.new(site_config) -@site.process -puts 'Site build complete' - -def load_site_urls - puts 'Running accessibility tests' - sitemap_text = File.read('_site/sitemap.xml') - sitemap_links = sitemap_text.scan(%r{.+}) - sitemap_links.filter_map do |link| - link = link.gsub("#{site_config['url']}", '').gsub('', '') - # Skip non-html pages - # (FUTURE?) Are there other pages that should be audited for accessibility? - # (e.g. PDFs, documents. They'd need a different checker.) - next unless link.end_with?('.html') || link.end_with?('/') - - link - end.sort -end -# -------- +require_relative './support/jekyll' -# This is the root of the repository, e.g. the bjc-r directory -# Update this is you move this file. +# Used to set the path for a local webserver. +# Update this if you move this file. REPO_ROOT = File.expand_path('../', __dir__) -# https://nts.strzibny.name/how-to-test-static-sites-with-rspec-capybara-and-webkit/ -class StaticSite - attr_reader :root, :server - - # TODO: Rack::File will be deprecated soon. Find a better solution. - def initialize(root) - @root = root - @server = Rack::Files.new(root) - end - - def call(env) - # Remove the /baseurl prefix, which is present in all URLs, but not in the file system. - path = "_site#{env['PATH_INFO'].gsub(site_config['baseurl'], '/')}" - - env['PATH_INFO'] = if path.end_with?('/') && exists?("#{path}index.html") - "#{path}index.html" - elsif !exists?(path) && exists?("#{path}.html") - "#{path}.html" - else - path - end - - server.call(env) - end - - def exists?(path) - File.exist?(File.join(root, path)) - end -end -# --------- - Capybara.register_driver :chrome_headless do |app| options = Selenium::WebDriver::Chrome::Options.new options.add_argument('--headless') options.add_argument('--no-sandbox') options.add_argument('--disable-dev-shm-usage') - # macbook air ~13" screen size, with an absurd height for full size screenshots. + # MacBook Air ~13" screen size, with an absurd height to capture more content. options.add_argument('--window-size=1280,4000') Capybara::Selenium::Driver.new(app, browser: :chrome, options:) @@ -120,7 +57,9 @@ def exists?(path) end Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example| - "tmp/capybara/screenshot_#{example.description.gsub('/', '-').gsub(' ', '-').gsub(%r{^.*/spec/}, '')}" + path = example.example_group.top_level_description.gsub(/^\//, '').gsub('/', '-').gsub(' is accessible', '') + standards = example.description.split(' ').last + "tmp/capybara/screenshot_#{page}_#{standards}" end Capybara::Screenshot.autosave_on_failure = true @@ -132,11 +71,8 @@ def exists?(path) Capybara.app = Rack::Builder.new do use Rack::Lint run StaticSite.new(REPO_ROOT) - # map '/' do - # end end.to_app -# --------- RSpec.configure do |config| # Allow rspec to use `--only-failures` and `--next-failure` flags # Ensure that `tmp` is in your `.gitignore` file diff --git a/spec/support/jekyll.rb b/spec/support/jekyll.rb new file mode 100644 index 0000000..d6e4050 --- /dev/null +++ b/spec/support/jekyll.rb @@ -0,0 +1,65 @@ + +require 'jekyll' + +# Tools to build / compile the Jekyll site and extract the sitemap +def site_config + # TODO(template): We should standardize the build for specs + # Consider simplifying baseurl + # Consider forcing the desination folder + # Override the local URL too? Would it break the sitemap? + # Note: Config keys must be strings and thus use => style hashes. + @site_config ||= Jekyll.configuration({'sass' => { 'quiet_deps' => true }}) +end + +def build_jekyll_site! + puts 'Building site...' + @site = Jekyll::Site.new(site_config) + @site.process + puts 'Site build complete.' +end + +def load_sitemap + # Ensure that you have called + sitemap_text = File.read('_site/sitemap.xml') + sitemap_links = sitemap_text.scan(%r{.+}) + sitemap_links.filter_map do |link| + link = link.gsub("#{site_config['url']}", '').gsub('', '') + # Skip non-html pages + # (FUTURE?) Are there other pages that should be audited for accessibility? + # (e.g. PDFs, documents. They'd need a different checker.) + next unless link.end_with?('.html') || link.end_with?('/') + + link + end.sort +end + + +# Start a local Rack server +# https://nts.strzibny.name/how-to-test-static-sites-with-rspec-capybara-and-webkit/ +class StaticSite + attr_reader :root, :server + + def initialize(root) + @root = root + @server = Rack::Files.new(root) + end + + def call(env) + # Remove the /baseurl prefix, which is present in all URLs, but not in the file system. + path = "_site#{env['PATH_INFO'].gsub(site_config['baseurl'], '/')}" + + env['PATH_INFO'] = if path.end_with?('/') && exists?("#{path}index.html") + "#{path}index.html" + elsif !exists?(path) && exists?("#{path}.html") + "#{path}.html" + else + path + end + + server.call(env) + end + + def exists?(path) + File.exist?(File.join(root, path)) + end +end diff --git a/spec/support/spec_summary.rb b/spec/support/spec_summary.rb index f83085e..0db4413 100644 --- a/spec/support/spec_summary.rb +++ b/spec/support/spec_summary.rb @@ -60,10 +60,12 @@ def nicely_print(hash) def print_summary results_data = JSON.parse(File.read(RESULTS_PATH)) failing_tests_by_type = summarize_results(results_data) - pp(failing_tests_by_type) - puts "Total: #{failing_tests_by_type.values.sum} failures." + total_failures = failing_tests_by_type.values.sum + puts "#{total_failures} total a11y failures." + return if total_failures == 0 - puts "\n#{'-' * 16}" + pp(failing_tests_by_type) + puts "Failing Pages:\n#{'-' * 16}" summary_group = group_results(results_data) nicely_print(test_failures_with_pages(summary_group)) end From d4c14e03ec1cfc928881045a292291e2701b881e Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Wed, 14 Aug 2024 20:16:34 -0700 Subject: [PATCH 2/7] delint (safe) --- spec/accessibility_spec.rb | 4 ++-- spec/spec_helper.rb | 4 ++-- spec/support/jekyll.rb | 4 +--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/spec/accessibility_spec.rb b/spec/accessibility_spec.rb index b24f0f2..67e6986 100644 --- a/spec/accessibility_spec.rb +++ b/spec/accessibility_spec.rb @@ -36,14 +36,14 @@ visit(path) end - it "meets WCAG 2.1" do + it 'meets WCAG 2.1' do expect(page).to be_axe_clean .according_to(*required_a11y_standards) .skipping(*skipped_rules) .excluding(*excluded_elements) end - it "meets WCAG 2.2" do + it 'meets WCAG 2.2' do expect(page).to be_axe_clean .according_to(*complete_a11y_standards) .skipping(*skipped_rules) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a43a151..4ca3c4f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,7 +30,7 @@ require 'axe-rspec' require 'axe-capybara' -require_relative './support/jekyll' +require_relative 'support/jekyll' # Used to set the path for a local webserver. # Update this if you move this file. @@ -57,7 +57,7 @@ end Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example| - path = example.example_group.top_level_description.gsub(/^\//, '').gsub('/', '-').gsub(' is accessible', '') + path = example.example_group.top_level_description.gsub(%r{^/}, '').gsub('/', '-').gsub(' is accessible', '') standards = example.description.split(' ').last "tmp/capybara/screenshot_#{page}_#{standards}" end diff --git a/spec/support/jekyll.rb b/spec/support/jekyll.rb index d6e4050..bf3d34b 100644 --- a/spec/support/jekyll.rb +++ b/spec/support/jekyll.rb @@ -1,4 +1,3 @@ - require 'jekyll' # Tools to build / compile the Jekyll site and extract the sitemap @@ -8,7 +7,7 @@ def site_config # Consider forcing the desination folder # Override the local URL too? Would it break the sitemap? # Note: Config keys must be strings and thus use => style hashes. - @site_config ||= Jekyll.configuration({'sass' => { 'quiet_deps' => true }}) + @site_config ||= Jekyll.configuration({ 'sass' => { 'quiet_deps' => true } }) end def build_jekyll_site! @@ -33,7 +32,6 @@ def load_sitemap end.sort end - # Start a local Rack server # https://nts.strzibny.name/how-to-test-static-sites-with-rspec-capybara-and-webkit/ class StaticSite From 81d85c747caa5f6cd7a9919609b941e67e58287a Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Wed, 14 Aug 2024 20:16:57 -0700 Subject: [PATCH 3/7] delint (unsafe?) --- spec/spec_helper.rb | 4 ++-- spec/support/jekyll.rb | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4ca3c4f..8cd31a4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -57,8 +57,8 @@ end Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example| - path = example.example_group.top_level_description.gsub(%r{^/}, '').gsub('/', '-').gsub(' is accessible', '') - standards = example.description.split(' ').last + example.example_group.top_level_description.gsub(%r{^/}, '').gsub('/', '-').gsub(' is accessible', '') + standards = example.description.split.last "tmp/capybara/screenshot_#{page}_#{standards}" end diff --git a/spec/support/jekyll.rb b/spec/support/jekyll.rb index bf3d34b..e288d08 100644 --- a/spec/support/jekyll.rb +++ b/spec/support/jekyll.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'jekyll' # Tools to build / compile the Jekyll site and extract the sitemap From 59b1556ebd47f67303454a4b249fa63df41429dd Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Thu, 15 Aug 2024 01:04:34 -0700 Subject: [PATCH 4/7] fix spec helper --- _includes/head_custom.html | 26 +++++++++++++++++++++++--- spec/spec_helper.rb | 2 +- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/_includes/head_custom.html b/_includes/head_custom.html index 2e7aafa..5f734bf 100644 --- a/_includes/head_custom.html +++ b/_includes/head_custom.html @@ -5,21 +5,41 @@ + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8cd31a4..f7c94ab 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -57,7 +57,7 @@ end Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example| - example.example_group.top_level_description.gsub(%r{^/}, '').gsub('/', '-').gsub(' is accessible', '') + page = example.example_group.top_level_description.gsub(%r{^/}, '').gsub('/', '-').gsub(' is accessible', '') standards = example.description.split.last "tmp/capybara/screenshot_#{page}_#{standards}" end From a426563884a108978373deea3800f5e172c755e6 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Thu, 15 Aug 2024 01:49:56 -0700 Subject: [PATCH 5/7] Reasonably happy with the light/dark mode toggle * button in the bottom of the sidebar * respects the browser pref is avaiable * saves setting to localStorage * provides an unset button to clear localStorage --- _includes/footer_custom.html | 1 - _includes/head_custom.html | 39 --------------- _includes/nav_footer_custom.html | 8 ++- _includes/toggle-color-scheme.html | 80 ++++++++++++++++++++++++++++++ home.md | 5 -- 5 files changed, 87 insertions(+), 46 deletions(-) create mode 100644 _includes/toggle-color-scheme.html diff --git a/_includes/footer_custom.html b/_includes/footer_custom.html index 6aba45d..497a3d0 100644 --- a/_includes/footer_custom.html +++ b/_includes/footer_custom.html @@ -1,5 +1,4 @@ diff --git a/_includes/head_custom.html b/_includes/head_custom.html index 5f734bf..91e8cc6 100644 --- a/_includes/head_custom.html +++ b/_includes/head_custom.html @@ -4,42 +4,3 @@ - - - diff --git a/_includes/nav_footer_custom.html b/_includes/nav_footer_custom.html index 396860b..5912952 100644 --- a/_includes/nav_footer_custom.html +++ b/_includes/nav_footer_custom.html @@ -1,9 +1,15 @@ {% if site.class_archive_path %} -