summaryrefslogtreecommitdiff
path: root/spec/helpers
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 15:44:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 15:44:42 +0000
commit4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch)
tree5423a1c7516cffe36384133ade12572cf709398d /spec/helpers
parente570267f2f6b326480d284e0164a6464ba4081bc (diff)
downloadgitlab-ce-4555e1b21c365ed8303ffb7a3325d773c9b8bf31.tar.gz
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'spec/helpers')
-rw-r--r--spec/helpers/application_helper_spec.rb29
-rw-r--r--spec/helpers/auth_helper_spec.rb47
-rw-r--r--spec/helpers/avatars_helper_spec.rb31
-rw-r--r--spec/helpers/boards_helper_spec.rb39
-rw-r--r--spec/helpers/ci/pipeline_editor_helper_spec.rb64
-rw-r--r--spec/helpers/commits_helper_spec.rb54
-rw-r--r--spec/helpers/dev_ops_report_helper_spec.rb41
-rw-r--r--spec/helpers/environments_helper_spec.rb51
-rw-r--r--spec/helpers/gitlab_routing_helper_spec.rb25
-rw-r--r--spec/helpers/groups/group_members_helper_spec.rb108
-rw-r--r--spec/helpers/groups_helper_spec.rb285
-rw-r--r--spec/helpers/ide_helper_spec.rb30
-rw-r--r--spec/helpers/invite_members_helper_spec.rb107
-rw-r--r--spec/helpers/issuables_helper_spec.rb8
-rw-r--r--spec/helpers/issues_helper_spec.rb72
-rw-r--r--spec/helpers/learn_gitlab_helper_spec.rb66
-rw-r--r--spec/helpers/namespaces_helper_spec.rb28
-rw-r--r--spec/helpers/nav/top_nav_helper_spec.rb376
-rw-r--r--spec/helpers/nav_helper_spec.rb4
-rw-r--r--spec/helpers/page_layout_helper_spec.rb2
-rw-r--r--spec/helpers/preferences_helper_spec.rb14
-rw-r--r--spec/helpers/projects/alert_management_helper_spec.rb35
-rw-r--r--spec/helpers/projects/project_members_helper_spec.rb90
-rw-r--r--spec/helpers/projects_helper_spec.rb143
-rw-r--r--spec/helpers/registrations_helper_spec.rb29
-rw-r--r--spec/helpers/users_helper_spec.rb12
-rw-r--r--spec/helpers/webpack_helper_spec.rb36
-rw-r--r--spec/helpers/whats_new_helper_spec.rb57
28 files changed, 1413 insertions, 470 deletions
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index ae039c1a8b1..bf533ca7034 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -284,14 +284,29 @@ RSpec.describe ApplicationHelper do
end
describe '#autocomplete_data_sources' do
- let(:project) { create(:project) }
- let(:noteable_type) { Issue }
+ context 'group' do
+ let(:group) { create(:group) }
+ let(:noteable_type) { Issue }
+
+ it 'returns paths for autocomplete_sources_controller' do
+ sources = helper.autocomplete_data_sources(group, noteable_type)
+ expect(sources.keys).to include(:members, :issues, :mergeRequests, :labels, :milestones, :commands)
+ sources.keys.each do |key|
+ expect(sources[key]).not_to be_nil
+ end
+ end
+ end
+
+ context 'project' do
+ let(:project) { create(:project) }
+ let(:noteable_type) { Issue }
- it 'returns paths for autocomplete_sources_controller' do
- sources = helper.autocomplete_data_sources(project, noteable_type)
- expect(sources.keys).to match_array([:members, :issues, :mergeRequests, :labels, :milestones, :commands, :snippets])
- sources.keys.each do |key|
- expect(sources[key]).not_to be_nil
+ it 'returns paths for autocomplete_sources_controller' do
+ sources = helper.autocomplete_data_sources(project, noteable_type)
+ expect(sources.keys).to match_array([:members, :issues, :mergeRequests, :labels, :milestones, :commands, :snippets])
+ sources.keys.each do |key|
+ expect(sources[key]).not_to be_nil
+ end
end
end
end
diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb
index beffa4cf60e..c1c961c5cbb 100644
--- a/spec/helpers/auth_helper_spec.rb
+++ b/spec/helpers/auth_helper_spec.rb
@@ -77,8 +77,8 @@ RSpec.describe AuthHelper do
end
context 'all providers are enabled to sign in' do
- it 'returns all the enabled providers from settings' do
- expect(helper.enabled_button_based_providers).to include('twitter', 'github', 'google_oauth2', 'openid_connect')
+ it 'returns all the enabled providers from settings in expected order' do
+ expect(helper.enabled_button_based_providers).to match(%w[google_oauth2 github twitter openid_connect])
end
it 'puts google and github in the beginning' do
@@ -99,19 +99,19 @@ RSpec.describe AuthHelper do
end
end
- describe 'trial_enabled_button_based_providers' do
- it 'returns the intersection set of github & google_oauth2 with enabled providers' do
+ describe 'popular_enabled_button_based_providers' do
+ it 'returns the intersection set of popular & enabled providers', :aggregate_failures do
allow(helper).to receive(:enabled_button_based_providers) { %w(twitter github google_oauth2) }
- expect(helper.trial_enabled_button_based_providers).to eq(%w(github google_oauth2))
+ expect(helper.popular_enabled_button_based_providers).to eq(%w(github google_oauth2))
allow(helper).to receive(:enabled_button_based_providers) { %w(google_oauth2 bitbucket) }
- expect(helper.trial_enabled_button_based_providers).to eq(%w(google_oauth2))
+ expect(helper.popular_enabled_button_based_providers).to eq(%w(google_oauth2))
allow(helper).to receive(:enabled_button_based_providers) { %w(bitbucket) }
- expect(helper.trial_enabled_button_based_providers).to be_empty
+ expect(helper.popular_enabled_button_based_providers).to be_empty
end
end
@@ -313,4 +313,37 @@ RSpec.describe AuthHelper do
it { is_expected.to be_falsey }
end
end
+
+ describe '#auth_app_owner_text' do
+ shared_examples 'generates text with the correct info' do
+ it 'includes the name of the application owner' do
+ auth_app_owner_text = helper.auth_app_owner_text(owner)
+
+ expect(auth_app_owner_text).to include(owner.name)
+ expect(auth_app_owner_text).to include(path_to_owner)
+ end
+ end
+
+ context 'when owner is a user' do
+ let_it_be(:owner) { create(:user) }
+
+ let(:path_to_owner) { user_path(owner) }
+
+ it_behaves_like 'generates text with the correct info'
+ end
+
+ context 'when owner is a group' do
+ let_it_be(:owner) { create(:group) }
+
+ let(:path_to_owner) { user_path(owner) }
+
+ it_behaves_like 'generates text with the correct info'
+ end
+
+ context 'when the user is missing' do
+ it 'returns nil' do
+ expect(helper.auth_app_owner_text(nil)).to be(nil)
+ end
+ end
+ end
end
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index 120dbe7cb49..047a6ca0b7d 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe AvatarsHelper do
shared_examples 'resource with a default avatar' do |source_type|
it 'returns a default avatar div' do
expect(public_send("#{source_type}_icon", *helper_args))
- .to match(%r{<div class="identicon bg\d+">F</div>})
+ .to match(%r{<span class="identicon bg\d+">F</span>})
end
end
@@ -409,4 +409,33 @@ RSpec.describe AvatarsHelper do
end
end
end
+
+ describe '#avatar_without_link' do
+ let(:options) { { size: 32 } }
+
+ subject { helper.avatar_without_link(resource, options) }
+
+ context 'with users' do
+ let(:resource) { user }
+
+ it 'displays user avatar' do
+ is_expected.to eq tag(
+ :img,
+ alt: "#{user.name}'s avatar",
+ src: avatar_icon_for_user(user, 32),
+ data: { container: 'body' },
+ class: 'avatar s32 has-tooltip',
+ title: user.name
+ )
+ end
+ end
+
+ context 'with groups' do
+ let(:resource) { build_stubbed(:group, name: 'foo') }
+
+ it 'displays group avatar' do
+ is_expected.to match(%r{<span class="avatar identicon bg\d+ s32">F</span>})
+ end
+ end
+ end
end
diff --git a/spec/helpers/boards_helper_spec.rb b/spec/helpers/boards_helper_spec.rb
index 00cd44809c7..cb4b6915b20 100644
--- a/spec/helpers/boards_helper_spec.rb
+++ b/spec/helpers/boards_helper_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe BoardsHelper do
end
describe '#board_base_url' do
- context 'when project board' do
+ context 'when group board' do
it 'generates the correct url' do
assign(:board, group_board)
assign(:group, base_group)
@@ -55,6 +55,43 @@ RSpec.describe BoardsHelper do
end
end
+ describe '#current_board_namespace' do
+ context 'when group board' do
+ it 'returns the correct namespace' do
+ assign(:board, group_board)
+ assign(:group, base_group)
+
+ expect(helper.current_board_namespace).to be(base_group)
+ end
+ end
+
+ context 'project under group' do
+ context 'when project board' do
+ it 'returns the correct namespace' do
+ assign(:project, project)
+ assign(:board, project_board)
+
+ expect(helper.current_board_namespace).to be(project.parent)
+ end
+ end
+ end
+
+ context 'project under user namespace' do
+ let_it_be(:project_under_user) { create(:project, namespace: user.namespace) }
+
+ context 'when project board' do
+ let_it_be(:project_board) { create(:board, project: project_under_user) }
+
+ it 'returns the correct namespace' do
+ assign(:project, project_under_user)
+ assign(:board, project_board)
+
+ expect(helper.current_board_namespace).to be(user.namespace)
+ end
+ end
+ end
+ end
+
describe '#board_data' do
context 'project_board' do
before do
diff --git a/spec/helpers/ci/pipeline_editor_helper_spec.rb b/spec/helpers/ci/pipeline_editor_helper_spec.rb
index a08517d0c57..2287718db5a 100644
--- a/spec/helpers/ci/pipeline_editor_helper_spec.rb
+++ b/spec/helpers/ci/pipeline_editor_helper_spec.rb
@@ -36,20 +36,56 @@ RSpec.describe Ci::PipelineEditorHelper do
subject(:pipeline_editor_data) { helper.js_pipeline_editor_data(project) }
- it 'returns pipeline editor data' do
- expect(pipeline_editor_data).to eq({
- "ci-config-path": project.ci_config_path_or_default,
- "commit-sha" => project.commit.sha,
- "default-branch" => project.default_branch,
- "empty-state-illustration-path" => 'foo',
- "initial-branch-name": nil,
- "lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'),
- "new-merge-request-path" => '/mock/project/-/merge_requests/new',
- "project-path" => project.path,
- "project-full-path" => project.full_path,
- "project-namespace" => project.namespace.full_path,
- "yml-help-page-path" => help_page_path('ci/yaml/README')
- })
+ context 'with a project with commits' do
+ it 'returns pipeline editor data' do
+ expect(pipeline_editor_data).to eq({
+ "ci-config-path": project.ci_config_path_or_default,
+ "ci-examples-help-page-path" => help_page_path('ci/examples/README'),
+ "ci-help-page-path" => help_page_path('ci/README'),
+ "commit-sha" => project.commit.sha,
+ "default-branch" => project.default_branch,
+ "empty-state-illustration-path" => 'foo',
+ "initial-branch-name": nil,
+ "lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'),
+ "needs-help-page-path" => help_page_path('ci/yaml/README', anchor: 'needs'),
+ "new-merge-request-path" => '/mock/project/-/merge_requests/new',
+ "pipeline_etag" => graphql_etag_pipeline_sha_path(project.commit.sha),
+ "pipeline-page-path" => project_pipelines_path(project),
+ "project-path" => project.path,
+ "project-full-path" => project.full_path,
+ "project-namespace" => project.namespace.full_path,
+ "runner-help-page-path" => help_page_path('ci/runners/README'),
+ "total-branches" => project.repository.branches.length,
+ "yml-help-page-path" => help_page_path('ci/yaml/README')
+ })
+ end
+ end
+
+ context 'with an empty project' do
+ let(:project) { create(:project, :empty_repo) }
+
+ it 'returns pipeline editor data' do
+ expect(pipeline_editor_data).to eq({
+ "ci-config-path": project.ci_config_path_or_default,
+ "ci-examples-help-page-path" => help_page_path('ci/examples/README'),
+ "ci-help-page-path" => help_page_path('ci/README'),
+ "commit-sha" => '',
+ "default-branch" => project.default_branch,
+ "empty-state-illustration-path" => 'foo',
+ "initial-branch-name": nil,
+ "lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'),
+ "needs-help-page-path" => help_page_path('ci/yaml/README', anchor: 'needs'),
+ "new-merge-request-path" => '/mock/project/-/merge_requests/new',
+ "pipeline_etag" => '',
+ "pipeline-page-path" => project_pipelines_path(project),
+ "project-path" => project.path,
+ "project-full-path" => project.full_path,
+ "project-namespace" => project.namespace.full_path,
+ "runner-help-page-path" => help_page_path('ci/runners/README'),
+ "total-branches" => 0,
+ "yml-help-page-path" => help_page_path('ci/yaml/README')
+ })
+ end
end
end
end
diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb
index 86ed133e599..9a1ecb22edb 100644
--- a/spec/helpers/commits_helper_spec.rb
+++ b/spec/helpers/commits_helper_spec.rb
@@ -144,7 +144,7 @@ RSpec.describe CommitsHelper do
}
end
- subject { helper.conditionally_paginate_diff_files(diffs_collection, paginate: paginate) }
+ subject { helper.conditionally_paginate_diff_files(diffs_collection, paginate: paginate, per: Projects::CommitController::COMMIT_DIFFS_PER_PAGE) }
before do
allow(helper).to receive(:params).and_return(params)
@@ -168,15 +168,15 @@ RSpec.describe CommitsHelper do
let(:page) { 1 }
it "has 20 diffs" do
- expect(subject.size).to eq(75)
+ expect(subject.size).to eq(20)
end
end
- context "page 2" do
- let(:page) { 2 }
+ context "page 5" do
+ let(:page) { 5 }
- it "has the remaining 10 diffs" do
- expect(subject.size).to eq(10)
+ it "has the remaining 5 out of 85 diffs" do
+ expect(subject.size).to eq(5)
end
end
end
@@ -289,4 +289,46 @@ RSpec.describe CommitsHelper do
}
end
end
+
+ describe "#commit_partial_cache_key" do
+ subject(:cache_key) { helper.commit_partial_cache_key(commit, ref: ref, merge_request: merge_request, request: request) }
+
+ let(:commit) { create(:commit).present(current_user: user) }
+ let(:commit_status) { Gitlab::Ci::Status::Running.new(pipeline, user) }
+ let(:pipeline) { create(:ci_pipeline, :running) }
+ let(:user) { create(:user) }
+ let(:ref) { "master" }
+ let(:merge_request) { nil }
+ let(:request) { double(xhr?: true) }
+ let(:current_path) { "test" }
+
+ before do
+ expect(commit).to receive(:status_for).with(ref).and_return(commit_status)
+ assign(:path, current_path)
+ end
+
+ it { is_expected.to be_an(Array) }
+ it { is_expected.to include(commit) }
+ it { is_expected.to include(commit.author) }
+ it { is_expected.to include(ref) }
+
+ it do
+ is_expected.to include(
+ {
+ merge_request: merge_request,
+ pipeline_status: commit_status,
+ xhr: true,
+ controller: "commits",
+ path: current_path
+ }
+ )
+ end
+
+ describe "final cache key output" do
+ subject { ActiveSupport::Cache.expand_cache_key(cache_key) }
+
+ it { is_expected.to include(commit.cache_key) }
+ it { is_expected.to include(pipeline.cache_key) }
+ end
+ end
end
diff --git a/spec/helpers/dev_ops_report_helper_spec.rb b/spec/helpers/dev_ops_report_helper_spec.rb
new file mode 100644
index 00000000000..7e7a89a3039
--- /dev/null
+++ b/spec/helpers/dev_ops_report_helper_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DevOpsReportHelper do
+ subject { DevOpsReport::MetricPresenter.new(metric) }
+
+ let(:metric) { build(:dev_ops_report_metric, created_at: DateTime.new(2021, 4, 3, 2, 1, 0) ) }
+
+ describe '#devops_score_metrics' do
+ let(:devops_score_metrics) { helper.devops_score_metrics(subject) }
+
+ it { expect(devops_score_metrics[:averageScore]).to eq({ scoreLevel: { icon: "status-alert", label: "Moderate", variant: "warning" }, value: "55.9" } ) }
+
+ it { expect(devops_score_metrics[:cards].first).to eq({ leadInstance: "9.3", score: "13.3", scoreLevel: { label: "Low", variant: "muted" }, title: "Issues created per active user", usage: "1.2" } ) }
+ it { expect(devops_score_metrics[:cards].second).to eq({ leadInstance: "30.3", score: "92.7", scoreLevel: { label: "High", variant: "success" }, title: "Comments created per active user", usage: "28.1" } ) }
+ it { expect(devops_score_metrics[:cards].fourth).to eq({ leadInstance: "5.2", score: "62.4", scoreLevel: { label: "Moderate", variant: "neutral" }, title: "Boards created per active user", usage: "3.3" } ) }
+
+ it { expect(devops_score_metrics[:createdAt]).to eq("2021-04-03 02:01") }
+
+ describe 'with low average score' do
+ let(:low_metric) { double(average_percentage_score: 2, cards: subject.cards, created_at: subject.created_at) }
+ let(:devops_score_metrics) { helper.devops_score_metrics(low_metric) }
+
+ it { expect(devops_score_metrics[:averageScore]).to eq({ scoreLevel: { icon: "status-failed", label: "Low", variant: "danger" }, value: "2.0" } ) }
+ end
+
+ describe 'with high average score' do
+ let(:high_metric) { double(average_percentage_score: 82, cards: subject.cards, created_at: subject.created_at) }
+ let(:devops_score_metrics) { helper.devops_score_metrics(high_metric) }
+
+ it { expect(devops_score_metrics[:averageScore]).to eq({ scoreLevel: { icon: "status_success_solid", label: "High", variant: "success" }, value: "82.0" } ) }
+ end
+
+ describe 'with blank metrics' do
+ let(:devops_score_metrics) { helper.devops_score_metrics({}) }
+
+ it { expect(devops_score_metrics).to eq({}) }
+ end
+ end
+end
diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb
index d316f2b0a0a..89cb0f72277 100644
--- a/spec/helpers/environments_helper_spec.rb
+++ b/spec/helpers/environments_helper_spec.rb
@@ -45,7 +45,8 @@ RSpec.describe EnvironmentsHelper do
'custom_dashboard_base_path' => Gitlab::Metrics::Dashboard::RepoDashboardFinder::DASHBOARD_ROOT,
'operations_settings_path' => project_settings_operations_path(project),
'can_access_operations_settings' => 'true',
- 'panel_preview_endpoint' => project_metrics_dashboards_builder_path(project, format: :json)
+ 'panel_preview_endpoint' => project_metrics_dashboards_builder_path(project, format: :json),
+ 'has_managed_prometheus' => 'false'
)
end
@@ -120,6 +121,52 @@ RSpec.describe EnvironmentsHelper do
end
end
end
+
+ context 'has_managed_prometheus' do
+ context 'without prometheus service' do
+ it "doesn't have managed prometheus" do
+ expect(metrics_data).to include(
+ 'has_managed_prometheus' => 'false'
+ )
+ end
+ end
+
+ context 'with prometheus service' do
+ let_it_be(:prometheus_service) { create(:prometheus_service, project: project) }
+
+ context 'when manual prometheus service is active' do
+ it "doesn't have managed prometheus" do
+ prometheus_service.update!(manual_configuration: true)
+
+ expect(metrics_data).to include(
+ 'has_managed_prometheus' => 'false'
+ )
+ end
+ end
+
+ context 'when prometheus service is inactive' do
+ it "doesn't have managed prometheus" do
+ prometheus_service.update!(manual_configuration: false)
+
+ expect(metrics_data).to include(
+ 'has_managed_prometheus' => 'false'
+ )
+ end
+ end
+
+ context 'when a cluster prometheus is available' do
+ let(:cluster) { create(:cluster, projects: [project]) }
+
+ it 'has managed prometheus' do
+ create(:clusters_applications_prometheus, :installed, cluster: cluster)
+
+ expect(metrics_data).to include(
+ 'has_managed_prometheus' => 'true'
+ )
+ end
+ end
+ end
+ end
end
describe '#custom_metrics_available?' do
@@ -144,7 +191,7 @@ RSpec.describe EnvironmentsHelper do
it 'returns logs data' do
expected_data = {
"environment_name": environment.name,
- "environments_path": project_environments_path(project, format: :json),
+ "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'),
"clusters_path": project_clusters_path(project, format: :json)
diff --git a/spec/helpers/gitlab_routing_helper_spec.rb b/spec/helpers/gitlab_routing_helper_spec.rb
index 0df04d2a8a7..40faf994ad2 100644
--- a/spec/helpers/gitlab_routing_helper_spec.rb
+++ b/spec/helpers/gitlab_routing_helper_spec.rb
@@ -113,6 +113,24 @@ RSpec.describe GitlabRoutingHelper do
end
end
+ describe 'members helpers' do
+ describe '#source_members_url' do
+ it 'returns a url to the memberships page for a group membership' do
+ membership = build_stubbed(:group_member)
+ group_members_url = "http://test.host/groups/#{membership.source.full_path}/-/group_members"
+
+ expect(source_members_url(membership)).to eq(group_members_url)
+ end
+
+ it 'returns a url to the memberships page for a project membership' do
+ membership = build_stubbed(:project_member)
+ project_members_url = "http://test.host/#{membership.source.full_path}/-/project_members"
+
+ expect(source_members_url(membership)).to eq(project_members_url)
+ end
+ end
+ end
+
context 'artifacts' do
let_it_be(:project) { create(:project) }
let_it_be(:job) { create(:ci_build, project: project, name: 'test:job', artifacts_expire_at: 1.hour.from_now) }
@@ -335,7 +353,12 @@ RSpec.describe GitlabRoutingHelper do
context 'GraphQL ETag paths' do
context 'with pipelines' do
- let(:pipeline) { double(id: 5) }
+ let(:sha) { 'b08774cb1a11ecdc27a82c5f444a69ea7e038ede' }
+ let(:pipeline) { double(id: 5 ) }
+
+ it 'returns an ETag path for a pipeline sha' do
+ expect(graphql_etag_pipeline_sha_path(sha)).to eq('/api/graphql:pipelines/sha/b08774cb1a11ecdc27a82c5f444a69ea7e038ede')
+ end
it 'returns an ETag path for pipelines' do
expect(graphql_etag_pipeline_path(pipeline)).to eq('/api/graphql:pipelines/id/5')
diff --git a/spec/helpers/groups/group_members_helper_spec.rb b/spec/helpers/groups/group_members_helper_spec.rb
index 99efc7963e6..c3f1509fbc8 100644
--- a/spec/helpers/groups/group_members_helper_spec.rb
+++ b/spec/helpers/groups/group_members_helper_spec.rb
@@ -23,83 +23,119 @@ RSpec.describe Groups::GroupMembersHelper do
end
end
- describe '#group_group_links_data_json' do
- include_context 'group_group_link'
+ describe '#group_members_list_data_json' do
+ let(:group_members) { create_list(:group_member, 2, group: group, created_by: current_user) }
- it 'matches json schema' do
- json = helper.group_group_links_data_json(shared_group.shared_with_group_links)
+ let(:pagination) { {} }
+ let(:collection) { group_members }
+ let(:presented_members) { present_members(collection) }
- expect(json).to match_schema('group_link/group_group_links')
- end
- end
+ subject { Gitlab::Json.parse(helper.group_members_list_data_json(group, presented_members, pagination)) }
- describe '#members_data_json' do
shared_examples 'members.json' do
- it 'matches json schema' do
- json = helper.members_data_json(group, present_members([group_member]))
-
- expect(json).to match_schema('members')
+ it 'returns `members` property that matches json schema' do
+ expect(subject['members'].to_json).to match_schema('members')
end
end
- context 'for a group member' do
- let(:group_member) { create(:group_member, group: group, created_by: current_user) }
+ 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)
+ end
+
+ it 'returns expected json' do
+ expected = {
+ member_path: '/groups/foo-bar/-/group_members/:id',
+ source_id: 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 'with user status set' do
let(:user) { create(:user) }
let!(:status) { create(:user_status, user: user) }
- let(:group_member) { create(:group_member, group: group, user: user, created_by: current_user) }
+ let(:group_members) { [create(:group_member, group: group, user: user, created_by: current_user)] }
it_behaves_like 'members.json'
end
end
context 'for an invited group member' do
- let(:group_member) { create(:group_member, :invited, group: group, created_by: current_user) }
+ let(:group_members) { create_list(:group_member, 2, :invited, group: group, created_by: current_user) }
it_behaves_like 'members.json'
end
context 'for an access request' do
- let(:group_member) { create(:group_member, :access_request, group: group, created_by: current_user) }
+ let(:group_members) { create_list(:group_member, 2, :access_request, group: group, created_by: current_user) }
it_behaves_like 'members.json'
end
- end
-
- describe '#group_members_list_data_attributes' do
- let(:group_member) { create(:group_member, group: group, created_by: current_user) }
- 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)
+ context 'when pagination is not available' do
+ it 'sets `pagination` attribute to expected json' do
+ expected = {
+ current_page: nil,
+ per_page: nil,
+ total_items: 2,
+ param_name: nil,
+ params: {}
+ }.as_json
+
+ expect(subject['pagination']).to include(expected)
+ end
end
- it 'returns expected hash' do
- expect(helper.group_members_list_data_attributes(group, present_members([group_member]))).to include({
- members: helper.members_data_json(group, present_members([group_member])),
- member_path: '/groups/foo-bar/-/group_members/:id',
- source_id: group.id,
- can_manage_members: 'true'
- })
+ 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 } } }
+
+ it 'sets `pagination` attribute to expected json' do
+ expected = {
+ current_page: 1,
+ per_page: 1,
+ total_items: 2,
+ param_name: :page,
+ params: { search_groups: nil }
+ }.as_json
+
+ expect(subject['pagination']).to include(expected)
+ end
end
end
- describe '#group_group_links_list_data_attributes' do
+ 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 hash' do
- expect(helper.group_group_links_list_data_attributes(shared_group)).to include({
- members: helper.group_group_links_data_json(shared_group.shared_with_group_links),
+ 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/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index d588120bb98..ad6852f63df 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -96,9 +96,31 @@ RSpec.describe GroupsHelper do
subject { helper.group_title(very_deep_nested_group) }
- it 'outputs the groups in the correct order' do
- expect(subject)
- .to match(%r{<li style="text-indent: 16px;"><a.*>#{deep_nested_group.name}.*</li>.*<a.*>#{very_deep_nested_group.name}</a>}m)
+ context 'traversal queries' do
+ shared_examples 'correct ancestor order' do
+ it 'outputs the groups in the correct order' do
+ expect(subject)
+ .to match(%r{<li style="text-indent: 16px;"><a.*>#{deep_nested_group.name}.*</li>.*<a.*>#{very_deep_nested_group.name}</a>}m)
+ end
+ end
+
+ context 'recursive' do
+ before do
+ stub_feature_flags(use_traversal_ids: false)
+ end
+
+ include_examples 'correct ancestor order'
+ end
+
+ context 'linear' do
+ before do
+ stub_feature_flags(use_traversal_ids: true)
+
+ very_deep_nested_group.reload # make sure traversal_ids are reloaded
+ end
+
+ include_examples 'correct ancestor order'
+ end
end
it 'enqueues the elements in the breadcrumb schema list' do
@@ -122,101 +144,121 @@ RSpec.describe GroupsHelper do
end
describe '#share_with_group_lock_help_text' do
- let_it_be_with_reload(:root_group) { create(:group) }
- let_it_be_with_reload(:subgroup) { create(:group, parent: root_group) }
- let_it_be_with_reload(:sub_subgroup) { create(:group, parent: subgroup) }
- let_it_be(:root_owner) { create(:user) }
- let_it_be(:sub_owner) { create(:user) }
- let_it_be(:sub_sub_owner) { create(:user) }
-
- let(:possible_help_texts) do
- {
- default_help: "This setting will be applied to all subgroups unless overridden by a group owner",
- ancestor_locked_but_you_can_override: %r{This setting is applied on <a .+>.+</a>\. You can override the setting or .+},
- ancestor_locked_so_ask_the_owner: /This setting is applied on .+\. To share projects in this group with another group, ask the owner to override the setting or remove the share with group lock from .+/,
- ancestor_locked_and_has_been_overridden: /This setting is applied on .+ and has been overridden on this subgroup/
- }
- end
-
- let(:possible_linked_ancestors) do
- {
- root_group: root_group,
- subgroup: subgroup
- }
- end
-
- let(:users) do
- {
- root_owner: root_owner,
- sub_owner: sub_owner,
- sub_sub_owner: sub_sub_owner
- }
- end
-
- subject { helper.share_with_group_lock_help_text(sub_subgroup) }
-
- before_all do
- root_group.add_owner(root_owner)
- subgroup.add_owner(sub_owner)
- sub_subgroup.add_owner(sub_sub_owner)
- end
-
- # rubocop:disable Layout/SpaceBeforeComma
- where(:root_share_with_group_locked, :subgroup_share_with_group_locked, :sub_subgroup_share_with_group_locked, :current_user, :help_text, :linked_ancestor) do
- [
- [false , false , false , :root_owner , :default_help , nil],
- [false , false , false , :sub_owner , :default_help , nil],
- [false , false , false , :sub_sub_owner , :default_help , nil],
- [false , false , true , :root_owner , :default_help , nil],
- [false , false , true , :sub_owner , :default_help , nil],
- [false , false , true , :sub_sub_owner , :default_help , nil],
- [false , true , false , :root_owner , :ancestor_locked_and_has_been_overridden , :subgroup],
- [false , true , false , :sub_owner , :ancestor_locked_and_has_been_overridden , :subgroup],
- [false , true , false , :sub_sub_owner , :ancestor_locked_and_has_been_overridden , :subgroup],
- [false , true , true , :root_owner , :ancestor_locked_but_you_can_override , :subgroup],
- [false , true , true , :sub_owner , :ancestor_locked_but_you_can_override , :subgroup],
- [false , true , true , :sub_sub_owner , :ancestor_locked_so_ask_the_owner , :subgroup],
- [true , false , false , :root_owner , :default_help , nil],
- [true , false , false , :sub_owner , :default_help , nil],
- [true , false , false , :sub_sub_owner , :default_help , nil],
- [true , false , true , :root_owner , :default_help , nil],
- [true , false , true , :sub_owner , :default_help , nil],
- [true , false , true , :sub_sub_owner , :default_help , nil],
- [true , true , false , :root_owner , :ancestor_locked_and_has_been_overridden , :root_group],
- [true , true , false , :sub_owner , :ancestor_locked_and_has_been_overridden , :root_group],
- [true , true , false , :sub_sub_owner , :ancestor_locked_and_has_been_overridden , :root_group],
- [true , true , true , :root_owner , :ancestor_locked_but_you_can_override , :root_group],
- [true , true , true , :sub_owner , :ancestor_locked_so_ask_the_owner , :root_group],
- [true , true , true , :sub_sub_owner , :ancestor_locked_so_ask_the_owner , :root_group]
- ]
- end
- # rubocop:enable Layout/SpaceBeforeComma
+ context 'traversal queries' do
+ let_it_be_with_reload(:root_group) { create(:group) }
+ let_it_be_with_reload(:subgroup) { create(:group, parent: root_group) }
+ let_it_be_with_reload(:sub_subgroup) { create(:group, parent: subgroup) }
+ let_it_be(:root_owner) { create(:user) }
+ let_it_be(:sub_owner) { create(:user) }
+ let_it_be(:sub_sub_owner) { create(:user) }
+
+ let(:possible_help_texts) do
+ {
+ default_help: "This setting will be applied to all subgroups unless overridden by a group owner",
+ ancestor_locked_but_you_can_override: %r{This setting is applied on <a .+>.+</a>\. You can override the setting or .+},
+ ancestor_locked_so_ask_the_owner: /This setting is applied on .+\. To share projects in this group with another group, ask the owner to override the setting or remove the share with group lock from .+/,
+ ancestor_locked_and_has_been_overridden: /This setting is applied on .+ and has been overridden on this subgroup/
+ }
+ end
- with_them do
- before do
- root_group.update_column(:share_with_group_lock, true) if root_share_with_group_locked
- subgroup.update_column(:share_with_group_lock, true) if subgroup_share_with_group_locked
- sub_subgroup.update_column(:share_with_group_lock, true) if sub_subgroup_share_with_group_locked
-
- allow(helper).to receive(:current_user).and_return(users[current_user])
- allow(helper).to receive(:can?)
- .with(users[current_user], :change_share_with_group_lock, subgroup)
- .and_return(Ability.allowed?(users[current_user], :change_share_with_group_lock, subgroup))
-
- ancestor = possible_linked_ancestors[linked_ancestor]
- if ancestor
- allow(helper).to receive(:can?)
- .with(users[current_user], :read_group, ancestor)
- .and_return(Ability.allowed?(users[current_user], :read_group, ancestor))
- allow(helper).to receive(:can?)
- .with(users[current_user], :admin_group, ancestor)
- .and_return(Ability.allowed?(users[current_user], :admin_group, ancestor))
+ let(:possible_linked_ancestors) do
+ {
+ root_group: root_group,
+ subgroup: subgroup
+ }
+ end
+
+ let(:users) do
+ {
+ root_owner: root_owner,
+ sub_owner: sub_owner,
+ sub_sub_owner: sub_sub_owner
+ }
+ end
+
+ subject { helper.share_with_group_lock_help_text(sub_subgroup) }
+
+ before_all do
+ root_group.add_owner(root_owner)
+ subgroup.add_owner(sub_owner)
+ sub_subgroup.add_owner(sub_sub_owner)
+ end
+
+ shared_examples 'correct ancestor order' do
+ # rubocop:disable Layout/SpaceBeforeComma
+ where(:root_share_with_group_locked, :subgroup_share_with_group_locked, :sub_subgroup_share_with_group_locked, :current_user, :help_text, :linked_ancestor) do
+ [
+ [false , false , false , :root_owner , :default_help , nil],
+ [false , false , false , :sub_owner , :default_help , nil],
+ [false , false , false , :sub_sub_owner , :default_help , nil],
+ [false , false , true , :root_owner , :default_help , nil],
+ [false , false , true , :sub_owner , :default_help , nil],
+ [false , false , true , :sub_sub_owner , :default_help , nil],
+ [false , true , false , :root_owner , :ancestor_locked_and_has_been_overridden , :subgroup],
+ [false , true , false , :sub_owner , :ancestor_locked_and_has_been_overridden , :subgroup],
+ [false , true , false , :sub_sub_owner , :ancestor_locked_and_has_been_overridden , :subgroup],
+ [false , true , true , :root_owner , :ancestor_locked_but_you_can_override , :subgroup],
+ [false , true , true , :sub_owner , :ancestor_locked_but_you_can_override , :subgroup],
+ [false , true , true , :sub_sub_owner , :ancestor_locked_so_ask_the_owner , :subgroup],
+ [true , false , false , :root_owner , :default_help , nil],
+ [true , false , false , :sub_owner , :default_help , nil],
+ [true , false , false , :sub_sub_owner , :default_help , nil],
+ [true , false , true , :root_owner , :default_help , nil],
+ [true , false , true , :sub_owner , :default_help , nil],
+ [true , false , true , :sub_sub_owner , :default_help , nil],
+ [true , true , false , :root_owner , :ancestor_locked_and_has_been_overridden , :root_group],
+ [true , true , false , :sub_owner , :ancestor_locked_and_has_been_overridden , :root_group],
+ [true , true , false , :sub_sub_owner , :ancestor_locked_and_has_been_overridden , :root_group],
+ [true , true , true , :root_owner , :ancestor_locked_but_you_can_override , :root_group],
+ [true , true , true , :sub_owner , :ancestor_locked_so_ask_the_owner , :root_group],
+ [true , true , true , :sub_sub_owner , :ancestor_locked_so_ask_the_owner , :root_group]
+ ]
+ end
+ # rubocop:enable Layout/SpaceBeforeComma
+
+ with_them do
+ before do
+ root_group.update_column(:share_with_group_lock, true) if root_share_with_group_locked
+ subgroup.update_column(:share_with_group_lock, true) if subgroup_share_with_group_locked
+ sub_subgroup.update_column(:share_with_group_lock, true) if sub_subgroup_share_with_group_locked
+
+ allow(helper).to receive(:current_user).and_return(users[current_user])
+ allow(helper).to receive(:can?)
+ .with(users[current_user], :change_share_with_group_lock, subgroup)
+ .and_return(Ability.allowed?(users[current_user], :change_share_with_group_lock, subgroup))
+
+ ancestor = possible_linked_ancestors[linked_ancestor]
+ if ancestor
+ allow(helper).to receive(:can?)
+ .with(users[current_user], :read_group, ancestor)
+ .and_return(Ability.allowed?(users[current_user], :read_group, ancestor))
+ allow(helper).to receive(:can?)
+ .with(users[current_user], :admin_group, ancestor)
+ .and_return(Ability.allowed?(users[current_user], :admin_group, ancestor))
+ end
+ end
+
+ it 'has the correct help text with correct ancestor links' do
+ expect(subject).to match(possible_help_texts[help_text])
+ expect(subject).to match(possible_linked_ancestors[linked_ancestor].name) unless help_text == :default_help
+ end
end
end
- it 'has the correct help text with correct ancestor links' do
- expect(subject).to match(possible_help_texts[help_text])
- expect(subject).to match(possible_linked_ancestors[linked_ancestor].name) unless help_text == :default_help
+ context 'recursive' do
+ before do
+ stub_feature_flags(use_traversal_ids: false)
+ end
+
+ include_examples 'correct ancestor order'
+ end
+
+ context 'linear' do
+ before do
+ stub_feature_flags(use_traversal_ids: true)
+ end
+
+ include_examples 'correct ancestor order'
end
end
end
@@ -420,42 +462,59 @@ RSpec.describe GroupsHelper do
describe '#show_invite_banner?' do
let_it_be(:current_user) { create(:user) }
let_it_be_with_refind(:group) { create(:group) }
+ let_it_be(:subgroup) { create(:group, parent: group) }
let_it_be(:users) { [current_user, create(:user)] }
- subject { helper.show_invite_banner?(group) }
-
before do
allow(helper).to receive(:current_user) { current_user }
allow(helper).to receive(:can?).with(current_user, :admin_group, group).and_return(can_admin_group)
- stub_feature_flags(invite_your_teammates_banner_a: feature_enabled_flag)
+ allow(helper).to receive(:can?).with(current_user, :admin_group, subgroup).and_return(can_admin_group)
users.take(group_members_count).each { |user| group.add_guest(user) }
end
using RSpec::Parameterized::TableSyntax
- where(:feature_enabled_flag, :can_admin_group, :group_members_count, :expected_result) do
- true | true | 1 | true
- true | false | 1 | false
- false | true | 1 | false
- false | false | 1 | false
- true | true | 2 | false
- true | false | 2 | false
- false | true | 2 | false
- false | false | 2 | false
+ where(:can_admin_group, :group_members_count, :expected_result) do
+ true | 1 | true
+ false | 1 | false
+ true | 2 | false
+ false | 2 | false
end
with_them do
- context 'when the group was just created' do
- before do
- flash[:notice] = "Group #{group.name} was successfully created"
+ context 'for a parent group' do
+ subject { helper.show_invite_banner?(group) }
+
+ context 'when the group was just created' do
+ before do
+ flash[:notice] = "Group #{group.name} was successfully created"
+ end
+
+ it { is_expected.to be_falsey }
end
- it { is_expected.to be_falsey }
+ context 'when no flash message' do
+ it 'returns the expected result' do
+ expect(subject).to eq(expected_result)
+ end
+ end
end
- context 'when no flash message' do
- it 'returns the expected result' do
- expect(subject).to eq(expected_result)
+ context 'for a subgroup' do
+ subject { helper.show_invite_banner?(subgroup) }
+
+ context 'when the subgroup was just created' do
+ before do
+ flash[:notice] = "Group #{subgroup.name} was successfully created"
+ end
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when no flash message' do
+ it 'returns the expected result' do
+ expect(subject).to eq(expected_result)
+ end
end
end
end
diff --git a/spec/helpers/ide_helper_spec.rb b/spec/helpers/ide_helper_spec.rb
index 963d5953d4c..d34358e49c0 100644
--- a/spec/helpers/ide_helper_spec.rb
+++ b/spec/helpers/ide_helper_spec.rb
@@ -45,5 +45,35 @@ RSpec.describe IdeHelper do
)
end
end
+
+ context 'environments guidance experiment', :experiment do
+ before do
+ stub_experiments(in_product_guidance_environments_webide: :candidate)
+ self.instance_variable_set(:@project, project)
+ end
+
+ context 'when project has no enviornments' do
+ it 'enables environment guidance' do
+ expect(helper.ide_data).to include('enable-environments-guidance' => 'true')
+ end
+
+ context 'and the callout has been dismissed' do
+ it 'disables environment guidance' do
+ callout = create(:user_callout, feature_name: :web_ide_ci_environments_guidance, user: project.creator)
+ callout.update!(dismissed_at: Time.now - 1.week)
+ allow(helper).to receive(:current_user).and_return(User.find(project.creator.id))
+ expect(helper.ide_data).to include('enable-environments-guidance' => 'false')
+ end
+ end
+ end
+
+ context 'when the project has environments' do
+ it 'disables environment guidance' do
+ create(:environment, project: project)
+
+ expect(helper.ide_data).to include('enable-environments-guidance' => 'false')
+ end
+ end
+ end
end
end
diff --git a/spec/helpers/invite_members_helper_spec.rb b/spec/helpers/invite_members_helper_spec.rb
index 109b1fc4441..122f2339b28 100644
--- a/spec/helpers/invite_members_helper_spec.rb
+++ b/spec/helpers/invite_members_helper_spec.rb
@@ -3,6 +3,8 @@
require "spec_helper"
RSpec.describe InviteMembersHelper do
+ include Devise::Test::ControllerHelpers
+
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user, developer_projects: [project]) }
@@ -12,35 +14,21 @@ RSpec.describe InviteMembersHelper do
helper.extend(Gitlab::Experimentation::ControllerConcern)
end
- describe '#show_invite_members_track_event' do
- it 'shows values when can directly invite members' do
- allow(helper).to receive(:directly_invite_members?).and_return(true)
-
- expect(helper.show_invite_members_track_event).to eq 'show_invite_members'
- end
-
- it 'shows values when can indirectly invite members' do
- allow(helper).to receive(:directly_invite_members?).and_return(false)
- allow(helper).to receive(:indirectly_invite_members?).and_return(true)
-
- expect(helper.show_invite_members_track_event).to eq 'show_invite_members_version_b'
- end
- end
-
context 'with project' do
before do
+ allow(helper).to receive(:current_user) { owner }
assign(:project, project)
end
describe "#can_invite_members_for_project?" do
- context 'when the user can_import_members' do
+ context 'when the user can_manage_project_members' do
before do
- allow(helper).to receive(:can_import_members?).and_return(true)
+ allow(helper).to receive(:can_manage_project_members?).and_return(true)
end
it 'returns true' do
expect(helper.can_invite_members_for_project?(project)).to eq true
- expect(helper).to have_received(:can_import_members?)
+ expect(helper).to have_received(:can_manage_project_members?)
end
context 'when feature flag is disabled' do
@@ -50,14 +38,14 @@ RSpec.describe InviteMembersHelper do
it 'returns false' do
expect(helper.can_invite_members_for_project?(project)).to eq false
- expect(helper).not_to have_received(:can_import_members?)
+ expect(helper).not_to have_received(:can_manage_project_members?)
end
end
end
- context 'when the user can not invite members' do
+ context 'when the user can not manage project members' do
before do
- expect(helper).to receive(:can_import_members?).and_return(false)
+ expect(helper).to receive(:can_manage_project_members?).and_return(false)
end
it 'returns false' do
@@ -87,88 +75,11 @@ RSpec.describe InviteMembersHelper do
end
end
end
-
- describe "#indirectly_invite_members?" do
- context 'when a user is a developer' do
- before do
- allow(helper).to receive(:current_user) { developer }
- end
-
- it 'returns false' do
- allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_b) { false }
-
- expect(helper.indirectly_invite_members?).to eq false
- end
-
- it 'returns true' do
- allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_b) { true }
-
- expect(helper.indirectly_invite_members?).to eq true
- end
- end
-
- context 'when a user is an owner' do
- before do
- allow(helper).to receive(:current_user) { owner }
- end
-
- it 'returns false' do
- allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_b) { true }
-
- expect(helper.indirectly_invite_members?).to eq false
- end
- end
- end
end
context 'with group' do
let_it_be(:group) { create(:group) }
- describe "#can_invite_members_for_group?" do
- include Devise::Test::ControllerHelpers
-
- let_it_be(:user) { create(:user) }
-
- before do
- sign_in(user)
- allow(helper).to receive(:current_user) { user }
- end
-
- context 'when the user can_import_members' do
- before do
- allow(helper).to receive(:can?).with(user, :admin_group_member, group).and_return(true)
- end
-
- it 'returns true' do
- expect(helper.can_invite_members_for_group?(group)).to eq true
- expect(helper).to have_received(:can?).with(user, :admin_group_member, group)
- end
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(invite_members_group_modal: false)
- end
-
- it 'returns false' do
- stub_feature_flags(invite_members_group_modal: false)
-
- expect(helper.can_invite_members_for_group?(group)).to eq false
- expect(helper).not_to have_received(:can?)
- end
- end
- end
-
- context 'when the user can not invite members' do
- before do
- expect(helper).to receive(:can?).with(user, :admin_group_member, group).and_return(false)
- end
-
- it 'returns false' do
- expect(helper.can_invite_members_for_group?(group)).to eq false
- end
- end
- end
-
describe "#invite_group_members?" do
context 'when the user is an owner' do
before do
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 54524858962..b0338d80ee7 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -133,13 +133,13 @@ RSpec.describe IssuablesHelper do
it 'returns navigation with badges' do
expect(helper.issuables_state_counter_text(:issues, :opened, true))
- .to eq('<span>Open</span> <span class="badge badge-pill">42</span>')
+ .to eq('<span>Open</span> <span class="badge badge-muted badge-pill gl-badge gl-tab-counter-badge sm">42</span>')
expect(helper.issuables_state_counter_text(:issues, :closed, true))
- .to eq('<span>Closed</span> <span class="badge badge-pill">42</span>')
+ .to eq('<span>Closed</span> <span class="badge badge-muted badge-pill gl-badge gl-tab-counter-badge sm">42</span>')
expect(helper.issuables_state_counter_text(:merge_requests, :merged, true))
- .to eq('<span>Merged</span> <span class="badge badge-pill">42</span>')
+ .to eq('<span>Merged</span> <span class="badge badge-muted badge-pill gl-badge gl-tab-counter-badge sm">42</span>')
expect(helper.issuables_state_counter_text(:merge_requests, :all, true))
- .to eq('<span>All</span> <span class="badge badge-pill">42</span>')
+ .to eq('<span>All</span> <span class="badge badge-muted badge-pill gl-badge gl-tab-counter-badge sm">42</span>')
end
end
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 21a01f349b5..17e6c75ca27 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -293,23 +293,32 @@ RSpec.describe IssuesHelper do
allow(helper).to receive(:url_for).and_return('#')
expected = {
+ autocomplete_award_emojis_path: autocomplete_award_emojis_path,
+ autocomplete_users_path: autocomplete_users_path(active: true, current_user: true, project_id: project.id, format: :json),
calendar_path: '#',
can_bulk_update: 'true',
can_edit: 'true',
can_import_issues: 'true',
email: current_user&.notification_email,
+ emails_help_page_path: help_page_path('development/emails', anchor: 'email-namespace'),
empty_state_svg_path: '#',
endpoint: expose_path(api_v4_projects_issues_path(id: project.id)),
export_csv_path: export_csv_project_issues_path(project),
- full_path: project.full_path,
has_issues: project_issues(project).exists?.to_s,
import_csv_issues_path: '#',
+ 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'),
+ 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 }),
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),
+ project_path: project.full_path,
+ quick_actions_help_path: help_page_path('user/project/quick_actions'),
+ reset_path: new_issuable_address_project_path(project, issuable_type: 'issue'),
rss_path: '#',
show_new_issue_link: 'true',
sign_in_path: new_user_session_path
@@ -332,4 +341,65 @@ RSpec.describe IssuesHelper do
end
end
end
+
+ describe '#issue_manual_ordering_class' do
+ context 'when sorting by relative position' do
+ before do
+ assign(:sort, 'relative_position')
+ end
+
+ it 'returns manual ordering class' do
+ expect(helper.issue_manual_ordering_class).to eq("manual-ordering")
+ end
+
+ context 'when manual sorting disabled' do
+ before do
+ allow(helper).to receive(:issue_repositioning_disabled?).and_return(true)
+ end
+
+ it 'returns nil' do
+ expect(helper.issue_manual_ordering_class).to eq(nil)
+ end
+ end
+ end
+ end
+
+ describe '#issue_repositioning_disabled?' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+
+ subject { helper.issue_repositioning_disabled? }
+
+ context 'for project' do
+ before do
+ assign(:project, project)
+ end
+
+ it { is_expected.to eq(false) }
+
+ context 'when block_issue_repositioning feature flag is enabled' do
+ before do
+ stub_feature_flags(block_issue_repositioning: group)
+ end
+
+ it { is_expected.to eq(true) }
+ end
+ end
+
+ context 'for group' do
+ before do
+ assign(:group, group)
+ end
+
+ it { is_expected.to eq(false) }
+
+ context 'when block_issue_repositioning feature flag is enabled' do
+ before do
+ stub_feature_flags(block_issue_repositioning: group)
+ end
+
+ it { is_expected.to eq(true) }
+ end
+ end
+ end
end
diff --git a/spec/helpers/learn_gitlab_helper_spec.rb b/spec/helpers/learn_gitlab_helper_spec.rb
index 82c8e4ba596..cf0d329c36f 100644
--- a/spec/helpers/learn_gitlab_helper_spec.rb
+++ b/spec/helpers/learn_gitlab_helper_spec.rb
@@ -7,14 +7,14 @@ RSpec.describe LearnGitlabHelper do
include Devise::Test::ControllerHelpers
let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project, name: LearnGitlab::PROJECT_NAME, namespace: user.namespace) }
+ let_it_be(:project) { create(:project, name: LearnGitlab::Project::PROJECT_NAME, namespace: user.namespace) }
let_it_be(:namespace) { project.namespace }
before do
project.add_developer(user)
allow(helper).to receive(:user).and_return(user)
- allow_next_instance_of(LearnGitlab) do |learn_gitlab|
+ allow_next_instance_of(LearnGitlab::Project) do |learn_gitlab|
allow(learn_gitlab).to receive(:project).and_return(project)
end
@@ -41,12 +41,12 @@ RSpec.describe LearnGitlabHelper do
it 'sets correct path and completion status' do
expect(onboarding_actions_data[:git_write]).to eq({
- url: project_issue_url(project, LearnGitlabHelper::ACTION_ISSUE_IDS[:git_write]),
+ url: project_issue_url(project, LearnGitlab::Onboarding::ACTION_ISSUE_IDS[:git_write]),
completed: true,
svg: helper.image_path("learn_gitlab/git_write.svg")
})
expect(onboarding_actions_data[:pipeline_created]).to eq({
- url: project_issue_url(project, LearnGitlabHelper::ACTION_ISSUE_IDS[:pipeline_created]),
+ url: project_issue_url(project, LearnGitlab::Onboarding::ACTION_ISSUE_IDS[:pipeline_created]),
completed: false,
svg: helper.image_path("learn_gitlab/pipeline_created.svg")
})
@@ -75,7 +75,7 @@ RSpec.describe LearnGitlabHelper do
before do
stub_experiment_for_subject(learn_gitlab_a: experiment_a, learn_gitlab_b: experiment_b)
allow(OnboardingProgress).to receive(:onboarding?).with(project.namespace).and_return(onboarding)
- allow_next(LearnGitlab, user).to receive(:available?).and_return(learn_gitlab_available)
+ allow_next(LearnGitlab::Project, user).to receive(:available?).and_return(learn_gitlab_available)
end
context 'when signed in' do
@@ -85,10 +85,62 @@ RSpec.describe LearnGitlabHelper do
it { is_expected.to eq(result) }
end
+ end
- context 'when not signed in' do
- it { is_expected.to eq(false) }
+ context 'when not signed in' do
+ before do
+ stub_experiment_for_subject(learn_gitlab_a: true, learn_gitlab_b: true)
end
+
+ it { is_expected.to eq(false) }
+ end
+ end
+
+ describe '.onboarding_sections_data' do
+ subject(:sections) { helper.onboarding_sections_data }
+
+ it 'has the right keys' do
+ expect(sections.keys).to contain_exactly(:deploy, :plan, :workspace)
+ end
+ it 'has the svg' do
+ expect(sections.values.map { |section| section.keys }).to eq([[:svg]] * 3)
+ end
+ end
+
+ describe '.learn_gitlab_experiment_tracking_category' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+
+ subject { helper.learn_gitlab_experiment_tracking_category }
+
+ where(:experiment_a, :experiment_b, :result) do
+ false | false | nil
+ false | true | 'Growth::Activation::Experiment::LearnGitLabB'
+ true | false | 'Growth::Conversion::Experiment::LearnGitLabA'
+ true | true | 'Growth::Conversion::Experiment::LearnGitLabA'
+ end
+
+ with_them do
+ before do
+ stub_experiment_for_subject(learn_gitlab_a: experiment_a, learn_gitlab_b: experiment_b)
+ end
+
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
+
+ it { is_expected.to eq(result) }
+ end
+ end
+
+ context 'when not signed in' do
+ before do
+ stub_experiment_for_subject(learn_gitlab_a: true, learn_gitlab_b: true)
+ end
+
+ it { is_expected.to eq(nil) }
end
end
end
diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb
index 8c08b06d8a8..a8a918cbc74 100644
--- a/spec/helpers/namespaces_helper_spec.rb
+++ b/spec/helpers/namespaces_helper_spec.rb
@@ -265,4 +265,32 @@ RSpec.describe NamespacesHelper do
end
end
end
+
+ describe '#cascading_namespace_setting_locked?' do
+ let(:attribute) { :delayed_project_removal }
+
+ context 'when `group` argument is `nil`' do
+ it 'returns `false`' do
+ expect(helper.cascading_namespace_setting_locked?(attribute, nil)).to eq(false)
+ end
+ end
+
+ context 'when `*_locked?` method does not exist' do
+ it 'returns `false`' do
+ expect(helper.cascading_namespace_setting_locked?(:attribute_that_does_not_exist, admin_group)).to eq(false)
+ end
+ end
+
+ context 'when `*_locked?` method does exist' do
+ before do
+ allow(admin_group.namespace_settings).to receive(:delayed_project_removal_locked?).and_return(true)
+ end
+
+ it 'calls corresponding `*_locked?` method' do
+ helper.cascading_namespace_setting_locked?(attribute, admin_group, include_self: true)
+
+ expect(admin_group.namespace_settings).to have_received(:delayed_project_removal_locked?).with(include_self: true)
+ end
+ end
+ end
end
diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb
new file mode 100644
index 00000000000..5c9e1e82b01
--- /dev/null
+++ b/spec/helpers/nav/top_nav_helper_spec.rb
@@ -0,0 +1,376 @@
+# frozen_string_literal: true
+
+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(:current_user) { nil }
+ let(:current_project) { nil }
+ let(:current_group) { nil }
+ let(:with_current_settings_admin_mode) { false }
+ let(:with_header_link_admin_mode) { false }
+ let(:with_sherlock_enabled) { false }
+ let(:with_projects) { false }
+ let(:with_groups) { false }
+ let(:with_milestones) { false }
+ let(:with_snippets) { false }
+ let(:with_activity) { false }
+
+ let(:subject) { helper.top_nav_view_model(project: current_project, group: current_group) }
+
+ 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 }
+
+ # Defaulting all `dashboard_nav_link?` calls to false ensures the EE-specific behavior
+ # is not enabled in this CE spec
+ allow(helper).to receive(:dashboard_nav_link?).with(anything) { false }
+
+ allow(helper).to receive(:dashboard_nav_link?).with(:projects) { with_projects }
+ allow(helper).to receive(:dashboard_nav_link?).with(:groups) { with_groups }
+ allow(helper).to receive(:dashboard_nav_link?).with(:milestones) { with_milestones }
+ allow(helper).to receive(:dashboard_nav_link?).with(:snippets) { with_snippets }
+ allow(helper).to receive(:dashboard_nav_link?).with(:activity) { with_activity }
+ end
+
+ it 'has :activeTitle' do
+ expect(subject[:activeTitle]).to eq(active_title)
+ end
+
+ 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
+ ])
+ end
+ end
+
+ context 'when current_user is non-admin' do
+ let(:current_user) { user }
+
+ it 'has no menu items or views by default' do
+ expect(subject).to eq({ activeTitle: active_title,
+ primary: [],
+ secondary: [],
+ views: {} })
+ end
+
+ context 'with projects' do
+ let(:with_projects) { true }
+ let(:projects_view) { subject[:views][:projects] }
+
+ it 'has expected :primary' do
+ expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
+ css_class: 'qa-projects-dropdown',
+ data: {
+ track_event: 'click_dropdown',
+ track_experiment: 'new_repo',
+ track_label: 'projects_dropdown'
+ },
+ icon: 'project',
+ id: 'project',
+ title: 'Projects',
+ view: 'projects'
+ )
+ expect(subject[:primary]).to eq([expected_primary])
+ end
+
+ context 'projects' do
+ it 'has expected :currentUserName' do
+ expect(projects_view[:currentUserName]).to eq(current_user.username)
+ end
+
+ it 'has expected :namespace' do
+ expect(projects_view[:namespace]).to eq('projects')
+ end
+
+ it 'has expected :linksPrimary' do
+ expected_links_primary = [
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/dashboard/projects',
+ id: 'your',
+ title: 'Your projects'
+ ),
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/dashboard/projects/starred',
+ id: 'starred',
+ title: 'Starred projects'
+ ),
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/explore',
+ id: 'explore',
+ title: 'Explore projects'
+ )
+ ]
+ expect(projects_view[:linksPrimary]).to eq(expected_links_primary)
+ end
+
+ it 'has expected :linksSecondary' do
+ expected_links_secondary = [
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/projects/new',
+ id: 'create',
+ title: 'Create new project'
+ )
+ ]
+ expect(projects_view[:linksSecondary]).to eq(expected_links_secondary)
+ end
+
+ context 'with persisted project' do
+ let_it_be(:project) { build_stubbed(:project) }
+
+ let(:current_project) { project }
+ let(:avatar_url) { 'project_avatar_url' }
+
+ before do
+ allow(project).to receive(:persisted?) { true }
+ allow(project).to receive(:avatar_url) { avatar_url }
+ end
+
+ it 'has project as :container' do
+ expected_container = {
+ avatarUrl: avatar_url,
+ id: project.id,
+ name: project.name,
+ namespace: project.full_name,
+ webUrl: project_path(project)
+ }
+
+ expect(projects_view[:currentItem]).to eq(expected_container)
+ end
+ end
+ end
+ end
+
+ context 'with groups' do
+ let(:with_groups) { true }
+ let(:groups_view) { subject[:views][:groups] }
+
+ it 'has expected :primary' do
+ expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
+ css_class: 'qa-groups-dropdown',
+ data: {
+ track_event: 'click_dropdown',
+ track_label: 'groups_dropdown'
+ },
+ icon: 'group',
+ id: 'groups',
+ title: 'Groups',
+ view: 'groups'
+ )
+ expect(subject[:primary]).to eq([expected_primary])
+ end
+
+ context 'groups' do
+ it 'has expected :currentUserName' do
+ expect(groups_view[:currentUserName]).to eq(current_user.username)
+ end
+
+ it 'has expected :namespace' do
+ expect(groups_view[:namespace]).to eq('groups')
+ end
+
+ it 'has expected :linksPrimary' do
+ expected_links_primary = [
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/dashboard/groups',
+ id: 'your',
+ title: 'Your groups'
+ ),
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/explore/groups',
+ id: 'explore',
+ title: 'Explore groups'
+ )
+ ]
+ expect(groups_view[:linksPrimary]).to eq(expected_links_primary)
+ end
+
+ it 'has expected :linksSecondary' do
+ expected_links_secondary = [
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/groups/new#create-group-pane',
+ id: 'create',
+ title: 'Create group'
+ )
+ ]
+ expect(groups_view[:linksSecondary]).to eq(expected_links_secondary)
+ end
+
+ context 'with persisted group' do
+ let_it_be(:group) { build_stubbed(:group) }
+
+ let(:current_group) { group }
+ let(:avatar_url) { 'group_avatar_url' }
+
+ before do
+ allow(group).to receive(:persisted?) { true }
+ allow(group).to receive(:avatar_url) { avatar_url }
+ end
+
+ it 'has expected :container' do
+ expected_container = {
+ avatarUrl: avatar_url,
+ id: group.id,
+ name: group.name,
+ namespace: group.full_name,
+ webUrl: group_path(group)
+ }
+
+ expect(groups_view[:currentItem]).to eq(expected_container)
+ end
+ end
+ end
+ end
+
+ context 'with milestones' do
+ let(:with_milestones) { true }
+
+ it 'has expected :primary' do
+ expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
+ data: {
+ qa_selector: 'milestones_link'
+ },
+ href: '/dashboard/milestones',
+ icon: 'clock',
+ id: 'milestones',
+ title: 'Milestones'
+ )
+ expect(subject[:primary]).to eq([expected_primary])
+ end
+ end
+
+ context 'with snippets' do
+ let(:with_snippets) { true }
+
+ it 'has expected :primary' do
+ expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
+ data: {
+ qa_selector: 'snippets_link'
+ },
+ href: '/dashboard/snippets',
+ icon: 'snippet',
+ id: 'snippets',
+ title: 'Snippets'
+ )
+ expect(subject[:primary]).to eq([expected_primary])
+ end
+ end
+
+ context 'with activity' do
+ let(:with_activity) { true }
+
+ it 'has expected :primary' do
+ expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
+ data: {
+ qa_selector: 'activity_link'
+ },
+ href: '/dashboard/activity',
+ icon: 'history',
+ id: 'activity',
+ title: 'Activity'
+ )
+ expect(subject[:primary]).to eq([expected_primary])
+ end
+ end
+
+ context 'when sherlock is enabled' do
+ let(:with_sherlock_enabled) { true }
+
+ before do
+ # Note: We have to mock the sherlock route because the route is conditional on
+ # sherlock being enabled, but it parsed at Rails load time and can't be overridden
+ # in a spec.
+ allow(helper).to receive(:sherlock_transactions_path) { '/fake_sherlock_path' }
+ end
+
+ it 'has sherlock as last :secondary item' do
+ expected_sherlock_item = ::Gitlab::Nav::TopNavMenuItem.build(
+ id: 'sherlock',
+ title: 'Sherlock Transactions',
+ icon: 'admin',
+ href: '/fake_sherlock_path'
+ )
+ expect(subject[:secondary].last).to eq(expected_sherlock_item)
+ end
+ end
+ end
+
+ context 'when current_user is admin' do
+ let_it_be(:current_user) { admin }
+
+ let(:with_current_settings_admin_mode) { true }
+
+ it 'has admin as first :secondary item' do
+ expected_admin_item = ::Gitlab::Nav::TopNavMenuItem.build(
+ id: 'admin',
+ title: 'Admin',
+ icon: 'admin',
+ href: '/admin',
+ css_class: 'qa-admin-area-link'
+ )
+
+ expect(subject[:secondary].first).to eq(expected_admin_item)
+ end
+
+ context 'with header link admin_mode true' do
+ let(:with_header_link_admin_mode) { true }
+
+ it 'has leave_admin_mode as last :secondary item' do
+ expected_leave_admin_mode_item = ::Gitlab::Nav::TopNavMenuItem.build(
+ id: 'leave_admin_mode',
+ title: 'Leave Admin Mode',
+ icon: 'lock-open',
+ href: '/admin/session/destroy',
+ method: :post
+ )
+ expect(subject[:secondary].last).to eq(expected_leave_admin_mode_item)
+ end
+ end
+
+ context 'with header link admin_mode false' do
+ let(:with_header_link_admin_mode) { false }
+
+ it 'has enter_admin_mode as last :secondary item' do
+ expected_enter_admin_mode_item = ::Gitlab::Nav::TopNavMenuItem.build(
+ id: 'enter_admin_mode',
+ title: 'Enter Admin Mode',
+ icon: 'lock',
+ href: '/admin/session/new'
+ )
+ expect(subject[:secondary].last).to eq(expected_enter_admin_mode_item)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/helpers/nav_helper_spec.rb b/spec/helpers/nav_helper_spec.rb
index 2efff3402c5..4c5f440b8a3 100644
--- a/spec/helpers/nav_helper_spec.rb
+++ b/spec/helpers/nav_helper_spec.rb
@@ -115,6 +115,10 @@ RSpec.describe NavHelper do
describe '.group_issues_sub_menu_items' do
subject { helper.group_issues_sub_menu_items }
+ before do
+ allow(helper).to receive(:current_user).and_return(nil)
+ end
+
it { is_expected.to all(be_a(String)) }
end
diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb
index d03e39f2051..d261fb43bb6 100644
--- a/spec/helpers/page_layout_helper_spec.rb
+++ b/spec/helpers/page_layout_helper_spec.rb
@@ -232,7 +232,6 @@ RSpec.describe PageLayoutHelper do
is_expected.to eq({
current_emoji: '',
current_message: '',
- can_set_user_availability: true,
default_emoji: UserStatus::DEFAULT_EMOJI
})
end
@@ -251,7 +250,6 @@ RSpec.describe PageLayoutHelper do
current_availability: 'busy',
current_emoji: 'basketball',
current_message: 'Some message',
- can_set_user_availability: true,
default_emoji: UserStatus::DEFAULT_EMOJI
})
end
diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb
index 4d7083c4ca7..6be6d3670d4 100644
--- a/spec/helpers/preferences_helper_spec.rb
+++ b/spec/helpers/preferences_helper_spec.rb
@@ -121,6 +121,20 @@ RSpec.describe PreferencesHelper do
end
end
+ describe '#language_choices' do
+ include StubLanguagesTranslationPercentage
+
+ it 'lists all the selectable language options with their translation percent' do
+ stub_languages_translation_percentage(en: 100, es: 65)
+ stub_user(preferred_language: :en)
+
+ expect(helper.language_choices).to eq([
+ '<option selected="selected" value="en">English (100% translated)</option>',
+ '<option value="es">Spanish - espaƱol (65% translated)</option>'
+ ].join("\n"))
+ end
+ end
+
def stub_user(messages = {})
if messages.empty?
allow(helper).to receive(:current_user).and_return(nil)
diff --git a/spec/helpers/projects/alert_management_helper_spec.rb b/spec/helpers/projects/alert_management_helper_spec.rb
index e836461b099..6f66a93b9ec 100644
--- a/spec/helpers/projects/alert_management_helper_spec.rb
+++ b/spec/helpers/projects/alert_management_helper_spec.rb
@@ -34,6 +34,7 @@ RSpec.describe Projects::AlertManagementHelper do
'empty-alert-svg-path' => match_asset_path('/assets/illustrations/alert-management-empty-state.svg'),
'user-can-enable-alert-management' => 'true',
'alert-management-enabled' => 'false',
+ 'has-managed-prometheus' => 'false',
'text-query': nil,
'assignee-username-query': nil
)
@@ -43,25 +44,53 @@ RSpec.describe Projects::AlertManagementHelper do
context 'with prometheus service' do
let_it_be(:prometheus_service) { create(:prometheus_service, project: project) }
- context 'when prometheus service is active' do
- it 'enables alert management' do
+ context 'when manual prometheus service is active' do
+ it "enables alert management and doesn't show managed prometheus" do
+ prometheus_service.update!(manual_configuration: true)
+
expect(data).to include(
'alert-management-enabled' => 'true'
)
+ expect(data).to include(
+ 'has-managed-prometheus' => 'false'
+ )
+ end
+ end
+
+ context 'when a cluster prometheus is available' do
+ let(:cluster) { create(:cluster, projects: [project]) }
+
+ it 'has managed prometheus' do
+ create(:clusters_applications_prometheus, :installed, cluster: cluster)
+
+ expect(data).to include(
+ 'has-managed-prometheus' => 'true'
+ )
end
end
context 'when prometheus service is inactive' do
- it 'disables alert management' do
+ it 'disables alert management and hides managed prometheus' do
prometheus_service.update!(manual_configuration: false)
expect(data).to include(
'alert-management-enabled' => 'false'
)
+ expect(data).to include(
+ 'has-managed-prometheus' => 'false'
+ )
end
end
end
+ context 'without prometheus service' do
+ it "doesn't have managed prometheus" do
+ expect(data).to include(
+ 'has-managed-prometheus' => 'false'
+ )
+ end
+ end
+
context 'with http integration' do
let_it_be(:integration) { create(:alert_management_http_integration, project: project) }
diff --git a/spec/helpers/projects/project_members_helper_spec.rb b/spec/helpers/projects/project_members_helper_spec.rb
index 0e08a18f912..90035f3e1c5 100644
--- a/spec/helpers/projects/project_members_helper_spec.rb
+++ b/spec/helpers/projects/project_members_helper_spec.rb
@@ -147,28 +147,64 @@ RSpec.describe Projects::ProjectMembersHelper do
end
describe 'project members' do
- let_it_be(:project_members) { create_list(:project_member, 1, project: project) }
+ let_it_be(:project_members) { create_list(:project_member, 2, project: project) }
- describe '#project_members_data_json' do
- it 'matches json schema' do
- expect(helper.project_members_data_json(project, present_members(project_members))).to match_schema('members')
- end
- end
+ let(:collection) { project_members }
+ let(:presented_members) { present_members(collection) }
- describe '#project_members_list_data_attributes' do
+ describe '#project_members_list_data_json' do
let(:allow_admin_project) { true }
+ let(:pagination) { {} }
+
+ subject { Gitlab::Json.parse(helper.project_members_list_data_json(project, presented_members, pagination)) }
before do
allow(helper).to receive(:project_project_member_path).with(project, ':id').and_return('/foo-bar/-/project_members/:id')
end
- it 'returns expected hash' do
- expect(helper.project_members_list_data_attributes(project, present_members(project_members))).to include({
- members: helper.project_members_data_json(project, present_members(project_members)),
+ it 'returns expected json' do
+ expected = {
member_path: '/foo-bar/-/project_members/:id',
source_id: project.id,
- can_manage_members: 'true'
- })
+ 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('members')
+ end
+
+ context 'when pagination is not available' do
+ it 'sets `pagination` attribute to expected json' do
+ expected = {
+ current_page: nil,
+ per_page: nil,
+ total_items: 2,
+ param_name: nil,
+ params: {}
+ }.as_json
+
+ expect(subject['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 } } }
+
+ it 'sets `pagination` attribute to expected json' do
+ expected = {
+ current_page: 1,
+ per_page: 1,
+ total_items: 2,
+ param_name: :page,
+ params: { search_groups: nil }
+ }.as_json
+
+ expect(subject['pagination']).to match(expected)
+ end
end
end
end
@@ -178,25 +214,33 @@ RSpec.describe Projects::ProjectMembersHelper do
let(:allow_admin_project) { true }
- describe '#project_group_links_data_json' do
- it 'matches json schema' do
- expect(helper.project_group_links_data_json(project_group_links)).to match_schema('group_link/project_group_links')
- end
- end
+ describe '#project_group_links_list_data_json' do
+ subject { Gitlab::Json.parse(helper.project_group_links_list_data_json(project, project_group_links)) }
- describe '#project_group_links_list_data_attributes' do
before do
allow(helper).to receive(:project_group_link_path).with(project, ':id').and_return('/foo-bar/-/group_links/:id')
allow(helper).to receive(:can?).with(current_user, :admin_project_member, project).and_return(true)
end
- it 'returns expected hash' do
- expect(helper.project_group_links_list_data_attributes(project, project_group_links)).to include({
- members: helper.project_group_links_data_json(project_group_links),
+ 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'
- })
+ 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
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 124cdcec05d..1804a9a99cf 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -390,149 +390,6 @@ RSpec.describe ProjectsHelper do
end
end
- describe '#get_project_nav_tabs' do
- before do
- allow(helper).to receive(:current_user).and_return(user)
- allow(helper).to receive(:can?) { true }
- end
-
- subject do
- helper.send(:get_project_nav_tabs, project, user)
- end
-
- context 'Security & Compliance tabs' do
- before do
- allow(helper).to receive(:can?).with(user, :read_security_configuration, project).and_return(can_read_security_configuration)
- end
-
- context 'when user cannot read security configuration' do
- let(:can_read_security_configuration) { false }
-
- it { is_expected.not_to include(:security_configuration) }
- end
-
- context 'when user can read security configuration' do
- let(:can_read_security_configuration) { true }
- let(:feature_flag_enabled) { true }
-
- it { is_expected.to include(:security_configuration) }
- end
- end
-
- context 'when builds feature is enabled' do
- before do
- allow(project).to receive(:builds_enabled?).and_return(true)
- end
-
- it "does include pipelines tab" do
- is_expected.to include(:pipelines)
- end
- end
-
- context 'when builds feature is disabled' do
- before do
- allow(project).to receive(:builds_enabled?).and_return(false)
- end
-
- context 'when user has access to builds' do
- it "does include pipelines tab" do
- is_expected.to include(:pipelines)
- end
- end
-
- context 'when user does not have access to builds' do
- before do
- allow(helper).to receive(:can?) { false }
- end
-
- it "does not include pipelines tab" do
- is_expected.not_to include(:pipelines)
- end
- end
- end
-
- context 'when project has external wiki' do
- it 'includes external wiki tab' do
- project.create_external_wiki_service(active: true, properties: { 'external_wiki_url' => 'https://gitlab.com' })
- project.reload
-
- is_expected.to include(:external_wiki)
- end
- end
-
- context 'when project does not have external wiki' do
- it 'does not include external wiki tab' do
- expect(project.external_wiki).to be_nil
- is_expected.not_to include(:external_wiki)
- end
- end
-
- context 'when project has confluence enabled' do
- before do
- allow(project).to receive(:has_confluence?).and_return(true)
- end
-
- it { is_expected.to include(:confluence) }
- it { is_expected.not_to include(:wiki) }
- end
-
- context 'when project does not have confluence enabled' do
- it { is_expected.not_to include(:confluence) }
- it { is_expected.to include(:wiki) }
- end
-
- context 'learn gitlab experiment' do
- context 'when it is enabled' do
- before do
- expect(helper).to receive(:learn_gitlab_experiment_enabled?).with(project).and_return(true)
- end
-
- it { is_expected.to include(:learn_gitlab) }
- end
-
- context 'when it is not enabled' do
- it { is_expected.not_to include(:learn_gitlab) }
- end
- end
- end
-
- describe '#can_view_operations_tab?' do
- before do
- allow(helper).to receive(:current_user).and_return(user)
- allow(helper).to receive(:can?).and_return(false)
- end
-
- subject { helper.send(:can_view_operations_tab?, user, project) }
-
- where(:ability) do
- [
- :metrics_dashboard,
- :read_alert_management_alert,
- :read_environment,
- :read_issue,
- :read_sentry_issue,
- :read_cluster
- ]
- end
-
- with_them do
- it 'includes operations tab' do
- allow(helper).to receive(:can?).with(user, ability, project).and_return(true)
-
- is_expected.to be(true)
- end
-
- context 'when operations feature is disabled' do
- it 'does not include operations tab' do
- allow(helper).to receive(:can?).with(user, ability, project).and_return(true)
- project.project_feature.update_attribute(:operations_access_level, ProjectFeature::DISABLED)
-
- is_expected.to be(false)
- end
- end
- end
- end
-
describe '#show_projects' do
let(:projects) do
Project.all
diff --git a/spec/helpers/registrations_helper_spec.rb b/spec/helpers/registrations_helper_spec.rb
new file mode 100644
index 00000000000..00d0a0850cd
--- /dev/null
+++ b/spec/helpers/registrations_helper_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe RegistrationsHelper do
+ using RSpec::Parameterized::TableSyntax
+
+ describe '#social_signin_enabled?' do
+ before do
+ allow(::Gitlab).to receive(:dev_env_or_com?).and_return(com)
+ allow(view).to receive(:omniauth_enabled?).and_return(omniauth_enabled)
+ allow(view).to receive(:button_based_providers_enabled?).and_return(button_based_providers_enabled)
+ allow(view).to receive(:devise_mapping).and_return(double(omniauthable?: omniauthable))
+ end
+
+ subject { helper.social_signin_enabled? }
+
+ where com: [true, false],
+ omniauth_enabled: [true, false],
+ omniauthable: [true, false],
+ button_based_providers_enabled: [true, false]
+
+ with_them do
+ let(:result) { com && omniauth_enabled && button_based_providers_enabled && omniauthable }
+
+ it { is_expected.to eq(result) }
+ end
+ end
+end
diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb
index f0f09408249..862fd58df04 100644
--- a/spec/helpers/users_helper_spec.rb
+++ b/spec/helpers/users_helper_spec.rb
@@ -136,6 +136,16 @@ RSpec.describe UsersHelper do
end
end
+ context 'with a banned user' do
+ it 'returns the banned badge' do
+ banned_user = create(:user, :banned)
+
+ badges = helper.user_badges_in_admin_section(banned_user)
+
+ expect(filter_ee_badges(badges)).to eq([text: 'Banned', variant: 'danger'])
+ end
+ end
+
context 'with an admin user' do
it "returns the admin badge" do
admin_user = create(:admin)
@@ -160,7 +170,7 @@ RSpec.describe UsersHelper do
it 'returns the "It\'s You" badge' do
badges = helper.user_badges_in_admin_section(user)
- expect(filter_ee_badges(badges)).to eq([text: "It's you!", variant: nil])
+ expect(filter_ee_badges(badges)).to eq([text: "It's you!", variant: "muted"])
end
end
diff --git a/spec/helpers/webpack_helper_spec.rb b/spec/helpers/webpack_helper_spec.rb
new file mode 100644
index 00000000000..f9386c99dc3
--- /dev/null
+++ b/spec/helpers/webpack_helper_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WebpackHelper do
+ let(:source) { 'foo.js' }
+ let(:asset_path) { "/assets/webpack/#{source}" }
+
+ describe '#prefetch_link_tag' do
+ it 'returns prefetch link tag' do
+ expect(helper.prefetch_link_tag(source)).to eq("<link rel=\"prefetch\" href=\"/#{source}\">")
+ end
+ end
+
+ describe '#webpack_preload_asset_tag' do
+ before do
+ allow(Gitlab::Webpack::Manifest).to receive(:asset_paths).and_return([asset_path])
+ end
+
+ it 'preloads the resource by default' do
+ expect(helper).to receive(:preload_link_tag).with(asset_path, {}).and_call_original
+
+ output = helper.webpack_preload_asset_tag(source)
+
+ expect(output).to eq("<link rel=\"preload\" href=\"#{asset_path}\" as=\"script\" type=\"text/javascript\">")
+ end
+
+ it 'prefetches the resource if explicitly asked' do
+ expect(helper).to receive(:prefetch_link_tag).with(asset_path).and_call_original
+
+ output = helper.webpack_preload_asset_tag(source, prefetch: true)
+
+ expect(output).to eq("<link rel=\"prefetch\" href=\"#{asset_path}\">")
+ end
+ end
+end
diff --git a/spec/helpers/whats_new_helper_spec.rb b/spec/helpers/whats_new_helper_spec.rb
index 0e4b4621560..9ae7ef38736 100644
--- a/spec/helpers/whats_new_helper_spec.rb
+++ b/spec/helpers/whats_new_helper_spec.rb
@@ -59,5 +59,62 @@ RSpec.describe WhatsNewHelper do
expect(subject).to be false
end
end
+
+ context 'depending on whats_new_variant' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:variant, :result) do
+ :all_tiers | true
+ :current_tier | true
+ :disabled | false
+ end
+
+ with_them do
+ it 'returns correct result depending on variant' do
+ allow(Gitlab).to receive(:dev_env_org_or_com?).and_return(true)
+ Gitlab::CurrentSettings.update!(whats_new_variant: ApplicationSetting.whats_new_variants[variant])
+
+ expect(subject).to eq(result)
+ end
+ end
+ end
+ end
+
+ describe '#whats_new_variants' do
+ it 'returns ApplicationSetting.whats_new_variants' do
+ expect(helper.whats_new_variants).to eq(ApplicationSetting.whats_new_variants)
+ end
+ end
+
+ describe '#whats_new_variants_label' do
+ let(:labels) do
+ [
+ helper.whats_new_variants_label('all_tiers'),
+ helper.whats_new_variants_label('current_tier'),
+ helper.whats_new_variants_label('disabled'),
+ helper.whats_new_variants_label(nil)
+ ]
+ end
+
+ it 'returns different labels depending on variant' do
+ expect(labels.uniq.size).to eq(labels.size)
+ expect(labels[3]).to be_nil
+ end
+ end
+
+ describe '#whats_new_variants_description' do
+ let(:descriptions) do
+ [
+ helper.whats_new_variants_description('all_tiers'),
+ helper.whats_new_variants_description('current_tier'),
+ helper.whats_new_variants_description('disabled'),
+ helper.whats_new_variants_description(nil)
+ ]
+ end
+
+ it 'returns different descriptions depending on variant' do
+ expect(descriptions.uniq.size).to eq(descriptions.size)
+ expect(descriptions[3]).to be_nil
+ end
end
end