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/application_settings/settings_helper_spec.rb20
-rw-r--r--spec/helpers/admin/broadcast_messages_helper_spec.rb (renamed from spec/helpers/broadcast_messages_helper_spec.rb)34
-rw-r--r--spec/helpers/admin/deploy_key_helper_spec.rb4
-rw-r--r--spec/helpers/application_helper_spec.rb46
-rw-r--r--spec/helpers/application_settings_helper_spec.rb4
-rw-r--r--spec/helpers/ci/runners_helper_spec.rb79
-rw-r--r--spec/helpers/ci/variables_helper_spec.rb62
-rw-r--r--spec/helpers/commits_helper_spec.rb50
-rw-r--r--spec/helpers/environments_helper_spec.rb3
-rw-r--r--spec/helpers/events_helper_spec.rb155
-rw-r--r--spec/helpers/integrations_helper_spec.rb3
-rw-r--r--spec/helpers/issuables_helper_spec.rb82
-rw-r--r--spec/helpers/issues_helper_spec.rb13
-rw-r--r--spec/helpers/labels_helper_spec.rb15
-rw-r--r--spec/helpers/markup_helper_spec.rb6
-rw-r--r--spec/helpers/nav_helper_spec.rb36
-rw-r--r--spec/helpers/notes_helper_spec.rb13
-rw-r--r--spec/helpers/profiles_helper_spec.rb35
-rw-r--r--spec/helpers/projects/observability_helper_spec.rb22
-rw-r--r--spec/helpers/projects_helper_spec.rb117
-rw-r--r--spec/helpers/sessions_helper_spec.rb66
-rw-r--r--spec/helpers/sidebars_helper_spec.rb60
-rw-r--r--spec/helpers/snippets_helper_spec.rb6
-rw-r--r--spec/helpers/time_helper_spec.rb2
-rw-r--r--spec/helpers/todos_helper_spec.rb1
-rw-r--r--spec/helpers/tree_helper_spec.rb4
-rw-r--r--spec/helpers/users_helper_spec.rb126
27 files changed, 841 insertions, 223 deletions
diff --git a/spec/helpers/admin/application_settings/settings_helper_spec.rb b/spec/helpers/admin/application_settings/settings_helper_spec.rb
index b008f52c0eb..9981e0d12bd 100644
--- a/spec/helpers/admin/application_settings/settings_helper_spec.rb
+++ b/spec/helpers/admin/application_settings/settings_helper_spec.rb
@@ -31,24 +31,4 @@ RSpec.describe Admin::ApplicationSettings::SettingsHelper do
})
end
end
-
- describe 'Code Suggestions for Self-Managed instances', feature_category: :code_suggestions do
- describe '#code_suggestions_description' do
- subject { helper.code_suggestions_description }
-
- it { is_expected.to include 'https://docs.gitlab.com/ee/user/project/repository/code_suggestions.html' }
- end
-
- describe '#code_suggestions_token_explanation' do
- subject { helper.code_suggestions_token_explanation }
-
- it { is_expected.to include 'https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#create-a-personal-access-token' }
- end
-
- describe '#code_suggestions_agreement' do
- subject { helper.code_suggestions_agreement }
-
- it { is_expected.to include 'https://about.gitlab.com/handbook/legal/testing-agreement/' }
- end
- end
end
diff --git a/spec/helpers/broadcast_messages_helper_spec.rb b/spec/helpers/admin/broadcast_messages_helper_spec.rb
index 05e745e249e..434b79d5271 100644
--- a/spec/helpers/broadcast_messages_helper_spec.rb
+++ b/spec/helpers/admin/broadcast_messages_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BroadcastMessagesHelper, feature_category: :onboarding do
+RSpec.describe Admin::BroadcastMessagesHelper, feature_category: :onboarding do
include Gitlab::Routing.url_helpers
let_it_be(:user) { create(:user) }
@@ -102,7 +102,7 @@ RSpec.describe BroadcastMessagesHelper, feature_category: :onboarding do
end
describe '#broadcast_message' do
- let(:current_broadcast_message) { BroadcastMessage.new(message: 'Current Message') }
+ let(:current_broadcast_message) { System::BroadcastMessage.new(message: 'Current Message') }
it 'returns nil when no current message' do
expect(helper.broadcast_message(nil)).to be_nil
@@ -133,6 +133,36 @@ RSpec.describe BroadcastMessagesHelper, feature_category: :onboarding do
end
end
+ describe '#render_broadcast_message' do
+ context 'when message is banner' do
+ let_it_be(:broadcast_message) do
+ System::BroadcastMessage.new(message: 'Current Message', broadcast_type: :banner)
+ end.freeze
+
+ it 'renders broadcast message' do
+ expect(helper.render_broadcast_message(broadcast_message)).to eq("<p>Current Message</p>")
+ end
+ end
+
+ context 'when message is notification' do
+ let_it_be(:broadcast_message) do
+ System::BroadcastMessage.new(message: 'Current Message', broadcast_type: :notification)
+ end.freeze
+
+ it 'renders broadcast message' do
+ expect(helper.render_broadcast_message(broadcast_message)).to eq("<p>Current Message</p>")
+ end
+ end
+ end
+
+ describe '#target_access_levels_display' do
+ let_it_be(:access_levels) { [Gitlab::Access::REPORTER, Gitlab::Access::DEVELOPER] }.freeze
+
+ it 'joins access levels' do
+ expect(helper.target_access_levels_display(access_levels)).to eq("Reporter, Developer")
+ end
+ end
+
describe '#admin_broadcast_messages_data' do
let(:starts_at) { 1.day.ago }
let(:ends_at) { 1.day.from_now }
diff --git a/spec/helpers/admin/deploy_key_helper_spec.rb b/spec/helpers/admin/deploy_key_helper_spec.rb
index ca951ccf485..0c07ecf90ce 100644
--- a/spec/helpers/admin/deploy_key_helper_spec.rb
+++ b/spec/helpers/admin/deploy_key_helper_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Admin::DeployKeyHelper do
let_it_be(:edit_path) { '/admin/deploy_keys/:id/edit' }
let_it_be(:delete_path) { '/admin/deploy_keys/:id' }
let_it_be(:create_path) { '/admin/deploy_keys/new' }
- let_it_be(:empty_state_svg_path) { '/assets/illustrations/empty-state/empty-deploy-keys-lg.svg' }
+ let_it_be(:empty_state_svg_path) { '/assets/illustrations/empty-state/empty-access-token-md.svg' }
subject(:result) { helper.admin_deploy_keys_data }
@@ -15,7 +15,7 @@ RSpec.describe Admin::DeployKeyHelper do
expect(helper).to receive(:edit_admin_deploy_key_path).with(':id').and_return(edit_path)
expect(helper).to receive(:admin_deploy_key_path).with(':id').and_return(delete_path)
expect(helper).to receive(:new_admin_deploy_key_path).and_return(create_path)
- expect(helper).to receive(:image_path).with('illustrations/empty-state/empty-deploy-keys-lg.svg').and_return(empty_state_svg_path)
+ expect(helper).to receive(:image_path).with('illustrations/empty-state/empty-access-token-md.svg').and_return(empty_state_svg_path)
expect(result).to eq({
edit_path: edit_path,
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 6ef57f8e22c..ad81c125055 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -845,4 +845,50 @@ RSpec.describe ApplicationHelper do
end
end
end
+
+ describe '#hidden_resource_icon', feature_category: :insider_threat do
+ let_it_be(:mock_svg) { '<svg></svg>'.html_safe }
+
+ shared_examples 'returns icon with tooltip' do
+ before do
+ allow(helper).to receive(:sprite_icon).with('spam', css_class: 'gl-vertical-align-text-bottom').and_return(mock_svg)
+ end
+
+ it 'returns icon with tooltip' do
+ result = helper.hidden_resource_icon(resource)
+ expect(result).to eq("<span class=\"has-tooltip\" title=\"#{expected_title}\">#{mock_svg}</span>")
+ end
+ end
+
+ context 'when resource is an issue' do
+ let_it_be(:resource) { build(:issue) }
+ let(:expected_title) { 'This issue is hidden because its author has been banned' }
+
+ it_behaves_like 'returns icon with tooltip'
+ end
+
+ context 'when resource is a merge request' do
+ let_it_be(:resource) { build(:merge_request) }
+ let(:expected_title) { 'This merge request is hidden because its author has been banned' }
+
+ it_behaves_like 'returns icon with tooltip'
+ end
+
+ context 'when resource is a project' do
+ let_it_be(:resource) { build(:project) }
+ let(:expected_title) { 'This project is hidden because its creator has been banned' }
+
+ it_behaves_like 'returns icon with tooltip'
+ end
+
+ context 'when css_class is provided' do
+ let_it_be(:resource) { build(:issue) }
+
+ it 'passes the value to sprite_icon' do
+ expect(helper).to receive(:sprite_icon).with('spam', css_class: 'gl-vertical-align-text-bottom extra-class').and_return(mock_svg)
+
+ helper.hidden_resource_icon(resource, css_class: 'extra-class')
+ end
+ end
+ end
end
diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb
index f924704ab54..9d591164547 100644
--- a/spec/helpers/application_settings_helper_spec.rb
+++ b/spec/helpers/application_settings_helper_spec.rb
@@ -74,6 +74,10 @@ RSpec.describe ApplicationSettingsHelper do
expect(helper.visible_attributes).to include(*params)
end
+ it 'contains :namespace_aggregation_schedule_lease_duration_in_seconds' do
+ expect(helper.visible_attributes).to include(:namespace_aggregation_schedule_lease_duration_in_seconds)
+ end
+
context 'when on SaaS', :saas do
it 'does not contain :deactivate_dormant_users' do
expect(helper.visible_attributes).not_to include(:deactivate_dormant_users)
diff --git a/spec/helpers/ci/runners_helper_spec.rb b/spec/helpers/ci/runners_helper_spec.rb
index c170d7fae67..febdc3bab65 100644
--- a/spec/helpers/ci/runners_helper_spec.rb
+++ b/spec/helpers/ci/runners_helper_spec.rb
@@ -83,22 +83,9 @@ RSpec.describe Ci::RunnersHelper, feature_category: :runner_fleet do
end
describe '#admin_runners_data_attributes' do
- let_it_be(:admin) { create(:user, :admin) }
- let_it_be(:instance_runner) { create(:ci_runner, :instance) }
- let_it_be(:project_runner) { create(:ci_runner, :project) }
+ subject { helper.admin_runners_data_attributes }
- before do
- allow(helper).to receive(:current_user).and_return(admin)
- end
-
- it 'returns the data in format' do
- expect(helper.admin_runners_data_attributes).to include(
- runner_install_help_page: 'https://docs.gitlab.com/runner/install/',
- registration_token: Gitlab::CurrentSettings.runners_registration_token,
- online_contact_timeout_secs: 7200,
- stale_timeout_secs: 7889238
- )
- end
+ it_behaves_like 'admin_runners_data_attributes contains data'
end
describe '#group_shared_runners_settings_data' do
@@ -115,12 +102,19 @@ RSpec.describe Ci::RunnersHelper, feature_category: :runner_fleet do
}
end
+ before do
+ allow(helper).to receive(:can?).with(user, :admin_group, parent).and_return(true)
+ end
+
it 'returns group data for top level group' do
result = {
group_id: parent.id,
group_name: parent.name,
group_is_empty: 'false',
shared_runners_setting: Namespace::SR_ENABLED,
+
+ parent_name: nil,
+ parent_settings_path: nil,
parent_shared_runners_setting: nil
}.merge(runner_constants)
@@ -133,7 +127,27 @@ RSpec.describe Ci::RunnersHelper, feature_category: :runner_fleet do
group_name: group.name,
group_is_empty: 'true',
shared_runners_setting: Namespace::SR_DISABLED_AND_UNOVERRIDABLE,
- parent_shared_runners_setting: Namespace::SR_ENABLED
+
+ parent_shared_runners_setting: Namespace::SR_ENABLED,
+ parent_name: parent.name,
+ parent_settings_path: group_settings_ci_cd_path(group.parent, anchor: 'runners-settings')
+ }.merge(runner_constants)
+
+ expect(helper.group_shared_runners_settings_data(group)).to eq result
+ end
+
+ it 'returns groups data for child group with no access to parent' do
+ allow(helper).to receive(:can?).with(user, :admin_group, parent).and_return(false)
+
+ result = {
+ group_id: group.id,
+ group_name: group.name,
+ group_is_empty: 'true',
+ shared_runners_setting: Namespace::SR_DISABLED_AND_UNOVERRIDABLE,
+
+ parent_shared_runners_setting: Namespace::SR_ENABLED,
+ parent_name: nil,
+ parent_settings_path: nil
}.merge(runner_constants)
expect(helper.group_shared_runners_settings_data(group)).to eq result
@@ -145,7 +159,10 @@ RSpec.describe Ci::RunnersHelper, feature_category: :runner_fleet do
group_name: group_with_project.name,
group_is_empty: 'false',
shared_runners_setting: Namespace::SR_ENABLED,
- parent_shared_runners_setting: Namespace::SR_ENABLED
+
+ parent_shared_runners_setting: Namespace::SR_ENABLED,
+ parent_name: parent.name,
+ parent_settings_path: group_settings_ci_cd_path(group.parent, anchor: 'runners-settings')
}.merge(runner_constants)
expect(helper.group_shared_runners_settings_data(group_with_project)).to eq result
@@ -190,8 +207,28 @@ RSpec.describe Ci::RunnersHelper, feature_category: :runner_fleet do
context 'when project has runners' do
it 'returns the correct value for is_enabled' do
+ allow(helper).to receive(:can?).with(user, :admin_group, group).and_return(false)
+
+ data = helper.toggle_shared_runners_settings_data(project_with_runners)
+
+ expect(data).to include(
+ is_enabled: 'true',
+ group_name: nil,
+ group_settings_path: nil
+ )
+ end
+ end
+
+ context 'when group can be configured by user' do
+ it 'returns values to configure group' do
+ allow(helper).to receive(:can?).with(user, :admin_group, group).and_return(true)
+
data = helper.toggle_shared_runners_settings_data(project_with_runners)
- expect(data[:is_enabled]).to eq("true")
+
+ expect(data).to include(
+ group_name: group.name,
+ group_settings_path: group_settings_ci_cd_path(group, anchor: 'runners-settings')
+ )
end
end
@@ -218,9 +255,9 @@ RSpec.describe Ci::RunnersHelper, feature_category: :runner_fleet do
using RSpec::Parameterized::TableSyntax
where(:shared_runners_setting, :is_disabled_and_unoverridable) do
- :shared_runners_enabled | "false"
- :disabled_and_overridable | "false"
- :disabled_and_unoverridable | "true"
+ :shared_runners_enabled | "false"
+ :shared_runners_disabled_and_overridable | "false"
+ :shared_runners_disabled_and_unoverridable | "true"
end
with_them do
diff --git a/spec/helpers/ci/variables_helper_spec.rb b/spec/helpers/ci/variables_helper_spec.rb
index 9c3236ace72..13970dd95b4 100644
--- a/spec/helpers/ci/variables_helper_spec.rb
+++ b/spec/helpers/ci/variables_helper_spec.rb
@@ -3,9 +3,71 @@
require 'spec_helper'
RSpec.describe Ci::VariablesHelper, feature_category: :secrets_management do
+ describe '#create_deploy_token_path' do
+ let_it_be(:group) { build_stubbed(:group) }
+ let_it_be(:project) { build_stubbed(:project) }
+
+ it 'returns the project deploy token path' do
+ expect(helper.create_deploy_token_path(project)).to eq(
+ create_deploy_token_project_settings_repository_path(project, {})
+ )
+ end
+
+ it 'returns the group deploy token path' do
+ expect(helper.create_deploy_token_path(group)).to eq(
+ create_deploy_token_group_settings_repository_path(group, {})
+ )
+ end
+ end
+
+ describe '#ci_variable_protected?' do
+ let(:variable) { build_stubbed(:ci_variable, key: 'test_key', value: 'test_value', protected: true) }
+
+ context 'when variable is provided and only_key_value is false' do
+ it 'expect ci_variable_protected? to return true' do
+ expect(helper.ci_variable_protected?(variable, false)).to eq(true)
+ end
+ end
+
+ context 'when variable is not provided / provided and only_key_value is true' do
+ it 'is equal to the value of ci_variable_protected_by_default?' do
+ expect(helper.ci_variable_protected?(nil, true)).to eq(
+ helper.ci_variable_protected_by_default?
+ )
+
+ expect(helper.ci_variable_protected?(variable, true)).to eq(
+ helper.ci_variable_protected_by_default?
+ )
+ end
+ end
+ end
+
+ describe '#ci_variable_masked?' do
+ let(:variable) { build_stubbed(:ci_variable, key: 'test_key', value: 'test_value', masked: true) }
+
+ context 'when variable is provided and only_key_value is false' do
+ it 'expect ci_variable_masked? to return true' do
+ expect(helper.ci_variable_masked?(variable, false)).to eq(true)
+ end
+ end
+
+ context 'when variable is not provided / provided and only_key_value is true' do
+ it 'expect ci_variable_masked? to return false' do
+ expect(helper.ci_variable_masked?(nil, true)).to eq(false)
+ expect(helper.ci_variable_masked?(variable, true)).to eq(false)
+ end
+ end
+ end
+
describe '#ci_variable_maskable_raw_regex' do
it 'converts to a javascript regex' do
expect(helper.ci_variable_maskable_raw_regex).to eq("^\\S{8,}$")
end
end
+
+ describe '#ci_variable_maskable_regex' do
+ it 'converts to a javascript regex' do
+ expect(helper.ci_variable_maskable_regex).to eq("^[a-zA-Z0-9_+=/@:.~-]{8,}$")
+ end
+ end
end
diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb
index 2d06f42dee4..49adba22ebe 100644
--- a/spec/helpers/commits_helper_spec.rb
+++ b/spec/helpers/commits_helper_spec.rb
@@ -91,22 +91,22 @@ RSpec.describe CommitsHelper do
let(:node) { Nokogiri::HTML.parse(helper.diff_mode_swap_button(keyword, 'abc')).at_css('a') }
context 'for rendered' do
- it 'renders the correct select-rendered button' do
+ it 'renders the correct select-rendered button', :aggregate_failures do
expect(node[:title]).to eq('Display rendered diff')
expect(node['data-file-hash']).to eq('abc')
expect(node['data-diff-toggle-entity']).to eq('renderedButton')
- expect(node.xpath("//a/svg")[0]["data-testid"]).to eq('doc-text-icon')
+ expect(node.xpath("//a/span/svg")[0]["data-testid"]).to eq('doc-text-icon')
end
end
context 'for raw' do
let(:keyword) { 'raw' }
- it 'renders the correct select-raw button' do
+ it 'renders the correct select-raw button', :aggregate_failures do
expect(node[:title]).to eq('Display raw diff')
expect(node['data-file-hash']).to eq('abc')
expect(node['data-diff-toggle-entity']).to eq('rawButton')
- expect(node.xpath("//a/svg")[0]["data-testid"]).to eq('doc-code-icon')
+ expect(node.xpath("//a/span/svg")[0]["data-testid"]).to eq('doc-code-icon')
end
end
end
@@ -357,4 +357,46 @@ RSpec.describe CommitsHelper do
it { is_expected.to eq(expected_path) }
end
+
+ describe '#local_committed_date' do
+ let(:commit) { build(:commit, committed_date: time) }
+ let(:user) { build(:user) }
+ let(:time) { Time.find_zone('UTC').parse('2023-01-01') }
+
+ subject { helper.local_committed_date(commit, user).to_s }
+
+ it { is_expected.to eq('2023-01-01') }
+
+ context 'when user has a custom timezone' do
+ let(:user) { build(:user, timezone: 'America/Mexico_City') }
+
+ it 'selects timezone of the user' do
+ is_expected.to eq('2022-12-31')
+ end
+ end
+
+ context "when user doesn't have a preferred timezone" do
+ let(:user) { build(:user, timezone: nil) }
+
+ it 'uses system timezone' do
+ is_expected.to eq('2023-01-01')
+ end
+ end
+
+ context 'when user timezone is not supported' do
+ let(:user) { build(:user, timezone: 'unknown') }
+
+ it 'uses system timezone' do
+ is_expected.to eq('2023-01-01')
+ end
+ end
+
+ context 'when user is missing' do
+ let(:user) { nil }
+
+ it 'uses system timezone' do
+ is_expected.to eq('2023-01-01')
+ end
+ end
+ end
end
diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb
index b69d6022e70..c0c729f2b67 100644
--- a/spec/helpers/environments_helper_spec.rb
+++ b/spec/helpers/environments_helper_spec.rb
@@ -41,8 +41,7 @@ RSpec.describe EnvironmentsHelper, feature_category: :environment_management do
'custom_metrics_available' => 'true',
'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)
+ 'can_access_operations_settings' => 'true'
)
end
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index 39901047b0f..6ffca876361 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -2,10 +2,20 @@
require 'spec_helper'
-RSpec.describe EventsHelper do
+# Persisting records is required because Event#target's AR scope.
+# We are trying hard to minimize record creations by:
+# * Using `let_it_be`
+# * Factory defaults via `create_default` + `factory_default: :keep`
+#
+# rubocop:disable RSpec/FactoryBot/AvoidCreate
+RSpec.describe EventsHelper, factory_default: :keep, feature_category: :user_profile do
include Gitlab::Routing
include Banzai::Filter::OutputSafety
+ let_it_be(:project) { create_default(:project).freeze }
+ let_it_be(:project_with_repo) { create(:project, :public, :repository).freeze }
+ let_it_be(:user) { create_default(:user).freeze }
+
describe '#link_to_author' do
let(:user) { create(:user) }
let(:event) { create(:event, author: user) }
@@ -40,9 +50,8 @@ RSpec.describe EventsHelper do
end
context 'when target is not a work item' do
- let(:project) { create(:project) }
- let(:issue) { create(:issue, project: project) }
- let(:event) { create(:event, target: issue, project: project) }
+ let(:issue) { create(:issue) }
+ let(:event) { create(:event, target: issue) }
it { is_expected.to eq([project, issue]) }
end
@@ -51,7 +60,7 @@ RSpec.describe EventsHelper do
describe '#localized_action_name' do
it 'handles all valid design events' do
created, updated, destroyed = %i[created updated destroyed].map do |trait|
- event = build(:design_event, trait)
+ event = build_stubbed(:design_event, trait)
helper.localized_action_name(event)
end
@@ -60,44 +69,46 @@ RSpec.describe EventsHelper do
expect(destroyed).to eq(_('removed'))
end
- context 'handles correct base actions' do
+ describe 'handles correct base actions' do
using RSpec::Parameterized::TableSyntax
- where(:trait, :localized_action_name) do
- :created | s_('Event|created')
- :updated | s_('Event|opened')
- :closed | s_('Event|closed')
- :reopened | s_('Event|opened')
- :commented | s_('Event|commented on')
- :merged | s_('Event|accepted')
- :joined | s_('Event|joined')
- :left | s_('Event|left')
- :destroyed | s_('Event|destroyed')
- :expired | s_('Event|removed due to membership expiration from')
- :approved | s_('Event|approved')
+ where(:trait, :localized_action_key) do
+ :created | 'Event|created'
+ :updated | 'Event|opened'
+ :closed | 'Event|closed'
+ :reopened | 'Event|opened'
+ :commented | 'Event|commented on'
+ :merged | 'Event|accepted'
+ :joined | 'Event|joined'
+ :left | 'Event|left'
+ :destroyed | 'Event|destroyed'
+ :expired | 'Event|removed due to membership expiration from'
+ :approved | 'Event|approved'
end
with_them do
it 'with correct name and method' do
- event = build(:event, trait)
+ Gitlab::I18n.with_locale(:de) do
+ event = build_stubbed(:event, trait)
- expect(helper.localized_action_name(event)).to eq(localized_action_name)
+ expect(helper.localized_action_name(event)).to eq(s_(localized_action_key))
+ end
end
end
end
end
describe '#event_commit_title' do
- let(:message) { 'foo & bar ' + 'A' * 70 + '\n' + 'B' * 80 }
+ let(:message) { "foo & bar #{'A' * 70}\\n#{'B' * 80}" }
subject { helper.event_commit_title(message) }
it 'returns the first line, truncated to 70 chars' do
- is_expected.to eq(message[0..66] + "...")
+ is_expected.to eq("#{message[0..66]}...")
end
it 'is not html-safe' do
- is_expected.not_to be_a(ActiveSupport::SafeBuffer)
+ is_expected.not_to be_html_safe
end
it 'handles empty strings' do
@@ -115,9 +126,8 @@ RSpec.describe EventsHelper do
describe '#event_feed_url' do
let(:event) { create(:event).present }
- let(:project) { create(:project, :public, :repository) }
- context 'issue' do
+ context 'for issue' do
before do
event.target = create(:issue)
end
@@ -131,9 +141,9 @@ RSpec.describe EventsHelper do
end
end
- context 'merge request' do
+ context 'for merge request' do
before do
- event.target = create(:merge_request)
+ event.target = create(:merge_request, source_project: project_with_repo)
end
it 'returns the project merge request url' do
@@ -146,7 +156,7 @@ RSpec.describe EventsHelper do
end
it 'returns project commit url' do
- event.target = create(:note_on_commit, project: project)
+ event.target = create(:note_on_commit, project: project_with_repo)
expect(helper.event_feed_url(event)).to eq(project_commit_url(event.project, event.note_target))
end
@@ -158,7 +168,6 @@ RSpec.describe EventsHelper do
end
it 'returns project url' do
- event.project = project
event.action = 1
expect(helper.event_feed_url(event)).to eq(project_url(event.project))
@@ -173,7 +182,8 @@ RSpec.describe EventsHelper do
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)
+ 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
@@ -229,8 +239,8 @@ RSpec.describe EventsHelper do
end
end
- describe 'event_wiki_page_target_url' do
- let(:project) { create(:project) }
+ describe '#event_wiki_page_target_url' do
+ let_it_be_with_reload(:project) { create(:project) }
let(:wiki_page) { create(:wiki_page, wiki: create(:project_wiki, project: project)) }
let(:event) { create(:wiki_page_event, project: project, wiki_page: wiki_page) }
@@ -240,7 +250,7 @@ RSpec.describe EventsHelper do
expect(helper.event_wiki_page_target_url(event)).to eq(url)
end
- context 'there is no canonical slug' do
+ context 'without canonical slug' do
let(:event) { create(:wiki_page_event, project: project) }
before do
@@ -274,14 +284,13 @@ RSpec.describe EventsHelper do
end
describe '#event_note_target_url' do
- let(:project) { create(:project, :public, :repository) }
- let(:event) { create(:event, project: project) }
+ let_it_be(:event) { create(:event) }
let(:project_base_url) { namespace_project_url(namespace_id: project.namespace, id: project) }
subject { helper.event_note_target_url(event) }
it 'returns a commit note url' do
- event.target = create(:note_on_commit, note: '+1 from me')
+ event.target = create(:note_on_commit, project: project_with_repo, note: '+1 from me')
expect(subject).to eq("#{project_base_url}/-/commit/#{event.target.commit_id}#note_#{event.target.id}")
end
@@ -289,7 +298,8 @@ RSpec.describe EventsHelper do
it 'returns a project snippet note url' do
event.target = create(:note_on_project_snippet, note: 'keep going')
- expect(subject).to eq("#{project_snippet_url(event.note_target.project, event.note_target)}#note_#{event.target.id}")
+ expect(subject).to eq("#{project_snippet_url(event.note_target.project,
+ event.note_target)}#note_#{event.target.id}")
end
it 'returns a personal snippet note url' do
@@ -311,7 +321,7 @@ RSpec.describe EventsHelper do
end
context 'for design note events' do
- let(:event) { create(:event, :for_design, project: project) }
+ let(:event) { create(:event, :for_design) }
it 'returns an appropriate URL' do
iid = event.note_target.issue.iid
@@ -326,54 +336,62 @@ RSpec.describe EventsHelper do
describe '#event_filter_visible' do
include DesignManagementTestHelpers
- let_it_be(:project) { create(:project) }
- let_it_be(:current_user) { create(:user) }
-
subject { helper.event_filter_visible(key) }
before do
enable_design_management
- project.add_reporter(current_user)
- allow(helper).to receive(:current_user).and_return(current_user)
+ allow(helper).to receive(:current_user).and_return(user)
end
- def disable_read_design_activity(object)
+ def can_read_design_activity(object, ability)
allow(Ability).to receive(:allowed?)
- .with(current_user, :read_design_activity, eq(object))
- .and_return(false)
+ .with(user, :read_design_activity, eq(object))
+ .and_return(ability)
end
context 'for :designs' do
let(:key) { :designs }
- context 'there is no relevant instance variable' do
+ context 'without relevant instance variable' do
it { is_expected.to be(true) }
end
- context 'a project has been assigned' do
+ context 'with assigned project' do
before do
assign(:project, project)
end
- it { is_expected.to be(true) }
+ context 'with permission' do
+ before do
+ can_read_design_activity(project, true)
+ end
+
+ it { is_expected.to be(true) }
+ end
- context 'the current user cannot read design activity' do
+ context 'without permission' do
before do
- disable_read_design_activity(project)
+ can_read_design_activity(project, false)
end
it { is_expected.to be(false) }
end
end
- context 'projects have been assigned' do
+ context 'with projects assigned' do
before do
- assign(:projects, Project.where(id: project.id))
+ assign(:projects, Project.id_in(project))
end
- it { is_expected.to be(true) }
+ context 'with permission' do
+ before do
+ can_read_design_activity(project, true)
+ end
+
+ it { is_expected.to be(true) }
+ end
- context 'the collection is empty' do
+ context 'with empty collection' do
before do
assign(:projects, Project.none)
end
@@ -381,36 +399,40 @@ RSpec.describe EventsHelper do
it { is_expected.to be(false) }
end
- context 'the current user cannot read design activity' do
+ context 'without permission' do
before do
- disable_read_design_activity(project)
+ can_read_design_activity(project, false)
end
it { is_expected.to be(false) }
end
end
- context 'a group has been assigned' do
+ context 'with group assigned' do
let_it_be(:group) { create(:group) }
before do
assign(:group, group)
end
- context 'there are no projects in the group' do
+ context 'without projects in the group' do
it { is_expected.to be(false) }
end
- context 'the group has at least one project' do
- before do
- create(:project_group_link, project: project, group: group)
- end
+ context 'with at least one project in the project' do
+ let_it_be(:group_link) { create(:project_group_link, group: group) }
- it { is_expected.to be(true) }
+ context 'with permission' do
+ before do
+ can_read_design_activity(group, true)
+ end
+
+ it { is_expected.to be(true) }
+ end
- context 'the current user cannot read design activity' do
+ context 'without permission' do
before do
- disable_read_design_activity(group)
+ can_read_design_activity(group, false)
end
it { is_expected.to be(false) }
@@ -420,3 +442,4 @@ RSpec.describe EventsHelper do
end
end
end
+# rubocop:enable RSpec/FactoryBot/AvoidCreate
diff --git a/spec/helpers/integrations_helper_spec.rb b/spec/helpers/integrations_helper_spec.rb
index f481611b2a2..6c5a489e664 100644
--- a/spec/helpers/integrations_helper_spec.rb
+++ b/spec/helpers/integrations_helper_spec.rb
@@ -271,6 +271,7 @@ RSpec.describe IntegrationsHelper, feature_category: :integrations do
"test_case" | _('Test case')
"requirement" | _('Requirement')
"task" | _('Task')
+ "ticket" | _('Service Desk Ticket')
end
with_them do
@@ -285,7 +286,7 @@ RSpec.describe IntegrationsHelper, feature_category: :integrations do
end
it "only consider these enumeration values are valid" do
- expected_valid_types = %w[issue incident test_case requirement task objective key_result]
+ expected_valid_types = %w[issue incident test_case requirement task objective key_result epic ticket]
expect(WorkItems::Type.base_types.keys).to contain_exactly(*expected_valid_types)
end
end
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index a2b8ee061bb..7b5537c54cc 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -524,6 +524,64 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
end
end
end
+
+ describe '#duplicatedToIssueUrl' do
+ let(:issue) { create(:issue, author: user) }
+
+ before do
+ assign(:project, issue.project)
+ end
+
+ context 'when issue is duplicated' do
+ before do
+ allow(issue).to receive(:duplicated?).and_return(true)
+ allow(issue).to receive(:duplicated_to).and_return(issue)
+ end
+
+ it 'returns url' do
+ expect(helper.issuable_initial_data(issue)[:duplicatedToIssueUrl]).to be_truthy
+ end
+ end
+
+ context 'when issue is not duplicated' do
+ before do
+ allow(issue).to receive(:duplicated?).and_return(false)
+ end
+
+ it 'returns nil' do
+ expect(helper.issuable_initial_data(issue)[:duplicatedToIssueUrl]).to be_nil
+ end
+ end
+ end
+
+ describe '#movedToIssueUrl' do
+ let(:issue) { create(:issue, author: user) }
+
+ before do
+ assign(:project, issue.project)
+ end
+
+ context 'when issue is moved' do
+ before do
+ allow(issue).to receive(:moved?).and_return(true)
+ allow(issue).to receive(:moved_to).and_return(issue)
+ end
+
+ it 'returns url' do
+ expect(helper.issuable_initial_data(issue)[:movedToIssueUrl]).to be_truthy
+ end
+ end
+
+ context 'when issue is not moved' do
+ before do
+ allow(issue).to receive(:moved?).and_return(false)
+ end
+
+ it 'returns nil' do
+ expect(helper.issuable_initial_data(issue)[:movedToIssueUrl]).to be_nil
+ end
+ end
+ end
end
describe '#assignee_sidebar_data' do
@@ -674,30 +732,6 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
end
end
- describe '#hidden_issuable_icon', feature_category: :insider_threat do
- let_it_be(:mock_svg) { '<svg></svg>'.html_safe }
-
- before do
- allow(helper).to receive(:sprite_icon).and_return(mock_svg)
- end
-
- context 'when issuable is an issue' do
- let_it_be(:issuable) { build(:issue) }
-
- it 'returns icon with tooltip' do
- expect(helper.hidden_issuable_icon(issuable)).to eq("<span class=\"has-tooltip\" title=\"This issue is hidden because its author has been banned\">#{mock_svg}</span>")
- end
- end
-
- context 'when issuable is a merge request' do
- let_it_be(:issuable) { build(:merge_request) }
-
- it 'returns icon with tooltip' do
- expect(helper.hidden_issuable_icon(issuable)).to eq("<span class=\"has-tooltip\" title=\"This merge request is hidden because its author has been banned\">#{mock_svg}</span>")
- end
- end
- end
-
describe '#issuable_type_selector_data' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index ba323140720..0cde9aeac8d 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -486,23 +486,26 @@ RSpec.describe IssuesHelper do
end
describe '#hidden_issue_icon' do
- let_it_be(:banned_user) { build(:user, :banned) }
- let_it_be(:hidden_issue) { build(:issue, author: banned_user) }
let_it_be(:mock_svg) { '<svg></svg>'.html_safe }
before do
- allow(helper).to receive(:sprite_icon).and_return(mock_svg)
+ allow(helper).to receive(:hidden_resource_icon).with(resource).and_return(mock_svg)
end
context 'when issue is hidden' do
+ let_it_be(:banned_user) { build(:user, :banned) }
+ let_it_be(:resource) { build(:issue, author: banned_user) }
+
it 'returns icon with tooltip' do
- expect(helper.hidden_issue_icon(hidden_issue)).to eq("<span class=\"has-tooltip\" title=\"This issue is hidden because its author has been banned\">#{mock_svg}</span>")
+ expect(helper.hidden_issue_icon(resource)).to eq(mock_svg)
end
end
context 'when issue is not hidden' do
+ let_it_be(:resource) { issue }
+
it 'returns `nil`' do
- expect(helper.hidden_issue_icon(issue)).to be_nil
+ expect(helper.hidden_issue_icon(resource)).to be_nil
end
end
end
diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb
index b4549630813..4877ab1ff03 100644
--- a/spec/helpers/labels_helper_spec.rb
+++ b/spec/helpers/labels_helper_spec.rb
@@ -275,9 +275,18 @@ RSpec.describe LabelsHelper do
let(:html) { '<img src="example.png">This is an image</img>' }
let(:label_with_html_content) { create(:label, title: 'test', description: html) }
- it 'removes HTML' do
- tooltip = label_tooltip_title(label_with_html_content)
- expect(tooltip).to eq('This is an image')
+ context 'tooltip shows description' do
+ it 'removes HTML' do
+ tooltip = label_tooltip_title(label_with_html_content)
+ expect(tooltip).to eq('This is an image')
+ end
+ end
+
+ context 'tooltip shows title' do
+ it 'shows title' do
+ tooltip = label_tooltip_title(label_with_html_content, tooltip_shows_title: true)
+ expect(tooltip).to eq('test')
+ end
end
end
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 562d6683d97..22d1113ee8c 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MarkupHelper do
+RSpec.describe MarkupHelper, feature_category: :team_planning do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) do
user = create(:user, username: 'gfm')
@@ -461,7 +461,7 @@ RSpec.describe MarkupHelper do
it 'displays the first line of a code block' do
object = create_object("```\nCode block\nwith two lines\n```")
- expected = %r{<pre.+><code><span class="line">Code block\.\.\.</span>\n</code></pre>}
+ expected = %r{<pre.+><code><span class="line">Code block\.\.\.</span></code></pre>}
expect(helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project)).to match(expected)
end
@@ -477,7 +477,7 @@ RSpec.describe MarkupHelper do
it 'preserves code color scheme' do
object = create_object("```ruby\ndef test\n 'hello world'\nend\n```")
expected = "\n<pre class=\"code highlight js-syntax-highlight language-ruby\">" \
- "<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>\n" \
+ "<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>" \
"</code></pre>\n"
expect(helper.first_line_in_markdown(object, attribute, 150, is_todo: true, project: project)).to eq(expected)
diff --git a/spec/helpers/nav_helper_spec.rb b/spec/helpers/nav_helper_spec.rb
index 4a02b184522..4b83561b265 100644
--- a/spec/helpers/nav_helper_spec.rb
+++ b/spec/helpers/nav_helper_spec.rb
@@ -169,15 +169,39 @@ RSpec.describe NavHelper, feature_category: :navigation do
end
end
- context 'when nil is provided' do
- specify { expect(helper.show_super_sidebar?(nil)).to eq false }
+ shared_examples 'anonymous show_super_sidebar is supposed to' do
+ before do
+ stub_feature_flags(super_sidebar_logged_out: feature_flag)
+ end
+
+ context 'when super_sidebar_logged_out feature flag is disabled' do
+ let(:feature_flag) { false }
+
+ specify { expect(subject).to eq false }
+ end
+
+ context 'when super_sidebar_logged_out feature flag is enabled' do
+ let(:feature_flag) { true }
+
+ specify { expect(subject).to eq true }
+ end
end
- context 'when no user is signed-in' do
- specify do
- allow(helper).to receive(:current_user).and_return(nil)
+ context 'without a user' do
+ context 'with current_user (nil) as a default' do
+ before do
+ allow(helper).to receive(:current_user).and_return(nil)
+ end
+
+ subject { helper.show_super_sidebar? }
+
+ it_behaves_like 'anonymous show_super_sidebar is supposed to'
+ end
+
+ context 'with nil provided as an argument' do
+ subject { helper.show_super_sidebar?(nil) }
- expect(helper.show_super_sidebar?).to eq false
+ it_behaves_like 'anonymous show_super_sidebar is supposed to'
end
end
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index 91635ffcdc0..62c0d1b1ff7 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -331,7 +331,9 @@ RSpec.describe NotesHelper, feature_category: :team_planning do
end
describe '#notes_data' do
- let(:issue) { create(:issue, project: project) }
+ let_it_be(:issue) { create(:issue, project: project) }
+
+ let(:notes_data) { helper.notes_data(issue) }
before do
@project = project
@@ -343,7 +345,14 @@ RSpec.describe NotesHelper, feature_category: :team_planning do
it 'includes the current notes filter for the user' do
guest.set_notes_filter(UserPreference::NOTES_FILTERS[:only_comments], issue)
- expect(helper.notes_data(issue)[:notesFilter]).to eq(UserPreference::NOTES_FILTERS[:only_comments])
+ expect(notes_data[:notesFilter]).to eq(UserPreference::NOTES_FILTERS[:only_comments])
+ end
+
+ it 'includes info about the noteable', :aggregate_failures do
+ expect(notes_data[:noteableType]).to eq('issue')
+ expect(notes_data[:noteableId]).to eq(issue.id)
+ expect(notes_data[:projectId]).to eq(project.id)
+ expect(notes_data[:groupId]).to be_nil
end
end
end
diff --git a/spec/helpers/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb
index 4c43b1ec4cf..15ca5f61b51 100644
--- a/spec/helpers/profiles_helper_spec.rb
+++ b/spec/helpers/profiles_helper_spec.rb
@@ -124,6 +124,41 @@ RSpec.describe ProfilesHelper do
end
end
+ describe '#user_profile_data' do
+ let(:time) { 3.hours.ago }
+ let(:user) do
+ build_stubbed(:user, status: UserStatus.new(
+ message: 'Some message',
+ emoji: 'basketball',
+ availability: 'busy',
+ clear_status_at: time
+ ))
+ end
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ it 'returns user profile data' do
+ data = helper.user_profile_data(user)
+
+ expect(data[:profile_path]).to be_a(String)
+ expect(data[:profile_avatar_path]).to be_a(String)
+ expect(data[:avatar_url]).to be_http_url
+ expect(data[:has_avatar]).to be_a(String)
+ expect(data[:gravatar_enabled]).to be_a(String)
+ expect(Gitlab::Json.parse(data[:gravatar_link])).to match(hash_including('hostname' => Gitlab.config.gravatar.host, 'url' => a_valid_url))
+ expect(data[:brand_profile_image_guidelines]).to be_a(String)
+ expect(data[:cropper_css_path]).to eq(ActionController::Base.helpers.stylesheet_path('lazy_bundles/cropper.css'))
+ expect(data[:user_path]).to be_a(String)
+ expect(data[:current_emoji]).to eq('basketball')
+ expect(data[:current_message]).to eq('Some message')
+ expect(data[:current_availability]).to eq('busy')
+ expect(data[:current_clear_status_after]).to eq(time.to_fs(:iso8601))
+ expect(data[:default_emoji]).to eq(UserStatus::DEFAULT_EMOJI)
+ end
+ end
+
def stub_auth0_omniauth_provider
provider = OpenStruct.new(
'name' => example_omniauth_provider,
diff --git a/spec/helpers/projects/observability_helper_spec.rb b/spec/helpers/projects/observability_helper_spec.rb
index 65b6ddf04ec..0f47cdb8be2 100644
--- a/spec/helpers/projects/observability_helper_spec.rb
+++ b/spec/helpers/projects/observability_helper_spec.rb
@@ -4,10 +4,12 @@ require 'spec_helper'
require 'json'
RSpec.describe Projects::ObservabilityHelper, type: :helper, feature_category: :tracing do
- describe '#observability_tracing_view_model' do
- let_it_be(:group) { build_stubbed(:group) }
- let_it_be(:project) { build_stubbed(:project, group: group) }
+ include Gitlab::Routing.url_helpers
+
+ let_it_be(:group) { build_stubbed(:group) }
+ let_it_be(:project) { build_stubbed(:project, group: group) }
+ describe '#observability_tracing_view_model' do
it 'generates the correct JSON' do
expected_json = {
tracingUrl: Gitlab::Observability.tracing_url(project),
@@ -18,4 +20,18 @@ RSpec.describe Projects::ObservabilityHelper, type: :helper, feature_category: :
expect(helper.observability_tracing_view_model(project)).to eq(expected_json)
end
end
+
+ describe '#observability_tracing_details_model' do
+ it 'generates the correct JSON' do
+ expected_json = {
+ tracingIndexUrl: namespace_project_tracing_index_path(project.group, project),
+ traceId: "trace-id",
+ tracingUrl: Gitlab::Observability.tracing_url(project),
+ provisioningUrl: Gitlab::Observability.provisioning_url(project),
+ oauthUrl: Gitlab::Observability.oauth_url
+ }.to_json
+
+ expect(helper.observability_tracing_details_model(project, "trace-id")).to eq(expected_json)
+ end
+ end
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 768038d8736..aa064a26ec4 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -993,6 +993,7 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
expect(settings).to include(
packagesEnabled: !!project.packages_enabled,
+ packageRegistryAllowAnyoneToPullOption: ::Gitlab::CurrentSettings.package_registry_allow_anyone_to_pull_option,
visibilityLevel: project.visibility_level,
requestAccessEnabled: !!project.request_access_enabled,
issuesAccessLevel: project.project_feature.issues_access_level,
@@ -1006,7 +1007,7 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
analyticsAccessLevel: project.project_feature.analytics_access_level,
containerRegistryEnabled: !!project.container_registry_enabled,
lfsEnabled: !!project.lfs_enabled,
- emailsDisabled: project.emails_disabled?,
+ emailsEnabled: project.emails_enabled?,
showDefaultAwardEmojis: project.show_default_award_emojis?,
securityAndComplianceAccessLevel: project.security_and_compliance_access_level,
containerRegistryAccessLevel: project.project_feature.container_registry_access_level,
@@ -1129,16 +1130,39 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
end
end
- describe '#fork_button_disabled_tooltip' do
+ describe '#fork_button_data_attributes' do
using RSpec::Parameterized::TableSyntax
- subject { helper.fork_button_disabled_tooltip(project) }
+ let_it_be(:project) { create(:project, :repository, :public) }
- where(:has_user, :can_fork_project, :can_create_fork, :expected) do
- false | false | false | nil
- true | true | true | nil
- true | false | true | 'You don\'t have permission to fork this project'
- true | true | false | 'You have reached your project limit'
+ project_path = '/project/path'
+ project_forks_path = '/project/forks'
+ project_new_fork_path = '/project/new/fork'
+ user_fork_url = '/user/fork'
+
+ common_data_attributes = {
+ forks_count: 4,
+ project_full_path: project_path,
+ project_forks_url: project_forks_path,
+ can_create_fork: "true",
+ can_fork_project: "true",
+ can_read_code: "true",
+ new_fork_url: project_new_fork_path
+ }
+
+ data_attributes_with_user_fork_url = common_data_attributes.merge({ user_fork_url: user_fork_url })
+ data_attributes_without_user_fork_url = common_data_attributes.merge({ user_fork_url: nil })
+
+ subject { helper.fork_button_data_attributes(project) }
+
+ # The stubs for the forkable namespaces seem not to make sense (they're just numbers),
+ # but they're set up that way because we don't really care about what the array contains, only about its length
+ where(:has_user, :project_already_forked, :forkable_namespaces, :expected) do
+ false | false | [] | nil
+ true | false | [0] | data_attributes_without_user_fork_url
+ true | false | [0, 1] | data_attributes_without_user_fork_url
+ true | true | [0] | data_attributes_with_user_fork_url
+ true | true | [0, 1] | data_attributes_without_user_fork_url
end
with_them do
@@ -1146,13 +1170,22 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
current_user = user if has_user
allow(helper).to receive(:current_user).and_return(current_user)
- allow(user).to receive(:can?).with(:fork_project, project).and_return(can_fork_project)
- allow(user).to receive(:can?).with(:create_fork).and_return(can_create_fork)
- end
+ allow(user).to receive(:can?).with(:fork_project, project).and_return(true)
+ allow(user).to receive(:can?).with(:create_fork).and_return(true)
+ allow(user).to receive(:can?).with(:create_projects, anything).and_return(true)
+ allow(user).to receive(:already_forked?).with(project).and_return(project_already_forked)
+ allow(user).to receive(:forkable_namespaces).and_return(forkable_namespaces)
- it 'returns tooltip text when user lacks privilege' do
- expect(subject).to eq(expected)
+ allow(project).to receive(:forks_count).and_return(4)
+ allow(project).to receive(:full_path).and_return(project_path)
+
+ user_fork_path = user_fork_url if project_already_forked
+ allow(helper).to receive(:namespace_project_path).with(user, anything).and_return(user_fork_path)
+ allow(helper).to receive(:new_project_fork_path).with(project).and_return(project_new_fork_path)
+ allow(helper).to receive(:project_forks_path).with(project).and_return(project_forks_path)
end
+
+ it { is_expected.to eq(expected) }
end
end
@@ -1614,4 +1647,62 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
it { is_expected.to eq(project_settings_repository_path(project, anchor: 'js-branch-rules')) }
end
+
+ describe '#visibility_level_content' do
+ shared_examples 'returns visibility level content_tag' do
+ let(:icon) { '<svg>fake visib level icon</svg>'.html_safe }
+ let(:description) { 'Fake visib desc' }
+
+ before do
+ allow(helper).to receive(:visibility_icon_description).and_return(description)
+ allow(helper).to receive(:visibility_level_icon).and_return(icon)
+ end
+
+ it 'returns visibility level content_tag' do
+ expected_result = "<span class=\"has-tooltip\" data-container=\"body\" data-placement=\"top\" title=\"#{description}\">#{icon}</span>"
+ expect(helper.visibility_level_content(project)).to eq(expected_result)
+ end
+
+ it 'returns visibility level content_tag with extra CSS classes' do
+ expected_result = "<span class=\"has-tooltip extra-class\" data-container=\"body\" data-placement=\"top\" title=\"#{description}\">#{icon}</span>"
+
+ expect(helper).to receive(:visibility_level_icon)
+ .with(anything, options: { class: 'extra-icon-class' })
+ .and_return(icon)
+ result = helper.visibility_level_content(project, css_class: 'extra-class', icon_css_class: 'extra-icon-class')
+ expect(result).to eq(expected_result)
+ end
+ end
+
+ it_behaves_like 'returns visibility level content_tag'
+
+ context 'when project creator is banned' do
+ let(:hidden_resource_icon) { '<svg>fake hidden resource icon</svg>' }
+
+ before do
+ allow(project).to receive(:created_and_owned_by_banned_user?).and_return(true)
+ allow(helper).to receive(:hidden_resource_icon).and_return(hidden_resource_icon)
+ end
+
+ it 'returns hidden resource icon' do
+ expect(helper.visibility_level_content(project)).to eq hidden_resource_icon
+ end
+ end
+
+ context 'with hide_projects_of_banned_users feature flag disabled' do
+ before do
+ stub_feature_flags(hide_projects_of_banned_users: false)
+ end
+
+ it_behaves_like 'returns visibility level content_tag'
+
+ context 'when project creator is banned' do
+ before do
+ allow(project).to receive(:created_and_owned_by_banned_user?).and_return(true)
+ end
+
+ it_behaves_like 'returns visibility level content_tag'
+ end
+ end
+ end
end
diff --git a/spec/helpers/sessions_helper_spec.rb b/spec/helpers/sessions_helper_spec.rb
index 5a46a20ce1a..366032100de 100644
--- a/spec/helpers/sessions_helper_spec.rb
+++ b/spec/helpers/sessions_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SessionsHelper do
+RSpec.describe SessionsHelper, feature_category: :system_access do
describe '#recently_confirmed_com?' do
subject { helper.recently_confirmed_com? }
@@ -51,28 +51,66 @@ RSpec.describe SessionsHelper do
end
end
- describe '#send_rate_limited?' do
+ describe '#unconfirmed_verification_email?', :freeze_time do
+ using RSpec::Parameterized::TableSyntax
+
let(:user) { build_stubbed(:user) }
+ let(:token_valid_for) { ::Users::EmailVerification::ValidateTokenService::TOKEN_VALID_FOR_MINUTES }
+
+ subject { helper.unconfirmed_verification_email?(user) }
+
+ where(:reset_first_offer?, :unconfirmed_email_present?, :token_valid?, :result) do
+ true | true | true | true
+ false | true | true | false
+ true | false | true | false
+ true | true | false | false
+ end
+
+ with_them do
+ before do
+ user.email_reset_offered_at = 1.minute.ago unless reset_first_offer?
+ user.unconfirmed_email = 'unconfirmed@email' if unconfirmed_email_present?
+ user.confirmation_sent_at = (token_valid? ? token_valid_for - 1 : token_valid_for + 1).minutes.ago
+ end
+
+ it { is_expected.to eq(result) }
+ end
+ end
+
+ describe '#verification_email' do
+ let(:unconfirmed_email) { 'unconfirmed@email' }
+ let(:user) { build_stubbed(:user, unconfirmed_email: unconfirmed_email) }
+
+ subject { helper.verification_email(user) }
- subject { helper.send_rate_limited?(user) }
+ context 'when there is an unconfirmed verification email' do
+ before do
+ allow(helper).to receive(:unconfirmed_verification_email?).and_return(true)
+ end
- before do
- allow(::Gitlab::ApplicationRateLimiter)
- .to receive(:peek)
- .with(:email_verification_code_send, scope: user)
- .and_return(rate_limited)
+ it { is_expected.to eq(unconfirmed_email) }
end
- context 'when rate limited' do
- let(:rate_limited) { true }
+ context 'when there is no unconfirmed verification email' do
+ before do
+ allow(helper).to receive(:unconfirmed_verification_email?).and_return(false)
+ end
- it { is_expected.to eq(true) }
+ it { is_expected.to eq(user.email) }
end
+ end
- context 'when not rate limited' do
- let(:rate_limited) { false }
+ describe '#verification_data' do
+ let(:user) { build_stubbed(:user) }
- it { is_expected.to eq(false) }
+ it 'returns the expected data' do
+ expect(helper.verification_data(user)).to eq({
+ obfuscated_email: obfuscated_email(user.email),
+ verify_path: helper.session_path(:user),
+ resend_path: users_resend_verification_code_path,
+ offer_email_reset: user.email_reset_offered_at.nil?.to_s,
+ update_email_path: users_update_email_path
+ })
end
end
diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb
index 8d8bbcd2737..4109eb01caa 100644
--- a/spec/helpers/sidebars_helper_spec.rb
+++ b/spec/helpers/sidebars_helper_spec.rb
@@ -91,15 +91,21 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
allow(user).to receive(:pinned_nav_items).and_return({ panel_type => %w[foo bar], 'another_panel' => %w[baz] })
end
+ # Tests for logged-out sidebar context
+ it_behaves_like 'logged-out super-sidebar context'
+
+ # Tests for logged-in sidebar context below
+ it_behaves_like 'shared super sidebar context'
+ it { is_expected.to include({ is_logged_in: true }) }
+
it 'returns sidebar values from user', :use_clean_rails_memory_store_caching do
expect(subject).to include({
- current_context_header: nil,
- current_menu_items: nil,
+ is_logged_in: true,
name: user.name,
username: user.username,
avatar_url: user.avatar_url,
has_link_to_profile: helper.current_user_menu?(:profile),
- link_to_profile: user_url(user),
+ link_to_profile: user_path(user),
status: {
can_update: helper.can?(user, :update_user_status, user),
busy: user.status&.busy?,
@@ -128,26 +134,11 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
todos_dashboard_path: dashboard_todos_path,
projects_path: dashboard_projects_path,
groups_path: dashboard_groups_path,
- support_path: helper.support_url,
- display_whats_new: helper.display_whats_new?,
- whats_new_most_recent_release_items_count: helper.whats_new_most_recent_release_items_count,
- whats_new_version_digest: helper.whats_new_version_digest,
- show_version_check: helper.show_version_check?,
- gitlab_version: Gitlab.version_info,
- gitlab_version_check: helper.gitlab_version_check,
gitlab_com_but_not_canary: Gitlab.com_but_not_canary?,
gitlab_com_and_canary: Gitlab.com_and_canary?,
canary_toggle_com_url: Gitlab::Saas.canary_toggle_com_url,
- search: {
- search_path: search_path,
- issues_path: issues_dashboard_path,
- mr_path: merge_requests_dashboard_path,
- autocomplete_path: search_autocomplete_path,
- search_context: helper.header_search_context
- },
pinned_items: %w[foo bar],
- panel_type: panel_type,
- update_pins_url: pins_url,
+ update_pins_url: pins_path,
shortcut_links: [
{
title: _('Milestones'),
@@ -383,11 +374,17 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
describe 'context switcher persistent links' do
let_it_be(:public_link) do
[
- { title: s_('Navigation|Your work'), link: '/', icon: 'work' },
{ title: s_('Navigation|Explore'), link: '/explore', icon: 'compass' }
]
end
+ let_it_be(:public_links_for_user) do
+ [
+ { title: s_('Navigation|Your work'), link: '/', icon: 'work' },
+ *public_link
+ ]
+ end
+
let_it_be(:admin_area_link) do
{ title: s_('Navigation|Admin Area'), link: '/admin', icon: 'admin' }
end
@@ -405,12 +402,20 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
helper.super_sidebar_context(user, group: nil, project: nil, panel: panel, panel_type: panel_type)
end
- context 'when user is not an admin' do
- it 'returns only the public links' do
+ context 'when user is not logged in' do
+ let(:user) { nil }
+
+ it 'returns only the public links for an anonymous user' do
expect(subject[:context_switcher_links]).to eq(public_link)
end
end
+ context 'when user is not an admin' do
+ it 'returns only the public links for a user' do
+ expect(subject[:context_switcher_links]).to eq(public_links_for_user)
+ end
+ end
+
context 'when user is an admin' do
before do
allow(user).to receive(:admin?).and_return(true)
@@ -429,7 +434,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
it 'returns public links, admin area and leave admin mode links' do
expect(subject[:context_switcher_links]).to eq([
- *public_link,
+ *public_links_for_user,
admin_area_link,
leave_admin_mode_link
])
@@ -439,7 +444,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
context 'when admin mode is off' do
it 'returns public links and enter admin mode link' do
expect(subject[:context_switcher_links]).to eq([
- *public_link,
+ *public_links_for_user,
enter_admin_mode_link
])
end
@@ -453,7 +458,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
it 'returns public links and admin area link' do
expect(subject[:context_switcher_links]).to eq([
- *public_link,
+ *public_links_for_user,
admin_area_link
])
end
@@ -471,8 +476,11 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
end
describe 'when impersonating' do
+ before do
+ session[:impersonator_id] = 5
+ end
+
it 'sets is_impersonating to `true`' do
- expect(helper).to receive(:session).and_return({ impersonator_id: 1 })
expect(subject[:is_impersonating]).to be(true)
end
end
diff --git a/spec/helpers/snippets_helper_spec.rb b/spec/helpers/snippets_helper_spec.rb
index 43e663464c8..1e899396de4 100644
--- a/spec/helpers/snippets_helper_spec.rb
+++ b/spec/helpers/snippets_helper_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe SnippetsHelper do
end
def download_link(url)
- "<a class=\"gl-button btn btn-default\" target=\"_blank\" rel=\"noopener noreferrer\" title=\"Open raw\" href=\"#{url}\">#{external_snippet_icon('doc-code')}</a>"
+ "<a rel=\"noopener noreferrer\" title=\"Open raw\" class=\"gl-button btn btn-md btn-default \" target=\"_blank\" href=\"#{url}\"><span class=\"gl-button-text\">\n#{external_snippet_icon('doc-code')}\n</span>\n\n</a>"
end
end
@@ -60,7 +60,7 @@ RSpec.describe SnippetsHelper do
end
def download_link(url)
- "<a class=\"gl-button btn btn-default\" target=\"_blank\" title=\"Download\" rel=\"noopener noreferrer\" href=\"#{url}?inline=false\">#{external_snippet_icon('download')}</a>"
+ "<a rel=\"noopener noreferrer\" title=\"Download\" class=\"gl-button btn btn-md btn-default \" target=\"_blank\" href=\"#{url}?inline=false\"><span class=\"gl-button-text\">\n#{external_snippet_icon('download')}\n</span>\n\n</a>"
end
end
@@ -102,7 +102,7 @@ RSpec.describe SnippetsHelper do
end
def copy_button(blob_id)
- "<button class=\"gl-button btn btn-default copy-to-clipboard-btn\" title=\"Copy snippet contents\" onclick=\"copyToClipboard(&#39;.blob-content[data-blob-id=&quot;#{blob_id}&quot;] &gt; pre&#39;)\">#{external_snippet_icon('copy-to-clipboard')}</button>"
+ "<button title=\"Copy snippet contents\" onclick=\"copyToClipboard(&#39;.blob-content[data-blob-id=&quot;#{blob_id}&quot;] &gt; pre&#39;)\" type=\"button\" class=\"gl-button btn btn-md btn-default \"><span class=\"gl-button-text\">\n#{external_snippet_icon('copy-to-clipboard')}\n</span>\n\n</button>"
end
end
diff --git a/spec/helpers/time_helper_spec.rb b/spec/helpers/time_helper_spec.rb
index 3e406f5e74e..02e28b2ba05 100644
--- a/spec/helpers/time_helper_spec.rb
+++ b/spec/helpers/time_helper_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe TimeHelper do
100.32 => "1 minute and 40 seconds",
120 => "2 minutes",
121 => "2 minutes and 1 second",
- 3721 => "62 minutes and 1 second",
+ 3721 => "1 hour, 2 minutes, and 1 second",
0 => "0 seconds"
}
diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb
index 9cbcca69dc8..dfb5cb995bc 100644
--- a/spec/helpers/todos_helper_spec.rb
+++ b/spec/helpers/todos_helper_spec.rb
@@ -370,6 +370,7 @@ RSpec.describe TodosHelper do
Todo::APPROVAL_REQUIRED | false | format(s_("Todos|set %{who} as an approver"), who: _('you'))
Todo::UNMERGEABLE | true | s_('Todos|Could not merge')
Todo::MERGE_TRAIN_REMOVED | true | s_("Todos|Removed from Merge Train")
+ Todo::REVIEW_SUBMITTED | false | s_('Todos|reviewed your merge request')
end
with_them do
diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb
index 1ca5b8eb954..c94844eebbc 100644
--- a/spec/helpers/tree_helper_spec.rb
+++ b/spec/helpers/tree_helper_spec.rb
@@ -21,12 +21,14 @@ RSpec.describe TreeHelper do
describe '#vue_file_list_data' do
it 'returns a list of attributes related to the project' do
+ helper.instance_variable_set(:@ref_type, 'heads')
expect(helper.vue_file_list_data(project, sha)).to include(
project_path: project.full_path,
project_short_path: project.path,
ref: sha,
escaped_ref: sha,
- full_name: project.name_with_namespace
+ full_name: project.name_with_namespace,
+ ref_type: 'heads'
)
end
end
diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb
index c0d3c31a36d..ad8aef276bb 100644
--- a/spec/helpers/users_helper_spec.rb
+++ b/spec/helpers/users_helper_spec.rb
@@ -150,6 +150,76 @@ RSpec.describe UsersHelper do
end
end
+ describe '#can_impersonate_user' do
+ let(:user) { create(:user) }
+ let(:impersonation_in_progress) { false }
+
+ subject { helper.can_impersonate_user(user, impersonation_in_progress) }
+
+ context 'when password is expired' do
+ let(:user) { create(:user, password_expires_at: 1.minute.ago) }
+
+ it { is_expected.to be false }
+ end
+
+ context 'when impersonation is in progress' do
+ let(:impersonation_in_progress) { true }
+
+ it { is_expected.to be false }
+ end
+
+ context 'when user is blocked' do
+ let(:user) { create(:user, :blocked) }
+
+ it { is_expected.to be false }
+ end
+
+ context 'when user is internal' do
+ let(:user) { create(:user, :bot) }
+
+ it { is_expected.to be false }
+ end
+
+ it { is_expected.to be true }
+ end
+
+ describe '#impersonation_error_text' do
+ let(:user) { create(:user) }
+ let(:impersonation_in_progress) { false }
+
+ subject { helper.impersonation_error_text(user, impersonation_in_progress) }
+
+ context 'when password is expired' do
+ let(:user) { create(:user, password_expires_at: 1.minute.ago) }
+
+ it { is_expected.to eq(_("You cannot impersonate a user with an expired password")) }
+ end
+
+ context 'when impersonation is in progress' do
+ let(:impersonation_in_progress) { true }
+
+ it { is_expected.to eq(_("You are already impersonating another user")) }
+ end
+
+ context 'when user is blocked' do
+ let(:user) { create(:user, :blocked) }
+
+ it { is_expected.to eq(_("You cannot impersonate a blocked user")) }
+ end
+
+ context 'when user is internal' do
+ let(:user) { create(:user, :bot) }
+
+ it { is_expected.to eq(_("You cannot impersonate an internal user")) }
+ end
+
+ context 'when user is inactive' do
+ let(:user) { create(:user, :deactivated) }
+
+ it { is_expected.to eq(_("You cannot impersonate a user who cannot log in")) }
+ end
+ end
+
describe '#user_badges_in_admin_section' do
before do
allow(helper).to receive(:current_user).and_return(user)
@@ -534,7 +604,7 @@ RSpec.describe UsersHelper do
describe '#load_max_project_member_accesses' do
let_it_be(:projects) { create_list(:project, 3) }
- before(:all) do
+ before_all do
projects.first.add_developer(user)
end
@@ -612,4 +682,58 @@ RSpec.describe UsersHelper do
it { is_expected.to eq('Active') }
end
end
+
+ describe '#user_profile_actions_data' do
+ let(:user_1) { create(:user) }
+ let(:user_2) { create(:user) }
+ let(:user_path) { '/users/root' }
+
+ subject { helper.user_profile_actions_data(user_1) }
+
+ before do
+ allow(helper).to receive(:user_path).and_return(user_path)
+ allow(helper).to receive(:user_url).and_return(user_path)
+ end
+
+ shared_examples 'user cannot report' do
+ it 'returns data without reporting related data' do
+ is_expected.to match({
+ user_id: user_1.id,
+ rss_subscription_path: user_path
+ })
+ end
+ end
+
+ context 'user is current user' do
+ before do
+ allow(helper).to receive(:current_user).and_return(user_1)
+ end
+
+ it_behaves_like 'user cannot report'
+ end
+
+ context 'user is not current user' do
+ before do
+ allow(helper).to receive(:current_user).and_return(user_2)
+ end
+
+ it 'returns data for reporting related data' do
+ is_expected.to match({
+ user_id: user_1.id,
+ rss_subscription_path: user_path,
+ report_abuse_path: add_category_abuse_reports_path,
+ reported_user_id: user_1.id,
+ reported_from_url: user_path
+ })
+ end
+ end
+
+ context 'when logged out' do
+ before do
+ allow(helper).to receive(:current_user).and_return(nil)
+ end
+
+ it_behaves_like 'user cannot report'
+ end
+ end
end