diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-20 15:19:03 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-20 15:19:03 +0000 |
commit | 14bd84b61276ef29b97d23642d698de769bacfd2 (patch) | |
tree | f9eba90140c1bd874211dea17750a0d422c04080 /spec/helpers | |
parent | 891c388697b2db0d8ee0c8358a9bdbf6dc56d581 (diff) | |
download | gitlab-ce-14bd84b61276ef29b97d23642d698de769bacfd2.tar.gz |
Add latest changes from gitlab-org/gitlab@15-10-stable-eev15.10.0-rc42
Diffstat (limited to 'spec/helpers')
32 files changed, 830 insertions, 428 deletions
diff --git a/spec/helpers/admin/abuse_reports_helper_spec.rb b/spec/helpers/admin/abuse_reports_helper_spec.rb new file mode 100644 index 00000000000..83393cc641d --- /dev/null +++ b/spec/helpers/admin/abuse_reports_helper_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Admin::AbuseReportsHelper, feature_category: :insider_threat do + describe '#abuse_reports_list_data' do + let!(:report) { create(:abuse_report) } # rubocop:disable RSpec/FactoryBot/AvoidCreate + let(:reports) { AbuseReport.all.page(1) } + let(:data) do + data = helper.abuse_reports_list_data(reports)[:abuse_reports_data] + Gitlab::Json.parse(data) + end + + it 'has expected attributes', :aggregate_failures do + expect(data['pagination']).to include( + "current_page" => 1, + "per_page" => 20, + "total_items" => 1 + ) + expect(data['reports'].first).to include("category", "updated_at", "reported_user", "reporter") + expect(data['categories']).to match_array(AbuseReport.categories.keys) + end + end +end diff --git a/spec/helpers/analytics/cycle_analytics_helper_spec.rb b/spec/helpers/analytics/cycle_analytics_helper_spec.rb deleted file mode 100644 index d906646e25c..00000000000 --- a/spec/helpers/analytics/cycle_analytics_helper_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true -require "spec_helper" - -RSpec.describe Analytics::CycleAnalyticsHelper do - describe '#cycle_analytics_initial_data' do - let(:user) { create(:user, name: 'fake user', username: 'fake_user') } - let(:image_path_keys) { [:empty_state_svg_path, :no_data_svg_path, :no_access_svg_path] } - let(:api_path_keys) { [:milestones_path, :labels_path] } - let(:additional_data_keys) { [:full_path, :group_id, :group_path, :project_id, :request_path] } - let(:group) { create(:group) } - - subject(:cycle_analytics_data) { helper.cycle_analytics_initial_data(project, group) } - - before do - project.add_maintainer(user) - end - - context 'when a group is present' do - let(:project) { create(:project, group: group) } - - it "sets the correct data keys" do - expect(cycle_analytics_data.keys) - .to match_array(api_path_keys + image_path_keys + additional_data_keys) - end - - it "sets group paths" do - expect(cycle_analytics_data) - .to include({ - full_path: project.full_path, - group_path: "/#{project.namespace.name}", - group_id: project.namespace.id, - request_path: "/#{project.full_path}/-/value_stream_analytics", - milestones_path: "/groups/#{group.name}/-/milestones.json", - labels_path: "/groups/#{group.name}/-/labels.json" - }) - end - end - - context 'when a group is not present' do - let(:group) { nil } - let(:project) { create(:project) } - - it "sets the correct data keys" do - expect(cycle_analytics_data.keys) - .to match_array(image_path_keys + api_path_keys + additional_data_keys) - end - - it "sets project name space paths" do - expect(cycle_analytics_data) - .to include({ - full_path: project.full_path, - group_path: project.namespace.path, - group_id: project.namespace.id, - request_path: "/#{project.full_path}/-/value_stream_analytics", - milestones_path: "/#{project.full_path}/-/milestones.json", - labels_path: "/#{project.full_path}/-/labels.json" - }) - end - end - end -end diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb index 19cb970553b..93db4661c82 100644 --- a/spec/helpers/application_settings_helper_spec.rb +++ b/spec/helpers/application_settings_helper_spec.rb @@ -68,11 +68,7 @@ RSpec.describe ApplicationSettingsHelper do )) end - context 'when GitLab.com' do - before do - allow(Gitlab).to receive(:com?).and_return(true) - end - + context 'when on SaaS', :saas do it 'does not contain :deactivate_dormant_users' do expect(helper.visible_attributes).not_to include(:deactivate_dormant_users) end diff --git a/spec/helpers/artifacts_helper_spec.rb b/spec/helpers/artifacts_helper_spec.rb index cf48f0ecc39..7c577cbf11c 100644 --- a/spec/helpers/artifacts_helper_spec.rb +++ b/spec/helpers/artifacts_helper_spec.rb @@ -17,6 +17,7 @@ RSpec.describe ArtifactsHelper, feature_category: :build_artifacts do it 'returns expected data' do expect(subject).to include({ project_path: project.full_path, + project_id: project.id, artifacts_management_feedback_image_path: match_asset_path('illustrations/chat-bubble-sm.svg') }) end diff --git a/spec/helpers/ci/catalog/resources_helper_spec.rb b/spec/helpers/ci/catalog/resources_helper_spec.rb new file mode 100644 index 00000000000..c4abdebd12e --- /dev/null +++ b/spec/helpers/ci/catalog/resources_helper_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::Catalog::ResourcesHelper, feature_category: :pipeline_composition do + let_it_be(:project) { build(:project) } + + describe 'can_view_private_catalog?' do + subject { helper.can_view_private_catalog?(project) } + + before do + allow(helper).to receive(:can_collaborate_with_project?).and_return(true) + stub_licensed_features(ci_private_catalog: false) + end + + it 'user cannot view the Catalog in CE regardless of permissions' do + expect(subject).to be false + end + end + + describe '#js_ci_catalog_data' do + let(:project) { build(:project, :repository) } + let(:default_helper_data) do + {} + end + + subject(:catalog_data) { helper.js_ci_catalog_data } + + it 'returns catalog data' do + expect(catalog_data).to eq(default_helper_data) + end + end +end diff --git a/spec/helpers/ci/pipeline_editor_helper_spec.rb b/spec/helpers/ci/pipeline_editor_helper_spec.rb index c9aac63a883..1a0f2e10a20 100644 --- a/spec/helpers/ci/pipeline_editor_helper_spec.rb +++ b/spec/helpers/ci/pipeline_editor_helper_spec.rb @@ -29,12 +29,12 @@ RSpec.describe Ci::PipelineEditorHelper do "ci-examples-help-page-path" => help_page_path('ci/examples/index'), "ci-help-page-path" => help_page_path('ci/index'), "ci-lint-path" => project_ci_lint_path(project), + "ci-troubleshooting-path" => help_page_path('ci/troubleshooting', anchor: 'common-cicd-issues'), "default-branch" => project.default_branch_or_main, "empty-state-illustration-path" => 'illustrations/empty.svg', "initial-branch-name" => nil, "includes-help-page-path" => help_page_path('ci/yaml/includes'), "lint-help-page-path" => help_page_path('ci/lint', anchor: 'check-cicd-syntax'), - "lint-unavailable-help-page-path" => help_page_path('ci/pipeline_editor/index', anchor: 'configuration-validation-currently-not-available-message'), "needs-help-page-path" => help_page_path('ci/yaml/index', anchor: 'needs'), "new-merge-request-path" => '/mock/project/-/merge_requests/new', "pipeline-page-path" => project_pipelines_path(project), diff --git a/spec/helpers/ci/pipelines_helper_spec.rb b/spec/helpers/ci/pipelines_helper_spec.rb index 19946afb1a4..535e8f3170e 100644 --- a/spec/helpers/ci/pipelines_helper_spec.rb +++ b/spec/helpers/ci/pipelines_helper_spec.rb @@ -192,11 +192,7 @@ RSpec.describe Ci::PipelinesHelper do end end - describe 'the `ios_runners_available` attribute' do - before do - allow(Gitlab).to receive(:com?).and_return(true) - end - + describe 'the `ios_runners_available` attribute', :saas do subject { data[:ios_runners_available] } context 'when the `ios_specific_templates` experiment variant is control' do diff --git a/spec/helpers/ci/variables_helper_spec.rb b/spec/helpers/ci/variables_helper_spec.rb index d032e7f9087..da727fd1b6b 100644 --- a/spec/helpers/ci/variables_helper_spec.rb +++ b/spec/helpers/ci/variables_helper_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::VariablesHelper, feature_category: :pipeline_authoring do +RSpec.describe Ci::VariablesHelper, feature_category: :pipeline_composition do describe '#ci_variable_maskable_raw_regex' do it 'converts to a javascript regex' do expect(helper.ci_variable_maskable_raw_regex).to eq("^\\S{8,}$") diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb index 27738f73ea5..c947d11e9de 100644 --- a/spec/helpers/commits_helper_spec.rb +++ b/spec/helpers/commits_helper_spec.rb @@ -325,21 +325,41 @@ RSpec.describe CommitsHelper do assign(:path, current_path) end - it { is_expected.to be_an(Array) } - it { is_expected.to include(commit) } - it { is_expected.to include(commit.author) } - it { is_expected.to include(ref) } - specify do - is_expected.to include( + expect(subject).to eq([ + commit, + commit.author, + ref, { merge_request: merge_request.cache_key, pipeline_status: pipeline.cache_key, xhr: true, controller: "commits", - path: current_path + path: current_path, + referenced_by: helper.tag_checksum(commit.referenced_by) } - ) + ]) + end + + context 'when the show_tags_on_commits_view flag is disabled' do + before do + stub_feature_flags(show_tags_on_commits_view: false) + end + + specify do + expect(subject).to eq([ + commit, + commit.author, + ref, + { + merge_request: merge_request.cache_key, + pipeline_status: pipeline.cache_key, + xhr: true, + controller: "commits", + path: current_path + } + ]) + end end describe "final cache key output" do diff --git a/spec/helpers/device_registration_helper_spec.rb b/spec/helpers/device_registration_helper_spec.rb new file mode 100644 index 00000000000..7556d037b3d --- /dev/null +++ b/spec/helpers/device_registration_helper_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe DeviceRegistrationHelper, feature_category: :system_access do + describe "#device_registration_data" do + it "returns a hash with device registration properties without initial error" do + device_registration_data = helper.device_registration_data( + current_password_required: false, + target_path: "/my/path", + webauthn_error: nil + ) + + expect(device_registration_data).to eq( + { + initial_error: nil, + target_path: "/my/path", + password_required: "false" + }) + end + + it "returns a hash with device registration properties with initial error" do + device_registration_data = helper.device_registration_data( + current_password_required: true, + target_path: "/my/path", + webauthn_error: { message: "my error" } + ) + + expect(device_registration_data).to eq( + { + initial_error: "my error", + target_path: "/my/path", + password_required: "true" + }) + end + end +end diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index a46f8c13f00..2318bbf861a 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -47,6 +47,12 @@ RSpec.describe DiffHelper do end describe 'diff_options' do + let(:large_notebooks_enabled) { false } + + before do + stub_feature_flags(large_ipynb_diffs: large_notebooks_enabled) + end + it 'returns no collapse false' do expect(diff_options).to include(expanded: false) end @@ -56,21 +62,48 @@ RSpec.describe DiffHelper do expect(diff_options).to include(expanded: true) end - it 'returns no collapse true if action name diff_for_path' do - allow(controller).to receive(:action_name) { 'diff_for_path' } - expect(diff_options).to include(expanded: true) - end + context 'when action name is diff_for_path' do + before do + allow(controller).to receive(:action_name) { 'diff_for_path' } + end - it 'returns paths if action name diff_for_path and param old path' do - allow(controller).to receive(:params) { { old_path: 'lib/wadus.rb' } } - allow(controller).to receive(:action_name) { 'diff_for_path' } - expect(diff_options[:paths]).to include('lib/wadus.rb') - end + it 'returns expanded true' do + expect(diff_options).to include(expanded: true) + end - it 'returns paths if action name diff_for_path and param new path' do - allow(controller).to receive(:params) { { new_path: 'lib/wadus.rb' } } - allow(controller).to receive(:action_name) { 'diff_for_path' } - expect(diff_options[:paths]).to include('lib/wadus.rb') + it 'returns paths if param old path' do + allow(controller).to receive(:params) { { old_path: 'lib/wadus.rb' } } + expect(diff_options[:paths]).to include('lib/wadus.rb') + end + + it 'returns paths if param new path' do + allow(controller).to receive(:params) { { new_path: 'lib/wadus.rb' } } + expect(diff_options[:paths]).to include('lib/wadus.rb') + end + + it 'does not set max_patch_bytes_for_file_extension' do + expect(diff_options[:max_patch_bytes_for_file_extension]).to be_nil + end + + context 'when file_identifier include .ipynb' do + before do + allow(controller).to receive(:params) { { file_identifier: 'something.ipynb' } } + end + + context 'when large_ipynb_diffs is disabled' do + it 'does not set max_patch_bytes_for_file_extension' do + expect(diff_options[:max_patch_bytes_for_file_extension]).to be_nil + end + end + + context 'when large_ipynb_diffs is enabled' do + let(:large_notebooks_enabled) { true } + + it 'sets max_patch_bytes_for_file_extension' do + expect(diff_options[:max_patch_bytes_for_file_extension]).to eq({ '.ipynb' => 1.megabyte }) + end + end + end end end diff --git a/spec/helpers/explore_helper_spec.rb b/spec/helpers/explore_helper_spec.rb index 4ae1b738858..68c5289a85f 100644 --- a/spec/helpers/explore_helper_spec.rb +++ b/spec/helpers/explore_helper_spec.rb @@ -12,7 +12,7 @@ RSpec.describe ExploreHelper do describe '#explore_nav_links' do it 'has all the expected links by default' do - menu_items = [:projects, :groups, :snippets] + menu_items = [:projects, :groups, :topics, :snippets] expect(helper.explore_nav_links).to contain_exactly(*menu_items) end diff --git a/spec/helpers/groups/observability_helper_spec.rb b/spec/helpers/groups/observability_helper_spec.rb index ee33a853f9c..f0e6aa0998a 100644 --- a/spec/helpers/groups/observability_helper_spec.rb +++ b/spec/helpers/groups/observability_helper_spec.rb @@ -4,77 +4,46 @@ require "spec_helper" RSpec.describe Groups::ObservabilityHelper do let(:group) { build_stubbed(:group) } - let(:observability_url) { Gitlab::Observability.observability_url } describe '#observability_iframe_src' do - context 'if observability_path is missing from params' do - it 'returns the iframe src for action: dashboards' do - allow(helper).to receive(:params).and_return({ action: 'dashboards' }) - expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/") - end - - it 'returns the iframe src for action: manage' do - allow(helper).to receive(:params).and_return({ action: 'manage' }) - expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/dashboards") - end - - it 'returns the iframe src for action: explore' do - allow(helper).to receive(:params).and_return({ action: 'explore' }) - expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/explore") - end - - it 'returns the iframe src for action: datasources' do - allow(helper).to receive(:params).and_return({ action: 'datasources' }) - expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/datasources") - end + before do + allow(Gitlab::Observability).to receive(:build_full_url).and_return('full-url') end - context 'if observability_path exists in params' do - context 'if observability_path is valid' do - it 'returns the iframe src by injecting the observability path' do - allow(helper).to receive(:params).and_return({ action: '/explore', observability_path: '/foo?bar=foobar' }) - expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/foo?bar=foobar") - end - end - - context 'if observability_path is not valid' do - it 'returns the iframe src by injecting the sanitised observability path' do - allow(helper).to receive(:params).and_return({ - action: '/explore', - observability_path: - "/test?groupId=<script>alert('attack!')</script>" - }) - expect(helper.observability_iframe_src(group)).to eq( - "#{observability_url}/-/#{group.id}/test?groupId=alert('attack!')" - ) - end - end + it 'returns the iframe src for action: dashboards' do + allow(helper).to receive(:params).and_return({ action: 'dashboards', observability_path: '/foo?bar=foobar' }) + expect(helper.observability_iframe_src(group)).to eq('full-url') + expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/') end - context 'when observability ui is standalone' do - before do - stub_env('STANDALONE_OBSERVABILITY_UI', 'true') - end + it 'returns the iframe src for action: manage' do + allow(helper).to receive(:params).and_return({ action: 'manage', observability_path: '/foo?bar=foobar' }) + expect(helper.observability_iframe_src(group)).to eq('full-url') + expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/dashboards') + end - it 'returns the iframe src without group.id for action: dashboards' do - allow(helper).to receive(:params).and_return({ action: 'dashboards' }) - expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/") - end + it 'returns the iframe src for action: explore' do + allow(helper).to receive(:params).and_return({ action: 'explore', observability_path: '/foo?bar=foobar' }) + expect(helper.observability_iframe_src(group)).to eq('full-url') + expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/explore') + end - it 'returns the iframe src without group.id for action: manage' do - allow(helper).to receive(:params).and_return({ action: 'manage' }) - expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/dashboards") - end + it 'returns the iframe src for action: datasources' do + allow(helper).to receive(:params).and_return({ action: 'datasources', observability_path: '/foo?bar=foobar' }) + expect(helper.observability_iframe_src(group)).to eq('full-url') + expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/datasources') + end - it 'returns the iframe src without group.id for action: explore' do - allow(helper).to receive(:params).and_return({ action: 'explore' }) - expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/explore") - end + it 'returns the iframe src when action is not recognised' do + allow(helper).to receive(:params).and_return({ action: 'unrecognised', observability_path: '/foo?bar=foobar' }) + expect(helper.observability_iframe_src(group)).to eq('full-url') + expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/') + end - it 'returns the iframe src without group.id for action: datasources' do - allow(helper).to receive(:params).and_return({ action: 'datasources' }) - expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/datasources") - end + it 'returns the iframe src when observability_path is missing' do + allow(helper).to receive(:params).and_return({ action: 'dashboards' }) + expect(helper.observability_iframe_src(group)).to eq('full-url') + expect(Gitlab::Observability).to have_received(:build_full_url).with(group, nil, '/') end end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 8b4ac6a7cfd..ce439e5bcdd 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -436,7 +436,8 @@ RSpec.describe GroupsHelper do it 'returns expected hash' do expect(subgroup_creation_data(subgroup)).to eq({ import_existing_group_path: '/groups/new#import-group-pane', - parent_group_name: name + parent_group_name: name, + parent_group_url: group_url(group) }) end end @@ -445,7 +446,8 @@ RSpec.describe GroupsHelper do it 'returns expected hash' do expect(subgroup_creation_data(group)).to eq({ import_existing_group_path: '/groups/new#import-group-pane', - parent_group_name: nil + parent_group_name: nil, + parent_group_url: nil }) end end diff --git a/spec/helpers/ide_helper_spec.rb b/spec/helpers/ide_helper_spec.rb index e2ee4f33eee..e5a39f6a24e 100644 --- a/spec/helpers/ide_helper_spec.rb +++ b/spec/helpers/ide_helper_spec.rb @@ -6,117 +6,135 @@ RSpec.describe IdeHelper, feature_category: :web_ide do describe '#ide_data' do let_it_be(:project) { create(:project) } let_it_be(:user) { project.creator } + let_it_be(:fork_info) { { ide_path: '/test/ide/path' } } + + let_it_be(:params) do + { + branch: 'master', + path: 'foo/bar', + merge_request_id: '1' + } + end + + let(:base_data) do + { + 'can-use-new-web-ide' => 'false', + 'use-new-web-ide' => 'false', + 'user-preferences-path' => profile_preferences_path, + 'project' => nil, + 'preview-markdown-path' => nil + } + end before do allow(helper).to receive(:current_user).and_return(user) allow(helper).to receive(:content_security_policy_nonce).and_return('test-csp-nonce') end - context 'with vscode_web_ide=true and instance vars set' do - before do - stub_feature_flags(vscode_web_ide: true) - end + it 'returns hash' do + expect(helper.ide_data(project: nil, fork_info: fork_info, params: params)) + .to include(base_data) + end - it 'returns hash' do - expect(helper.ide_data(project: project, branch: 'master', path: 'foo/README.md', merge_request: '7', -fork_info: nil)) - .to match( - 'can-use-new-web-ide' => 'true', - 'use-new-web-ide' => 'true', - 'user-preferences-path' => profile_preferences_path, - 'new-web-ide-help-page-path' => - help_page_path('user/project/web_ide/index.md', anchor: 'vscode-reimplementation'), - 'branch-name' => 'master', - 'project-path' => project.path_with_namespace, - 'csp-nonce' => 'test-csp-nonce', - 'ide-remote-path' => ide_remote_path(remote_host: ':remote_host', remote_path: ':remote_path'), - 'file-path' => 'foo/README.md', - 'editor-font-family' => 'JetBrains Mono', - 'editor-font-format' => 'woff2', - 'editor-font-src-url' => a_string_matching(%r{jetbrains-mono/JetBrainsMono}), - 'merge-request' => '7', - 'fork-info' => nil - ) + context 'with project' do + it 'returns hash with parameters' do + serialized_project = API::Entities::Project.represent(project, current_user: user).to_json + + expect( + helper.ide_data(project: project, fork_info: nil, params: params) + ).to include(base_data.merge( + 'fork-info' => nil, + 'branch-name' => params[:branch], + 'file-path' => params[:path], + 'merge-request' => params[:merge_request_id], + 'project' => serialized_project, + 'preview-markdown-path' => Gitlab::Routing.url_helpers.preview_markdown_project_path(project) + )) end - it 'does not use new web ide if user.use_legacy_web_ide' do - allow(user).to receive(:use_legacy_web_ide).and_return(true) - - expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil, -fork_info: nil)).to include('use-new-web-ide' => 'false') + context 'with fork info' do + it 'returns hash with fork info' do + expect(helper.ide_data(project: project, fork_info: fork_info, params: params)) + .to include('fork-info' => fork_info.to_json) + end end end - context 'with vscode_web_ide=false' do + context 'with environments guidance experiment', :experiment do before do - stub_feature_flags(vscode_web_ide: false) + stub_experiments(in_product_guidance_environments_webide: :candidate) end - context 'when instance vars and parameters are not set' do - it 'returns instance data in the hash as nil' do - expect(helper.ide_data(project: nil, branch: nil, path: nil, merge_request: nil, fork_info: nil)) - .to include( - 'can-use-new-web-ide' => 'false', - 'use-new-web-ide' => 'false', - 'user-preferences-path' => profile_preferences_path, - 'branch-name' => nil, - 'file-path' => nil, - 'merge-request' => nil, - 'fork-info' => nil, - 'project' => nil, - 'preview-markdown-path' => nil - ) + context 'when project has no enviornments' do + it 'enables environment guidance' do + expect(helper.ide_data(project: project, fork_info: fork_info, params: params)) + .to include('enable-environments-guidance' => 'true') end - end - context 'when instance vars are set' do - it 'returns instance data in the hash' do - fork_info = { ide_path: '/test/ide/path' } - - serialized_project = API::Entities::Project.represent(project, current_user: project.creator).to_json - - expect(helper.ide_data(project: project, branch: 'master', path: 'foo/bar', merge_request: '1', -fork_info: fork_info)) - .to include( - 'branch-name' => 'master', - 'file-path' => 'foo/bar', - 'merge-request' => '1', - 'fork-info' => fork_info.to_json, - 'project' => serialized_project, - 'preview-markdown-path' => Gitlab::Routing.url_helpers.preview_markdown_project_path(project) - ) + context 'and the callout has been dismissed' do + it 'disables environment guidance' do + callout = create(:callout, feature_name: :web_ide_ci_environments_guidance, user: user) + callout.update!(dismissed_at: Time.now - 1.week) + allow(helper).to receive(:current_user).and_return(User.find(user.id)) + + expect(helper.ide_data(project: project, fork_info: fork_info, params: params)) + .to include('enable-environments-guidance' => 'false') + end end end - context 'environments guidance experiment', :experiment do - before do - stub_experiments(in_product_guidance_environments_webide: :candidate) + context 'when the project has environments' do + it 'disables environment guidance' do + create(:environment, project: project) + + expect(helper.ide_data(project: project, fork_info: fork_info, params: params)) + .to include('enable-environments-guidance' => 'false') end + end + end - context 'when project has no enviornments' do - it 'enables environment guidance' do - expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil, -fork_info: nil)).to include('enable-environments-guidance' => 'true') - end + context 'with vscode_web_ide=true' do + let(:base_data) do + { + 'can-use-new-web-ide' => 'true', + 'use-new-web-ide' => 'true', + 'user-preferences-path' => profile_preferences_path, + 'new-web-ide-help-page-path' => + help_page_path('user/project/web_ide/index.md', anchor: 'vscode-reimplementation'), + 'csp-nonce' => 'test-csp-nonce', + 'ide-remote-path' => ide_remote_path(remote_host: ':remote_host', remote_path: ':remote_path'), + 'editor-font-family' => 'JetBrains Mono', + 'editor-font-format' => 'woff2', + 'editor-font-src-url' => a_string_matching(%r{jetbrains-mono/JetBrainsMono}) + } + end - context 'and the callout has been dismissed' do - it 'disables environment guidance' do - callout = create(:callout, feature_name: :web_ide_ci_environments_guidance, user: project.creator) - callout.update!(dismissed_at: Time.now - 1.week) - allow(helper).to receive(:current_user).and_return(User.find(project.creator.id)) - expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil, -fork_info: nil)).to include('enable-environments-guidance' => 'false') - end - end - end + before do + stub_feature_flags(vscode_web_ide: true) + end - context 'when the project has environments' do - it 'disables environment guidance' do - create(:environment, project: project) + it 'returns hash' do + expect(helper.ide_data(project: nil, fork_info: fork_info, params: params)) + .to include(base_data) + end - expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil, -fork_info: nil)).to include('enable-environments-guidance' => 'false') - end + it 'does not use new web ide if user.use_legacy_web_ide' do + allow(user).to receive(:use_legacy_web_ide).and_return(true) + + expect(helper.ide_data(project: nil, fork_info: fork_info, params: params)) + .to include('use-new-web-ide' => 'false') + end + + context 'with project' do + it 'returns hash with parameters' do + expect( + helper.ide_data(project: project, fork_info: nil, params: params) + ).to include(base_data.merge( + 'branch-name' => params[:branch], + 'file-path' => params[:path], + 'merge-request' => params[:merge_request_id], + 'fork-info' => nil + )) end end end diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 1ae834c0769..fd10b204e50 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -293,10 +293,13 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do end describe '#issuable_reference' do + let(:project_namespace) { build_stubbed(:project_namespace) } + let(:project) { build_stubbed(:project, project_namespace: project_namespace) } + context 'when show_full_reference truthy' do it 'display issuable full reference' do assign(:show_full_reference, true) - issue = build_stubbed(:issue) + issue = build_stubbed(:issue, project: project) expect(helper.issuable_reference(issue)).to eql(issue.to_reference(full: true)) end @@ -305,12 +308,10 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do context 'when show_full_reference falsey' do context 'when @group present' do it 'display issuable reference to @group' do - project = build_stubbed(:project) - assign(:show_full_reference, nil) assign(:group, project.namespace) - issue = build_stubbed(:issue) + issue = build_stubbed(:issue, project: project) expect(helper.issuable_reference(issue)).to eql(issue.to_reference(project.namespace)) end @@ -318,13 +319,11 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do context 'when @project present' do it 'display issuable reference to @project' do - project = build_stubbed(:project) - assign(:show_full_reference, nil) assign(:group, nil) assign(:project, project) - issue = build_stubbed(:issue) + issue = build_stubbed(:issue, project: project) expect(helper.issuable_reference(issue)).to eql(issue.to_reference(project)) end @@ -333,8 +332,11 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do end describe '#issuable_project_reference' do + let(:project_namespace) { build_stubbed(:project_namespace) } + let(:project) { build_stubbed(:project, project_namespace: project_namespace) } + it 'display project name and simple reference with `#` to an issue' do - issue = build_stubbed(:issue) + issue = build_stubbed(:issue, project: project) expect(helper.issuable_project_reference(issue)).to eq("#{issue.project.full_name} ##{issue.iid}") end @@ -430,7 +432,8 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do action: "show", namespace_id: "foo", project_id: "bar", - id: incident.iid + id: incident.iid, + incident_tab: 'timeline' }).permit! end @@ -441,7 +444,9 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do expected_data = { issueType: 'incident', hasLinkedAlerts: false, - canUpdateTimelineEvent: true + canUpdateTimelineEvent: true, + currentPath: "/foo/bar/-/issues/incident/#{incident.iid}/timeline", + currentTab: 'timeline' } expect(helper.issuable_initial_data(incident)).to match(hash_including(expected_data)) diff --git a/spec/helpers/jira_connect_helper_spec.rb b/spec/helpers/jira_connect_helper_spec.rb index 31aeff85c70..4f56bb7467f 100644 --- a/spec/helpers/jira_connect_helper_spec.rb +++ b/spec/helpers/jira_connect_helper_spec.rb @@ -9,8 +9,7 @@ RSpec.describe JiraConnectHelper, feature_category: :integrations do let(:user) { create(:user) } let(:client_id) { '123' } - let(:enable_public_keys_storage_config) { false } - let(:enable_public_keys_storage_setting) { false } + let(:enable_public_keys_storage) { false } before do stub_application_setting(jira_connect_application_key: client_id) @@ -22,9 +21,7 @@ RSpec.describe JiraConnectHelper, feature_category: :integrations do before do allow(view).to receive(:current_user).and_return(nil) allow(Gitlab.config.gitlab).to receive(:url).and_return('http://test.host') - allow(Gitlab.config.jira_connect).to receive(:enable_public_keys_storage) - .and_return(enable_public_keys_storage_config) - stub_application_setting(jira_connect_public_key_storage_enabled: enable_public_keys_storage_setting) + stub_application_setting(jira_connect_public_key_storage_enabled: enable_public_keys_storage) end it 'includes Jira Connect app attributes' do @@ -108,16 +105,8 @@ RSpec.describe JiraConnectHelper, feature_category: :integrations do expect(subject[:public_key_storage_enabled]).to eq(false) end - context 'when public_key_storage is enabled via config' do - let(:enable_public_keys_storage_config) { true } - - it 'assignes public_key_storage_enabled to true' do - expect(subject[:public_key_storage_enabled]).to eq(true) - end - end - - context 'when public_key_storage is enabled via setting' do - let(:enable_public_keys_storage_setting) { true } + context 'when public_key_storage is enabled' do + let(:enable_public_keys_storage) { true } it 'assignes public_key_storage_enabled to true' do expect(subject[:public_key_storage_enabled]).to eq(true) diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 088519248c6..a9f99f29f6d 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -534,6 +534,45 @@ RSpec.describe MarkupHelper do helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project) end.not_to change { Gitlab::GitalyClient.get_request_count } end + + it 'strips non-user links' do + html = 'This a cool [website](https://gitlab.com/).' + + object = create_object(html) + result = helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project) + + expect(result).to include('This a cool website.') + end + + it 'styles the current user link', :aggregate_failures do + another_user = create(:user) + html = "Please have a look, @#{user.username} @#{another_user.username}!" + + object = create_object(html) + result = helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project) + links = Nokogiri::HTML.parse(result).css('//a') + + expect(links[0].classes).to include('current-user') + expect(links[1].classes).not_to include('current-user') + end + + context 'when current_user is nil' do + before do + allow(helper).to receive(:current_user).and_return(nil) + end + + it 'renders the link with no styling when current_user is nil' do + another_user = create(:user) + html = "Please have a look, @#{user.username} @#{another_user.username}!" + + object = create_object(html) + result = helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project) + links = Nokogiri::HTML.parse(result).css('//a') + + expect(links[0].classes).not_to include('current-user') + expect(links[1].classes).not_to include('current-user') + end + end end context 'when the asked attribute can be redacted' do diff --git a/spec/helpers/nav/new_dropdown_helper_spec.rb b/spec/helpers/nav/new_dropdown_helper_spec.rb index 3a66fe474ab..5ae057dc97d 100644 --- a/spec/helpers/nav/new_dropdown_helper_spec.rb +++ b/spec/helpers/nav/new_dropdown_helper_spec.rb @@ -11,8 +11,11 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do let(:with_can_create_project) { false } let(:with_can_create_group) { false } let(:with_can_create_snippet) { false } + let(:title) { 'Create new...' } - subject(:view_model) { helper.new_dropdown_view_model(project: current_project, group: current_group) } + subject(:view_model) do + helper.new_dropdown_view_model(project: current_project, group: current_group) + end before do allow(helper).to receive(:current_user) { current_user } @@ -22,7 +25,7 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do allow(user).to receive(:can?).with(:create_snippet) { with_can_create_snippet } end - shared_examples 'invite member item' do + shared_examples 'invite member item' do |partial| it 'shows invite member link with emoji' do expect(view_model[:menu_sections]).to eq( expected_menu_section( @@ -30,12 +33,12 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do menu_item: ::Gitlab::Nav::TopNavMenuItem.build( id: 'invite', title: 'Invite members', - emoji: 'shaking_hands', - href: expected_href, + icon: 'shaking_hands', + partial: partial, + component: 'invite_members', data: { - track_action: 'click_link_invite_members', - track_label: 'plus_menu_dropdown', - track_property: 'navigation_top' + trigger_source: 'top-nav', + trigger_element: 'text-emoji' } ) ) @@ -54,8 +57,13 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do end context 'when group and project are nil' do - it 'has no menu sections' do - expect(view_model[:menu_sections]).to eq([]) + it 'has base results' do + results = { + title: title, + menu_sections: [] + } + + expect(view_model).to eq(results) end context 'when can create project' do @@ -145,8 +153,13 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do .to receive(:can?).with(current_user, :admin_group_member, group) { with_can_admin_in_group } end - it 'has no menu sections' do - expect(view_model[:menu_sections]).to eq([]) + it 'has base results' do + results = { + title: title, + menu_sections: [] + } + + expect(view_model).to eq(results) end context 'when can create projects in group' do @@ -199,7 +212,7 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do let(:expected_title) { 'In this group' } let(:expected_href) { "/groups/#{group.full_path}/-/group_members" } - it_behaves_like 'invite member item' + it_behaves_like 'invite member item', 'groups/invite_members_top_nav_link' end end @@ -219,8 +232,13 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do allow(helper).to receive(:can_admin_project_member?) { with_can_admin_project_member } end - it 'has no menu sections' do - expect(view_model[:menu_sections]).to eq([]) + it 'has base results' do + results = { + title: title, + menu_sections: [] + } + + expect(view_model).to eq(results) end context 'with show_new_issue_link?' do @@ -296,7 +314,7 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do let(:expected_title) { 'In this project' } let(:expected_href) { "/#{project.path_with_namespace}/-/project_members" } - it_behaves_like 'invite member item' + it_behaves_like 'invite member item', 'projects/invite_members_top_nav_link' end end @@ -311,22 +329,27 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do allow(helper).to receive(:can?).with(current_user, :create_projects, group).and_return(true) end - it 'gives precedence to group over project' do - group_section = expected_menu_section( - title: 'In this group', + it 'gives precedence to project over group' do + project_section = expected_menu_section( + title: 'In this project', menu_item: ::Gitlab::Nav::TopNavMenuItem.build( - id: 'new_project', - title: 'New project/repository', - href: "/projects/new?namespace_id=#{group.id}", + id: 'new_issue', + title: 'New issue', + href: "/#{project.path_with_namespace}/-/issues/new", data: { - track_action: 'click_link_new_project_group', + track_action: 'click_link_new_issue', track_label: 'plus_menu_dropdown', - track_property: 'navigation_top' + track_property: 'navigation_top', + qa_selector: 'new_issue_link' } ) ) + results = { + title: title, + menu_sections: project_section + } - expect(view_model[:menu_sections]).to eq(group_section) + expect(view_model).to eq(results) end end diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb index ce5ac2e5404..2b69557b840 100644 --- a/spec/helpers/nav/top_nav_helper_spec.rb +++ b/spec/helpers/nav/top_nav_helper_spec.rb @@ -56,6 +56,7 @@ RSpec.describe Nav::TopNavHelper do expected_primary = [ { href: '/explore', icon: 'project', id: 'project', title: 'Projects' }, { href: '/explore/groups', icon: 'group', id: 'groups', title: 'Groups' }, + { href: '/explore/projects/topics', icon: 'labels', id: 'topics', title: 'Topics' }, { href: '/explore/snippets', icon: 'snippet', id: 'snippets', title: 'Snippets' } ].map do |item| ::Gitlab::Nav::TopNavMenuItem.build(**item) @@ -79,6 +80,12 @@ RSpec.describe Nav::TopNavHelper do css_class: 'dashboard-shortcuts-groups' }, { + href: '/explore/projects/topics', + id: 'topics-shortcut', + title: 'Topics', + css_class: 'dashboard-shortcuts-topics' + }, + { href: '/explore/snippets', id: 'snippets-shortcut', title: 'Snippets', @@ -320,20 +327,6 @@ RSpec.describe Nav::TopNavHelper do context 'with milestones' do let(:with_milestones) { true } - it 'has expected :primary' do - expected_header = ::Gitlab::Nav::TopNavMenuHeader.build( - title: 'Explore' - ) - expected_primary = ::Gitlab::Nav::TopNavMenuItem.build( - data: { **menu_data_tracking_attrs('milestones') }, - href: '/dashboard/milestones', - icon: 'clock', - id: 'milestones', - title: 'Milestones' - ) - expect(subject[:primary]).to eq([expected_header, expected_primary]) - end - it 'has expected :shortcuts' do expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build( id: 'milestones-shortcut', @@ -348,23 +341,6 @@ RSpec.describe Nav::TopNavHelper do context 'with snippets' do let(:with_snippets) { true } - it 'has expected :primary' do - expected_header = ::Gitlab::Nav::TopNavMenuHeader.build( - title: 'Explore' - ) - expected_primary = ::Gitlab::Nav::TopNavMenuItem.build( - data: { - qa_selector: 'snippets_link', - **menu_data_tracking_attrs('snippets') - }, - href: '/dashboard/snippets', - icon: 'snippet', - id: 'snippets', - title: 'Snippets' - ) - expect(subject[:primary]).to eq([expected_header, expected_primary]) - end - it 'has expected :shortcuts' do expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build( id: 'snippets-shortcut', @@ -379,20 +355,6 @@ RSpec.describe Nav::TopNavHelper do context 'with activity' do let(:with_activity) { true } - it 'has expected :primary' do - expected_header = ::Gitlab::Nav::TopNavMenuHeader.build( - title: 'Explore' - ) - expected_primary = ::Gitlab::Nav::TopNavMenuItem.build( - data: { **menu_data_tracking_attrs('activity') }, - href: '/dashboard/activity', - icon: 'history', - id: 'activity', - title: 'Activity' - ) - expect(subject[:primary]).to eq([expected_header, expected_primary]) - end - it 'has expected :shortcuts' do expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build( id: 'activity-shortcut', diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index 68a6b6293c8..91635ffcdc0 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -RSpec.describe NotesHelper do +RSpec.describe NotesHelper, feature_category: :team_planning do include RepoHelpers let_it_be(:owner) { create(:owner) } @@ -223,6 +223,17 @@ RSpec.describe NotesHelper do end end + describe '#initial_notes_data' do + it 'return initial notes data for issuable' do + autocomplete = '/autocomplete/users' + @project = project + @noteable = create(:issue, project: @project) + + expect(helper.initial_notes_data(autocomplete).keys).to match_array(%i[notesUrl now diffView enableGFM]) + expect(helper.initial_notes_data(autocomplete)[:enableGFM].keys).to match(%i[emojis members issues mergeRequests vulnerabilities epics milestones labels]) + end + end + describe '#notes_url' do it 'return snippet notes path for personal snippet' do @snippet = create(:personal_snippet) diff --git a/spec/helpers/packages_helper_spec.rb b/spec/helpers/packages_helper_spec.rb index fc69aee4e04..b6546a2eaf3 100644 --- a/spec/helpers/packages_helper_spec.rb +++ b/spec/helpers/packages_helper_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe PackagesHelper do +RSpec.describe PackagesHelper, feature_category: :package_registry do using RSpec::Parameterized::TableSyntax let_it_be_with_reload(:project) { create(:project) } @@ -38,11 +38,18 @@ RSpec.describe PackagesHelper do describe '#pypi_registry_url' do let_it_be(:base_url_with_token) { base_url.sub('://', '://__token__:<your_personal_token>@') } + let_it_be(:public_project) { create(:project, :public) } - it 'returns the pypi registry url' do - url = helper.pypi_registry_url(1) + it 'returns the pypi registry url with token when project is private' do + url = helper.pypi_registry_url(project) - expect(url).to eq("#{base_url_with_token}projects/1/packages/pypi/simple") + expect(url).to eq("#{base_url_with_token}projects/#{project.id}/packages/pypi/simple") + end + + it 'returns the pypi registry url without token when project is public' do + url = helper.pypi_registry_url(public_project) + + expect(url).to eq("#{base_url}projects/#{public_project.id}/packages/pypi/simple") end end diff --git a/spec/helpers/plan_limits_helper_spec.rb b/spec/helpers/plan_limits_helper_spec.rb new file mode 100644 index 00000000000..121338c9cf2 --- /dev/null +++ b/spec/helpers/plan_limits_helper_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe PlanLimitsHelper, feature_category: :continuous_integration do + describe '#plan_limit_setting_description' do + it 'describes known limits', :aggregate_failures do + [ + :ci_pipeline_size, + :ci_active_jobs, + :ci_active_pipelines, + :ci_project_subscriptions, + :ci_pipeline_schedules, + :ci_needs_size_limit, + :ci_registered_group_runners, + :ci_registered_project_runners, + :pipeline_hierarchy_size + ].each do |limit_name| + expect(helper.plan_limit_setting_description(limit_name)).to be_present + end + end + + it 'raises an ArgumentError on invalid arguments' do + expect { helper.plan_limit_setting_description(:some_invalid_limit) }.to( + raise_error(ArgumentError, /No description/) + ) + end + end +end diff --git a/spec/helpers/projects/settings/branch_rules_helper_spec.rb b/spec/helpers/projects/settings/branch_rules_helper_spec.rb new file mode 100644 index 00000000000..35a21f72f11 --- /dev/null +++ b/spec/helpers/projects/settings/branch_rules_helper_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::Settings::BranchRulesHelper, feature_category: :source_code_management do + let_it_be(:project) { build_stubbed(:project) } + + describe '#branch_rules_data' do + subject(:data) { helper.branch_rules_data(project) } + + it 'returns branch rules data' do + expect(data).to match({ + project_path: project.full_path, + protected_branches_path: project_settings_repository_path(project, anchor: 'js-protected-branches-settings'), + approval_rules_path: project_settings_merge_requests_path(project, + anchor: 'js-merge-request-approval-settings'), + status_checks_path: project_settings_merge_requests_path(project, anchor: 'js-merge-request-settings'), + branches_path: project_branches_path(project), + show_status_checks: 'false', + show_approvers: 'false', + show_code_owners: 'false' + }) + end + end +end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 477b5cd7753..93352715ff4 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -1286,7 +1286,7 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do let_it_be(:has_active_license) { true } it 'displays the correct messagee' do - expect(subject).to eq(s_('Clusters|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support.')) + expect(subject).to eq(s_('Clusters|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions.')) end end @@ -1373,9 +1373,36 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do source_name: source_project.full_name, source_path: project_path(source_project), ahead_compare_path: ahead_path, - behind_compare_path: behind_path + behind_compare_path: behind_path, + source_default_branch: source_project.default_branch }) end end end + + describe '#remote_mirror_setting_enabled?' do + it 'returns false' do + expect(helper.remote_mirror_setting_enabled?).to be_falsy + end + end + + describe '#http_clone_url_to_repo' do + before do + allow(project).to receive(:http_url_to_repo).and_return('http_url_to_repo') + end + + subject { helper.http_clone_url_to_repo(project) } + + it { expect(subject).to eq('http_url_to_repo') } + end + + describe '#ssh_clone_url_to_repo' do + before do + allow(project).to receive(:ssh_url_to_repo).and_return('ssh_url_to_repo') + end + + subject { helper.ssh_clone_url_to_repo(project) } + + it { expect(subject).to eq('ssh_url_to_repo') } + end end diff --git a/spec/helpers/registrations_helper_spec.rb b/spec/helpers/registrations_helper_spec.rb index eec87bc8712..b2f9a794cb3 100644 --- a/spec/helpers/registrations_helper_spec.rb +++ b/spec/helpers/registrations_helper_spec.rb @@ -8,20 +8,4 @@ RSpec.describe RegistrationsHelper do expect(helper.signup_username_data_attributes.keys).to include(:min_length, :min_length_message, :max_length, :max_length_message, :qa_selector) end end - - describe '#arkose_labs_challenge_enabled?' do - before do - stub_application_setting( - arkose_labs_private_api_key: nil, - arkose_labs_public_api_key: nil, - arkose_labs_namespace: nil - ) - stub_env('ARKOSE_LABS_PRIVATE_KEY', nil) - stub_env('ARKOSE_LABS_PUBLIC_KEY', nil) - end - - it 'is false' do - expect(helper.arkose_labs_challenge_enabled?).to eq false - end - end end diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index c7afe0bf391..ba703914049 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -829,6 +829,21 @@ RSpec.describe SearchHelper, feature_category: :global_search do expect(header_search_context[:project_metadata]).to eq(project_metadata) end + context 'feature issues is not available' do + let(:feature_available) { false } + let(:project_metadata) { { mr_path: project_merge_requests_path(project) } } + + before do + allow(project).to receive(:feature_available?).and_call_original + allow(project).to receive(:feature_available?).with(:issues, current_user).and_return(feature_available) + end + + it 'adds the :project and :project-metadata correctly to hash' do + expect(header_search_context[:project]).to eq({ id: project.id, name: project.name }) + expect(header_search_context[:project_metadata]).to eq(project_metadata) + end + end + context 'with scope' do let(:scope) { 'issues' } diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb index 672c2ef7589..dbb6f9bd9f3 100644 --- a/spec/helpers/sidebars_helper_spec.rb +++ b/spec/helpers/sidebars_helper_spec.rb @@ -62,36 +62,71 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do end describe '#super_sidebar_context' do - let(:user) { build(:user) } - let(:group) { build(:group) } + let_it_be(:user) { build(:user) } + let_it_be(:group) { build(:group) } + let_it_be(:panel) { {} } - subject { helper.super_sidebar_context(user, group: group, project: nil) } + subject do + helper.super_sidebar_context(user, group: group, project: nil, panel: panel) + end before do allow(helper).to receive(:current_user) { user } - Rails.cache.write(['users', user.id, 'assigned_open_issues_count'], 1) - Rails.cache.write(['users', user.id, 'assigned_open_merge_requests_count'], 4) - Rails.cache.write(['users', user.id, 'review_requested_open_merge_requests_count'], 0) - Rails.cache.write(['users', user.id, 'todos_pending_count'], 3) - Rails.cache.write(['users', user.id, 'total_merge_requests_count'], 4) + allow(helper).to receive(:can?).and_return(true) + allow(panel).to receive(:super_sidebar_menu_items).and_return(nil) + allow(panel).to receive(:super_sidebar_context_header).and_return(nil) + allow(user).to receive(:assigned_open_issues_count).and_return(1) + allow(user).to receive(:assigned_open_merge_requests_count).and_return(4) + allow(user).to receive(:review_requested_open_merge_requests_count).and_return(0) + allow(user).to receive(:todos_pending_count).and_return(3) + allow(user).to receive(:total_merge_requests_count).and_return(4) end it 'returns sidebar values from user', :use_clean_rails_memory_store_caching do expect(subject).to include({ + current_context_header: nil, + current_menu_items: nil, name: user.name, username: user.username, avatar_url: user.avatar_url, + has_link_to_profile: helper.current_user_menu?(:profile), + link_to_profile: user_url(user), + status: { + can_update: helper.can?(user, :update_user_status, user), + busy: user.status&.busy?, + customized: user.status&.customized?, + availability: user.status&.availability.to_s, + emoji: user.status&.emoji, + message: user.status&.message_html&.html_safe, + clear_after: nil + }, + trial: { + has_start_trial: helper.current_user_menu?(:start_trial), + url: helper.trials_link_url + }, + settings: { + has_settings: helper.current_user_menu?(:settings), + profile_path: profile_path, + profile_preferences_path: profile_preferences_path + }, + can_sign_out: helper.current_user_menu?(:sign_out), + sign_out_link: destroy_user_session_path, assigned_open_issues_count: 1, todos_pending_count: 3, issues_dashboard_path: issues_dashboard_path(assignee_username: user.username), total_merge_requests_count: 4, + projects_path: projects_path, + groups_path: groups_path, support_path: helper.support_url, display_whats_new: helper.display_whats_new?, whats_new_most_recent_release_items_count: helper.whats_new_most_recent_release_items_count, whats_new_version_digest: helper.whats_new_version_digest, show_version_check: helper.show_version_check?, gitlab_version: Gitlab.version_info, - gitlab_version_check: helper.gitlab_version_check + gitlab_version_check: helper.gitlab_version_check, + gitlab_com_but_not_canary: Gitlab.com_but_not_canary?, + gitlab_com_and_canary: Gitlab.com_and_canary?, + canary_toggle_com_url: Gitlab::Saas.canary_toggle_com_url }) end @@ -138,7 +173,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do items: array_including( { href: "/projects/new", text: "New project/repository" }, { href: "/groups/new#create-group-pane", text: "New subgroup" }, - { href: "/groups/#{group.full_path}/-/group_members", text: "Invite members" } + { href: '', text: "Invite members" } ) ), a_hash_including( @@ -151,5 +186,108 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do ) ) end + + describe 'current context' do + context 'when current context is a project' do + let_it_be(:project) { build(:project) } + + subject do + helper.super_sidebar_context(user, group: nil, project: project, panel: panel) + end + + before do + allow(project).to receive(:persisted?).and_return(true) + end + + it 'returns project context' do + expect(subject[:current_context]).to eq({ + namespace: 'projects', + item: { + id: project.id, + avatarUrl: project.avatar_url, + name: project.name, + namespace: project.full_name, + webUrl: project_path(project) + } + }) + end + end + + context 'when current context is a group' do + subject do + helper.super_sidebar_context(user, group: group, project: nil, panel: panel) + end + + before do + allow(group).to receive(:persisted?).and_return(true) + end + + it 'returns group context' do + expect(subject[:current_context]).to eq({ + namespace: 'groups', + item: { + id: group.id, + avatarUrl: group.avatar_url, + name: group.name, + namespace: group.full_name, + webUrl: group_path(group) + } + }) + end + end + + context 'when current context is not tracked' do + subject do + helper.super_sidebar_context(user, group: nil, project: nil, panel: panel) + end + + it 'returns no context' do + expect(subject[:current_context]).to eq({}) + end + end + end + end + + describe '#super_sidebar_nav_panel' do + let(:user) { build(:user) } + let(:group) { build(:group) } + let(:project) { build(:project) } + + before do + allow(helper).to receive(:project_sidebar_context_data).and_return( + { current_user: nil, container: project, can_view_pipeline_editor: false, learn_gitlab_enabled: false }) + allow(helper).to receive(:group_sidebar_context_data).and_return({ current_user: nil, container: group }) + + allow(group).to receive(:to_global_id).and_return(5) + Rails.cache.write(['users', user.id, 'assigned_open_issues_count'], 1) + Rails.cache.write(['users', user.id, 'assigned_open_merge_requests_count'], 4) + Rails.cache.write(['users', user.id, 'review_requested_open_merge_requests_count'], 0) + Rails.cache.write(['users', user.id, 'todos_pending_count'], 3) + Rails.cache.write(['users', user.id, 'total_merge_requests_count'], 4) + end + + it 'returns Project Panel for project nav' do + expect(helper.super_sidebar_nav_panel(nav: 'project')).to be_a(Sidebars::Projects::SuperSidebarPanel) + end + + it 'returns Group Panel for group nav' do + expect(helper.super_sidebar_nav_panel(nav: 'group')).to be_a(Sidebars::Groups::SuperSidebarPanel) + end + + it 'returns User Settings Panel for profile nav' do + expect(helper.super_sidebar_nav_panel(nav: 'profile')).to be_a(Sidebars::UserSettings::Panel) + end + + it 'returns User profile Panel for user profile nav' do + expect(helper.super_sidebar_nav_panel(nav: 'user_profile')).to be_a(Sidebars::UserProfile::Panel) + end + + it 'returns "Your Work" Panel for your_work nav', :use_clean_rails_memory_store_caching do + expect(helper.super_sidebar_nav_panel(nav: 'your_work', user: user)).to be_a(Sidebars::YourWork::Panel) + end + + it 'returns "Your Work" Panel as a fallback', :use_clean_rails_memory_store_caching do + expect(helper.super_sidebar_nav_panel(user: user)).to be_a(Sidebars::YourWork::Panel) + end end end diff --git a/spec/helpers/sorting_helper_spec.rb b/spec/helpers/sorting_helper_spec.rb index d561b08efac..d625b46e286 100644 --- a/spec/helpers/sorting_helper_spec.rb +++ b/spec/helpers/sorting_helper_spec.rb @@ -10,6 +10,60 @@ RSpec.describe SortingHelper do allow(self).to receive(:request).and_return(double(path: 'http://test.com', query_parameters: { label_name: option })) end + describe '#issuable_sort_options' do + let(:viewing_issues) { false } + let(:viewing_merge_requests) { false } + let(:params) { {} } + + subject(:options) { helper.issuable_sort_options(viewing_issues, viewing_merge_requests) } + + before do + allow(helper).to receive(:params).and_return(params) + end + + shared_examples 'with merged date option' do + it 'adds merged date option' do + expect(options).to include( + a_hash_including( + value: 'merged_at', + text: 'Merged date' + ) + ) + end + end + + shared_examples 'without merged date option' do + it 'does not set merged date option' do + expect(options).not_to include( + a_hash_including( + value: 'merged_at', + text: 'Merged date' + ) + ) + end + end + + it_behaves_like 'without merged date option' + + context 'when viewing_merge_requests is true' do + let(:viewing_merge_requests) { true } + + it_behaves_like 'without merged date option' + + context 'when state param is all' do + let(:params) { { state: 'all' } } + + it_behaves_like 'with merged date option' + end + + context 'when state param is merged' do + let(:params) { { state: 'merged' } } + + it_behaves_like 'with merged date option' + end + end + end + describe '#admin_users_sort_options' do it 'returns correct link attributes in array' do options = admin_users_sort_options(filter: 'filter', search_query: 'search') diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb index 26951b0c1e7..8d24e9576e0 100644 --- a/spec/helpers/todos_helper_spec.rb +++ b/spec/helpers/todos_helper_spec.rb @@ -135,18 +135,6 @@ RSpec.describe TodosHelper do context 'when given a task' do let(:todo) { task_todo } - context 'when the use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'responds with an appropriate path' do - path = helper.todo_target_path(todo) - - expect(path).to eq("/#{todo.project.full_path}/-/work_items/#{todo.target.id}") - end - end - it 'responds with an appropriate path using iid' do path = helper.todo_target_path(todo) diff --git a/spec/helpers/users/callouts_helper_spec.rb b/spec/helpers/users/callouts_helper_spec.rb index 4cb179e4f60..cb724816daf 100644 --- a/spec/helpers/users/callouts_helper_spec.rb +++ b/spec/helpers/users/callouts_helper_spec.rb @@ -165,7 +165,27 @@ RSpec.describe Users::CalloutsHelper do end end - describe '#web_hook_disabled_dismissed?' do + describe '.show_pages_menu_callout?' do + subject { helper.show_pages_menu_callout? } + + before do + allow(helper).to receive(:user_dismissed?).with(described_class::PAGES_MOVED_CALLOUT) { dismissed } + end + + context 'when user has not dismissed' do + let(:dismissed) { false } + + it { is_expected.to be true } + end + + context 'when user dismissed' do + let(:dismissed) { true } + + it { is_expected.to be false } + end + end + + describe '#web_hook_disabled_dismissed?', feature_category: :integrations do context 'without a project' do it 'is false' do expect(helper).not_to be_web_hook_disabled_dismissed(nil) @@ -174,50 +194,12 @@ RSpec.describe Users::CalloutsHelper do context 'with a project' do let_it_be(:project) { create(:project) } + let(:factory) { :project_callout } + let(:container_key) { :project } + let(:container) { project } + let(:key) { "web_hooks:last_failure:project-#{project.id}" } - context 'the web-hook failure callout has never been dismissed' do - it 'is false' do - expect(helper).not_to be_web_hook_disabled_dismissed(project) - end - end - - context 'the web-hook failure callout has been dismissed', :freeze_time do - before do - create(:project_callout, - feature_name: described_class::WEB_HOOK_DISABLED, - user: user, - project: project, - dismissed_at: 1.week.ago) - end - - it 'is true' do - expect(helper).to be_web_hook_disabled_dismissed(project) - end - - context 'when there was an older failure', :clean_gitlab_redis_shared_state do - let(:key) { "web_hooks:last_failure:project-#{project.id}" } - - before do - Gitlab::Redis::SharedState.with { |r| r.set(key, 1.month.ago.iso8601) } - end - - it 'is true' do - expect(helper).to be_web_hook_disabled_dismissed(project) - end - end - - context 'when there has been a more recent failure', :clean_gitlab_redis_shared_state do - let(:key) { "web_hooks:last_failure:project-#{project.id}" } - - before do - Gitlab::Redis::SharedState.with { |r| r.set(key, 1.day.ago.iso8601) } - end - - it 'is false' do - expect(helper).not_to be_web_hook_disabled_dismissed(project) - end - end - end + include_examples 'CalloutsHelper#web_hook_disabled_dismissed shared examples' end end end diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb index c2c78be6a0f..2829236f7d1 100644 --- a/spec/helpers/users_helper_spec.rb +++ b/spec/helpers/users_helper_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe UsersHelper do include TermsHelper - let(:user) { create(:user) } + let_it_be(:user) { create(:user, timezone: ActiveSupport::TimeZone::MAPPING['UTC']) } def filter_ee_badges(badges) badges.reject { |badge| badge[:text] == 'Is using seat' } @@ -37,6 +37,35 @@ RSpec.describe UsersHelper do end end + describe '#user_clear_status_at' do + context 'when status exists' do + context 'with clear_status_at set' do + it 'has the correct iso formatted date', time_travel_to: '2020-01-01 00:00:00 +0000' do + clear_status_at = 1.day.from_now + status = build_stubbed(:user_status, clear_status_at: clear_status_at) + + expect(user_clear_status_at(status.user)).to eq('2020-01-02T00:00:00Z') + end + end + + context 'without clear_status_at set' do + it 'returns nil' do + status = build_stubbed(:user_status, clear_status_at: nil) + + expect(user_clear_status_at(status.user)).to be_nil + end + end + end + + context 'without status' do + it 'returns nil' do + user = build_stubbed(:user) + + expect(user_clear_status_at(user)).to be_nil + end + end + end + describe '#profile_tabs' do subject(:tabs) { helper.profile_tabs } @@ -468,4 +497,31 @@ RSpec.describe UsersHelper do expect(data[:paths]).to match_schema('entities/admin_users_data_attributes_paths') end end + + describe '#trials_link_url' do + it 'returns the correct URL' do + if Gitlab.ee? + expect(trials_link_url).to eq('/-/trial_registrations/new?glm_content=top-right-dropdown&glm_source=gitlab.com') + else + expect(trials_link_url).to eq('https://about.gitlab.com/free-trial/') + end + end + end + + describe '#user_profile_tabs_app_data' do + before do + allow(helper).to receive(:user_calendar_path).with(user, :json).and_return('/users/root/calendar.json') + allow(user).to receive_message_chain(:followers, :count).and_return(2) + allow(user).to receive_message_chain(:followees, :count).and_return(3) + end + + it 'returns expected hash' do + expect(helper.user_profile_tabs_app_data(user)).to eq({ + followees: 3, + followers: 2, + user_calendar_path: '/users/root/calendar.json', + utc_offset: 0 + }) + end + end end |