From 311b0269b4eb9839fa63f80c8d7a58f32b8138a0 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 18 Nov 2021 13:16:36 +0000 Subject: Add latest changes from gitlab-org/gitlab@14-5-stable-ee --- spec/helpers/admin/deploy_key_helper_spec.rb | 28 +++ spec/helpers/boards_helper_spec.rb | 6 +- spec/helpers/ci/pipelines_helper_spec.rb | 22 +++ spec/helpers/ci/runners_helper_spec.rb | 72 +++++-- spec/helpers/clusters_helper_spec.rb | 120 ++++++++--- spec/helpers/emoji_helper_spec.rb | 5 +- spec/helpers/environments_helper_spec.rb | 64 +----- spec/helpers/graph_helper_spec.rb | 12 ++ spec/helpers/groups/settings_helper_spec.rb | 38 ++++ spec/helpers/groups_helper_spec.rb | 2 +- spec/helpers/invite_members_helper_spec.rb | 79 +++++++- .../issuables_description_templates_helper_spec.rb | 14 +- spec/helpers/issuables_helper_spec.rb | 23 +-- spec/helpers/issues_helper_spec.rb | 1 + spec/helpers/learn_gitlab_helper_spec.rb | 155 +++++++++++---- spec/helpers/members_helper_spec.rb | 6 + spec/helpers/nav/top_nav_helper_spec.rb | 5 + spec/helpers/notes_helper_spec.rb | 12 +- spec/helpers/one_trust_helper_spec.rb | 19 +- .../projects/alert_management_helper_spec.rb | 33 +--- spec/helpers/projects/incidents_helper_spec.rb | 49 +++-- .../projects/security/configuration_helper_spec.rb | 2 +- spec/helpers/projects_helper_spec.rb | 18 +- .../routing/pseudonymization_helper_spec.rb | 220 ++++++++++++++++----- spec/helpers/storage_helper_spec.rb | 19 +- spec/helpers/tab_helper_spec.rb | 28 ++- spec/helpers/terms_helper_spec.rb | 44 +++++ spec/helpers/time_zone_helper_spec.rb | 32 +++ spec/helpers/user_callouts_helper_spec.rb | 14 -- spec/helpers/users_helper_spec.rb | 2 +- spec/helpers/wiki_helper_spec.rb | 6 +- 31 files changed, 819 insertions(+), 331 deletions(-) create mode 100644 spec/helpers/admin/deploy_key_helper_spec.rb create mode 100644 spec/helpers/groups/settings_helper_spec.rb create mode 100644 spec/helpers/terms_helper_spec.rb (limited to 'spec/helpers') diff --git a/spec/helpers/admin/deploy_key_helper_spec.rb b/spec/helpers/admin/deploy_key_helper_spec.rb new file mode 100644 index 00000000000..ca951ccf485 --- /dev/null +++ b/spec/helpers/admin/deploy_key_helper_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Admin::DeployKeyHelper do + describe '#admin_deploy_keys_data' 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' } + + subject(:result) { helper.admin_deploy_keys_data } + + it 'returns correct hash' 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(result).to eq({ + edit_path: edit_path, + delete_path: delete_path, + create_path: create_path, + empty_state_svg_path: empty_state_svg_path + }) + end + end +end diff --git a/spec/helpers/boards_helper_spec.rb b/spec/helpers/boards_helper_spec.rb index cb4b6915b20..ec949fde30e 100644 --- a/spec/helpers/boards_helper_spec.rb +++ b/spec/helpers/boards_helper_spec.rb @@ -23,14 +23,14 @@ RSpec.describe BoardsHelper do it 'returns correct path for base group' do assign(:board, group_board) - expect(helper.build_issue_link_base).to eq('/base/:project_path/issues') + expect(helper.build_issue_link_base).to eq('/:project_path/-/issues') end it 'returns correct path for subgroup' do subgroup = create(:group, parent: base_group, path: 'sub') assign(:board, create(:board, group: subgroup)) - expect(helper.build_issue_link_base).to eq('/base/sub/:project_path/issues') + expect(helper.build_issue_link_base).to eq('/:project_path/-/issues') end end end @@ -149,7 +149,7 @@ RSpec.describe BoardsHelper do end it 'returns correct path for base group' do - expect(helper.build_issue_link_base).to eq("/#{base_group.full_path}/:project_path/issues") + expect(helper.build_issue_link_base).to eq("/:project_path/-/issues") end it 'returns required label endpoints' do diff --git a/spec/helpers/ci/pipelines_helper_spec.rb b/spec/helpers/ci/pipelines_helper_spec.rb index 94b5e707d73..751bcc97582 100644 --- a/spec/helpers/ci/pipelines_helper_spec.rb +++ b/spec/helpers/ci/pipelines_helper_spec.rb @@ -71,4 +71,26 @@ RSpec.describe Ci::PipelinesHelper do it { expect(has_gitlab_ci?).to eq(result) } end end + + describe 'has_pipeline_badges?' do + let(:pipeline) { create(:ci_empty_pipeline) } + + subject { helper.has_pipeline_badges?(pipeline) } + + context 'when pipeline has a badge' do + before do + pipeline.drop!(:config_error) + end + + it 'shows pipeline badges' do + expect(subject).to eq(true) + end + end + + context 'when pipeline has no badges' do + it 'shows pipeline badges' do + expect(subject).to eq(false) + end + end + end end diff --git a/spec/helpers/ci/runners_helper_spec.rb b/spec/helpers/ci/runners_helper_spec.rb index 49ea2ac8d3b..173a0d3ab3c 100644 --- a/spec/helpers/ci/runners_helper_spec.rb +++ b/spec/helpers/ci/runners_helper_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Ci::RunnersHelper do - let_it_be(:user, refind: true) { create(:user) } + let_it_be(:user) { create(:user) } before do allow(helper).to receive(:current_user).and_return(user) @@ -12,22 +12,22 @@ RSpec.describe Ci::RunnersHelper do describe '#runner_status_icon', :clean_gitlab_redis_cache do it "returns - not contacted yet" do runner = create(:ci_runner) - expect(runner_status_icon(runner)).to include("not connected yet") + expect(helper.runner_status_icon(runner)).to include("not connected yet") end it "returns offline text" do runner = create(:ci_runner, contacted_at: 1.day.ago, active: true) - expect(runner_status_icon(runner)).to include("Runner is offline") + expect(helper.runner_status_icon(runner)).to include("Runner is offline") end it "returns online text" do runner = create(:ci_runner, contacted_at: 1.second.ago, active: true) - expect(runner_status_icon(runner)).to include("Runner is online") + expect(helper.runner_status_icon(runner)).to include("Runner is online") end it "returns paused text" do runner = create(:ci_runner, contacted_at: 1.second.ago, active: false) - expect(runner_status_icon(runner)).to include("Runner is paused") + expect(helper.runner_status_icon(runner)).to include("Runner is paused") end end @@ -42,7 +42,7 @@ RSpec.describe Ci::RunnersHelper do context 'without sorting' do it 'returns cached value' do - expect(runner_contacted_at(runner)).to eq(contacted_at_cached) + expect(helper.runner_contacted_at(runner)).to eq(contacted_at_cached) end end @@ -52,7 +52,7 @@ RSpec.describe Ci::RunnersHelper do end it 'returns cached value' do - expect(runner_contacted_at(runner)).to eq(contacted_at_cached) + expect(helper.runner_contacted_at(runner)).to eq(contacted_at_cached) end end @@ -62,29 +62,63 @@ RSpec.describe Ci::RunnersHelper do end it 'returns stored value' do - expect(runner_contacted_at(runner)).to eq(contacted_at_stored) + expect(helper.runner_contacted_at(runner)).to eq(contacted_at_stored) end end 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 ) } + + 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 eq({ + runner_install_help_page: 'https://docs.gitlab.com/runner/install/', + registration_token: Gitlab::CurrentSettings.runners_registration_token, + active_runners_count: '0', + all_runners_count: '2', + instance_runners_count: '1', + group_runners_count: '0', + project_runners_count: '1' + }) + end + end + describe '#group_shared_runners_settings_data' do - let(:group) { create(:group, parent: parent, shared_runners_enabled: false) } - let(:parent) { create(:group) } + let_it_be(:parent) { create(:group) } + let_it_be(:group) { create(:group, parent: parent, shared_runners_enabled: false) } + + let(:runner_constants) do + { + runner_enabled: Namespace::SR_ENABLED, + runner_disabled: Namespace::SR_DISABLED_AND_UNOVERRIDABLE, + runner_allow_override: Namespace::SR_DISABLED_WITH_OVERRIDE + } + end it 'returns group data for top level group' do - data = group_shared_runners_settings_data(parent) + result = { + update_path: "/api/v4/groups/#{parent.id}", + shared_runners_availability: Namespace::SR_ENABLED, + parent_shared_runners_availability: nil + }.merge(runner_constants) - expect(data[:update_path]).to eq("/api/v4/groups/#{parent.id}") - expect(data[:shared_runners_availability]).to eq('enabled') - expect(data[:parent_shared_runners_availability]).to eq(nil) + expect(helper.group_shared_runners_settings_data(parent)).to eq result end it 'returns group data for child group' do - data = group_shared_runners_settings_data(group) + result = { + update_path: "/api/v4/groups/#{group.id}", + shared_runners_availability: Namespace::SR_DISABLED_AND_UNOVERRIDABLE, + parent_shared_runners_availability: Namespace::SR_ENABLED + }.merge(runner_constants) - expect(data[:update_path]).to eq("/api/v4/groups/#{group.id}") - expect(data[:shared_runners_availability]).to eq(Namespace::SR_DISABLED_AND_UNOVERRIDABLE) - expect(data[:parent_shared_runners_availability]).to eq('enabled') + expect(helper.group_shared_runners_settings_data(group)).to eq result end end @@ -92,7 +126,7 @@ RSpec.describe Ci::RunnersHelper do let(:group) { create(:group) } it 'returns group data to render a runner list' do - data = group_runners_data_attributes(group) + data = helper.group_runners_data_attributes(group) expect(data[:registration_token]).to eq(group.runners_token) expect(data[:group_id]).to eq(group.id) diff --git a/spec/helpers/clusters_helper_spec.rb b/spec/helpers/clusters_helper_spec.rb index f1e19f17c72..51f111917d1 100644 --- a/spec/helpers/clusters_helper_spec.rb +++ b/spec/helpers/clusters_helper_spec.rb @@ -59,54 +59,96 @@ RSpec.describe ClustersHelper do end end - describe '#js_cluster_agents_list_data' do - let_it_be(:project) { build(:project, :repository) } + describe '#js_clusters_list_data' do + let_it_be(:current_user) { create(:user) } + let_it_be(:project) { build(:project) } + let_it_be(:clusterable) { ClusterablePresenter.fabricate(project, current_user: current_user) } - subject { helper.js_cluster_agents_list_data(project) } + subject { helper.js_clusters_list_data(clusterable) } - it 'displays project default branch' do - expect(subject[:default_branch_name]).to eq(project.default_branch) + it 'displays endpoint path' do + expect(subject[:endpoint]).to eq("#{project_path(project)}/-/clusters.json") end - it 'displays image path' do - expect(subject[:empty_state_image]).to match(%r(/illustrations/logos/clusters_empty|svg)) + it 'generates svg image data', :aggregate_failures do + expect(subject.dig(:img_tags, :aws, :path)).to match(%r(/illustrations/logos/amazon_eks|svg)) + expect(subject.dig(:img_tags, :default, :path)).to match(%r(/illustrations/logos/kubernetes|svg)) + expect(subject.dig(:img_tags, :gcp, :path)).to match(%r(/illustrations/logos/google_gke|svg)) + + expect(subject.dig(:img_tags, :aws, :text)).to eq('Amazon EKS') + expect(subject.dig(:img_tags, :default, :text)).to eq('Kubernetes Cluster') + expect(subject.dig(:img_tags, :gcp, :text)).to eq('Google GKE') end - it 'displays project path' do - expect(subject[:project_path]).to eq(project.full_path) + it 'displays and ancestor_help_path' do + expect(subject[:ancestor_help_path]).to eq(help_page_path('user/group/clusters/index', anchor: 'cluster-precedence')) end - it 'generates docs urls' do - expect(subject[:agent_docs_url]).to eq(help_page_path('user/clusters/agent/index')) - expect(subject[:install_docs_url]).to eq(help_page_path('administration/clusters/kas')) - expect(subject[:get_started_docs_url]).to eq(help_page_path('user/clusters/agent/index', anchor: 'define-a-configuration-repository')) - expect(subject[:integration_docs_url]).to eq(help_page_path('user/clusters/agent/index', anchor: 'get-started-with-gitops-and-the-gitlab-agent')) + it 'displays empty image path' do + expect(subject[:clusters_empty_state_image]).to match(%r(/illustrations/empty-state/empty-state-clusters|svg)) end - it 'displays kas address' do - expect(subject[:kas_address]).to eq(Gitlab::Kas.external_url) + it 'displays create cluster using certificate path' do + expect(subject[:new_cluster_path]).to eq("#{project_path(project)}/-/clusters/new?tab=create") + end + + context 'user has no permissions to create a cluster' do + it 'displays that user can\t add cluster' do + expect(subject[:can_add_cluster]).to eq("false") + end + end + + context 'user is a maintainer' do + before do + project.add_maintainer(current_user) + end + + it 'displays that the user can add cluster' do + expect(subject[:can_add_cluster]).to eq("true") + end + end + + context 'project cluster' do + it 'doesn\'t display empty state help text' do + expect(subject[:empty_state_help_text]).to be_nil + end + end + + context 'group cluster' do + let_it_be(:group) { create(:group) } + let_it_be(:clusterable) { ClusterablePresenter.fabricate(group, current_user: current_user) } + + it 'displays empty state help text' do + expect(subject[:empty_state_help_text]).to eq(s_('ClusterIntegration|Adding an integration to your group will share the cluster across all your projects.')) + end end end - describe '#js_clusters_list_data' do - subject { helper.js_clusters_list_data('/path') } + describe '#js_clusters_data' do + let_it_be(:current_user) { create(:user) } + let_it_be(:project) { build(:project) } + let_it_be(:clusterable) { ClusterablePresenter.fabricate(project, current_user: current_user) } - it 'displays endpoint path' do - expect(subject[:endpoint]).to eq('/path') + subject { helper.js_clusters_data(clusterable) } + + it 'displays project default branch' do + expect(subject[:default_branch_name]).to eq(project.default_branch) end - it 'generates svg image data', :aggregate_failures do - expect(subject.dig(:img_tags, :aws, :path)).to match(%r(/illustrations/logos/amazon_eks|svg)) - expect(subject.dig(:img_tags, :default, :path)).to match(%r(/illustrations/logos/kubernetes|svg)) - expect(subject.dig(:img_tags, :gcp, :path)).to match(%r(/illustrations/logos/google_gke|svg)) + it 'displays image path' do + expect(subject[:empty_state_image]).to match(%r(/illustrations/empty-state/empty-state-agents|svg)) + end - expect(subject.dig(:img_tags, :aws, :text)).to eq('Amazon EKS') - expect(subject.dig(:img_tags, :default, :text)).to eq('Kubernetes Cluster') - expect(subject.dig(:img_tags, :gcp, :text)).to eq('Google GKE') + it 'displays project path' do + expect(subject[:project_path]).to eq(project.full_path) end - it 'displays and ancestor_help_path' do - expect(subject[:ancestor_help_path]).to eq(help_page_path('user/group/clusters/index', anchor: 'cluster-precedence')) + it 'displays add cluster using certificate path' do + expect(subject[:add_cluster_path]).to eq("#{project_path(project)}/-/clusters/new?tab=add") + end + + it 'displays kas address' do + expect(subject[:kas_address]).to eq(Gitlab::Kas.external_url) end end @@ -152,4 +194,24 @@ RSpec.describe ClustersHelper do end end end + + describe '#display_cluster_agents?' do + subject { helper.display_cluster_agents?(clusterable) } + + context 'when clusterable is a project' do + let(:clusterable) { build(:project) } + + it 'allows agents to display' do + expect(subject).to be_truthy + end + end + + context 'when clusterable is a group' do + let(:clusterable) { build(:group) } + + it 'does not allow agents to display' do + expect(subject).to be_falsey + end + end + end end diff --git a/spec/helpers/emoji_helper_spec.rb b/spec/helpers/emoji_helper_spec.rb index 15e4ce03960..6f4c962c0fb 100644 --- a/spec/helpers/emoji_helper_spec.rb +++ b/spec/helpers/emoji_helper_spec.rb @@ -6,6 +6,7 @@ RSpec.describe EmojiHelper do describe '#emoji_icon' do let(:options) { {} } let(:emoji_text) { 'rocket' } + let(:unicode_version) { '6.0' } let(:aria_hidden_option) { "aria-hidden=\"true\"" } subject { helper.emoji_icon(emoji_text, options) } @@ -14,7 +15,7 @@ RSpec.describe EmojiHelper do is_expected.to include(' 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), - 'has_managed_prometheus' => 'false' + 'panel_preview_endpoint' => project_metrics_dashboards_builder_path(project, format: :json) ) end @@ -63,20 +61,6 @@ RSpec.describe EnvironmentsHelper do end end - context 'without read_prometheus_alerts permission' do - before do - allow(helper).to receive(:can?) - .with(user, :read_prometheus_alerts, project) - .and_return(false) - end - - it 'returns false' do - expect(metrics_data).to include( - 'prometheus_alerts_available' => 'false' - ) - end - end - context 'with metrics_setting' do before do create(:project_metrics_setting, project: project, external_dashboard_url: 'http://gitlab.com') @@ -120,52 +104,6 @@ RSpec.describe EnvironmentsHelper do end end end - - context 'has_managed_prometheus' do - context 'without prometheus integration' do - it "doesn't have managed prometheus" do - expect(metrics_data).to include( - 'has_managed_prometheus' => 'false' - ) - end - end - - context 'with prometheus integration' do - let_it_be(:prometheus_integration) { create(:prometheus_integration, project: project) } - - context 'when manual prometheus integration is active' do - it "doesn't have managed prometheus" do - prometheus_integration.update!(manual_configuration: true) - - expect(metrics_data).to include( - 'has_managed_prometheus' => 'false' - ) - end - end - - context 'when prometheus integration is inactive' do - it "doesn't have managed prometheus" do - prometheus_integration.update!(manual_configuration: false) - - expect(metrics_data).to include( - 'has_managed_prometheus' => 'false' - ) - end - end - - context 'when a cluster prometheus is available' do - let(:cluster) { create(:cluster, projects: [project]) } - - it 'has managed prometheus' do - create(:clusters_integrations_prometheus, cluster: cluster) - - expect(metrics_data).to include( - 'has_managed_prometheus' => 'true' - ) - end - end - end - end end describe '#custom_metrics_available?' do diff --git a/spec/helpers/graph_helper_spec.rb b/spec/helpers/graph_helper_spec.rb index 0930417accb..a5d4e1313e1 100644 --- a/spec/helpers/graph_helper_spec.rb +++ b/spec/helpers/graph_helper_spec.rb @@ -27,4 +27,16 @@ RSpec.describe GraphHelper do expect(should_render_dora_charts).to be(false) end end + + describe '#should_render_quality_summary' do + let(:project) { create(:project, :private) } + + before do + self.instance_variable_set(:@project, project) + end + + it 'always returns false' do + expect(should_render_quality_summary).to be(false) + end + end end diff --git a/spec/helpers/groups/settings_helper_spec.rb b/spec/helpers/groups/settings_helper_spec.rb new file mode 100644 index 00000000000..f8c0bfc19a1 --- /dev/null +++ b/spec/helpers/groups/settings_helper_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Groups::SettingsHelper do + include GroupsHelper + + let_it_be(:group) { create(:group, path: "foo") } + + describe('#group_settings_confirm_modal_data') do + using RSpec::Parameterized::TableSyntax + + fake_form_id = "fake_form_id" + + where(:is_paid, :is_button_disabled, :form_value_id) do + true | "true" | nil + true | "true" | fake_form_id + false | "false" | nil + false | "false" | fake_form_id + end + + with_them do + it "returns expected parameters" do + allow(group).to receive(:paid?).and_return(is_paid) + + expected = helper.group_settings_confirm_modal_data(group, form_value_id) + expect(expected).to eq({ + button_text: "Remove group", + confirm_danger_message: remove_group_message(group), + remove_form_id: form_value_id, + phrase: group.full_path, + button_testid: "remove-group-button", + disabled: is_button_disabled + }) + end + end + end +end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 4d647696130..8859ed27022 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -92,7 +92,7 @@ RSpec.describe GroupsHelper do shared_examples 'correct ancestor order' do it 'outputs the groups in the correct order' do expect(subject) - .to match(%r{
  • #{deep_nested_group.name}.*
  • .*#{very_deep_nested_group.name}}m) + .to match(%r{
  • #{deep_nested_group.name}.*
  • .*#{very_deep_nested_group.name}}m) end end diff --git a/spec/helpers/invite_members_helper_spec.rb b/spec/helpers/invite_members_helper_spec.rb index e0e05140d6c..02f0416a17a 100644 --- a/spec/helpers/invite_members_helper_spec.rb +++ b/spec/helpers/invite_members_helper_spec.rb @@ -59,7 +59,84 @@ RSpec.describe InviteMembersHelper do no_selection_areas_of_focus: [] } - expect(helper.common_invite_modal_dataset(project)).to match(attributes) + expect(helper.common_invite_modal_dataset(project)).to include(attributes) + end + end + + context 'tasks_to_be_done' do + subject(:output) { helper.common_invite_modal_dataset(source) } + + let_it_be(:source) { project } + + before do + stub_experiments(invite_members_for_task: true) + end + + context 'when not logged in' do + before do + allow(helper).to receive(:params).and_return({ open_modal: 'invite_members_for_task' }) + end + + it "doesn't have the tasks to be done attributes" do + expect(output[:tasks_to_be_done_options]).to be_nil + expect(output[:projects]).to be_nil + expect(output[:new_project_path]).to be_nil + end + end + + context 'when logged in but the open_modal param is not present' do + before do + allow(helper).to receive(:current_user).and_return(developer) + end + + it "doesn't have the tasks to be done attributes" do + expect(output[:tasks_to_be_done_options]).to be_nil + expect(output[:projects]).to be_nil + expect(output[:new_project_path]).to be_nil + end + end + + context 'when logged in and the open_modal param is present' do + before do + allow(helper).to receive(:current_user).and_return(developer) + allow(helper).to receive(:params).and_return({ open_modal: 'invite_members_for_task' }) + end + + context 'for a group' do + let_it_be(:source) { create(:group, projects: [project]) } + + it 'has the expected attributes', :aggregate_failures do + expect(output[:tasks_to_be_done_options]).to eq( + [ + { value: :code, text: 'Create/import code into a project (repository)' }, + { value: :ci, text: 'Set up CI/CD pipelines to build, test, deploy, and monitor code' }, + { value: :issues, text: 'Create/import issues (tickets) to collaborate on ideas and plan work' } + ].to_json + ) + expect(output[:projects]).to eq( + [{ id: project.id, title: project.title }].to_json + ) + expect(output[:new_project_path]).to eq( + new_project_path(namespace_id: source.id) + ) + end + end + + context 'for a project' do + it 'has the expected attributes', :aggregate_failures do + expect(output[:tasks_to_be_done_options]).to eq( + [ + { value: :code, text: 'Create/import code into a project (repository)' }, + { value: :ci, text: 'Set up CI/CD pipelines to build, test, deploy, and monitor code' }, + { value: :issues, text: 'Create/import issues (tickets) to collaborate on ideas and plan work' } + ].to_json + ) + expect(output[:projects]).to eq( + [{ id: project.id, title: project.title }].to_json + ) + expect(output[:new_project_path]).to eq('') + end + end end end end diff --git a/spec/helpers/issuables_description_templates_helper_spec.rb b/spec/helpers/issuables_description_templates_helper_spec.rb index 55649e9087a..6b05bab7432 100644 --- a/spec/helpers/issuables_description_templates_helper_spec.rb +++ b/spec/helpers/issuables_description_templates_helper_spec.rb @@ -44,7 +44,7 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do end end - describe '#issuable_templates_names' do + describe '#selected_template' do let_it_be(:project) { build(:project) } before do @@ -63,7 +63,14 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do end it 'returns project templates' do - expect(helper.issuable_templates_names(Issue.new)).to eq(%w[another_issue_template custom_issue_template]) + value = [ + "", + [ + { name: "another_issue_template", id: "another_issue_template", project_id: project.id }, + { name: "custom_issue_template", id: "custom_issue_template", project_id: project.id } + ] + ].to_json + expect(helper.available_service_desk_templates_for(@project)).to eq(value) end end @@ -71,7 +78,8 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do let(:templates) { {} } it 'returns empty array' do - expect(helper.issuable_templates_names(Issue.new)).to eq([]) + value = [].to_json + expect(helper.available_service_desk_templates_for(@project)).to eq(value) end end end diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 30049745433..fa19395ebc7 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -169,26 +169,9 @@ RSpec.describe IssuablesHelper do stub_const("Gitlab::IssuablesCountForState::THRESHOLD", 1000) end - context 'when feature flag cached_issues_state_count is disabled' do - before do - stub_feature_flags(cached_issues_state_count: false) - end - - it 'returns complete count' do - expect(helper.issuables_state_counter_text(:issues, :opened, true)) - .to eq('Open 1,100') - end - end - - context 'when feature flag cached_issues_state_count is enabled' do - before do - stub_feature_flags(cached_issues_state_count: true) - end - - it 'returns truncated count' do - expect(helper.issuables_state_counter_text(:issues, :opened, true)) - .to eq('Open 1.1k') - end + it 'returns truncated count' do + expect(helper.issuables_state_counter_text(:issues, :opened, true)) + .to eq('Open 1.1k') end end end diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 850051c7875..43b27dded3b 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -326,6 +326,7 @@ RSpec.describe IssuesHelper do new_issue_path: new_project_issue_path(project, issue: { milestone_id: finder.milestones.first.id }), project_import_jira_path: project_import_jira_path(project), quick_actions_help_path: help_page_path('user/project/quick_actions'), + releases_path: project_releases_path(project, format: :json), reset_path: new_issuable_address_project_path(project, issuable_type: 'issue'), rss_path: '#', show_new_issue_link: 'true', diff --git a/spec/helpers/learn_gitlab_helper_spec.rb b/spec/helpers/learn_gitlab_helper_spec.rb index 1159fd96d59..b9f34853a77 100644 --- a/spec/helpers/learn_gitlab_helper_spec.rb +++ b/spec/helpers/learn_gitlab_helper_spec.rb @@ -11,9 +11,6 @@ RSpec.describe LearnGitlabHelper do let_it_be(:namespace) { project.namespace } before do - project.add_developer(user) - - allow(helper).to receive(:user).and_return(user) allow_next_instance_of(LearnGitlab::Project) do |learn_gitlab| allow(learn_gitlab).to receive(:project).and_return(project) end @@ -22,38 +19,7 @@ RSpec.describe LearnGitlabHelper do OnboardingProgress.register(namespace, :git_write) end - describe '.onboarding_actions_data' do - subject(:onboarding_actions_data) { helper.onboarding_actions_data(project) } - - it 'has all actions' do - expect(onboarding_actions_data.keys).to contain_exactly( - :issue_created, - :git_write, - :pipeline_created, - :merge_request_created, - :user_added, - :trial_started, - :required_mr_approvals_enabled, - :code_owners_enabled, - :security_scan_enabled - ) - end - - it 'sets correct path and completion status' do - expect(onboarding_actions_data[:git_write]).to eq({ - url: project_issue_url(project, LearnGitlab::Onboarding::ACTION_ISSUE_IDS[:git_write]), - completed: true, - svg: helper.image_path("learn_gitlab/git_write.svg") - }) - expect(onboarding_actions_data[:pipeline_created]).to eq({ - url: project_issue_url(project, LearnGitlab::Onboarding::ACTION_ISSUE_IDS[:pipeline_created]), - completed: false, - svg: helper.image_path("learn_gitlab/pipeline_created.svg") - }) - end - end - - describe '.learn_gitlab_enabled?' do + describe '#learn_gitlab_enabled?' do using RSpec::Parameterized::TableSyntax let_it_be(:user) { create(:user) } @@ -89,14 +55,121 @@ RSpec.describe LearnGitlabHelper do end end - describe '.onboarding_sections_data' do - subject(:sections) { helper.onboarding_sections_data } + describe '#learn_gitlab_data' do + subject(:learn_gitlab_data) { helper.learn_gitlab_data(project) } + + let(:onboarding_actions_data) { Gitlab::Json.parse(learn_gitlab_data[:actions]).deep_symbolize_keys } + let(:onboarding_sections_data) { Gitlab::Json.parse(learn_gitlab_data[:sections]).deep_symbolize_keys } + + shared_examples 'has all data' do + it 'has all actions' do + expected_keys = [ + :issue_created, + :git_write, + :pipeline_created, + :merge_request_created, + :user_added, + :trial_started, + :required_mr_approvals_enabled, + :code_owners_enabled, + :security_scan_enabled + ] + + expect(onboarding_actions_data.keys).to contain_exactly(*expected_keys) + end - it 'has the right keys' do - expect(sections.keys).to contain_exactly(:deploy, :plan, :workspace) + it 'has all section data', :aggregate_failures do + expect(onboarding_sections_data.keys).to contain_exactly(:deploy, :plan, :workspace) + expect(onboarding_sections_data.values.map { |section| section.keys }).to match_array([[:svg]] * 3) + end end - it 'has the svg' do - expect(sections.values.map { |section| section.keys }).to eq([[:svg]] * 3) + + it_behaves_like 'has all data' + + it 'sets correct paths' do + expect(onboarding_actions_data).to match({ + trial_started: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/2\z}) + ), + issue_created: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/4\z}) + ), + git_write: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/6\z}) + ), + pipeline_created: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/7\z}) + ), + user_added: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/8\z}) + ), + merge_request_created: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/9\z}) + ), + code_owners_enabled: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/10\z}) + ), + required_mr_approvals_enabled: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/11\z}) + ), + security_scan_enabled: a_hash_including( + url: a_string_matching(%r{docs\.gitlab\.com/ee/user/application_security/security_dashboard/#gitlab-security-dashboard-security-center-and-vulnerability-reports\z}) + ) + }) + end + + it 'sets correct completion statuses' do + expect(onboarding_actions_data).to match({ + issue_created: a_hash_including(completed: false), + git_write: a_hash_including(completed: true), + pipeline_created: a_hash_including(completed: false), + merge_request_created: a_hash_including(completed: false), + user_added: a_hash_including(completed: false), + trial_started: a_hash_including(completed: false), + required_mr_approvals_enabled: a_hash_including(completed: false), + code_owners_enabled: a_hash_including(completed: false), + security_scan_enabled: a_hash_including(completed: false) + }) + end + + context 'when in the new action URLs experiment' do + before do + stub_experiments(change_continuous_onboarding_link_urls: :candidate) + end + + it_behaves_like 'has all data' + + it 'sets mostly new paths' do + expect(onboarding_actions_data).to match({ + trial_started: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/2\z}) + ), + issue_created: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues\z}) + ), + git_write: a_hash_including( + url: a_string_matching(%r{/learn_gitlab\z}) + ), + pipeline_created: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/pipelines\z}) + ), + user_added: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/project_members\z}) + ), + merge_request_created: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/merge_requests\z}) + ), + code_owners_enabled: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/10\z}) + ), + required_mr_approvals_enabled: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/issues/11\z}) + ), + security_scan_enabled: a_hash_including( + url: a_string_matching(%r{/learn_gitlab/-/security/configuration\z}) + ) + }) + end end end end diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb index c671379c4b4..e94eb63fc2c 100644 --- a/spec/helpers/members_helper_spec.rb +++ b/spec/helpers/members_helper_spec.rb @@ -68,4 +68,10 @@ RSpec.describe MembersHelper do it { expect(leave_confirmation_message(project)).to eq "Are you sure you want to leave the \"#{project.full_name}\" project?" } it { expect(leave_confirmation_message(group)).to eq "Are you sure you want to leave the \"#{group.name}\" group?" } end + + describe '#localized_tasks_to_be_done_choices' do + it 'has a translation for all `TASKS_TO_BE_DONE` keys' do + expect(localized_tasks_to_be_done_choices).to include(*MemberTask::TASKS.keys) + end + end end diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb index da7e5d5dce2..10bd45e3189 100644 --- a/spec/helpers/nav/top_nav_helper_spec.rb +++ b/spec/helpers/nav/top_nav_helper_spec.rb @@ -188,6 +188,11 @@ RSpec.describe Nav::TopNavHelper do href: '/explore', id: 'explore', title: 'Explore projects' + ), + ::Gitlab::Nav::TopNavMenuItem.build( + href: '/explore/projects/topics', + id: 'topics', + title: 'Explore topics' ) ] expect(projects_view[:linksPrimary]).to eq(expected_links_primary) diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index fc62bbf8bf8..913a38d353f 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -322,11 +322,21 @@ RSpec.describe NotesHelper do describe '#notes_data' do let(:issue) { create(:issue, project: project) } - it 'sets last_fetched_at to 0 when start_at_zero is true' do + before do @project = project @noteable = issue + allow(helper).to receive(:current_user).and_return(guest) + end + + it 'sets last_fetched_at to 0 when start_at_zero is true' do expect(helper.notes_data(issue, true)[:lastFetchedAt]).to eq(0) end + + 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]) + end end end diff --git a/spec/helpers/one_trust_helper_spec.rb b/spec/helpers/one_trust_helper_spec.rb index 85c38885304..20b731ac73d 100644 --- a/spec/helpers/one_trust_helper_spec.rb +++ b/spec/helpers/one_trust_helper_spec.rb @@ -4,11 +4,8 @@ require "spec_helper" RSpec.describe OneTrustHelper do describe '#one_trust_enabled?' do - let(:user) { nil } - before do stub_config(extra: { one_trust_id: SecureRandom.uuid }) - allow(helper).to receive(:current_user).and_return(user) end subject(:one_trust_enabled?) { helper.one_trust_enabled? } @@ -18,20 +15,10 @@ RSpec.describe OneTrustHelper do stub_feature_flags(ecomm_instrumentation: false) end - context 'when id is set and no user is set' do - let(:user) { instance_double('User') } - - it { is_expected.to be_falsey } - end + it { is_expected.to be_falsey } end context 'with ecomm_instrumentation feature flag enabled' do - context 'when current user is set' do - let(:user) { instance_double('User') } - - it { is_expected.to be_falsey } - end - context 'when no id is set' do before do stub_config(extra: {}) @@ -39,10 +26,6 @@ RSpec.describe OneTrustHelper do it { is_expected.to be_falsey } end - - context 'when id is set and no user is set' do - it { is_expected.to be_truthy } - end end end end diff --git a/spec/helpers/projects/alert_management_helper_spec.rb b/spec/helpers/projects/alert_management_helper_spec.rb index 2450f7838b3..0a5c4bedaa6 100644 --- a/spec/helpers/projects/alert_management_helper_spec.rb +++ b/spec/helpers/projects/alert_management_helper_spec.rb @@ -34,7 +34,6 @@ RSpec.describe Projects::AlertManagementHelper do 'empty-alert-svg-path' => match_asset_path('/assets/illustrations/alert-management-empty-state.svg'), 'user-can-enable-alert-management' => 'true', 'alert-management-enabled' => 'false', - 'has-managed-prometheus' => 'false', 'text-query': nil, 'assignee-username-query': nil ) @@ -45,52 +44,26 @@ RSpec.describe Projects::AlertManagementHelper do let_it_be(:prometheus_integration) { create(:prometheus_integration, project: project) } context 'when manual prometheus integration is active' do - it "enables alert management and doesn't show managed prometheus" do + it "enables alert management" do prometheus_integration.update!(manual_configuration: true) expect(data).to include( 'alert-management-enabled' => 'true' ) - expect(data).to include( - 'has-managed-prometheus' => 'false' - ) - end - end - - context 'when a cluster prometheus is available' do - let(:cluster) { create(:cluster, projects: [project]) } - - it 'has managed prometheus' do - create(:clusters_integrations_prometheus, cluster: cluster) - - expect(data).to include( - 'has-managed-prometheus' => 'true' - ) end end - context 'when prometheus integration is inactive' do - it 'disables alert management and hides managed prometheus' do + context 'when prometheus service is inactive' do + it 'disables alert management' do prometheus_integration.update!(manual_configuration: false) expect(data).to include( 'alert-management-enabled' => 'false' ) - expect(data).to include( - 'has-managed-prometheus' => 'false' - ) end end end - context 'without prometheus integration' do - it "doesn't have managed prometheus" do - expect(data).to include( - 'has-managed-prometheus' => 'false' - ) - end - end - context 'with http integration' do let_it_be(:integration) { create(:alert_management_http_integration, project: project) } diff --git a/spec/helpers/projects/incidents_helper_spec.rb b/spec/helpers/projects/incidents_helper_spec.rb index 7a8a6d5222f..d0dc18d56b0 100644 --- a/spec/helpers/projects/incidents_helper_spec.rb +++ b/spec/helpers/projects/incidents_helper_spec.rb @@ -5,7 +5,8 @@ require 'spec_helper' RSpec.describe Projects::IncidentsHelper do include Gitlab::Routing.url_helpers - let(:project) { create(:project) } + let(:user) { build_stubbed(:user) } + let(:project) { build_stubbed(:project) } let(:project_path) { project.full_path } let(:new_issue_path) { new_project_issue_path(project) } let(:issue_path) { project_issues_path(project) } @@ -17,21 +18,43 @@ RSpec.describe Projects::IncidentsHelper do } end + before do + allow(helper).to receive(:current_user).and_return(user) + allow(helper).to receive(:can?) + .with(user, :create_incident, project) + .and_return(can_create_incident) + end + describe '#incidents_data' do subject(:data) { helper.incidents_data(project, params) } - it 'returns frontend configuration' do - expect(data).to include( - 'project-path' => project_path, - 'new-issue-path' => new_issue_path, - 'incident-template-name' => 'incident', - 'incident-type' => 'incident', - 'issue-path' => issue_path, - 'empty-list-svg-path' => match_asset_path('/assets/illustrations/incident-empty-state.svg'), - 'text-query': 'search text', - 'author-username-query': 'root', - 'assignee-username-query': 'max.power' - ) + shared_examples 'frontend configuration' do + it 'returns frontend configuration' do + expect(data).to include( + 'project-path' => project_path, + 'new-issue-path' => new_issue_path, + 'incident-template-name' => 'incident', + 'incident-type' => 'incident', + 'issue-path' => issue_path, + 'empty-list-svg-path' => match_asset_path('/assets/illustrations/incident-empty-state.svg'), + 'text-query': 'search text', + 'author-username-query': 'root', + 'assignee-username-query': 'max.power', + 'can-create-incident': can_create_incident.to_s + ) + end + end + + context 'when user can create incidents' do + let(:can_create_incident) { true } + + include_examples 'frontend configuration' + end + + context 'when user cannot create incidents' do + let(:can_create_incident) { false } + + include_examples 'frontend configuration' end end end diff --git a/spec/helpers/projects/security/configuration_helper_spec.rb b/spec/helpers/projects/security/configuration_helper_spec.rb index c5049bd87f0..4c30ba87897 100644 --- a/spec/helpers/projects/security/configuration_helper_spec.rb +++ b/spec/helpers/projects/security/configuration_helper_spec.rb @@ -8,6 +8,6 @@ RSpec.describe Projects::Security::ConfigurationHelper do describe 'security_upgrade_path' do subject { security_upgrade_path } - it { is_expected.to eq('https://about.gitlab.com/pricing/') } + it { is_expected.to eq("https://#{ApplicationHelper.promo_host}/pricing/") } end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 5d52c9178cb..5d2af567549 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -268,7 +268,7 @@ RSpec.describe ProjectsHelper do end end - describe '#link_to_set_password' do + describe '#no_password_message' do let(:user) { create(:user, password_automatically_set: true) } before do @@ -276,18 +276,18 @@ RSpec.describe ProjectsHelper do end context 'password authentication is enabled for Git' do - it 'returns link to set a password' do + it 'returns message prompting user to set password or set up a PAT' do stub_application_setting(password_authentication_enabled_for_git?: true) - expect(helper.link_to_set_password).to match %r{set a password} + expect(helper.no_password_message).to eq('Your account is authenticated with SSO or SAML. To push and pull over HTTP with Git using this account, you must set a password or set up a Personal Access Token to use instead of a password. For more information, see Clone with HTTPS.') end end context 'password authentication is disabled for Git' do - it 'returns link to create a personal access token' do + it 'returns message prompting user to set up a PAT' do stub_application_setting(password_authentication_enabled_for_git?: false) - expect(helper.link_to_set_password).to match %r{create a personal access token} + expect(helper.no_password_message).to eq('Your account is authenticated with SSO or SAML. To push and pull over HTTP with Git using this account, you must set up a Personal Access Token to use instead of a password. For more information, see Clone with HTTPS.') end end end @@ -983,4 +983,12 @@ RSpec.describe ProjectsHelper do it { is_expected.not_to include('project-highlight-puc') } end end + + describe "#delete_confirm_phrase" do + subject { helper.delete_confirm_phrase(project) } + + it 'includes the project path with namespace' do + expect(subject).to eq(project.path_with_namespace) + end + end end diff --git a/spec/helpers/routing/pseudonymization_helper_spec.rb b/spec/helpers/routing/pseudonymization_helper_spec.rb index a28a86d1f53..82ed893289d 100644 --- a/spec/helpers/routing/pseudonymization_helper_spec.rb +++ b/spec/helpers/routing/pseudonymization_helper_spec.rb @@ -25,95 +25,196 @@ RSpec.describe ::Routing::PseudonymizationHelper do describe 'when url has params to mask' do context 'with controller for MR' do - let(:masked_url) { "http://test.host/namespace:#{group.id}/project:#{project.id}/-/merge_requests/#{merge_request.id}" } + let(:masked_url) { "http://localhost/namespace#{group.id}/project#{project.id}/-/merge_requests/#{merge_request.id}" } + let(:request) do + double(:Request, + path_parameters: { + controller: "projects/merge_requests", + action: "show", + namespace_id: group.name, + project_id: project.name, + id: merge_request.id.to_s + }, + protocol: 'http', + host: 'localhost', + query_string: '') + end before do - allow(Rails.application.routes).to receive(:recognize_path).and_return({ - controller: "projects/merge_requests", - action: "show", - namespace_id: group.name, - project_id: project.name, - id: merge_request.id.to_s - }) + allow(helper).to receive(:request).and_return(request) end it_behaves_like 'masked url' end context 'with controller for issue' do - let(:masked_url) { "http://test.host/namespace:#{group.id}/project:#{project.id}/-/issues/#{issue.id}" } + let(:masked_url) { "http://localhost/namespace#{group.id}/project#{project.id}/-/issues/#{issue.id}" } + let(:request) do + double(:Request, + path_parameters: { + controller: "projects/issues", + action: "show", + namespace_id: group.name, + project_id: project.name, + id: issue.id.to_s + }, + protocol: 'http', + host: 'localhost', + query_string: '') + end before do - allow(Rails.application.routes).to receive(:recognize_path).and_return({ - controller: "projects/issues", - action: "show", - namespace_id: group.name, - project_id: project.name, - id: issue.id.to_s - }) + allow(helper).to receive(:request).and_return(request) end it_behaves_like 'masked url' end context 'with controller for groups with subgroups and project' do - let(:masked_url) { "http://test.host/namespace:#{subgroup.id}/project:#{subproject.id}"} + let(:masked_url) { "http://localhost/namespace#{subgroup.id}/project#{subproject.id}"} + let(:request) do + double(:Request, + path_parameters: { + controller: 'projects', + action: 'show', + namespace_id: subgroup.name, + id: subproject.name + }, + protocol: 'http', + host: 'localhost', + query_string: '') + end before do allow(helper).to receive(:group).and_return(subgroup) allow(helper).to receive(:project).and_return(subproject) - allow(Rails.application.routes).to receive(:recognize_path).and_return({ - controller: 'projects', - action: 'show', - namespace_id: subgroup.name, - id: subproject.name - }) + allow(helper).to receive(:request).and_return(request) end it_behaves_like 'masked url' end context 'with controller for groups and subgroups' do - let(:masked_url) { "http://test.host/namespace:#{subgroup.id}"} + let(:masked_url) { "http://localhost/groups/namespace#{subgroup.id}/-/shared"} + let(:request) do + double(:Request, + path_parameters: { + controller: 'groups', + action: 'show', + id: subgroup.name + }, + protocol: 'http', + host: 'localhost', + query_string: '') + end before do allow(helper).to receive(:group).and_return(subgroup) - allow(Rails.application.routes).to receive(:recognize_path).and_return({ - controller: 'groups', - action: 'show', - id: subgroup.name - }) + allow(helper).to receive(:request).and_return(request) end it_behaves_like 'masked url' end context 'with controller for blob with file path' do - let(:masked_url) { "http://test.host/namespace:#{group.id}/project:#{project.id}/-/blob/:repository_path" } + let(:masked_url) { "http://localhost/namespace#{group.id}/project#{project.id}/-/blob/:repository_path" } + let(:request) do + double(:Request, + path_parameters: { + controller: 'projects/blob', + action: 'show', + namespace_id: group.name, + project_id: project.name, + id: 'master/README.md' + }, + protocol: 'http', + host: 'localhost', + query_string: '') + end + + before do + allow(helper).to receive(:request).and_return(request) + end + + it_behaves_like 'masked url' + end + + context 'when assignee_username is present' do + let(:masked_url) { "http://localhost/dashboard/issues?assignee_username=masked_assignee_username" } + let(:request) do + double(:Request, + path_parameters: { + controller: 'dashboard', + action: 'issues' + }, + protocol: 'http', + host: 'localhost', + query_string: 'assignee_username=root') + end before do - allow(Rails.application.routes).to receive(:recognize_path).and_return({ - controller: 'projects/blob', - action: 'show', - namespace_id: group.name, - project_id: project.name, - id: 'master/README.md' - }) + allow(helper).to receive(:request).and_return(request) end it_behaves_like 'masked url' end - context 'with non identifiable controller' do - let(:masked_url) { "http://test.host/dashboard/issues?assignee_username=root" } + context 'when author_username is present' do + let(:masked_url) { "http://localhost/dashboard/issues?author_username=masked_author_username&scope=masked_scope&state=masked_state" } + let(:request) do + double(:Request, + path_parameters: { + controller: 'dashboard', + action: 'issues' + }, + protocol: 'http', + host: 'localhost', + query_string: 'author_username=root&scope=all&state=opened') + end before do - controller.request.path = '/dashboard/issues' - controller.request.query_string = 'assignee_username=root' - allow(Rails.application.routes).to receive(:recognize_path).and_return({ - controller: 'dashboard', - action: 'issues' - }) + allow(helper).to receive(:request).and_return(request) + end + + it_behaves_like 'masked url' + end + + context 'when some query params are not required to be masked' do + let(:masked_url) { "http://localhost/dashboard/issues?author_username=masked_author_username&scope=all&state=masked_state" } + let(:request) do + double(:Request, + path_parameters: { + controller: 'dashboard', + action: 'issues' + }, + protocol: 'http', + host: 'localhost', + query_string: 'author_username=root&scope=all&state=opened') + end + + before do + stub_const('Routing::PseudonymizationHelper::MaskHelper::QUERY_PARAMS_TO_NOT_MASK', %w[scope].freeze) + allow(helper).to receive(:request).and_return(request) + end + + it_behaves_like 'masked url' + end + + context 'when query string has keys with the same names as path params' do + let(:masked_url) { "http://localhost/dashboard/issues?action=masked_action&scope=masked_scope&state=masked_state" } + let(:request) do + double(:Request, + path_parameters: { + controller: 'dashboard', + action: 'issues' + }, + protocol: 'http', + host: 'localhost', + query_string: 'action=foobar&scope=all&state=opened') + end + + before do + allow(helper).to receive(:request).and_return(request) end it_behaves_like 'masked url' @@ -121,9 +222,13 @@ RSpec.describe ::Routing::PseudonymizationHelper do end describe 'when url has no params to mask' do - let(:root_url) { 'http://test.host' } + let(:root_url) { 'http://localhost/some/path' } context 'returns root url' do + before do + controller.request.path = 'some/path' + end + it 'masked_page_url' do expect(helper.masked_page_url).to eq(root_url) end @@ -132,17 +237,26 @@ RSpec.describe ::Routing::PseudonymizationHelper do describe 'when it raises exception' do context 'calls error tracking' do + let(:request) do + double(:Request, + path_parameters: { + controller: 'dashboard', + action: 'issues' + }, + protocol: 'http', + host: 'localhost', + query_string: 'assignee_username=root', + original_fullpath: '/dashboard/issues?assignee_username=root') + end + before do - controller.request.path = '/dashboard/issues' - controller.request.query_string = 'assignee_username=root' - allow(Rails.application.routes).to receive(:recognize_path).and_return({ - controller: 'dashboard', - action: 'issues' - }) + allow(helper).to receive(:request).and_return(request) end it 'sends error to sentry and returns nil' do - allow(helper).to receive(:mask_params).with(anything).and_raise(ActionController::RoutingError, 'Some routing error') + allow_next_instance_of(Routing::PseudonymizationHelper::MaskHelper) do |mask_helper| + allow(mask_helper).to receive(:mask_params).and_raise(ActionController::RoutingError, 'Some routing error') + end expect(Gitlab::ErrorTracking).to receive(:track_exception).with( ActionController::RoutingError, diff --git a/spec/helpers/storage_helper_spec.rb b/spec/helpers/storage_helper_spec.rb index 2cec7203fe1..d0646b30161 100644 --- a/spec/helpers/storage_helper_spec.rb +++ b/spec/helpers/storage_helper_spec.rb @@ -27,17 +27,18 @@ RSpec.describe StorageHelper do create(:project, namespace: namespace, statistics: build(:project_statistics, - namespace: namespace, - repository_size: 10.kilobytes, - wiki_size: 10.bytes, - lfs_objects_size: 20.gigabytes, - build_artifacts_size: 30.megabytes, - snippets_size: 40.megabytes, - packages_size: 12.megabytes, - uploads_size: 15.megabytes)) + namespace: namespace, + repository_size: 10.kilobytes, + wiki_size: 10.bytes, + lfs_objects_size: 20.gigabytes, + build_artifacts_size: 30.megabytes, + pipeline_artifacts_size: 11.megabytes, + snippets_size: 40.megabytes, + packages_size: 12.megabytes, + uploads_size: 15.megabytes)) end - let(:message) { 'Repository: 10 KB / Wikis: 10 Bytes / Build Artifacts: 30 MB / LFS: 20 GB / Snippets: 40 MB / Packages: 12 MB / Uploads: 15 MB' } + let(:message) { 'Repository: 10 KB / Wikis: 10 Bytes / Build Artifacts: 30 MB / Pipeline Artifacts: 11 MB / LFS: 20 GB / Snippets: 40 MB / Packages: 12 MB / Uploads: 15 MB' } it 'works on ProjectStatistics' do expect(helper.storage_counters_details(project.statistics)).to eq(message) diff --git a/spec/helpers/tab_helper_spec.rb b/spec/helpers/tab_helper_spec.rb index 346bfc7850c..e5e88466946 100644 --- a/spec/helpers/tab_helper_spec.rb +++ b/spec/helpers/tab_helper_spec.rb @@ -36,7 +36,15 @@ RSpec.describe TabHelper do expect(gl_tab_link_to('/url') { 'block content' }).to match(/block content/) end - it 'creates a tab with custom classes' do + it 'creates a tab with custom classes for enclosing list item without content block provided' do + expect(gl_tab_link_to('Link', '/url', { tab_class: 'my-class' })).to match(/
  • 1') + end + + context 'with extra classes' do + it 'creates a tab counter badge with the correct class attribute' do + expect(gl_tab_counter_badge(1, { class: 'js-test' })).to eq('1') + end + end + + context 'with data attributes' do + it 'creates a tab counter badge with the data attributes' do + expect(gl_tab_counter_badge(1, { data: { some_attribute: 'foo' } })).to eq('1') + end + end + end end diff --git a/spec/helpers/terms_helper_spec.rb b/spec/helpers/terms_helper_spec.rb new file mode 100644 index 00000000000..9120aad4627 --- /dev/null +++ b/spec/helpers/terms_helper_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe TermsHelper do + let_it_be(:current_user) { build(:user) } + let_it_be(:terms) { build(:term) } + + before do + allow(helper).to receive(:current_user).and_return(current_user) + end + + describe '#terms_data' do + let_it_be(:redirect) { '%2F' } + let_it_be(:terms_markdown) { 'Lorem ipsum dolor sit amet' } + let_it_be(:accept_path) { '/-/users/terms/14/accept?redirect=%2F' } + let_it_be(:decline_path) { '/-/users/terms/14/decline?redirect=%2F' } + + subject(:result) { Gitlab::Json.parse(helper.terms_data(terms, redirect)) } + + it 'returns correct json' do + expect(helper).to receive(:markdown_field).with(terms, :terms).and_return(terms_markdown) + expect(helper).to receive(:can?).with(current_user, :accept_terms, terms).and_return(true) + expect(helper).to receive(:can?).with(current_user, :decline_terms, terms).and_return(true) + expect(helper).to receive(:accept_term_path).with(terms, { redirect: redirect }).and_return(accept_path) + expect(helper).to receive(:decline_term_path).with(terms, { redirect: redirect }).and_return(decline_path) + + expected = { + terms: terms_markdown, + permissions: { + can_accept: true, + can_decline: true + }, + paths: { + accept: accept_path, + decline: decline_path, + root: root_path + } + }.as_json + + expect(result).to eq(expected) + end + end +end diff --git a/spec/helpers/time_zone_helper_spec.rb b/spec/helpers/time_zone_helper_spec.rb index 43ad130c4b5..006fae5b814 100644 --- a/spec/helpers/time_zone_helper_spec.rb +++ b/spec/helpers/time_zone_helper_spec.rb @@ -100,4 +100,36 @@ RSpec.describe TimeZoneHelper, :aggregate_failures do end end end + + describe '#local_time_instance' do + let_it_be(:timezone) { 'UTC' } + + before do + travel_to Time.find_zone(timezone).local(2021, 7, 20, 15, 30, 45) + end + + context 'when timezone is `nil`' do + it 'returns the system timezone instance' do + expect(helper.local_time_instance(nil).name).to eq(timezone) + end + end + + context 'when timezone is blank' do + it 'returns the system timezone instance' do + expect(helper.local_time_instance('').name).to eq(timezone) + end + end + + context 'when a valid timezone is passed' do + it 'returns the local time instance' do + expect(helper.local_time_instance('America/Los_Angeles').name).to eq('America/Los_Angeles') + end + end + + context 'when an invalid timezone is passed' do + it 'returns the system timezone instance' do + expect(helper.local_time_instance('Foo/Bar').name).to eq(timezone) + end + end + end end diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb index f738ba855b8..7abc67e29a4 100644 --- a/spec/helpers/user_callouts_helper_spec.rb +++ b/spec/helpers/user_callouts_helper_spec.rb @@ -216,20 +216,6 @@ RSpec.describe UserCalloutsHelper do context 'when the invite_members_banner has not been dismissed' do it { is_expected.to eq(true) } - context 'when a user has dismissed this banner via cookies already' do - before do - helper.request.cookies["invite_#{group.id}_#{user.id}"] = 'true' - end - - it { is_expected.to eq(false) } - - it 'creates the callout from cookie', :aggregate_failures do - expect { subject }.to change { Users::GroupCallout.count }.by(1) - expect(Users::GroupCallout.last).to have_attributes(group_id: group.id, - feature_name: described_class::INVITE_MEMBERS_BANNER) - end - end - context 'when the group was just created' do before do flash[:notice] = "Group #{group.name} was successfully created" diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb index 480b1e2a0de..2b55319c70c 100644 --- a/spec/helpers/users_helper_spec.rb +++ b/spec/helpers/users_helper_spec.rb @@ -383,7 +383,7 @@ RSpec.describe UsersHelper do end context 'when `user.unconfirmed_email` is set' do - let(:user) { create(:user, unconfirmed_email: 'foo@bar.com') } + let(:user) { create(:user, :unconfirmed, unconfirmed_email: 'foo@bar.com') } it 'sets `modal_attributes.messageHtml` correctly' do expect(Gitlab::Json.parse(confirm_user_data[:modal_attributes])['messageHtml']).to eq('This user has an unconfirmed email address (foo@bar.com). You may force a confirmation.') diff --git a/spec/helpers/wiki_helper_spec.rb b/spec/helpers/wiki_helper_spec.rb index dc76f92db1b..0d04ca2b876 100644 --- a/spec/helpers/wiki_helper_spec.rb +++ b/spec/helpers/wiki_helper_spec.rb @@ -8,7 +8,7 @@ RSpec.describe WikiHelper do it 'sets the title for the show action' do expect(helper).to receive(:breadcrumb_title).with(page.human_title) - expect(helper).to receive(:wiki_breadcrumb_dropdown_links).with(page.slug) + expect(helper).to receive(:wiki_breadcrumb_collapsed_links).with(page.slug) expect(helper).to receive(:page_title).with(page.human_title, 'Wiki') expect(helper).to receive(:add_to_breadcrumbs).with('Wiki', helper.wiki_path(page.wiki)) @@ -17,7 +17,7 @@ RSpec.describe WikiHelper do it 'sets the title for a custom action' do expect(helper).to receive(:breadcrumb_title).with(page.human_title) - expect(helper).to receive(:wiki_breadcrumb_dropdown_links).with(page.slug) + expect(helper).to receive(:wiki_breadcrumb_collapsed_links).with(page.slug) expect(helper).to receive(:page_title).with('Edit', page.human_title, 'Wiki') expect(helper).to receive(:add_to_breadcrumbs).with('Wiki', helper.wiki_path(page.wiki)) @@ -27,7 +27,7 @@ RSpec.describe WikiHelper do it 'sets the title for an unsaved page' do expect(page).to receive(:persisted?).and_return(false) expect(helper).not_to receive(:breadcrumb_title) - expect(helper).not_to receive(:wiki_breadcrumb_dropdown_links) + expect(helper).not_to receive(:wiki_breadcrumb_collapsed_links) expect(helper).to receive(:page_title).with('Wiki') expect(helper).to receive(:add_to_breadcrumbs).with('Wiki', helper.wiki_path(page.wiki)) -- cgit v1.2.3