diff options
Diffstat (limited to 'spec/helpers')
42 files changed, 749 insertions, 403 deletions
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index c7470f31ad8..ae039c1a8b1 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -168,11 +168,13 @@ RSpec.describe ApplicationHelper do it { expect(helper.active_when(false)).to eq(nil) } end - describe '#promo_host' do - subject { helper.promo_host } + unless Gitlab.jh? + describe '#promo_host' do + subject { helper.promo_host } - it 'returns the url' do - is_expected.to eq('about.gitlab.com') + it 'returns the url' do + is_expected.to eq('about.gitlab.com') + end end end @@ -180,7 +182,7 @@ RSpec.describe ApplicationHelper do subject { helper.promo_url } it 'returns the url' do - is_expected.to eq('https://about.gitlab.com') + is_expected.to eq("https://#{helper.promo_host}") end it 'changes if promo_host changes' do @@ -194,7 +196,7 @@ RSpec.describe ApplicationHelper do subject { helper.contact_sales_url } it 'returns the url' do - is_expected.to eq('https://about.gitlab.com/sales') + is_expected.to eq("https://#{helper.promo_host}/sales") end it 'changes if promo_url changes' do @@ -316,9 +318,7 @@ RSpec.describe ApplicationHelper do let(:user) { create(:user, static_object_token: 'hunter1') } before do - allow_next_instance_of(ApplicationSetting) do |instance| - allow(instance).to receive(:static_objects_external_storage_url).and_return('https://cdn.gitlab.com') - end + stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com') allow(helper).to receive(:current_user).and_return(user) end diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb index 7fcd5ae880a..120dbe7cb49 100644 --- a/spec/helpers/avatars_helper_spec.rb +++ b/spec/helpers/avatars_helper_spec.rb @@ -121,27 +121,13 @@ RSpec.describe AvatarsHelper do end end - context "when :avatar_cache_for_email flag is enabled" do - before do - stub_feature_flags(avatar_cache_for_email: true) - end - - it_behaves_like "returns avatar for email" + it_behaves_like "returns avatar for email" - it "caches the request" do - expect(User).to receive(:find_by_any_email).once.and_call_original - - expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url) - expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url) - end - end - - context "when :avatar_cache_for_email flag is disabled" do - before do - stub_feature_flags(avatar_cache_for_email: false) - end + it "caches the request" do + expect(User).to receive(:find_by_any_email).once.and_call_original - it_behaves_like "returns avatar for email" + expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url) + expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url) end end diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb index b584a906565..885569574a4 100644 --- a/spec/helpers/blob_helper_spec.rb +++ b/spec/helpers/blob_helper_spec.rb @@ -304,6 +304,7 @@ RSpec.describe BlobHelper do let_it_be(:namespace) { create(:namespace, name: 'gitlab') } let_it_be(:project) { create(:project, :repository, namespace: namespace) } let_it_be(:current_user) { create(:user) } + let(:can_push_code) { true } let(:blob) { project.repository.blob_at('refs/heads/master', 'README.md') } @@ -489,9 +490,18 @@ RSpec.describe BlobHelper do expect(uri.path).to eq("/#{project.namespace.path}/#{project.path}/-/forks") expect(params).to include("continue[to]=/-/ide/project/#{project.namespace.path}/#{project.path}/edit/master") + expect(params).to include("continue[notice]=#{edit_in_new_fork_notice}") + expect(params).to include("continue[notice_now]=#{edit_in_new_fork_notice_now}") expect(params).to include("namespace_key=#{current_user.namespace.id}") end + it 'does not include notice params with_notice: false' do + uri = URI(helper.ide_fork_and_edit_path(project, "master", "", with_notice: false)) + + expect(uri.path).to eq("/#{project.namespace.path}/#{project.path}/-/forks") + expect(CGI.unescape(uri.query)).to eq("continue[to]=/-/ide/project/#{project.namespace.path}/#{project.path}/edit/master&namespace_key=#{current_user.namespace.id}") + end + context 'when user is not logged in' do let(:current_user) { nil } diff --git a/spec/helpers/boards_helper_spec.rb b/spec/helpers/boards_helper_spec.rb index b00ee19cea2..00cd44809c7 100644 --- a/spec/helpers/boards_helper_spec.rb +++ b/spec/helpers/boards_helper_spec.rb @@ -64,6 +64,7 @@ RSpec.describe BoardsHelper do allow(helper).to receive(:current_user) { user } allow(helper).to receive(:can?).with(user, :create_non_backlog_issues, project_board).and_return(true) allow(helper).to receive(:can?).with(user, :admin_issue, project_board).and_return(true) + allow(helper).to receive(:can?).with(user, :admin_issue_board_list, project).and_return(false) end it 'returns a board_lists_path as lists_endpoint' do @@ -86,6 +87,17 @@ RSpec.describe BoardsHelper do it 'returns the group id of a project' do expect(helper.board_data[:group_id]).to eq(project.group.id) end + + context 'can_admin_list' do + it 'returns can_admin_list as false by default' do + expect(helper.board_data[:can_admin_list]).to eq('false') + end + it 'returns can_admin_list as true when user can admin the board' do + allow(helper).to receive(:can?).with(user, :admin_issue_board_list, project).and_return(true) + + expect(helper.board_data[:can_admin_list]).to eq('true') + end + end end context 'group board' do @@ -96,6 +108,7 @@ RSpec.describe BoardsHelper do allow(helper).to receive(:current_user) { user } allow(helper).to receive(:can?).with(user, :create_non_backlog_issues, group_board).and_return(true) allow(helper).to receive(:can?).with(user, :admin_issue, group_board).and_return(true) + allow(helper).to receive(:can?).with(user, :admin_issue_board_list, base_group).and_return(false) end it 'returns correct path for base group' do @@ -110,6 +123,17 @@ RSpec.describe BoardsHelper do it 'returns the group id' do expect(helper.board_data[:group_id]).to eq(base_group.id) end + + context 'can_admin_list' do + it 'returns can_admin_list as false by default' do + expect(helper.board_data[:can_admin_list]).to eq('false') + end + it 'returns can_admin_list as true when user can admin the board' do + allow(helper).to receive(:can?).with(user, :admin_issue_board_list, base_group).and_return(true) + + expect(helper.board_data[:can_admin_list]).to eq('true') + end + end end end diff --git a/spec/helpers/broadcast_messages_helper_spec.rb b/spec/helpers/broadcast_messages_helper_spec.rb index 21fde35954e..3e8cbdf89a0 100644 --- a/spec/helpers/broadcast_messages_helper_spec.rb +++ b/spec/helpers/broadcast_messages_helper_spec.rb @@ -28,6 +28,7 @@ RSpec.describe BroadcastMessagesHelper do describe 'broadcast_message' do let_it_be(:user) { create(:user) } + let(:current_broadcast_message) { BroadcastMessage.new(message: 'Current Message') } before do diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb index ecb9c98b1bf..09495bbde35 100644 --- a/spec/helpers/button_helper_spec.rb +++ b/spec/helpers/button_helper_spec.rb @@ -171,6 +171,7 @@ RSpec.describe ButtonHelper do expect(element.attr('data-placement')).to eq('bottom') expect(element.attr('data-container')).to eq('body') expect(element.attr('data-clipboard-text')).to eq(nil) + expect(element.attr('itemprop')).to eq(nil) expect(element.inner_text).to eq("") expect(element.to_html).to include sprite_icon('copy-to-clipboard') @@ -209,5 +210,11 @@ RSpec.describe ButtonHelper do expect(element(hide_button_icon: true).to_html).not_to include sprite_icon('duplicate') end end + + context 'with `itemprop` attribute provided' do + it 'shows copy to clipboard button with `itemprop` attribute' do + expect(element(itemprop: "identifier").attr('itemprop')).to eq("identifier") + end + end end end diff --git a/spec/helpers/ci/pipeline_editor_helper_spec.rb b/spec/helpers/ci/pipeline_editor_helper_spec.rb index 7686983eb0f..a08517d0c57 100644 --- a/spec/helpers/ci/pipeline_editor_helper_spec.rb +++ b/spec/helpers/ci/pipeline_editor_helper_spec.rb @@ -20,4 +20,36 @@ RSpec.describe Ci::PipelineEditorHelper do expect(subject).to be false end end + + describe '#js_pipeline_editor_data' do + let(:project) { create(:project, :repository) } + + before do + allow(helper) + .to receive(:namespace_project_new_merge_request_path) + .and_return('/mock/project/-/merge_requests/new') + + allow(helper) + .to receive(:image_path) + .and_return('foo') + end + + subject(:pipeline_editor_data) { helper.js_pipeline_editor_data(project) } + + it 'returns pipeline editor data' do + expect(pipeline_editor_data).to eq({ + "ci-config-path": project.ci_config_path_or_default, + "commit-sha" => project.commit.sha, + "default-branch" => project.default_branch, + "empty-state-illustration-path" => 'foo', + "initial-branch-name": nil, + "lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'), + "new-merge-request-path" => '/mock/project/-/merge_requests/new', + "project-path" => project.path, + "project-full-path" => project.full_path, + "project-namespace" => project.namespace.full_path, + "yml-help-page-path" => help_page_path('ci/yaml/README') + }) + end + end end diff --git a/spec/helpers/ci/runners_helper_spec.rb b/spec/helpers/ci/runners_helper_spec.rb index 6e41afac4ee..94d4d620de9 100644 --- a/spec/helpers/ci/runners_helper_spec.rb +++ b/spec/helpers/ci/runners_helper_spec.rb @@ -3,19 +3,26 @@ require 'spec_helper' RSpec.describe Ci::RunnersHelper do - it "returns - not contacted yet" do - runner = FactoryBot.build :ci_runner - expect(runner_status_icon(runner)).to include("not connected yet") - end + describe '#runner_status_icon', :clean_gitlab_redis_cache do + it "returns - not contacted yet" do + runner = create(:ci_runner) + expect(runner_status_icon(runner)).to include("not connected yet") + end - it "returns offline text" do - runner = FactoryBot.build(:ci_runner, contacted_at: 1.day.ago, active: true) - expect(runner_status_icon(runner)).to include("Runner is offline") - end + it "returns offline text" do + runner = create(:ci_runner, contacted_at: 1.day.ago, active: true) + expect(runner_status_icon(runner)).to include("Runner is offline") + end - it "returns online text" do - runner = FactoryBot.build(:ci_runner, contacted_at: 1.second.ago, active: true) - expect(runner_status_icon(runner)).to include("Runner is online") + it "returns online text" do + runner = create(:ci_runner, contacted_at: 1.second.ago, active: true) + expect(runner_status_icon(runner)).to include("Runner is online") + end + + it "returns paused text" do + runner = create(:ci_runner, contacted_at: 1.second.ago, active: false) + expect(runner_status_icon(runner)).to include("Runner is paused") + end end describe '#runner_contacted_at' do @@ -77,6 +84,7 @@ RSpec.describe Ci::RunnersHelper do describe '#toggle_shared_runners_settings_data' do let_it_be(:group) { create(:group) } + let(:project_with_runners) { create(:project, namespace: group, shared_runners_enabled: true) } let(:project_without_runners) { create(:project, namespace: group, shared_runners_enabled: false) } diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb index 2a8e2e04947..86ed133e599 100644 --- a/spec/helpers/commits_helper_spec.rb +++ b/spec/helpers/commits_helper_spec.rb @@ -5,58 +5,6 @@ require 'spec_helper' RSpec.describe CommitsHelper do include ProjectForksHelper - describe '#revert_commit_link' do - context 'when current_user exists' do - before do - allow(helper).to receive(:current_user).and_return(double('User')) - end - - it 'renders a div for Vue' do - result = helper.revert_commit_link - - expect(result).to include('js-revert-commit-trigger') - end - end - - context 'when current_user does not exist' do - before do - allow(helper).to receive(:current_user).and_return(nil) - end - - it 'does not render anything' do - result = helper.revert_commit_link - - expect(result).to be_nil - end - end - end - - describe '#cherry_pick_commit_link' do - context 'when current_user exists' do - before do - allow(helper).to receive(:current_user).and_return(double('User')) - end - - it 'renders a div for Vue' do - result = helper.cherry_pick_commit_link - - expect(result).to include('js-cherry-pick-commit-trigger') - end - end - - context 'when current_user does not exist' do - before do - allow(helper).to receive(:current_user).and_return(nil) - end - - it 'does not render anything' do - result = helper.cherry_pick_commit_link - - expect(result).to be_nil - end - end - end - describe 'commit_author_link' do it 'escapes the author email' do commit = double( @@ -252,7 +200,7 @@ RSpec.describe CommitsHelper do end it 'returns data for cherry picking into a project' do - expect(helper.cherry_pick_projects_data(project)).to match_array([ + expect(helper.cherry_pick_projects_data(forked_project)).to match_array([ { id: project.id.to_s, name: project.full_path, refsUrl: refs_project_path(project) }, { id: forked_project.id.to_s, name: forked_project.full_path, refsUrl: refs_project_path(forked_project) } ]) @@ -268,4 +216,77 @@ RSpec.describe CommitsHelper do end end end + + describe "#commit_options_dropdown_data" do + let(:project) { build(:project, :repository) } + let(:commit) { build(:commit) } + let(:user) { build(:user) } + + subject { helper.commit_options_dropdown_data(project, commit) } + + context "when user is logged in" do + before do + allow(helper).to receive(:can?).with(user, :push_code, project).and_return(true) + allow(helper).to receive(:current_user).and_return(user) + end + + it "returns data as expected" do + is_expected.to eq standard_expected_data + end + + context "when can not collaborate on project" do + before do + allow(helper).to receive(:can_collaborate_with_project?).with(project).and_return(false) + end + + it "returns data as expected" do + no_collaboration_values = { + can_revert: 'false', + can_cherry_pick: 'false' + } + + is_expected.to eq standard_expected_data.merge(no_collaboration_values) + end + end + + context "when commit has already been reverted" do + before do + allow(commit).to receive(:has_been_reverted?).with(user).and_return(true) + end + + it "returns data as expected" do + is_expected.to eq standard_expected_data.merge({ can_revert: 'false' }) + end + end + end + + context "when user is not logged in" do + before do + allow(helper).to receive(:can?).with(nil, :push_code, project).and_return(false) + allow(helper).to receive(:current_user).and_return(nil) + end + + it "returns data as expected" do + logged_out_values = { + can_revert: '', + can_cherry_pick: '', + can_tag: 'false' + } + + is_expected.to eq standard_expected_data.merge(logged_out_values) + end + end + + def standard_expected_data + { + new_project_tag_path: new_project_tag_path(project, ref: commit), + email_patches_path: project_commit_path(project, commit, format: :patch), + plain_diff_path: project_commit_path(project, commit, format: :diff), + can_revert: 'true', + can_cherry_pick: 'true', + can_tag: 'true', + can_email_patches: 'true' + } + end + end end diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 20fa8d62884..dfea1020c52 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -291,6 +291,8 @@ RSpec.describe DiffHelper do end describe '#render_overflow_warning?' do + using RSpec::Parameterized::TableSyntax + let(:diffs_collection) { instance_double(Gitlab::Diff::FileCollection::MergeRequestDiff, raw_diff_files: diff_files) } let(:diff_files) { Gitlab::Git::DiffCollection.new(files) } let(:safe_file) { { too_large: false, diff: '' } } @@ -299,13 +301,42 @@ RSpec.describe DiffHelper do before do allow(diff_files).to receive(:overflow?).and_return(false) + allow(diff_files).to receive(:overflow_max_bytes?).and_return(false) + allow(diff_files).to receive(:overflow_max_files?).and_return(false) + allow(diff_files).to receive(:overflow_max_lines?).and_return(false) + allow(diff_files).to receive(:collapsed_safe_bytes?).and_return(false) + allow(diff_files).to receive(:collapsed_safe_files?).and_return(false) + allow(diff_files).to receive(:collapsed_safe_lines?).and_return(false) end - context 'when neither collection nor individual file hit the limit' do + context 'when no limits are hit' do it 'returns false and does not log any overflow events' do expect(Gitlab::Metrics).not_to receive(:add_event).with(:diffs_overflow_collection_limits) expect(Gitlab::Metrics).not_to receive(:add_event).with(:diffs_overflow_single_file_limits) + expect(Gitlab::Metrics).not_to receive(:add_event).with(:diffs_overflow_max_bytes_limits) + expect(Gitlab::Metrics).not_to receive(:add_event).with(:diffs_overflow_max_files_limits) + expect(Gitlab::Metrics).not_to receive(:add_event).with(:diffs_overflow_max_lines_limits) + expect(Gitlab::Metrics).not_to receive(:add_event).with(:diffs_overflow_collapsed_bytes_limits) + expect(Gitlab::Metrics).not_to receive(:add_event).with(:diffs_overflow_collapsed_files_limits) + expect(Gitlab::Metrics).not_to receive(:add_event).with(:diffs_overflow_collapsed_lines_limits) + + expect(render_overflow_warning?(diffs_collection)).to be false + end + end + + where(:overflow_method, :event_name) do + :overflow_max_bytes? | :diffs_overflow_max_bytes_limits + :overflow_max_files? | :diffs_overflow_max_files_limits + :overflow_max_lines? | :diffs_overflow_max_lines_limits + :collapsed_safe_bytes? | :diffs_overflow_collapsed_bytes_limits + :collapsed_safe_files? | :diffs_overflow_collapsed_files_limits + :collapsed_safe_lines? | :diffs_overflow_collapsed_lines_limits + end + with_them do + it 'returns false and only logs the correct collection overflow event' do + allow(diff_files).to receive(overflow_method).and_return(true) + expect(Gitlab::Metrics).to receive(:add_event).with(event_name).once expect(render_overflow_warning?(diffs_collection)).to be false end end @@ -315,9 +346,8 @@ RSpec.describe DiffHelper do allow(diff_files).to receive(:overflow?).and_return(true) end - it 'returns false and only logs collection overflow event' do - expect(Gitlab::Metrics).to receive(:add_event).with(:diffs_overflow_collection_limits).exactly(:once) - expect(Gitlab::Metrics).not_to receive(:add_event).with(:diffs_overflow_single_file_limits) + it 'returns true and only logs all the correct collection overflow event' do + expect(Gitlab::Metrics).to receive(:add_event).with(:diffs_overflow_collection_limits).once expect(render_overflow_warning?(diffs_collection)).to be true end diff --git a/spec/helpers/graph_helper_spec.rb b/spec/helpers/graph_helper_spec.rb index 682f6365481..0930417accb 100644 --- a/spec/helpers/graph_helper_spec.rb +++ b/spec/helpers/graph_helper_spec.rb @@ -16,7 +16,7 @@ RSpec.describe GraphHelper do end end - describe '#should_render_deployment_frequency_charts' do + describe '#should_render_dora_charts' do let(:project) { create(:project, :private) } before do @@ -24,7 +24,7 @@ RSpec.describe GraphHelper do end it 'always returns false' do - expect(should_render_deployment_frequency_charts).to be(false) + expect(should_render_dora_charts).to be(false) end end end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 0d2af464902..d588120bb98 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -5,33 +5,31 @@ require 'spec_helper' RSpec.describe GroupsHelper do include ApplicationHelper - describe 'group_icon_url' do + describe '#group_icon_url' do it 'returns an url for the avatar' do - avatar_file_path = File.join('spec', 'fixtures', 'banana_sample.gif') + group = create(:group, :with_avatar) - group = create(:group) - group.avatar = fixture_file_upload(avatar_file_path) - group.save! - expect(group_icon_url(group.path).to_s) - .to match(group.avatar.url) + expect(group_icon_url(group.path).to_s).to match(group.avatar.url) end it 'gives default avatar_icon when no avatar is present' do - group = create(:group) + group = build_stubbed(:group) + expect(group_icon_url(group.path)).to match_asset_path('group_avatar.png') end end - describe 'group_dependency_proxy_url' do + describe '#group_dependency_proxy_url' do it 'converts uppercase letters to lowercase' do - group = create(:group, path: 'GroupWithUPPERcaseLetters') + group = build_stubbed(:group, path: 'GroupWithUPPERcaseLetters') + expect(group_dependency_proxy_url(group)).to end_with("/groupwithuppercaseletters#{DependencyProxy::URL_SUFFIX}") end end - describe 'group_lfs_status' do - let(:group) { create(:group) } - let!(:project) { create(:project, namespace_id: group.id) } + describe '#group_lfs_status' do + let_it_be_with_reload(:group) { create(:group) } + let_it_be_with_reload(:project) { create(:project, namespace_id: group.id) } before do allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) @@ -54,9 +52,7 @@ RSpec.describe GroupsHelper do end context 'more than one project in group' do - before do - create(:project, namespace_id: group.id) - end + let_it_be_with_reload(:another_project) { create(:project, namespace_id: group.id) } context 'LFS enabled in group' do before do @@ -92,7 +88,7 @@ RSpec.describe GroupsHelper do end end - describe 'group_title' do + describe '#group_title' do let_it_be(:group) { create(:group) } let_it_be(:nested_group) { create(:group, parent: group) } let_it_be(:deep_nested_group) { create(:group, parent: nested_group) } @@ -113,16 +109,26 @@ RSpec.describe GroupsHelper do subject end + + it 'avoids N+1 queries' do + control_count = ActiveRecord::QueryRecorder.new do + helper.group_title(nested_group) + end + + expect do + helper.group_title(very_deep_nested_group) + end.not_to exceed_query_limit(control_count) + end end - # rubocop:disable Layout/SpaceBeforeComma describe '#share_with_group_lock_help_text' do - let!(:root_group) { create(:group) } - let!(:subgroup) { create(:group, parent: root_group) } - let!(:sub_subgroup) { create(:group, parent: subgroup) } - let(:root_owner) { create(:user) } - let(:sub_owner) { create(:user) } - let(:sub_sub_owner) { create(:user) } + let_it_be_with_reload(:root_group) { create(:group) } + let_it_be_with_reload(:subgroup) { create(:group, parent: root_group) } + let_it_be_with_reload(:sub_subgroup) { create(:group, parent: subgroup) } + let_it_be(:root_owner) { create(:user) } + let_it_be(:sub_owner) { create(:user) } + let_it_be(:sub_sub_owner) { create(:user) } + let(:possible_help_texts) do { default_help: "This setting will be applied to all subgroups unless overridden by a group owner", @@ -149,6 +155,13 @@ RSpec.describe GroupsHelper do subject { helper.share_with_group_lock_help_text(sub_subgroup) } + before_all do + root_group.add_owner(root_owner) + subgroup.add_owner(sub_owner) + sub_subgroup.add_owner(sub_sub_owner) + end + + # rubocop:disable Layout/SpaceBeforeComma where(:root_share_with_group_locked, :subgroup_share_with_group_locked, :sub_subgroup_share_with_group_locked, :current_user, :help_text, :linked_ancestor) do [ [false , false , false , :root_owner , :default_help , nil], @@ -177,13 +190,10 @@ RSpec.describe GroupsHelper do [true , true , true , :sub_sub_owner , :ancestor_locked_so_ask_the_owner , :root_group] ] end + # rubocop:enable Layout/SpaceBeforeComma with_them do before do - root_group.add_owner(root_owner) - subgroup.add_owner(sub_owner) - sub_subgroup.add_owner(sub_sub_owner) - root_group.update_column(:share_with_group_lock, true) if root_share_with_group_locked subgroup.update_column(:share_with_group_lock, true) if subgroup_share_with_group_locked sub_subgroup.update_column(:share_with_group_lock, true) if sub_subgroup_share_with_group_locked @@ -212,8 +222,8 @@ RSpec.describe GroupsHelper do end describe '#group_container_registry_nav' do - let(:group) { create(:group, :public) } - let(:user) { create(:user) } + let_it_be(:group) { create(:group, :public) } + let_it_be(:user) { create(:user) } before do stub_container_registry_config(enabled: true) @@ -248,8 +258,8 @@ RSpec.describe GroupsHelper do end describe '#group_sidebar_links' do - let(:group) { create(:group, :public) } - let(:user) { create(:user) } + let_it_be(:group) { create(:group, :public) } + let_it_be(:user) { create(:user) } before do group.add_owner(user) @@ -287,10 +297,10 @@ RSpec.describe GroupsHelper do end end - describe 'parent_group_options' do - let(:current_user) { create(:user) } - let(:group) { create(:group, name: 'group') } - let(:group2) { create(:group, name: 'group2') } + describe '#parent_group_options' do + let_it_be(:current_user) { create(:user) } + let_it_be(:group) { create(:group, name: 'group') } + let_it_be(:group2) { create(:group, name: 'group2') } before do group.add_owner(current_user) @@ -321,9 +331,9 @@ RSpec.describe GroupsHelper do end describe '#can_disable_group_emails?' do - let(:current_user) { create(:user) } - let(:group) { create(:group, name: 'group') } - let(:subgroup) { create(:group, name: 'subgroup', parent: group) } + let_it_be(:current_user) { create(:user) } + let_it_be(:group) { create(:group, name: 'group') } + let_it_be(:subgroup) { create(:group, name: 'subgroup', parent: group) } before do allow(helper).to receive(:current_user) { current_user } @@ -361,8 +371,8 @@ RSpec.describe GroupsHelper do end describe '#can_update_default_branch_protection?' do - let(:current_user) { create(:user) } - let(:group) { create(:group) } + let_it_be(:current_user) { create(:user) } + let_it_be(:group) { create(:group) } subject { helper.can_update_default_branch_protection?(group) } @@ -451,75 +461,42 @@ RSpec.describe GroupsHelper do end end - describe '#group_open_issues_count' do + describe '#render_setting_to_allow_project_access_token_creation?' do let_it_be(:current_user) { create(:user) } - let_it_be(:group) { create(:group, :public) } - let_it_be(:count_service) { Groups::OpenIssuesCountService } + let_it_be(:parent) { create(:group) } + let_it_be(:group) { create(:group, parent: parent) } before do allow(helper).to receive(:current_user) { current_user } + parent.add_owner(current_user) + group.add_owner(current_user) end - it 'returns count value from cache' do - allow_next_instance_of(count_service) do |service| - allow(service).to receive(:count).and_return(2500) - end - - expect(helper.group_open_issues_count(group)).to eq('2.5k') + it 'returns true if group is root' do + expect(helper.render_setting_to_allow_project_access_token_creation?(parent)).to be_truthy end - context 'when cached_sidebar_open_issues_count feature flag is disabled' do - before do - stub_feature_flags(cached_sidebar_open_issues_count: false) - end - - it 'returns not cached issues count' do - allow(helper).to receive(:group_issues_count).and_return(2500) - - expect(helper.group_open_issues_count(group)).to eq('2,500') - end + it 'returns false if group is subgroup' do + expect(helper.render_setting_to_allow_project_access_token_creation?(group)).to be_falsy end end - describe '#cached_open_group_issues_count' do + describe '#cached_issuables_count' do let_it_be(:current_user) { create(:user) } let_it_be(:group) { create(:group, name: 'group') } - let_it_be(:count_service) { Groups::OpenIssuesCountService } - before do - allow(helper).to receive(:current_user) { current_user } - end + context 'with issues type' do + let(:type) { :issues } + let(:count_service) { Groups::OpenIssuesCountService } - it 'returns all digits for count value under 1000' do - allow_next_instance_of(count_service) do |service| - allow(service).to receive(:count).and_return(999) - end - - expect(helper.cached_open_group_issues_count(group)).to eq('999') - end - - it 'returns truncated digits for count value over 1000' do - allow_next_instance_of(count_service) do |service| - allow(service).to receive(:count).and_return(2300) - end - - expect(helper.cached_open_group_issues_count(group)).to eq('2.3k') + it_behaves_like 'cached issuables count' end - it 'returns truncated digits for count value over 10000' do - allow_next_instance_of(count_service) do |service| - allow(service).to receive(:count).and_return(12560) - end - - expect(helper.cached_open_group_issues_count(group)).to eq('12.6k') - end - - it 'returns truncated digits for count value over 100000' do - allow_next_instance_of(count_service) do |service| - allow(service).to receive(:count).and_return(112560) - end + context 'with merge requests type' do + let(:type) { :merge_requests } + let(:count_service) { Groups::MergeRequestsCountService } - expect(helper.cached_open_group_issues_count(group)).to eq('112.6k') + it_behaves_like 'cached issuables count' end end end diff --git a/spec/helpers/ide_helper_spec.rb b/spec/helpers/ide_helper_spec.rb index db30446fa95..963d5953d4c 100644 --- a/spec/helpers/ide_helper_spec.rb +++ b/spec/helpers/ide_helper_spec.rb @@ -17,7 +17,7 @@ RSpec.describe IdeHelper do 'branch-name' => nil, 'file-path' => nil, 'merge-request' => nil, - 'forked-project' => nil, + 'fork-info' => nil, 'project' => nil ) end @@ -25,10 +25,12 @@ RSpec.describe IdeHelper do context 'when instance vars are set' do it 'returns instance data in the hash' do + fork_info = { ide_path: '/test/ide/path' } + self.instance_variable_set(:@branch, 'master') self.instance_variable_set(:@path, 'foo/bar') self.instance_variable_set(:@merge_request, '1') - self.instance_variable_set(:@forked_project, project) + self.instance_variable_set(:@fork_info, fork_info) self.instance_variable_set(:@project, project) serialized_project = API::Entities::Project.represent(project).to_json @@ -38,7 +40,7 @@ RSpec.describe IdeHelper do 'branch-name' => 'master', 'file-path' => 'foo/bar', 'merge-request' => '1', - 'forked-project' => serialized_project, + 'fork-info' => fork_info.to_json, 'project' => serialized_project ) end diff --git a/spec/helpers/invite_members_helper_spec.rb b/spec/helpers/invite_members_helper_spec.rb index 62bd953cce8..109b1fc4441 100644 --- a/spec/helpers/invite_members_helper_spec.rb +++ b/spec/helpers/invite_members_helper_spec.rb @@ -5,6 +5,7 @@ require "spec_helper" RSpec.describe InviteMembersHelper do let_it_be(:project) { create(:project) } let_it_be(:developer) { create(:user, developer_projects: [project]) } + let(:owner) { project.owner } before do @@ -253,6 +254,7 @@ RSpec.describe InviteMembersHelper do context 'with a project' do let_it_be(:form_model) { project } + let(:link_href) { "href=\"#{project_project_members_path(form_model)}\"" } it_behaves_like 'dropdown invite members link' @@ -260,6 +262,7 @@ RSpec.describe InviteMembersHelper do context 'with a group' do let_it_be(:form_model) { create(:group) } + let(:link_href) { "href=\"#{group_group_members_path(form_model)}\"" } it_behaves_like 'dropdown invite members link' diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index d6b002b47eb..54524858962 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -44,6 +44,60 @@ RSpec.describe IssuablesHelper do end end + describe '#assignees_label' do + let(:issuable) { build(:merge_request) } + let(:assignee1) { build_stubbed(:user, name: 'Jane Doe') } + let(:assignee2) { build_stubbed(:user, name: 'John Doe') } + + before do + allow(issuable).to receive(:assignees).and_return(assignees) + end + + context 'when multiple assignees exist' do + let(:assignees) { [assignee1, assignee2] } + + it 'returns assignee label with assignee names' do + expect(helper.assignees_label(issuable)).to eq("Assignees: Jane Doe and John Doe") + end + + it 'returns assignee label only with include_value: false' do + expect(helper.assignees_label(issuable, include_value: false)).to eq("Assignees") + end + + context 'when the name contains a URL' do + let(:assignees) { [build_stubbed(:user, name: 'www.gitlab.com')] } + + it 'returns sanitized name' do + expect(helper.assignees_label(issuable)).to eq("Assignee: www_gitlab_com") + end + end + end + + context 'when one assignee exists' do + let(:assignees) { [assignee1] } + + it 'returns assignee label with no names' do + expect(helper.assignees_label(issuable)).to eq("Assignee: Jane Doe") + end + + it 'returns assignee label only with include_value: false' do + expect(helper.assignees_label(issuable, include_value: false)).to eq("Assignee") + end + end + + context 'when no assignees exist' do + let(:assignees) { [] } + + it 'returns assignee label with no names' do + expect(helper.assignees_label(issuable)).to eq("Assignees: ") + end + + it 'returns assignee label only with include_value: false' do + expect(helper.assignees_label(issuable, include_value: false)).to eq("Assignees") + end + end + end + describe '#issuable_meta' do let(:user) { create(:user) } diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 07e55e9b016..21a01f349b5 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -281,4 +281,55 @@ RSpec.describe IssuesHelper do expect(helper.issue_header_actions_data(project, issue, current_user)).to include(expected) end end + + shared_examples 'issues list data' do + it 'returns expected result' do + finder = double.as_null_object + allow(helper).to receive(:current_user).and_return(current_user) + allow(helper).to receive(:finder).and_return(finder) + allow(helper).to receive(:can?).and_return(true) + allow(helper).to receive(:image_path).and_return('#') + allow(helper).to receive(:import_csv_namespace_project_issues_path).and_return('#') + allow(helper).to receive(:url_for).and_return('#') + + expected = { + calendar_path: '#', + can_bulk_update: 'true', + can_edit: 'true', + can_import_issues: 'true', + email: current_user&.notification_email, + empty_state_svg_path: '#', + endpoint: expose_path(api_v4_projects_issues_path(id: project.id)), + export_csv_path: export_csv_project_issues_path(project), + full_path: project.full_path, + has_issues: project_issues(project).exists?.to_s, + import_csv_issues_path: '#', + is_signed_in: current_user.present?.to_s, + issues_path: project_issues_path(project), + jira_integration_path: help_page_url('user/project/integrations/jira', anchor: 'view-jira-issues'), + max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes), + new_issue_path: new_project_issue_path(project, issue: { assignee_id: finder.assignee.id, milestone_id: finder.milestones.first.id }), + project_import_jira_path: project_import_jira_path(project), + rss_path: '#', + show_new_issue_link: 'true', + sign_in_path: new_user_session_path + } + + expect(helper.issues_list_data(project, current_user, finder)).to include(expected) + end + end + + describe '#issues_list_data' do + context 'when user is signed in' do + it_behaves_like 'issues list data' do + let(:current_user) { double.as_null_object } + end + end + + context 'when user is anonymous' do + it_behaves_like 'issues list data' do + let(:current_user) { nil } + end + end + end end diff --git a/spec/helpers/jira_connect_helper_spec.rb b/spec/helpers/jira_connect_helper_spec.rb index 9695bed948b..55a5c724665 100644 --- a/spec/helpers/jira_connect_helper_spec.rb +++ b/spec/helpers/jira_connect_helper_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' RSpec.describe JiraConnectHelper do describe '#jira_connect_app_data' do let_it_be(:subscription) { create(:jira_connect_subscription) } + let(:user) { create(:user) } subject { helper.jira_connect_app_data([subscription]) } diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index b93dc03e434..526983a0d5f 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -36,6 +36,7 @@ RSpec.describe LabelsHelper do context 'with a group label' do let_it_be(:group) { create(:group) } + let(:label) { create(:group_label, group: group, title: 'bug') } context 'when asking for an issue link' do diff --git a/spec/helpers/learn_gitlab_helper_spec.rb b/spec/helpers/learn_gitlab_helper_spec.rb index 6cee8a9191c..82c8e4ba596 100644 --- a/spec/helpers/learn_gitlab_helper_spec.rb +++ b/spec/helpers/learn_gitlab_helper_spec.rb @@ -27,6 +27,7 @@ RSpec.describe LearnGitlabHelper do it 'has all actions' do expect(onboarding_actions_data.keys).to contain_exactly( + :issue_created, :git_write, :pipeline_created, :merge_request_created, diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 3d1690f6588..00a59f037e0 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -13,6 +13,7 @@ RSpec.describe MarkupHelper do let_it_be(:issue) { create(:issue, project: project) } let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let_it_be(:snippet) { create(:project_snippet, project: project) } + let(:commit) { project.commit } before do @@ -382,6 +383,27 @@ RSpec.describe MarkupHelper do end end + context 'when file is Kramdown' do + let(:extension) { 'rmd' } + let(:content) do + <<-EOF +{::options parse_block_html="true" /} + +<div> +FooBar +</div> + EOF + end + + it 'renders using #markdown_unsafe helper method' do + expect(helper).to receive(:markdown_unsafe).with(content, context) + + result = helper.render_wiki_content(wiki) + + expect(result).to be_empty + end + end + context 'any other format' do let(:extension) { 'foo' } @@ -432,6 +454,7 @@ RSpec.describe MarkupHelper do let_it_be(:project_base) { create(:project, :repository) } let_it_be(:context) { { project: project_base } } + let(:file_name) { 'foo.bar' } let(:text) { 'Noël' } @@ -554,7 +577,7 @@ RSpec.describe MarkupHelper do it 'preserves code color scheme' do object = create_object("```ruby\ndef test\n 'hello world'\nend\n```") - expected = "<pre class=\"code highlight js-syntax-highlight ruby\">" \ + expected = "<pre class=\"code highlight js-syntax-highlight language-ruby\">" \ "<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>\n" \ "</code></pre>" diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb index b436f4ab0c9..8c08b06d8a8 100644 --- a/spec/helpers/namespaces_helper_spec.rb +++ b/spec/helpers/namespaces_helper_spec.rb @@ -194,4 +194,75 @@ RSpec.describe NamespacesHelper do end end end + + describe '#cascading_namespace_settings_enabled?' do + subject { helper.cascading_namespace_settings_enabled? } + + context 'when `cascading_namespace_settings` feature flag is enabled' do + it 'returns `true`' do + expect(subject).to be(true) + end + end + + context 'when `cascading_namespace_settings` feature flag is disabled' do + before do + stub_feature_flags(cascading_namespace_settings: false) + end + + it 'returns `false`' do + expect(subject).to be(false) + end + end + end + + describe '#cascading_namespace_settings_popover_data' do + attribute = :delayed_project_removal + + subject do + helper.cascading_namespace_settings_popover_data( + attribute, + subgroup1, + -> (locked_ancestor) { edit_group_path(locked_ancestor, anchor: 'js-permissions-settings') } + ) + end + + context 'when locked by an application setting' do + before do + allow(subgroup1.namespace_settings).to receive("#{attribute}_locked_by_application_setting?").and_return(true) + allow(subgroup1.namespace_settings).to receive("#{attribute}_locked_by_ancestor?").and_return(false) + end + + it 'returns expected hash' do + expect(subject).to match({ + popover_data: { + locked_by_application_setting: true, + locked_by_ancestor: false + }.to_json, + testid: 'cascading-settings-lock-icon' + }) + end + end + + context 'when locked by an ancestor namespace' do + before do + allow(subgroup1.namespace_settings).to receive("#{attribute}_locked_by_application_setting?").and_return(false) + allow(subgroup1.namespace_settings).to receive("#{attribute}_locked_by_ancestor?").and_return(true) + allow(subgroup1.namespace_settings).to receive("#{attribute}_locked_ancestor").and_return(admin_group.namespace_settings) + end + + it 'returns expected hash' do + expect(subject).to match({ + popover_data: { + locked_by_application_setting: false, + locked_by_ancestor: true, + ancestor_namespace: { + full_name: admin_group.full_name, + path: edit_group_path(admin_group, anchor: 'js-permissions-settings') + } + }.to_json, + testid: 'cascading-settings-lock-icon' + }) + end + end + end end diff --git a/spec/helpers/nav_helper_spec.rb b/spec/helpers/nav_helper_spec.rb index c4795a814ba..2efff3402c5 100644 --- a/spec/helpers/nav_helper_spec.rb +++ b/spec/helpers/nav_helper_spec.rb @@ -35,7 +35,7 @@ RSpec.describe NavHelper do context 'as admin' do let(:user) { create(:user, :admin) } - context 'feature flag :user_mode_in_session is enabled' do + context 'application setting :admin_mode is enabled' do it 'does not contain the admin mode link by default' do expect(helper.header_links).not_to include(:admin_mode) end @@ -52,9 +52,9 @@ RSpec.describe NavHelper do end end - context 'feature flag :user_mode_in_session is disabled' do + context 'application setting :admin_mode is disabled' do before do - stub_feature_flags(user_mode_in_session: false) + stub_application_setting(admin_mode: false) end it 'does not contain the admin mode link' do diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index b8502cdf25e..fc62bbf8bf8 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -15,6 +15,7 @@ RSpec.describe NotesHelper do let_it_be(:owner_note) { create(:note, author: owner, project: project) } let_it_be(:maintainer_note) { create(:note, author: maintainer, project: project) } let_it_be(:reporter_note) { create(:note, author: reporter, project: project) } + let!(:notes) { [owner_note, maintainer_note, reporter_note] } before_all do @@ -73,6 +74,7 @@ RSpec.describe NotesHelper do describe '#discussion_path' do let_it_be(:project) { create(:project, :repository) } + let(:anchor) { discussion.line_code } context 'for a merge request discusion' do diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index 99cdee6dbb2..d03e39f2051 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -223,39 +223,37 @@ RSpec.describe PageLayoutHelper do end describe '#user_status_properties' do - using RSpec::Parameterized::TableSyntax - let(:user) { build(:user) } - availability_types = Types::AvailabilityEnum.enum - - where(:message, :emoji, :availability) do - "Some message" | UserStatus::DEFAULT_EMOJI | availability_types[:busy] - "Some message" | UserStatus::DEFAULT_EMOJI | availability_types[:not_set] - "Some message" | "basketball" | availability_types[:busy] - "Some message" | "basketball" | availability_types[:not_set] - "Some message" | "" | availability_types[:busy] - "Some message" | "" | availability_types[:not_set] - "" | UserStatus::DEFAULT_EMOJI | availability_types[:busy] - "" | UserStatus::DEFAULT_EMOJI | availability_types[:not_set] - "" | "basketball" | availability_types[:busy] - "" | "basketball" | availability_types[:not_set] - "" | "" | availability_types[:busy] - "" | "" | availability_types[:not_set] - end + subject { helper.user_status_properties(user) } - with_them do - it "sets the default user status fields" do - user.status = UserStatus.new(message: message, emoji: emoji, availability: availability) - result = { + context 'when the user has no status' do + it 'returns default properties' do + is_expected.to eq({ + current_emoji: '', + current_message: '', can_set_user_availability: true, - current_availability: availability, - current_emoji: emoji, - current_message: message, default_emoji: UserStatus::DEFAULT_EMOJI - } + }) + end + end + + context 'when user has a status' do + let(:time) { 3.hours.ago } - expect(helper.user_status_properties(user)).to eq(result) + before do + user.status = UserStatus.new(message: 'Some message', emoji: 'basketball', availability: 'busy', clear_status_at: time) + end + + it 'merges the status properties with the defaults' do + is_expected.to eq({ + current_clear_status_after: time.to_s, + current_availability: 'busy', + current_emoji: 'basketball', + current_message: 'Some message', + can_set_user_availability: true, + default_emoji: UserStatus::DEFAULT_EMOJI + }) end end end diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index e5420fb6729..4d7083c4ca7 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -33,7 +33,7 @@ RSpec.describe PreferencesHelper do ["Your Groups", 'groups'], ["Your To-Do List", 'todos'], ["Assigned Issues", 'issues'], - ["Assigned Merge Requests", 'merge_requests'] + ["Assigned merge requests", 'merge_requests'] ] end end diff --git a/spec/helpers/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb index 9687d038162..2ea832f95dc 100644 --- a/spec/helpers/profiles_helper_spec.rb +++ b/spec/helpers/profiles_helper_spec.rb @@ -112,6 +112,46 @@ RSpec.describe ProfilesHelper do end end + describe "#ssh_key_expiration_tooltip" do + using RSpec::Parameterized::TableSyntax + + before do + allow(Key).to receive(:enforce_ssh_key_expiration_feature_available?).and_return(false) + end + + error_message = 'Key type is forbidden. Must be DSA, ECDSA, or ED25519' + + where(:error, :expired, :result) do + false | false | nil + true | false | error_message + false | true | 'Key usable beyond expiration date.' + true | true | error_message + end + + with_them do + let_it_be(:key) do + build(:personal_key) + end + + it do + key.expires_at = expired ? 2.days.ago : 2.days.from_now + key.errors.add(:base, error_message) if error + + expect(helper.ssh_key_expiration_tooltip(key)).to eq(result) + end + end + end + + describe "#ssh_key_expires_field_description" do + before do + allow(Key).to receive(:enforce_ssh_key_expiration_feature_available?).and_return(false) + end + + it 'returns the description' do + expect(helper.ssh_key_expires_field_description).to eq('Key can still be used after expiration.') + end + end + def stub_cas_omniauth_provider provider = OpenStruct.new( 'name' => 'cas3', diff --git a/spec/helpers/projects/alert_management_helper_spec.rb b/spec/helpers/projects/alert_management_helper_spec.rb index 0df194e460a..e836461b099 100644 --- a/spec/helpers/projects/alert_management_helper_spec.rb +++ b/spec/helpers/projects/alert_management_helper_spec.rb @@ -7,6 +7,7 @@ RSpec.describe Projects::AlertManagementHelper do let_it_be(:project, reload: true) { create(:project) } let_it_be(:current_user) { create(:user) } + let(:project_path) { project.full_path } let(:project_id) { project.id } diff --git a/spec/helpers/projects/issues/service_desk_helper_spec.rb b/spec/helpers/projects/issues/service_desk_helper_spec.rb index 3f488fe692d..05766ee13c6 100644 --- a/spec/helpers/projects/issues/service_desk_helper_spec.rb +++ b/spec/helpers/projects/issues/service_desk_helper_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe Projects::Issues::ServiceDeskHelper do let_it_be(:project) { create(:project, :public, service_desk_enabled: true) } + let(:user) { build_stubbed(:user) } let(:current_user) { user } diff --git a/spec/helpers/projects/project_members_helper_spec.rb b/spec/helpers/projects/project_members_helper_spec.rb index 1a55840a58a..0e08a18f912 100644 --- a/spec/helpers/projects/project_members_helper_spec.rb +++ b/spec/helpers/projects/project_members_helper_spec.rb @@ -128,6 +128,7 @@ RSpec.describe Projects::ProjectMembersHelper do describe "when current user is not the owner of the project's parent group" do let_it_be(:user) { create(:user) } + let(:project2) { create(:project, namespace: group) } before do @@ -174,6 +175,7 @@ RSpec.describe Projects::ProjectMembersHelper do describe 'project group links' do let_it_be(:project_group_links) { create_list(:project_group_link, 1, project: project) } + let(:allow_admin_project) { true } describe '#project_group_links_data_json' do diff --git a/spec/helpers/projects/terraform_helper_spec.rb b/spec/helpers/projects/terraform_helper_spec.rb index 70b08f4139b..8833e23c47d 100644 --- a/spec/helpers/projects/terraform_helper_spec.rb +++ b/spec/helpers/projects/terraform_helper_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' RSpec.describe Projects::TerraformHelper do describe '#js_terraform_list_data' do let_it_be(:project) { create(:project) } + let(:current_user) { project.creator } subject { helper.js_terraform_list_data(current_user, project) } diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index e6cd11a4d70..124cdcec05d 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -85,6 +85,7 @@ RSpec.describe ProjectsHelper do describe "can_change_visibility_level?" do let_it_be(:user) { create(:project_member, :reporter, user: create(:user), project: project).user } + let(:forked_project) { fork_project(project, user) } it "returns false if there are no appropriate permissions" do diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 13d3a80bd13..7b2334ab79e 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -489,6 +489,7 @@ RSpec.describe SearchHelper do describe '#repository_ref' do let_it_be(:project) { create(:project, :repository) } + let(:params) { { repository_ref: 'the-repository-ref-param' } } subject { repository_ref(project) } diff --git a/spec/helpers/services_helper_spec.rb b/spec/helpers/services_helper_spec.rb index 1726a8362a7..6dd872225ba 100644 --- a/spec/helpers/services_helper_spec.rb +++ b/spec/helpers/services_helper_spec.rb @@ -27,17 +27,31 @@ RSpec.describe ServicesHelper do ] end + let(:jira_fields) do + [ + :jira_issue_transition_automatic, + :jira_issue_transition_id + ] + end + subject { helper.integration_form_data(integration) } context 'Slack service' do let(:integration) { build(:slack_service) } it { is_expected.to include(*fields) } + it { is_expected.not_to include(*jira_fields) } specify do expect(subject[:reset_path]).to eq(helper.scoped_reset_integration_path(integration)) end end + + context 'Jira service' do + let(:integration) { build(:jira_service) } + + it { is_expected.to include(*fields, *jira_fields) } + end end describe '#scoped_reset_integration_path' do diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb new file mode 100644 index 00000000000..e329968e6c0 --- /dev/null +++ b/spec/helpers/sidebars_helper_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe SidebarsHelper do + describe '#sidebar_tracking_attributes_by_object' do + subject { helper.sidebar_tracking_attributes_by_object(object) } + + before do + allow(helper).to receive(:tracking_enabled?).and_return(true) + end + + context 'when object is a project' do + let(:object) { build(:project) } + + it 'returns tracking attrs for project' do + expect(subject[:data]).to eq({ track_label: 'projects_side_navigation', track_property: 'projects_side_navigation', track_action: 'render' }) + end + end + + context 'when object is a group' do + let(:object) { build(:group) } + + it 'returns tracking attrs for group' do + expect(subject[:data]).to eq({ track_label: 'groups_side_navigation', track_property: 'groups_side_navigation', track_action: 'render' }) + end + end + + context 'when object is a user' do + let(:object) { build(:user) } + + it 'returns tracking attrs for user' do + expect(subject[:data]).to eq({ track_label: 'user_side_navigation', track_property: 'user_side_navigation', track_action: 'render' }) + end + end + + context 'when object is something else' do + let(:object) { build(:ci_pipeline) } + + it 'returns no attributes' do + expect(subject).to eq({}) + end + end + end +end diff --git a/spec/helpers/snippets_helper_spec.rb b/spec/helpers/snippets_helper_spec.rb index 5a3c8e37e8c..35882c9337b 100644 --- a/spec/helpers/snippets_helper_spec.rb +++ b/spec/helpers/snippets_helper_spec.rb @@ -32,7 +32,7 @@ RSpec.describe SnippetsHelper do end def download_link(url) - "<a class=\"btn\" target=\"_blank\" rel=\"noopener noreferrer\" title=\"Open raw\" href=\"#{url}\">#{external_snippet_icon('doc-code')}</a>" + "<a class=\"gl-button btn btn-default\" target=\"_blank\" rel=\"noopener noreferrer\" title=\"Open raw\" href=\"#{url}\">#{external_snippet_icon('doc-code')}</a>" end end @@ -59,31 +59,7 @@ RSpec.describe SnippetsHelper do end def download_link(url) - "<a class=\"btn\" target=\"_blank\" title=\"Download\" rel=\"noopener noreferrer\" href=\"#{url}?inline=false\">#{external_snippet_icon('download')}</a>" - end - end - - describe '#download_raw_snippet_button' do - subject { download_raw_snippet_button(snippet) } - - context 'with personal snippet' do - let(:snippet) { public_personal_snippet } - - it 'returns the download button' do - expect(subject).to eq(download_link("/-/snippets/#{snippet.id}/raw")) - end - end - - context 'with project snippet' do - let(:snippet) { public_project_snippet } - - it 'returns the download button' do - expect(subject).to eq(download_link("/#{snippet.project.path_with_namespace}/-/snippets/#{snippet.id}/raw")) - end - end - - def download_link(url) - "<a target=\"_blank\" rel=\"noopener noreferrer\" class=\"btn btn-sm has-tooltip\" title=\"Download\" data-container=\"body\" href=\"#{url}?inline=false\">#{sprite_icon('download')}</a>" + "<a class=\"gl-button btn btn-default\" target=\"_blank\" title=\"Download\" rel=\"noopener noreferrer\" href=\"#{url}?inline=false\">#{external_snippet_icon('download')}</a>" end end diff --git a/spec/helpers/tab_helper_spec.rb b/spec/helpers/tab_helper_spec.rb index f89d0ac0f5a..bd8a8fa174a 100644 --- a/spec/helpers/tab_helper_spec.rb +++ b/spec/helpers/tab_helper_spec.rb @@ -6,81 +6,94 @@ RSpec.describe TabHelper do include ApplicationHelper describe 'nav_link' do + using RSpec::Parameterized::TableSyntax + before do allow(controller).to receive(:controller_name).and_return('foo') allow(self).to receive(:action_name).and_return('foo') end context 'with the content of the li' do - it "captures block output" do + it 'captures block output' do expect(nav_link { "Testing Blocks" }).to match(/Testing Blocks/) end end - context 'with controller param' do - it "performs checks on the current controller" do - expect(nav_link(controller: :foo)).to match(/<li class="active">/) - expect(nav_link(controller: :bar)).not_to match(/active/) - expect(nav_link(controller: [:foo, :bar])).to match(/active/) - end + it 'passes extra html options to the list element' do + expect(nav_link(action: :foo, html_options: { class: 'home' })).to match(/<li class="home active">/) + expect(nav_link(html_options: { class: 'active' })).to match(/<li class="active">/) + end - context 'with action param' do - it "performs checks on both controller and action when both are present" do - expect(nav_link(controller: :bar, action: :foo)).not_to match(/active/) - expect(nav_link(controller: :foo, action: :bar)).not_to match(/active/) - expect(nav_link(controller: :foo, action: :foo)).to match(/active/) - end - end + where(:controller_param, :action_param, :path_param, :active) do + nil | nil | nil | false + :foo | nil | nil | true + :bar | nil | nil | false + :bar | :foo | nil | false + :foo | :bar | nil | false + :foo | :foo | nil | true + :bar | nil | 'foo#foo' | true + :bar | nil | ['foo#foo', 'bar#bar'] | true + :bar | :bar | ['foo#foo', 'bar#bar'] | true + :foo | nil | 'bar#foo' | true + :bar | nil | 'bar#foo' | false + :foo | [:foo, :bar] | 'bar#foo' | true + :bar | :bar | 'foo#foo' | true + :foo | :foo | 'bar#foo' | true + :bar | :foo | 'bar#foo' | false + :foo | :bar | 'bar#foo' | false + [:foo, :bar] | nil | nil | true + [:foo, :bar] | nil | 'bar#foo' | true + [:foo, :bar] | :foo | 'bar#foo' | true + nil | :foo | nil | true + nil | :bar | nil | false + nil | nil | 'foo#bar' | false + nil | nil | 'foo#foo' | true + nil | :bar | ['foo#foo', 'bar#bar'] | true + nil | :bar | 'foo#foo' | true + nil | :foo | 'bar#foo' | true + nil | [:foo, :bar] | nil | true + nil | [:foo, :bar] | 'bar#foo' | true + nil | :bar | 'bar#foo' | false + end - context 'with namespace in path notation' do - before do - allow(controller).to receive(:controller_path).and_return('bar/foo') - end + with_them do + specify do + result = nav_link(controller: controller_param, action: action_param, path: path_param) - it 'performs checks on both controller and namespace' do - expect(nav_link(controller: 'foo/foo')).not_to match(/active/) - expect(nav_link(controller: 'bar/foo')).to match(/active/) - end - - context 'with action param' do - it "performs checks on both namespace, controller and action when they are all present" do - expect(nav_link(controller: 'foo/foo', action: :foo)).not_to match(/active/) - expect(nav_link(controller: 'bar/foo', action: :bar)).not_to match(/active/) - expect(nav_link(controller: 'bar/foo', action: :foo)).to match(/active/) - end + if active + expect(result).to match(/active/) + else + expect(result).not_to match(/active/) end end end - context 'with action param' do - it "performs checks on the current action" do - expect(nav_link(action: :foo)).to match(/<li class="active">/) - expect(nav_link(action: :bar)).not_to match(/active/) - expect(nav_link(action: [:foo, :bar])).to match(/active/) + context 'with namespace in path notation' do + before do + allow(controller).to receive(:controller_path).and_return('bar/foo') end - end - context 'with path param' do - it "accepts a path shorthand" do - expect(nav_link(path: 'foo#bar')).not_to match(/active/) - expect(nav_link(path: 'foo#foo')).to match(/active/) + where(:controller_param, :action_param, :path_param, :active) do + 'foo/foo' | nil | nil | false + 'bar/foo' | nil | nil | true + 'foo/foo' | :foo | nil | false + 'bar/foo' | :bar | nil | false + 'bar/foo' | :foo | nil | true + nil | nil | 'foo/foo#foo' | false + nil | nil | 'bar/foo#foo' | true end - context 'with namespace' do - before do - allow(controller).to receive(:controller_path).and_return('bar/foo') - end + with_them do + specify do + result = nav_link(controller: controller_param, action: action_param, path: path_param) - it 'accepts a path shorthand with namespace' do - expect(nav_link(path: 'bar/foo#foo')).to match(/active/) - expect(nav_link(path: 'foo/foo#foo')).not_to match(/active/) + if active + expect(result).to match(/active/) + else + expect(result).not_to match(/active/) + end end end end - - it "passes extra html options to the list element" do - expect(nav_link(action: :foo, html_options: { class: 'home' })).to match(/<li class="home active">/) - expect(nav_link(html_options: { class: 'active' })).to match(/<li class="active">/) - end end end diff --git a/spec/helpers/timeboxes_helper_spec.rb b/spec/helpers/timeboxes_helper_spec.rb index 9cbed7668ac..1b9442c0a09 100644 --- a/spec/helpers/timeboxes_helper_spec.rb +++ b/spec/helpers/timeboxes_helper_spec.rb @@ -3,42 +3,6 @@ require 'spec_helper' RSpec.describe TimeboxesHelper do - describe '#milestones_filter_dropdown_path' do - let(:project) { create(:project) } - let(:project2) { create(:project) } - let(:group) { create(:group) } - - context 'when @project present' do - it 'returns project milestones JSON URL' do - assign(:project, project) - - expect(helper.milestones_filter_dropdown_path).to eq(project_milestones_path(project, :json)) - end - end - - context 'when @target_project present' do - it 'returns targeted project milestones JSON URL' do - assign(:target_project, project2) - - expect(helper.milestones_filter_dropdown_path).to eq(project_milestones_path(project2, :json)) - end - end - - context 'when @group present' do - it 'returns group milestones JSON URL' do - assign(:group, group) - - expect(helper.milestones_filter_dropdown_path).to eq(group_milestones_path(group, :json)) - end - end - - context 'when neither of @project/@target_project/@group present' do - it 'returns dashboard milestones JSON URL' do - expect(helper.milestones_filter_dropdown_path).to eq(dashboard_milestones_path(:json)) - end - end - end - describe "#timebox_date_range" do let(:yesterday) { Date.yesterday } let(:tomorrow) { yesterday + 2 } diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb index 9481d756c16..3787864e144 100644 --- a/spec/helpers/todos_helper_spec.rb +++ b/spec/helpers/todos_helper_spec.rb @@ -40,26 +40,6 @@ RSpec.describe TodosHelper do end end - describe '#todo_projects_options' do - let(:projects) { create_list(:project, 3) } - let(:user) { create(:user) } - - it 'returns users authorised projects in json format' do - projects.first.add_developer(user) - projects.second.add_developer(user) - - allow(helper).to receive(:current_user).and_return(user) - - expected_results = [ - { 'id' => '', 'text' => 'Any Project' }, - { 'id' => projects.second.id, 'text' => projects.second.full_name }, - { 'id' => projects.first.id, 'text' => projects.first.full_name } - ] - - expect(Gitlab::Json.parse(helper.todo_projects_options)).to match_array(expected_results) - end - end - describe '#todo_target_link' do context 'when given a design' do let(:todo) { design_todo } diff --git a/spec/helpers/tracking_helper_spec.rb b/spec/helpers/tracking_helper_spec.rb index 47b344cfc25..cd2f8f9b7d1 100644 --- a/spec/helpers/tracking_helper_spec.rb +++ b/spec/helpers/tracking_helper_spec.rb @@ -10,7 +10,7 @@ RSpec.describe TrackingHelper do let(:results) do { no_data: {}, - with_data: { data: { track_label: 'a', track_event: 'b', track_property: 'c' } } + with_data: { data: { track_label: 'a', track_action: 'b', track_property: 'c' } } } end diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb index b6607182461..3dbaa655aeb 100644 --- a/spec/helpers/user_callouts_helper_spec.rb +++ b/spec/helpers/user_callouts_helper_spec.rb @@ -81,45 +81,43 @@ RSpec.describe UserCalloutsHelper do end end - describe '.show_service_templates_deprecated?' do - subject { helper.show_service_templates_deprecated? } + describe '.show_service_templates_deprecated_callout?' do + using RSpec::Parameterized::TableSyntax - context 'when user has not dismissed' do - before do - allow(helper).to receive(:user_dismissed?).with(described_class::SERVICE_TEMPLATES_DEPRECATED) { false } - end + let_it_be(:admin) { create(:user, :admin) } + let_it_be(:non_admin) { create(:user) } - it { is_expected.to be true } + subject { helper.show_service_templates_deprecated_callout? } + + where(:self_managed, :is_admin_user, :has_active_service_template, :callout_dismissed, :should_show_callout) do + true | true | true | false | true + true | true | true | true | false + true | false | true | false | false + false | true | true | false | false + true | true | false | false | false end - context 'when user dismissed' do + with_them do before do - allow(helper).to receive(:user_dismissed?).with(described_class::SERVICE_TEMPLATES_DEPRECATED) { true } + allow(::Gitlab).to receive(:com?).and_return(!self_managed) + allow(helper).to receive(:current_user).and_return(is_admin_user ? admin : non_admin) + allow(helper).to receive(:user_dismissed?).with(described_class::SERVICE_TEMPLATES_DEPRECATED_CALLOUT) { callout_dismissed } + create(:service, :template, type: 'MattermostService', active: has_active_service_template) end - it { is_expected.to be false } + it { is_expected.to be should_show_callout } end end describe '.show_customize_homepage_banner?' do - let(:customize_homepage) { true } - - subject { helper.show_customize_homepage_banner?(customize_homepage) } + subject { helper.show_customize_homepage_banner? } context 'when user has not dismissed' do before do allow(helper).to receive(:user_dismissed?).with(described_class::CUSTOMIZE_HOMEPAGE) { false } end - context 'when customize_homepage is set' do - it { is_expected.to be true } - end - - context 'when customize_homepage is false' do - let(:customize_homepage) { false } - - it { is_expected.to be false } - end + it { is_expected.to be true } end context 'when user dismissed' do diff --git a/spec/helpers/whats_new_helper_spec.rb b/spec/helpers/whats_new_helper_spec.rb index 017826921ff..0e4b4621560 100644 --- a/spec/helpers/whats_new_helper_spec.rb +++ b/spec/helpers/whats_new_helper_spec.rb @@ -3,25 +3,15 @@ require 'spec_helper' RSpec.describe WhatsNewHelper do - describe '#whats_new_storage_key' do - subject { helper.whats_new_storage_key } + include Devise::Test::ControllerHelpers - context 'when version exist' do - let(:release_item) { double(:item) } + describe '#whats_new_version_digest' do + let(:digest) { 'digest' } - before do - allow(ReleaseHighlight).to receive(:versions).and_return([84.0]) - end - - it { is_expected.to eq('display-whats-new-notification-84.0') } - end + it 'calls ReleaseHighlight.most_recent_version_digest' do + expect(ReleaseHighlight).to receive(:most_recent_version_digest).and_return(digest) - context 'when most recent release highlights do NOT exist' do - before do - allow(ReleaseHighlight).to receive(:versions).and_return(nil) - end - - it { is_expected.to be_nil } + expect(helper.whats_new_version_digest).to eq(digest) end end @@ -45,13 +35,29 @@ RSpec.describe WhatsNewHelper do end end - describe '#whats_new_versions' do - let(:versions) { [84.0] } + describe '#display_whats_new?' do + subject { helper.display_whats_new? } + + it 'returns true when gitlab.com' do + allow(Gitlab).to receive(:dev_env_org_or_com?).and_return(true) - it 'returns ReleaseHighlight.versions' do - expect(ReleaseHighlight).to receive(:versions).and_return(versions) + expect(subject).to be true + end + + context 'when self-managed' do + before do + allow(Gitlab).to receive(:dev_env_org_or_com?).and_return(false) + end - expect(helper.whats_new_versions).to eq(versions) + it 'returns true if user is signed in' do + sign_in(create(:user)) + + expect(subject).to be true + end + + it "returns false if user isn't signed in" do + expect(subject).to be false + end end end end diff --git a/spec/helpers/wiki_helper_spec.rb b/spec/helpers/wiki_helper_spec.rb index 45e1859893f..dc76f92db1b 100644 --- a/spec/helpers/wiki_helper_spec.rb +++ b/spec/helpers/wiki_helper_spec.rb @@ -76,7 +76,7 @@ RSpec.describe WikiHelper do describe '#wiki_sort_controls' do let(:wiki) { create(:project_wiki) } let(:wiki_link) { helper.wiki_sort_controls(wiki, sort, direction) } - let(:classes) { "btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort" } + let(:classes) { "gl-button btn btn-default btn-icon has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort" } def expected_link(sort, direction, icon_class) path = "/#{wiki.project.full_path}/-/wikis/pages?direction=#{direction}&sort=#{sort}" |