Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/helpers')
-rw-r--r--spec/helpers/admin/background_migrations_helper_spec.rb67
-rw-r--r--spec/helpers/application_settings_helper_spec.rb20
-rw-r--r--spec/helpers/commits_helper_spec.rb16
-rw-r--r--spec/helpers/environments_helper_spec.rb5
-rw-r--r--spec/helpers/events_helper_spec.rb7
-rw-r--r--spec/helpers/gitlab_script_tag_helper_spec.rb7
-rw-r--r--spec/helpers/groups/group_members_helper_spec.rb106
-rw-r--r--spec/helpers/invite_members_helper_spec.rb65
-rw-r--r--spec/helpers/issuables_description_templates_helper_spec.rb93
-rw-r--r--spec/helpers/issuables_helper_spec.rb14
-rw-r--r--spec/helpers/issues_helper_spec.rb6
-rw-r--r--spec/helpers/keyset_helper_spec.rb94
-rw-r--r--spec/helpers/nav/new_dropdown_helper_spec.rb320
-rw-r--r--spec/helpers/nav/top_nav_helper_spec.rb235
-rw-r--r--spec/helpers/notify_helper_spec.rb32
-rw-r--r--spec/helpers/operations_helper_spec.rb18
-rw-r--r--spec/helpers/packages_helper_spec.rb169
-rw-r--r--spec/helpers/preferences_helper_spec.rb37
-rw-r--r--spec/helpers/projects/alert_management_helper_spec.rb2
-rw-r--r--spec/helpers/projects/project_members_helper_spec.rb75
-rw-r--r--spec/helpers/registrations_helper_spec.rb6
-rw-r--r--spec/helpers/user_callouts_helper_spec.rb20
-rw-r--r--spec/helpers/webpack_helper_spec.rb3
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