diff options
Diffstat (limited to 'spec/helpers')
23 files changed, 1070 insertions, 347 deletions
diff --git a/spec/helpers/admin/background_migrations_helper_spec.rb b/spec/helpers/admin/background_migrations_helper_spec.rb new file mode 100644 index 00000000000..8880a00755b --- /dev/null +++ b/spec/helpers/admin/background_migrations_helper_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Admin::BackgroundMigrationsHelper do + describe '#batched_migration_status_badge_class_name' do + using RSpec::Parameterized::TableSyntax + + where(:status, :class_name) do + :active | 'badge-info' + :paused | 'badge-warning' + :failed | 'badge-danger' + :finished | 'badge-success' + end + + subject { helper.batched_migration_status_badge_class_name(migration) } + + with_them do + let(:migration) { build(:batched_background_migration, status: status) } + + it { is_expected.to eq(class_name) } + end + end + + describe '#batched_migration_progress' do + subject { helper.batched_migration_progress(migration, completed_rows) } + + let(:migration) { build(:batched_background_migration, status: :active, total_tuple_count: 100) } + let(:completed_rows) { 25 } + + it 'returns completion percentage' do + expect(subject).to eq(25) + end + + context 'when migration is finished' do + let(:migration) { build(:batched_background_migration, status: :finished, total_tuple_count: nil) } + + it 'returns 100 percent' do + expect(subject).to eq(100) + end + end + + context 'when total_tuple_count is nil' do + let(:migration) { build(:batched_background_migration, status: :active, total_tuple_count: nil) } + + it 'returns nil' do + expect(subject).to eq(nil) + end + + context 'when there are no completed rows' do + let(:completed_rows) { 0 } + + it 'returns 0 percent' do + expect(subject).to eq(0) + end + end + end + + context 'when completed rows are greater than total count' do + let(:completed_rows) { 150 } + + it 'returns 99 percent' do + expect(subject).to eq(99) + end + end + end +end diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb index c74ee3ce0ec..4c62b3e12c1 100644 --- a/spec/helpers/application_settings_helper_spec.rb +++ b/spec/helpers/application_settings_helper_spec.rb @@ -37,8 +37,24 @@ RSpec.describe ApplicationSettingsHelper do it_behaves_like 'when HTTP protocol is in use', 'https' it_behaves_like 'when HTTP protocol is in use', 'http' - context 'with tracking parameters' do - it { expect(visible_attributes).to include(*%i(snowplow_collector_hostname snowplow_cookie_domain snowplow_enabled snowplow_app_id)) } + describe '.visible_attributes' do + it 'contains tracking parameters' do + expect(helper.visible_attributes).to include(*%i(snowplow_collector_hostname snowplow_cookie_domain snowplow_enabled snowplow_app_id)) + end + + it 'contains :deactivate_dormant_users' do + expect(helper.visible_attributes).to include(:deactivate_dormant_users) + end + + context 'when GitLab.com' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it 'does not contain :deactivate_dormant_users' do + expect(helper.visible_attributes).not_to include(:deactivate_dormant_users) + end + end end describe '.integration_expanded?' do diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb index 9a1ecb22edb..4e94636ba45 100644 --- a/spec/helpers/commits_helper_spec.rb +++ b/spec/helpers/commits_helper_spec.rb @@ -205,16 +205,6 @@ RSpec.describe CommitsHelper do { id: forked_project.id.to_s, name: forked_project.full_path, refsUrl: refs_project_path(forked_project) } ]) end - - context 'pick_into_project is disabled' do - before do - stub_feature_flags(pick_into_project: false) - end - - it 'does not calculate target projects' do - expect(helper.cherry_pick_projects_data(project)).to eq([]) - end - end end describe "#commit_options_dropdown_data" do @@ -298,7 +288,7 @@ RSpec.describe CommitsHelper do let(:pipeline) { create(:ci_pipeline, :running) } let(:user) { create(:user) } let(:ref) { "master" } - let(:merge_request) { nil } + let(:merge_request) { create(:merge_request) } let(:request) { double(xhr?: true) } let(:current_path) { "test" } @@ -315,8 +305,8 @@ RSpec.describe CommitsHelper do it do is_expected.to include( { - merge_request: merge_request, - pipeline_status: commit_status, + merge_request: merge_request.cache_key, + pipeline_status: pipeline.cache_key, xhr: true, controller: "commits", path: current_path diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb index 89cb0f72277..96869fcc777 100644 --- a/spec/helpers/environments_helper_spec.rb +++ b/spec/helpers/environments_helper_spec.rb @@ -34,7 +34,6 @@ RSpec.describe EnvironmentsHelper do 'project_path' => project_path(project), 'tags_path' => project_tags_path(project), 'has_metrics' => "#{environment.has_metrics?}", - 'prometheus_status' => "#{environment.prometheus_status}", 'external_dashboard_url' => nil, 'environment_state' => environment.state, 'custom_metrics_path' => project_prometheus_metrics_path(project), @@ -158,7 +157,7 @@ RSpec.describe EnvironmentsHelper do let(:cluster) { create(:cluster, projects: [project]) } it 'has managed prometheus' do - create(:clusters_applications_prometheus, :installed, cluster: cluster) + create(:clusters_integrations_prometheus, cluster: cluster) expect(metrics_data).to include( 'has_managed_prometheus' => 'true' @@ -193,7 +192,7 @@ 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/applications.md', anchor: 'elastic-stack'), + "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/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index 264bad92d56..073cebeecd5 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -88,6 +88,13 @@ RSpec.describe EventsHelper do expect(helper.event_feed_url(event)).to eq(push_event_feed_url(event)) end + + it 'returns nil for push event with multiple refs' do + event = create(:push_event) + create(:push_event_payload, event: event, ref_count: 2, ref: nil, ref_type: :tag, commit_count: 0, action: :pushed) + + expect(helper.event_feed_url(event)).to eq(nil) + end end describe '#event_preposition' do diff --git a/spec/helpers/gitlab_script_tag_helper_spec.rb b/spec/helpers/gitlab_script_tag_helper_spec.rb index 37413b9b1c2..35f2c0795be 100644 --- a/spec/helpers/gitlab_script_tag_helper_spec.rb +++ b/spec/helpers/gitlab_script_tag_helper_spec.rb @@ -41,4 +41,11 @@ RSpec.describe GitlabScriptTagHelper do expect(helper.javascript_tag( '// ignored', type: 'application/javascript') { 'alert(1)' }.to_s).to eq tag_with_nonce_and_type end end + + describe '#preload_link_tag' do + it 'returns a link tag with a nonce' do + expect(helper.preload_link_tag('https://example.com/script.js').to_s) + .to eq "<link rel=\"preload\" href=\"https://example.com/script.js\" as=\"script\" type=\"text/javascript\" nonce=\"noncevalue\">" + end + end end diff --git a/spec/helpers/groups/group_members_helper_spec.rb b/spec/helpers/groups/group_members_helper_spec.rb index c3f1509fbc8..b409bebaac3 100644 --- a/spec/helpers/groups/group_members_helper_spec.rb +++ b/spec/helpers/groups/group_members_helper_spec.rb @@ -23,58 +23,79 @@ RSpec.describe Groups::GroupMembersHelper do end end - describe '#group_members_list_data_json' do - let(:group_members) { create_list(:group_member, 2, group: group, created_by: current_user) } - - let(:pagination) { {} } - let(:collection) { group_members } - let(:presented_members) { present_members(collection) } + describe '#group_members_app_data_json' do + include_context 'group_group_link' - subject { Gitlab::Json.parse(helper.group_members_list_data_json(group, presented_members, pagination)) } + let(:members) { create_list(:group_member, 2, group: shared_group, created_by: current_user) } + let(:invited) { create_list(:group_member, 2, :invited, group: shared_group, created_by: current_user) } + let!(:access_requests) { create_list(:group_member, 2, :access_request, group: shared_group, created_by: current_user) } + + let(:members_collection) { members } + + subject do + Gitlab::Json.parse( + helper.group_members_app_data_json( + shared_group, + members: present_members(members_collection), + invited: present_members(invited), + access_requests: present_members(access_requests) + ) + ) + end - shared_examples 'members.json' do + shared_examples 'members.json' do |member_type| it 'returns `members` property that matches json schema' do - expect(subject['members'].to_json).to match_schema('members') + expect(subject[member_type]['members'].to_json).to match_schema('members') + end + + it 'sets `member_path` property' do + expect(subject[member_type]['member_path']).to eq('/groups/foo-bar/-/group_members/:id') end end before do - allow(helper).to receive(:group_group_member_path).with(group, ':id').and_return('/groups/foo-bar/-/group_members/:id') - allow(helper).to receive(:can?).with(current_user, :admin_group_member, group).and_return(true) + allow(helper).to receive(:group_group_member_path).with(shared_group, ':id').and_return('/groups/foo-bar/-/group_members/:id') + allow(helper).to receive(:group_group_link_path).with(shared_group, ':id').and_return('/groups/foo-bar/-/group_links/:id') + allow(helper).to receive(:can?).with(current_user, :admin_group_member, shared_group).and_return(true) end it 'returns expected json' do expected = { - member_path: '/groups/foo-bar/-/group_members/:id', - source_id: group.id, + source_id: shared_group.id, can_manage_members: true }.as_json expect(subject).to include(expected) end - context 'for a group member' do - it_behaves_like 'members.json' + context 'group members' do + it_behaves_like 'members.json', 'user' context 'with user status set' do let(:user) { create(:user) } let!(:status) { create(:user_status, user: user) } - let(:group_members) { [create(:group_member, group: group, user: user, created_by: current_user)] } + let(:members) { [create(:group_member, group: shared_group, user: user, created_by: current_user)] } - it_behaves_like 'members.json' + it_behaves_like 'members.json', 'user' end end - context 'for an invited group member' do - let(:group_members) { create_list(:group_member, 2, :invited, group: group, created_by: current_user) } + context 'invited group members' do + it_behaves_like 'members.json', 'invite' + end - it_behaves_like 'members.json' + context 'access requests' do + it_behaves_like 'members.json', 'access_request' end - context 'for an access request' do - let(:group_members) { create_list(:group_member, 2, :access_request, group: group, created_by: current_user) } + context 'group links' do + it 'sets `group.members` property that matches json schema' do + expect(subject['group']['members'].to_json).to match_schema('group_link/group_group_links') + end - it_behaves_like 'members.json' + it 'sets `member_path` property' do + expect(subject['group']['member_path']).to eq('/groups/foo-bar/-/group_links/:id') + end end context 'when pagination is not available' do @@ -87,13 +108,12 @@ RSpec.describe Groups::GroupMembersHelper do params: {} }.as_json - expect(subject['pagination']).to include(expected) + expect(subject['access_request']['pagination']).to include(expected) end end context 'when pagination is available' do - let(:collection) { Kaminari.paginate_array(group_members).page(1).per(1) } - let(:pagination) { { param_name: :page, params: { search_groups: nil } } } + let(:members_collection) { Kaminari.paginate_array(members).page(1).per(1) } it 'sets `pagination` attribute to expected json' do expected = { @@ -101,41 +121,11 @@ RSpec.describe Groups::GroupMembersHelper do per_page: 1, total_items: 2, param_name: :page, - params: { search_groups: nil } + params: { invited_members_page: nil, search_invited: nil } }.as_json - expect(subject['pagination']).to include(expected) + expect(subject['user']['pagination']).to include(expected) end end end - - describe '#group_group_links_list_data_json' do - include_context 'group_group_link' - - subject { Gitlab::Json.parse(helper.group_group_links_list_data_json(shared_group)) } - - before do - allow(helper).to receive(:group_group_link_path).with(shared_group, ':id').and_return('/groups/foo-bar/-/group_links/:id') - end - - it 'returns expected json' do - expected = { - pagination: { - current_page: nil, - per_page: nil, - total_items: 1, - param_name: nil, - params: {} - }, - member_path: '/groups/foo-bar/-/group_links/:id', - source_id: shared_group.id - }.as_json - - expect(subject).to include(expected) - end - - it 'returns `members` property that matches json schema' do - expect(subject['members'].to_json).to match_schema('group_link/group_group_links') - end - end end diff --git a/spec/helpers/invite_members_helper_spec.rb b/spec/helpers/invite_members_helper_spec.rb index 122f2339b28..3d2adaa5b5d 100644 --- a/spec/helpers/invite_members_helper_spec.rb +++ b/spec/helpers/invite_members_helper_spec.rb @@ -114,69 +114,4 @@ RSpec.describe InviteMembersHelper do end end end - - describe '#dropdown_invite_members_link' do - shared_examples_for 'dropdown invite members link' do - let(:link_regex) do - /data-track-event="click_link".*data-track-property="_track_property_".*Invite members/ - end - - before do - allow(helper).to receive(:experiment_tracking_category_and_group) { '_track_property_' } - allow(helper).to receive(:current_user) { owner } - end - - it 'records the experiment' do - allow(helper).to receive(:experiment_enabled?) - - helper.dropdown_invite_members_link(form_model) - - expect(helper).to have_received(:experiment_tracking_category_and_group).with(:invite_members_new_dropdown) - end - - context 'with experiment enabled' do - before do - allow(helper).to receive(:experiment_enabled?).with(:invite_members_new_dropdown) { true } - end - - it 'returns link' do - link = helper.dropdown_invite_members_link(form_model) - - expect(link).to match(link_regex) - expect(link).to include(link_href) - expect(link).to include('gl-emoji') - end - end - - context 'with no experiment enabled' do - before do - allow(helper).to receive(:experiment_enabled?).with(:invite_members_new_dropdown) { false } - end - - it 'returns link' do - link = helper.dropdown_invite_members_link(form_model) - - expect(link).to match(link_regex) - expect(link).to include(link_href) - expect(link).not_to include('gl-emoji') - end - end - end - - 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' - end - - 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' - end - end end diff --git a/spec/helpers/issuables_description_templates_helper_spec.rb b/spec/helpers/issuables_description_templates_helper_spec.rb index e8961ccb535..95460174266 100644 --- a/spec/helpers/issuables_description_templates_helper_spec.rb +++ b/spec/helpers/issuables_description_templates_helper_spec.rb @@ -13,24 +13,8 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do 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) } - context 'when feature flag disabled' do - before do - stub_feature_flags(inherited_issuable_templates: false) - end - - it 'returns empty array when template type does not exist' do - expect(helper.issuable_templates(project, 'non-existent-template-type')).to eq([]) - end - end - - context 'when feature flag enabled' do - before do - stub_feature_flags(inherited_issuable_templates: true) - end - - it 'returns empty hash when template type does not exist' do - expect(helper.issuable_templates(build(:project), 'non-existent-template-type')).to eq({}) - end + 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 @@ -81,16 +65,18 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do allow(helper).to receive(:issuable_templates).and_return(templates) end - context 'when feature flag disabled' do + context 'with matching project templates' do 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 - - before do - stub_feature_flags(inherited_issuable_templates: false) + { + "" => [ + { name: "another_issue_template", id: "another_issue_template", project_id: project.id }, + { name: "custom_issue_template", id: "custom_issue_template", project_id: project.id } + ], + "Instance" => [ + { name: "first_issue_issue_template", id: "first_issue_issue_template", project_id: non_existing_record_id }, + { name: "second_instance_issue_template", id: "second_instance_issue_template", project_id: non_existing_record_id } + ] + } end it 'returns project templates only' do @@ -98,47 +84,22 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do end end - context 'when feature flag enabled' do - before do - stub_feature_flags(inherited_issuable_templates: true) - end - - context 'with matching project templates' do - 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 } - ], - "Instance" => [ - { name: "first_issue_issue_template", id: "first_issue_issue_template", project_id: non_existing_record_id }, - { name: "second_instance_issue_template", id: "second_instance_issue_template", project_id: non_existing_record_id } - ] - } - end - - it 'returns project templates only' do - expect(helper.issuable_templates_names(Issue.new)).to eq(%w[another_issue_template custom_issue_template]) - end + context 'without matching project templates' do + let(:templates) do + { + "Project Templates" => [ + { name: "another_issue_template", id: "another_issue_template", project_id: non_existing_record_id }, + { name: "custom_issue_template", id: "custom_issue_template", project_id: non_existing_record_id } + ], + "Instance" => [ + { name: "first_issue_issue_template", id: "first_issue_issue_template", project_id: non_existing_record_id }, + { name: "second_instance_issue_template", id: "second_instance_issue_template", project_id: non_existing_record_id } + ] + } end - context 'without matching project templates' do - let(:templates) do - { - "Project Templates" => [ - { name: "another_issue_template", id: "another_issue_template", project_id: non_existing_record_id }, - { name: "custom_issue_template", id: "custom_issue_template", project_id: non_existing_record_id } - ], - "Instance" => [ - { name: "first_issue_issue_template", id: "first_issue_issue_template", project_id: non_existing_record_id }, - { name: "second_instance_issue_template", id: "second_instance_issue_template", project_id: non_existing_record_id } - ] - } - end - - it 'returns empty array' do - expect(helper.issuable_templates_names(Issue.new)).to eq([]) - end + it 'returns empty array' do + expect(helper.issuable_templates_names(Issue.new)).to eq([]) end end diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index b0338d80ee7..ecaee03eeea 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -202,6 +202,20 @@ RSpec.describe IssuablesHelper do end end + describe '#issuable_project_reference' do + it 'display project name and simple reference with `#` to an issue' do + issue = build_stubbed(:issue) + + expect(helper.issuable_project_reference(issue)).to eq("#{issue.project.full_name} ##{issue.iid}") + end + + it 'display project name and simple reference with `!` to an MR' do + merge_request = build_stubbed(:merge_request) + + expect(helper.issuable_project_reference(merge_request)).to eq("#{merge_request.project.full_name} !#{merge_request.iid}") + end + end + describe '#updated_at_by' do let(:user) { create(:user) } let(:unedited_issuable) { create(:issue) } diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 17e6c75ca27..59b42dfca20 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -304,15 +304,15 @@ RSpec.describe IssuesHelper do empty_state_svg_path: '#', endpoint: expose_path(api_v4_projects_issues_path(id: project.id)), export_csv_path: export_csv_project_issues_path(project), - has_issues: project_issues(project).exists?.to_s, + has_project_issues: project_issues(project).exists?.to_s, import_csv_issues_path: '#', initial_email: project.new_issuable_address(current_user, 'issue'), 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'), + jira_integration_path: help_page_url('integration/jira/', anchor: 'view-jira-issues'), markdown_help_path: help_page_path('user/markdown'), 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 }), + new_issue_path: new_project_issue_path(project, issue: { milestone_id: finder.milestones.first.id }), project_import_jira_path: project_import_jira_path(project), project_labels_path: project_labels_path(project, include_ancestor_groups: true, format: :json), project_milestones_path: project_milestones_path(project, format: :json), diff --git a/spec/helpers/keyset_helper_spec.rb b/spec/helpers/keyset_helper_spec.rb new file mode 100644 index 00000000000..2e4bf537e2f --- /dev/null +++ b/spec/helpers/keyset_helper_spec.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe KeysetHelper, type: :controller do + controller(Admin::UsersController) do + def index + @users = User + .where(admin: false) + .order(id: :desc) + .keyset_paginate(cursor: params[:cursor], per_page: 2) + + render inline: "<%= keyset_paginate @users %>", layout: false # rubocop: disable Rails/RenderInline + end + end + + render_views + + let(:admin) { create(:admin) } + + before do + sign_in(admin) + end + + context 'with admin mode', :enable_admin_mode do + context 'when no users are present' do + it 'does not render pagination links' do + get :index + + expect(response.body).not_to include(s_('Pagination|First')) + expect(response.body).not_to include(s_('Pagination|Prev')) + expect(response.body).not_to include(s_('Pagination|Next')) + expect(response.body).not_to include(s_('Pagination|Last')) + end + end + + context 'when one user is present' do + before do + create(:user) + end + + it 'does not render pagination links' do + get :index + + expect(response.body).not_to include(s_('Pagination|First')) + expect(response.body).not_to include(s_('Pagination|Prev')) + expect(response.body).not_to include(s_('Pagination|Next')) + expect(response.body).not_to include(s_('Pagination|Last')) + end + end + + context 'when more users are present' do + let_it_be(:users) { create_list(:user, 5) } + + let(:paginator) { User.where(admin: false).order(id: :desc).keyset_paginate(per_page: 2) } + + context 'when on the first page' do + it 'renders the next and last links' do + get :index + + expect(response.body).not_to include(s_('Pagination|First')) + expect(response.body).not_to include(s_('Pagination|Prev')) + expect(response.body).to include(s_('Pagination|Next')) + expect(response.body).to include(s_('Pagination|Last')) + end + end + + context 'when at the last page' do + it 'renders the prev and first links' do + cursor = paginator.cursor_for_last_page + + get :index, params: { cursor: cursor } + + expect(response.body).to include(s_('Pagination|First')) + expect(response.body).to include(s_('Pagination|Prev')) + expect(response.body).not_to include(s_('Pagination|Next')) + expect(response.body).not_to include(s_('Pagination|Last')) + end + end + + context 'when at the second page' do + it 'renders all links' do + cursor = paginator.cursor_for_next_page + + get :index, params: { cursor: cursor } + + expect(response.body).to include(s_('Pagination|First')) + expect(response.body).to include(s_('Pagination|Prev')) + expect(response.body).to include(s_('Pagination|Next')) + expect(response.body).to include(s_('Pagination|Last')) + end + end + end + end +end diff --git a/spec/helpers/nav/new_dropdown_helper_spec.rb b/spec/helpers/nav/new_dropdown_helper_spec.rb new file mode 100644 index 00000000000..dd860ce3180 --- /dev/null +++ b/spec/helpers/nav/new_dropdown_helper_spec.rb @@ -0,0 +1,320 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Nav::NewDropdownHelper do + describe '#new_dropdown_view_model' do + let_it_be(:user) { build_stubbed(:user) } + + let(:current_user) { user } + let(:current_project) { nil } + let(:current_group) { nil } + + let(:with_can_create_project) { false } + let(:with_can_create_group) { false } + let(:with_can_create_snippet) { false } + let(:with_new_repo_experiment) { :control } + let(:with_invite_members_experiment) { false } + let(:with_invite_members_experiment_enabled) { false } + + let(:subject) { helper.new_dropdown_view_model(project: current_project, group: current_group) } + + def expected_menu_section(title:, menu_item:) + [ + { + title: title, + menu_items: [menu_item] + } + ] + end + + before do + stub_experiments(new_repo: with_new_repo_experiment) + allow(::Gitlab::Experimentation).to receive(:active?).with(:invite_members_new_dropdown) { with_invite_members_experiment } + allow(helper).to receive(:experiment_enabled?).with(:invite_members_new_dropdown) { with_invite_members_experiment_enabled } + allow(helper).to receive(:tracking_label) { 'test_tracking_label' } + allow(helper).to receive(:experiment_tracking_category_and_group) { |x| x } + + allow(helper).to receive(:current_user) { current_user } + allow(helper).to receive(:can?) { false } + + allow(user).to receive(:can_create_project?) { with_can_create_project } + allow(user).to receive(:can_create_group?) { with_can_create_group } + allow(user).to receive(:can?).with(:create_snippet) { with_can_create_snippet } + end + + shared_examples 'new repo experiment shared example' do |title| + let(:with_new_repo_experiment) { :candidate } + + it 'has experiment project title' do + expect(subject[:menu_sections]).to match( + expected_menu_section( + title: title, + menu_item: a_hash_including(title: 'New project/repository') + ) + ) + end + end + + shared_examples 'invite member link shared example' do + it 'shows invite member link' do + expect(subject[:menu_sections]).to eq( + expected_menu_section( + title: expected_title, + menu_item: ::Gitlab::Nav::TopNavMenuItem.build( + id: 'invite', + title: 'Invite members', + href: expected_href, + data: { + track_event: 'click_link', + track_label: 'test_tracking_label', + track_property: :invite_members_new_dropdown + } + ) + ) + ) + end + + context 'with experiment enabled' do + let(:with_invite_members_experiment_enabled) { true } + + it 'shows emoji with invite member link' do + expect(subject[:menu_sections]).to match( + expected_menu_section( + title: expected_title, + menu_item: a_hash_including( + emoji: 'shaking_hands' + ) + ) + ) + end + end + end + + it 'has title' do + expect(subject[:title]).to eq('New...') + end + + context 'when current_user is nil (anonymous)' do + let(:current_user) { nil } + + it 'is nil' do + expect(subject).to be_nil + end + end + + context 'when group and project are nil' do + it 'has no menu sections' do + expect(subject[:menu_sections]).to eq([]) + end + + context 'when can create project' do + let(:with_can_create_project) { true } + + it 'has project menu item' do + expect(subject[:menu_sections]).to eq( + expected_menu_section( + title: 'GitLab', + menu_item: ::Gitlab::Nav::TopNavMenuItem.build( + id: 'general_new_project', + title: 'New project', + href: '/projects/new', + data: { track_experiment: 'new_repo', track_event: 'click_link_new_project', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_project_link' } + ) + ) + ) + end + + it_behaves_like 'new repo experiment shared example', 'GitLab' + end + + context 'when can create group' do + let(:with_can_create_group) { true } + + it 'has group menu item' do + expect(subject[:menu_sections]).to eq( + expected_menu_section( + title: 'GitLab', + menu_item: ::Gitlab::Nav::TopNavMenuItem.build( + id: 'general_new_group', + title: 'New group', + href: '/groups/new', + data: { track_event: 'click_link_new_group', track_label: 'plus_menu_dropdown' } + ) + ) + ) + end + end + + context 'when can create snippet' do + let(:with_can_create_snippet) { true } + + it 'has new snippet menu item' do + expect(subject[:menu_sections]).to eq( + expected_menu_section( + title: 'GitLab', + menu_item: ::Gitlab::Nav::TopNavMenuItem.build( + id: 'general_new_snippet', + title: 'New snippet', + href: '/-/snippets/new', + data: { track_event: 'click_link_new_snippet_parent', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_snippet_link' } + ) + ) + ) + end + end + end + + context 'with persisted group' do + let_it_be(:group) { build_stubbed(:group) } + + let(:current_group) { group } + let(:with_can_create_projects_in_group) { false } + let(:with_can_create_subgroup_in_group) { false } + let(:with_can_admin_in_group) { false } + + before do + allow(group).to receive(:persisted?) { true } + allow(helper).to receive(:can?).with(current_user, :create_projects, group) { with_can_create_projects_in_group } + allow(helper).to receive(:can?).with(current_user, :create_subgroup, group) { with_can_create_subgroup_in_group } + allow(helper).to receive(:can?).with(current_user, :admin_group_member, group) { with_can_admin_in_group } + end + + it 'has no menu sections' do + expect(subject[:menu_sections]).to eq([]) + end + + context 'when can create projects in group' do + let(:with_can_create_projects_in_group) { true } + + it 'has new project menu item' do + expect(subject[:menu_sections]).to eq( + expected_menu_section( + title: 'This group', + menu_item: ::Gitlab::Nav::TopNavMenuItem.build( + id: 'new_project', + title: 'New project', + href: "/projects/new?namespace_id=#{group.id}", + data: { track_experiment: 'new_repo', track_event: 'click_link_new_project_group', track_label: 'plus_menu_dropdown' } + ) + ) + ) + end + + it_behaves_like 'new repo experiment shared example', 'This group' + end + + context 'when can create subgroup' do + let(:with_can_create_subgroup_in_group) { true } + + it 'has new subgroup menu item' do + expect(subject[:menu_sections]).to eq( + expected_menu_section( + title: 'This group', + menu_item: ::Gitlab::Nav::TopNavMenuItem.build( + id: 'new_subgroup', + title: 'New subgroup', + href: "/groups/new?parent_id=#{group.id}", + data: { track_event: 'click_link_new_subgroup', track_label: 'plus_menu_dropdown' } + ) + ) + ) + end + end + + context 'when can invite members' do + let(:with_can_admin_in_group) { true } + let(:with_invite_members_experiment) { true } + let(:expected_title) { 'This group' } + let(:expected_href) { "/groups/#{group.full_path}/-/group_members" } + + it_behaves_like 'invite member link shared example' + end + end + + context 'with persisted project' do + let_it_be(:project) { build_stubbed(:project) } + let_it_be(:merge_project) { build_stubbed(:project) } + + let(:current_project) { project } + let(:with_show_new_issue_link) { false } + let(:with_merge_project) { nil } + let(:with_can_create_snippet_in_project) { false } + let(:with_can_import_members) { false } + + before do + allow(helper).to receive(:show_new_issue_link?).with(project) { with_show_new_issue_link } + allow(helper).to receive(:merge_request_source_project_for_project).with(project) { with_merge_project } + allow(helper).to receive(:can?).with(user, :create_snippet, project) { with_can_create_snippet_in_project } + allow(helper).to receive(:can_import_members?) { with_can_import_members } + end + + it 'has no menu sections' do + expect(subject[:menu_sections]).to eq([]) + end + + context 'with show_new_issue_link?' do + let(:with_show_new_issue_link) { true } + + it 'shows new issue menu item' do + expect(subject[:menu_sections]).to eq( + expected_menu_section( + title: 'This project', + menu_item: ::Gitlab::Nav::TopNavMenuItem.build( + id: 'new_issue', + title: 'New issue', + href: "/#{project.path_with_namespace}/-/issues/new", + data: { track_event: 'click_link_new_issue', track_label: 'plus_menu_dropdown', qa_selector: 'new_issue_link' } + ) + ) + ) + end + end + + context 'with merge project' do + let(:with_merge_project) { merge_project } + + it 'shows merge project' do + expect(subject[:menu_sections]).to eq( + expected_menu_section( + title: 'This project', + menu_item: ::Gitlab::Nav::TopNavMenuItem.build( + id: 'new_mr', + title: 'New merge request', + href: "/#{merge_project.path_with_namespace}/-/merge_requests/new", + data: { track_event: 'click_link_new_mr', track_label: 'plus_menu_dropdown' } + ) + ) + ) + end + end + + context 'when can create snippet' do + let(:with_can_create_snippet_in_project) { true } + + it 'shows new snippet' do + expect(subject[:menu_sections]).to eq( + expected_menu_section( + title: 'This project', + menu_item: ::Gitlab::Nav::TopNavMenuItem.build( + id: 'new_snippet', + title: 'New snippet', + href: "/#{project.path_with_namespace}/-/snippets/new", + data: { track_event: 'click_link_new_snippet_project', track_label: 'plus_menu_dropdown' } + ) + ) + ) + end + end + + context 'when invite members experiment' do + let(:with_invite_members_experiment) { true } + let(:with_can_import_members) { true } + let(:expected_title) { 'This project' } + let(:expected_href) { "/#{project.path_with_namespace}/-/project_members" } + + it_behaves_like 'invite member link shared example' + end + end + end +end diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb index 5c9e1e82b01..d87c751c62f 100644 --- a/spec/helpers/nav/top_nav_helper_spec.rb +++ b/spec/helpers/nav/top_nav_helper_spec.rb @@ -5,11 +5,17 @@ require 'spec_helper' RSpec.describe Nav::TopNavHelper do include ActionView::Helpers::UrlHelper - describe '#top_nav_view_model' do - let_it_be(:user) { build_stubbed(:user) } - let_it_be(:admin) { build_stubbed(:user, :admin) } + let_it_be(:user) { build_stubbed(:user) } + let_it_be(:admin) { build_stubbed(:user, :admin) } + let_it_be(:external_user) { build_stubbed(:user, :external, can_create_group: false) } + + let(:current_user) { nil } + + before do + allow(helper).to receive(:current_user) { current_user } + end - let(:current_user) { nil } + describe '#top_nav_view_model' do let(:current_project) { nil } let(:current_group) { nil } let(:with_current_settings_admin_mode) { false } @@ -26,7 +32,6 @@ RSpec.describe Nav::TopNavHelper do let(:active_title) { 'Menu' } before do - allow(helper).to receive(:current_user) { current_user } allow(Gitlab::CurrentSettings).to receive(:admin_mode) { with_current_settings_admin_mode } allow(helper).to receive(:header_link?).with(:admin_mode) { with_header_link_admin_mode } allow(Gitlab::Sherlock).to receive(:enabled?) { with_sherlock_enabled } @@ -48,30 +53,73 @@ RSpec.describe Nav::TopNavHelper do context 'when current_user is nil (anonymous)' do it 'has expected :primary' do - expected_projects_item = ::Gitlab::Nav::TopNavMenuItem.build( - href: '/explore', - icon: 'project', - id: 'project', - title: 'Projects' - ) - expected_groups_item = ::Gitlab::Nav::TopNavMenuItem.build( - href: '/explore/groups', - icon: 'group', - id: 'groups', - title: 'Groups' - ) - expected_snippets_item = ::Gitlab::Nav::TopNavMenuItem.build( - href: '/explore/snippets', - icon: 'snippet', - id: 'snippets', - title: 'Snippets' - ) - expect(subject[:primary]) - .to eq([ - expected_projects_item, - expected_groups_item, - expected_snippets_item - ]) + expected_primary = [ + ::Gitlab::Nav::TopNavMenuItem.build( + href: '/explore', + icon: 'project', + id: 'project', + title: 'Projects' + ), + ::Gitlab::Nav::TopNavMenuItem.build( + href: '/explore/groups', + icon: 'group', + id: 'groups', + title: 'Groups' + ), + ::Gitlab::Nav::TopNavMenuItem.build( + href: '/explore/snippets', + icon: 'snippet', + id: 'snippets', + title: 'Snippets' + ) + ] + expect(subject[:primary]).to eq(expected_primary) + end + + it 'has expected :shortcuts' do + expected_shortcuts = [ + ::Gitlab::Nav::TopNavMenuItem.build( + href: '/explore', + id: 'project-shortcut', + title: 'Projects', + css_class: 'dashboard-shortcuts-projects' + ), + ::Gitlab::Nav::TopNavMenuItem.build( + href: '/explore/groups', + id: 'groups-shortcut', + title: 'Groups', + css_class: 'dashboard-shortcuts-groups' + ), + ::Gitlab::Nav::TopNavMenuItem.build( + href: '/explore/snippets', + id: 'snippets-shortcut', + title: 'Snippets', + css_class: 'dashboard-shortcuts-snippets' + ) + ] + expect(subject[:shortcuts]).to eq(expected_shortcuts) + end + + it 'has expected :secondary' do + expected_secondary = [ + ::Gitlab::Nav::TopNavMenuItem.build( + href: '/help', + id: 'help', + title: 'Help', + icon: 'question-o' + ) + ] + expect(subject[:secondary]).to eq(expected_secondary) + end + + context 'with current nav as project' do + before do + helper.nav('project') + end + + it 'has expected :active' do + expect(subject[:primary].detect { |entry| entry[:id] == 'project' }[:active]).to eq(true) + end end end @@ -82,6 +130,7 @@ RSpec.describe Nav::TopNavHelper do expect(subject).to eq({ activeTitle: active_title, primary: [], secondary: [], + shortcuts: [], views: {} }) end @@ -105,6 +154,16 @@ RSpec.describe Nav::TopNavHelper do expect(subject[:primary]).to eq([expected_primary]) end + it 'has expected :shortcuts' do + expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build( + id: 'project-shortcut', + title: 'Projects', + href: '/dashboard/projects', + css_class: 'dashboard-shortcuts-projects' + ) + expect(subject[:shortcuts]).to eq([expected_shortcuts]) + end + context 'projects' do it 'has expected :currentUserName' do expect(projects_view[:currentUserName]).to eq(current_user.username) @@ -146,6 +205,16 @@ RSpec.describe Nav::TopNavHelper do expect(projects_view[:linksSecondary]).to eq(expected_links_secondary) end + context 'with current nav as project' do + before do + helper.nav('project') + end + + it 'has expected :active' do + expect(subject[:primary].detect { |entry| entry[:id] == 'project' }[:active]).to eq(true) + end + end + context 'with persisted project' do let_it_be(:project) { build_stubbed(:project) } @@ -191,6 +260,16 @@ RSpec.describe Nav::TopNavHelper do expect(subject[:primary]).to eq([expected_primary]) end + it 'has expected :shortcuts' do + expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build( + id: 'groups-shortcut', + title: 'Groups', + href: '/dashboard/groups', + css_class: 'dashboard-shortcuts-groups' + ) + expect(subject[:shortcuts]).to eq([expected_shortcuts]) + end + context 'groups' do it 'has expected :currentUserName' do expect(groups_view[:currentUserName]).to eq(current_user.username) @@ -219,7 +298,7 @@ RSpec.describe Nav::TopNavHelper do it 'has expected :linksSecondary' do expected_links_secondary = [ ::Gitlab::Nav::TopNavMenuItem.build( - href: '/groups/new#create-group-pane', + href: '/groups/new', id: 'create', title: 'Create group' ) @@ -227,6 +306,24 @@ RSpec.describe Nav::TopNavHelper do expect(groups_view[:linksSecondary]).to eq(expected_links_secondary) end + context 'with external user' do + let(:current_user) { external_user } + + it 'does not have create group link' do + expect(groups_view[:linksSecondary]).to eq([]) + end + end + + context 'with current nav as group' do + before do + helper.nav('group') + end + + it 'has expected :active' do + expect(subject[:primary].detect { |entry| entry[:id] == 'groups' }[:active]).to eq(true) + end + end + context 'with persisted group' do let_it_be(:group) { build_stubbed(:group) } @@ -268,6 +365,16 @@ RSpec.describe Nav::TopNavHelper do ) expect(subject[:primary]).to eq([expected_primary]) end + + it 'has expected :shortcuts' do + expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build( + id: 'milestones-shortcut', + title: 'Milestones', + href: '/dashboard/milestones', + css_class: 'dashboard-shortcuts-milestones' + ) + expect(subject[:shortcuts]).to eq([expected_shortcuts]) + end end context 'with snippets' do @@ -285,6 +392,16 @@ RSpec.describe Nav::TopNavHelper do ) expect(subject[:primary]).to eq([expected_primary]) end + + it 'has expected :shortcuts' do + expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build( + id: 'snippets-shortcut', + title: 'Snippets', + href: '/dashboard/snippets', + css_class: 'dashboard-shortcuts-snippets' + ) + expect(subject[:shortcuts]).to eq([expected_shortcuts]) + end end context 'with activity' do @@ -302,6 +419,16 @@ RSpec.describe Nav::TopNavHelper do ) expect(subject[:primary]).to eq([expected_primary]) end + + it 'has expected :shortcuts' do + expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build( + id: 'activity-shortcut', + title: 'Activity', + href: '/dashboard/activity', + css_class: 'dashboard-shortcuts-activity' + ) + expect(subject[:shortcuts]).to eq([expected_shortcuts]) + end end context 'when sherlock is enabled' do @@ -352,7 +479,7 @@ RSpec.describe Nav::TopNavHelper do title: 'Leave Admin Mode', icon: 'lock-open', href: '/admin/session/destroy', - method: :post + data: { method: 'post' } ) expect(subject[:secondary].last).to eq(expected_leave_admin_mode_item) end @@ -373,4 +500,50 @@ RSpec.describe Nav::TopNavHelper do end end end + + describe '#top_nav_responsive_view_model' do + let_it_be(:project) { create(:project) } + let_it_be(:group) { create(:group) } + + let(:with_search) { false } + let(:with_new_view_model) { nil } + + let(:subject) { helper.top_nav_responsive_view_model(project: project, group: group) } + + before do + allow(helper).to receive(:header_link?).with(:search) { with_search } + allow(helper).to receive(:new_dropdown_view_model).with(project: project, group: group) { with_new_view_model } + end + + it 'has nil new subview' do + expect(subject[:views][:new]).to be_nil + end + + it 'has nil search subview' do + expect(subject[:views][:search]).to be_nil + end + + context 'with search' do + let(:with_search) { true } + + it 'has search subview' do + expect(subject[:views][:search]).to eq( + ::Gitlab::Nav::TopNavMenuItem.build( + id: 'search', + title: 'Search', + icon: 'search', + href: search_path + ) + ) + end + end + + context 'with new' do + let(:with_new_view_model) { { id: 'test-new-view-model' } } + + it 'has new subview' do + expect(subject[:views][:new]).to eq({ id: 'test-new-view-model' }) + end + end + end end diff --git a/spec/helpers/notify_helper_spec.rb b/spec/helpers/notify_helper_spec.rb index eb0f796038c..e2a7a212b1b 100644 --- a/spec/helpers/notify_helper_spec.rb +++ b/spec/helpers/notify_helper_spec.rb @@ -28,27 +28,12 @@ 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/ + build(:project, description: nil) | /Projects are/ + build(:group, description: nil) | /Groups assemble/ + build(:project, description: '_description_') | '_description_' + build(:group, description: '_description_') | '_description_' end with_them do @@ -56,6 +41,15 @@ RSpec.describe NotifyHelper do expect(helper.invited_to_description(source)).to match description end end + + it 'truncates long descriptions', :aggregate_failures do + description = '_description_ ' * 30 + project = build(:project, description: description) + + result = helper.invited_to_description(project) + expect(result).not_to match description + expect(result.length).to be <= 200 + end end def reference_link(entity, url) diff --git a/spec/helpers/operations_helper_spec.rb b/spec/helpers/operations_helper_spec.rb index 5b0ce00063f..e1bd477bc75 100644 --- a/spec/helpers/operations_helper_spec.rb +++ b/spec/helpers/operations_helper_spec.rb @@ -40,7 +40,14 @@ RSpec.describe OperationsHelper do 'prometheus_url' => notify_project_prometheus_alerts_url(project, format: :json), 'disabled' => 'false', 'project_path' => project.full_path, - 'multi_integrations' => 'false' + 'multi_integrations' => 'false', + 'templates' => '[]', + 'create_issue' => 'false', + 'issue_template_key' => '', + 'send_email' => 'false', + 'auto_close_incident' => 'true', + 'operations_settings_endpoint' => project_settings_operations_path(project), + 'pagerduty_reset_key_path' => reset_pagerduty_token_project_settings_operations_path(project) ) end end @@ -106,9 +113,7 @@ RSpec.describe OperationsHelper do create( :project_incident_management_setting, project: project, - issue_template_key: 'template-key', - pagerduty_active: true, - auto_close_incident: false + pagerduty_active: true ) end @@ -117,11 +122,6 @@ RSpec.describe OperationsHelper do it 'returns the correct set of data' do is_expected.to include( operations_settings_endpoint: project_settings_operations_path(project), - templates: '[]', - create_issue: 'false', - issue_template_key: 'template-key', - send_email: 'false', - auto_close_incident: 'false', pagerduty_active: 'true', pagerduty_token: operations_settings.pagerduty_token, pagerduty_webhook_url: project_incidents_integrations_pagerduty_url(project, token: operations_settings.pagerduty_token), diff --git a/spec/helpers/packages_helper_spec.rb b/spec/helpers/packages_helper_spec.rb index dacd386d01c..93d32cb8418 100644 --- a/spec/helpers/packages_helper_spec.rb +++ b/spec/helpers/packages_helper_spec.rb @@ -3,11 +3,13 @@ require 'spec_helper' RSpec.describe PackagesHelper do + using RSpec::Parameterized::TableSyntax + + let_it_be_with_reload(:project) { create(:project) } let_it_be(:base_url) { "#{Gitlab.config.gitlab.url}/api/v4/" } - let_it_be(:project) { create(:project) } - describe 'package_registry_instance_url' do - it 'returns conant instance url when registry_type is conant' do + describe '#package_registry_instance_url' do + it 'returns conan instance url when registry_type is conant' do url = helper.package_registry_instance_url(:conan) expect(url).to eq("#{base_url}packages/conan") @@ -20,7 +22,7 @@ RSpec.describe PackagesHelper do end end - describe 'package_registry_project_url' do + describe '#package_registry_project_url' do it 'returns maven registry url when registry_type is not provided' do url = helper.package_registry_project_url(1) @@ -34,7 +36,7 @@ RSpec.describe PackagesHelper do end end - describe 'pypi_registry_url' do + describe '#pypi_registry_url' do let_it_be(:base_url_with_token) { base_url.sub('://', '://__token__:<your_personal_token>@') } it 'returns the pypi registry url' do @@ -44,7 +46,7 @@ RSpec.describe PackagesHelper do end end - describe 'composer_registry_url' do + describe '#composer_registry_url' do it 'return the composer registry url' do url = helper.composer_registry_url(1) @@ -52,7 +54,7 @@ RSpec.describe PackagesHelper do end end - describe 'composer_config_repository_name' do + describe '#composer_config_repository_name' do let(:host) { Gitlab.config.gitlab.host } let(:group_id) { 1 } @@ -62,4 +64,157 @@ RSpec.describe PackagesHelper do expect(id).to eq("#{host}/#{group_id}") end end + + describe '#show_cleanup_policy_on_alert' do + let_it_be_with_reload(:container_repository) { create(:container_repository) } + + subject { helper.show_cleanup_policy_on_alert(project.reload) } + + where(:com, :config_registry, :project_registry, :historic_entries, :historic_entry, :nil_policy, :container_repositories_exist, :expected_result) do + false | false | false | false | false | false | false | false + false | false | false | false | false | false | true | false + false | false | false | false | false | true | false | false + false | false | false | false | false | true | true | false + false | false | false | false | true | false | false | false + false | false | false | false | true | false | true | false + false | false | false | false | true | true | false | false + false | false | false | false | true | true | true | false + false | false | false | true | false | false | false | false + false | false | false | true | false | false | true | false + false | false | false | true | false | true | false | false + false | false | false | true | false | true | true | false + false | false | false | true | true | false | false | false + false | false | false | true | true | false | true | false + false | false | false | true | true | true | false | false + false | false | false | true | true | true | true | false + false | false | true | false | false | false | false | false + false | false | true | false | false | false | true | false + false | false | true | false | false | true | false | false + false | false | true | false | false | true | true | false + false | false | true | false | true | false | false | false + false | false | true | false | true | false | true | false + false | false | true | false | true | true | false | false + false | false | true | false | true | true | true | false + false | false | true | true | false | false | false | false + false | false | true | true | false | false | true | false + false | false | true | true | false | true | false | false + false | false | true | true | false | true | true | false + false | false | true | true | true | false | false | false + false | false | true | true | true | false | true | false + false | false | true | true | true | true | false | false + false | false | true | true | true | true | true | false + false | true | false | false | false | false | false | false + false | true | false | false | false | false | true | false + false | true | false | false | false | true | false | false + false | true | false | false | false | true | true | false + false | true | false | false | true | false | false | false + false | true | false | false | true | false | true | false + false | true | false | false | true | true | false | false + false | true | false | false | true | true | true | false + false | true | false | true | false | false | false | false + false | true | false | true | false | false | true | false + false | true | false | true | false | true | false | false + false | true | false | true | false | true | true | false + false | true | false | true | true | false | false | false + false | true | false | true | true | false | true | false + false | true | false | true | true | true | false | false + false | true | false | true | true | true | true | false + false | true | true | false | false | false | false | false + false | true | true | false | false | false | true | false + false | true | true | false | false | true | false | false + false | true | true | false | false | true | true | false + false | true | true | false | true | false | false | false + false | true | true | false | true | false | true | false + false | true | true | false | true | true | false | false + false | true | true | false | true | true | true | false + false | true | true | true | false | false | false | false + false | true | true | true | false | false | true | false + false | true | true | true | false | true | false | false + false | true | true | true | false | true | true | false + false | true | true | true | true | false | false | false + false | true | true | true | true | false | true | false + false | true | true | true | true | true | false | false + false | true | true | true | true | true | true | false + true | false | false | false | false | false | false | false + true | false | false | false | false | false | true | false + true | false | false | false | false | true | false | false + true | false | false | false | false | true | true | false + true | false | false | false | true | false | false | false + true | false | false | false | true | false | true | false + true | false | false | false | true | true | false | false + true | false | false | false | true | true | true | false + true | false | false | true | false | false | false | false + true | false | false | true | false | false | true | false + true | false | false | true | false | true | false | false + true | false | false | true | false | true | true | false + true | false | false | true | true | false | false | false + true | false | false | true | true | false | true | false + true | false | false | true | true | true | false | false + true | false | false | true | true | true | true | false + true | false | true | false | false | false | false | false + true | false | true | false | false | false | true | false + true | false | true | false | false | true | false | false + true | false | true | false | false | true | true | false + true | false | true | false | true | false | false | false + true | false | true | false | true | false | true | false + true | false | true | false | true | true | false | false + true | false | true | false | true | true | true | false + true | false | true | true | false | false | false | false + true | false | true | true | false | false | true | false + true | false | true | true | false | true | false | false + true | false | true | true | false | true | true | false + true | false | true | true | true | false | false | false + true | false | true | true | true | false | true | false + true | false | true | true | true | true | false | false + true | false | true | true | true | true | true | false + true | true | false | false | false | false | false | false + true | true | false | false | false | false | true | false + true | true | false | false | false | true | false | false + true | true | false | false | false | true | true | false + true | true | false | false | true | false | false | false + true | true | false | false | true | false | true | false + true | true | false | false | true | true | false | false + true | true | false | false | true | true | true | false + true | true | false | true | false | false | false | false + true | true | false | true | false | false | true | false + true | true | false | true | false | true | false | false + true | true | false | true | false | true | true | false + true | true | false | true | true | false | false | false + true | true | false | true | true | false | true | false + true | true | false | true | true | true | false | false + true | true | false | true | true | true | true | false + true | true | true | false | false | false | false | false + true | true | true | false | false | false | true | false + true | true | true | false | false | true | false | false + true | true | true | false | false | true | true | false + true | true | true | false | true | false | false | false + true | true | true | false | true | false | true | false + true | true | true | false | true | true | false | false + true | true | true | false | true | true | true | true + true | true | true | true | false | false | false | false + true | true | true | true | false | false | true | false + true | true | true | true | false | true | false | false + true | true | true | true | false | true | true | false + true | true | true | true | true | false | false | false + true | true | true | true | true | false | true | false + true | true | true | true | true | true | false | false + true | true | true | true | true | true | true | false + end + + with_them do + before do + allow(Gitlab).to receive(:com?).and_return(com) + stub_config(registry: { enabled: config_registry }) + allow(project).to receive(:container_registry_enabled).and_return(project_registry) + stub_application_setting(container_expiration_policies_enable_historic_entries: historic_entries) + stub_feature_flags(container_expiration_policies_historic_entry: false) + stub_feature_flags(container_expiration_policies_historic_entry: project) if historic_entry + + project.container_expiration_policy.destroy! if nil_policy + container_repository.update!(project_id: project.id) if container_repositories_exist + end + + it { is_expected.to eq(expected_result) } + end + end end diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index 6be6d3670d4..ad2f142e3ff 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -143,4 +143,41 @@ RSpec.describe PreferencesHelper do .and_return(double('user', messages)) end end + + describe '#integration_views' do + let(:gitpod_url) { 'http://gitpod.test' } + + before do + allow(Gitlab::CurrentSettings).to receive(:gitpod_enabled).and_return(gitpod_enabled) + allow(Gitlab::CurrentSettings).to receive(:gitpod_url).and_return(gitpod_url) + end + + context 'when Gitpod is not enabled' do + let(:gitpod_enabled) { false } + + it 'does not include Gitpod integration' do + expect(helper.integration_views).to be_empty + end + end + + context 'when Gitpod is enabled' do + let(:gitpod_enabled) { true } + + it 'includes Gitpod integration' do + expect(helper.integration_views[0][:name]).to eq 'gitpod' + end + + it 'returns the Gitpod url configured in settings' do + expect(helper.integration_views[0][:message_url]).to eq gitpod_url + end + + context 'when Gitpod url is not set' do + let(:gitpod_url) { '' } + + it 'returns the Gitpod default url' do + expect(helper.integration_views[0][:message_url]).to eq 'https://gitpod.io/' + end + end + end + end end diff --git a/spec/helpers/projects/alert_management_helper_spec.rb b/spec/helpers/projects/alert_management_helper_spec.rb index 6f66a93b9ec..9895d06f93a 100644 --- a/spec/helpers/projects/alert_management_helper_spec.rb +++ b/spec/helpers/projects/alert_management_helper_spec.rb @@ -61,7 +61,7 @@ RSpec.describe Projects::AlertManagementHelper do let(:cluster) { create(:cluster, projects: [project]) } it 'has managed prometheus' do - create(:clusters_applications_prometheus, :installed, cluster: cluster) + create(:clusters_integrations_prometheus, cluster: cluster) expect(data).to include( 'has-managed-prometheus' => 'true' diff --git a/spec/helpers/projects/project_members_helper_spec.rb b/spec/helpers/projects/project_members_helper_spec.rb index 90035f3e1c5..b180b5ec06f 100644 --- a/spec/helpers/projects/project_members_helper_spec.rb +++ b/spec/helpers/projects/project_members_helper_spec.rb @@ -147,16 +147,27 @@ RSpec.describe Projects::ProjectMembersHelper do end describe 'project members' do - let_it_be(:project_members) { create_list(:project_member, 2, project: project) } + 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) } - let(:collection) { project_members } - let(:presented_members) { present_members(collection) } + let(:members_collection) { members } - describe '#project_members_list_data_json' do + describe '#project_members_app_data_json' do let(:allow_admin_project) { true } - let(:pagination) { {} } - subject { Gitlab::Json.parse(helper.project_members_list_data_json(project, presented_members, pagination)) } + subject do + Gitlab::Json.parse( + 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) + ) + ) + end before do allow(helper).to receive(:project_project_member_path).with(project, ':id').and_return('/foo-bar/-/project_members/:id') @@ -164,7 +175,6 @@ RSpec.describe Projects::ProjectMembersHelper do it 'returns expected json' do expected = { - member_path: '/foo-bar/-/project_members/:id', source_id: project.id, can_manage_members: true }.as_json @@ -172,8 +182,12 @@ RSpec.describe Projects::ProjectMembersHelper do expect(subject).to include(expected) end - it 'returns `members` property that matches json schema' do - expect(subject['members'].to_json).to match_schema('members') + it 'sets `members` property that matches json schema' do + expect(subject['user']['members'].to_json).to match_schema('members') + end + + it 'sets `member_path` property' do + expect(subject['user']['member_path']).to eq('/foo-bar/-/project_members/:id') end context 'when pagination is not available' do @@ -186,13 +200,12 @@ RSpec.describe Projects::ProjectMembersHelper do params: {} }.as_json - expect(subject['pagination']).to include(expected) + expect(subject['invite']['pagination']).to include(expected) end end context 'when pagination is available' do - let(:collection) { Kaminari.paginate_array(project_members).page(1).per(1) } - let(:pagination) { { param_name: :page, params: { search_groups: nil } } } + let(:members_collection) { Kaminari.paginate_array(members).page(1).per(1) } it 'sets `pagination` attribute to expected json' do expected = { @@ -203,45 +216,9 @@ RSpec.describe Projects::ProjectMembersHelper do params: { search_groups: nil } }.as_json - expect(subject['pagination']).to match(expected) + expect(subject['user']['pagination']).to match(expected) end 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_list_data_json' do - subject { Gitlab::Json.parse(helper.project_group_links_list_data_json(project, project_group_links)) } - - 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 json' do - expected = { - pagination: { - current_page: nil, - per_page: nil, - total_items: 1, - param_name: nil, - params: {} - }, - member_path: '/foo-bar/-/group_links/:id', - source_id: project.id, - can_manage_members: true - }.as_json - - expect(subject).to include(expected) - end - - it 'returns `members` property that matches json schema' do - expect(subject['members'].to_json).to match_schema('group_link/project_group_links') - end - end - end end diff --git a/spec/helpers/registrations_helper_spec.rb b/spec/helpers/registrations_helper_spec.rb index 00d0a0850cd..fa647548b3c 100644 --- a/spec/helpers/registrations_helper_spec.rb +++ b/spec/helpers/registrations_helper_spec.rb @@ -26,4 +26,10 @@ RSpec.describe RegistrationsHelper do it { is_expected.to eq(result) } end end + + describe '#signup_username_data_attributes' do + it 'has expected attributes' do + expect(helper.signup_username_data_attributes.keys).to include(:min_length, :min_length_message, :max_length, :max_length_message, :qa_selector) + end + end end diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb index 3dbaa655aeb..f68da45bb9a 100644 --- a/spec/helpers/user_callouts_helper_spec.rb +++ b/spec/helpers/user_callouts_helper_spec.rb @@ -61,26 +61,6 @@ RSpec.describe UserCalloutsHelper do end end - describe '.show_admin_integrations_moved?' do - subject { helper.show_admin_integrations_moved? } - - context 'when user has not dismissed' do - before do - allow(helper).to receive(:user_dismissed?).with(described_class::ADMIN_INTEGRATIONS_MOVED) { false } - end - - it { is_expected.to be true } - end - - context 'when user dismissed' do - before do - allow(helper).to receive(:user_dismissed?).with(described_class::ADMIN_INTEGRATIONS_MOVED) { true } - end - - it { is_expected.to be false } - end - end - describe '.show_service_templates_deprecated_callout?' do using RSpec::Parameterized::TableSyntax diff --git a/spec/helpers/webpack_helper_spec.rb b/spec/helpers/webpack_helper_spec.rb index f9386c99dc3..f9e2d265153 100644 --- a/spec/helpers/webpack_helper_spec.rb +++ b/spec/helpers/webpack_helper_spec.rb @@ -15,6 +15,7 @@ RSpec.describe WebpackHelper do describe '#webpack_preload_asset_tag' do before do allow(Gitlab::Webpack::Manifest).to receive(:asset_paths).and_return([asset_path]) + allow(helper).to receive(:content_security_policy_nonce).and_return('noncevalue') end it 'preloads the resource by default' do @@ -22,7 +23,7 @@ RSpec.describe WebpackHelper do output = helper.webpack_preload_asset_tag(source) - expect(output).to eq("<link rel=\"preload\" href=\"#{asset_path}\" as=\"script\" type=\"text/javascript\">") + expect(output).to eq("<link rel=\"preload\" href=\"#{asset_path}\" as=\"script\" type=\"text/javascript\" nonce=\"noncevalue\">") end it 'prefetches the resource if explicitly asked' do |