Browse Source

CLDC-759 Add accessibility testing (#2529)

* Add accessibility tests

* Add accessibiliy tests to CI

* Lint and refactor

* Adjust and update paths

* Add some more page tests
pull/2528/head^2
kosiakkatrina 5 months ago committed by GitHub
parent
commit
45d73955c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 61
      .github/workflows/staging_pipeline.yml
  2. 1
      Gemfile
  3. 23
      Gemfile.lock
  4. 2
      config/routes.rb
  5. 194
      spec/features/accessibility_spec.rb
  6. 4
      spec/rails_helper.rb

61
.github/workflows/staging_pipeline.yml

@ -130,7 +130,7 @@ jobs:
- name: Run tests
run: |
bundle exec rspec spec/features --fail-fast
bundle exec rspec spec/features --fail-fast --exclude-pattern "spec/features/accessibility_spec.rb"
model_test:
name: Model tests
@ -249,6 +249,65 @@ jobs:
run: |
bundle exec rake parallel:spec['spec/requests']
accessibility_test:
name: Accessibility tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:13.5
env:
POSTGRES_PASSWORD: password
POSTGRES_USER: postgres
POSTGRES_DB: data_collector
ports:
- 5432:5432
# Needed because the Postgres container does not provide a health check
# tmpfs makes database faster by using RAM
options: >-
--mount type=tmpfs,destination=/var/lib/postgresql/data
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
RAILS_ENV: test
GEMFILE_RUBY_VERSION: 3.1.1
DB_HOST: localhost
DB_DATABASE: data_collector
DB_USERNAME: postgres
DB_PASSWORD: password
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
PARALLEL_TEST_PROCESSORS: 4
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version: 20
- name: Create database
run: |
bundle exec rake parallel:setup
- name: Compile assets
run: |
bundle exec rake assets:precompile
- name: Run tests
run: |
bundle exec rspec spec/features/accessibility_spec.rb --fail-fast
lint:
name: Lint
runs-on: ubuntu-latest

1
Gemfile

@ -97,6 +97,7 @@ group :development do
end
group :test do
gem "axe-core-rspec"
gem "capybara", require: false
gem "capybara-lockstep"
gem "capybara-screenshot"

23
Gemfile.lock

@ -91,6 +91,17 @@ GEM
aws-sigv4 (~> 1.8)
aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2)
axe-core-api (4.9.1)
dumb_delegator
virtus
axe-core-rspec (4.9.1)
axe-core-api (= 4.9.1)
dumb_delegator
virtus
axiom-types (0.1.1)
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
base64 (0.2.0)
bcrypt (3.1.20)
better_html (2.0.2)
@ -128,6 +139,8 @@ GEM
launchy
childprocess (5.0.0)
coderay (1.1.3)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
concurrent-ruby (1.3.3)
connection_pool (2.4.1)
crack (1.0.0)
@ -137,6 +150,8 @@ GEM
cssbundling-rails (1.4.0)
railties (>= 6.0.0)
date (3.3.4)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (4.9.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
@ -155,6 +170,7 @@ GEM
dotenv-rails (3.0.2)
dotenv (= 3.0.2)
railties (>= 6.1)
dumb_delegator (1.0.0)
encryptor (3.0.0)
erb_lint (0.5.0)
activesupport
@ -204,6 +220,7 @@ GEM
activesupport (>= 6.1.4.4)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
iniparse (1.5.0)
jmespath (1.6.2)
jsbundling-rails (1.3.0)
@ -450,6 +467,7 @@ GEM
railties (>= 6.0.0)
strscan (3.1.0)
thor (1.3.1)
thread_safe (0.3.6)
timecop (0.9.8)
timeout (0.4.1)
turbo-rails (1.5.0)
@ -467,6 +485,10 @@ GEM
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0)
method_source (~> 1.0)
virtus (2.0.0)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.1)
@ -499,6 +521,7 @@ PLATFORMS
DEPENDENCIES
auto_strip_attributes
aws-sdk-s3
axe-core-rspec
bootsnap (>= 1.4.4)
bundler-audit
byebug

2
config/routes.rb

@ -72,7 +72,6 @@ Rails.application.routes.draw do
get "details", to: "schemes#details"
get "check-answers", to: "schemes#check_answers"
get "edit-name", to: "schemes#edit_name"
get "support-services-provider", to: "schemes#support_services_provider"
get "new-deactivation", to: "schemes#new_deactivation"
get "deactivate-confirm", to: "schemes#deactivate_confirm"
get "reactivate", to: "schemes#reactivate"
@ -148,7 +147,6 @@ Rails.application.routes.draw do
post "data-sharing-agreement", to: "organisations#confirm_data_sharing_agreement"
get "users", to: "organisations#users"
get "users/invite", to: "users/account#new"
get "lettings-logs", to: "organisations#lettings_logs"
get "delete-lettings-logs", to: "delete_logs#delete_lettings_logs_for_organisation"
post "delete-lettings-logs", to: "delete_logs#delete_lettings_logs_for_organisation_with_selected_ids"

194
spec/features/accessibility_spec.rb

@ -0,0 +1,194 @@
require "rails_helper"
RSpec.describe "Accessibility", js: true do
let(:user) { create(:user, :support) }
let!(:other_user) { create(:user, name: "new user", organisation: user.organisation, email: "new_user@example.com", confirmation_token: "abc") }
def find_routes(type, resource, subresource)
routes = Rails.application.routes.routes.select do |route|
route.verb == "GET" && route.path.spec.to_s.start_with?("/#{type}")
end
routes.map do |route|
route_path = route.path.spec.to_s
route_path
.gsub("/#{type}s/:id", "/#{type}s/#{resource.id}")
.gsub(":#{type.underscore}_id", resource.id.to_s)
.gsub(":id", subresource.id.to_s)
.gsub("(.:format)", "")
end
end
before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in(user)
end
context "when viewing user pages" do
let(:user_paths) do
Rails.application.routes.routes.select { |route| route.verb == "GET" && route.path.spec.to_s.start_with?("/user") }.map { |route|
route_path = route.path.spec.to_s
route_path.gsub(":id", other_user.id.to_s).gsub(":user_id", other_user.id.to_s).gsub("(.:format)", "")
}.uniq
end
it "is has accessible pages" do
user_paths.each do |path|
visit(path)
expect(page).to have_current_path(path)
expect(page).to be_axe_clean.according_to :wcag2aa
end
end
end
context "when viewing organisation pages" do
let(:parent_relationship) { create(:organisation_relationship, parent_organisation: other_user.organisation) }
let(:child_relationship) { create(:organisation_relationship, child_organisation: other_user.organisation) }
let(:organisation_paths) do
routes = find_routes("organisation", other_user.organisation, other_user.organisation).reject do |route|
route.match?(/\A\/organisations\/#{other_user.organisation_id}\z/) ||
route.include?("filters/update")
end
routes << "/organisations/#{other_user.organisation_id}/details"
route_mappings = {
"/schemes/csv-download" => "?download_type=combined",
"logs/csv-download" => "?codes_only=false&years[]=2024",
"filters/update" => "?codes_only=false",
"stock-owners/remove" => "?target_organisation_id=#{child_relationship.parent_organisation.id}",
"managing-agents/remove" => "?target_organisation_id=#{parent_relationship.child_organisation.id}",
}
routes.map do |route|
additional_params = route_mappings.find { |pattern, _| route.include?(pattern) }&.last
route += additional_params if additional_params
route
end
end
it "is has accessible pages" do
organisation_paths.each do |path|
visit(path)
expect(page).to have_current_path(path)
expect(page).to be_axe_clean.according_to :wcag2aa
end
end
end
context "when viewing lettings log pages" do
let(:bulk_upload) { create(:bulk_upload, user:) }
let(:lettings_log) { create(:lettings_log, :completed, assigned_to: other_user, bulk_upload_id: bulk_upload.id) }
let(:organisation_relationship) { create(:organisation_relationship, parent_organisation: user.organisation) }
let(:lettings_log_paths) do
routes = find_routes("lettings-log", lettings_log, bulk_upload)
all_page_ids = FormHandler.instance.lettings_forms.values.flat_map(&:pages).map(&:id).uniq
lettings_log_pages = lettings_log.form.pages
other_form_page_ids = all_page_ids - lettings_log_pages.map(&:id)
routes.reject { |path|
path.include?("/edit") || path.include?("/new") || path.include?("*page") || path.include?("filters/update") ||
path.include?("local-authority/check-answers") || path.include?("declaration/check-answers") ||
path.include?("/lettings-logs/bulk-upload-logs/#{bulk_upload.id}") ||
path.include?("bulk-upload-soft-validations-check") ||
path == "/lettings-logs/bulk-upload-resume/#{bulk_upload.id}" ||
other_form_page_ids.any? { |page_id| path.include?(page_id.dasherize) } ||
lettings_log_pages.any? { |page| path.include?(page.id.dasherize) && !page.routed_to?(lettings_log, user) }
}.uniq
end
before do
lettings_log.dup.tap do |log|
log.save(validate: false)
end
allow(FormHandler.instance).to receive(:in_crossover_period?).and_return(true)
end
it "is has accessible pages" do
lettings_log_paths.each do |path|
path += "?original_log_id=#{lettings_log.id}" if path.include?("duplicate")
path += "?codes_only=true&years[]=2024" if path.include?("csv")
path.gsub!("/start", "/prepare-your-file?form[year]=2024") if path.include?("bulk-upload-logs/start")
path.gsub!("/start", "/fix-choice") if path.include?("/bulk-upload-resume/#{bulk_upload.id}/start")
visit(path)
expect(page).to have_current_path(path)
expect(page).to be_axe_clean.according_to :wcag2aa
end
end
end
context "when viewing sales log pages" do
let(:bulk_upload) { create(:bulk_upload, user:) }
let(:sales_log) { create(:sales_log, :completed, assigned_to: other_user, bulk_upload_id: bulk_upload.id) }
let(:organisation_relationship) { create(:organisation_relationship, parent_organisation: user.organisation) }
let(:sales_log_paths) do
all_page_ids = FormHandler.instance.sales_forms.values.flat_map(&:pages).map(&:id).uniq
sales_log_pages = sales_log.form.pages
other_form_page_ids = all_page_ids - sales_log_pages.map(&:id)
routes = find_routes("sales-log", sales_log, bulk_upload)
routes.reject { |path|
path.include?("/edit") || path.include?("/new") || path.include?("*page") ||
path.include?("/sales-logs/bulk-upload-logs/#{bulk_upload.id}") ||
path.include?("bulk-upload-soft-validations-check") || path.include?("filters/update") ||
path == "/sales-logs/bulk-upload-resume/#{bulk_upload.id}" ||
path == "/sales-logs/bulk-upload-logs" ||
other_form_page_ids.any? { |page_id| path.include?(page_id.dasherize) } ||
sales_log_pages.any? { |page| path.include?(page.id.dasherize) && !page.routed_to?(sales_log, user) }
}.uniq
end
it "is has accessible pages" do
sales_log_paths.each do |path|
path += "?original_log_id=#{sales_log.id}" if path.include?("duplicate")
path += "?codes_only=true&years[]=2024" if path.include?("csv")
path.gsub!("/start", "/prepare-your-file?form[year]=2024") if path.include?("bulk-upload-logs/start")
path.gsub!("/start", "/fix-choice") if path.include?("/bulk-upload-resume/#{bulk_upload.id}/start")
visit(path)
expect(page).to have_current_path(path)
expect(page).to be_axe_clean.according_to :wcag2aa
end
end
end
context "when viewing scheme pages" do
let(:scheme) { create(:scheme, owning_organisation: other_user.organisation) }
let!(:location) { create(:location, scheme:) }
let(:scheme_paths) do
routes = find_routes("scheme", scheme, location)
routes.reject { |path|
path.include?("/edit") || path.include?("/new") || path.include?("*page") ||
path.include?("reactivate") || path.include?("deactivate")
}.uniq
end
before do
allow(FormHandler.instance).to receive(:in_crossover_period?).and_return(true)
end
it "is has accessible pages" do
scheme_paths.each do |path|
visit(path)
expect(page).to have_current_path(path)
expect(page).to be_axe_clean.according_to :wcag2aa
end
end
end
context "when viewing other pages" do
[{ path: "/", title: "homepage" },
{ path: "/guidance", title: "guidance" },
{ path: "/privacy-notice", title: "privacy notice" },
{ path: "/lettings-logs/bulk-upload-logs/guidance?form[year]=2024&referrer=home", title: "lettings BU guidance" },
{ path: "/sales-logs/bulk-upload-logs/guidance?form[year]=2024&referrer=home", title: "sales BU guidance" }].each do |test_case|
it "is has accessible #{test_case[:title]} page" do
visit(test_case[:path])
expect(page).to have_current_path(test_case[:path])
expect(page).to be_axe_clean.according_to :wcag2aa
end
end
end
end

4
spec/rails_helper.rb

@ -10,10 +10,14 @@ require "capybara-screenshot/rspec"
require "selenium-webdriver"
require "view_component/test_helpers"
require "pundit/rspec"
require "axe-rspec"
Capybara.register_driver :headless do |app|
options = Selenium::WebDriver::Firefox::Options.new
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--window-size=1400,1400")
Capybara::Selenium::Driver.new(app, browser: :firefox, options:)
end

Loading…
Cancel
Save