From 6d0a7a41041053d015b6dff739df2a1148967354 Mon Sep 17 00:00:00 2001 From: Christophe Bliard Date: Mon, 30 Oct 2023 10:11:17 +0100 Subject: [PATCH] Add axe a11y test for Home page content Issues found by axe-core and fixed: Found 1 accessibility violation: 1) image-alt: Images must have alternate text (critical) https://dequeuniversity.com/rules/axe/4.8/image-alt?application=axeAPI The following 2 nodes violate this rule: Selector: .widget-box--teaser-image HTML: Fix any of the following: - Element does not have an alt attribute - 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's default semantics were not overridden with role="none" or role="presentation" Selector: .widget-box--blocks--upsale-image HTML: Fix any of the following: - Element does not have an alt attribute - 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's default semantics were not overridden with role="none" or role="presentation" Also removed useless title attributes from tags --- Gemfile | 3 ++ Gemfile.lock | 23 +++++++++++ app/views/homescreen/blocks/_upsale.html.erb | 26 ++++++------ .../blocks/new-features.component.ts | 1 + spec/features/a11y/home_spec.rb | 40 +++++++++++++++++++ spec/support/a11y.rb | 31 ++++++++++++++ 6 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 spec/features/a11y/home_spec.rb create mode 100644 spec/support/a11y.rb diff --git a/Gemfile b/Gemfile index 314c64783da..c33225a65ee 100644 --- a/Gemfile +++ b/Gemfile @@ -237,6 +237,9 @@ group :test do gem 'retriable', '~> 3.1.1' gem 'rspec-retry', '~> 0.6.1' + # Accessibility tests + gem 'axe-core-rspec' + # Modify ENV gem 'climate_control' diff --git a/Gemfile.lock b/Gemfile.lock index eda38d29683..611a6021692 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -328,6 +328,17 @@ GEM aws-sigv4 (~> 1.1) aws-sigv4 (1.6.1) aws-eventstream (~> 1, >= 1.0.2) + axe-core-api (4.8.0) + dumb_delegator + virtus + axe-core-rspec (4.8.0) + axe-core-api + 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.19) better_html (2.0.2) @@ -370,6 +381,8 @@ GEM activerecord (>= 4.2.10) with_advisory_lock (>= 4.0.0) coderay (1.1.3) + coercible (1.0.0) + descendants_tracker (~> 0.0.1) colored2 (4.0.0) commonmarker (0.23.10) compare-xml (0.66) @@ -404,6 +417,8 @@ GEM delayed_job_active_record (4.1.8) activerecord (>= 3.0, < 8.0) delayed_job (>= 3.0, < 5) + descendants_tracker (0.0.4) + thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.5.0) disposable (0.6.3) declarative (>= 0.0.9, < 1.0.0) @@ -430,6 +445,7 @@ GEM dry-inflector (~> 1.0) dry-logic (~> 1.4) zeitwerk (~> 2.6) + dumb_delegator (1.0.0) em-http-request (1.1.7) addressable (>= 2.3.4) cookiejar (!= 0.3.1) @@ -560,6 +576,7 @@ GEM icalendar (2.10.0) ice_cube (~> 0.16) ice_cube (0.16.4) + ice_nine (0.11.2) interception (0.5) io-console (0.6.0) irb (1.8.3) @@ -961,6 +978,7 @@ GEM test-prof (1.2.3) text-hyphen (1.5.0) thor (1.3.0) + thread_safe (0.3.6) timecop (0.9.8) timeout (0.4.0) trailblazer-option (0.1.2) @@ -991,6 +1009,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) warden-basic_auth (0.2.1) @@ -1034,6 +1056,7 @@ DEPENDENCIES awesome_nested_set (~> 3.6.0) aws-sdk-core (~> 3.107) aws-sdk-s3 (~> 1.91) + axe-core-rspec bcrypt (~> 3.1.6) bootsnap (~> 1.17.0) brakeman (~> 6.0.0) diff --git a/app/views/homescreen/blocks/_upsale.html.erb b/app/views/homescreen/blocks/_upsale.html.erb index 126e5117bb3..a8709a97549 100644 --- a/app/views/homescreen/blocks/_upsale.html.erb +++ b/app/views/homescreen/blocks/_upsale.html.erb @@ -1,14 +1,14 @@
- <%= image_tag "enterprise-add-on.svg", class: "widget-box--blocks--upsale-image" %> + <%= image_tag "enterprise-add-on.svg", role: "presentation", class: "widget-box--blocks--upsale-image" %>
<%= spot_icon('enterprise-addons') %> <%= t('homescreen.blocks.upsale.title') %> -
+

<%= t('js.admin.enterprise.upsale.text') %>

- +

<%= t('js.admin.enterprise.upsale.become_hero') %> <%= t('js.admin.enterprise.upsale.you_contribute') %>

@@ -21,25 +21,25 @@
<%= link_to "#{OpenProject::Static::Links.links[:upsale][:href]}/?utm_source=unknown&utm_medium=community-edition&utm_campaign=home-screen", - { class: 'button--link widget-box--blocks--upsale-info-button', - aria: {label: t('homescreen.blocks.upsale.more_info')}, - target: '_blank', - title: t('homescreen.blocks.upsale.more_info')} do %> + class: 'button--link widget-box--blocks--upsale-info-button', + aria: { label: t('homescreen.blocks.upsale.more_info') }, + target: '_blank', + rel: 'noopener' do %> <%= spot_icon('external-link') %> <%= t('homescreen.blocks.upsale.more_info') %> - + <% end %> <%= link_to(OpenProject::Static::Links.links[:pricing][:href], - { class: 'button -highlight', - aria: {label: t('admin.enterprise.buttons.upgrade')}, - target: '_blank', - title: t('admin.enterprise.buttons.upgrade')}) do %> + class: 'button -highlight', + aria: { label: t('admin.enterprise.buttons.upgrade') }, + target: '_blank', + rel: 'noopener') do %> <%= spot_icon('enterprise-addons') %> <%= t('admin.enterprise.buttons.upgrade') %> <% end %> <% if current_user.admin? %> <%= link_to t('js.admin.enterprise.upsale.button_start_trial'), enterprise_path, class: 'button -alt-highlight' %> - <% end %> + <% end %>
diff --git a/frontend/src/app/features/homescreen/blocks/new-features.component.ts b/frontend/src/app/features/homescreen/blocks/new-features.component.ts index 6bbeaa38791..21cdc35ca32 100644 --- a/frontend/src/app/features/homescreen/blocks/new-features.component.ts +++ b/frontend/src/app/features/homescreen/blocks/new-features.component.ts @@ -50,6 +50,7 @@ const featureTeaserImage = '13_0_features.svg';

diff --git a/spec/features/a11y/home_spec.rb b/spec/features/a11y/home_spec.rb new file mode 100644 index 00000000000..18a5cf3f9b9 --- /dev/null +++ b/spec/features/a11y/home_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2023 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require 'spec_helper' + +RSpec.describe 'Home', :js, with_settings: { login_required: false } do + context 'for #content' do + it 'passes axe-core accessibility tests' do + visit '/' + expect(page).to be_axe_clean.within '#content' + end + end +end diff --git a/spec/support/a11y.rb b/spec/support/a11y.rb new file mode 100644 index 00000000000..13c02bf6d17 --- /dev/null +++ b/spec/support/a11y.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2023 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require 'axe-rspec'