diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 15:40:28 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 15:40:28 +0000 |
commit | b595cb0c1dec83de5bdee18284abe86614bed33b (patch) | |
tree | 8c3d4540f193c5ff98019352f554e921b3a41a72 /spec/helpers | |
parent | 2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff) | |
download | gitlab-ce-b595cb0c1dec83de5bdee18284abe86614bed33b.tar.gz |
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'spec/helpers')
22 files changed, 531 insertions, 161 deletions
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb index 192e48f43e5..9c0f8b77d45 100644 --- a/spec/helpers/avatars_helper_spec.rb +++ b/spec/helpers/avatars_helper_spec.rb @@ -221,48 +221,56 @@ RSpec.describe AvatarsHelper do stub_application_setting(gravatar_enabled?: true) end - it 'returns a generic avatar when email is blank' do - expect(helper.gravatar_icon('')).to match_asset_path(described_class::DEFAULT_AVATAR_PATH) - end + context 'with FIPS not enabled', fips_mode: false do + it 'returns a generic avatar when email is blank' do + expect(helper.gravatar_icon('')).to match_asset_path(described_class::DEFAULT_AVATAR_PATH) + end - it 'returns a valid Gravatar URL' do - stub_config_setting(https: false) + it 'returns a valid Gravatar URL' do + stub_config_setting(https: false) - expect(helper.gravatar_icon(user_email)) - .to match('https://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118') - end + expect(helper.gravatar_icon(user_email)) + .to match('https://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118') + end - it 'uses HTTPs when configured' do - stub_config_setting(https: true) + it 'uses HTTPs when configured' do + stub_config_setting(https: true) - expect(helper.gravatar_icon(user_email)) - .to match('https://secure.gravatar.com') - end + expect(helper.gravatar_icon(user_email)) + .to match('https://secure.gravatar.com') + end - it 'returns custom gravatar path when gravatar_url is set' do - stub_gravatar_setting(plain_url: 'http://example.local/?s=%{size}&hash=%{hash}') + it 'returns custom gravatar path when gravatar_url is set' do + stub_gravatar_setting(plain_url: 'http://example.local/?s=%{size}&hash=%{hash}') - expect(gravatar_icon(user_email, 20)) - .to eq('http://example.local/?s=40&hash=b58c6f14d292556214bd64909bcdb118') - end + expect(gravatar_icon(user_email, 20)) + .to eq('http://example.local/?s=40&hash=b58c6f14d292556214bd64909bcdb118') + end - it 'accepts a custom size argument' do - expect(helper.gravatar_icon(user_email, 64)).to include '?s=128' - end + it 'accepts a custom size argument' do + expect(helper.gravatar_icon(user_email, 64)).to include '?s=128' + end - it 'defaults size to 40@2x when given an invalid size' do - expect(helper.gravatar_icon(user_email, nil)).to include '?s=80' - end + it 'defaults size to 40@2x when given an invalid size' do + expect(helper.gravatar_icon(user_email, nil)).to include '?s=80' + end - it 'accepts a scaling factor' do - expect(helper.gravatar_icon(user_email, 40, 3)).to include '?s=120' - end + it 'accepts a scaling factor' do + expect(helper.gravatar_icon(user_email, 40, 3)).to include '?s=120' + end - it 'ignores case and surrounding whitespace' do - normal = helper.gravatar_icon('foo@example.com') - upcase = helper.gravatar_icon(' FOO@EXAMPLE.COM ') + it 'ignores case and surrounding whitespace' do + normal = helper.gravatar_icon('foo@example.com') + upcase = helper.gravatar_icon(' FOO@EXAMPLE.COM ') - expect(normal).to eq upcase + expect(normal).to eq upcase + end + end + + context 'with FIPS enabled', :fips_mode do + it 'returns a generic avatar' do + expect(helper.gravatar_icon(user_email)).to match_asset_path(described_class::DEFAULT_AVATAR_PATH) + 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 8366506aa45..bc9e47a4ca1 100644 --- a/spec/helpers/ci/pipeline_editor_helper_spec.rb +++ b/spec/helpers/ci/pipeline_editor_helper_spec.rb @@ -48,6 +48,7 @@ RSpec.describe Ci::PipelineEditorHelper do "ci-config-path": project.ci_config_path_or_default, "ci-examples-help-page-path" => help_page_path('ci/examples/index'), "ci-help-page-path" => help_page_path('ci/index'), + "ci-lint-path" => project_ci_lint_path(project), "default-branch" => project.default_branch_or_main, "empty-state-illustration-path" => 'illustrations/empty.svg', "initial-branch-name" => nil, @@ -62,6 +63,7 @@ RSpec.describe Ci::PipelineEditorHelper do "project-full-path" => project.full_path, "project-namespace" => project.namespace.full_path, "runner-help-page-path" => help_page_path('ci/runners/index'), + "simulate-pipeline-help-page-path" => help_page_path('ci/lint', anchor: 'simulate-a-pipeline'), "total-branches" => project.repository.branches.length, "validate-tab-illustration-path" => 'illustrations/validate.svg', "yml-help-page-path" => help_page_path('ci/yaml/index') @@ -77,6 +79,7 @@ RSpec.describe Ci::PipelineEditorHelper do "ci-config-path": project.ci_config_path_or_default, "ci-examples-help-page-path" => help_page_path('ci/examples/index'), "ci-help-page-path" => help_page_path('ci/index'), + "ci-lint-path" => project_ci_lint_path(project), "default-branch" => project.default_branch_or_main, "empty-state-illustration-path" => 'illustrations/empty.svg', "initial-branch-name" => nil, @@ -91,6 +94,7 @@ RSpec.describe Ci::PipelineEditorHelper do "project-full-path" => project.full_path, "project-namespace" => project.namespace.full_path, "runner-help-page-path" => help_page_path('ci/runners/index'), + "simulate-pipeline-help-page-path" => help_page_path('ci/lint', anchor: 'simulate-a-pipeline'), "total-branches" => 0, "validate-tab-illustration-path" => 'illustrations/validate.svg', "yml-help-page-path" => help_page_path('ci/yaml/index') diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb index 961e7688202..b5b572e9719 100644 --- a/spec/helpers/commits_helper_spec.rb +++ b/spec/helpers/commits_helper_spec.rb @@ -94,7 +94,7 @@ RSpec.describe CommitsHelper do it 'renders the correct select-rendered button' do expect(node[:title]).to eq('Display rendered diff') expect(node['data-file-hash']).to eq('abc') - expect(node['data-diff-toggle-entity']).to eq('toShowBtn') + expect(node['data-diff-toggle-entity']).to eq('renderedButton') expect(node.xpath("//a/svg")[0]["data-testid"]).to eq('doc-text-icon') end end @@ -105,7 +105,7 @@ RSpec.describe CommitsHelper do it 'renders the correct select-raw button' do expect(node[:title]).to eq('Display raw diff') expect(node['data-file-hash']).to eq('abc') - expect(node['data-diff-toggle-entity']).to eq('toHideBtn') + expect(node['data-diff-toggle-entity']).to eq('rawButton') expect(node.xpath("//a/svg")[0]["data-testid"]).to eq('doc-code-icon') end end diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index cf16807723b..93efce6b58b 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -470,22 +470,69 @@ RSpec.describe DiffHelper do end describe '#conflicts' do - let(:merge_request) { instance_double(MergeRequest) } + let(:merge_request) { instance_double(MergeRequest, cannot_be_merged?: true) } + let(:merge_ref_head_diff) { true } + let(:can_be_resolved_in_ui?) { true } + let(:allow_tree_conflicts) { false } + let(:files) { [instance_double(Gitlab::Conflict::File, path: 'a')] } + let(:exception) { nil } before do allow(helper).to receive(:merge_request).and_return(merge_request) - allow(helper).to receive(:options).and_return(merge_ref_head_diff: true) + allow(helper).to receive(:options).and_return(merge_ref_head_diff: merge_ref_head_diff) + + allow_next_instance_of(MergeRequests::Conflicts::ListService, merge_request, allow_tree_conflicts: allow_tree_conflicts) do |svc| + allow(svc).to receive(:can_be_resolved_in_ui?).and_return(can_be_resolved_in_ui?) + + if exception.present? + allow(svc).to receive_message_chain(:conflicts, :files).and_raise(exception) + else + allow(svc).to receive_message_chain(:conflicts, :files).and_return(files) + end + end end - context 'when Gitlab::Git::Conflict::Resolver::ConflictSideMissing exception is raised' do - before do - allow_next_instance_of(MergeRequests::Conflicts::ListService, merge_request, allow_tree_conflicts: true) do |svc| - allow(svc).to receive_message_chain(:conflicts, :files).and_raise(Gitlab::Git::Conflict::Resolver::ConflictSideMissing) + it 'returns list of conflicts indexed by path' do + expect(helper.conflicts).to eq('a' => files.first) + end + + context 'when merge_ref_head_diff option is false' do + let(:merge_ref_head_diff) { false } + + it 'returns nil' do + expect(helper.conflicts).to be_nil + end + end + + context 'when merge request can be merged' do + let(:merge_request) { instance_double(MergeRequest, cannot_be_merged?: false) } + + it 'returns nil' do + expect(helper.conflicts).to be_nil + end + end + + context 'when conflicts cannot be resolved in UI' do + let(:can_be_resolved_in_ui?) { false } + + it 'returns nil' do + expect(helper.conflicts).to be_nil + end + + context 'when allow_tree_conflicts is true' do + let(:allow_tree_conflicts) { true } + + it 'returns list of conflicts' do + expect(helper.conflicts(allow_tree_conflicts: allow_tree_conflicts)).to eq('a' => files.first) end end + end + + context 'when Gitlab::Git::Conflict::Resolver::ConflictSideMissing exception is raised' do + let(:exception) { Gitlab::Git::Conflict::Resolver::ConflictSideMissing } it 'returns an empty hash' do - expect(helper.conflicts(allow_tree_conflicts: true)).to eq({}) + expect(helper.conflicts).to eq({}) end end end diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb index 220e154aad8..04653d9ff03 100644 --- a/spec/helpers/emails_helper_spec.rb +++ b/spec/helpers/emails_helper_spec.rb @@ -77,7 +77,7 @@ RSpec.describe EmailsHelper do end describe 'notification_reason_text' do - subject { helper.notification_reason_text(reason_code) } + subject { helper.notification_reason_text(reason: reason_code) } using RSpec::Parameterized::TableSyntax diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb index e4d4f18ad68..c1eaf1b1bcd 100644 --- a/spec/helpers/environments_helper_spec.rb +++ b/spec/helpers/environments_helper_spec.rb @@ -129,7 +129,6 @@ RSpec.describe EnvironmentsHelper do "environment_name": environment.name, "environments_path": api_v4_projects_environments_path(id: project.id), "environment_id": environment.id, - "cluster_applications_documentation_path" => help_page_path('user/clusters/integrations.md', anchor: 'elastic-stack-cluster-integration'), "clusters_path": project_clusters_path(project, format: :json) } diff --git a/spec/helpers/groups/group_members_helper_spec.rb b/spec/helpers/groups/group_members_helper_spec.rb index d308df3a017..89c26c21338 100644 --- a/spec/helpers/groups/group_members_helper_spec.rb +++ b/spec/helpers/groups/group_members_helper_spec.rb @@ -44,6 +44,7 @@ RSpec.describe Groups::GroupMembersHelper do members: present_members(members_collection), invited: present_members(invited), access_requests: present_members(access_requests), + banned: [], include_relations: [:inherited, :direct], search: nil ) @@ -117,6 +118,7 @@ RSpec.describe Groups::GroupMembersHelper do members: present_members(members_collection), invited: present_members(invited), access_requests: present_members(access_requests), + banned: [], include_relations: include_relations, search: nil ) diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index bcbe571db5e..d00cd8f1d6b 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -355,8 +355,8 @@ RSpec.describe GroupsHelper do end end - describe '#show_thanks_for_purchase_banner?' do - subject { helper.show_thanks_for_purchase_banner? } + describe '#show_thanks_for_purchase_alert?' do + subject { helper.show_thanks_for_purchase_alert? } it 'returns true with purchased_quantity present in params' do allow(controller).to receive(:params) { { purchased_quantity: '1' } } diff --git a/spec/helpers/learn_gitlab_helper_spec.rb b/spec/helpers/learn_gitlab_helper_spec.rb index 9fce7495b5a..7c9dfd6b5be 100644 --- a/spec/helpers/learn_gitlab_helper_spec.rb +++ b/spec/helpers/learn_gitlab_helper_spec.rb @@ -92,38 +92,6 @@ RSpec.describe LearnGitlabHelper do it_behaves_like 'has all data' - it 'sets correct paths' do - expect(onboarding_actions_data).to match({ - trial_started: a_hash_including( - url: a_string_matching(%r{/learn_gitlab/-/issues/2\z}) - ), - pipeline_created: a_hash_including( - url: a_string_matching(%r{/learn_gitlab/-/issues/7\z}) - ), - code_owners_enabled: a_hash_including( - url: a_string_matching(%r{/learn_gitlab/-/issues/10\z}) - ), - required_mr_approvals_enabled: a_hash_including( - url: a_string_matching(%r{/learn_gitlab/-/issues/11\z}) - ), - issue_created: a_hash_including( - url: a_string_matching(%r{/learn_gitlab/-/issues\z}) - ), - git_write: a_hash_including( - url: a_string_matching(%r{/learn_gitlab\z}) - ), - user_added: a_hash_including( - url: a_string_matching(%r{/learn_gitlab/-/project_members\z}) - ), - merge_request_created: a_hash_including( - url: a_string_matching(%r{/learn_gitlab/-/merge_requests\z}) - ), - security_scan_enabled: a_hash_including( - url: a_string_matching(%r{/learn_gitlab/-/security/configuration\z}) - ) - }) - end - it 'sets correct completion statuses' do expect(onboarding_actions_data).to match({ issue_created: a_hash_including(completed: false), @@ -137,5 +105,58 @@ RSpec.describe LearnGitlabHelper do security_scan_enabled: a_hash_including(completed: false) }) end + + describe 'security_actions_continuous_onboarding experiment' do + let(:base_paths) do + { + trial_started: a_hash_including(url: %r{/learn_gitlab/-/issues/2\z}), + pipeline_created: a_hash_including(url: %r{/learn_gitlab/-/issues/7\z}), + code_owners_enabled: a_hash_including(url: %r{/learn_gitlab/-/issues/10\z}), + required_mr_approvals_enabled: a_hash_including(url: %r{/learn_gitlab/-/issues/11\z}), + issue_created: a_hash_including(url: %r{/learn_gitlab/-/issues\z}), + git_write: a_hash_including(url: %r{/learn_gitlab\z}), + user_added: a_hash_including(url: %r{/learn_gitlab/-/project_members\z}), + merge_request_created: a_hash_including(url: %r{/learn_gitlab/-/merge_requests\z}) + } + end + + context 'when control' do + before do + stub_experiments(security_actions_continuous_onboarding: :control) + end + + it 'sets correct paths' do + expect(onboarding_actions_data).to match( + base_paths.merge( + security_scan_enabled: a_hash_including( + url: %r{/learn_gitlab/-/security/configuration\z} + ) + ) + ) + end + end + + context 'when candidate' do + before do + stub_experiments(security_actions_continuous_onboarding: :candidate) + end + + it 'sets correct paths' do + expect(onboarding_actions_data).to match( + base_paths.merge( + license_scanning_run: a_hash_including( + url: described_class::LICENSE_SCANNING_RUN_URL + ), + secure_dependency_scanning_run: a_hash_including( + url: project_security_configuration_path(project, anchor: 'dependency-scanning') + ), + secure_dast_run: a_hash_including( + url: project_security_configuration_path(project, anchor: 'dast') + ) + ) + ) + end + end + end end end diff --git a/spec/helpers/namespace_storage_limit_alert_helper_spec.rb b/spec/helpers/namespace_storage_limit_alert_helper_spec.rb deleted file mode 100644 index ab3cf96edef..00000000000 --- a/spec/helpers/namespace_storage_limit_alert_helper_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe NamespaceStorageLimitAlertHelper do - describe '#display_namespace_storage_limit_alert!' do - it 'is defined in CE' do - expect { helper.display_namespace_storage_limit_alert! }.not_to raise_error - end - end -end diff --git a/spec/helpers/nav/new_dropdown_helper_spec.rb b/spec/helpers/nav/new_dropdown_helper_spec.rb index 4f32ac5b5c6..2fe237fb996 100644 --- a/spec/helpers/nav/new_dropdown_helper_spec.rb +++ b/spec/helpers/nav/new_dropdown_helper_spec.rb @@ -55,7 +55,7 @@ RSpec.describe Nav::NewDropdownHelper do end it 'has title' do - expect(subject[:title]).to eq('Create new') + expect(subject[:title]).to eq('Create new...') end context 'when current_user is nil (anonymous)' do diff --git a/spec/helpers/projects/pipeline_helper_spec.rb b/spec/helpers/projects/pipeline_helper_spec.rb index d04aa9a9d04..2b2dad286c7 100644 --- a/spec/helpers/projects/pipeline_helper_spec.rb +++ b/spec/helpers/projects/pipeline_helper_spec.rb @@ -11,7 +11,11 @@ RSpec.describe Projects::PipelineHelper do let_it_be(:pipeline) { Ci::PipelinePresenter.new(raw_pipeline, current_user: user)} describe '#js_pipeline_tabs_data' do - subject(:pipeline_tabs_data) { helper.js_pipeline_tabs_data(project, pipeline) } + before do + project.add_developer(user) + end + + subject(:pipeline_tabs_data) { helper.js_pipeline_tabs_data(project, pipeline, user) } it 'returns pipeline tabs data' do expect(pipeline_tabs_data).to include({ diff --git a/spec/helpers/projects/project_members_helper_spec.rb b/spec/helpers/projects/project_members_helper_spec.rb index 2414a1782c5..844c33de635 100644 --- a/spec/helpers/projects/project_members_helper_spec.rb +++ b/spec/helpers/projects/project_members_helper_spec.rb @@ -14,7 +14,6 @@ RSpec.describe Projects::ProjectMembersHelper do describe 'project members' do let_it_be(:members) { create_list(:project_member, 2, project: project) } - let_it_be(:group_links) { create_list(:project_group_link, 1, project: project) } let_it_be(:invited) { create_list(:project_member, 2, :invited, project: project) } let_it_be(:access_requests) { create_list(:project_member, 2, :access_request, project: project) } @@ -26,9 +25,10 @@ RSpec.describe Projects::ProjectMembersHelper do helper.project_members_app_data_json( project, members: present_members(members_collection), - group_links: group_links, invited: present_members(invited), - access_requests: present_members(access_requests) + access_requests: present_members(access_requests), + include_relations: [:inherited, :direct], + search: nil ) ) end @@ -84,6 +84,70 @@ RSpec.describe Projects::ProjectMembersHelper do expect(subject['user']['pagination']).to match(expected) end end + + context 'group links' do + let_it_be(:shared_with_group) { create(:group) } + let_it_be(:group_link) { create(:project_group_link, project: project, group: shared_with_group) } + + before do + allow(helper).to receive(:project_group_link_path).with(project, ':id').and_return('/foo-group/foo-project/-/group_links/:id') + end + + it 'sets `group.members` property that matches json schema' do + expect(subject['group']['members'].to_json).to match_schema('group_link/project_group_links') + end + + it 'sets `member_path` property' do + expect(subject['group']['member_path']).to eq('/foo-group/foo-project/-/group_links/:id') + end + + context 'inherited' do + let_it_be(:shared_with_group_1) { create(:group) } + let_it_be(:shared_with_group_2) { create(:group) } + let_it_be(:shared_with_group_3) { create(:group) } + let_it_be(:shared_with_group_4) { create(:group) } + let_it_be(:shared_with_group_5) { create(:group) } + let_it_be(:top_group) { create(:group) } + let_it_be(:sub_group) { create(:group, parent: top_group) } + let_it_be(:project) { create(:project, group: sub_group) } + let_it_be(:group_link_1) { create(:group_group_link, shared_group: top_group, shared_with_group: shared_with_group_1, group_access: Gitlab::Access::GUEST) } + let_it_be(:group_link_2) { create(:group_group_link, shared_group: top_group, shared_with_group: shared_with_group_4, group_access: Gitlab::Access::GUEST) } + let_it_be(:group_link_3) { create(:group_group_link, shared_group: top_group, shared_with_group: shared_with_group_5, group_access: Gitlab::Access::DEVELOPER) } + let_it_be(:group_link_4) { create(:group_group_link, shared_group: sub_group, shared_with_group: shared_with_group_2, group_access: Gitlab::Access::DEVELOPER) } + let_it_be(:group_link_5) { create(:group_group_link, shared_group: sub_group, shared_with_group: shared_with_group_4, group_access: Gitlab::Access::DEVELOPER) } + let_it_be(:group_link_6) { create(:group_group_link, shared_group: sub_group, shared_with_group: shared_with_group_5, group_access: Gitlab::Access::GUEST) } + let_it_be(:group_link_7) { create(:project_group_link, project: project, group: shared_with_group_1, group_access: Gitlab::Access::DEVELOPER) } + let_it_be(:group_link_8) { create(:project_group_link, project: project, group: shared_with_group_2, group_access: Gitlab::Access::GUEST) } + let_it_be(:group_link_9) { create(:project_group_link, project: project, group: shared_with_group_3, group_access: Gitlab::Access::REPORTER) } + + subject do + Gitlab::Json.parse( + helper.project_members_app_data_json( + project, + members: present_members(members_collection), + invited: present_members(invited), + access_requests: present_members(access_requests), + include_relations: include_relations, + search: nil + ) + ) + end + + using RSpec::Parameterized::TableSyntax + + where(:include_relations, :result) do + [:inherited, :direct] | lazy { [group_link_7, group_link_4, group_link_9, group_link_5, group_link_3].map(&:id) } + [:inherited] | lazy { [group_link_1, group_link_4, group_link_5, group_link_3].map(&:id) } + [:direct] | lazy { [group_link_7, group_link_8, group_link_9].map(&:id) } + end + + with_them do + it 'returns correct group links' do + expect(subject['group']['members'].map { |link| link['id'] }).to match_array(result) + end + end + end + end end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 4502729866c..b7cc8c217a4 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -698,7 +698,7 @@ RSpec.describe ProjectsHelper do def grant_user_access(project, user, access) case access when :developer, :maintainer - project.add_user(user, access) + project.add_member(user, access) when :owner project.namespace.update!(owner: user) end @@ -969,6 +969,10 @@ RSpec.describe ProjectsHelper do containerRegistryAccessLevel: project.project_feature.container_registry_access_level ) end + + it 'includes membersPagePath' do + expect(subject).to include(membersPagePath: project_project_members_path(project)) + end end describe '#project_classes' do diff --git a/spec/helpers/releases_helper_spec.rb b/spec/helpers/releases_helper_spec.rb index b7493e84c6a..59a92c067f4 100644 --- a/spec/helpers/releases_helper_spec.rb +++ b/spec/helpers/releases_helper_spec.rb @@ -64,7 +64,9 @@ RSpec.describe ReleasesHelper do release_assets_docs_path manage_milestones_path new_milestone_path - edit_release_docs_path) + upcoming_release_docs_path + edit_release_docs_path + delete_release_docs_path) expect(helper.data_for_edit_release_page.keys).to match_array(keys) end @@ -76,6 +78,7 @@ RSpec.describe ReleasesHelper do group_id group_milestones_available project_path + tag_name releases_page_path markdown_preview_path markdown_docs_path @@ -83,6 +86,7 @@ RSpec.describe ReleasesHelper do manage_milestones_path new_milestone_path default_branch + upcoming_release_docs_path edit_release_docs_path) expect(helper.data_for_new_release_page.keys).to match_array(keys) diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 4117d577f20..1ead1fc9b8b 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -741,7 +741,7 @@ RSpec.describe SearchHelper do let(:for_group) { true } it 'adds the :group and :group_metadata correctly to hash' do - expect(header_search_context[:group]).to eq({ id: group.id, name: group.name }) + expect(header_search_context[:group]).to eq({ id: group.id, name: group.name, full_name: group.full_name }) expect(header_search_context[:group_metadata]).to eq(group_metadata) end diff --git a/spec/helpers/sessions_helper_spec.rb b/spec/helpers/sessions_helper_spec.rb index fd3d7100ba1..15424425060 100644 --- a/spec/helpers/sessions_helper_spec.rb +++ b/spec/helpers/sessions_helper_spec.rb @@ -50,4 +50,51 @@ RSpec.describe SessionsHelper do expect(helper.unconfirmed_email?).to be_falsey end end + + describe '#send_rate_limited?' do + let_it_be(:user) { build(:user) } + + subject { helper.send_rate_limited?(user) } + + before do + allow(::Gitlab::ApplicationRateLimiter) + .to receive(:peek) + .with(:email_verification_code_send, scope: user) + .and_return(rate_limited) + end + + context 'when rate limited' do + let(:rate_limited) { true } + + it { is_expected.to eq(true) } + end + + context 'when not rate limited' do + let(:rate_limited) { false } + + it { is_expected.to eq(false) } + end + end + + describe '#obfuscated_email' do + subject { helper.obfuscated_email(email) } + + context 'when an email address is normal length' do + let(:email) { 'alex@gitlab.com' } + + it { is_expected.to eq('al**@g*****.com') } + end + + context 'when an email address contains multiple top level domains' do + let(:email) { 'alex@gl.co.uk' } + + it { is_expected.to eq('al**@g****.uk') } + end + + context 'when an email address is very short' do + let(:email) { 'a@b' } + + it { is_expected.to eq('a@b') } + end + end end diff --git a/spec/helpers/storage_helper_spec.rb b/spec/helpers/storage_helper_spec.rb index c2c508cf485..4b46bf169e0 100644 --- a/spec/helpers/storage_helper_spec.rb +++ b/spec/helpers/storage_helper_spec.rb @@ -51,14 +51,14 @@ RSpec.describe StorageHelper do end end - describe "storage_enforcement_banner", :saas do + describe "storage_enforcement_banner" do let_it_be_with_refind(:current_user) { create(:user) } let_it_be(:free_group) { create(:group) } let_it_be(:paid_group) { create(:group) } before do - allow(helper).to receive(:can?).with(current_user, :admin_namespace, free_group).and_return(true) - allow(helper).to receive(:can?).with(current_user, :admin_namespace, paid_group).and_return(true) + allow(helper).to receive(:can?).with(current_user, :maintain_namespace, free_group).and_return(true) + allow(helper).to receive(:can?).with(current_user, :maintain_namespace, paid_group).and_return(true) allow(helper).to receive(:current_user) { current_user } allow(paid_group).to receive(:paid?).and_return(true) @@ -84,7 +84,13 @@ RSpec.describe StorageHelper do end it 'returns nil when current_user do not have access usage quotas page' do - allow(helper).to receive(:can?).with(current_user, :admin_namespace, free_group).and_return(false) + allow(helper).to receive(:can?).with(current_user, :maintain_namespace, free_group).and_return(false) + + expect(helper.storage_enforcement_banner_info(free_group)).to be(nil) + end + + it 'returns nil when namespace_storage_limit_show_preenforcement_banner FF is disabled' do + stub_feature_flags(namespace_storage_limit_show_preenforcement_banner: false) expect(helper.storage_enforcement_banner_info(free_group)).to be(nil) end diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb index 922fb1d7c92..bbabfedc3ee 100644 --- a/spec/helpers/todos_helper_spec.rb +++ b/spec/helpers/todos_helper_spec.rb @@ -5,7 +5,8 @@ require 'spec_helper' RSpec.describe TodosHelper do let_it_be(:user) { create(:user) } let_it_be(:author) { create(:user) } - let_it_be(:issue) { create(:issue, title: 'Issue 1') } + let_it_be(:project) { create(:project) } + let_it_be(:issue) { create(:issue, title: 'Issue 1', project: project) } let_it_be(:design) { create(:design, issue: issue) } let_it_be(:note) do create(:note, @@ -16,7 +17,7 @@ RSpec.describe TodosHelper do let_it_be(:design_todo) do create(:todo, :mentioned, user: user, - project: issue.project, + project: project, target: design, author: author, note: note) @@ -27,6 +28,15 @@ RSpec.describe TodosHelper do create(:todo, target: alert) end + let_it_be(:task_todo) do + task = create(:work_item, :task, project: project) + create(:todo, target: task, target_type: task.class.name, project: project) + end + + let_it_be(:issue_todo) do + create(:todo, target: issue) + end + describe '#todos_count_format' do it 'shows fuzzy count for 100 or more items' do expect(helper.todos_count_format(100)).to eq '99+' @@ -113,27 +123,62 @@ RSpec.describe TodosHelper do ) end end + + context 'when given a task' do + let(:todo) { task_todo } + + it 'responds with an appropriate path' do + path = helper.todo_target_path(todo) + + expect(path).to eq("/#{todo.project.full_path}/-/work_items/#{todo.target.id}") + end + end + + context 'when given an issue with a note anchor' do + let(:todo) { create(:todo, project: issue.project, target: issue, note: note) } + + it 'responds with an appropriate path' do + path = helper.todo_target_path(todo) + + expect(path).to eq("/#{issue.project.full_path}/-/issues/#{issue.iid}##{dom_id(note)}") + end + end end describe '#todo_target_type_name' do + subject { helper.todo_target_type_name(todo) } + context 'when given a design todo' do let(:todo) { design_todo } - it 'responds with an appropriate target type name' do - name = helper.todo_target_type_name(todo) - - expect(name).to eq('design') - end + it { is_expected.to eq('design') } end context 'when given an alert todo' do let(:todo) { alert_todo } - it 'responds with an appropriate target type name' do - name = helper.todo_target_type_name(todo) + it { is_expected.to eq('alert') } + end + + context 'when given a task todo' do + let(:todo) { task_todo } - expect(name).to eq('alert') + it { is_expected.to eq('task') } + end + + context 'when given an issue todo' do + let(:todo) { issue_todo } + + it { is_expected.to eq('issue') } + end + + context 'when given a merge request todo' do + let(:todo) do + merge_request = create(:merge_request, source_project: project) + create(:todo, target: merge_request) end + + it { is_expected.to eq('merge request') } end end diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb index 026432adf99..c40284ee933 100644 --- a/spec/helpers/tree_helper_spec.rb +++ b/spec/helpers/tree_helper_spec.rb @@ -3,63 +3,12 @@ require 'spec_helper' RSpec.describe TreeHelper do - let(:project) { create(:project, :repository) } + let_it_be(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:sha) { 'c1c67abbaf91f624347bb3ae96eabe3a1b742478' } let_it_be(:user) { create(:user) } - def create_file(filename) - project.repository.create_file( - project.creator, - filename, - 'test this', - message: "Automatically created file #{filename}", - branch_name: 'master' - ) - end - - describe 'flatten_tree' do - let(:tree) { repository.tree(sha, 'files') } - let(:root_path) { 'files' } - let(:tree_item) { tree.entries.find { |entry| entry.path == path } } - - subject { flatten_tree(root_path, tree_item) } - - context "on a directory containing more than one file/directory" do - let(:path) { 'files/html' } - - it "returns the directory name" do - expect(subject).to match('html') - end - end - - context "on a directory containing only one directory" do - let(:path) { 'files/flat' } - - it "returns the flattened path" do - expect(subject).to match('flat/path/correct') - end - - context "with a nested root path" do - let(:root_path) { 'files/flat' } - - it "returns the flattened path with the root path suffix removed" do - expect(subject).to match('path/correct') - end - end - end - - context 'when the root path contains a plus character' do - let(:root_path) { 'gtk/C++' } - let(:tree_item) { double(flat_path: 'gtk/C++/glade') } - - it 'returns the flattened path' do - expect(subject).to eq('glade') - end - end - end - describe '#commit_in_single_accessible_branch' do it 'escapes HTML from the branch name' do helper.instance_variable_set(:@branch_name, "<script>alert('escape me!');</script>") @@ -163,6 +112,7 @@ RSpec.describe TreeHelper do context 'user does not have write access but a personal fork exists' do include ProjectForksHelper + let(:project) { create(:project, :repository) } let(:forked_project) { create(:project, :repository, namespace: user.namespace) } before do diff --git a/spec/helpers/users/callouts_helper_spec.rb b/spec/helpers/users/callouts_helper_spec.rb index 71a8d340b30..2c148aabead 100644 --- a/spec/helpers/users/callouts_helper_spec.rb +++ b/spec/helpers/users/callouts_helper_spec.rb @@ -222,4 +222,60 @@ RSpec.describe Users::CalloutsHelper do it { is_expected.to be true } end end + + describe '#web_hook_disabled_dismissed?' do + context 'without a project' do + it 'is false' do + expect(helper).not_to be_web_hook_disabled_dismissed(nil) + end + end + + context 'with a project' do + let_it_be(:project) { create(:project) } + + context 'the web-hook failure callout has never been dismissed' do + it 'is false' do + expect(helper).not_to be_web_hook_disabled_dismissed(project) + end + end + + context 'the web-hook failure callout has been dismissed', :freeze_time do + before do + create(:namespace_callout, + feature_name: described_class::WEB_HOOK_DISABLED, + user: user, + namespace: project.namespace, + dismissed_at: 1.week.ago) + end + + it 'is true' do + expect(helper).to be_web_hook_disabled_dismissed(project) + end + + context 'when there was an older failure', :clean_gitlab_redis_shared_state do + let(:key) { "web_hooks:last_failure:project-#{project.id}" } + + before do + Gitlab::Redis::SharedState.with { |r| r.set(key, 1.month.ago.iso8601) } + end + + it 'is true' do + expect(helper).to be_web_hook_disabled_dismissed(project) + end + end + + context 'when there has been a more recent failure', :clean_gitlab_redis_shared_state do + let(:key) { "web_hooks:last_failure:project-#{project.id}" } + + before do + Gitlab::Redis::SharedState.with { |r| r.set(key, 1.day.ago.iso8601) } + end + + it 'is false' do + expect(helper).not_to be_web_hook_disabled_dismissed(project) + end + end + end + end + end end diff --git a/spec/helpers/web_hooks/web_hooks_helper_spec.rb b/spec/helpers/web_hooks/web_hooks_helper_spec.rb new file mode 100644 index 00000000000..473f33a982f --- /dev/null +++ b/spec/helpers/web_hooks/web_hooks_helper_spec.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe WebHooks::WebHooksHelper do + let_it_be_with_reload(:project) { create(:project) } + + let(:current_user) { nil } + let(:callout_dismissed) { false } + let(:web_hooks_disable_failed) { false } + let(:webhooks_failed_callout) { false } + + before do + allow(helper).to receive(:current_user).and_return(current_user) + allow(helper).to receive(:web_hook_disabled_dismissed?).with(project).and_return(callout_dismissed) + + stub_feature_flags( + webhooks_failed_callout: webhooks_failed_callout, + web_hooks_disable_failed: web_hooks_disable_failed + ) + end + + shared_context 'user is logged in' do + let(:current_user) { create(:user) } + end + + shared_context 'webhooks_failed_callout is enabled' do + let(:webhooks_failed_callout) { true } + end + + shared_context 'webhooks_failed_callout is enabled for this project' do + let(:webhooks_failed_callout) { project } + end + + shared_context 'web_hooks_disable_failed is enabled' do + let(:web_hooks_disable_failed) { true } + end + + shared_context 'web_hooks_disable_failed is enabled for this project' do + let(:web_hooks_disable_failed) { project } + end + + shared_context 'the user has permission' do + before do + project.add_maintainer(current_user) + end + end + + shared_context 'the user dismissed the callout' do + let(:callout_dismissed) { true } + end + + shared_context 'a hook has failed' do + before do + create(:project_hook, :permanently_disabled, project: project) + end + end + + describe '#show_project_hook_failed_callout?' do + context 'all conditions are met' do + include_context 'user is logged in' + include_context 'webhooks_failed_callout is enabled' + include_context 'web_hooks_disable_failed is enabled' + include_context 'the user has permission' + include_context 'a hook has failed' + + it 'is true' do + expect(helper).to be_show_project_hook_failed_callout(project: project) + end + + it 'caches the DB calls until the TTL', :use_clean_rails_memory_store_caching, :request_store do + helper.show_project_hook_failed_callout?(project: project) + + travel_to((described_class::EXPIRY_TTL - 1.second).from_now) do + expect do + helper.show_project_hook_failed_callout?(project: project) + end.not_to exceed_query_limit(0) + end + + travel_to((described_class::EXPIRY_TTL + 1.second).from_now) do + expect do + helper.show_project_hook_failed_callout?(project: project) + end.to exceed_query_limit(0) + end + end + end + + context 'all conditions are met, project scoped flags' do + include_context 'user is logged in' + include_context 'webhooks_failed_callout is enabled for this project' + include_context 'web_hooks_disable_failed is enabled for this project' + include_context 'the user has permission' + include_context 'a hook has failed' + + it 'is true' do + expect(helper).to be_show_project_hook_failed_callout(project: project) + end + end + + context 'one condition is not met' do + contexts = [ + 'user is logged in', + 'webhooks_failed_callout is enabled', + 'web_hooks_disable_failed is enabled', + 'the user has permission', + 'a hook has failed' + ] + + contexts.each do |name| + context "namely #{name}" do + contexts.each { |ctx| include_context(ctx) unless ctx == name } + + it 'is false' do + expect(helper).not_to be_show_project_hook_failed_callout(project: project) + end + end + end + end + end +end |