From d1b549786705eeede716d7d3508b2f6c002fab72 Mon Sep 17 00:00:00 2001 From: Vasilii Iakliushin Date: Tue, 21 Nov 2023 18:35:12 +0100 Subject: [PATCH 1/4] Try to implement a AccordionComponent Contributes to https://gitlab.com/gitlab-org/gitlab/-/issues/433130 WIP --- .../pajamas/accordion_component.html.haml | 8 ++++ app/components/pajamas/accordion_component.rb | 43 +++++++++++++++++++ .../projects/_new_project_fields.html.haml | 11 +++++ locale/gitlab.pot | 3 ++ 4 files changed, 65 insertions(+) create mode 100644 app/components/pajamas/accordion_component.html.haml create mode 100644 app/components/pajamas/accordion_component.rb diff --git a/app/components/pajamas/accordion_component.html.haml b/app/components/pajamas/accordion_component.html.haml new file mode 100644 index 00000000000000..824d736f8d2d5f --- /dev/null +++ b/app/components/pajamas/accordion_component.html.haml @@ -0,0 +1,8 @@ +.gl-accordion-item + %h3.gl-accordion-item-header + = render Pajamas::ButtonComponent.new(variant: :link, button_options: { aria_controls: "accordion-item", style: 'overflow-anchor: none;', **button_class }) do + = sprite_icon('chevron-right', size: nil, css_class: 'gl-button-icon gl-icon s16') + = @title.html_safe + + .gl-mt-3.gl-font-base.collapse{ id: 'accordion-item', **body_class } + = @body diff --git a/app/components/pajamas/accordion_component.rb b/app/components/pajamas/accordion_component.rb new file mode 100644 index 00000000000000..de1b071a7b35a6 --- /dev/null +++ b/app/components/pajamas/accordion_component.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +# Renders a accordion component +module Pajamas + class AccordionComponent < Pajamas::Component + # @param [String] title + # @param [String] body + # @param [Symbol] state + def initialize(title: nil, body: nil, state: :closed) + @title = title + @body = body + @state = filter_attribute(state.to_sym, STATE_OPTIONS) + end + + delegate :sprite_icon, to: :helpers + + private + + STATE_OPTIONS = [:opened, :closed].freeze + + def button_class + case @state + when :closed + { class: 'collapsed', aria_expanded: false } + when :opened + { class: 'non-collapsed', aria_expanded: true } + else + {} + end + end + + def body_class + case @state + when :closed + { style: 'display: none' } + when :opened + { class: 'show' } + else + {} + end + end + end +end diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml index 58ae445fc02837..e1bba39e1fdb5a 100644 --- a/app/views/projects/_new_project_fields.html.haml +++ b/app/views/projects/_new_project_fields.html.haml @@ -92,6 +92,17 @@ = s_('ProjectsNew|Analyze your source code for known security vulnerabilities.') = link_to _('Learn more.'), help_page_path('user/application_security/sast/index'), target: '_blank', rel: 'noopener noreferrer', data: { track_action: 'followed' } + .form-group + - sha256_component = render Pajamas::CheckboxTagComponent.new(name: 'project[use_sha256_repository]') do |c| + - c.with_label do + = s_('ProjectsNew|Use SHA-256 as the repository hashing algorithm') + - c.with_help_text do + = s_('ProjectsNew|Default hashing algorithm is SHA-1.') + + + - accordion_badge = render Pajamas::BadgeComponent.new(_('Experimental'), variant: :muted) + = render Pajamas::AccordionComponent.new(title: "Experimental settings #{accordion_badge}", body: sha256_component, state: :closed) + - if display_sha256_repository .form-group = render Pajamas::CheckboxTagComponent.new(name: 'project[use_sha256_repository]') do |c| diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 2a2f7c434b950e..11661d7f7771a0 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -20371,6 +20371,9 @@ msgstr "" msgid "ExperimentBadge|What's an Experiment?" msgstr "" +msgid "Experimental" +msgstr "" + msgid "Experiments" msgstr "" -- GitLab From 9e8fb0c137177c9fbd488ff4c45f5a5a0be11a07 Mon Sep 17 00:00:00 2001 From: Jacques Date: Fri, 2 Feb 2024 13:31:01 +0100 Subject: [PATCH 2/4] Add interactivity to the accordion component Adds the JS code for interactivity --- app/assets/javascripts/accordion/index.js | 28 +++++++++++ app/assets/javascripts/projects/new/index.js | 3 ++ .../pajamas/accordion_component.html.haml | 5 +- app/components/pajamas/accordion_component.rb | 22 ++------- .../projects/_new_project_fields.html.haml | 23 +++------ locale/gitlab.pot | 14 +++--- .../pajamas/accordion_component_spec.rb | 49 +++++++++++++++++++ .../projects/user_creates_project_spec.rb | 3 +- spec/frontend/accordion/index_spec.js | 43 ++++++++++++++++ 9 files changed, 145 insertions(+), 45 deletions(-) create mode 100644 app/assets/javascripts/accordion/index.js create mode 100644 spec/components/pajamas/accordion_component_spec.rb create mode 100644 spec/frontend/accordion/index_spec.js diff --git a/app/assets/javascripts/accordion/index.js b/app/assets/javascripts/accordion/index.js new file mode 100644 index 00000000000000..432c469260e31f --- /dev/null +++ b/app/assets/javascripts/accordion/index.js @@ -0,0 +1,28 @@ +import { spriteIcon } from '~/lib/utils/common_utils'; + +/** + * This adds interactivity to accordions created via HAML + */ +export default (el) => { + if (!el) return; + + const accordionTrigger = el.querySelector('button'); + const accordionItem = el.querySelector('#accordion-item'); + const iconClass = 's16 gl-icon gl-button-icon js-chevron-icon'; + const chevronRight = spriteIcon('chevron-right', iconClass); + const chevronDown = spriteIcon('chevron-down', iconClass); + + accordionTrigger.addEventListener('click', () => { + const chevronIcon = el.querySelector('.js-chevron-icon'); + accordionItem.classList.toggle('show'); + + if (accordionItem.classList.contains('show')) { + // eslint-disable-next-line no-unsanitized/property + chevronIcon.outerHTML = chevronDown; + return; + } + + // eslint-disable-next-line no-unsanitized/property + chevronIcon.outerHTML = chevronRight; + }); +}; diff --git a/app/assets/javascripts/projects/new/index.js b/app/assets/javascripts/projects/new/index.js index a5a833dc73bb14..1560e47c33ef2f 100644 --- a/app/assets/javascripts/projects/new/index.js +++ b/app/assets/javascripts/projects/new/index.js @@ -2,6 +2,7 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; import { parseBoolean } from '~/lib/utils/common_utils'; +import initAccordion from '~/accordion'; import NewProjectCreationApp from './components/app.vue'; import NewProjectUrlSelect from './components/new_project_url_select.vue'; import DeploymentTargetSelect from './components/deployment_target_select.vue'; @@ -89,3 +90,5 @@ export function initDeploymentTargetSelect() { render: (createElement) => createElement(DeploymentTargetSelect), }); } + +initAccordion(document.getElementById('js-experimental-setting-accordion')); diff --git a/app/components/pajamas/accordion_component.html.haml b/app/components/pajamas/accordion_component.html.haml index 824d736f8d2d5f..d3c2e6ecb1a141 100644 --- a/app/components/pajamas/accordion_component.html.haml +++ b/app/components/pajamas/accordion_component.html.haml @@ -1,8 +1,7 @@ .gl-accordion-item %h3.gl-accordion-item-header - = render Pajamas::ButtonComponent.new(variant: :link, button_options: { aria_controls: "accordion-item", style: 'overflow-anchor: none;', **button_class }) do - = sprite_icon('chevron-right', size: nil, css_class: 'gl-button-icon gl-icon s16') - = @title.html_safe + = render Pajamas::ButtonComponent.new(variant: :link, icon: icon, icon_classes: "js-chevron-icon", button_options: { aria_controls: "accordion-item" }) do + = @title .gl-mt-3.gl-font-base.collapse{ id: 'accordion-item', **body_class } = @body diff --git a/app/components/pajamas/accordion_component.rb b/app/components/pajamas/accordion_component.rb index de1b071a7b35a6..b98ac5088c4f13 100644 --- a/app/components/pajamas/accordion_component.rb +++ b/app/components/pajamas/accordion_component.rb @@ -14,30 +14,14 @@ def initialize(title: nil, body: nil, state: :closed) delegate :sprite_icon, to: :helpers - private - STATE_OPTIONS = [:opened, :closed].freeze - def button_class - case @state - when :closed - { class: 'collapsed', aria_expanded: false } - when :opened - { class: 'non-collapsed', aria_expanded: true } - else - {} - end + def icon + @state == :opened ? "chevron-down" : "chevron-right" end def body_class - case @state - when :closed - { style: 'display: none' } - when :opened - { class: 'show' } - else - {} - end + @state == :opened ? { class: 'show' } : {} end end end diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml index e1bba39e1fdb5a..9f919d95041024 100644 --- a/app/views/projects/_new_project_fields.html.haml +++ b/app/views/projects/_new_project_fields.html.haml @@ -92,24 +92,17 @@ = s_('ProjectsNew|Analyze your source code for known security vulnerabilities.') = link_to _('Learn more.'), help_page_path('user/application_security/sast/index'), target: '_blank', rel: 'noopener noreferrer', data: { track_action: 'followed' } - .form-group - - sha256_component = render Pajamas::CheckboxTagComponent.new(name: 'project[use_sha256_repository]') do |c| - - c.with_label do - = s_('ProjectsNew|Use SHA-256 as the repository hashing algorithm') - - c.with_help_text do - = s_('ProjectsNew|Default hashing algorithm is SHA-1.') - - - - accordion_badge = render Pajamas::BadgeComponent.new(_('Experimental'), variant: :muted) - = render Pajamas::AccordionComponent.new(title: "Experimental settings #{accordion_badge}", body: sha256_component, state: :closed) - - if display_sha256_repository - .form-group - = render Pajamas::CheckboxTagComponent.new(name: 'project[use_sha256_repository]') do |c| + .form-group.gl-mb-6 + - sha256_component = render Pajamas::CheckboxTagComponent.new(name: 'project[use_sha256_repository]') do |c| - c.with_label do - = s_('ProjectsNew|Use SHA-256 as the repository hashing algorithm') + = s_('ProjectsNew|Use SHA-256 for repository hashing algorithm') + = render_if_exists 'shared/experimental_badge_tag' - c.with_help_text do - = s_('ProjectsNew|Default hashing algorithm is SHA-1.') + = s_("ProjectsNew|Might break existing functionality with other repositories or APIs. It's not possible to change SHA-256 repositories back to the default SHA-1 hashing algorithm.") + + #js-experimental-setting-accordion + = render Pajamas::AccordionComponent.new(title: s_("ProjectsNew|Experimental settings"), body: sha256_component, state: :closed) -# this partial is from JiHu, see details in https://jihulab.com/gitlab-cn/gitlab/-/merge_requests/675 = render_if_exists 'shared/other_project_options', f: f, visibility_level: visibility_level, track_label: track_label diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 11661d7f7771a0..4837d7e3632558 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -20371,9 +20371,6 @@ msgstr "" msgid "ExperimentBadge|What's an Experiment?" msgstr "" -msgid "Experimental" -msgstr "" - msgid "Experiments" msgstr "" @@ -39405,15 +39402,15 @@ msgstr "" msgid "ProjectsNew|Create new project" msgstr "" -msgid "ProjectsNew|Default hashing algorithm is SHA-1." -msgstr "" - msgid "ProjectsNew|Description format" msgstr "" msgid "ProjectsNew|Enable Static Application Security Testing (SAST)" msgstr "" +msgid "ProjectsNew|Experimental settings" +msgstr "" + msgid "ProjectsNew|Group name" msgstr "" @@ -39429,6 +39426,9 @@ msgstr "" msgid "ProjectsNew|Initialize repository with a README" msgstr "" +msgid "ProjectsNew|Might break existing functionality with other repositories or APIs. It's not possible to change SHA-256 repositories back to the default SHA-1 hashing algorithm." +msgstr "" + msgid "ProjectsNew|Migrate your data from an external source like GitHub, Bitbucket, or another instance of GitLab." msgstr "" @@ -39471,7 +39471,7 @@ msgstr "" msgid "ProjectsNew|Unable to suggest a path. Please refresh and try again." msgstr "" -msgid "ProjectsNew|Use SHA-256 as the repository hashing algorithm" +msgid "ProjectsNew|Use SHA-256 for repository hashing algorithm" msgstr "" msgid "ProjectsNew|Visibility Level" diff --git a/spec/components/pajamas/accordion_component_spec.rb b/spec/components/pajamas/accordion_component_spec.rb new file mode 100644 index 00000000000000..aa12118178dd2e --- /dev/null +++ b/spec/components/pajamas/accordion_component_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Pajamas::AccordionComponent, type: :component, feature_category: :shared do + let(:title) { "This is a title" } + let(:body) { "This is the body" } + let(:state) { :opened } + + before do + render_inline(described_class.new(title: title, body: body, state: state)) + end + + describe "title param" do + it "is shown inside the accordion" do + expect(page).to have_content(title) + end + end + + describe "body param" do + it "is shown inside the accordion" do + expect(page).to have_content(body) + end + end + + describe "state (opened) param" do + it "renders the show class" do + expect(page).to have_selector('.show') + end + + it "renders a chevron-down icon" do + expect(page).to have_selector('[data-testid="chevron-down-icon"]') + end + end + + describe "state (closed) param" do + before do + render_inline(described_class.new(title: title, body: body, state: :closed)) + end + + it "does not render the show class" do + expect(page).not_to have_selector('.show') + end + + it "renders a chevron-right icon" do + expect(page).to have_selector('[data-testid="chevron-right-icon"]') + end + end +end diff --git a/spec/features/projects/user_creates_project_spec.rb b/spec/features/projects/user_creates_project_spec.rb index 96156f14cfc3e9..b715733ca20710 100644 --- a/spec/features/projects/user_creates_project_spec.rb +++ b/spec/features/projects/user_creates_project_spec.rb @@ -58,12 +58,13 @@ end context 'when creating a project with SHA256 repository' do - let(:sha256_field) { 'Use SHA-256 as the repository hashing algorithm' } + let(:sha256_field) { 'Use SHA-256 for repository hashing algorithm' } it 'creates a new project' do visit(new_project_path) click_link 'Create blank project' + click_button 'Experimental settings' fill_in(:project_name, with: 'With initial commits') expect(page).to have_checked_field 'Initialize repository with a README' diff --git a/spec/frontend/accordion/index_spec.js b/spec/frontend/accordion/index_spec.js new file mode 100644 index 00000000000000..2dd83de65f9d30 --- /dev/null +++ b/spec/frontend/accordion/index_spec.js @@ -0,0 +1,43 @@ +import initAccordion from '~/accordion'; +import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; + +describe('Init Accordion component', () => { + beforeEach(() => { + setHTMLFixture( + '
', + ); + initAccordion(document.querySelector('.js-accordion')); + }); + + afterEach(() => resetHTMLFixture()); + + const findAccordionTrigger = () => document.querySelector('button'); + const findAccordionItem = () => document.querySelector('#accordion-item'); + const findSvgIconLink = () => document.querySelector('use').getAttribute('xlink:href'); + + it('adds a `show` class to the accordion item when expanded', () => { + findAccordionTrigger().click(); + expect(findAccordionItem().classList.contains('show')).toBe(true); + }); + + it('removes `show` class from the accordion item when collapsed', () => { + findAccordionTrigger().click(); // expands the accordion + expect(findAccordionItem().classList.contains('show')).toBe(true); + + findAccordionTrigger().click(); // collapses the accordion + expect(findAccordionItem().classList.contains('show')).toBe(false); + }); + + it('renders a chevron-down icon when expanded', () => { + findAccordionTrigger().click(); + + expect(findSvgIconLink()).toContain('#chevron-down'); + }); + + it('renders a chevron-right icon when collapsed', () => { + findAccordionTrigger().click(); // expands the accordion + findAccordionTrigger().click(); // collapses the accordion + + expect(findSvgIconLink()).toContain('#chevron-right'); + }); +}); -- GitLab From 7438ec87b4d4cbf06a61e9d465d98bebc59c65f7 Mon Sep 17 00:00:00 2001 From: Jacques Date: Thu, 8 Feb 2024 11:25:05 +0100 Subject: [PATCH 3/4] Add lookbook preview for the accordion Added a lookbook preview for the accordion component --- .../pajamas/accordion_component_preview.rb | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 spec/components/previews/pajamas/accordion_component_preview.rb diff --git a/spec/components/previews/pajamas/accordion_component_preview.rb b/spec/components/previews/pajamas/accordion_component_preview.rb new file mode 100644 index 00000000000000..5c722cdee69598 --- /dev/null +++ b/spec/components/previews/pajamas/accordion_component_preview.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Pajamas + class AccordionComponentPreview < ViewComponent::Preview + # @param title text + # @param body text + # @param state + def default(title: "Accordion title (open)", body: "Accordion body", state: :opened) + render(Pajamas::AccordionComponent.new( + title: title, + body: body, + state: state + )) + end + + def closed(title: "Accordion title (closed)", body: "Accordion body", state: :closed) + render(Pajamas::AccordionComponent.new( + title: title, + body: body, + state: state + )) + end + end +end -- GitLab From c97fa66c00baef8745d5875391aac35d696abf29 Mon Sep 17 00:00:00 2001 From: Jacques Date: Fri, 9 Feb 2024 10:09:01 +0100 Subject: [PATCH 4/4] Address maintainer review comments General cleanup of the code --- app/assets/javascripts/accordion/index.js | 4 +- .../pajamas/accordion_component.html.haml | 7 --- .../accordion_item_component.html.haml | 7 +++ ...mponent.rb => accordion_item_component.rb} | 10 ++-- .../projects/_new_project_fields.html.haml | 17 ++++--- ...ec.rb => accordion_item_component_spec.rb} | 24 +++++++--- spec/frontend/accordion/index_spec.js | 47 +++++++++++-------- 7 files changed, 69 insertions(+), 47 deletions(-) delete mode 100644 app/components/pajamas/accordion_component.html.haml create mode 100644 app/components/pajamas/accordion_item_component.html.haml rename app/components/pajamas/{accordion_component.rb => accordion_item_component.rb} (75%) rename spec/components/pajamas/{accordion_component_spec.rb => accordion_item_component_spec.rb} (53%) diff --git a/app/assets/javascripts/accordion/index.js b/app/assets/javascripts/accordion/index.js index 432c469260e31f..44296d44465e88 100644 --- a/app/assets/javascripts/accordion/index.js +++ b/app/assets/javascripts/accordion/index.js @@ -7,7 +7,7 @@ export default (el) => { if (!el) return; const accordionTrigger = el.querySelector('button'); - const accordionItem = el.querySelector('#accordion-item'); + const accordionItem = el.querySelector('.accordion-item'); const iconClass = 's16 gl-icon gl-button-icon js-chevron-icon'; const chevronRight = spriteIcon('chevron-right', iconClass); const chevronDown = spriteIcon('chevron-down', iconClass); @@ -19,10 +19,12 @@ export default (el) => { if (accordionItem.classList.contains('show')) { // eslint-disable-next-line no-unsanitized/property chevronIcon.outerHTML = chevronDown; + accordionTrigger.setAttribute('aria-expanded', 'true'); return; } // eslint-disable-next-line no-unsanitized/property chevronIcon.outerHTML = chevronRight; + accordionTrigger.setAttribute('aria-expanded', 'false'); }); }; diff --git a/app/components/pajamas/accordion_component.html.haml b/app/components/pajamas/accordion_component.html.haml deleted file mode 100644 index d3c2e6ecb1a141..00000000000000 --- a/app/components/pajamas/accordion_component.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -.gl-accordion-item - %h3.gl-accordion-item-header - = render Pajamas::ButtonComponent.new(variant: :link, icon: icon, icon_classes: "js-chevron-icon", button_options: { aria_controls: "accordion-item" }) do - = @title - - .gl-mt-3.gl-font-base.collapse{ id: 'accordion-item', **body_class } - = @body diff --git a/app/components/pajamas/accordion_item_component.html.haml b/app/components/pajamas/accordion_item_component.html.haml new file mode 100644 index 00000000000000..5b1b99f617b335 --- /dev/null +++ b/app/components/pajamas/accordion_item_component.html.haml @@ -0,0 +1,7 @@ +.gl-accordion-item + %h3.gl-accordion-item-header + = render Pajamas::ButtonComponent.new(variant: :link, icon: icon, icon_classes: "js-chevron-icon", button_options: { "aria-controls": "accordion-item", "aria-expanded": expanded }) do + = @title + + .accordion-item.gl-mt-3.gl-font-base.collapse{ **body_class } + = content diff --git a/app/components/pajamas/accordion_component.rb b/app/components/pajamas/accordion_item_component.rb similarity index 75% rename from app/components/pajamas/accordion_component.rb rename to app/components/pajamas/accordion_item_component.rb index b98ac5088c4f13..e489d31b3644c5 100644 --- a/app/components/pajamas/accordion_component.rb +++ b/app/components/pajamas/accordion_item_component.rb @@ -2,13 +2,11 @@ # Renders a accordion component module Pajamas - class AccordionComponent < Pajamas::Component + class AccordionItemComponent < Pajamas::Component # @param [String] title - # @param [String] body # @param [Symbol] state - def initialize(title: nil, body: nil, state: :closed) + def initialize(title: nil, state: :closed) @title = title - @body = body @state = filter_attribute(state.to_sym, STATE_OPTIONS) end @@ -23,5 +21,9 @@ def icon def body_class @state == :opened ? { class: 'show' } : {} end + + def expanded + @state == :opened + end end end diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml index 9f919d95041024..302e7e9bcd5eb0 100644 --- a/app/views/projects/_new_project_fields.html.haml +++ b/app/views/projects/_new_project_fields.html.haml @@ -93,16 +93,15 @@ = link_to _('Learn more.'), help_page_path('user/application_security/sast/index'), target: '_blank', rel: 'noopener noreferrer', data: { track_action: 'followed' } - if display_sha256_repository - .form-group.gl-mb-6 - - sha256_component = render Pajamas::CheckboxTagComponent.new(name: 'project[use_sha256_repository]') do |c| - - c.with_label do - = s_('ProjectsNew|Use SHA-256 for repository hashing algorithm') - = render_if_exists 'shared/experimental_badge_tag' - - c.with_help_text do - = s_("ProjectsNew|Might break existing functionality with other repositories or APIs. It's not possible to change SHA-256 repositories back to the default SHA-1 hashing algorithm.") + #js-experimental-setting-accordion.form-group.gl-mb-6 + = render Pajamas::AccordionItemComponent.new(title: s_("ProjectsNew|Experimental settings"), state: :closed) do + = render Pajamas::CheckboxTagComponent.new(name: 'project[use_sha256_repository]') do |c| + - c.with_label do + = s_('ProjectsNew|Use SHA-256 for repository hashing algorithm') + = render_if_exists 'shared/experimental_badge_tag' + - c.with_help_text do + = s_("ProjectsNew|Might break existing functionality with other repositories or APIs. It's not possible to change SHA-256 repositories back to the default SHA-1 hashing algorithm.") - #js-experimental-setting-accordion - = render Pajamas::AccordionComponent.new(title: s_("ProjectsNew|Experimental settings"), body: sha256_component, state: :closed) -# this partial is from JiHu, see details in https://jihulab.com/gitlab-cn/gitlab/-/merge_requests/675 = render_if_exists 'shared/other_project_options', f: f, visibility_level: visibility_level, track_label: track_label diff --git a/spec/components/pajamas/accordion_component_spec.rb b/spec/components/pajamas/accordion_item_component_spec.rb similarity index 53% rename from spec/components/pajamas/accordion_component_spec.rb rename to spec/components/pajamas/accordion_item_component_spec.rb index aa12118178dd2e..10aef4a44ad37e 100644 --- a/spec/components/pajamas/accordion_component_spec.rb +++ b/spec/components/pajamas/accordion_item_component_spec.rb @@ -2,24 +2,26 @@ require "spec_helper" -RSpec.describe Pajamas::AccordionComponent, type: :component, feature_category: :shared do +RSpec.describe Pajamas::AccordionItemComponent, type: :component, feature_category: :shared do let(:title) { "This is a title" } - let(:body) { "This is the body" } + let(:content) { "This is the content" } let(:state) { :opened } before do - render_inline(described_class.new(title: title, body: body, state: state)) + render_inline(described_class.new(title: title, state: state)) do |_c| + content + end end describe "title param" do it "is shown inside the accordion" do - expect(page).to have_content(title) + expect(page).to have_button(title) end end - describe "body param" do + describe "content" do it "is shown inside the accordion" do - expect(page).to have_content(body) + expect(page).to have_css ".accordion-item", text: content end end @@ -31,11 +33,15 @@ it "renders a chevron-down icon" do expect(page).to have_selector('[data-testid="chevron-down-icon"]') end + + it "renders a button with the correct aria-expanded value" do + expect(page).to have_selector('button[aria-expanded="true"]') + end end describe "state (closed) param" do before do - render_inline(described_class.new(title: title, body: body, state: :closed)) + render_inline(described_class.new(title: title, state: :closed)) end it "does not render the show class" do @@ -45,5 +51,9 @@ it "renders a chevron-right icon" do expect(page).to have_selector('[data-testid="chevron-right-icon"]') end + + it "renders a button with the correct aria-expanded value" do + expect(page).to have_selector('button[aria-expanded="false"]') + end end end diff --git a/spec/frontend/accordion/index_spec.js b/spec/frontend/accordion/index_spec.js index 2dd83de65f9d30..10ce1cdd00e43a 100644 --- a/spec/frontend/accordion/index_spec.js +++ b/spec/frontend/accordion/index_spec.js @@ -4,7 +4,7 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; describe('Init Accordion component', () => { beforeEach(() => { setHTMLFixture( - '
', + '
', ); initAccordion(document.querySelector('.js-accordion')); }); @@ -12,32 +12,41 @@ describe('Init Accordion component', () => { afterEach(() => resetHTMLFixture()); const findAccordionTrigger = () => document.querySelector('button'); - const findAccordionItem = () => document.querySelector('#accordion-item'); + const findAccordionItem = () => document.querySelector('.accordion-item'); const findSvgIconLink = () => document.querySelector('use').getAttribute('xlink:href'); - it('adds a `show` class to the accordion item when expanded', () => { - findAccordionTrigger().click(); - expect(findAccordionItem().classList.contains('show')).toBe(true); - }); + describe('expanded', () => { + beforeEach(() => findAccordionTrigger().click()); + + it('adds a `show` class to the accordion item', () => { + expect(findAccordionItem().classList.contains('show')).toBe(true); + }); - it('removes `show` class from the accordion item when collapsed', () => { - findAccordionTrigger().click(); // expands the accordion - expect(findAccordionItem().classList.contains('show')).toBe(true); + it('renders a chevron-down icon', () => { + expect(findSvgIconLink()).toContain('#chevron-down'); + }); - findAccordionTrigger().click(); // collapses the accordion - expect(findAccordionItem().classList.contains('show')).toBe(false); + it('renders a button with the correct aria-expanded value', () => { + expect(findAccordionTrigger().getAttribute('aria-expanded')).toBe('true'); + }); }); - it('renders a chevron-down icon when expanded', () => { - findAccordionTrigger().click(); + describe('collapsed', () => { + beforeEach(() => { + findAccordionTrigger().click(); // expands the accordion + findAccordionTrigger().click(); // collapses the accordion + }); - expect(findSvgIconLink()).toContain('#chevron-down'); - }); + it('removes `show` class from the accordion item', () => { + expect(findAccordionItem().classList.contains('show')).toBe(false); + }); - it('renders a chevron-right icon when collapsed', () => { - findAccordionTrigger().click(); // expands the accordion - findAccordionTrigger().click(); // collapses the accordion + it('renders a chevron-right icon', () => { + expect(findSvgIconLink()).toContain('#chevron-right'); + }); - expect(findSvgIconLink()).toContain('#chevron-right'); + it('renders a button with the correct aria-expanded value', () => { + expect(findAccordionTrigger().getAttribute('aria-expanded')).toBe('false'); + }); }); }); -- GitLab