diff options
Diffstat (limited to 'spec/lib/sidebars')
88 files changed, 1964 insertions, 167 deletions
diff --git a/spec/lib/sidebars/admin/menus/abuse_reports_menu_spec.rb b/spec/lib/sidebars/admin/menus/abuse_reports_menu_spec.rb new file mode 100644 index 00000000000..5926852ff57 --- /dev/null +++ b/spec/lib/sidebars/admin/menus/abuse_reports_menu_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::AbuseReportsMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/abuse_reports', + title: _('Abuse Reports'), + icon: 'slight-frown' + + it_behaves_like 'Admin menu without sub menus', active_routes: { controller: :abuse_reports } + + describe '#pill_count' do + let_it_be(:user) { create(:user, :admin) } + + let(:context) { Sidebars::Context.new(current_user: user, container: nil) } + + subject { described_class.new(context) } + + it 'returns zero when there are no abuse reports' do + expect(subject.pill_count).to eq 0 + end + + it 'memoizes the query' do + subject.pill_count + + control = ActiveRecord::QueryRecorder.new do + subject.pill_count + end + + expect(control.count).to eq 0 + end + + context 'when there are abuse reports' do + it 'returns the number of abuse reports' do + create_list(:abuse_report, 2) + + expect(subject.pill_count).to eq 2 + end + end + end +end diff --git a/spec/lib/sidebars/admin/menus/admin_overview_menu_spec.rb b/spec/lib/sidebars/admin/menus/admin_overview_menu_spec.rb new file mode 100644 index 00000000000..d076e73fdd1 --- /dev/null +++ b/spec/lib/sidebars/admin/menus/admin_overview_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::AdminOverviewMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin', + title: s_('Admin|Overview'), + icon: 'overview' + + it_behaves_like 'Admin menu with sub menus' +end diff --git a/spec/lib/sidebars/admin/menus/admin_settings_menu_spec.rb b/spec/lib/sidebars/admin/menus/admin_settings_menu_spec.rb new file mode 100644 index 00000000000..4c9f603e99f --- /dev/null +++ b/spec/lib/sidebars/admin/menus/admin_settings_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::AdminSettingsMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/application_settings/general', + title: s_('Admin|Settings'), + icon: 'settings', + separated: true + + it_behaves_like 'Admin menu with sub menus' +end diff --git a/spec/lib/sidebars/admin/menus/analytics_menu_spec.rb b/spec/lib/sidebars/admin/menus/analytics_menu_spec.rb new file mode 100644 index 00000000000..b4aa6e9aeb6 --- /dev/null +++ b/spec/lib/sidebars/admin/menus/analytics_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::AnalyticsMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/dev_ops_reports', + title: s_('Admin|Analytics'), + icon: 'chart' + + it_behaves_like 'Admin menu with sub menus' +end diff --git a/spec/lib/sidebars/admin/menus/applications_menu_spec.rb b/spec/lib/sidebars/admin/menus/applications_menu_spec.rb new file mode 100644 index 00000000000..0346fa4adfa --- /dev/null +++ b/spec/lib/sidebars/admin/menus/applications_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::ApplicationsMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/applications', + title: s_('Admin|Applications'), + icon: 'applications' + + it_behaves_like 'Admin menu without sub menus', active_routes: { controller: :applications } +end diff --git a/spec/lib/sidebars/admin/menus/ci_cd_menu_spec.rb b/spec/lib/sidebars/admin/menus/ci_cd_menu_spec.rb new file mode 100644 index 00000000000..b0d46abbee2 --- /dev/null +++ b/spec/lib/sidebars/admin/menus/ci_cd_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::CiCdMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/runners', + title: s_('Admin|CI/CD'), + icon: 'rocket' + + it_behaves_like 'Admin menu with sub menus' +end diff --git a/spec/lib/sidebars/admin/menus/deploy_keys_menu_spec.rb b/spec/lib/sidebars/admin/menus/deploy_keys_menu_spec.rb new file mode 100644 index 00000000000..f0ee846fb42 --- /dev/null +++ b/spec/lib/sidebars/admin/menus/deploy_keys_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::DeployKeysMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/deploy_keys', + title: s_('Admin|Deploy Keys'), + icon: 'key' + + it_behaves_like 'Admin menu without sub menus', active_routes: { controller: :deploy_keys } +end diff --git a/spec/lib/sidebars/admin/menus/labels_menu_spec.rb b/spec/lib/sidebars/admin/menus/labels_menu_spec.rb new file mode 100644 index 00000000000..63e4927ab0d --- /dev/null +++ b/spec/lib/sidebars/admin/menus/labels_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::LabelsMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/labels', + title: s_('Admin|Labels'), + icon: 'labels' + + it_behaves_like 'Admin menu without sub menus', active_routes: { controller: :labels } +end diff --git a/spec/lib/sidebars/admin/menus/messages_menu_spec.rb b/spec/lib/sidebars/admin/menus/messages_menu_spec.rb new file mode 100644 index 00000000000..14979b7e47a --- /dev/null +++ b/spec/lib/sidebars/admin/menus/messages_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::MessagesMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/broadcast_messages', + title: s_('Admin|Messages'), + icon: 'messages' + + it_behaves_like 'Admin menu without sub menus', active_routes: { controller: :broadcast_messages } +end diff --git a/spec/lib/sidebars/admin/menus/monitoring_menu_spec.rb b/spec/lib/sidebars/admin/menus/monitoring_menu_spec.rb new file mode 100644 index 00000000000..0483159da7a --- /dev/null +++ b/spec/lib/sidebars/admin/menus/monitoring_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::MonitoringMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/system_info', + title: s_('Admin|Monitoring'), + icon: 'monitor' + + it_behaves_like 'Admin menu with sub menus' +end diff --git a/spec/lib/sidebars/admin/menus/system_hooks_menu_spec.rb b/spec/lib/sidebars/admin/menus/system_hooks_menu_spec.rb new file mode 100644 index 00000000000..a2d0b851091 --- /dev/null +++ b/spec/lib/sidebars/admin/menus/system_hooks_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Menus::SystemHooksMenu, feature_category: :navigation do + it_behaves_like 'Admin menu', + link: '/admin/hooks', + title: s_('Admin|System Hooks'), + icon: 'hook' + + it_behaves_like 'Admin menu without sub menus', active_routes: { controller: :hooks } +end diff --git a/spec/lib/sidebars/admin/panel_spec.rb b/spec/lib/sidebars/admin/panel_spec.rb new file mode 100644 index 00000000000..9c362f527f5 --- /dev/null +++ b/spec/lib/sidebars/admin/panel_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Admin::Panel, feature_category: :navigation do + let_it_be(:user) { build(:admin) } + + let(:context) { Sidebars::Context.new(current_user: user, container: nil) } + let(:panel) { described_class.new(context) } + + subject { described_class.new(context) } + + describe '#aria_label' do + it 'returns the correct aria label' do + expect(panel.aria_label).to eq(_('Admin Area')) + end + end + + describe '#super_sidebar_context_header' do + it 'returns a hash with the correct title and icon' do + expected_header = { + title: panel.aria_label, + icon: 'admin' + } + + expect(panel.super_sidebar_context_header).to eq(expected_header) + end + end + + it_behaves_like 'a panel with uniquely identifiable menu items' +end diff --git a/spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb b/spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb new file mode 100644 index 00000000000..e0c05379a9e --- /dev/null +++ b/spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' + +RSpec.describe Sidebars::Concerns::SuperSidebarPanel, feature_category: :navigation do + let(:menu_class_foo) { Class.new(Sidebars::Menu) } + let(:menu_foo) { menu_class_foo.new({}) } + + let(:menu_class_bar) do + Class.new(Sidebars::Menu) do + def title + "Bar" + end + + def pick_into_super_sidebar? + true + end + end + end + + let(:menu_bar) { menu_class_bar.new({}) } + + subject do + Class.new(Sidebars::Panel) do + include Sidebars::Concerns::SuperSidebarPanel + end.new({}) + end + + before do + allow(menu_foo).to receive(:render?).and_return(true) + allow(menu_bar).to receive(:render?).and_return(true) + end + + describe '#pick_from_old_menus' do + it 'removes items with #pick_into_super_sidebar? from a list and adds them to the panel menus' do + old_menus = [menu_foo, menu_bar] + + subject.pick_from_old_menus(old_menus) + + expect(old_menus).to include(menu_foo) + expect(subject.renderable_menus).not_to include(menu_foo) + + expect(old_menus).not_to include(menu_bar) + expect(subject.renderable_menus).to include(menu_bar) + end + end + + describe '#transform_old_menus' do + let(:uncategorized_menu) { ::Sidebars::UncategorizedMenu.new({}) } + + let(:menu_item) do + Sidebars::MenuItem.new(title: 'foo3', link: 'foo3', active_routes: { controller: 'barc' }, + super_sidebar_parent: menu_class_foo) + end + + let(:nil_menu_item) { Sidebars::NilMenuItem.new(item_id: :nil_item) } + let(:existing_item) do + Sidebars::MenuItem.new( + item_id: :exists, + title: 'Existing item', + link: 'foo2', + active_routes: { controller: 'foo2' } + ) + end + + let(:current_menus) { [menu_foo, uncategorized_menu] } + + before do + allow(menu_bar).to receive(:serialize_as_menu_item_args).and_return(nil) + menu_foo.add_item(existing_item) + end + + context 'for Menus with Menu Items' do + before do + menu_bar.add_item(menu_item) + menu_bar.add_item(nil_menu_item) + end + + it 'adds Menu Items to defined super_sidebar_parent' do + subject.transform_old_menus(current_menus, menu_bar) + + expect(menu_foo.renderable_items).to eq([existing_item, menu_item]) + expect(uncategorized_menu.renderable_items).to eq([]) + end + + it 'replaces placeholder Menu Items in the defined super_sidebar_parent' do + menu_foo.insert_item_before(:exists, nil_menu_item) + allow(menu_item).to receive(:item_id).and_return(:nil_item) + + subject.transform_old_menus(current_menus, menu_bar) + + expect(menu_foo.renderable_items).to eq([menu_item, existing_item]) + expect(uncategorized_menu.renderable_items).to eq([]) + end + + it 'considers Menu Items uncategorized if super_sidebar_parent is nil' do + allow(menu_item).to receive(:super_sidebar_parent).and_return(nil) + subject.transform_old_menus(current_menus, menu_bar) + + expect(menu_foo.renderable_items).to eq([existing_item]) + expect(uncategorized_menu.renderable_items).to eq([menu_item]) + end + + it 'considers Menu Items uncategorized if super_sidebar_parent cannot be found' do + allow(menu_item).to receive(:super_sidebar_parent).and_return(menu_class_bar) + subject.transform_old_menus(current_menus, menu_bar) + + expect(menu_foo.renderable_items).to eq([existing_item]) + expect(uncategorized_menu.renderable_items).to eq([menu_item]) + end + + it 'considers Menu Items deleted if super_sidebar_parent is Sidebars::NilMenuItem' do + allow(menu_item).to receive(:super_sidebar_parent).and_return(::Sidebars::NilMenuItem) + subject.transform_old_menus(current_menus, menu_bar) + + expect(menu_foo.renderable_items).to eq([existing_item]) + expect(uncategorized_menu.renderable_items).to eq([]) + end + end + + it 'converts "solo" top-level Menu entry to Menu Item' do + allow(Sidebars::MenuItem).to receive(:new).and_return(menu_item) + allow(menu_bar).to receive(:serialize_as_menu_item_args).and_return({}) + + subject.transform_old_menus(current_menus, menu_bar) + + expect(menu_foo.renderable_items).to eq([existing_item, menu_item]) + expect(uncategorized_menu.renderable_items).to eq([]) + end + + it 'drops "solo" top-level Menu entries, if they serialize to nil' do + allow(Sidebars::MenuItem).to receive(:new).and_return(menu_item) + allow(menu_bar).to receive(:serialize_as_menu_item_args).and_return(nil) + + subject.transform_old_menus(current_menus, menu_bar) + + expect(menu_foo.renderable_items).to eq([existing_item]) + expect(uncategorized_menu.renderable_items).to eq([]) + end + end +end diff --git a/spec/lib/sidebars/groups/menus/group_information_menu_spec.rb b/spec/lib/sidebars/groups/menus/group_information_menu_spec.rb index 1b27db53b6f..4a0301e2f2d 100644 --- a/spec/lib/sidebars/groups/menus/group_information_menu_spec.rb +++ b/spec/lib/sidebars/groups/menus/group_information_menu_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sidebars::Groups::Menus::GroupInformationMenu do +RSpec.describe Sidebars::Groups::Menus::GroupInformationMenu, feature_category: :navigation do let_it_be(:owner) { create(:user) } let_it_be(:root_group) do build(:group, :private).tap do |g| @@ -14,6 +14,10 @@ RSpec.describe Sidebars::Groups::Menus::GroupInformationMenu do let(:user) { owner } let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) } + it_behaves_like 'not serializable as super_sidebar_menu_args' do + let(:menu) { described_class.new(context) } + end + describe '#title' do subject { described_class.new(context).title } diff --git a/spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb b/spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb deleted file mode 100644 index a79e5182f45..00000000000 --- a/spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Sidebars::Groups::Menus::InviteTeamMembersMenu do - let_it_be(:owner) { create(:user) } - let_it_be(:guest) { create(:user) } - let_it_be(:group) do - build(:group).tap do |g| - g.add_owner(owner) - end - end - - let(:context) { Sidebars::Groups::Context.new(current_user: owner, container: group) } - - subject(:invite_menu) { described_class.new(context) } - - context 'when the group is viewed by an owner of the group' do - describe '#render?' do - it 'renders the Invite team members link' do - expect(invite_menu.render?).to eq(true) - end - - context 'when the group already has at least 2 members' do - before do - group.add_guest(guest) - end - - it 'does not render the link' do - expect(invite_menu.render?).to eq(false) - end - end - end - - describe '#title' do - it 'displays the correct Invite team members text for the link in the side nav' do - expect(invite_menu.title).to eq('Invite members') - end - end - end - - context 'when the group is viewed by a guest user without admin permissions' do - let(:context) { Sidebars::Groups::Context.new(current_user: guest, container: group) } - - before do - group.add_guest(guest) - end - - describe '#render?' do - it 'does not render the link' do - expect(subject.render?).to eq(false) - end - end - end -end diff --git a/spec/lib/sidebars/groups/menus/issues_menu_spec.rb b/spec/lib/sidebars/groups/menus/issues_menu_spec.rb index 3d55eb3af40..415011e0027 100644 --- a/spec/lib/sidebars/groups/menus/issues_menu_spec.rb +++ b/spec/lib/sidebars/groups/menus/issues_menu_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sidebars::Groups::Menus::IssuesMenu do +RSpec.describe Sidebars::Groups::Menus::IssuesMenu, feature_category: :navigation do let_it_be(:owner) { create(:user) } let_it_be(:group) do build(:group, :private).tap do |g| @@ -51,4 +51,16 @@ RSpec.describe Sidebars::Groups::Menus::IssuesMenu do it_behaves_like 'pill_count formatted results' do let(:count_service) { ::Groups::OpenIssuesCountService } end + + it_behaves_like 'serializable as super_sidebar_menu_args' do + let(:extra_attrs) do + { + item_id: :group_issue_list, + active_routes: { path: 'groups#issues' }, + pill_count: menu.pill_count, + has_pill: menu.has_pill?, + super_sidebar_parent: Sidebars::Groups::SuperSidebarMenus::PlanMenu + } + end + end end diff --git a/spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb b/spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb index 5bf8be9d6e5..8eb9a22e3e1 100644 --- a/spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb +++ b/spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sidebars::Groups::Menus::KubernetesMenu, :request_store do +RSpec.describe Sidebars::Groups::Menus::KubernetesMenu, :request_store, feature_category: :navigation do let_it_be(:owner) { create(:user) } let_it_be(:group) do build(:group, :private).tap do |g| @@ -14,6 +14,15 @@ RSpec.describe Sidebars::Groups::Menus::KubernetesMenu, :request_store do let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) } let(:menu) { described_class.new(context) } + it_behaves_like 'serializable as super_sidebar_menu_args' do + let(:extra_attrs) do + { + super_sidebar_parent: Sidebars::Groups::SuperSidebarMenus::OperationsMenu, + item_id: :group_kubernetes_clusters + } + end + end + describe '#render?' do context 'when user can read clusters' do it 'returns true' do diff --git a/spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb b/spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb index 3aceff29d6d..a4421226eeb 100644 --- a/spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb +++ b/spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sidebars::Groups::Menus::MergeRequestsMenu do +RSpec.describe Sidebars::Groups::Menus::MergeRequestsMenu, feature_category: :navigation do let_it_be(:owner) { create(:user) } let_it_be(:group) do build(:group, :private).tap do |g| @@ -33,4 +33,15 @@ RSpec.describe Sidebars::Groups::Menus::MergeRequestsMenu do it_behaves_like 'pill_count formatted results' do let(:count_service) { ::Groups::MergeRequestsCountService } end + + it_behaves_like 'serializable as super_sidebar_menu_args' do + let(:extra_attrs) do + { + item_id: :group_merge_request_list, + pill_count: menu.pill_count, + has_pill: menu.has_pill?, + super_sidebar_parent: Sidebars::Groups::SuperSidebarMenus::CodeMenu + } + end + end end diff --git a/spec/lib/sidebars/groups/menus/observability_menu_spec.rb b/spec/lib/sidebars/groups/menus/observability_menu_spec.rb index 5b993cd6f28..20af8ea00be 100644 --- a/spec/lib/sidebars/groups/menus/observability_menu_spec.rb +++ b/spec/lib/sidebars/groups/menus/observability_menu_spec.rb @@ -20,26 +20,74 @@ RSpec.describe Sidebars::Groups::Menus::ObservabilityMenu do allow(menu).to receive(:can?).and_call_original end - context 'when observability is enabled' do + context 'when observability#explore is allowed' do before do - allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(true) + allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, :explore).and_return(true) end it 'returns true' do expect(menu.render?).to eq true - expect(Gitlab::Observability).to have_received(:observability_enabled?).with(user, group) + expect(Gitlab::Observability).to have_received(:allowed_for_action?).with(user, group, :explore) end end - context 'when observability is disabled' do + context 'when observability#explore is not allowed' do before do - allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(false) + allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, :explore).and_return(false) end it 'returns false' do expect(menu.render?).to eq false - expect(Gitlab::Observability).to have_received(:observability_enabled?).with(user, group) + expect(Gitlab::Observability).to have_received(:allowed_for_action?).with(user, group, :explore) end end end + + describe "Menu items" do + before do + allow(Gitlab::Observability).to receive(:allowed_for_action?).and_return(false) + end + + subject { find_menu(menu, item_id) } + + shared_examples 'observability menu entry' do + context 'when action is allowed' do + before do + allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, item_id).and_return(true) + end + + it 'the menu item is added to list of menu items' do + is_expected.not_to be_nil + end + end + + context 'when action is not allowed' do + before do + allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, item_id).and_return(false) + end + + it 'the menu item is added to list of menu items' do + is_expected.to be_nil + end + end + end + + describe 'Explore' do + it_behaves_like 'observability menu entry' do + let(:item_id) { :explore } + end + end + + describe 'Datasources' do + it_behaves_like 'observability menu entry' do + let(:item_id) { :datasources } + end + end + end + + private + + def find_menu(menu, item) + menu.renderable_items.find { |i| i.item_id == item } + end end diff --git a/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb b/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb index ce368ad5bd6..382ee07e458 100644 --- a/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb +++ b/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sidebars::Groups::Menus::PackagesRegistriesMenu do +RSpec.describe Sidebars::Groups::Menus::PackagesRegistriesMenu, feature_category: :navigation do let_it_be(:owner) { create(:user) } let_it_be_with_reload(:group) do build(:group, :private).tap do |g| @@ -16,6 +16,8 @@ RSpec.describe Sidebars::Groups::Menus::PackagesRegistriesMenu do let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) } let(:menu) { described_class.new(context) } + it_behaves_like 'not serializable as super_sidebar_menu_args' + describe '#render?' do context 'when menu has menu items to show' do it 'returns true' do diff --git a/spec/lib/sidebars/groups/menus/scope_menu_spec.rb b/spec/lib/sidebars/groups/menus/scope_menu_spec.rb index 4b77a09117a..d3aceaf422b 100644 --- a/spec/lib/sidebars/groups/menus/scope_menu_spec.rb +++ b/spec/lib/sidebars/groups/menus/scope_menu_spec.rb @@ -2,14 +2,26 @@ require 'spec_helper' -RSpec.describe Sidebars::Groups::Menus::ScopeMenu do +RSpec.describe Sidebars::Groups::Menus::ScopeMenu, feature_category: :navigation do let(:group) { build(:group) } let(:user) { group.owner } let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) } + let(:menu) { described_class.new(context) } describe '#extra_nav_link_html_options' do - subject { described_class.new(context).extra_nav_link_html_options } + subject { menu.extra_nav_link_html_options } specify { is_expected.to match(hash_including(class: 'context-header has-tooltip', title: context.group.name)) } end + + it_behaves_like 'serializable as super_sidebar_menu_args' do + let(:extra_attrs) do + { + sprite_icon: 'group', + super_sidebar_parent: ::Sidebars::StaticMenu, + title: _('Group overview'), + item_id: :group_overview + } + end + end end diff --git a/spec/lib/sidebars/groups/menus/settings_menu_spec.rb b/spec/lib/sidebars/groups/menus/settings_menu_spec.rb index c5246fe93dd..bc30d7628af 100644 --- a/spec/lib/sidebars/groups/menus/settings_menu_spec.rb +++ b/spec/lib/sidebars/groups/menus/settings_menu_spec.rb @@ -25,6 +25,12 @@ RSpec.describe Sidebars::Groups::Menus::SettingsMenu, :with_license do end end + describe '#separated?' do + it 'returns true' do + expect(menu.separated?).to be true + end + end + describe 'Menu items' do subject { menu.renderable_items.find { |e| e.item_id == item_id } } diff --git a/spec/lib/sidebars/groups/super_sidebar_menus/analyze_menu_spec.rb b/spec/lib/sidebars/groups/super_sidebar_menus/analyze_menu_spec.rb new file mode 100644 index 00000000000..3d3d304a5a0 --- /dev/null +++ b/spec/lib/sidebars/groups/super_sidebar_menus/analyze_menu_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Groups::SuperSidebarMenus::AnalyzeMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Analyze")) + expect(subject.sprite_icon).to eq("chart") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :cycle_analytics, + :ci_cd_analytics, + :contribution_analytics, + :devops_adoption, + :insights, + :issues_analytics, + :productivity_analytics, + :repository_analytics + ]) + end +end diff --git a/spec/lib/sidebars/groups/super_sidebar_menus/build_menu_spec.rb b/spec/lib/sidebars/groups/super_sidebar_menus/build_menu_spec.rb new file mode 100644 index 00000000000..9437e11c1b6 --- /dev/null +++ b/spec/lib/sidebars/groups/super_sidebar_menus/build_menu_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Groups::SuperSidebarMenus::BuildMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Build")) + expect(subject.sprite_icon).to eq("rocket") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :runners + ]) + end +end diff --git a/spec/lib/sidebars/groups/super_sidebar_menus/manage_menu_spec.rb b/spec/lib/sidebars/groups/super_sidebar_menus/manage_menu_spec.rb new file mode 100644 index 00000000000..916d0942db2 --- /dev/null +++ b/spec/lib/sidebars/groups/super_sidebar_menus/manage_menu_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Groups::SuperSidebarMenus::ManageMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Manage")) + expect(subject.sprite_icon).to eq("users") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :activity, + :members, + :labels + ]) + end +end diff --git a/spec/lib/sidebars/groups/super_sidebar_menus/monitor_menu_spec.rb b/spec/lib/sidebars/groups/super_sidebar_menus/monitor_menu_spec.rb new file mode 100644 index 00000000000..759975856b8 --- /dev/null +++ b/spec/lib/sidebars/groups/super_sidebar_menus/monitor_menu_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Groups::SuperSidebarMenus::MonitorMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Monitor")) + expect(subject.sprite_icon).to eq("monitor") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :explore, + :datasources + ]) + end +end diff --git a/spec/lib/sidebars/groups/super_sidebar_menus/operations_menu_spec.rb b/spec/lib/sidebars/groups/super_sidebar_menus/operations_menu_spec.rb new file mode 100644 index 00000000000..e9c2701021c --- /dev/null +++ b/spec/lib/sidebars/groups/super_sidebar_menus/operations_menu_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Groups::SuperSidebarMenus::OperationsMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Operate")) + expect(subject.sprite_icon).to eq("deployments") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :dependency_proxy, + :packages_registry, + :container_registry, + :group_kubernetes_clusters + ]) + end +end diff --git a/spec/lib/sidebars/groups/super_sidebar_menus/plan_menu_spec.rb b/spec/lib/sidebars/groups/super_sidebar_menus/plan_menu_spec.rb new file mode 100644 index 00000000000..1ac2cf87236 --- /dev/null +++ b/spec/lib/sidebars/groups/super_sidebar_menus/plan_menu_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Groups::SuperSidebarMenus::PlanMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Plan")) + expect(subject.sprite_icon).to eq("planning") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :group_issue_list, + :group_epic_list, + :issue_boards, + :epic_boards, + :roadmap, + :milestones, + :iterations, + :group_wiki, + :crm_contacts, + :crm_organizations + ]) + end +end diff --git a/spec/lib/sidebars/groups/super_sidebar_menus/secure_menu_spec.rb b/spec/lib/sidebars/groups/super_sidebar_menus/secure_menu_spec.rb new file mode 100644 index 00000000000..9eb81dda462 --- /dev/null +++ b/spec/lib/sidebars/groups/super_sidebar_menus/secure_menu_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Groups::SuperSidebarMenus::SecureMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Secure")) + expect(subject.sprite_icon).to eq("shield") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :security_dashboard, + :vulnerability_report, + :audit_events, + :compliance, + :scan_policies + ]) + end +end diff --git a/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb b/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb new file mode 100644 index 00000000000..5035da9c488 --- /dev/null +++ b/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Groups::SuperSidebarPanel, feature_category: :navigation do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group).tap { |group| group.add_owner(user) } } + + let(:context) do + Sidebars::Groups::Context.new( + current_user: user, + container: group, + is_super_sidebar: true, + # Turn features off that do not add/remove menu items + show_promotions: false, + show_discover_group_security: false + ) + end + + subject { described_class.new(context) } + + it 'implements #super_sidebar_context_header' do + expect(subject.super_sidebar_context_header).to eq( + { + title: group.name, + avatar: group.avatar_url, + id: group.id + }) + end + + describe '#renderable_menus' do + let(:category_menu) do + [ + Sidebars::StaticMenu, + Sidebars::Groups::SuperSidebarMenus::ManageMenu, + Sidebars::Groups::SuperSidebarMenus::PlanMenu, + Sidebars::Groups::SuperSidebarMenus::CodeMenu, + Sidebars::Groups::SuperSidebarMenus::BuildMenu, + Sidebars::Groups::SuperSidebarMenus::SecureMenu, + Sidebars::Groups::SuperSidebarMenus::OperationsMenu, + Sidebars::Groups::SuperSidebarMenus::MonitorMenu, + Sidebars::Groups::SuperSidebarMenus::AnalyzeMenu, + Sidebars::UncategorizedMenu, + Sidebars::Groups::Menus::SettingsMenu + ] + end + + it "is exposed as a renderable menu" do + expect(subject.instance_variable_get(:@menus).map(&:class)).to eq(category_menu) + end + end + + it_behaves_like 'a panel with uniquely identifiable menu items' + it_behaves_like 'a panel with all menu_items categorized' +end diff --git a/spec/lib/sidebars/menu_item_spec.rb b/spec/lib/sidebars/menu_item_spec.rb index 15804f51934..84bc3430260 100644 --- a/spec/lib/sidebars/menu_item_spec.rb +++ b/spec/lib/sidebars/menu_item_spec.rb @@ -18,4 +18,14 @@ RSpec.describe Sidebars::MenuItem do expect(menu_item.container_html_options).to eq html_options end end + + describe "#serialize_for_super_sidebar" do + let(:html_options) { { class: 'custom-class' } } + + subject { menu_item.serialize_for_super_sidebar } + + it 'includes custom CSS classes' do + expect(subject[:link_classes]).to be('custom-class') + end + end end diff --git a/spec/lib/sidebars/menu_spec.rb b/spec/lib/sidebars/menu_spec.rb index 53a889c2db8..4f77cb3aed4 100644 --- a/spec/lib/sidebars/menu_spec.rb +++ b/spec/lib/sidebars/menu_spec.rb @@ -2,9 +2,10 @@ require 'spec_helper' -RSpec.describe Sidebars::Menu do +RSpec.describe Sidebars::Menu, feature_category: :navigation do let(:menu) { described_class.new(context) } let(:context) { Sidebars::Context.new(current_user: nil, container: nil) } + let(:nil_menu_item) { Sidebars::NilMenuItem.new(item_id: :foo) } describe '#all_active_routes' do @@ -21,6 +22,94 @@ RSpec.describe Sidebars::Menu do end end + describe '#serialize_for_super_sidebar' do + before do + allow(menu).to receive(:title).and_return('Title') + allow(menu).to receive(:active_routes).and_return({ path: 'foo' }) + end + + it 'returns a tree-like structure of itself and all menu items' do + menu.add_item(Sidebars::MenuItem.new( + item_id: 'id1', + title: 'Is active', + link: 'foo2', + active_routes: { controller: 'fooc' } + )) + menu.add_item(Sidebars::MenuItem.new( + item_id: 'id2', + title: 'Not active', + link: 'foo3', + active_routes: { controller: 'barc' }, + has_pill: true, + pill_count: 10 + )) + menu.add_item(nil_menu_item) + + allow(context).to receive(:route_is_active).and_return(->(x) { x[:controller] == 'fooc' }) + + expect(menu.serialize_for_super_sidebar).to eq( + { + title: "Title", + icon: nil, + link: "foo2", + is_active: true, + pill_count: nil, + separated: false, + items: [ + { + id: 'id1', + title: "Is active", + icon: nil, + link: "foo2", + is_active: true, + pill_count: nil, + link_classes: nil + }, + { + id: 'id2', + title: "Not active", + icon: nil, + link: "foo3", + is_active: false, + pill_count: 10, + link_classes: nil + } + ] + }) + end + + it 'returns pill data if defined' do + allow(menu).to receive(:has_pill?).and_return(true) + allow(menu).to receive(:pill_count).and_return('foo') + expect(menu.serialize_for_super_sidebar).to eq( + { + title: "Title", + icon: nil, + link: nil, + is_active: false, + pill_count: 'foo', + separated: false, + items: [] + }) + end + end + + describe '#serialize_as_menu_item_args' do + it 'returns hash of title, link, active_routes, container_html_options' do + allow(menu).to receive(:title).and_return('Title') + allow(menu).to receive(:active_routes).and_return({ path: 'foo' }) + allow(menu).to receive(:container_html_options).and_return({ class: 'foo' }) + allow(menu).to receive(:link).and_return('/link') + + expect(menu.serialize_as_menu_item_args).to eq({ + title: 'Title', + link: '/link', + active_routes: { path: 'foo' }, + container_html_options: { class: 'foo' } + }) + end + end + describe '#render?' do context 'when the menus has no items' do it 'returns false' do @@ -153,6 +242,47 @@ RSpec.describe Sidebars::Menu do end end + describe '#replace_placeholder' do + let(:item1) { Sidebars::NilMenuItem.new(item_id: :foo1) } + let(:item2) { Sidebars::MenuItem.new(item_id: :foo2, title: 'foo2', link: 'foo2', active_routes: {}) } + let(:item3) { Sidebars::NilMenuItem.new(item_id: :foo3) } + + subject { menu.instance_variable_get(:@items) } + + before do + menu.add_item(item1) + menu.add_item(item2) + menu.add_item(item3) + end + + context 'when a NilMenuItem reference element exists' do + it 'replaces the reference element with the provided item' do + item = Sidebars::MenuItem.new(item_id: :foo1, title: 'target', active_routes: {}, link: 'target') + menu.replace_placeholder(item) + + expect(subject).to eq [item, item2, item3] + end + end + + context 'when a MenuItem reference element exists' do + it 'does not replace the reference element and adds to the end of the list' do + item = Sidebars::MenuItem.new(item_id: :foo2, title: 'target', active_routes: {}, link: 'target') + menu.replace_placeholder(item) + + expect(subject).to eq [item1, item2, item3, item] + end + end + + context 'when reference element does not exist' do + it 'adds the element to the end of the list' do + item = Sidebars::MenuItem.new(item_id: :new_element, title: 'target', active_routes: {}, link: 'target') + menu.replace_placeholder(item) + + expect(subject).to eq [item1, item2, item3, item] + end + end + end + describe '#remove_element' do let(:item1) { Sidebars::MenuItem.new(title: 'foo1', link: 'foo1', active_routes: {}, item_id: :foo1) } let(:item2) { Sidebars::MenuItem.new(title: 'foo2', link: 'foo2', active_routes: {}, item_id: :foo2) } diff --git a/spec/lib/sidebars/panel_spec.rb b/spec/lib/sidebars/panel_spec.rb index b70a79361d0..2c1b9c73595 100644 --- a/spec/lib/sidebars/panel_spec.rb +++ b/spec/lib/sidebars/panel_spec.rb @@ -2,11 +2,12 @@ require 'spec_helper' -RSpec.describe Sidebars::Panel do +RSpec.describe Sidebars::Panel, feature_category: :navigation do let(:context) { Sidebars::Context.new(current_user: nil, container: nil) } let(:panel) { Sidebars::Panel.new(context) } let(:menu1) { Sidebars::Menu.new(context) } let(:menu2) { Sidebars::Menu.new(context) } + let(:menu3) { Sidebars::Menu.new(context) } describe '#renderable_menus' do it 'returns only renderable menus' do @@ -20,6 +21,31 @@ RSpec.describe Sidebars::Panel do end end + describe '#super_sidebar_menu_items' do + it "serializes every renderable menu and returns a flattened result" do + panel.add_menu(menu1) + panel.add_menu(menu2) + panel.add_menu(menu3) + + allow(menu1).to receive(:render?).and_return(true) + allow(menu1).to receive(:serialize_for_super_sidebar).and_return("foo") + + allow(menu2).to receive(:render?).and_return(false) + allow(menu2).to receive(:serialize_for_super_sidebar).and_return("i-should-not-appear-in-results") + + allow(menu3).to receive(:render?).and_return(true) + allow(menu3).to receive(:serialize_for_super_sidebar).and_return(%w[bar baz]) + + expect(panel.super_sidebar_menu_items).to eq(%w[foo bar baz]) + end + end + + describe '#super_sidebar_context_header' do + it 'raises `NotImplementedError`' do + expect { panel.super_sidebar_context_header }.to raise_error(NotImplementedError) + end + end + describe '#has_renderable_menus?' do it 'returns false when no renderable menus' do expect(panel.has_renderable_menus?).to be false diff --git a/spec/lib/sidebars/projects/menus/ci_cd_menu_spec.rb b/spec/lib/sidebars/projects/menus/ci_cd_menu_spec.rb index 2ceb9dcada9..6116fff792a 100644 --- a/spec/lib/sidebars/projects/menus/ci_cd_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/ci_cd_menu_spec.rb @@ -50,20 +50,8 @@ RSpec.describe Sidebars::Projects::Menus::CiCdMenu do describe 'Artifacts' do let(:item_id) { :artifacts } - context 'when feature flag :artifacts_management_page is disabled' do - it 'does not include artifacts menu item' do - stub_feature_flags(artifacts_management_page: false) - - is_expected.to be_nil - end - end - - context 'when feature flag :artifacts_management_page is enabled' do - it 'includes artifacts menu item' do - stub_feature_flags(artifacts_management_page: true) - - is_expected.not_to be_nil - end + it 'includes artifacts menu item' do + is_expected.not_to be_nil end end end diff --git a/spec/lib/sidebars/projects/menus/confluence_menu_spec.rb b/spec/lib/sidebars/projects/menus/confluence_menu_spec.rb index 836c6d26c6c..55c55b70a43 100644 --- a/spec/lib/sidebars/projects/menus/confluence_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/confluence_menu_spec.rb @@ -41,4 +41,13 @@ RSpec.describe Sidebars::Projects::Menus::ConfluenceMenu do end end end + + describe 'serialize_as_menu_item_args' do + it 'renders as part of the Plan section' do + expect(subject.serialize_as_menu_item_args).to include({ + item_id: :confluence, + super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu + }) + end + end end diff --git a/spec/lib/sidebars/projects/menus/deployments_menu_spec.rb b/spec/lib/sidebars/projects/menus/deployments_menu_spec.rb index ce971915174..a63acdb5dc2 100644 --- a/spec/lib/sidebars/projects/menus/deployments_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/deployments_menu_spec.rb @@ -2,12 +2,16 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Menus::DeploymentsMenu do +RSpec.describe Sidebars::Projects::Menus::DeploymentsMenu, feature_category: :navigation do let_it_be(:project, reload: true) { create(:project, :repository) } let(:user) { project.first_owner } let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) } + it_behaves_like 'not serializable as super_sidebar_menu_args' do + let(:menu) { described_class.new(context) } + end + describe '#render?' do subject { described_class.new(context) } @@ -47,7 +51,7 @@ RSpec.describe Sidebars::Projects::Menus::DeploymentsMenu do end end - describe 'Feature Flags' do + describe 'Feature flags' do let(:item_id) { :feature_flags } it_behaves_like 'access rights checks' diff --git a/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb b/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb index 116948b7cb0..346c681625a 100644 --- a/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb @@ -2,11 +2,15 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu do +RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu, feature_category: :navigation do let(:project) { build(:project) } let(:user) { project.first_owner } let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, show_cluster_hint: false) } + it_behaves_like 'not serializable as super_sidebar_menu_args' do + let(:menu) { described_class.new(context) } + end + describe '#render?' do subject { described_class.new(context) } @@ -60,13 +64,13 @@ RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu do subject.renderable_items.delete(find_menu_item(:kubernetes)) end - it 'menu link points to Terraform page' do - expect(subject.link).to eq find_menu_item(:terraform).link + it 'menu link points to Terraform states page' do + expect(subject.link).to eq find_menu_item(:terraform_states).link end - context 'when Terraform menu is not visible' do + context 'when Terraform states menu is not visible' do before do - subject.renderable_items.delete(find_menu_item(:terraform)) + subject.renderable_items.delete(find_menu_item(:terraform_states)) end it 'menu link points to Google Cloud page' do @@ -99,10 +103,26 @@ RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu do it_behaves_like 'access rights checks' end - describe 'Terraform' do - let(:item_id) { :terraform } + describe 'Terraform states' do + let(:item_id) { :terraform_states } it_behaves_like 'access rights checks' + + context 'if terraform_state.enabled=true' do + before do + stub_config(terraform_state: { enabled: true }) + end + + it_behaves_like 'access rights checks' + end + + context 'if terraform_state.enabled=false' do + before do + stub_config(terraform_state: { enabled: false }) + end + + it { is_expected.to be_nil } + end end describe 'Google Cloud' do @@ -141,6 +161,56 @@ RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu do it_behaves_like 'access rights checks' end end + + context 'when instance is not configured for Google OAuth2' do + before do + stub_feature_flags(incubation_5mp_google_cloud: true) + unconfigured_google_oauth2 = Struct.new(:app_id, :app_secret).new('', '') + allow(Gitlab::Auth::OAuth::Provider).to receive(:config_for) + .with('google_oauth2') + .and_return(unconfigured_google_oauth2) + end + + it { is_expected.to be_nil } + end + end + + describe 'AWS' do + let(:item_id) { :aws } + + it_behaves_like 'access rights checks' + + context 'when feature flag is turned off globally' do + before do + stub_feature_flags(cloudseed_aws: false) + end + + it { is_expected.to be_nil } + + context 'when feature flag is enabled for specific project' do + before do + stub_feature_flags(cloudseed_aws: project) + end + + it_behaves_like 'access rights checks' + end + + context 'when feature flag is enabled for specific group' do + before do + stub_feature_flags(cloudseed_aws: project.group) + end + + it_behaves_like 'access rights checks' + end + + context 'when feature flag is enabled for specific project' do + before do + stub_feature_flags(cloudseed_aws: user) + end + + it_behaves_like 'access rights checks' + end + end end end end diff --git a/spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb b/spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb deleted file mode 100644 index 9838aa8c3e3..00000000000 --- a/spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Sidebars::Projects::Menus::InviteTeamMembersMenu do - let_it_be(:project) { create(:project) } - let_it_be(:guest) { create(:user) } - - let(:context) { Sidebars::Projects::Context.new(current_user: owner, container: project) } - - subject(:invite_menu) { described_class.new(context) } - - context 'when the project is viewed by an owner of the group' do - let(:owner) { project.first_owner } - - describe '#render?' do - it 'renders the Invite team members link' do - expect(invite_menu.render?).to eq(true) - end - - context 'when the project already has at least 2 members' do - before do - project.add_guest(guest) - end - - it 'does not render the link' do - expect(invite_menu.render?).to eq(false) - end - end - end - - describe '#title' do - it 'displays the correct Invite team members text for the link in the side nav' do - expect(invite_menu.title).to eq('Invite members') - end - end - end - - context 'when the project is viewed by a guest user without admin permissions' do - let(:context) { Sidebars::Projects::Context.new(current_user: guest, container: project) } - - before do - project.add_guest(guest) - end - - describe '#render?' do - it 'does not render' do - expect(invite_menu.render?).to eq(false) - end - end - end -end diff --git a/spec/lib/sidebars/projects/menus/issues_menu_spec.rb b/spec/lib/sidebars/projects/menus/issues_menu_spec.rb index 4c0016a77a1..544cbcb956d 100644 --- a/spec/lib/sidebars/projects/menus/issues_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/issues_menu_spec.rb @@ -2,13 +2,25 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Menus::IssuesMenu do +RSpec.describe Sidebars::Projects::Menus::IssuesMenu, feature_category: :navigation do let(:project) { build(:project) } let(:user) { project.first_owner } let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) } subject { described_class.new(context) } + it_behaves_like 'serializable as super_sidebar_menu_args' do + let(:menu) { subject } + let(:extra_attrs) do + { + item_id: :project_issue_list, + pill_count: menu.pill_count, + has_pill: menu.has_pill?, + super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::PlanMenu + } + end + end + describe '#render?' do context 'when user can read issues' do it 'returns true' do @@ -43,7 +55,7 @@ RSpec.describe Sidebars::Projects::Menus::IssuesMenu do describe '#pill_count' do it 'returns zero when there are no open issues' do - expect(subject.pill_count).to eq 0 + expect(subject.pill_count).to eq '0' end it 'memoizes the query' do @@ -61,7 +73,14 @@ RSpec.describe Sidebars::Projects::Menus::IssuesMenu do create_list(:issue, 2, :opened, project: project) create(:issue, :closed, project: project) - expect(subject.pill_count).to eq 2 + expect(subject.pill_count).to eq '2' + end + end + + describe 'formatting' do + it 'returns truncated digits for count value over 1000' do + allow(project).to receive(:open_issues_count).and_return 1001 + expect(subject.pill_count).to eq('1k') end end end diff --git a/spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb b/spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb index 45c49500e46..08f35b6acd0 100644 --- a/spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Menus::MergeRequestsMenu do +RSpec.describe Sidebars::Projects::Menus::MergeRequestsMenu, feature_category: :navigation do let_it_be(:project) { create(:project, :repository) } let(:user) { project.first_owner } @@ -10,6 +10,18 @@ RSpec.describe Sidebars::Projects::Menus::MergeRequestsMenu do subject { described_class.new(context) } + it_behaves_like 'serializable as super_sidebar_menu_args' do + let(:menu) { subject } + let(:extra_attrs) do + { + item_id: :project_merge_request_list, + pill_count: menu.pill_count, + has_pill: menu.has_pill?, + super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::CodeMenu + } + end + end + describe '#render?' do context 'when repository is not present' do let(:project) { build(:project) } @@ -38,7 +50,7 @@ RSpec.describe Sidebars::Projects::Menus::MergeRequestsMenu do describe '#pill_count' do it 'returns zero when there are no open merge requests' do - expect(subject.pill_count).to eq 0 + expect(subject.pill_count).to eq '0' end it 'memoizes the query' do @@ -56,7 +68,16 @@ RSpec.describe Sidebars::Projects::Menus::MergeRequestsMenu do create_list(:merge_request, 2, :unique_branches, source_project: project, author: user, state: :opened) create(:merge_request, source_project: project, state: :merged) - expect(subject.pill_count).to eq 2 + expect(subject.pill_count).to eq '2' + end + end + + describe 'formatting' do + it 'returns truncated digits for count value over 1000' do + create_list(:merge_request, 1001, :unique_branches, source_project: project, author: user, state: :opened) + create(:merge_request, source_project: project, state: :merged) + + expect(subject.pill_count).to eq('1k') end end end diff --git a/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb b/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb index a1e6ae13e68..aa1e67085cd 100644 --- a/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb @@ -57,6 +57,10 @@ RSpec.describe Sidebars::Projects::Menus::MonitorMenu do end context 'Menu items' do + before do + stub_feature_flags(remove_monitor_metrics: false) + end + subject { described_class.new(context).renderable_items.index { |e| e.item_id == item_id } } shared_examples 'access rights checks' do diff --git a/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb b/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb index b03269c424a..860206dc6af 100644 --- a/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu do +RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu, feature_category: :navigation do let_it_be(:project) { create(:project) } let_it_be(:harbor_integration) { create(:harbor_integration, project: project) } @@ -12,6 +12,10 @@ RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu do subject { described_class.new(context) } + it_behaves_like 'not serializable as super_sidebar_menu_args' do + let(:menu) { subject } + end + describe '#render?' do context 'when menu does not have any menu item to show' do it 'returns false' do @@ -35,7 +39,7 @@ RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu do before do stub_container_registry_config(enabled: registry_enabled) stub_config(packages: { enabled: packages_enabled }) - stub_feature_flags(harbor_registry_integration: false) + stub_feature_flags(harbor_registry_integration: false, ml_experiment_tracking: false) end context 'when Packages Registry is visible' do @@ -164,6 +168,7 @@ RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu do stub_feature_flags(harbor_registry_integration: true) is_expected.not_to be_nil + expect(subject.active_routes[:controller]).to eq('projects/harbor/repositories') end end @@ -176,5 +181,25 @@ RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu do end end end + + describe 'Model experiments' do + let(:item_id) { :model_experiments } + + context 'when :ml_experiment_tracking is enabled' do + it 'shows the menu item' do + stub_feature_flags(ml_experiment_tracking: true) + + is_expected.not_to be_nil + end + end + + context 'when :ml_experiment_tracking is disabled' do + it 'does not show the menu item' do + stub_feature_flags(ml_experiment_tracking: false) + + is_expected.to be_nil + end + end + end end end diff --git a/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb b/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb index 7ff06ac229e..7547f152b27 100644 --- a/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb @@ -2,12 +2,16 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Menus::ProjectInformationMenu do +RSpec.describe Sidebars::Projects::Menus::ProjectInformationMenu, feature_category: :navigation do let_it_be_with_reload(:project) { create(:project, :repository) } let(:user) { project.first_owner } let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) } + it_behaves_like 'not serializable as super_sidebar_menu_args' do + let(:menu) { described_class.new(context) } + end + describe '#container_html_options' do subject { described_class.new(context).container_html_options } diff --git a/spec/lib/sidebars/projects/menus/repository_menu_spec.rb b/spec/lib/sidebars/projects/menus/repository_menu_spec.rb index 40ca2107698..1aa0ea30d0a 100644 --- a/spec/lib/sidebars/projects/menus/repository_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/repository_menu_spec.rb @@ -6,7 +6,11 @@ RSpec.describe Sidebars::Projects::Menus::RepositoryMenu, feature_category: :sou let_it_be(:project) { create(:project, :repository) } let(:user) { project.first_owner } - let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, current_ref: 'master') } + let(:is_super_sidebar) { false } + let(:context) do + Sidebars::Projects::Context.new(current_user: user, container: project, current_ref: 'master', + is_super_sidebar: is_super_sidebar) + end subject { described_class.new(context) } @@ -36,9 +40,8 @@ RSpec.describe Sidebars::Projects::Menus::RepositoryMenu, feature_category: :sou end context 'for menu items' do - shared_examples_for 'repository menu item link for' do |item_id| + shared_examples_for 'repository menu item link for' do let(:ref) { 'master' } - let(:item_id) { item_id } subject { described_class.new(context).renderable_items.find { |e| e.item_id == item_id }.link } using RSpec::Parameterized::TableSyntax @@ -77,15 +80,39 @@ RSpec.describe Sidebars::Projects::Menus::RepositoryMenu, feature_category: :sou end end + shared_examples_for 'repository menu item with different super sidebar title' do |title, super_sidebar_title| + subject { described_class.new(context).renderable_items.find { |e| e.item_id == item_id } } + + specify do + expect(subject.title).to eq(title) + end + + context 'when inside the super sidebar' do + let(:is_super_sidebar) { true } + + specify do + expect(subject.title).to eq(super_sidebar_title) + end + end + end + + describe 'Files' do + let_it_be(:item_id) { :files } + + it_behaves_like 'repository menu item with different super sidebar title', + _('Files'), + _('Repository') + end + describe 'Commits' do let_it_be(:item_id) { :commits } - it_behaves_like 'repository menu item link for', :commits do + it_behaves_like 'repository menu item link for' do let(:route) { "/#{project.full_path}/-/commits/#{ref}" } end end - describe 'Contributors' do + describe 'Contributor statistics' do let_it_be(:item_id) { :contributors } context 'when analytics is disabled' do @@ -103,16 +130,22 @@ RSpec.describe Sidebars::Projects::Menus::RepositoryMenu, feature_category: :sou project.project_feature.update!(analytics_access_level: ProjectFeature::ENABLED) end - it_behaves_like 'repository menu item link for', :contributors do + it_behaves_like 'repository menu item link for' do let(:route) { "/#{project.full_path}/-/graphs/#{ref}" } end end end describe 'Network' do - it_behaves_like 'repository menu item link for', :graphs do + let_it_be(:item_id) { :graphs } + + it_behaves_like 'repository menu item link for' do let(:route) { "/#{project.full_path}/-/network/#{ref}" } end + + it_behaves_like 'repository menu item with different super sidebar title', + _('Graph'), + _('Repository graph') end end end diff --git a/spec/lib/sidebars/projects/menus/scope_menu_spec.rb b/spec/lib/sidebars/projects/menus/scope_menu_spec.rb index 4e87f3b8ead..45464278880 100644 --- a/spec/lib/sidebars/projects/menus/scope_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/scope_menu_spec.rb @@ -2,11 +2,23 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Menus::ScopeMenu do +RSpec.describe Sidebars::Projects::Menus::ScopeMenu, feature_category: :navigation do let(:project) { build(:project) } let(:user) { project.first_owner } let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) } + it_behaves_like 'serializable as super_sidebar_menu_args' do + let(:menu) { described_class.new(context) } + let(:extra_attrs) do + { + title: _('Project overview'), + sprite_icon: 'project', + super_sidebar_parent: ::Sidebars::StaticMenu, + item_id: :project_overview + } + end + end + describe '#container_html_options' do subject { described_class.new(context).container_html_options } diff --git a/spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb b/spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb index 41158bd58dc..697359b7941 100644 --- a/spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb @@ -20,7 +20,7 @@ RSpec.describe Sidebars::Projects::Menus::SecurityComplianceMenu do end context 'when user is authenticated' do - context 'when the Security & Compliance is disabled' do + context 'when the Security and Compliance is disabled' do before do allow(Ability).to receive(:allowed?).with(user, :access_security_and_compliance, project).and_return(false) end @@ -28,7 +28,7 @@ RSpec.describe Sidebars::Projects::Menus::SecurityComplianceMenu do it { is_expected.to be_falsey } end - context 'when the Security & Compliance is not disabled' do + context 'when the Security and Compliance is not disabled' do it { is_expected.to be_truthy } end end diff --git a/spec/lib/sidebars/projects/menus/settings_menu_spec.rb b/spec/lib/sidebars/projects/menus/settings_menu_spec.rb index c7aca0fb97e..4be99892631 100644 --- a/spec/lib/sidebars/projects/menus/settings_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/settings_menu_spec.rb @@ -22,6 +22,12 @@ RSpec.describe Sidebars::Projects::Menus::SettingsMenu do end end + describe '#separated?' do + it 'returns true' do + expect(subject.separated?).to be true + end + end + describe 'Menu items' do subject { described_class.new(context).renderable_items.find { |e| e.item_id == item_id } } diff --git a/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb b/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb index 04b8c128e3d..9d50eb6f817 100644 --- a/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb @@ -2,13 +2,23 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Menus::SnippetsMenu do +RSpec.describe Sidebars::Projects::Menus::SnippetsMenu, feature_category: :navigation do let(:project) { build(:project) } let(:user) { project.first_owner } let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) } subject { described_class.new(context) } + it_behaves_like 'serializable as super_sidebar_menu_args' do + let(:menu) { subject } + let(:extra_attrs) do + { + super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::CodeMenu, + item_id: :project_snippets + } + end + end + describe '#render?' do context 'when user cannot access snippets' do let(:user) { nil } diff --git a/spec/lib/sidebars/projects/menus/wiki_menu_spec.rb b/spec/lib/sidebars/projects/menus/wiki_menu_spec.rb index 362da3e7b50..64050e3e488 100644 --- a/spec/lib/sidebars/projects/menus/wiki_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/wiki_menu_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Menus::WikiMenu do +RSpec.describe Sidebars::Projects::Menus::WikiMenu, feature_category: :navigation do let(:project) { build(:project) } let(:user) { project.first_owner } let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) } @@ -28,4 +28,14 @@ RSpec.describe Sidebars::Projects::Menus::WikiMenu do end end end + + it_behaves_like 'serializable as super_sidebar_menu_args' do + let(:menu) { subject } + let(:extra_attrs) do + { + super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu, + item_id: :project_wiki + } + end + end end diff --git a/spec/lib/sidebars/projects/panel_spec.rb b/spec/lib/sidebars/projects/panel_spec.rb index ff253eedd08..ec1df438cf1 100644 --- a/spec/lib/sidebars/projects/panel_spec.rb +++ b/spec/lib/sidebars/projects/panel_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sidebars::Projects::Panel do +RSpec.describe Sidebars::Projects::Panel, feature_category: :navigation do let_it_be(:project) { create(:project) } let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project) } diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/analyze_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/analyze_menu_spec.rb new file mode 100644 index 00000000000..d459d47c31a --- /dev/null +++ b/spec/lib/sidebars/projects/super_sidebar_menus/analyze_menu_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Projects::SuperSidebarMenus::AnalyzeMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Analyze")) + expect(subject.sprite_icon).to eq("chart") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :dashboards_analytics, + :cycle_analytics, + :contributors, + :ci_cd_analytics, + :repository_analytics, + :code_review, + :merge_request_analytics, + :issues, + :insights, + :model_experiments + ]) + end +end diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/build_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/build_menu_spec.rb new file mode 100644 index 00000000000..3f2a40e1c7d --- /dev/null +++ b/spec/lib/sidebars/projects/super_sidebar_menus/build_menu_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Projects::SuperSidebarMenus::BuildMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Build")) + expect(subject.sprite_icon).to eq("rocket") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :pipelines, + :jobs, + :pipelines_editor, + :releases, + :environments, + :pipeline_schedules, + :feature_flags, + :test_cases, + :artifacts + ]) + end +end diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/code_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/code_menu_spec.rb new file mode 100644 index 00000000000..8f69717eb29 --- /dev/null +++ b/spec/lib/sidebars/projects/super_sidebar_menus/code_menu_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Projects::SuperSidebarMenus::CodeMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Code")) + expect(subject.sprite_icon).to eq("code") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :project_merge_request_list, + :files, + :branches, + :commits, + :tags, + :graphs, + :compare, + :project_snippets, + :file_locks + ]) + end +end diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/manage_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/manage_menu_spec.rb new file mode 100644 index 00000000000..afcdf2550d7 --- /dev/null +++ b/spec/lib/sidebars/projects/super_sidebar_menus/manage_menu_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Projects::SuperSidebarMenus::ManageMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Manage")) + expect(subject.sprite_icon).to eq("users") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :activity, + :members, + :labels + ]) + end +end diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/monitor_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/monitor_menu_spec.rb new file mode 100644 index 00000000000..9344bbc76db --- /dev/null +++ b/spec/lib/sidebars/projects/super_sidebar_menus/monitor_menu_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Projects::SuperSidebarMenus::MonitorMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Monitor")) + expect(subject.sprite_icon).to eq("monitor") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :metrics, + :error_tracking, + :alert_management, + :incidents, + :on_call_schedules, + :escalation_policies, + :service_desk + ]) + end +end diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/operations_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/operations_menu_spec.rb new file mode 100644 index 00000000000..6ab070c40ae --- /dev/null +++ b/spec/lib/sidebars/projects/super_sidebar_menus/operations_menu_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Projects::SuperSidebarMenus::OperationsMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Operate")) + expect(subject.sprite_icon).to eq("deployments") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :packages_registry, + :container_registry, + :kubernetes, + :terraform_states, + :infrastructure_registry, + :google_cloud, + :aws + ]) + end +end diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb new file mode 100644 index 00000000000..8d61c9d9a0e --- /dev/null +++ b/spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Projects::SuperSidebarMenus::PlanMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Plan")) + expect(subject.sprite_icon).to eq("planning") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :project_issue_list, + :boards, + :milestones, + :iterations, + :project_wiki, + :requirements + ]) + end +end diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/secure_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/secure_menu_spec.rb new file mode 100644 index 00000000000..74ef761332e --- /dev/null +++ b/spec/lib/sidebars/projects/super_sidebar_menus/secure_menu_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Projects::SuperSidebarMenus::SecureMenu, feature_category: :navigation do + subject { described_class.new({}) } + + let(:items) { subject.instance_variable_get(:@items) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(s_("Navigation|Secure")) + expect(subject.sprite_icon).to eq("shield") + end + + it 'defines list of NilMenuItem placeholders' do + expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) + expect(items.map(&:item_id)).to eq([ + :discover_project_security, + :dashboard, + :vulnerability_report, + :dependency_list, + :license_compliance, + :audit_events, + :scan_policies, + :on_demand_scans, + :configuration + ]) + end +end diff --git a/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb b/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb new file mode 100644 index 00000000000..93f0072a111 --- /dev/null +++ b/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Projects::SuperSidebarPanel, feature_category: :navigation do + let_it_be(:project) { create(:project, :repository) } + + let(:user) { project.first_owner } + let(:context) do + Sidebars::Projects::Context.new( + current_user: user, + container: project, + current_ref: project.repository.root_ref, + is_super_sidebar: true, + # Turn features on that impact the list of items rendered + can_view_pipeline_editor: true, + learn_gitlab_enabled: true, + show_discover_project_security: true, + # Turn features off that do not add/remove items + show_cluster_hint: false, + show_promotions: false + ) + end + + subject { described_class.new(context) } + + before do + # Enable integrations with menu items + allow(project).to receive(:external_wiki).and_return(build(:external_wiki_integration, project: project)) + allow(project).to receive(:external_issue_tracker).and_return(build(:bugzilla_integration, project: project)) + end + + it 'implements #super_sidebar_context_header' do + expect(subject.super_sidebar_context_header).to eq( + { + title: project.name, + avatar: project.avatar_url, + id: project.id + }) + end + + describe '#renderable_menus' do + let(:category_menu) do + [ + Sidebars::StaticMenu, + Sidebars::Projects::SuperSidebarMenus::ManageMenu, + Sidebars::Projects::SuperSidebarMenus::PlanMenu, + Sidebars::Projects::SuperSidebarMenus::CodeMenu, + Sidebars::Projects::SuperSidebarMenus::BuildMenu, + Sidebars::Projects::SuperSidebarMenus::SecureMenu, + Sidebars::Projects::SuperSidebarMenus::OperationsMenu, + Sidebars::Projects::SuperSidebarMenus::MonitorMenu, + Sidebars::Projects::SuperSidebarMenus::AnalyzeMenu, + Sidebars::UncategorizedMenu, + Sidebars::Projects::Menus::SettingsMenu + ] + end + + it "is exposed as a renderable menu" do + expect(subject.instance_variable_get(:@menus).map(&:class)).to eq(category_menu) + end + end + + it_behaves_like 'a panel with uniquely identifiable menu items' + it_behaves_like 'a panel with all menu_items categorized' +end diff --git a/spec/lib/sidebars/search/panel_spec.rb b/spec/lib/sidebars/search/panel_spec.rb new file mode 100644 index 00000000000..30801ff800e --- /dev/null +++ b/spec/lib/sidebars/search/panel_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::Search::Panel, feature_category: :navigation do + let_it_be(:current_user) { create(:user) } + let_it_be(:user) { create(:user) } + + let(:context) { Sidebars::Context.new(current_user: current_user, container: user) } + let(:panel) { described_class.new(context) } + + subject { described_class.new(context) } + + it_behaves_like 'a panel with uniquely identifiable menu items' + + describe '#aria_label' do + it 'returns the correct aria label' do + expect(panel.aria_label).to eq(_('Search results')) + end + end + + describe '#super_sidebar_context_header' do + it 'returns a hash with the correct title and icon' do + expected_header = { + title: 'Search results', + icon: 'search-results' + } + expect(panel.super_sidebar_context_header).to eq(expected_header) + end + end +end diff --git a/spec/lib/sidebars/static_menu_spec.rb b/spec/lib/sidebars/static_menu_spec.rb new file mode 100644 index 00000000000..3d9feee0494 --- /dev/null +++ b/spec/lib/sidebars/static_menu_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::StaticMenu, feature_category: :navigation do + let(:context) { {} } + + subject { described_class.new(context) } + + describe '#serialize_for_super_sidebar' do + it 'returns flat list of all menu items' do + subject.add_item(Sidebars::MenuItem.new(item_id: 'id1', title: 'Is active', link: 'foo2', + active_routes: { controller: 'fooc' })) + subject.add_item(Sidebars::MenuItem.new(item_id: 'id2', title: 'Not active', link: 'foo3', + active_routes: { controller: 'barc' })) + subject.add_item(Sidebars::NilMenuItem.new(item_id: 'nil_item')) + + allow(context).to receive(:route_is_active).and_return(->(x) { x[:controller] == 'fooc' }) + + expect(subject.serialize_for_super_sidebar).to eq( + [ + { + id: 'id1', + title: "Is active", + icon: nil, + link: "foo2", + is_active: true, + pill_count: nil, + link_classes: nil + }, + { + id: 'id2', + title: "Not active", + icon: nil, + link: "foo3", + is_active: false, + pill_count: nil, + link_classes: nil + } + ] + ) + end + end +end diff --git a/spec/lib/sidebars/uncategorized_menu_spec.rb b/spec/lib/sidebars/uncategorized_menu_spec.rb new file mode 100644 index 00000000000..45e7c0c87e2 --- /dev/null +++ b/spec/lib/sidebars/uncategorized_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UncategorizedMenu, feature_category: :navigation do + subject { described_class.new({}) } + + it 'has title and sprite_icon' do + expect(subject.title).to eq(_("Uncategorized")) + expect(subject.sprite_icon).to eq("question") + end +end diff --git a/spec/lib/sidebars/user_profile/menus/activity_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/activity_menu_spec.rb new file mode 100644 index 00000000000..6689b8b2da3 --- /dev/null +++ b/spec/lib/sidebars/user_profile/menus/activity_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Menus::ActivityMenu, feature_category: :navigation do + it_behaves_like 'User profile menu', + title: s_('UserProfile|Activity'), + icon: 'history', + active_route: 'users#activity' do + let(:link) { "/users/#{user.username}/activity" } + end +end diff --git a/spec/lib/sidebars/user_profile/menus/contributed_projects_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/contributed_projects_menu_spec.rb new file mode 100644 index 00000000000..2677851247b --- /dev/null +++ b/spec/lib/sidebars/user_profile/menus/contributed_projects_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Menus::ContributedProjectsMenu, feature_category: :navigation do + it_behaves_like 'User profile menu', + title: s_('UserProfile|Contributed projects'), + icon: 'project', + active_route: 'users#contributed' do + let(:link) { "/users/#{user.username}/contributed" } + end +end diff --git a/spec/lib/sidebars/user_profile/menus/followers_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/followers_menu_spec.rb new file mode 100644 index 00000000000..2d3d48f0a8c --- /dev/null +++ b/spec/lib/sidebars/user_profile/menus/followers_menu_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Menus::FollowersMenu, feature_category: :navigation do + it_behaves_like 'User profile menu', + title: s_('UserProfile|Followers'), + icon: 'users', + active_route: 'users#followers' do + let(:link) { "/users/#{user.username}/followers" } + end + + it_behaves_like 'Followers/followees counts', :followers +end diff --git a/spec/lib/sidebars/user_profile/menus/following_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/following_menu_spec.rb new file mode 100644 index 00000000000..8d8db2611e6 --- /dev/null +++ b/spec/lib/sidebars/user_profile/menus/following_menu_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Menus::FollowingMenu, feature_category: :navigation do + it_behaves_like 'User profile menu', + title: s_('UserProfile|Following'), + icon: 'users', + active_route: 'users#following' do + let(:link) { "/users/#{user.username}/following" } + end + + it_behaves_like 'Followers/followees counts', :followees +end diff --git a/spec/lib/sidebars/user_profile/menus/groups_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/groups_menu_spec.rb new file mode 100644 index 00000000000..989cc1ff5ce --- /dev/null +++ b/spec/lib/sidebars/user_profile/menus/groups_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Menus::GroupsMenu, feature_category: :navigation do + it_behaves_like 'User profile menu', + title: s_('UserProfile|Groups'), + icon: 'group', + active_route: 'users#groups' do + let(:link) { "/users/#{user.username}/groups" } + end +end diff --git a/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb new file mode 100644 index 00000000000..7cf86676892 --- /dev/null +++ b/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Menus::OverviewMenu, feature_category: :navigation do + it_behaves_like 'User profile menu', + title: s_('UserProfile|Overview'), + icon: 'overview', + active_route: 'users#show' do + let(:link) { "/#{user.username}" } + end +end diff --git a/spec/lib/sidebars/user_profile/menus/personal_projects_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/personal_projects_menu_spec.rb new file mode 100644 index 00000000000..3e0bc269a66 --- /dev/null +++ b/spec/lib/sidebars/user_profile/menus/personal_projects_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Menus::PersonalProjectsMenu, feature_category: :navigation do + it_behaves_like 'User profile menu', + title: s_('UserProfile|Personal projects'), + icon: 'project', + active_route: 'users#projects' do + let(:link) { "/users/#{user.username}/projects" } + end +end diff --git a/spec/lib/sidebars/user_profile/menus/snippets_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/snippets_menu_spec.rb new file mode 100644 index 00000000000..b2363706113 --- /dev/null +++ b/spec/lib/sidebars/user_profile/menus/snippets_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Menus::SnippetsMenu, feature_category: :navigation do + it_behaves_like 'User profile menu', + title: s_('UserProfile|Snippets'), + icon: 'snippet', + active_route: 'users#snippets' do + let(:link) { "/users/#{user.username}/snippets" } + end +end diff --git a/spec/lib/sidebars/user_profile/menus/starred_projects_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/starred_projects_menu_spec.rb new file mode 100644 index 00000000000..aa6ad0a74e7 --- /dev/null +++ b/spec/lib/sidebars/user_profile/menus/starred_projects_menu_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Menus::StarredProjectsMenu, feature_category: :navigation do + it_behaves_like 'User profile menu', + title: s_('UserProfile|Starred projects'), + icon: 'star-o', + active_route: 'users#starred' do + let(:link) { "/users/#{user.username}/starred" } + end +end diff --git a/spec/lib/sidebars/user_profile/panel_spec.rb b/spec/lib/sidebars/user_profile/panel_spec.rb new file mode 100644 index 00000000000..c62c7f9fd96 --- /dev/null +++ b/spec/lib/sidebars/user_profile/panel_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserProfile::Panel, feature_category: :navigation do + let_it_be(:current_user) { create(:user) } + let_it_be(:user) { create(:user) } + + let(:context) { Sidebars::Context.new(current_user: current_user, container: user) } + + subject { described_class.new(context) } + + it_behaves_like 'a panel with uniquely identifiable menu items' + + it 'implements #aria_label' do + expect(subject.aria_label).to eq(s_('UserProfile|User profile navigation')) + end + + it 'implements #super_sidebar_context_header' do + expect(subject.super_sidebar_context_header).to eq({ + title: user.name, + avatar: user.avatar_url, + avatar_shape: 'circle' + }) + end +end diff --git a/spec/lib/sidebars/user_settings/menus/access_tokens_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/access_tokens_menu_spec.rb new file mode 100644 index 00000000000..fa33e7bedfb --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/access_tokens_menu_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::AccessTokensMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/personal_access_tokens', + title: _('Access Tokens'), + icon: 'token', + active_routes: { controller: :personal_access_tokens } + + describe '#render?' do + subject { described_class.new(context) } + + let_it_be(:user) { build(:user) } + + context 'when personal access tokens are disabled' do + before do + allow(::Gitlab::CurrentSettings).to receive_messages(personal_access_tokens_disabled?: true) + end + + context 'when user is logged in' do + let(:context) { Sidebars::Context.new(current_user: user, container: nil) } + + it 'does not render' do + expect(subject.render?).to be false + end + end + + context 'when user is not logged in' do + let(:context) { Sidebars::Context.new(current_user: nil, container: nil) } + + subject { described_class.new(context) } + + it 'does not render' do + expect(subject.render?).to be false + end + end + end + + context 'when personal access tokens are enabled' do + before do + allow(::Gitlab::CurrentSettings).to receive_messages(personal_access_tokens_disabled?: false) + end + + context 'when user is logged in' do + let(:context) { Sidebars::Context.new(current_user: user, container: nil) } + + it 'renders' do + expect(subject.render?).to be true + end + end + + context 'when user is not logged in' do + let(:context) { Sidebars::Context.new(current_user: nil, container: nil) } + + subject { described_class.new(context) } + + it 'does not render' do + expect(subject.render?).to be false + end + end + end + end +end diff --git a/spec/lib/sidebars/user_settings/menus/account_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/account_menu_spec.rb new file mode 100644 index 00000000000..d5810d9c5ae --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/account_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::AccountMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/account', + title: _('Account'), + icon: 'account', + active_routes: { controller: [:accounts, :two_factor_auths] } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/active_sessions_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/active_sessions_menu_spec.rb new file mode 100644 index 00000000000..be5f826ee58 --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/active_sessions_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::ActiveSessionsMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/active_sessions', + title: _('Active Sessions'), + icon: 'monitor-lines', + active_routes: { controller: :active_sessions } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/applications_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/applications_menu_spec.rb new file mode 100644 index 00000000000..eeda4fb844c --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/applications_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::ApplicationsMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/applications', + title: _('Applications'), + icon: 'applications', + active_routes: { controller: 'oauth/applications' } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/authentication_log_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/authentication_log_menu_spec.rb new file mode 100644 index 00000000000..33be5050c37 --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/authentication_log_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::AuthenticationLogMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/audit_log', + title: _('Authentication Log'), + icon: 'log', + active_routes: { path: 'profiles#audit_log' } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/chat_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/chat_menu_spec.rb new file mode 100644 index 00000000000..2a0587e2504 --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/chat_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::ChatMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/chat', + title: _('Chat'), + icon: 'comment', + active_routes: { controller: :chat_names } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/comment_templates_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/comment_templates_menu_spec.rb new file mode 100644 index 00000000000..37a383cfd9d --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/comment_templates_menu_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::CommentTemplatesMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/comment_templates', + title: _('Comment Templates'), + icon: 'comment-lines', + active_routes: { controller: :comment_templates } + + describe '#render?' do + subject { described_class.new(context) } + + let_it_be(:user) { build(:user) } + + context 'when comment templates are enabled' do + before do + allow(subject).to receive(:saved_replies_enabled?).and_return(true) + end + + context 'when user is logged in' do + let(:context) { Sidebars::Context.new(current_user: user, container: nil) } + + it 'does not render' do + expect(subject.render?).to be true + end + end + + context 'when user is not logged in' do + let(:context) { Sidebars::Context.new(current_user: nil, container: nil) } + + subject { described_class.new(context) } + + it 'does not render' do + expect(subject.render?).to be false + end + end + end + + context 'when comment templates are disabled' do + before do + allow(subject).to receive(:saved_replies_enabled?).and_return(false) + end + + context 'when user is logged in' do + let(:context) { Sidebars::Context.new(current_user: user, container: nil) } + + it 'renders' do + expect(subject.render?).to be false + end + end + + context 'when user is not logged in' do + let(:context) { Sidebars::Context.new(current_user: nil, container: nil) } + + subject { described_class.new(context) } + + it 'does not render' do + expect(subject.render?).to be false + end + end + end + end +end diff --git a/spec/lib/sidebars/user_settings/menus/emails_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/emails_menu_spec.rb new file mode 100644 index 00000000000..2f16c68e601 --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/emails_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::EmailsMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/emails', + title: _('Emails'), + icon: 'mail', + active_routes: { controller: :emails } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/gpg_keys_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/gpg_keys_menu_spec.rb new file mode 100644 index 00000000000..1f4340ad29c --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/gpg_keys_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::GpgKeysMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/gpg_keys', + title: _('GPG Keys'), + icon: 'key', + active_routes: { controller: :gpg_keys } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/notifications_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/notifications_menu_spec.rb new file mode 100644 index 00000000000..282324056d4 --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/notifications_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::NotificationsMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/notifications', + title: _('Notifications'), + icon: 'notifications', + active_routes: { controller: :notifications } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/password_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/password_menu_spec.rb new file mode 100644 index 00000000000..168019fea5d --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/password_menu_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::PasswordMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/password', + title: _('Password'), + icon: 'lock', + active_routes: { controller: :passwords } + + describe '#render?' do + subject { described_class.new(context) } + + let_it_be(:user) { build(:user) } + let(:context) { Sidebars::Context.new(current_user: user, container: nil) } + + context 'when password authentication is enabled' do + before do + allow(user).to receive(:allow_password_authentication?).and_return(true) + end + + it 'renders' do + expect(subject.render?).to be true + end + end + + context 'when password authentication is disabled' do + before do + allow(user).to receive(:allow_password_authentication?).and_return(false) + end + + it 'renders' do + expect(subject.render?).to be false + end + end + end +end diff --git a/spec/lib/sidebars/user_settings/menus/preferences_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/preferences_menu_spec.rb new file mode 100644 index 00000000000..83a67a40081 --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/preferences_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::PreferencesMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/preferences', + title: _('Preferences'), + icon: 'preferences', + active_routes: { controller: :preferences } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/profile_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/profile_menu_spec.rb new file mode 100644 index 00000000000..8410ba7cfcd --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/profile_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::ProfileMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile', + title: _('Profile'), + icon: 'profile', + active_routes: { path: 'profiles#show' } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/menus/ssh_keys_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/ssh_keys_menu_spec.rb new file mode 100644 index 00000000000..8c781cc743b --- /dev/null +++ b/spec/lib/sidebars/user_settings/menus/ssh_keys_menu_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Menus::SshKeysMenu, feature_category: :navigation do + it_behaves_like 'User settings menu', + link: '/-/profile/keys', + title: _('SSH Keys'), + icon: 'key', + active_routes: { controller: :keys } + + it_behaves_like 'User settings menu #render? method' +end diff --git a/spec/lib/sidebars/user_settings/panel_spec.rb b/spec/lib/sidebars/user_settings/panel_spec.rb new file mode 100644 index 00000000000..0c02bf77d0e --- /dev/null +++ b/spec/lib/sidebars/user_settings/panel_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::UserSettings::Panel, feature_category: :navigation do + let_it_be(:user) { create(:user) } + + let(:context) { Sidebars::Context.new(current_user: user, container: nil) } + + subject { described_class.new(context) } + + it_behaves_like 'a panel with uniquely identifiable menu items' + + it 'implements #super_sidebar_context_header' do + expect(subject.super_sidebar_context_header).to eq({ title: _('User settings'), avatar: user.avatar_url }) + end +end diff --git a/spec/lib/sidebars/your_work/panel_spec.rb b/spec/lib/sidebars/your_work/panel_spec.rb new file mode 100644 index 00000000000..ae9c3aa18e6 --- /dev/null +++ b/spec/lib/sidebars/your_work/panel_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Sidebars::YourWork::Panel, feature_category: :navigation do + let_it_be(:user) { create(:user) } + + let(:context) { Sidebars::Context.new(current_user: user, container: nil) } + + subject { described_class.new(context) } + + it_behaves_like 'a panel with uniquely identifiable menu items' + + it 'implements #super_sidebar_context_header' do + expect(subject.super_sidebar_context_header).to eq({ title: 'Your work', icon: 'work' }) + end +end |