summaryrefslogtreecommitdiff
path: root/spec/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'spec/helpers')
-rw-r--r--spec/helpers/auth_helper_spec.rb40
-rw-r--r--spec/helpers/blob_helper_spec.rb55
-rw-r--r--spec/helpers/ci/pipelines_helper_spec.rb24
-rw-r--r--spec/helpers/clusters_helper_spec.rb10
-rw-r--r--spec/helpers/container_registry_helper_spec.rb27
-rw-r--r--spec/helpers/dropdowns_helper_spec.rb253
-rw-r--r--spec/helpers/emails_helper_spec.rb72
-rw-r--r--spec/helpers/environments_helper_spec.rb82
-rw-r--r--spec/helpers/groups/group_members_helper_spec.rb48
-rw-r--r--spec/helpers/groups_helper_spec.rb44
-rw-r--r--spec/helpers/issuables_helper_spec.rb4
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb2
-rw-r--r--spec/helpers/notifications_helper_spec.rb12
-rw-r--r--spec/helpers/operations_helper_spec.rb4
-rw-r--r--spec/helpers/releases_helper_spec.rb2
-rw-r--r--spec/helpers/search_helper_spec.rb82
-rw-r--r--spec/helpers/services_helper_spec.rb35
-rw-r--r--spec/helpers/snippets_helper_spec.rb2
-rw-r--r--spec/helpers/storage_helper_spec.rb5
-rw-r--r--spec/helpers/submodule_helper_spec.rb174
-rw-r--r--spec/helpers/tree_helper_spec.rb88
-rw-r--r--spec/helpers/user_callouts_helper_spec.rb20
-rw-r--r--spec/helpers/whats_new_helper_spec.rb22
-rw-r--r--spec/helpers/wiki_helper_spec.rb16
24 files changed, 1017 insertions, 106 deletions
diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb
index 1e843ee221b..e0d316baa17 100644
--- a/spec/helpers/auth_helper_spec.rb
+++ b/spec/helpers/auth_helper_spec.rb
@@ -220,4 +220,44 @@ RSpec.describe AuthHelper do
it { is_expected.to be(false) }
end
end
+
+ describe '#auth_active?' do
+ let(:user) { create(:user) }
+
+ def auth_active?
+ helper.auth_active?(provider)
+ end
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ context 'for atlassian_oauth2 provider' do
+ let_it_be(:provider) { :atlassian_oauth2 }
+
+ it 'returns true when present' do
+ create(:atlassian_identity, user: user)
+
+ expect(auth_active?).to be true
+ end
+
+ it 'returns false when not present' do
+ expect(auth_active?).to be false
+ end
+ end
+
+ context 'for other omniauth providers' do
+ let_it_be(:provider) { 'google_oauth2' }
+
+ it 'returns true when present' do
+ create(:identity, provider: provider, user: user)
+
+ expect(auth_active?).to be true
+ end
+
+ it 'returns false when not present' do
+ expect(auth_active?).to be false
+ end
+ end
+ end
end
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index 3ba9f39d21a..06f86e7716a 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -481,4 +481,59 @@ RSpec.describe BlobHelper do
end
end
end
+
+ describe '#editing_ci_config?' do
+ let(:project) { build(:project) }
+
+ subject { helper.editing_ci_config? }
+
+ before do
+ assign(:project, project)
+ assign(:path, path)
+ end
+
+ context 'when path is nil' do
+ let(:path) { nil }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when path is not a ci file' do
+ let(:path) { 'some-file.txt' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when path ends is gitlab-ci.yml' do
+ let(:path) { '.gitlab-ci.yml' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when path ends with gitlab-ci.yml' do
+ let(:path) { 'template.gitlab-ci.yml' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'with custom ci paths' do
+ let(:path) { 'path/to/ci.yaml' }
+
+ before do
+ project.ci_config_path = 'path/to/ci.yaml'
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'with custom ci config and path' do
+ let(:path) { 'path/to/template.gitlab-ci.yml' }
+
+ before do
+ project.ci_config_path = 'ci/path/.gitlab-ci.yml@another-group/another-project'
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
end
diff --git a/spec/helpers/ci/pipelines_helper_spec.rb b/spec/helpers/ci/pipelines_helper_spec.rb
index 89b9907d0c2..a96d6e7711f 100644
--- a/spec/helpers/ci/pipelines_helper_spec.rb
+++ b/spec/helpers/ci/pipelines_helper_spec.rb
@@ -22,8 +22,8 @@ RSpec.describe Ci::PipelinesHelper do
let(:warning_messages) { [double(content: 'Warning 1'), double(content: 'Warning 2')] }
it 'returns a warning callout box' do
- expect(subject).to have_css 'div.alert-warning'
- expect(subject).to include 'Warning:'
+ expect(subject).to have_css 'div.bs-callout-warning'
+ expect(subject).to include '2 warning(s) found:'
end
it 'lists the the warnings' do
@@ -32,4 +32,24 @@ RSpec.describe Ci::PipelinesHelper do
end
end
end
+
+ describe 'warning_header' do
+ subject { helper.warning_header(count) }
+
+ context 'when warnings are more than max cap' do
+ let(:count) { 30 }
+
+ it 'returns 30 warning(s) found: showing first 25' do
+ expect(subject).to eq('30 warning(s) found: showing first 25')
+ end
+ end
+
+ context 'when warnings are less than max cap' do
+ let(:count) { 15 }
+
+ it 'returns 15 warning(s) found' do
+ expect(subject).to eq('15 warning(s) found:')
+ end
+ end
+ end
end
diff --git a/spec/helpers/clusters_helper_spec.rb b/spec/helpers/clusters_helper_spec.rb
index dff83005c89..6164f3b5e8d 100644
--- a/spec/helpers/clusters_helper_spec.rb
+++ b/spec/helpers/clusters_helper_spec.rb
@@ -77,7 +77,15 @@ RSpec.describe ClustersHelper do
end
it 'displays and ancestor_help_path' do
- expect(subject[:ancestor_help_path]).to eq('/help/user/group/clusters/index#cluster-precedence')
+ expect(subject[:ancestor_help_path]).to eq(help_page_path('user/group/clusters/index', anchor: 'cluster-precedence'))
+ end
+ end
+
+ describe '#js_cluster_new' do
+ subject { helper.js_cluster_new }
+
+ it 'displays a cluster_connect_help_path' do
+ expect(subject[:cluster_connect_help_path]).to eq(help_page_path('user/project/clusters/add_remove_clusters', anchor: 'add-existing-cluster'))
end
end
diff --git a/spec/helpers/container_registry_helper_spec.rb b/spec/helpers/container_registry_helper_spec.rb
new file mode 100644
index 00000000000..6e6e8137b3e
--- /dev/null
+++ b/spec/helpers/container_registry_helper_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ContainerRegistryHelper do
+ using RSpec::Parameterized::TableSyntax
+
+ describe '#limit_delete_tags_service?' do
+ subject { helper.limit_delete_tags_service? }
+
+ where(:feature_flag_enabled, :client_support, :expected_result) do
+ true | true | true
+ true | false | false
+ false | true | false
+ false | false | false
+ end
+
+ with_them do
+ before do
+ stub_feature_flags(container_registry_expiration_policies_throttling: feature_flag_enabled)
+ allow(ContainerRegistry::Client).to receive(:supports_tag_delete?).and_return(client_support)
+ end
+
+ it { is_expected.to eq(expected_result) }
+ end
+ end
+end
diff --git a/spec/helpers/dropdowns_helper_spec.rb b/spec/helpers/dropdowns_helper_spec.rb
new file mode 100644
index 00000000000..fd1125d0024
--- /dev/null
+++ b/spec/helpers/dropdowns_helper_spec.rb
@@ -0,0 +1,253 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DropdownsHelper do
+ before do
+ allow(helper).to receive(:sprite_icon).and_return('<span class="icon"></span>'.html_safe)
+ allow(helper).to receive(:icon).and_return('<span class="icon"></span>'.html_safe)
+ end
+
+ shared_examples 'has two icons' do
+ it 'returns two icons' do
+ expect(content.scan('icon').count).to eq(2)
+ end
+ end
+
+ describe '#dropdown_tag' do
+ let(:content) { helper.dropdown_tag('toggle', options: { wrapper_class: 'fuz' }) { 'fizzbuzz' } }
+
+ it 'returns the container in the content' do
+ expect(content).to include('dropdown fuz')
+ end
+
+ it 'returns the block in the content' do
+ expect(content).to include('fizzbuzz')
+ end
+ end
+
+ describe '#dropdown_toggle' do
+ let(:content) { helper.dropdown_toggle('foo', { default_label: 'foo' }, { toggle_class: 'fuz' }) }
+
+ it 'returns the button' do
+ expect(content).to include('dropdown-menu-toggle fuz')
+ end
+
+ it 'returns the buttons default label data attribute' do
+ expect(content).to include('data-default-label="foo"')
+ end
+
+ it 'returns the dropdown toggle text', :aggregate_failures do
+ expect(content).to include('dropdown-toggle-text is-default')
+ expect(content).to include('foo')
+ end
+
+ it 'returns the button icon in the content' do
+ expect(content.scan('icon').count).to eq(1)
+ end
+ end
+
+ describe '#dropdown_toggle_link' do
+ let(:content) { dropdown_toggle_link('foo', { data: 'bar' }, { toggle_class: 'fuz' }) }
+
+ it 'returns the link' do
+ expect(content).to include('dropdown-toggle-text fuz')
+ end
+
+ it 'returns the links data attribute' do
+ expect(content).to include('data-data="bar"')
+ end
+
+ it 'returns the link text' do
+ expect(content).to include('foo')
+ end
+ end
+
+ describe '#dropdown_title' do
+ shared_examples 'has a back button' do
+ it 'contains the back button' do
+ expect(content).to include('dropdown-title-button dropdown-menu-back')
+ end
+ end
+
+ shared_examples 'does not have a back button' do
+ it 'does not contain the back button' do
+ expect(content).not_to include('dropdown-title-button dropdown-menu-back')
+ end
+ end
+
+ shared_examples 'does not apply the margin class to the back button' do
+ it 'does not contain the back button margin class' do
+ expect(content).not_to include('dropdown-title-button dropdown-menu-back gl-mr-auto')
+ end
+ end
+
+ shared_examples 'has a close button' do
+ it 'contains the close button' do
+ expect(content).to include('dropdown-title-button dropdown-menu-close')
+ end
+ end
+
+ shared_examples 'does not have a close button' do
+ it 'does not contain the close button' do
+ expect(content).not_to include('dropdown-title-button dropdown-menu-close')
+ end
+ end
+
+ shared_examples 'does not apply the margin class to the close button' do
+ it 'does not contain the close button margin class' do
+ expect(content).not_to include('dropdown-title-button dropdown-menu-close gl-ml-auto')
+ end
+ end
+
+ shared_examples 'has the title text' do
+ it 'contains the title text' do
+ expect(content).to include('Foo')
+ end
+ end
+
+ shared_examples 'has the title margin class' do |margin_class: ''|
+ it 'contains the title margin class' do
+ expect(content).to match(/class="#{margin_class}.*"[^>]*>Foo/)
+ end
+ end
+
+ shared_examples 'does not have the title margin class' do
+ it 'does not have the title margin class' do
+ expect(content).not_to match(/class="gl-m[r|l]-auto.*"[^>]*>Foo/)
+ end
+ end
+
+ context 'with a back and close button' do
+ let(:content) { helper.dropdown_title('Foo', options: { back: true, close: true }) }
+
+ it 'applies the justification class to the container', :aggregate_failures do
+ expect(content).to match(/"dropdown-title.*gl-justify-content-space-between"/)
+ end
+
+ it_behaves_like 'has a back button'
+ it_behaves_like 'has the title text'
+ it_behaves_like 'has a close button'
+ it_behaves_like 'has two icons'
+ it_behaves_like 'does not have the title margin class'
+ end
+
+ context 'with a back button' do
+ let(:content) { helper.dropdown_title('Foo', options: { back: true, close: false }) }
+
+ it_behaves_like 'has a back button'
+ it_behaves_like 'has the title text'
+ it_behaves_like 'has the title margin class', margin_class: 'gl-mr-auto'
+ it_behaves_like 'does not have a close button'
+
+ it 'returns the back button icon' do
+ expect(content.scan('icon').count).to eq(1)
+ end
+ end
+
+ context 'with a close button' do
+ let(:content) { helper.dropdown_title('Foo', options: { back: false, close: true }) }
+
+ it_behaves_like 'does not have a back button'
+ it_behaves_like 'has the title text'
+ it_behaves_like 'has the title margin class', margin_class: 'gl-ml-auto'
+ it_behaves_like 'has a close button'
+
+ it 'returns the close button icon' do
+ expect(content.scan('icon').count).to eq(1)
+ end
+ end
+
+ context 'without any buttons' do
+ let(:content) { helper.dropdown_title('Foo', options: { back: false, close: false }) }
+
+ it_behaves_like 'does not have a back button'
+ it_behaves_like 'has the title text'
+ it_behaves_like 'does not have the title margin class'
+ it_behaves_like 'does not have a close button'
+
+ it 'returns no button icons' do
+ expect(content.scan('icon').count).to eq(0)
+ end
+ end
+ end
+
+ describe '#dropdown_filter' do
+ let(:content) { helper.dropdown_filter('foo') }
+
+ it_behaves_like 'has two icons'
+
+ it 'returns the container' do
+ expect(content).to include('dropdown-input')
+ end
+
+ it 'returns the search input', :aggregate_failures do
+ expect(content).to include('dropdown-input-field')
+ expect(content).to include('placeholder="foo"')
+ end
+ end
+
+ describe '#dropdown_content' do
+ shared_examples 'contains the container' do
+ it 'returns the container in the content' do
+ expect(content).to include('dropdown-content')
+ end
+ end
+
+ context 'without block' do
+ let(:content) { helper.dropdown_content }
+
+ it_behaves_like 'contains the container'
+ end
+
+ context 'with block' do
+ let(:content) { helper.dropdown_content { 'foo' } }
+
+ it_behaves_like 'contains the container'
+
+ it 'returns the block in the content' do
+ expect(content).to include('foo')
+ end
+ end
+ end
+
+ describe '#dropdown_footer' do
+ shared_examples 'contains the content' do
+ it 'returns the container in the content' do
+ expect(content).to include('dropdown-footer')
+ end
+
+ it 'returns the block in the content' do
+ expect(content).to include('foo')
+ end
+ end
+
+ context 'without a content class' do
+ let(:content) { helper.dropdown_footer { 'foo' } }
+
+ it_behaves_like 'contains the content'
+ end
+
+ context 'without a content class' do
+ let(:content) { helper.dropdown_footer(add_content_class: true) { 'foo' } }
+
+ it_behaves_like 'contains the content'
+
+ it 'returns the footer in the content' do
+ expect(content).to include('dropdown-footer-content')
+ end
+ end
+ end
+
+ describe '#dropdown_loading' do
+ let(:content) { helper.dropdown_loading }
+
+ it 'returns the container in the content' do
+ expect(content).to include('dropdown-loading')
+ end
+
+ it 'returns an icon in the content' do
+ expect(content.scan('icon').count).to eq(1)
+ end
+ end
+end
diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb
index bc5fe05ab52..96ac4015c77 100644
--- a/spec/helpers/emails_helper_spec.rb
+++ b/spec/helpers/emails_helper_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe EmailsHelper do
context "and format is unknown" do
it "returns plain text" do
- expect(helper.closure_reason_text(merge_request, format: :text)).to eq("via merge request #{merge_request.to_reference} (#{merge_request_presenter.web_url})")
+ expect(helper.closure_reason_text(merge_request, format: 'unknown')).to eq("via merge request #{merge_request.to_reference} (#{merge_request_presenter.web_url})")
end
end
end
@@ -110,6 +110,76 @@ RSpec.describe EmailsHelper do
end
end
+ describe '#say_hi' do
+ let(:user) { create(:user, name: 'John') }
+
+ it 'returns the greeting message for the given user' do
+ expect(say_hi(user)).to eq('Hi John!')
+ end
+ end
+
+ describe '#say_hello' do
+ let(:user) { build(:user, name: 'John') }
+
+ it 'returns the greeting message for the given user' do
+ expect(say_hello(user)).to eq('Hello, John!')
+ end
+ end
+
+ describe '#two_factor_authentication_disabled_text' do
+ it 'returns the message that 2FA is disabled' do
+ expect(two_factor_authentication_disabled_text).to eq(
+ _('Two-factor authentication has been disabled for your GitLab account.')
+ )
+ end
+ end
+
+ describe '#re_enable_two_factor_authentication_text' do
+ context 'format is html' do
+ it 'returns HTML' do
+ expect(re_enable_two_factor_authentication_text(format: :html)).to eq(
+ "If you want to re-enable two-factor authentication, visit the " \
+ "#{link_to('two-factor authentication settings', profile_two_factor_auth_url, target: :_blank, rel: 'noopener noreferrer')} page."
+ )
+ end
+ end
+
+ context 'format is not specified' do
+ it 'returns text' do
+ expect(re_enable_two_factor_authentication_text).to eq(
+ "If you want to re-enable two-factor authentication, visit #{profile_two_factor_auth_url}"
+ )
+ end
+ end
+ end
+
+ describe '#admin_changed_password_text' do
+ context 'format is html' do
+ it 'returns HTML' do
+ expect(admin_changed_password_text(format: :html)).to eq(
+ "An administrator changed the password for your GitLab account on " \
+ "#{link_to(Gitlab.config.gitlab.url, Gitlab.config.gitlab.url, target: :_blank, rel: 'noopener noreferrer')}."
+ )
+ end
+ end
+
+ context 'format is not specified' do
+ it 'returns text' do
+ expect(admin_changed_password_text).to eq(
+ "An administrator changed the password for your GitLab account on #{Gitlab.config.gitlab.url}."
+ )
+ end
+ end
+ end
+
+ describe '#contact_your_administrator_text' do
+ it 'returns the message to contact the administrator' do
+ expect(contact_your_administrator_text).to eq(
+ _('Please contact your administrator with any questions.')
+ )
+ end
+ end
+
describe 'password_reset_token_valid_time' do
def validate_time_string(time_limit, expected_string)
Devise.reset_password_within = time_limit
diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb
index cb7d12b331a..d316f2b0a0a 100644
--- a/spec/helpers/environments_helper_spec.rb
+++ b/spec/helpers/environments_helper_spec.rb
@@ -18,34 +18,34 @@ RSpec.describe EnvironmentsHelper do
it 'returns data' do
expect(metrics_data).to include(
- 'settings-path' => edit_project_service_path(project, 'prometheus'),
- 'clusters-path' => project_clusters_path(project),
- 'metrics-dashboard-base-path' => environment_metrics_path(environment),
- 'current-environment-name' => environment.name,
- 'documentation-path' => help_page_path('administration/monitoring/prometheus/index.md'),
- 'add-dashboard-documentation-path' => help_page_path('operations/metrics/dashboards/index.md', anchor: 'add-a-new-dashboard-to-your-project'),
- 'empty-getting-started-svg-path' => match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
- 'empty-loading-svg-path' => match_asset_path('/assets/illustrations/monitoring/loading.svg'),
- 'empty-no-data-svg-path' => match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
- 'empty-unable-to-connect-svg-path' => match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'),
- 'metrics-endpoint' => additional_metrics_project_environment_path(project, environment, format: :json),
- 'deployments-endpoint' => project_environment_deployments_path(project, environment, format: :json),
- 'default-branch' => 'master',
- 'project-path' => project_path(project),
- 'tags-path' => project_tags_path(project),
- 'has-metrics' => "#{environment.has_metrics?}",
- 'prometheus-status' => "#{environment.prometheus_status}",
- 'external-dashboard-url' => nil,
- 'environment-state' => environment.state,
- 'custom-metrics-path' => project_prometheus_metrics_path(project),
- 'validate-query-path' => validate_query_project_prometheus_metrics_path(project),
- 'custom-metrics-available' => 'true',
- 'alerts-endpoint' => project_prometheus_alerts_path(project, environment_id: environment.id, format: :json),
- 'prometheus-alerts-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)
+ 'settings_path' => edit_project_service_path(project, 'prometheus'),
+ 'clusters_path' => project_clusters_path(project),
+ 'metrics_dashboard_base_path' => environment_metrics_path(environment),
+ 'current_environment_name' => environment.name,
+ 'documentation_path' => help_page_path('administration/monitoring/prometheus/index.md'),
+ 'add_dashboard_documentation_path' => help_page_path('operations/metrics/dashboards/index.md', anchor: 'add-a-new-dashboard-to-your-project'),
+ 'empty_getting_started_svg_path' => match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
+ 'empty_loading_svg_path' => match_asset_path('/assets/illustrations/monitoring/loading.svg'),
+ 'empty_no_data_svg_path' => match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
+ 'empty_unable_to_connect_svg_path' => match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'),
+ 'metrics_endpoint' => additional_metrics_project_environment_path(project, environment, format: :json),
+ 'deployments_endpoint' => project_environment_deployments_path(project, environment, format: :json),
+ 'default_branch' => 'master',
+ 'project_path' => project_path(project),
+ 'tags_path' => project_tags_path(project),
+ 'has_metrics' => "#{environment.has_metrics?}",
+ 'prometheus_status' => "#{environment.prometheus_status}",
+ 'external_dashboard_url' => nil,
+ 'environment_state' => environment.state,
+ 'custom_metrics_path' => project_prometheus_metrics_path(project),
+ 'validate_query_path' => validate_query_project_prometheus_metrics_path(project),
+ 'custom_metrics_available' => 'true',
+ 'alerts_endpoint' => project_prometheus_alerts_path(project, environment_id: environment.id, format: :json),
+ 'prometheus_alerts_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)
)
end
@@ -58,7 +58,7 @@ RSpec.describe EnvironmentsHelper do
specify do
expect(metrics_data).to include(
- 'can-access-operations-settings' => 'false'
+ 'can_access_operations_settings' => 'false'
)
end
end
@@ -72,7 +72,7 @@ RSpec.describe EnvironmentsHelper do
it 'returns false' do
expect(metrics_data).to include(
- 'prometheus-alerts-available' => 'false'
+ 'prometheus_alerts_available' => 'false'
)
end
end
@@ -83,7 +83,7 @@ RSpec.describe EnvironmentsHelper do
end
it 'adds external_dashboard_url' do
- expect(metrics_data['external-dashboard-url']).to eq('http://gitlab.com')
+ expect(metrics_data['external_dashboard_url']).to eq('http://gitlab.com')
end
end
@@ -94,7 +94,7 @@ RSpec.describe EnvironmentsHelper do
subject { metrics_data }
- it { is_expected.to include('environment-state' => 'stopped') }
+ it { is_expected.to include('environment_state' => 'stopped') }
end
context 'when request is from project scoped metrics path' do
@@ -107,16 +107,16 @@ RSpec.describe EnvironmentsHelper do
context '/:namespace/:project/-/metrics' do
let(:path) { project_metrics_dashboard_path(project) }
- it 'uses correct path for metrics-dashboard-base-path' do
- expect(metrics_data['metrics-dashboard-base-path']).to eq(project_metrics_dashboard_path(project))
+ it 'uses correct path for metrics_dashboard_base_path' do
+ expect(metrics_data['metrics_dashboard_base_path']).to eq(project_metrics_dashboard_path(project))
end
end
context '/:namespace/:project/-/metrics/some_custom_dashboard.yml' do
let(:path) { "#{project_metrics_dashboard_path(project)}/some_custom_dashboard.yml" }
- it 'uses correct path for metrics-dashboard-base-path' do
- expect(metrics_data['metrics-dashboard-base-path']).to eq(project_metrics_dashboard_path(project))
+ it 'uses correct path for metrics_dashboard_base_path' do
+ expect(metrics_data['metrics_dashboard_base_path']).to eq(project_metrics_dashboard_path(project))
end
end
end
@@ -143,11 +143,11 @@ RSpec.describe EnvironmentsHelper do
describe '#environment_logs_data' do
it 'returns logs data' do
expected_data = {
- "environment-name": environment.name,
- "environments-path": project_environments_path(project, format: :json),
- "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)
+ "environment_name": environment.name,
+ "environments_path": project_environments_path(project, format: :json),
+ "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)
}
expect(helper.environment_logs_data(project, environment)).to eq(expected_data)
diff --git a/spec/helpers/groups/group_members_helper_spec.rb b/spec/helpers/groups/group_members_helper_spec.rb
index 90792331d9b..a25bf1c4157 100644
--- a/spec/helpers/groups/group_members_helper_spec.rb
+++ b/spec/helpers/groups/group_members_helper_spec.rb
@@ -3,6 +3,8 @@
require "spec_helper"
RSpec.describe Groups::GroupMembersHelper do
+ include MembersPresentation
+
describe '.group_member_select_options' do
let(:group) { create(:group) }
@@ -14,4 +16,50 @@ RSpec.describe Groups::GroupMembersHelper do
expect(helper.group_member_select_options).to include(multiple: true, scope: :all, email_user: true)
end
end
+
+ describe '#linked_groups_data_json' do
+ include_context 'group_group_link'
+
+ it 'matches json schema' do
+ json = helper.linked_groups_data_json(shared_group.shared_with_group_links)
+
+ expect(json).to match_schema('group_group_links')
+ end
+ end
+
+ describe '#members_data_json' do
+ let(:current_user) { create(:user) }
+ let(:group) { create(:group) }
+
+ before do
+ allow(helper).to receive(:can?).with(current_user, :owner_access, group).and_return(true)
+ allow(helper).to receive(:current_user).and_return(current_user)
+ end
+
+ shared_examples 'group_members.json' do
+ it 'matches json schema' do
+ json = helper.members_data_json(group, present_members([group_member]))
+
+ expect(json).to match_schema('group_members')
+ end
+ end
+
+ context 'for a group member' do
+ let(:group_member) { create(:group_member, group: group, created_by: current_user) }
+
+ it_behaves_like 'group_members.json'
+ end
+
+ context 'for an invited group member' do
+ let(:group_member) { create(:group_member, :invited, group: group, created_by: current_user) }
+
+ it_behaves_like 'group_members.json'
+ end
+
+ context 'for an access request' do
+ let(:group_member) { create(:group_member, :access_request, group: group, created_by: current_user) }
+
+ it_behaves_like 'group_members.json'
+ end
+ end
end
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 0790dc1b674..08b25d64b43 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -369,4 +369,48 @@ RSpec.describe GroupsHelper do
it { is_expected.to be_falsey }
end
end
+
+ describe '#show_invite_banner?' do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be_with_refind(:group) { create(: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)
+ 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
+ end
+
+ with_them do
+ 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
+
+ context 'when no flash message' do
+ it 'returns the expected result' do
+ expect(subject).to eq(expected_result)
+ end
+ end
+ end
+ end
end
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 9b32758c053..89a2a92ea57 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -197,7 +197,9 @@ RSpec.describe IssuablesHelper do
initialTitleText: issue.title,
initialDescriptionHtml: '<p dir="auto">issue text</p>',
initialDescriptionText: 'issue text',
- initialTaskStatus: '0 of 0 tasks completed'
+ initialTaskStatus: '0 of 0 tasks completed',
+ issueType: 'issue',
+ iid: issue.iid.to_s
}
expect(helper.issuable_initial_data(issue)).to match(hash_including(expected_data))
end
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index fcb9efa39d5..153dc19335b 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -75,7 +75,7 @@ RSpec.describe MergeRequestsHelper do
describe '#tab_link_for' do
let(:merge_request) { create(:merge_request, :simple) }
- let(:options) { Hash.new }
+ let(:options) { {} }
subject { tab_link_for(merge_request, :show, options) { 'Discussion' } }
diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb
index 8d2806cbef6..176585e2ded 100644
--- a/spec/helpers/notifications_helper_spec.rb
+++ b/spec/helpers/notifications_helper_spec.rb
@@ -4,12 +4,12 @@ require 'spec_helper'
RSpec.describe NotificationsHelper do
describe 'notification_icon' do
- it { expect(notification_icon(:disabled)).to match('class="fa fa-microphone-slash fa-fw"') }
- it { expect(notification_icon(:owner_disabled)).to match('class="fa fa-microphone-slash fa-fw"') }
- it { expect(notification_icon(:participating)).to match('class="fa fa-volume-up fa-fw"') }
- it { expect(notification_icon(:mention)).to match('class="fa fa-at fa-fw"') }
- it { expect(notification_icon(:global)).to match('class="fa fa-globe fa-fw"') }
- it { expect(notification_icon(:watch)).to match('class="fa fa-eye fa-fw"') }
+ it { expect(notification_icon(:disabled)).to match('data-testid="notifications-off-icon"') }
+ it { expect(notification_icon(:owner_disabled)).to match('data-testid="notifications-off-icon"') }
+ it { expect(notification_icon(:participating)).to match('data-testid="notifications-icon"') }
+ it { expect(notification_icon(:mention)).to match('data-testid="at-icon"') }
+ it { expect(notification_icon(:global)).to match('data-testid="earth-icon') }
+ it { expect(notification_icon(:watch)).to match('data-testid="eye-icon"') }
end
describe 'notification_title' do
diff --git a/spec/helpers/operations_helper_spec.rb b/spec/helpers/operations_helper_spec.rb
index 8e3b1db5272..3dac2cf54dc 100644
--- a/spec/helpers/operations_helper_spec.rb
+++ b/spec/helpers/operations_helper_spec.rb
@@ -137,7 +137,8 @@ RSpec.describe OperationsHelper do
:project_incident_management_setting,
project: project,
issue_template_key: 'template-key',
- pagerduty_active: true
+ pagerduty_active: true,
+ auto_close_incident: false
)
end
@@ -150,6 +151,7 @@ RSpec.describe OperationsHelper do
create_issue: 'false',
issue_template_key: 'template-key',
send_email: 'false',
+ auto_close_incident: 'false',
pagerduty_active: 'true',
pagerduty_token: operations_settings.pagerduty_token,
pagerduty_webhook_url: project_incidents_integrations_pagerduty_url(project, token: operations_settings.pagerduty_token),
diff --git a/spec/helpers/releases_helper_spec.rb b/spec/helpers/releases_helper_spec.rb
index 6ae99648ff3..f10a2ed8e60 100644
--- a/spec/helpers/releases_helper_spec.rb
+++ b/spec/helpers/releases_helper_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe ReleasesHelper do
let(:release) { create(:release, project: project) }
let(:user) { create(:user) }
let(:can_user_create_release) { false }
- let(:common_keys) { [:project_id, :illustration_path, :documentation_path] }
+ let(:common_keys) { [:project_id, :project_path, :illustration_path, :documentation_path] }
# rubocop: disable CodeReuse/ActiveRecord
before do
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index 699232e67b1..594c5c11994 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe SearchHelper do
+ include MarkupHelper
+
# Override simple_sanitize for our testing purposes
def simple_sanitize(str)
str
@@ -71,6 +73,72 @@ RSpec.describe SearchHelper do
expect(result.keys).to match_array(%i[category id label url avatar_url])
end
+ it 'includes the first 5 of the users recent issues' do
+ recent_issues = instance_double(::Gitlab::Search::RecentIssues)
+ expect(::Gitlab::Search::RecentIssues).to receive(:new).with(user: user).and_return(recent_issues)
+ project1 = create(:project, :with_avatar, namespace: user.namespace)
+ project2 = create(:project, namespace: user.namespace)
+ issue1 = create(:issue, title: 'issue 1', project: project1)
+ issue2 = create(:issue, title: 'issue 2', project: project2)
+
+ other_issues = create_list(:issue, 5)
+
+ expect(recent_issues).to receive(:search).with('the search term').and_return(Issue.id_in_ordered([issue1.id, issue2.id, *other_issues.map(&:id)]))
+
+ results = search_autocomplete_opts("the search term")
+
+ expect(results.count).to eq(5)
+
+ expect(results[0]).to include({
+ category: 'Recent issues',
+ id: issue1.id,
+ label: 'issue 1',
+ url: Gitlab::Routing.url_helpers.project_issue_path(issue1.project, issue1),
+ avatar_url: project1.avatar_url
+ })
+
+ expect(results[1]).to include({
+ category: 'Recent issues',
+ id: issue2.id,
+ label: 'issue 2',
+ url: Gitlab::Routing.url_helpers.project_issue_path(issue2.project, issue2),
+ avatar_url: '' # This project didn't have an avatar so set this to ''
+ })
+ end
+
+ it 'includes the first 5 of the users recent merge requests' do
+ recent_merge_requests = instance_double(::Gitlab::Search::RecentMergeRequests)
+ expect(::Gitlab::Search::RecentMergeRequests).to receive(:new).with(user: user).and_return(recent_merge_requests)
+ project1 = create(:project, :with_avatar, namespace: user.namespace)
+ project2 = create(:project, namespace: user.namespace)
+ merge_request1 = create(:merge_request, :unique_branches, title: 'Merge request 1', target_project: project1, source_project: project1)
+ merge_request2 = create(:merge_request, :unique_branches, title: 'Merge request 2', target_project: project2, source_project: project2)
+
+ other_merge_requests = create_list(:merge_request, 5)
+
+ expect(recent_merge_requests).to receive(:search).with('the search term').and_return(MergeRequest.id_in_ordered([merge_request1.id, merge_request2.id, *other_merge_requests.map(&:id)]))
+
+ results = search_autocomplete_opts("the search term")
+
+ expect(results.count).to eq(5)
+
+ expect(results[0]).to include({
+ category: 'Recent merge requests',
+ id: merge_request1.id,
+ label: 'Merge request 1',
+ url: Gitlab::Routing.url_helpers.project_merge_request_path(merge_request1.project, merge_request1),
+ avatar_url: project1.avatar_url
+ })
+
+ expect(results[1]).to include({
+ category: 'Recent merge requests',
+ id: merge_request2.id,
+ label: 'Merge request 2',
+ url: Gitlab::Routing.url_helpers.project_merge_request_path(merge_request2.project, merge_request2),
+ avatar_url: '' # This project didn't have an avatar so set this to ''
+ })
+ end
+
it "does not include the public group" do
group = create(:group)
expect(search_autocomplete_opts(group.name).size).to eq(0)
@@ -228,6 +296,20 @@ RSpec.describe SearchHelper do
end
end
+ describe 'search_md_sanitize' do
+ it 'does not do extra sql queries for partial markdown rendering' do
+ @project = create(:project)
+
+ description = FFaker::Lorem.characters(210)
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { search_md_sanitize(description) }.count
+
+ issues = create_list(:issue, 4, project: @project)
+
+ description_with_issues = description + ' ' + issues.map { |issue| "##{issue.iid}" }.join(' ')
+ expect { search_md_sanitize(description_with_issues) }.not_to exceed_all_query_limit(control_count)
+ end
+ end
+
describe 'search_filter_link' do
it 'renders a search filter link for the current scope' do
@scope = 'projects'
diff --git a/spec/helpers/services_helper_spec.rb b/spec/helpers/services_helper_spec.rb
index 481bc41bcf3..d6b48b3d565 100644
--- a/spec/helpers/services_helper_spec.rb
+++ b/spec/helpers/services_helper_spec.rb
@@ -21,9 +21,42 @@ RSpec.describe ServicesHelper do
:comment_detail,
:trigger_events,
:fields,
- :inherit_from_id
+ :inherit_from_id,
+ :integration_level
)
end
end
end
+
+ describe '#group_level_integrations?' do
+ subject { helper.group_level_integrations? }
+
+ context 'when no group is present' do
+ it { is_expected.to eq(false) }
+ end
+
+ context 'when group is present' do
+ let(:group) { build_stubbed(:group) }
+
+ before do
+ assign(:group, group)
+ end
+
+ context 'when `group_level_integrations` is not enabled' do
+ it 'returns false' do
+ stub_feature_flags(group_level_integrations: false)
+
+ is_expected.to eq(false)
+ end
+ end
+
+ context 'when `group_level_integrations` is enabled for the group' do
+ it 'returns true' do
+ stub_feature_flags(group_level_integrations: group)
+
+ is_expected.to eq(true)
+ end
+ end
+ end
+ end
end
diff --git a/spec/helpers/snippets_helper_spec.rb b/spec/helpers/snippets_helper_spec.rb
index 302122c3990..a3244bec56f 100644
--- a/spec/helpers/snippets_helper_spec.rb
+++ b/spec/helpers/snippets_helper_spec.rb
@@ -109,7 +109,7 @@ RSpec.describe SnippetsHelper do
end
def download_link(url)
- "<a target=\"_blank\" rel=\"noopener noreferrer\" class=\"btn btn-sm has-tooltip\" title=\"Download\" data-container=\"body\" href=\"#{url}?inline=false\"><i aria-hidden=\"true\" data-hidden=\"true\" class=\"fa fa-download\"></i></a>"
+ "<a target=\"_blank\" rel=\"noopener noreferrer\" class=\"btn btn-sm has-tooltip\" title=\"Download\" data-container=\"body\" href=\"#{url}?inline=false\">#{sprite_icon('download')}</a>"
end
end
diff --git a/spec/helpers/storage_helper_spec.rb b/spec/helpers/storage_helper_spec.rb
index eca42c8ce06..255ec2a41b4 100644
--- a/spec/helpers/storage_helper_spec.rb
+++ b/spec/helpers/storage_helper_spec.rb
@@ -22,11 +22,12 @@ RSpec.describe StorageHelper do
end
describe "#storage_counters_details" do
- let(:namespace) { create :namespace }
- let(:project) do
+ let_it_be(:namespace) { create(:namespace) }
+ let_it_be(:project) do
create(:project,
namespace: namespace,
statistics: build(:project_statistics,
+ namespace: namespace,
repository_size: 10.kilobytes,
wiki_size: 10.bytes,
lfs_objects_size: 20.gigabytes,
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index 426bca2ced2..a419b6b9c84 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -24,7 +24,11 @@ RSpec.describe SubmoduleHelper do
allow(Gitlab.config.gitlab_shell).to receive(:ssh_port).and_return(22) # set this just to be sure
allow(Gitlab.config.gitlab_shell).to receive(:ssh_path_prefix).and_return(Settings.send(:build_gitlab_shell_ssh_path_prefix))
stub_url([config.ssh_user, '@', config.host, ':gitlab-org/gitlab-foss.git'].join(''))
- expect(subject).to eq([namespace_project_path('gitlab-org', 'gitlab-foss'), namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash')])
+ aggregate_failures do
+ expect(subject.web).to eq(namespace_project_path('gitlab-org', 'gitlab-foss'))
+ expect(subject.tree).to eq(namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash'))
+ expect(subject.compare).to be_nil
+ end
end
it 'detects ssh on standard port without a username' do
@@ -32,14 +36,22 @@ RSpec.describe SubmoduleHelper do
allow(Gitlab.config.gitlab_shell).to receive(:ssh_user).and_return('')
allow(Gitlab.config.gitlab_shell).to receive(:ssh_path_prefix).and_return(Settings.send(:build_gitlab_shell_ssh_path_prefix))
stub_url([config.host, ':gitlab-org/gitlab-foss.git'].join(''))
- expect(subject).to eq([namespace_project_path('gitlab-org', 'gitlab-foss'), namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash')])
+ aggregate_failures do
+ expect(subject.web).to eq(namespace_project_path('gitlab-org', 'gitlab-foss'))
+ expect(subject.tree).to eq(namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash'))
+ expect(subject.compare).to be_nil
+ end
end
it 'detects ssh on non-standard port' do
allow(Gitlab.config.gitlab_shell).to receive(:ssh_port).and_return(2222)
allow(Gitlab.config.gitlab_shell).to receive(:ssh_path_prefix).and_return(Settings.send(:build_gitlab_shell_ssh_path_prefix))
stub_url(['ssh://', config.ssh_user, '@', config.host, ':2222/gitlab-org/gitlab-foss.git'].join(''))
- expect(subject).to eq([namespace_project_path('gitlab-org', 'gitlab-foss'), namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash')])
+ aggregate_failures do
+ expect(subject.web).to eq(namespace_project_path('gitlab-org', 'gitlab-foss'))
+ expect(subject.tree).to eq(namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash'))
+ expect(subject.compare).to be_nil
+ end
end
it 'detects ssh on non-standard port without a username' do
@@ -47,21 +59,33 @@ RSpec.describe SubmoduleHelper do
allow(Gitlab.config.gitlab_shell).to receive(:ssh_user).and_return('')
allow(Gitlab.config.gitlab_shell).to receive(:ssh_path_prefix).and_return(Settings.send(:build_gitlab_shell_ssh_path_prefix))
stub_url(['ssh://', config.host, ':2222/gitlab-org/gitlab-foss.git'].join(''))
- expect(subject).to eq([namespace_project_path('gitlab-org', 'gitlab-foss'), namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash')])
+ aggregate_failures do
+ expect(subject.web).to eq(namespace_project_path('gitlab-org', 'gitlab-foss'))
+ expect(subject.tree).to eq(namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash'))
+ expect(subject.compare).to be_nil
+ end
end
it 'detects http on standard port' do
allow(Gitlab.config.gitlab).to receive(:port).and_return(80)
allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url))
stub_url(['http://', config.host, '/gitlab-org/gitlab-foss.git'].join(''))
- expect(subject).to eq([namespace_project_path('gitlab-org', 'gitlab-foss'), namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash')])
+ aggregate_failures do
+ expect(subject.web).to eq(namespace_project_path('gitlab-org', 'gitlab-foss'))
+ expect(subject.tree).to eq(namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash'))
+ expect(subject.compare).to be_nil
+ end
end
it 'detects http on non-standard port' do
allow(Gitlab.config.gitlab).to receive(:port).and_return(3000)
allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url))
stub_url(['http://', config.host, ':3000/gitlab-org/gitlab-foss.git'].join(''))
- expect(subject).to eq([namespace_project_path('gitlab-org', 'gitlab-foss'), namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash')])
+ aggregate_failures do
+ expect(subject.web).to eq(namespace_project_path('gitlab-org', 'gitlab-foss'))
+ expect(subject.tree).to eq(namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash'))
+ expect(subject.compare).to be_nil
+ end
end
it 'works with relative_url_root' do
@@ -69,7 +93,11 @@ RSpec.describe SubmoduleHelper do
allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return('/gitlab/root')
allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url))
stub_url(['http://', config.host, '/gitlab/root/gitlab-org/gitlab-foss.git'].join(''))
- expect(subject).to eq([namespace_project_path('gitlab-org', 'gitlab-foss'), namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash')])
+ aggregate_failures do
+ expect(subject.web).to eq(namespace_project_path('gitlab-org', 'gitlab-foss'))
+ expect(subject.tree).to eq(namespace_project_tree_path('gitlab-org', 'gitlab-foss', 'hash'))
+ expect(subject.compare).to be_nil
+ end
end
it 'works with subgroups' do
@@ -77,61 +105,105 @@ RSpec.describe SubmoduleHelper do
allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return('/gitlab/root')
allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url))
stub_url(['http://', config.host, '/gitlab/root/gitlab-org/sub/gitlab-foss.git'].join(''))
- expect(subject).to eq([namespace_project_path('gitlab-org/sub', 'gitlab-foss'), namespace_project_tree_path('gitlab-org/sub', 'gitlab-foss', 'hash')])
+ aggregate_failures do
+ expect(subject.web).to eq(namespace_project_path('gitlab-org/sub', 'gitlab-foss'))
+ expect(subject.tree).to eq(namespace_project_tree_path('gitlab-org/sub', 'gitlab-foss', 'hash'))
+ expect(subject.compare).to be_nil
+ end
end
end
context 'submodule on gist.github.com' do
it 'detects ssh' do
stub_url('git@gist.github.com:gitlab-org/gitlab-foss.git')
- is_expected.to eq(['https://gist.github.com/gitlab-org/gitlab-foss', 'https://gist.github.com/gitlab-org/gitlab-foss/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://gist.github.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://gist.github.com/gitlab-org/gitlab-foss/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'detects http' do
stub_url('http://gist.github.com/gitlab-org/gitlab-foss.git')
- is_expected.to eq(['https://gist.github.com/gitlab-org/gitlab-foss', 'https://gist.github.com/gitlab-org/gitlab-foss/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://gist.github.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://gist.github.com/gitlab-org/gitlab-foss/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'detects https' do
stub_url('https://gist.github.com/gitlab-org/gitlab-foss.git')
- is_expected.to eq(['https://gist.github.com/gitlab-org/gitlab-foss', 'https://gist.github.com/gitlab-org/gitlab-foss/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://gist.github.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://gist.github.com/gitlab-org/gitlab-foss/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'handles urls with no .git on the end' do
stub_url('http://gist.github.com/gitlab-org/gitlab-foss')
- is_expected.to eq(['https://gist.github.com/gitlab-org/gitlab-foss', 'https://gist.github.com/gitlab-org/gitlab-foss/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://gist.github.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://gist.github.com/gitlab-org/gitlab-foss/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'returns original with non-standard url' do
stub_url('http://gist.github.com/another/gitlab-org/gitlab-foss.git')
- is_expected.to eq([repo.submodule_url_for, nil])
+ aggregate_failures do
+ expect(subject.web).to eq(repo.submodule_url_for)
+ expect(subject.tree).to be_nil
+ expect(subject.compare).to be_nil
+ end
end
end
context 'submodule on github.com' do
it 'detects ssh' do
stub_url('git@github.com:gitlab-org/gitlab-foss.git')
- expect(subject).to eq(['https://github.com/gitlab-org/gitlab-foss', 'https://github.com/gitlab-org/gitlab-foss/tree/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://github.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://github.com/gitlab-org/gitlab-foss/tree/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'detects http' do
stub_url('http://github.com/gitlab-org/gitlab-foss.git')
- expect(subject).to eq(['https://github.com/gitlab-org/gitlab-foss', 'https://github.com/gitlab-org/gitlab-foss/tree/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://github.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://github.com/gitlab-org/gitlab-foss/tree/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'detects https' do
stub_url('https://github.com/gitlab-org/gitlab-foss.git')
- expect(subject).to eq(['https://github.com/gitlab-org/gitlab-foss', 'https://github.com/gitlab-org/gitlab-foss/tree/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://github.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://github.com/gitlab-org/gitlab-foss/tree/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'handles urls with no .git on the end' do
stub_url('http://github.com/gitlab-org/gitlab-foss')
- expect(subject).to eq(['https://github.com/gitlab-org/gitlab-foss', 'https://github.com/gitlab-org/gitlab-foss/tree/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://github.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://github.com/gitlab-org/gitlab-foss/tree/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'returns original with non-standard url' do
stub_url('http://github.com/another/gitlab-org/gitlab-foss.git')
- expect(subject).to eq([repo.submodule_url_for, nil])
+ aggregate_failures do
+ expect(subject.web).to eq(repo.submodule_url_for)
+ expect(subject.tree).to be_nil
+ expect(subject.compare).to be_nil
+ end
end
end
@@ -143,39 +215,67 @@ RSpec.describe SubmoduleHelper do
allow(repo).to receive(:project).and_return(project)
stub_url('./')
- expect(subject).to eq(["/master-project/#{project.path}", "/master-project/#{project.path}/-/tree/hash"])
+ aggregate_failures do
+ expect(subject.web).to eq("/master-project/#{project.path}")
+ expect(subject.tree).to eq("/master-project/#{project.path}/-/tree/hash")
+ expect(subject.compare).to be_nil
+ end
end
end
context 'submodule on gitlab.com' do
it 'detects ssh' do
stub_url('git@gitlab.com:gitlab-org/gitlab-foss.git')
- expect(subject).to eq(['https://gitlab.com/gitlab-org/gitlab-foss', 'https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://gitlab.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'detects http' do
stub_url('http://gitlab.com/gitlab-org/gitlab-foss.git')
- expect(subject).to eq(['https://gitlab.com/gitlab-org/gitlab-foss', 'https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://gitlab.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'detects https' do
stub_url('https://gitlab.com/gitlab-org/gitlab-foss.git')
- expect(subject).to eq(['https://gitlab.com/gitlab-org/gitlab-foss', 'https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://gitlab.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'handles urls with no .git on the end' do
stub_url('http://gitlab.com/gitlab-org/gitlab-foss')
- expect(subject).to eq(['https://gitlab.com/gitlab-org/gitlab-foss', 'https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://gitlab.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'handles urls with trailing whitespace' do
stub_url('http://gitlab.com/gitlab-org/gitlab-foss.git ')
- expect(subject).to eq(['https://gitlab.com/gitlab-org/gitlab-foss', 'https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash'])
+ aggregate_failures do
+ expect(subject.web).to eq('https://gitlab.com/gitlab-org/gitlab-foss')
+ expect(subject.tree).to eq('https://gitlab.com/gitlab-org/gitlab-foss/-/tree/hash')
+ expect(subject.compare).to be_nil
+ end
end
it 'returns original with non-standard url' do
stub_url('http://gitlab.com/another/gitlab-org/gitlab-foss.git')
- expect(subject).to eq([repo.submodule_url_for, nil])
+ aggregate_failures do
+ expect(subject.web).to eq(repo.submodule_url_for)
+ expect(subject.tree).to be_nil
+ expect(subject.compare).to be_nil
+ end
end
end
@@ -183,25 +283,29 @@ RSpec.describe SubmoduleHelper do
it 'sanitizes unsupported protocols' do
stub_url('javascript:alert("XSS");')
- expect(subject).to eq([nil, nil])
+ expect(subject).to be_nil
end
it 'sanitizes unsupported protocols disguised as a repository URL' do
stub_url('javascript:alert("XSS");foo/bar.git')
- expect(subject).to eq([nil, nil])
+ expect(subject).to be_nil
end
it 'sanitizes invalid URL with extended ASCII' do
stub_url('é')
- expect(subject).to eq([nil, nil])
+ expect(subject).to be_nil
end
it 'returns original' do
stub_url('http://mygitserver.com/gitlab-org/gitlab-foss')
- expect(subject).to eq([repo.submodule_url_for, nil])
+ aggregate_failures do
+ expect(subject.web).to eq(repo.submodule_url_for)
+ expect(subject.tree).to be_nil
+ expect(subject.compare).to be_nil
+ end
end
end
@@ -214,7 +318,11 @@ RSpec.describe SubmoduleHelper do
stub_url(relative_path)
result = subject
- expect(result).to eq([expected_path, "#{expected_path}/-/tree/#{submodule_item.id}"])
+ aggregate_failures do
+ expect(result.web).to eq(expected_path)
+ expect(result.tree).to eq("#{expected_path}/-/tree/#{submodule_item.id}")
+ expect(result.compare).to be_nil
+ end
end
it 'handles project under same group' do
@@ -235,7 +343,7 @@ RSpec.describe SubmoduleHelper do
result = subject
- expect(result).to eq([nil, nil])
+ expect(result).to be_nil
end
end
@@ -245,7 +353,7 @@ RSpec.describe SubmoduleHelper do
result = subject
- expect(result).to eq([nil, nil])
+ expect(result).to be_nil
end
end
@@ -289,7 +397,7 @@ RSpec.describe SubmoduleHelper do
end
it 'returns no links' do
- expect(subject).to eq([nil, nil])
+ expect(subject).to be_nil
end
end
end
diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb
index 307479744ef..97b6802dde9 100644
--- a/spec/helpers/tree_helper_spec.rb
+++ b/spec/helpers/tree_helper_spec.rb
@@ -156,21 +156,36 @@ RSpec.describe TreeHelper do
end
describe '#vue_file_list_data' do
- before do
- allow(helper).to receive(:current_user).and_return(nil)
- end
-
it 'returns a list of attributes related to the project' do
expect(helper.vue_file_list_data(project, sha)).to include(
- can_push_code: nil,
- fork_path: nil,
- escaped_ref: sha,
- ref: sha,
project_path: project.full_path,
project_short_path: project.path,
+ ref: sha,
+ escaped_ref: sha,
full_name: project.name_with_namespace
)
end
+ end
+
+ describe '#vue_ide_link_data' do
+ before do
+ allow(helper).to receive(:current_user).and_return(nil)
+ allow(helper).to receive(:can_collaborate_with_project?).and_return(true)
+ allow(helper).to receive(:can?).and_return(true)
+ end
+
+ subject { helper.vue_ide_link_data(project, sha) }
+
+ it 'returns a list of attributes related to the project' do
+ expect(subject).to include(
+ ide_base_path: project.full_path,
+ needs_to_fork: false,
+ show_web_ide_button: true,
+ show_gitpod_button: false,
+ gitpod_url: "",
+ gitpod_enabled: nil
+ )
+ end
context 'user does not have write access but a personal fork exists' do
include ProjectForksHelper
@@ -185,9 +200,9 @@ RSpec.describe TreeHelper do
allow(helper).to receive(:current_user).and_return(user)
end
- it 'includes fork_path too' do
- expect(helper.vue_file_list_data(project, sha)).to include(
- fork_path: forked_project.full_path
+ it 'includes ide_base_path: forked_project.full_path' do
+ expect(subject).to include(
+ ide_base_path: forked_project.full_path
)
end
end
@@ -201,9 +216,54 @@ RSpec.describe TreeHelper do
allow(helper).to receive(:current_user).and_return(user)
end
- it 'includes can_push_code: true' do
- expect(helper.vue_file_list_data(project, sha)).to include(
- can_push_code: "true"
+ it 'includes ide_base_path: project.full_path' do
+ expect(subject).to include(
+ ide_base_path: project.full_path
+ )
+ end
+ end
+
+ context 'gitpod feature is enabled' do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ stub_feature_flags(gitpod: true)
+ allow(Gitlab::CurrentSettings)
+ .to receive(:gitpod_enabled)
+ .and_return(true)
+
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ it 'has show_gitpod_button: true' do
+ expect(subject).to include(
+ show_gitpod_button: true
+ )
+ end
+
+ it 'has gitpod_enabled: true when user has enabled gitpod' do
+ user.gitpod_enabled = true
+
+ expect(subject).to include(
+ gitpod_enabled: true
+ )
+ end
+
+ it 'has gitpod_enabled: false when user has not enabled gitpod' do
+ user.gitpod_enabled = false
+
+ expect(subject).to include(
+ gitpod_enabled: false
+ )
+ end
+
+ it 'has show_gitpod_button: false when web ide button is not shown' do
+ allow(helper).to receive(:can_collaborate_with_project?).and_return(false)
+ allow(helper).to receive(:can?).and_return(false)
+
+ expect(subject).to include(
+ show_web_ide_button: false,
+ show_gitpod_button: false
)
end
end
diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb
index 6f1f358af83..a42be3c87fb 100644
--- a/spec/helpers/user_callouts_helper_spec.rb
+++ b/spec/helpers/user_callouts_helper_spec.rb
@@ -81,6 +81,26 @@ RSpec.describe UserCalloutsHelper do
end
end
+ describe '.show_service_templates_deprecated?' do
+ subject { helper.show_service_templates_deprecated? }
+
+ context 'when user has not dismissed' do
+ before do
+ allow(helper).to receive(:user_dismissed?).with(described_class::SERVICE_TEMPLATES_DEPRECATED) { false }
+ end
+
+ it { is_expected.to be true }
+ end
+
+ context 'when user dismissed' do
+ before do
+ allow(helper).to receive(:user_dismissed?).with(described_class::SERVICE_TEMPLATES_DEPRECATED) { true }
+ end
+
+ it { is_expected.to be false }
+ end
+ end
+
describe '.show_customize_homepage_banner?' do
let(:customize_homepage) { true }
diff --git a/spec/helpers/whats_new_helper_spec.rb b/spec/helpers/whats_new_helper_spec.rb
new file mode 100644
index 00000000000..db880163454
--- /dev/null
+++ b/spec/helpers/whats_new_helper_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WhatsNewHelper do
+ describe '#whats_new_most_recent_release_items' do
+ let(:fixture_dir_glob) { Dir.glob(File.join('spec', 'fixtures', 'whats_new', '*.yml')) }
+
+ it 'returns json from the most recent file' do
+ allow(Dir).to receive(:glob).with(Rails.root.join('data', 'whats_new', '*.yml')).and_return(fixture_dir_glob)
+
+ expect(helper.whats_new_most_recent_release_items).to include({ title: "bright and sunshinin' day" }.to_json)
+ end
+
+ it 'fails gracefully and logs an error' do
+ allow(YAML).to receive(:load_file).and_raise
+
+ expect(Gitlab::ErrorTracking).to receive(:track_exception)
+ expect(helper.whats_new_most_recent_release_items).to eq(''.to_json)
+ end
+ end
+end
diff --git a/spec/helpers/wiki_helper_spec.rb b/spec/helpers/wiki_helper_spec.rb
index 6c7172e6232..65a52412f8c 100644
--- a/spec/helpers/wiki_helper_spec.rb
+++ b/spec/helpers/wiki_helper_spec.rb
@@ -53,6 +53,22 @@ RSpec.describe WikiHelper do
end
end
+ describe '#wiki_attachment_upload_url' do
+ it 'returns the upload endpoint for project wikis' do
+ @wiki = build_stubbed(:project_wiki)
+
+ expect(helper.wiki_attachment_upload_url).to end_with("/api/v4/projects/#{@wiki.project.id}/wikis/attachments")
+ end
+
+ it 'raises an exception for unsupported wiki containers' do
+ @wiki = Wiki.new(User.new)
+
+ expect do
+ helper.wiki_attachment_upload_url
+ end.to raise_error(TypeError)
+ end
+ end
+
describe '#wiki_sort_controls' do
let(:wiki) { create(:project_wiki) }
let(:wiki_link) { helper.wiki_sort_controls(wiki, sort, direction) }