diff options
Diffstat (limited to 'spec/helpers')
28 files changed, 888 insertions, 214 deletions
diff --git a/spec/helpers/analytics/unique_visits_helper_spec.rb b/spec/helpers/analytics/unique_visits_helper_spec.rb index ff363e81ac7..b4b370c169d 100644 --- a/spec/helpers/analytics/unique_visits_helper_spec.rb +++ b/spec/helpers/analytics/unique_visits_helper_spec.rb @@ -9,19 +9,6 @@ RSpec.describe Analytics::UniqueVisitsHelper do let(:target_id) { 'p_analytics_valuestream' } let(:current_user) { create(:user) } - before do - stub_feature_flags(track_unique_visits: true) - end - - it 'does not track visits if feature flag disabled' do - stub_feature_flags(track_unique_visits: false) - sign_in(current_user) - - expect_any_instance_of(Gitlab::Analytics::UniqueVisits).not_to receive(:track_visit) - - helper.track_visit(target_id) - end - it 'does not track visit if user is not logged in' do expect_any_instance_of(Gitlab::Analytics::UniqueVisits).not_to receive(:track_visit) diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb index 479e2d7ef9d..2cd01451e0d 100644 --- a/spec/helpers/application_settings_helper_spec.rb +++ b/spec/helpers/application_settings_helper_spec.rb @@ -194,4 +194,33 @@ RSpec.describe ApplicationSettingsHelper do it { is_expected.to be false } end end + + describe '.kroki_available_formats' do + let(:application_setting) { build(:application_setting) } + + before do + helper.instance_variable_set(:@application_setting, application_setting) + stub_application_setting(kroki_formats: { 'blockdiag' => true, 'bpmn' => false, 'excalidraw' => false }) + end + + it 'returns available formats correctly' do + expect(helper.kroki_available_formats).to eq([ + { + name: 'kroki_formats_blockdiag', + label: 'BlockDiag (includes BlockDiag, SeqDiag, ActDiag, NwDiag, PacketDiag and RackDiag)', + value: true + }, + { + name: 'kroki_formats_bpmn', + label: 'BPMN', + value: false + }, + { + name: 'kroki_formats_excalidraw', + label: 'Excalidraw', + value: false + } + ]) + end + end end diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb index 00c4a1880de..b5d70af1336 100644 --- a/spec/helpers/auth_helper_spec.rb +++ b/spec/helpers/auth_helper_spec.rb @@ -73,12 +73,12 @@ RSpec.describe AuthHelper do describe 'enabled_button_based_providers' do before do - allow(helper).to receive(:auth_providers) { [:twitter, :github, :google_oauth2] } + allow(helper).to receive(:auth_providers) { [:twitter, :github, :google_oauth2, :openid_connect] } end context 'all providers are enabled to sign in' do it 'returns all the enabled providers from settings' do - expect(helper.enabled_button_based_providers).to include('twitter', 'github', 'google_oauth2') + expect(helper.enabled_button_based_providers).to include('twitter', 'github', 'google_oauth2', 'openid_connect') end it 'puts google and github in the beginning' do diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb index 8a570bf9a90..2f5f4c4596b 100644 --- a/spec/helpers/commits_helper_spec.rb +++ b/spec/helpers/commits_helper_spec.rb @@ -7,19 +7,38 @@ RSpec.describe CommitsHelper do context 'when current_user exists' do before do allow(helper).to receive(:current_user).and_return(double('User')) - allow(helper).to receive(:can_collaborate_with_project?).and_return(true) end it 'renders a div for Vue' do - result = helper.revert_commit_link('_commit_', '_path_', pajamas: true) + 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 - it 'does not render a div for Vue' do - result = helper.revert_commit_link('_commit_', '_path_') + 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 - expect(result).not_to include('js-revert-commit-trigger') + it 'renders a div for Vue' do + result = helper.cherry_pick_commit_link + + expect(result).to include('js-cherry-pick-commit-trigger') end end @@ -29,7 +48,7 @@ RSpec.describe CommitsHelper do end it 'does not render anything' do - result = helper.revert_commit_link(double('Commit'), '_path_') + result = helper.cherry_pick_commit_link expect(result).to be_nil end @@ -157,4 +176,77 @@ RSpec.describe CommitsHelper do expect(helper.commit_path(project, commit)).to eq(project_commit_path(project, commit)) end end + + describe "#conditionally_paginate_diff_files" do + let(:diffs_collection) { instance_double(Gitlab::Diff::FileCollection::Commit, diff_files: diff_files) } + let(:diff_files) { Gitlab::Git::DiffCollection.new(files) } + let(:page) { nil } + + let(:files) do + Array.new(85).map do + { too_large: false, diff: "" } + end + end + + let(:params) do + { + page: page + } + end + + subject { helper.conditionally_paginate_diff_files(diffs_collection, paginate: paginate) } + + before do + allow(helper).to receive(:params).and_return(params) + end + + context "pagination is enabled" do + let(:paginate) { true } + + it "has been paginated" do + expect(subject).to be_an(Array) + end + + it "can change the number of items per page" do + commits = helper.conditionally_paginate_diff_files(diffs_collection, paginate: paginate, per: 10) + + expect(commits).to be_an(Array) + expect(commits.size).to eq(10) + end + + context "page 1" do + let(:page) { 1 } + + it "has 20 diffs" do + expect(subject.size).to eq(75) + end + end + + context "page 2" do + let(:page) { 2 } + + it "has the remaining 10 diffs" do + expect(subject.size).to eq(10) + end + end + end + + context "pagination is disabled" do + let(:paginate) { false } + + it "returns a standard DiffCollection" do + expect(subject).to be_a(Gitlab::Git::DiffCollection) + end + end + + context "feature flag is disabled" do + let(:paginate) { true } + + it "returns a standard DiffCollection" do + stub_feature_flags(paginate_commit_view: false) + + expect(subject).to be_a(Gitlab::Git::DiffCollection) + end + end + end end diff --git a/spec/helpers/container_registry_helper_spec.rb b/spec/helpers/container_registry_helper_spec.rb index 6e6e8137b3e..49e56113dd8 100644 --- a/spec/helpers/container_registry_helper_spec.rb +++ b/spec/helpers/container_registry_helper_spec.rb @@ -5,8 +5,8 @@ require 'spec_helper' RSpec.describe ContainerRegistryHelper do using RSpec::Parameterized::TableSyntax - describe '#limit_delete_tags_service?' do - subject { helper.limit_delete_tags_service? } + describe '#container_registry_expiration_policies_throttling?' do + subject { helper.container_registry_expiration_policies_throttling? } where(:feature_flag_enabled, :client_support, :expected_result) do true | true | true diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 3580959fde0..20fa8d62884 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -169,9 +169,9 @@ RSpec.describe DiffHelper do it "returns strings with marked inline diffs" do marked_old_line, marked_new_line = mark_inline_diffs(old_line, new_line) - expect(marked_old_line).to eq(%q{abc <span class="idiff left right deletion">'def'</span>}) + expect(marked_old_line).to eq(%q{abc <span class="idiff left deletion">'</span>def<span class="idiff right deletion">'</span>}) expect(marked_old_line).to be_html_safe - expect(marked_new_line).to eq(%q{abc <span class="idiff left right addition">"def"</span>}) + expect(marked_new_line).to eq(%q{abc <span class="idiff left addition">"</span>def<span class="idiff right addition">"</span>}) expect(marked_new_line).to be_html_safe end @@ -358,4 +358,48 @@ RSpec.describe DiffHelper do expect(diff_file_path_text(diff_file, max: 10)).to eq("...open.rb") end end + + describe "#collapsed_diff_url" do + let(:params) do + { + controller: "projects/commit", + action: "show", + namespace_id: "foo", + project_id: "bar", + id: commit.sha + } + end + + subject { helper.collapsed_diff_url(diff_file) } + + it "returns a valid URL" do + allow(helper).to receive(:safe_params).and_return(params) + + expect(subject).to match(/foo\/bar\/-\/commit\/#{commit.sha}\/diff_for_path/) + end + end + + describe "#render_fork_suggestion" do + subject { helper.render_fork_suggestion } + + before do + allow(helper).to receive(:current_user).and_return(current_user) + end + + context "user signed in" do + let(:current_user) { build(:user) } + + it "renders the partial" do + expect(helper).to receive(:render).with(partial: "projects/fork_suggestion").exactly(:once) + + 5.times { subject } + end + end + + context "guest" do + let(:current_user) { nil } + + it { is_expected.to be_nil } + end + end end diff --git a/spec/helpers/enable_search_settings_helper_spec.rb b/spec/helpers/enable_search_settings_helper_spec.rb new file mode 100644 index 00000000000..c55c549ea51 --- /dev/null +++ b/spec/helpers/enable_search_settings_helper_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe EnableSearchSettingsHelper do + describe '#enable_search_settings' do + def before_content + helper.content_for(:before_content) + end + + it 'sets content for before_content' do + expect(before_content).to be_nil + + locals = { container_class: 'test-container-class' } + + helper.enable_search_settings(locals: locals) + + expect(before_content).to eql(helper.render("shared/search_settings", locals)) + end + end +end diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index c629643e248..264bad92d56 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -200,7 +200,13 @@ RSpec.describe EventsHelper do it 'returns a project snippet note url' do event.target = create(:note_on_project_snippet, note: 'keep going') - expect(subject).to eq("#{project_base_url}/-/snippets/#{event.note_target.id}#note_#{event.target.id}") + expect(subject).to eq("#{project_snippet_url(event.note_target.project, event.note_target)}#note_#{event.target.id}") + end + + it 'returns a personal snippet note url' do + event.target = create(:note_on_personal_snippet, note: 'keep going') + + expect(subject).to eq("#{snippet_url(event.note_target)}#note_#{event.target.id}") end it 'returns a project issue url' do diff --git a/spec/helpers/groups/group_members_helper_spec.rb b/spec/helpers/groups/group_members_helper_spec.rb index d75124b6da7..99efc7963e6 100644 --- a/spec/helpers/groups/group_members_helper_spec.rb +++ b/spec/helpers/groups/group_members_helper_spec.rb @@ -23,13 +23,13 @@ RSpec.describe Groups::GroupMembersHelper do end end - describe '#linked_groups_data_json' do + describe '#group_group_links_data_json' do include_context 'group_group_link' it 'matches json schema' do - json = helper.linked_groups_data_json(shared_group.shared_with_group_links) + json = helper.group_group_links_data_json(shared_group.shared_with_group_links) - expect(json).to match_schema('group_group_links') + expect(json).to match_schema('group_link/group_group_links') end end @@ -81,13 +81,13 @@ RSpec.describe Groups::GroupMembersHelper do expect(helper.group_members_list_data_attributes(group, present_members([group_member]))).to include({ members: helper.members_data_json(group, present_members([group_member])), member_path: '/groups/foo-bar/-/group_members/:id', - group_id: group.id, + source_id: group.id, can_manage_members: 'true' }) end end - describe '#linked_groups_list_data_attributes' do + describe '#group_group_links_list_data_attributes' do include_context 'group_group_link' before do @@ -95,10 +95,10 @@ RSpec.describe Groups::GroupMembersHelper do end it 'returns expected hash' do - expect(helper.linked_groups_list_data_attributes(shared_group)).to include({ - members: helper.linked_groups_data_json(shared_group.shared_with_group_links), + expect(helper.group_group_links_list_data_attributes(shared_group)).to include({ + members: helper.group_group_links_data_json(shared_group.shared_with_group_links), member_path: '/groups/foo-bar/-/group_links/:id', - group_id: shared_group.id + source_id: shared_group.id }) end end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 8eb1b7b3b3d..61aaa618c45 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -444,4 +444,82 @@ RSpec.describe GroupsHelper do end end end + + describe '#group_open_issues_count' do + let_it_be(:current_user) { create(:user) } + let_it_be(:group) { create(:group, :public) } + let_it_be(:count_service) { Groups::OpenIssuesCountService } + + before do + allow(helper).to receive(:current_user) { current_user } + end + + context 'when cached_sidebar_open_issues_count feature flag is enabled' do + before do + stub_feature_flags(cached_sidebar_open_issues_count: true) + 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') + end + 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 + end + end + + describe '#cached_open_group_issues_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 + + 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') + 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 + + expect(helper.cached_open_group_issues_count(group)).to eq('112.6k') + end + end end diff --git a/spec/helpers/invite_members_helper_spec.rb b/spec/helpers/invite_members_helper_spec.rb index 914d0931476..576021b37b3 100644 --- a/spec/helpers/invite_members_helper_spec.rb +++ b/spec/helpers/invite_members_helper_spec.rb @@ -7,11 +7,49 @@ RSpec.describe InviteMembersHelper do let_it_be(:developer) { create(:user, developer_projects: [project]) } let(:owner) { project.owner } + before do + helper.extend(Gitlab::Experimentation::ControllerConcern) + end + context 'with project' do before do assign(:project, project) end + describe "#can_invite_members_for_project?" do + context 'when the user can_import_members' do + before do + allow(helper).to receive(:can_import_members?).and_return(true) + end + + it 'returns true' do + expect(helper.can_invite_members_for_project?(project)).to eq true + expect(helper).to have_received(:can_import_members?) + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(invite_members_group_modal: false) + end + + it 'returns false' do + expect(helper.can_invite_members_for_project?(project)).to eq false + expect(helper).not_to have_received(:can_import_members?) + end + end + end + + context 'when the user can not invite members' do + before do + expect(helper).to receive(:can_import_members?).and_return(false) + end + + it 'returns false' do + expect(helper.can_invite_members_for_project?(project)).to eq false + end + end + end + describe "#directly_invite_members?" do context 'when the user is an owner' do before do @@ -80,6 +118,51 @@ RSpec.describe InviteMembersHelper do context 'with group' do let_it_be(:group) { create(:group) } + describe "#can_invite_members_for_group?" do + include Devise::Test::ControllerHelpers + + let_it_be(:user) { create(:user) } + + before do + sign_in(user) + allow(helper).to receive(:current_user) { user } + end + + context 'when the user can_import_members' do + before do + allow(helper).to receive(:can?).with(user, :admin_group_member, group).and_return(true) + end + + it 'returns true' do + expect(helper.can_invite_members_for_group?(group)).to eq true + expect(helper).to have_received(:can?).with(user, :admin_group_member, group) + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(invite_members_group_modal: false) + end + + it 'returns false' do + stub_feature_flags(invite_members_group_modal: false) + + expect(helper.can_invite_members_for_group?(group)).to eq false + expect(helper).not_to have_received(:can?) + end + end + end + + context 'when the user can not invite members' do + before do + expect(helper).to receive(:can?).with(user, :admin_group_member, group).and_return(false) + end + + it 'returns false' do + expect(helper.can_invite_members_for_group?(group)).to eq false + end + end + end + describe "#invite_group_members?" do context 'when the user is an owner' do before do @@ -123,7 +206,6 @@ RSpec.describe InviteMembersHelper do before do allow(helper).to receive(:experiment_tracking_category_and_group) { '_track_property_' } - allow(helper).to receive(:tracking_label).with(owner) allow(helper).to receive(:current_user) { owner } end @@ -132,8 +214,7 @@ RSpec.describe InviteMembersHelper do helper.dropdown_invite_members_link(form_model) - expect(helper).to have_received(:experiment_tracking_category_and_group) - .with(:invite_members_new_dropdown, subject: owner) + expect(helper).to have_received(:experiment_tracking_category_and_group).with(:invite_members_new_dropdown) end context 'with experiment enabled' do diff --git a/spec/helpers/issuables_description_templates_helper_spec.rb b/spec/helpers/issuables_description_templates_helper_spec.rb new file mode 100644 index 00000000000..42643b755f8 --- /dev/null +++ b/spec/helpers/issuables_description_templates_helper_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do + include_context 'project issuable templates context' + + describe '#issuable_templates' do + let_it_be(:inherited_from) { nil } + let_it_be(:user) { create(:user) } + let_it_be(:parent_group, reload: true) { create(:group) } + let_it_be(:project, reload: true) { create(:project, :custom_repo, files: issuable_template_files) } + let_it_be(:group_member) { create(:group_member, :developer, group: parent_group, user: user) } + let_it_be(:project_member) { create(:project_member, :developer, user: user, project: project) } + + it 'returns empty hash when template type does not exist' do + expect(helper.issuable_templates(build(:project), 'non-existent-template-type')).to eq([]) + end + + context 'with cached issuable templates' do + before do + allow(Gitlab::Template::IssueTemplate).to receive(:template_names).and_return({}) + allow(Gitlab::Template::MergeRequestTemplate).to receive(:template_names).and_return({}) + + helper.issuable_templates(project, 'issues') + helper.issuable_templates(project, 'merge_request') + end + + it 'does not call TemplateFinder' do + expect(Gitlab::Template::IssueTemplate).not_to receive(:template_names) + expect(Gitlab::Template::MergeRequestTemplate).not_to receive(:template_names) + helper.issuable_templates(project, 'issues') + helper.issuable_templates(project, 'merge_request') + end + end + + context 'when project has no parent group' do + it_behaves_like 'project issuable templates' + end + + context 'when project has parent group' do + before do + project.update!(group: parent_group) + end + + context 'when project parent group does not have a file template project' do + it_behaves_like 'project issuable templates' + end + + context 'when project parent group has a file template project' do + let_it_be(:file_template_project) { create(:project, :custom_repo, group: parent_group, files: issuable_template_files) } + let_it_be(:group, reload: true) { create(:group, parent: parent_group) } + let_it_be(:project, reload: true) { create(:project, :custom_repo, group: group, files: issuable_template_files) } + + before do + project.update!(group: group) + parent_group.update_columns(file_template_project_id: file_template_project.id) + end + + it_behaves_like 'project issuable templates' + end + end + end + + describe '#issuable_templates_names' do + let(:project) { double(Project, id: 21) } + + let(:templates) do + [ + { name: "another_issue_template", id: "another_issue_template", project_id: project.id }, + { name: "custom_issue_template", id: "custom_issue_template", project_id: project.id } + ] + end + + it 'returns project templates only' do + allow(helper).to receive(:ref_project).and_return(project) + allow(helper).to receive(:issuable_templates).and_return(templates) + + expect(helper.issuable_templates_names(Issue.new)).to eq(%w[another_issue_template custom_issue_template]) + end + + context 'when there are not templates in the project' do + let(:templates) { {} } + + it 'returns empty array' do + allow(helper).to receive(:ref_project).and_return(project) + allow(helper).to receive(:issuable_templates).and_return(templates) + + expect(helper.issuable_templates_names(Issue.new)).to eq([]) + end + end + end +end diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 57845904d32..d6b002b47eb 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -72,28 +72,38 @@ RSpec.describe IssuablesHelper do let(:user) { create(:user) } describe 'state text' do - before do - allow(helper).to receive(:issuables_count_for_state).and_return(42) - end - - it 'returns "Open" when state is :opened' do - expect(helper.issuables_state_counter_text(:issues, :opened, true)) - .to eq('<span>Open</span> <span class="badge badge-pill">42</span>') - end + context 'when number of issuables can be generated' do + before do + allow(helper).to receive(:issuables_count_for_state).and_return(42) + end - it 'returns "Closed" when state is :closed' do - expect(helper.issuables_state_counter_text(:issues, :closed, true)) - .to eq('<span>Closed</span> <span class="badge badge-pill">42</span>') + it 'returns navigation with badges' do + expect(helper.issuables_state_counter_text(:issues, :opened, true)) + .to eq('<span>Open</span> <span class="badge badge-pill">42</span>') + expect(helper.issuables_state_counter_text(:issues, :closed, true)) + .to eq('<span>Closed</span> <span class="badge badge-pill">42</span>') + expect(helper.issuables_state_counter_text(:merge_requests, :merged, true)) + .to eq('<span>Merged</span> <span class="badge badge-pill">42</span>') + expect(helper.issuables_state_counter_text(:merge_requests, :all, true)) + .to eq('<span>All</span> <span class="badge badge-pill">42</span>') + end end - it 'returns "Merged" when state is :merged' do - expect(helper.issuables_state_counter_text(:merge_requests, :merged, true)) - .to eq('<span>Merged</span> <span class="badge badge-pill">42</span>') - end + context 'when count cannot be generated' do + before do + allow(helper).to receive(:issuables_count_for_state).and_return(-1) + end - it 'returns "All" when state is :all' do - expect(helper.issuables_state_counter_text(:merge_requests, :all, true)) - .to eq('<span>All</span> <span class="badge badge-pill">42</span>') + it 'returns avigation without badges' do + expect(helper.issuables_state_counter_text(:issues, :opened, true)) + .to eq('<span>Open</span>') + expect(helper.issuables_state_counter_text(:issues, :closed, true)) + .to eq('<span>Closed</span>') + expect(helper.issuables_state_counter_text(:merge_requests, :merged, true)) + .to eq('<span>Merged</span>') + expect(helper.issuables_state_counter_text(:merge_requests, :all, true)) + .to eq('<span>All</span>') + end end end end @@ -199,6 +209,7 @@ RSpec.describe IssuablesHelper do markdownDocsPath: '/help/user/markdown', lockVersion: issue.lock_version, projectPath: @project.path, + projectId: @project.id, projectNamespace: @project.namespace.path, initialTitleHtml: issue.title, initialTitleText: issue.title, diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 1ed61bd3144..07e55e9b016 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -254,4 +254,31 @@ RSpec.describe IssuesHelper do expect(helper.use_startup_call?).to eq(true) end end + + describe '#issue_header_actions_data' do + let(:current_user) { create(:user) } + + before do + allow(helper).to receive(:current_user).and_return(current_user) + allow(helper).to receive(:can?).and_return(true) + end + + it 'returns expected result' do + expected = { + can_create_issue: "true", + can_reopen_issue: "true", + can_report_spam: "false", + can_update_issue: "true", + iid: issue.iid, + is_issue_author: "false", + issue_type: "issue", + new_issue_path: new_project_issue_path(project), + project_path: project.full_path, + report_abuse_path: new_abuse_report_path(user_id: issue.author.id, ref_url: issue_url(issue)), + submit_as_spam_path: mark_as_spam_project_issue_path(project, issue) + } + + expect(helper.issue_header_actions_data(project, issue, current_user)).to include(expected) + end + end end diff --git a/spec/helpers/jira_connect_helper_spec.rb b/spec/helpers/jira_connect_helper_spec.rb index a99072527c8..9695bed948b 100644 --- a/spec/helpers/jira_connect_helper_spec.rb +++ b/spec/helpers/jira_connect_helper_spec.rb @@ -4,12 +4,43 @@ require 'spec_helper' RSpec.describe JiraConnectHelper do describe '#jira_connect_app_data' do - subject { helper.jira_connect_app_data } + let_it_be(:subscription) { create(:jira_connect_subscription) } + let(:user) { create(:user) } - it 'includes Jira Connect app attributes' do - is_expected.to include( - :groups_path - ) + subject { helper.jira_connect_app_data([subscription]) } + + context 'user is not logged in' do + before do + allow(view).to receive(:current_user).and_return(nil) + end + + it 'includes Jira Connect app attributes' do + is_expected.to include( + :groups_path, + :subscriptions_path, + :users_path + ) + end + + it 'assigns users_path with value' do + expect(subject[:users_path]).to eq(jira_connect_users_path) + end + + it 'passes group as "skip_groups" param' do + skip_groups_param = CGI.escape('skip_groups[]') + + expect(subject[:groups_path]).to include("#{skip_groups_param}=#{subscription.namespace.id}") + end + end + + context 'user is logged in' do + before do + allow(view).to receive(:current_user).and_return(user) + end + + it 'assigns users_path to nil' do + expect(subject[:users_path]).to be_nil + end end end end diff --git a/spec/helpers/learn_gitlab_helper_spec.rb b/spec/helpers/learn_gitlab_helper_spec.rb new file mode 100644 index 00000000000..f789eb9d940 --- /dev/null +++ b/spec/helpers/learn_gitlab_helper_spec.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe LearnGitlabHelper do + include AfterNextHelpers + include Devise::Test::ControllerHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, name: LearnGitlab::PROJECT_NAME, namespace: user.namespace) } + let_it_be(:namespace) { project.namespace } + + before do + project.add_developer(user) + + allow(helper).to receive(:user).and_return(user) + allow_next_instance_of(LearnGitlab) do |learn_gitlab| + allow(learn_gitlab).to receive(:project).and_return(project) + end + + OnboardingProgress.onboard(namespace) + OnboardingProgress.register(namespace, :git_write) + end + + describe '.onboarding_actions_data' do + subject(:onboarding_actions_data) { helper.onboarding_actions_data(project) } + + it 'has all actions' do + expect(onboarding_actions_data.keys).to contain_exactly( + :git_write, + :pipeline_created, + :merge_request_created, + :user_added, + :trial_started, + :required_mr_approvals_enabled, + :code_owners_enabled, + :security_scan_enabled + ) + end + + it 'sets correct path and completion status' do + expect(onboarding_actions_data[:git_write]).to eq({ + url: project_issue_url(project, LearnGitlabHelper::ACTION_ISSUE_IDS[:git_write]), + completed: true + }) + expect(onboarding_actions_data[:pipeline_created]).to eq({ + url: project_issue_url(project, LearnGitlabHelper::ACTION_ISSUE_IDS[:pipeline_created]), + completed: false + }) + end + end + + describe '.learn_gitlab_experiment_enabled?' do + using RSpec::Parameterized::TableSyntax + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, namespace: user.namespace) } + + let(:params) { { namespace_id: project.namespace.to_param, project_id: project } } + + subject { helper.learn_gitlab_experiment_enabled?(project) } + + where(:experiment_a, :experiment_b, :onboarding, :learn_gitlab_available, :result) do + true | false | true | true | true + false | true | true | true | true + false | false | true | true | false + true | true | true | false | false + true | true | false | true | false + end + + with_them do + before do + stub_experiment_for_subject(learn_gitlab_a: experiment_a, learn_gitlab_b: experiment_b) + allow(OnboardingProgress).to receive(:onboarding?).with(project.namespace).and_return(onboarding) + allow_next(LearnGitlab, user).to receive(:available?).and_return(learn_gitlab_available) + end + + context 'when signed in' do + before do + sign_in(user) + end + + it { is_expected.to eq(result) } + end + + context 'when not signed in' do + it { is_expected.to eq(false) } + end + end + end +end diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb index 821faaab194..fce4d560b2f 100644 --- a/spec/helpers/merge_requests_helper_spec.rb +++ b/spec/helpers/merge_requests_helper_spec.rb @@ -89,15 +89,5 @@ RSpec.describe MergeRequestsHelper do total: user.assigned_open_merge_requests_count + user.review_requested_open_merge_requests_count ) end - - context 'when merge_request_reviewers is disabled' do - before do - stub_feature_flags(merge_request_reviewers: false) - end - - it 'returns review_requested as 0' do - expect(subject[:review_requested]).to eq(0) - end - end end end diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index f9b3b535334..b8502cdf25e 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -316,4 +316,15 @@ RSpec.describe NotesHelper do end end end + + describe '#notes_data' do + let(:issue) { create(:issue, project: project) } + + it 'sets last_fetched_at to 0 when start_at_zero is true' do + @project = project + @noteable = issue + + expect(helper.notes_data(issue, true)[:lastFetchedAt]).to eq(0) + end + end end diff --git a/spec/helpers/notify_helper_spec.rb b/spec/helpers/notify_helper_spec.rb index 9c9d745cb53..eb0f796038c 100644 --- a/spec/helpers/notify_helper_spec.rb +++ b/spec/helpers/notify_helper_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe NotifyHelper do include ActionView::Helpers::UrlHelper + using RSpec::Parameterized::TableSyntax describe 'merge_request_reference_link' do let(:project) { create(:project) } @@ -27,6 +28,36 @@ RSpec.describe NotifyHelper do end end + describe '#invited_role_description' do + where(:role, :description) do + "Guest" | /As a guest/ + "Reporter" | /As a reporter/ + "Developer" | /As a developer/ + "Maintainer" | /As a maintainer/ + "Owner" | /As an owner/ + "Minimal Access" | /As a user with minimal access/ + end + + with_them do + specify do + expect(helper.invited_role_description(role)).to match description + end + end + end + + describe '#invited_to_description' do + where(:source, :description) do + "project" | /Projects can/ + "group" | /Groups assemble/ + end + + with_them do + specify do + expect(helper.invited_to_description(source)).to match description + end + end + end + def reference_link(entity, url) "<a href=\"#{url}\">#{entity.to_reference}</a>" end diff --git a/spec/helpers/operations_helper_spec.rb b/spec/helpers/operations_helper_spec.rb index 801d5de79b1..5b0ce00063f 100644 --- a/spec/helpers/operations_helper_spec.rb +++ b/spec/helpers/operations_helper_spec.rb @@ -30,7 +30,7 @@ RSpec.describe OperationsHelper do it 'returns the correct values' do expect(subject).to eq( - 'alerts_setup_url' => help_page_path('operations/incident_management/alert_integrations.md', anchor: 'generic-http-endpoint'), + 'alerts_setup_url' => help_page_path('operations/incident_management/integrations.md', anchor: 'configuration'), 'alerts_usage_url' => project_alert_management_index_path(project), 'prometheus_form_path' => project_service_path(project, prometheus_service), 'prometheus_reset_key_path' => reset_alerting_token_project_settings_operations_path(project), diff --git a/spec/helpers/projects/alert_management_helper_spec.rb b/spec/helpers/projects/alert_management_helper_spec.rb index fd35c1ecab8..0df194e460a 100644 --- a/spec/helpers/projects/alert_management_helper_spec.rb +++ b/spec/helpers/projects/alert_management_helper_spec.rb @@ -28,8 +28,8 @@ RSpec.describe Projects::AlertManagementHelper do expect(helper.alert_management_data(current_user, project)).to match( 'project-path' => project_path, 'enable-alert-management-path' => setting_path, - 'alerts-help-url' => 'http://test.host/help/operations/incident_management/index.md', - 'populating-alerts-help-url' => 'http://test.host/help/operations/incident_management/index.md#enable-alert-management', + 'alerts-help-url' => 'http://test.host/help/operations/incident_management/alerts.md', + 'populating-alerts-help-url' => 'http://test.host/help/operations/incident_management/integrations.md#configuration', 'empty-alert-svg-path' => match_asset_path('/assets/illustrations/alert-management-empty-state.svg'), 'user-can-enable-alert-management' => 'true', 'alert-management-enabled' => 'false', @@ -113,7 +113,8 @@ RSpec.describe Projects::AlertManagementHelper do 'alert-id' => alert_id, 'project-path' => project_path, 'project-id' => project_id, - 'project-issues-path' => issues_path + 'project-issues-path' => issues_path, + 'page' => 'OPERATIONS' ) end end diff --git a/spec/helpers/projects/project_members_helper_spec.rb b/spec/helpers/projects/project_members_helper_spec.rb index cc290367e34..5e0b4df7f7f 100644 --- a/spec/helpers/projects/project_members_helper_spec.rb +++ b/spec/helpers/projects/project_members_helper_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Projects::ProjectMembersHelper do + include MembersPresentation + let_it_be(:current_user) { create(:user) } let_it_be(:project) { create(:project) } @@ -142,4 +144,58 @@ RSpec.describe Projects::ProjectMembersHelper do it { is_expected.to be(false) } end end + + describe 'project members' do + let_it_be(:project_members) { create_list(:project_member, 1, project: project) } + + describe '#project_members_data_json' do + it 'matches json schema' do + expect(helper.project_members_data_json(project, present_members(project_members))).to match_schema('members') + end + end + + describe '#project_members_list_data_attributes' do + let(:allow_admin_project) { true } + + before do + allow(helper).to receive(:project_project_member_path).with(project, ':id').and_return('/foo-bar/-/project_members/:id') + end + + it 'returns expected hash' do + expect(helper.project_members_list_data_attributes(project, present_members(project_members))).to include({ + members: helper.project_members_data_json(project, present_members(project_members)), + member_path: '/foo-bar/-/project_members/:id', + source_id: project.id, + can_manage_members: true + }) + end + end + end + + 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 + it 'matches json schema' do + expect(helper.project_group_links_data_json(project_group_links)).to match_schema('group_link/project_group_links') + end + end + + describe '#project_group_links_list_data_attributes' do + before do + allow(helper).to receive(:project_group_link_path).with(project, ':id').and_return('/foo-bar/-/group_links/:id') + allow(helper).to receive(:can?).with(current_user, :admin_project_member, project).and_return(true) + end + + it 'returns expected hash' do + expect(helper.project_group_links_list_data_attributes(project, project_group_links)).to include({ + members: helper.project_group_links_data_json(project_group_links), + member_path: '/foo-bar/-/group_links/:id', + source_id: project.id, + can_manage_members: true + }) + end + end + end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index b920e2e5600..303e3c78153 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe ProjectsHelper do include ProjectForksHelper + include AfterNextHelpers let_it_be_with_reload(:project) { create(:project) } let_it_be_with_refind(:project_with_repo) { create(:project, :repository) } @@ -398,6 +399,45 @@ RSpec.describe ProjectsHelper do helper.send(:get_project_nav_tabs, project, user) end + context 'Security & Compliance tabs' do + before do + stub_feature_flags(secure_security_and_compliance_configuration_page_on_ce: feature_flag_enabled) + allow(helper).to receive(:can?).with(user, :read_security_configuration, project).and_return(can_read_security_configuration) + end + + context 'when user cannot read security configuration' do + let(:can_read_security_configuration) { false } + + context 'when feature flag is disabled' do + let(:feature_flag_enabled) { false } + + it { is_expected.not_to include(:security_configuration) } + end + + context 'when feature flag is enabled' do + let(:feature_flag_enabled) { true } + + it { is_expected.not_to include(:security_configuration) } + end + end + + context 'when user can read security configuration' do + let(:can_read_security_configuration) { true } + + context 'when feature flag is disabled' do + let(:feature_flag_enabled) { false } + + it { is_expected.not_to include(:security_configuration) } + end + + context 'when feature flag is enabled' do + let(:feature_flag_enabled) { true } + + it { is_expected.to include(:security_configuration) } + end + end + end + context 'when builds feature is enabled' do before do allow(project).to receive(:builds_enabled?).and_return(true) @@ -459,6 +499,20 @@ RSpec.describe ProjectsHelper do it { is_expected.not_to include(:confluence) } it { is_expected.to include(:wiki) } end + + context 'learn gitlab experiment' do + context 'when it is enabled' do + before do + expect(helper).to receive(:learn_gitlab_experiment_enabled?).with(project).and_return(true) + end + + it { is_expected.to include(:learn_gitlab) } + end + + context 'when it is not enabled' do + it { is_expected.not_to include(:learn_gitlab) } + end + end end describe '#can_view_operations_tab?' do @@ -657,31 +711,6 @@ RSpec.describe ProjectsHelper do end end - describe 'link_to_filter_repo' do - subject { helper.link_to_filter_repo } - - it 'generates a hardcoded link to git filter-repo' do - result = helper.link_to_filter_repo - doc = Nokogiri::HTML.fragment(result) - - expect(doc.children.size).to eq(1) - - link = doc.children.first - - aggregate_failures do - expect(result).to be_html_safe - - expect(link.name).to eq('a') - expect(link[:target]).to eq('_blank') - expect(link[:rel]).to eq('noopener noreferrer') - expect(link[:href]).to eq('https://github.com/newren/git-filter-repo') - expect(link.inner_html).to eq('git filter-repo') - - expect(result).to be_html_safe - end - end - end - describe '#explore_projects_tab?' do subject { helper.explore_projects_tab? } @@ -854,16 +883,36 @@ RSpec.describe ProjectsHelper do end describe '#can_import_members?' do - let(:owner) { project.owner } + context 'when user is project owner' do + before do + allow(helper).to receive(:current_user) { project.owner } + end - it 'returns false if user cannot admin_project_member' do - allow(helper).to receive(:current_user) { user } - expect(helper.can_import_members?).to eq false + it 'returns true for owner of project' do + expect(helper.can_import_members?).to eq true + end end - it 'returns true if user can admin_project_member' do - allow(helper).to receive(:current_user) { owner } - expect(helper.can_import_members?).to eq true + context 'when user is not a project owner' do + using RSpec::Parameterized::TableSyntax + + where(:user_project_role, :can_import) do + :maintainer | true + :developer | false + :reporter | false + :guest | false + end + + with_them do + before do + project.add_role(user, user_project_role) + allow(helper).to receive(:current_user) { user } + end + + it 'resolves if the user can import members' do + expect(helper.can_import_members?).to eq can_import + end + end end end diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 2cb9d66ac63..a977f2c88c6 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -610,4 +610,35 @@ RSpec.describe SearchHelper do end end end + + describe '#search_sort_options' do + let(:user) { create(:user) } + + mock_created_sort = [ + { + title: _('Created date'), + sortable: true, + sortParam: { + asc: 'created_asc', + desc: 'created_desc' + } + }, + { + title: _('Last updated'), + sortable: true, + sortParam: { + asc: 'updated_asc', + desc: 'updated_desc' + } + } + ] + + before do + allow(self).to receive(:current_user).and_return(user) + end + + it 'returns the correct data' do + expect(search_sort_options).to eq(mock_created_sort) + end + end end diff --git a/spec/helpers/sorting_helper_spec.rb b/spec/helpers/sorting_helper_spec.rb index 2d581dfba37..f976fb098a8 100644 --- a/spec/helpers/sorting_helper_spec.rb +++ b/spec/helpers/sorting_helper_spec.rb @@ -50,24 +50,6 @@ RSpec.describe SortingHelper do end end - describe '#search_sort_direction_button' do - before do - set_sorting_url 'test_label' - end - - it 'keeps label filter param' do - expect(search_sort_direction_button('created_asc')).to include('label_name=test_label') - end - - it 'returns icon with sort-lowest when sort is asc' do - expect(search_sort_direction_button('created_asc')).to include('sort-lowest') - end - - it 'returns icon with sort-highest when sort is desc' do - expect(search_sort_direction_button('created_desc')).to include('sort-highest') - end - end - def stub_controller_path(value) allow(helper.controller).to receive(:controller_path).and_return(value) end diff --git a/spec/helpers/stat_anchors_helper_spec.rb b/spec/helpers/stat_anchors_helper_spec.rb index c6556647bc8..0615baac3cb 100644 --- a/spec/helpers/stat_anchors_helper_spec.rb +++ b/spec/helpers/stat_anchors_helper_spec.rb @@ -21,7 +21,7 @@ RSpec.describe StatAnchorsHelper do let(:anchor) { anchor_klass.new(false, nil, nil, 'default') } it 'returns the proper attributes' do - expect(subject[:class]).to include('btn btn-default') + expect(subject[:class]).to include('gl-button btn btn-default') end end @@ -29,7 +29,7 @@ RSpec.describe StatAnchorsHelper do let(:anchor) { anchor_klass.new(false) } it 'returns the proper attributes' do - expect(subject[:class]).to include('btn btn-missing') + expect(subject[:class]).to include('gl-button btn btn-dashed') end end end diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb index 6cb9894e306..bc25a2fcdfc 100644 --- a/spec/helpers/tree_helper_spec.rb +++ b/spec/helpers/tree_helper_spec.rb @@ -19,94 +19,6 @@ RSpec.describe TreeHelper do ) end - describe '.render_tree' do - before do - @id = sha - @path = "" - @project = project - @lfs_blob_ids = [] - end - - it 'displays all entries without a warning' do - tree = repository.tree(sha, 'files') - - html = render_tree(tree) - - expect(html).not_to have_selector('.tree-truncated-warning') - end - - it 'truncates entries and adds a warning' do - stub_const('TreeHelper::FILE_LIMIT', 1) - tree = repository.tree(sha, 'files') - - html = render_tree(tree) - - expect(html).to have_selector('.tree-truncated-warning', count: 1) - expect(html).to have_selector('.tree-item-file-name', count: 1) - end - end - - describe '.fast_project_blob_path' do - it 'generates the same path as project_blob_path' do - blob_path = repository.tree(sha, 'with space').entries.first.path - fast_path = fast_project_blob_path(project, blob_path) - std_path = project_blob_path(project, blob_path) - - expect(fast_path).to eq(std_path) - end - - it 'generates the same path with encoded file names' do - tree = repository.tree(sha, 'encoding') - blob_path = tree.entries.find { |entry| entry.path == 'encoding/ใในใ.txt' }.path - fast_path = fast_project_blob_path(project, blob_path) - std_path = project_blob_path(project, blob_path) - - expect(fast_path).to eq(std_path) - end - - it 'respects a configured relative URL' do - allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return('/gitlab/root') - blob_path = repository.tree(sha, '').entries.first.path - fast_path = fast_project_blob_path(project, blob_path) - - expect(fast_path).to start_with('/gitlab/root') - end - - it 'encodes files starting with #' do - filename = '#test-file' - create_file(filename) - - fast_path = fast_project_blob_path(project, filename) - - expect(fast_path).to end_with('%23test-file') - end - end - - describe '.fast_project_tree_path' do - let(:tree_path) { repository.tree(sha, 'with space').path } - let(:fast_path) { fast_project_tree_path(project, tree_path) } - let(:std_path) { project_tree_path(project, tree_path) } - - it 'generates the same path as project_tree_path' do - expect(fast_path).to eq(std_path) - end - - it 'respects a configured relative URL' do - allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return('/gitlab/root') - - expect(fast_path).to start_with('/gitlab/root') - end - - it 'encodes files starting with #' do - filename = '#test-file' - create_file(filename) - - fast_path = fast_project_tree_path(project, filename) - - expect(fast_path).to end_with('%23test-file') - end - end - describe 'flatten_tree' do let(:tree) { repository.tree(sha, 'files') } let(:root_path) { 'files' } diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb index 250aedda906..b6607182461 100644 --- a/spec/helpers/user_callouts_helper_spec.rb +++ b/spec/helpers/user_callouts_helper_spec.rb @@ -222,4 +222,24 @@ RSpec.describe UserCalloutsHelper do it { is_expected.to be true } end end + + describe '.show_unfinished_tag_cleanup_callout?' do + subject { helper.show_unfinished_tag_cleanup_callout? } + + before do + allow(helper).to receive(:user_dismissed?).with(described_class::UNFINISHED_TAG_CLEANUP_CALLOUT) { dismissed } + end + + context 'when user has not dismissed' do + let(:dismissed) { false } + + it { is_expected.to be true } + end + + context 'when user dismissed' do + let(:dismissed) { true } + + it { is_expected.to be false } + end + end end |