summaryrefslogtreecommitdiff
path: root/spec/support/shared_examples
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-21 03:08:37 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-21 03:08:37 +0000
commit2399724614f3c4dcf3059038d997193830de93ee (patch)
tree3315c4453ef3efb5c1162911753436cad4f3e57d /spec/support/shared_examples
parent6755df108b123ecc8ae330d7c7bf2f04fbf36a81 (diff)
downloadgitlab-ce-2399724614f3c4dcf3059038d997193830de93ee.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/support/shared_examples')
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/ci/auto_merge_merge_requests_shared_examples.rb (renamed from spec/support/shared_examples/ci/auto_merge_merge_requests_examples.rb)4
-rw-r--r--spec/support/shared_examples/ci/pipeline_email_shared_examples.rb (renamed from spec/support/shared_examples/ci/pipeline_email_examples.rb)2
-rw-r--r--spec/support/shared_examples/ci/stage_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/application_settings_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/discussions_provider_shared_examples.rb (renamed from spec/support/shared_examples/discussions_provider_shared_examples.rb)4
-rw-r--r--spec/support/shared_examples/controllers/environments_controller_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/controllers/error_tracking_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb508
-rw-r--r--spec/support/shared_examples/controllers/instance_statistics_controllers_shared_examples.rb (renamed from spec/support/shared_examples/instance_statistics_controllers_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/issuables_list_metadata_shared_examples.rb (renamed from spec/support/shared_examples/issuables_list_metadata_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/controllers/issuables_requiring_filter_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb (renamed from spec/support/shared_examples/milestone_tabs_examples.rb)2
-rw-r--r--spec/support/shared_examples/controllers/paginated_collection_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb (renamed from spec/support/shared_examples/controllers/repository_lfs_file_load_examples.rb)2
-rw-r--r--spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb108
-rw-r--r--spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/todos_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/trackable_shared_examples.rb (renamed from spec/support/shared_examples/trackable_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/controllers/update_invalid_issuable_shared_examples.rb (renamed from spec/support/shared_examples/update_invalid_issuable.rb)2
-rw-r--r--spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/controllers/variables_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/email_shared_examples.rb9
-rw-r--r--spec/support/shared_examples/evidence_updated_exposed_fields.rb29
-rw-r--r--spec/support/shared_examples/fast_destroy_all.rb40
-rw-r--r--spec/support/shared_examples/features/archive_download_buttons_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/dirty_submit_form_shared_examples.rb (renamed from spec/support/shared_examples/dirty_submit_form_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/features/discussion_comments_shared_example.rb314
-rw-r--r--spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/project_list_shared_examples.rb (renamed from spec/support/shared_examples/project_list_shared_examples.rb)4
-rw-r--r--spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb (renamed from spec/support/shared_examples/features/protected_branches_access_control_ce.rb)2
-rw-r--r--spec/support/shared_examples/features/reportable_note_shared_examples.rb49
-rw-r--r--spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb43
-rw-r--r--spec/support/shared_examples/features/rss_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/features/search_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/showing_user_status_shared_examples.rb (renamed from spec/support/shared_examples/showing_user_status_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/features/snippets_shared_examples.rb (renamed from spec/support/shared_examples/snippets_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/features/variable_list_shared_examples.rb388
-rw-r--r--spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb (renamed from spec/support/shared_examples/wiki_file_attachments_examples.rb)2
-rw-r--r--spec/support/shared_examples/finders/assignees_filter_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/finders/finder_with_external_authorization_enabled_shared_examples.rb (renamed from spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb)4
-rw-r--r--spec/support/shared_examples/finders/snippet_visibility_shared_examples.rb (renamed from spec/support/shared_examples/snippet_visibility_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/graphql/connection_paged_nodes_shared_examples.rb (renamed from spec/support/shared_examples/graphql/connection_paged_nodes.rb)0
-rw-r--r--spec/support/shared_examples/graphql/failure_to_find_anything_shared_examples.rb (renamed from spec/support/shared_examples/graphql/failure_to_find_anything.rb)4
-rw-r--r--spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/initializers/uses_gitlab_url_blocker_shared_examples.rb (renamed from spec/support/shared_examples/uses_gitlab_url_blocker_examples.rb)2
-rw-r--r--spec/support/shared_examples/legacy_path_redirect_shared_examples.rb23
-rw-r--r--spec/support/shared_examples/lib/banzai/reference_parser_shared_examples.rb (renamed from spec/support/shared_examples/reference_parser_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_shared_examples.rb (renamed from spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb)2
-rw-r--r--spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb (renamed from spec/support/shared_examples/ci_trace_shared_examples.rb)6
-rw-r--r--spec/support/shared_examples/lib/gitlab/cycle_analytics_event_shared_examples.rb (renamed from spec/support/shared_examples/cycle_analytics_event_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb (renamed from spec/support/shared_examples/diff_file_collections.rb)6
-rw-r--r--spec/support/shared_examples/lib/gitlab/file_finder_shared_examples.rb (renamed from spec/support/shared_examples/file_finder.rb)2
-rw-r--r--spec/support/shared_examples/lib/gitlab/gitlab_verify_shared_examples.rb (renamed from spec/support/shared_examples/gitlab_verify.rb)0
-rw-r--r--spec/support/shared_examples/lib/gitlab/helm_generated_script_shared_examples.rb (renamed from spec/support/shared_examples/helm_generated_script.rb)2
-rw-r--r--spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/gitlab/ldap_shared_examples.rb (renamed from spec/support/shared_examples/ldap_shared_examples.rb)4
-rw-r--r--spec/support/shared_examples/lib/gitlab/malicious_regexp_shared_examples.rb (renamed from spec/support/shared_examples/malicious_regexp_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/lib/gitlab/migration_helpers_shared_examples.rb (renamed from spec/support/shared_examples/migration_helpers_examples.rb)4
-rw-r--r--spec/support/shared_examples/lib/gitlab/position_formatters_shared_examples.rb (renamed from spec/support/shared_examples/position_formatters.rb)2
-rw-r--r--spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb (renamed from spec/support/shared_examples/repo_type_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/lib/gitlab/unique_ip_check_shared_examples.rb (renamed from spec/support/shared_examples/unique_ip_check_shared_examples.rb)42
-rw-r--r--spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter_shared_examples.rb (renamed from spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb)4
-rw-r--r--spec/support/shared_examples/mail_room_shared_examples.rb35
-rw-r--r--spec/support/shared_examples/mailers/notify_shared_examples.rb (renamed from spec/support/shared_examples/notify_shared_examples.rb)68
-rw-r--r--spec/support/shared_examples/models/active_record_enum_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/application_setting_shared_examples.rb (renamed from spec/support/shared_examples/application_setting_examples.rb)0
-rw-r--r--spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/chat_service_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/chat_slash_commands_shared_examples.rb (renamed from spec/support/shared_examples/chat_slash_commands_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/models/ci_variable_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/cluster_application_core_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/cluster_application_helm_cert_shared_examples.rb (renamed from spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb)2
-rw-r--r--spec/support/shared_examples/models/cluster_application_initial_status_shared_examples.rb (renamed from spec/support/shared_examples/models/cluster_application_initial_status.rb)2
-rw-r--r--spec/support/shared_examples/models/cluster_application_status_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/cluster_application_version_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/cluster_cleanup_worker_base_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/clusters/providers/provider_status_shared_examples.rb (renamed from spec/support/shared_examples/models/clusters/providers/provider_status.rb)2
-rw-r--r--spec/support/shared_examples/models/concerns/issuable_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/models/concerns/redactable_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb (renamed from spec/support/shared_examples/cycle_analytics_stage_shared_examples.rb)4
-rw-r--r--spec/support/shared_examples/models/diff_note_after_commit_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/email_format_shared_examples.rb (renamed from spec/support/shared_examples/email_format_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/models/group_members_shared_example.rb (renamed from spec/support/shared_examples/group_members_shared_example.rb)0
-rw-r--r--spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/issue_tracker_service_shared_examples.rb (renamed from spec/support/shared_examples/issue_tracker_service_shared_example.rb)0
-rw-r--r--spec/support/shared_examples/models/label_note_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/member_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/mentionable_shared_examples.rb (renamed from spec/support/shared_examples/mentionable_shared_examples.rb)12
-rw-r--r--spec/support/shared_examples/models/project_hook_data_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb (renamed from spec/support/shared_examples/project_latest_successful_build_for_examples.rb)2
-rw-r--r--spec/support/shared_examples/models/relative_positioning_shared_examples.rb (renamed from spec/support/shared_examples/relative_positioning_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/models/services_fields_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb (renamed from spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/models/taskable_shared_examples.rb (renamed from spec/support/shared_examples/taskable_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/models/throttled_touch_shared_examples.rb (renamed from spec/support/shared_examples/throttled_touch.rb)2
-rw-r--r--spec/support/shared_examples/models/update_project_statistics_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/user_mentions_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/versioned_description_shared_examples.rb (renamed from spec/support/shared_examples/versioned_description_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/models/with_uploads_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/policies/clusterable_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issue/zoom_quick_actions_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/award_emoji_todo_shared_examples.rb (renamed from spec/support/shared_examples/award_emoji_todo_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/requests/api/boards_shared_examples.rb189
-rw-r--r--spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb (renamed from spec/support/shared_examples/container_repositories_shared_examples.rb)6
-rw-r--r--spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/diff_discussions_shared_examples.rb (renamed from spec/support/shared_examples/requests/api/diff_discussions.rb)2
-rw-r--r--spec/support/shared_examples/requests/api/discussions_shared_examples.rb (renamed from spec/support/shared_examples/requests/api/discussions.rb)4
-rw-r--r--spec/support/shared_examples/requests/api/issuable_participants_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/issues_resolving_discussions_shared_examples.rb17
-rw-r--r--spec/support/shared_examples/requests/api/issues_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb (renamed from spec/support/shared_examples/logging_application_context_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/requests/api/members_shared_examples.rb13
-rw-r--r--spec/support/shared_examples/requests/api/milestones_shared_examples.rb405
-rw-r--r--spec/support/shared_examples/requests/api/notes_shared_examples.rb (renamed from spec/support/shared_examples/requests/api/notes.rb)2
-rw-r--r--spec/support/shared_examples/requests/api/pipelines/visibility_table_shared_examples.rb (renamed from spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb)2
-rw-r--r--spec/support/shared_examples/requests/api/read_user_shared_examples.rb87
-rw-r--r--spec/support/shared_examples/requests/api/repositories_shared_context.rb12
-rw-r--r--spec/support/shared_examples/requests/api/resolvable_discussions_shared_examples.rb (renamed from spec/support/shared_examples/requests/api/resolvable_discussions.rb)2
-rw-r--r--spec/support/shared_examples/requests/api/resource_label_events_api_shared_examples.rb (renamed from spec/support/shared_examples/resource_label_events_api.rb)2
-rw-r--r--spec/support/shared_examples/requests/api/status_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb148
-rw-r--r--spec/support/shared_examples/requests/graphql_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/requests/lfs_http_shared_examples.rb (renamed from spec/support/shared_examples/lfs_http_shared_examples.rb)12
-rw-r--r--spec/support/shared_examples/requests/rack_attack_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/routing/legacy_path_redirect_shared_examples.rb9
-rw-r--r--spec/support/shared_examples/serializers/diff_file_entity_shared_examples.rb (renamed from spec/support/shared_examples/serializers/diff_file_entity_examples.rb)6
-rw-r--r--spec/support/shared_examples/serializers/note_entity_shared_examples.rb (renamed from spec/support/shared_examples/serializers/note_entity_examples.rb)2
-rw-r--r--spec/support/shared_examples/services/base_helm_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/boards/boards_create_service_shared_examples.rb (renamed from spec/support/shared_examples/services/boards/boards_create_service.rb)2
-rw-r--r--spec/support/shared_examples/services/boards/boards_list_service_shared_examples.rb (renamed from spec/support/shared_examples/services/boards/boards_list_service.rb)4
-rw-r--r--spec/support/shared_examples/services/boards/issues_list_service_shared_examples.rb (renamed from spec/support/shared_examples/services/boards/issues_list_service.rb)2
-rw-r--r--spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb (renamed from spec/support/shared_examples/services/boards/issues_move_service.rb)2
-rw-r--r--spec/support/shared_examples/services/boards/lists_destroy_service_shared_examples.rb (renamed from spec/support/shared_examples/services/boards/lists_destroy_service.rb)2
-rw-r--r--spec/support/shared_examples/services/boards/lists_list_service_shared_examples.rb (renamed from spec/support/shared_examples/services/boards/lists_list_service.rb)2
-rw-r--r--spec/support/shared_examples/services/boards/lists_move_service_shared_examples.rb (renamed from spec/support/shared_examples/services/boards/lists_move_service.rb)2
-rw-r--r--spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/common_system_notes_shared_examples.rb (renamed from spec/support/shared_examples/common_system_notes_examples.rb)8
-rw-r--r--spec/support/shared_examples/services/count_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/error_tracking_service_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/issuable_shared_examples.rb (renamed from spec/support/shared_examples/issuable_shared_examples.rb)6
-rw-r--r--spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/services/notification_service_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/services/pages_size_limit_shared_examples.rb (renamed from spec/support/shared_examples/pages_size_limit_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/services/updating_mentions_shared_examples.rb (renamed from spec/support/shared_examples/updating_mentions_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/uploaders/object_storage_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/uploaders/upload_type_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/validators/url_validator_shared_examples.rb (renamed from spec/support/shared_examples/url_validator_examples.rb)0
-rw-r--r--spec/support/shared_examples/views/nav_sidebar_shared_examples.rb (renamed from spec/support/shared_examples/views/nav_sidebar.rb)2
-rw-r--r--spec/support/shared_examples/workers/concerns/reenqueuer_shared_examples.rb4
168 files changed, 2541 insertions, 445 deletions
diff --git a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
index f2f31e1b7f2..113252a6ab5 100644
--- a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
+++ b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'multiple issue boards' do
+RSpec.shared_examples 'multiple issue boards' do
context 'authorized user' do
before do
parent.add_maintainer(user)
diff --git a/spec/support/shared_examples/ci/auto_merge_merge_requests_examples.rb b/spec/support/shared_examples/ci/auto_merge_merge_requests_shared_examples.rb
index c11448ffe0f..9024845c325 100644
--- a/spec/support/shared_examples/ci/auto_merge_merge_requests_examples.rb
+++ b/spec/support/shared_examples/ci/auto_merge_merge_requests_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'aborted merge requests for MWPS' do
+RSpec.shared_examples 'aborted merge requests for MWPS' do
let(:aborted_message) do
/aborted the automatic merge because target branch was updated/
end
@@ -23,7 +23,7 @@ shared_examples 'aborted merge requests for MWPS' do
end
end
-shared_examples 'maintained merge requests for MWPS' do
+RSpec.shared_examples 'maintained merge requests for MWPS' do
it 'does not cancel auto merge' do
expect(merge_request.auto_merge_enabled?).to be_truthy
expect(merge_request.notes).to be_empty
diff --git a/spec/support/shared_examples/ci/pipeline_email_examples.rb b/spec/support/shared_examples/ci/pipeline_email_shared_examples.rb
index f72d8af3c65..01e453d8fd9 100644
--- a/spec/support/shared_examples/ci/pipeline_email_examples.rb
+++ b/spec/support/shared_examples/ci/pipeline_email_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'correct pipeline information for pipelines for merge requests' do
+RSpec.shared_examples 'correct pipeline information for pipelines for merge requests' do
context 'when pipeline for merge request' do
let(:pipeline) { merge_request.all_pipelines.first }
diff --git a/spec/support/shared_examples/ci/stage_shared_examples.rb b/spec/support/shared_examples/ci/stage_shared_examples.rb
index 925974ed11e..a2849e00d27 100644
--- a/spec/support/shared_examples/ci/stage_shared_examples.rb
+++ b/spec/support/shared_examples/ci/stage_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'manual playable stage' do |stage_type|
+RSpec.shared_examples 'manual playable stage' do |stage_type|
let(:stage) { build(stage_type, status: status) }
describe '#manual_playable?' do
diff --git a/spec/support/shared_examples/controllers/application_settings_shared_examples.rb b/spec/support/shared_examples/controllers/application_settings_shared_examples.rb
index 9619451cd14..3ee5d35d008 100644
--- a/spec/support/shared_examples/controllers/application_settings_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/application_settings_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'renders correct panels' do
+RSpec.shared_examples 'renders correct panels' do
it 'renders correct action on error' do
expect_next_instance_of(ApplicationSettings::UpdateService) do |service|
allow(service).to receive(:execute).and_return(false)
diff --git a/spec/support/shared_examples/discussions_provider_shared_examples.rb b/spec/support/shared_examples/controllers/discussions_provider_shared_examples.rb
index 0e7f491c6a4..43b5fa2d204 100644
--- a/spec/support/shared_examples/discussions_provider_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/discussions_provider_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples 'discussions provider' do
+RSpec.shared_examples 'discussions provider' do
it 'returns the expected discussions' do
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: requested_iid }
diff --git a/spec/support/shared_examples/controllers/environments_controller_shared_examples.rb b/spec/support/shared_examples/controllers/environments_controller_shared_examples.rb
index 3540f60bf1b..c6e880635aa 100644
--- a/spec/support/shared_examples/controllers/environments_controller_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/environments_controller_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'successful response for #cancel_auto_stop' do
+RSpec.shared_examples 'successful response for #cancel_auto_stop' do
include GitlabRoutingHelper
context 'when request is html' do
@@ -42,7 +42,7 @@ shared_examples_for 'successful response for #cancel_auto_stop' do
end
end
-shared_examples_for 'failed response for #cancel_auto_stop' do
+RSpec.shared_examples 'failed response for #cancel_auto_stop' do
context 'when request is html' do
let(:params) { environment_params(format: :html) }
diff --git a/spec/support/shared_examples/controllers/error_tracking_shared_examples.rb b/spec/support/shared_examples/controllers/error_tracking_shared_examples.rb
index 71251f6ab51..08e5efcf63c 100644
--- a/spec/support/shared_examples/controllers/error_tracking_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/error_tracking_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'sets the polling header' do
+RSpec.shared_examples 'sets the polling header' do
subject { response.headers[Gitlab::PollingInterval::HEADER_NAME] }
it { is_expected.to eq '1000'}
diff --git a/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb b/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb
index cccce7b91b5..d521106fa26 100644
--- a/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples 'disabled when using an external authorization service' do
+RSpec.shared_examples 'disabled when using an external authorization service' do
include ExternalAuthorizationServiceHelpers
it 'works when the feature is not enabled' do
@@ -20,7 +18,7 @@ shared_examples 'disabled when using an external authorization service' do
end
end
-shared_examples 'unauthorized when external service denies access' do
+RSpec.shared_examples 'unauthorized when external service denies access' do
include ExternalAuthorizationServiceHelpers
it 'allows access when the authorization service allows it' do
diff --git a/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb b/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
new file mode 100644
index 00000000000..a01fa49d701
--- /dev/null
+++ b/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
@@ -0,0 +1,508 @@
+# frozen_string_literal: true
+
+# Specifications for behavior common to all objects with an email attribute.
+# Takes a list of email-format attributes and requires:
+# - subject { "the object with a attribute= setter" }
+# Note: You have access to `email_value` which is the email address value
+# being currently tested).
+
+def assign_session_token(provider)
+ session[:"#{provider}_access_token"] = 'asdasd12345'
+end
+
+RSpec.shared_examples 'a GitHub-ish import controller: POST personal_access_token' do
+ let(:status_import_url) { public_send("status_import_#{provider}_url") }
+
+ it "updates access token" do
+ token = 'asdfasdf9876'
+
+ allow_any_instance_of(Gitlab::LegacyGithubImport::Client)
+ .to receive(:user).and_return(true)
+
+ post :personal_access_token, params: { personal_access_token: token }
+
+ expect(session[:"#{provider}_access_token"]).to eq(token)
+ expect(controller).to redirect_to(status_import_url)
+ end
+
+ it "strips access token with spaces" do
+ token = 'asdfasdf9876'
+
+ allow_any_instance_of(Gitlab::LegacyGithubImport::Client)
+ .to receive(:user).and_return(true)
+
+ post :personal_access_token, params: { personal_access_token: " #{token} " }
+
+ expect(session[:"#{provider}_access_token"]).to eq(token)
+ expect(controller).to redirect_to(status_import_url)
+ end
+end
+
+RSpec.shared_examples 'a GitHub-ish import controller: GET new' do
+ let(:status_import_url) { public_send("status_import_#{provider}_url") }
+
+ it "redirects to status if we already have a token" do
+ assign_session_token(provider)
+ allow(controller).to receive(:logged_in_with_provider?).and_return(false)
+
+ get :new
+
+ expect(controller).to redirect_to(status_import_url)
+ end
+
+ it "renders the :new page if no token is present in session" do
+ get :new
+
+ expect(response).to render_template(:new)
+ end
+end
+
+RSpec.shared_examples 'a GitHub-ish import controller: GET status' do
+ let(:new_import_url) { public_send("new_import_#{provider}_url") }
+ let(:user) { create(:user) }
+ let(:repo) { OpenStruct.new(login: 'vim', full_name: 'asd/vim', name: 'vim', owner: { login: 'owner' }) }
+ let(:org) { OpenStruct.new(login: 'company') }
+ let(:org_repo) { OpenStruct.new(login: 'company', full_name: 'company/repo', name: 'repo', owner: { login: 'owner' }) }
+
+ before do
+ assign_session_token(provider)
+ end
+
+ it "returns variables for json request" do
+ project = create(:project, import_type: provider, namespace: user.namespace, import_status: :finished, import_source: 'example/repo')
+ group = create(:group)
+ group.add_owner(user)
+ stub_client(repos: [repo, org_repo], orgs: [org], org_repos: [org_repo])
+
+ get :status, format: :json
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id)
+ expect(json_response.dig("provider_repos", 0, "id")).to eq(repo.id)
+ expect(json_response.dig("provider_repos", 1, "id")).to eq(org_repo.id)
+ expect(json_response.dig("namespaces", 0, "id")).to eq(group.id)
+ end
+
+ it "does not show already added project" do
+ project = create(:project, import_type: provider, namespace: user.namespace, import_status: :finished, import_source: 'asd/vim')
+ stub_client(repos: [repo], orgs: [])
+
+ get :status, format: :json
+
+ expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id)
+ expect(json_response.dig("provider_repos")).to eq([])
+ end
+
+ it "touches the etag cache store" do
+ expect(stub_client(repos: [], orgs: [])).to receive(:repos)
+ expect_next_instance_of(Gitlab::EtagCaching::Store) do |store|
+ expect(store).to receive(:touch) { "realtime_changes_import_#{provider}_path" }
+ end
+
+ get :status, format: :json
+ end
+
+ it "requests provider repos list" do
+ expect(stub_client(repos: [], orgs: [])).to receive(:repos)
+
+ get :status
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it "handles an invalid access token" do
+ allow_any_instance_of(Gitlab::LegacyGithubImport::Client)
+ .to receive(:repos).and_raise(Octokit::Unauthorized)
+
+ get :status
+
+ expect(session[:"#{provider}_access_token"]).to be_nil
+ expect(controller).to redirect_to(new_import_url)
+ expect(flash[:alert]).to eq("Access denied to your #{Gitlab::ImportSources.title(provider.to_s)} account.")
+ end
+
+ it "does not produce N+1 database queries" do
+ stub_client(repos: [repo], orgs: [])
+ group_a = create(:group)
+ group_a.add_owner(user)
+ create(:project, :import_started, import_type: provider, namespace: user.namespace)
+
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ get :status, format: :json
+ end.count
+
+ stub_client(repos: [repo, org_repo], orgs: [])
+ group_b = create(:group)
+ group_b.add_owner(user)
+ create(:project, :import_started, import_type: provider, namespace: user.namespace)
+
+ expect { get :status, format: :json }
+ .not_to exceed_all_query_limit(control_count)
+ end
+
+ context 'when filtering' do
+ let(:repo_2) { OpenStruct.new(login: 'emacs', full_name: 'asd/emacs', name: 'emacs', owner: { login: 'owner' }) }
+ let(:project) { create(:project, import_type: provider, namespace: user.namespace, import_status: :finished, import_source: 'example/repo') }
+ let(:group) { create(:group) }
+
+ before do
+ group.add_owner(user)
+ stub_client(repos: [repo, repo_2, org_repo], orgs: [org], org_repos: [org_repo])
+ end
+
+ it 'filters list of repositories by name' do
+ get :status, params: { filter: 'emacs' }, format: :json
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.dig("imported_projects").count).to eq(0)
+ expect(json_response.dig("provider_repos").count).to eq(1)
+ expect(json_response.dig("provider_repos", 0, "id")).to eq(repo_2.id)
+ expect(json_response.dig("namespaces", 0, "id")).to eq(group.id)
+ end
+
+ context 'when user input contains html' do
+ let(:expected_filter) { 'test' }
+ let(:filter) { "<html>#{expected_filter}</html>" }
+
+ it 'sanitizes user input' do
+ get :status, params: { filter: filter }, format: :json
+
+ expect(assigns(:filter)).to eq(expected_filter)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'a GitHub-ish import controller: POST create' do
+ let(:user) { create(:user) }
+ let(:provider_username) { user.username }
+ let(:provider_user) { OpenStruct.new(login: provider_username) }
+ let(:project) { create(:project, import_type: provider, import_status: :finished, import_source: "#{provider_username}/vim") }
+ let(:provider_repo) do
+ OpenStruct.new(
+ name: 'vim',
+ full_name: "#{provider_username}/vim",
+ owner: OpenStruct.new(login: provider_username)
+ )
+ end
+
+ before do
+ stub_client(user: provider_user, repo: provider_repo)
+ assign_session_token(provider)
+ end
+
+ it 'returns 200 response when the project is imported successfully' do
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns 422 response with the base error when the project could not be imported' do
+ project = build(:project)
+ project.errors.add(:name, 'is invalid')
+ project.errors.add(:path, 'is old')
+
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response['errors']).to eq('Name is invalid, Path is old')
+ end
+
+ it "touches the etag cache store" do
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+ expect_next_instance_of(Gitlab::EtagCaching::Store) do |store|
+ expect(store).to receive(:touch) { "realtime_changes_import_#{provider}_path" }
+ end
+
+ post :create, format: :json
+ end
+
+ context "when the repository owner is the provider user" do
+ context "when the provider user and GitLab user's usernames match" do
+ it "takes the current user's namespace" do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+ end
+ end
+
+ context "when the provider user and GitLab user's usernames don't match" do
+ let(:provider_username) { "someone_else" }
+
+ it "takes the current user's namespace" do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+ end
+ end
+ end
+
+ context "when the repository owner is not the provider user" do
+ let(:other_username) { "someone_else" }
+
+ before do
+ provider_repo.owner = OpenStruct.new(login: other_username)
+ assign_session_token(provider)
+ end
+
+ context "when a namespace with the provider user's username already exists" do
+ let!(:existing_namespace) { user.namespace }
+
+ context "when the namespace is owned by the GitLab user" do
+ before do
+ user.username = other_username
+ user.save
+ end
+
+ it "takes the existing namespace" do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, existing_namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+ end
+ end
+
+ context "when the namespace is not owned by the GitLab user" do
+ it "creates a project using user's namespace" do
+ create(:user, username: other_username)
+
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+ end
+ end
+ end
+
+ context "when a namespace with the provider user's username doesn't exist" do
+ context "when current user can create namespaces" do
+ it "creates the namespace" do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).and_return(double(execute: project))
+
+ expect { post :create, params: { target_namespace: provider_repo.name }, format: :json }.to change(Namespace, :count).by(1)
+ end
+
+ it "takes the new namespace" do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, an_instance_of(Group), user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, params: { target_namespace: provider_repo.name }, format: :json
+ end
+ end
+
+ context "when current user can't create namespaces" do
+ before do
+ user.update_attribute(:can_create_group, false)
+ end
+
+ it "doesn't create the namespace" do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).and_return(double(execute: project))
+
+ expect { post :create, format: :json }.not_to change(Namespace, :count)
+ end
+
+ it "takes the current user's namespace" do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+ end
+ end
+ end
+
+ context 'user has chosen a namespace and name for the project' do
+ let(:test_namespace) { create(:group, name: 'test_namespace') }
+ let(:test_name) { 'test_name' }
+
+ before do
+ test_namespace.add_owner(user)
+ end
+
+ it 'takes the selected namespace and name' do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, test_namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, params: { target_namespace: test_namespace.name, new_name: test_name }, format: :json
+ end
+
+ it 'takes the selected name and default namespace' do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, params: { new_name: test_name }, format: :json
+ end
+ end
+
+ context 'user has chosen an existing nested namespace and name for the project' do
+ let(:parent_namespace) { create(:group, name: 'foo') }
+ let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) }
+ let(:test_name) { 'test_name' }
+
+ before do
+ parent_namespace.add_owner(user)
+ nested_namespace.add_owner(user)
+ end
+
+ it 'takes the selected namespace and name' do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, nested_namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, params: { target_namespace: nested_namespace.full_path, new_name: test_name }, format: :json
+ end
+ end
+
+ context 'user has chosen a non-existent nested namespaces and name for the project' do
+ let(:test_name) { 'test_name' }
+
+ it 'takes the selected namespace and name' do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json
+ end
+
+ it 'creates the namespaces' do
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ expect { post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json }
+ .to change { Namespace.count }.by(2)
+ end
+
+ it 'new namespace has the right parent' do
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json
+
+ expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo')
+ end
+ end
+
+ context 'user has chosen existent and non-existent nested namespaces and name for the project' do
+ let(:test_name) { 'test_name' }
+ let!(:parent_namespace) { create(:group, name: 'foo') }
+
+ before do
+ parent_namespace.add_owner(user)
+ end
+
+ it 'takes the selected namespace and name' do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :json
+ end
+
+ it 'creates the namespaces' do
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ expect { post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :json }
+ .to change { Namespace.count }.by(2)
+ end
+
+ it 'does not create a new namespace under the user namespace' do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ expect { post :create, params: { target_namespace: "#{user.namespace_path}/test_group", new_name: test_name }, format: :js }
+ .not_to change { Namespace.count }
+ end
+ end
+
+ context 'user cannot create a subgroup inside a group is not a member of' do
+ let(:test_name) { 'test_name' }
+ let!(:parent_namespace) { create(:group, name: 'foo') }
+
+ it 'does not take the selected namespace and name' do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :js
+ end
+
+ it 'does not create the namespaces' do
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ expect { post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :js }
+ .not_to change { Namespace.count }
+ end
+ end
+
+ context 'user can use a group without having permissions to create a group' do
+ let(:test_name) { 'test_name' }
+ let!(:group) { create(:group, name: 'foo') }
+
+ it 'takes the selected namespace and name' do
+ group.add_owner(user)
+ user.update!(can_create_group: false)
+
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, group, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, params: { target_namespace: 'foo', new_name: test_name }, format: :js
+ end
+ end
+
+ context 'when user can not create projects in the chosen namespace' do
+ it 'returns 422 response' do
+ other_namespace = create(:group, name: 'other_namespace')
+
+ post :create, params: { target_namespace: other_namespace.name }, format: :json
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'a GitHub-ish import controller: GET realtime_changes' do
+ let(:user) { create(:user) }
+
+ before do
+ assign_session_token(provider)
+ end
+
+ it 'sets a Poll-Interval header' do
+ project = create(:project, import_type: provider, namespace: user.namespace, import_status: :finished, import_source: 'example/repo')
+
+ get :realtime_changes
+
+ expect(json_response).to eq([{ "id" => project.id, "import_status" => project.import_status }])
+ expect(Integer(response.headers['Poll-Interval'])).to be > -1
+ end
+end
diff --git a/spec/support/shared_examples/instance_statistics_controllers_shared_examples.rb b/spec/support/shared_examples/controllers/instance_statistics_controllers_shared_examples.rb
index 8ea307c7c61..e4d59463d93 100644
--- a/spec/support/shared_examples/instance_statistics_controllers_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/instance_statistics_controllers_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'instance statistics availability' do
+RSpec.shared_examples 'instance statistics availability' do
let(:user) { create(:user) }
before do
diff --git a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
index 26ed86bfe26..5ecc5c08bbd 100644
--- a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issuable notes filter' do
+RSpec.shared_examples 'issuable notes filter' do
let(:params) do
if issuable_parent.is_a?(Project)
{ namespace_id: issuable_parent.namespace, project_id: issuable_parent, id: issuable.iid }
diff --git a/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb b/spec/support/shared_examples/controllers/issuables_list_metadata_shared_examples.rb
index 52d90b5f183..2dbaea57c44 100644
--- a/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/issuables_list_metadata_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issuables list meta-data' do |issuable_type, action = nil|
+RSpec.shared_examples 'issuables list meta-data' do |issuable_type, action = nil|
include ProjectForksHelper
def get_action(action, project, extra_params = {})
diff --git a/spec/support/shared_examples/controllers/issuables_requiring_filter_shared_examples.rb b/spec/support/shared_examples/controllers/issuables_requiring_filter_shared_examples.rb
index ee25df00dfb..e7514e7bb72 100644
--- a/spec/support/shared_examples/controllers/issuables_requiring_filter_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/issuables_requiring_filter_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issuables requiring filter' do |action|
+RSpec.shared_examples 'issuables requiring filter' do |action|
it "doesn't load any issuables if no filter is set" do
expect_any_instance_of(described_class).not_to receive(:issuables_collection)
diff --git a/spec/support/shared_examples/milestone_tabs_examples.rb b/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb
index bda4b978737..d9656824452 100644
--- a/spec/support/shared_examples/milestone_tabs_examples.rb
+++ b/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'milestone tabs' do
+RSpec.shared_examples 'milestone tabs' do
def go(path, extra_params = {})
params =
case milestone
diff --git a/spec/support/shared_examples/controllers/paginated_collection_shared_examples.rb b/spec/support/shared_examples/controllers/paginated_collection_shared_examples.rb
index 41a8d2d8117..620a6eaf879 100644
--- a/spec/support/shared_examples/controllers/paginated_collection_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/paginated_collection_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples 'paginated collection' do
+RSpec.shared_examples 'paginated collection' do
let(:collection) { nil }
let(:last_page) { collection.page.total_pages }
let(:action) { :index }
diff --git a/spec/support/shared_examples/controllers/repository_lfs_file_load_examples.rb b/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb
index 8e5fae5da18..b8967bc8df3 100644
--- a/spec/support/shared_examples/controllers/repository_lfs_file_load_examples.rb
+++ b/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb
@@ -17,7 +17,7 @@
# it_behaves_like 'a controller that can serve LFS files', skip_lfs_disabled_tests: true do
# ...
# end
-shared_examples 'a controller that can serve LFS files' do |options = {}|
+RSpec.shared_examples 'a controller that can serve LFS files' do |options = {}|
let(:lfs_oid) { '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897' }
let(:lfs_size) { '1575078' }
let!(:lfs_object) { create(:lfs_object, oid: lfs_oid, size: lfs_size) }
diff --git a/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb b/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb
new file mode 100644
index 00000000000..e21a3b2f588
--- /dev/null
+++ b/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'authenticates sessionless user' do |path, format, params|
+ params ||= {}
+
+ before do
+ stub_authentication_activity_metrics(debug: false)
+ end
+
+ let(:user) { create(:user) }
+ let(:personal_access_token) { create(:personal_access_token, user: user) }
+ let(:default_params) { { format: format }.merge(params.except(:public) || {}) }
+
+ context "when the 'personal_access_token' param is populated with the personal access token" do
+ it 'logs the user in' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+ .and increment(:user_session_override_counter)
+ .and increment(:user_sessionless_authentication_counter)
+
+ get path, params: default_params.merge(private_token: personal_access_token.token)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(controller.current_user).to eq(user)
+ end
+
+ it 'does not log the user in if page is public', if: params[:public] do
+ get path, params: default_params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(controller.current_user).to be_nil
+ end
+ end
+
+ context 'when the personal access token has no api scope', unless: params[:public] do
+ it 'does not log the user in' do
+ # Several instances of where these specs are shared route the request
+ # through ApplicationController#route_not_found which does not involve
+ # the usual auth code from Devise, so does not increment the
+ # :user_unauthenticated_counter
+ #
+ unless params[:ignore_incrementing]
+ expect(authentication_metrics)
+ .to increment(:user_unauthenticated_counter)
+ end
+
+ personal_access_token.update(scopes: [:read_user])
+
+ get path, params: default_params.merge(private_token: personal_access_token.token)
+
+ expect(response).not_to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context "when the 'PERSONAL_ACCESS_TOKEN' header is populated with the personal access token" do
+ it 'logs the user in' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+ .and increment(:user_session_override_counter)
+ .and increment(:user_sessionless_authentication_counter)
+
+ @request.headers['PRIVATE-TOKEN'] = personal_access_token.token
+ get path, params: default_params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context "when the 'feed_token' param is populated with the feed token", if: format == :rss do
+ it "logs the user in" do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+ .and increment(:user_session_override_counter)
+ .and increment(:user_sessionless_authentication_counter)
+
+ get path, params: default_params.merge(feed_token: user.feed_token)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context "when the 'feed_token' param is populated with an invalid feed token", if: format == :rss, unless: params[:public] do
+ it "logs the user" do
+ expect(authentication_metrics)
+ .to increment(:user_unauthenticated_counter)
+
+ get path, params: default_params.merge(feed_token: 'token')
+
+ expect(response.status).not_to eq 200
+ end
+ end
+
+ it "doesn't log the user in otherwise", unless: params[:public] do
+ # Several instances of where these specs are shared route the request
+ # through ApplicationController#route_not_found which does not involve
+ # the usual auth code from Devise, so does not increment the
+ # :user_unauthenticated_counter
+ #
+ unless params[:ignore_incrementing]
+ expect(authentication_metrics)
+ .to increment(:user_unauthenticated_counter)
+ end
+
+ get path, params: default_params.merge(private_token: 'token')
+
+ expect(response.status).not_to eq(200)
+ end
+end
diff --git a/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb b/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb
index d89eded6e69..9b5f957d489 100644
--- a/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'set sort order from user preference' do
+RSpec.shared_examples 'set sort order from user preference' do
describe '#set_sort_order_from_user_preference' do
# There is no sorting_field defined in any CE controllers yet,
# however any other field present in user_preferences table can be used for testing.
diff --git a/spec/support/shared_examples/controllers/todos_shared_examples.rb b/spec/support/shared_examples/controllers/todos_shared_examples.rb
index e220f6bfc9b..98fc9d9d926 100644
--- a/spec/support/shared_examples/controllers/todos_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/todos_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'todos actions' do
+RSpec.shared_examples 'todos actions' do
context 'when authorized' do
before do
sign_in(user)
diff --git a/spec/support/shared_examples/trackable_shared_examples.rb b/spec/support/shared_examples/controllers/trackable_shared_examples.rb
index 6ad75a14d6b..e82c27c43f5 100644
--- a/spec/support/shared_examples/trackable_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/trackable_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'a Trackable Controller' do
+RSpec.shared_examples 'a Trackable Controller' do
describe '#track_event' do
before do
sign_in user
diff --git a/spec/support/shared_examples/update_invalid_issuable.rb b/spec/support/shared_examples/controllers/update_invalid_issuable_shared_examples.rb
index b7ac08372f9..224cf45ebb3 100644
--- a/spec/support/shared_examples/update_invalid_issuable.rb
+++ b/spec/support/shared_examples/controllers/update_invalid_issuable_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'update invalid issuable' do |klass|
+RSpec.shared_examples 'update invalid issuable' do |klass|
let(:params) do
{
namespace_id: project.namespace.path,
diff --git a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
index 11dd8042b45..73087befad2 100644
--- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'handle uploads' do
+RSpec.shared_examples 'handle uploads' do
let(:user) { create(:user) }
let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
@@ -287,7 +287,7 @@ shared_examples 'handle uploads' do
end
end
-shared_examples 'handle uploads authorize' do
+RSpec.shared_examples 'handle uploads authorize' do
describe "POST #authorize" do
context 'when a user is not authorized to upload a file' do
it 'returns 404 status' do
diff --git a/spec/support/shared_examples/controllers/variables_shared_examples.rb b/spec/support/shared_examples/controllers/variables_shared_examples.rb
index 78666e677ef..752bdc47851 100644
--- a/spec/support/shared_examples/controllers/variables_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/variables_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'GET #show lists all variables' do
+RSpec.shared_examples 'GET #show lists all variables' do
it 'renders the variables as json' do
subject
@@ -14,7 +14,7 @@ shared_examples 'GET #show lists all variables' do
end
end
-shared_examples 'PATCH #update updates variables' do
+RSpec.shared_examples 'PATCH #update updates variables' do
let(:variable_attributes) do
{ id: variable.id,
key: variable.key,
diff --git a/spec/support/shared_examples/email_shared_examples.rb b/spec/support/shared_examples/email_shared_examples.rb
deleted file mode 100644
index 634a2504766..00000000000
--- a/spec/support/shared_examples/email_shared_examples.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-shared_examples_for 'correctly finds the mail key' do
- specify do
- expect(Gitlab::Email::Handler).to receive(:for).with(an_instance_of(Mail::Message), 'gitlabhq/gitlabhq+auth_token').and_return(handler)
-
- receiver.execute
- end
-end
diff --git a/spec/support/shared_examples/evidence_updated_exposed_fields.rb b/spec/support/shared_examples/evidence_updated_exposed_fields.rb
deleted file mode 100644
index 2a02fdd7666..00000000000
--- a/spec/support/shared_examples/evidence_updated_exposed_fields.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-shared_examples 'updated exposed field' do
- it 'creates another Evidence object' do
- model.send("#{updated_field}=", updated_value)
-
- expect(model.evidence_summary_keys).to include(updated_field)
- expect { model.save! }.to change(Evidence, :count).by(1)
- expect(updated_json_field).to eq(updated_value)
- end
-end
-
-shared_examples 'updated non-exposed field' do
- it 'does not create any Evidence object' do
- model.send("#{updated_field}=", updated_value)
-
- expect(model.evidence_summary_keys).not_to include(updated_field)
- expect { model.save! }.not_to change(Evidence, :count)
- end
-end
-
-shared_examples 'updated field on non-linked entity' do
- it 'does not create any Evidence object' do
- model.send("#{updated_field}=", updated_value)
-
- expect(model.evidence_summary_keys).to be_empty
- expect { model.save! }.not_to change(Evidence, :count)
- end
-end
diff --git a/spec/support/shared_examples/fast_destroy_all.rb b/spec/support/shared_examples/fast_destroy_all.rb
deleted file mode 100644
index a64259c03f2..00000000000
--- a/spec/support/shared_examples/fast_destroy_all.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-shared_examples_for 'fast destroyable' do
- describe 'Forbid #destroy and #destroy_all' do
- it 'does not delete database rows and associted external data' do
- expect(external_data_counter).to be > 0
- expect(subjects.count).to be > 0
-
- expect { subjects.first.destroy }.to raise_error('`destroy` and `destroy_all` are forbidden. Please use `fast_destroy_all`')
- expect { subjects.destroy_all }.to raise_error('`destroy` and `destroy_all` are forbidden. Please use `fast_destroy_all`') # rubocop: disable DestroyAll
-
- expect(subjects.count).to be > 0
- expect(external_data_counter).to be > 0
- end
- end
-
- describe '.fast_destroy_all' do
- it 'deletes database rows and associted external data' do
- expect(external_data_counter).to be > 0
- expect(subjects.count).to be > 0
-
- expect { subjects.fast_destroy_all }.not_to raise_error
-
- expect(subjects.count).to eq(0)
- expect(external_data_counter).to eq(0)
- end
- end
-
- describe '.use_fast_destroy' do
- it 'performs cascading delete with fast_destroy_all' do
- expect(external_data_counter).to be > 0
- expect(subjects.count).to be > 0
-
- expect { parent.destroy }.not_to raise_error
-
- expect(subjects.count).to eq(0)
- expect(external_data_counter).to eq(0)
- end
- end
-end
diff --git a/spec/support/shared_examples/features/archive_download_buttons_shared_examples.rb b/spec/support/shared_examples/features/archive_download_buttons_shared_examples.rb
index 21c32c9c04a..73acc7a39eb 100644
--- a/spec/support/shared_examples/features/archive_download_buttons_shared_examples.rb
+++ b/spec/support/shared_examples/features/archive_download_buttons_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'archive download buttons' do
+RSpec.shared_examples 'archive download buttons' do
let(:path_to_visit) { project_path(project) }
let(:ref) { project.default_branch }
diff --git a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
index f24e47f4638..fb3b17d05ee 100644
--- a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
+++ b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'comment on merge request file' do
+RSpec.shared_examples 'comment on merge request file' do
it 'adds a comment' do
click_diff_line(find("[id='#{sample_commit.line_code}']"))
diff --git a/spec/support/shared_examples/dirty_submit_form_shared_examples.rb b/spec/support/shared_examples/features/dirty_submit_form_shared_examples.rb
index 60c8899d349..cb81eeba236 100644
--- a/spec/support/shared_examples/dirty_submit_form_shared_examples.rb
+++ b/spec/support/shared_examples/features/dirty_submit_form_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'dirty submit form' do |selector_args|
+RSpec.shared_examples 'dirty submit form' do |selector_args|
selectors = selector_args.is_a?(Array) ? selector_args : [selector_args]
def expect_disabled_state(form, submit_selector, is_disabled = true)
diff --git a/spec/support/shared_examples/features/discussion_comments_shared_example.rb b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
new file mode 100644
index 00000000000..f8d2fdece7d
--- /dev/null
+++ b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
@@ -0,0 +1,314 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'thread comments' do |resource_name|
+ let(:form_selector) { '.js-main-target-form' }
+ let(:dropdown_selector) { "#{form_selector} .comment-type-dropdown" }
+ let(:toggle_selector) { "#{dropdown_selector} .dropdown-toggle" }
+ let(:menu_selector) { "#{dropdown_selector} .dropdown-menu" }
+ let(:submit_selector) { "#{form_selector} .js-comment-submit-button" }
+ let(:close_selector) { "#{form_selector} .btn-comment-and-close" }
+ let(:comments_selector) { '.timeline > .note.timeline-entry' }
+
+ it 'clicking "Comment" will post a comment', :quarantine do
+ expect(page).to have_selector toggle_selector
+
+ find("#{form_selector} .note-textarea").send_keys('a')
+
+ find(submit_selector).click
+
+ wait_for_requests
+
+ find(comments_selector, match: :first)
+ new_comment = all(comments_selector).last
+
+ expect(new_comment).to have_content 'a'
+ expect(new_comment).not_to have_selector '.discussion'
+ end
+
+ if resource_name == 'issue'
+ it "clicking 'Comment & close #{resource_name}' will post a comment and close the #{resource_name}" do
+ find("#{form_selector} .note-textarea").send_keys('a')
+
+ find(close_selector).click
+ wait_for_requests
+
+ find(comments_selector, match: :first)
+ find("#{comments_selector}.system-note")
+ entries = all(comments_selector)
+ close_note = entries.last
+ new_comment = entries[-2]
+
+ expect(close_note).to have_content 'closed'
+ expect(new_comment).not_to have_selector '.discussion'
+ end
+ end
+
+ describe 'when the toggle is clicked' do
+ before do
+ find("#{form_selector} .note-textarea").send_keys('a')
+
+ find(toggle_selector).click
+ end
+
+ it 'has a "Comment" item (selected by default) and "Start thread" item' do
+ expect(page).to have_selector menu_selector
+
+ find("#{menu_selector} li", match: :first)
+ items = all("#{menu_selector} li")
+
+ expect(items.first).to have_content 'Comment'
+ expect(items.first).to have_content "Add a general comment to this #{resource_name}."
+ expect(items.first).to have_selector '.fa-check'
+ expect(items.first['class']).to match 'droplab-item-selected'
+
+ expect(items.last).to have_content 'Start thread'
+ expect(items.last).to have_content "Discuss a specific suggestion or question#{' that needs to be resolved' if resource_name == 'merge request'}."
+ expect(items.last).not_to have_selector '.fa-check'
+ expect(items.last['class']).not_to match 'droplab-item-selected'
+ end
+
+ it 'closes the menu when clicking the toggle or body' do
+ find(toggle_selector).click
+
+ expect(page).not_to have_selector menu_selector
+
+ find(toggle_selector).click
+ find("#{form_selector} .note-textarea").click
+
+ expect(page).not_to have_selector menu_selector
+ end
+
+ it 'clicking the ul padding or divider should not change the text' do
+ execute_script("document.querySelector('#{menu_selector}').click()")
+
+ # on issues page, the menu closes when clicking anywhere, on other pages it will
+ # remain open if clicking divider or menu padding, but should not change button action
+ #
+ # if dropdown menu is not toggled (and also not present),
+ # it's "issue-type" dropdown
+ if first(menu_selector, minimum: 0).nil?
+ expect(find(dropdown_selector)).to have_content 'Comment'
+
+ find(toggle_selector).click
+ execute_script("document.querySelector('#{menu_selector} .divider').click()")
+ else
+ execute_script("document.querySelector('#{menu_selector}').click()")
+
+ expect(page).to have_selector menu_selector
+ expect(find(dropdown_selector)).to have_content 'Comment'
+
+ execute_script("document.querySelector('#{menu_selector} .divider').click()")
+
+ expect(page).to have_selector menu_selector
+ end
+
+ expect(find(dropdown_selector)).to have_content 'Comment'
+ end
+
+ describe 'when selecting "Start thread"' do
+ before do
+ find("#{menu_selector} li", match: :first)
+ all("#{menu_selector} li").last.click
+ end
+
+ it 'updates the submit button text and closes the dropdown' do
+ button = find(submit_selector)
+
+ # on issues page, the submit input is a <button>, on other pages it is <input>
+ if button.tag_name == 'button'
+ expect(find(submit_selector)).to have_content 'Start thread'
+ else
+ expect(find(submit_selector).value).to eq 'Start thread'
+ end
+
+ expect(page).not_to have_selector menu_selector
+ end
+
+ if resource_name =~ /(issue|merge request)/
+ it 'updates the close button text' do
+ expect(find(close_selector)).to have_content "Start thread & close #{resource_name}"
+ end
+
+ it 'typing does not change the close button text' do
+ find("#{form_selector} .note-textarea").send_keys('b')
+
+ expect(find(close_selector)).to have_content "Start thread & close #{resource_name}"
+ end
+ end
+
+ describe 'creating a thread' do
+ before do
+ find(submit_selector).click
+ wait_for_requests
+
+ find(comments_selector, match: :first)
+ end
+
+ def submit_reply(text)
+ find("#{comments_selector} .js-vue-discussion-reply").click
+ find("#{comments_selector} .note-textarea").send_keys(text)
+
+ click_button "Comment"
+ wait_for_requests
+ end
+
+ it 'clicking "Start thread" will post a thread' do
+ new_comment = all(comments_selector).last
+
+ expect(new_comment).to have_content 'a'
+ expect(new_comment).to have_selector '.discussion'
+ end
+
+ if resource_name =~ /(issue|merge request)/
+ it 'can be replied to' do
+ submit_reply('some text')
+
+ expect(page).to have_css('.discussion-notes .note', count: 2)
+ expect(page).to have_content 'Collapse replies'
+ end
+
+ it 'can be collapsed' do
+ submit_reply('another text')
+
+ find('.js-collapse-replies').click
+ expect(page).to have_css('.discussion-notes .note', count: 1)
+ expect(page).to have_content '1 reply'
+ end
+ end
+
+ if resource_name == 'merge request'
+ let(:note_id) { find("#{comments_selector} .note:first-child", match: :first)['data-note-id'] }
+ let(:reply_id) { find("#{comments_selector} .note:last-of-type", match: :first)['data-note-id'] }
+
+ it 'can be replied to after resolving' do
+ click_button "Resolve thread"
+ wait_for_requests
+
+ refresh
+ wait_for_requests
+
+ submit_reply('to reply or not reply')
+ end
+
+ it 'shows resolved thread when toggled' do
+ submit_reply('a')
+
+ click_button "Resolve thread"
+ wait_for_requests
+
+ expect(page).to have_selector(".note-row-#{note_id}", visible: true)
+
+ refresh
+ click_button "1 reply"
+
+ expect(page).to have_selector(".note-row-#{reply_id}", visible: true)
+ end
+ end
+ end
+
+ if resource_name == 'issue'
+ it "clicking 'Start thread & close #{resource_name}' will post a thread and close the #{resource_name}" do
+ find(close_selector).click
+
+ find(comments_selector, match: :first)
+ find("#{comments_selector}.system-note")
+ entries = all(comments_selector)
+ close_note = entries.last
+ new_discussion = entries[-2]
+
+ expect(close_note).to have_content 'closed'
+ expect(new_discussion).to have_selector '.discussion'
+ end
+ end
+
+ describe 'when opening the menu' do
+ before do
+ find(toggle_selector).click
+ end
+
+ it 'has "Start thread" selected' do
+ find("#{menu_selector} li", match: :first)
+ items = all("#{menu_selector} li")
+
+ expect(items.first).to have_content 'Comment'
+ expect(items.first).not_to have_selector '.fa-check'
+ expect(items.first['class']).not_to match 'droplab-item-selected'
+
+ expect(items.last).to have_content 'Start thread'
+ expect(items.last).to have_selector '.fa-check'
+ expect(items.last['class']).to match 'droplab-item-selected'
+ end
+
+ describe 'when selecting "Comment"' do
+ before do
+ find("#{menu_selector} li", match: :first).click
+ end
+
+ it 'updates the submit button text and closes the dropdown' do
+ button = find(submit_selector)
+
+ # on issues page, the submit input is a <button>, on other pages it is <input>
+ if button.tag_name == 'button'
+ expect(button).to have_content 'Comment'
+ else
+ expect(button.value).to eq 'Comment'
+ end
+
+ expect(page).not_to have_selector menu_selector
+ end
+
+ if resource_name =~ /(issue|merge request)/
+ it 'updates the close button text' do
+ expect(find(close_selector)).to have_content "Comment & close #{resource_name}"
+ end
+
+ it 'typing does not change the close button text' do
+ find("#{form_selector} .note-textarea").send_keys('b')
+
+ expect(find(close_selector)).to have_content "Comment & close #{resource_name}"
+ end
+ end
+
+ it 'has "Comment" selected when opening the menu', quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/196825' do
+ find(toggle_selector).click
+
+ find("#{menu_selector} li", match: :first)
+ items = all("#{menu_selector} li")
+
+ expect(items.first).to have_content 'Comment'
+ expect(items.first).to have_selector '.fa-check'
+ expect(items.first['class']).to match 'droplab-item-selected'
+
+ expect(items.last).to have_content 'Start thread'
+ expect(items.last).not_to have_selector '.fa-check'
+ expect(items.last['class']).not_to match 'droplab-item-selected'
+ end
+ end
+ end
+ end
+ end
+
+ if resource_name =~ /(issue|merge request)/
+ describe "on a closed #{resource_name}" do
+ before do
+ find("#{form_selector} .js-note-target-close").click
+ wait_for_requests
+
+ find("#{form_selector} .note-textarea").send_keys('a')
+ end
+
+ it "shows a 'Comment & reopen #{resource_name}' button" do
+ expect(find("#{form_selector} .js-note-target-reopen")).to have_content "Comment & reopen #{resource_name}"
+ end
+
+ it "shows a 'Start thread & reopen #{resource_name}' button when 'Start thread' is selected" do
+ find(toggle_selector).click
+
+ find("#{menu_selector} li", match: :first)
+ all("#{menu_selector} li").last.click
+
+ expect(find("#{form_selector} .js-note-target-reopen")).to have_content "Start thread & reopen #{resource_name}"
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb b/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb
index 09a48533ee3..a112ee568f9 100644
--- a/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb
+++ b/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issue sidebar stays collapsed on mobile' do
+RSpec.shared_examples 'issue sidebar stays collapsed on mobile' do
before do
resize_screen_xs
end
diff --git a/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb b/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb
index 3da80541072..e0d9b828992 100644
--- a/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb
+++ b/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issuable user dropdown behaviors' do
+RSpec.shared_examples 'issuable user dropdown behaviors' do
include FilteredSearchHelpers
before do
diff --git a/spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb b/spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb
index bab7963f06f..19a5750cf6d 100644
--- a/spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb
+++ b/spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'multiple assignees merge request' do |action, save_button_title|
+RSpec.shared_examples 'multiple assignees merge request' do |action, save_button_title|
it "#{action} a MR with multiple assignees", :js do
find('.js-assignee-search').click
page.within '.dropdown-menu-user' do
diff --git a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
index 51559c0b110..d410653ca43 100644
--- a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
+++ b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'project features apply to issuables' do |klass|
+RSpec.shared_examples 'project features apply to issuables' do |klass|
let(:described_class) { klass }
let(:group) { create(:group) }
diff --git a/spec/support/shared_examples/project_list_shared_examples.rb b/spec/support/shared_examples/features/project_list_shared_examples.rb
index 675d489fcab..a15ba27b4ca 100644
--- a/spec/support/shared_examples/project_list_shared_examples.rb
+++ b/spec/support/shared_examples/features/project_list_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'shows public projects' do
+RSpec.shared_examples 'shows public projects' do
it 'shows projects' do
expect(page).to have_content(public_project.title)
expect(page).not_to have_content(internal_project.title)
@@ -9,7 +9,7 @@ shared_examples 'shows public projects' do
end
end
-shared_examples 'shows public and internal projects' do
+RSpec.shared_examples 'shows public and internal projects' do
it 'shows projects' do
expect(page).to have_content(public_project.title)
expect(page).to have_content(internal_project.title)
diff --git a/spec/support/shared_examples/features/protected_branches_access_control_ce.rb b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
index db83d6f0793..65db082505a 100644
--- a/spec/support/shared_examples/features/protected_branches_access_control_ce.rb
+++ b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples "protected branches > access control > CE" do
+RSpec.shared_examples "protected branches > access control > CE" do
ProtectedRefAccess::HUMAN_ACCESS_LEVELS.each do |(access_type_id, access_type_name)|
it "allows creating protected branches that #{access_type_name} can push to" do
visit project_protected_branches_path(project)
diff --git a/spec/support/shared_examples/features/reportable_note_shared_examples.rb b/spec/support/shared_examples/features/reportable_note_shared_examples.rb
new file mode 100644
index 00000000000..bdaa375721f
--- /dev/null
+++ b/spec/support/shared_examples/features/reportable_note_shared_examples.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'reportable note' do |type|
+ include MobileHelpers
+ include NotesHelper
+
+ let(:comment) { find("##{ActionView::RecordIdentifier.dom_id(note)}") }
+ let(:more_actions_selector) { '.more-actions.dropdown' }
+ let(:abuse_report_path) { new_abuse_report_path(user_id: note.author.id, ref_url: noteable_note_url(note)) }
+
+ it 'has an edit button' do
+ expect(comment).to have_selector('.js-note-edit')
+ end
+
+ it 'has a `More actions` dropdown' do
+ expect(comment).to have_selector(more_actions_selector)
+ end
+
+ it 'dropdown has Report and Delete links' do
+ dropdown = comment.find(more_actions_selector)
+ open_dropdown(dropdown)
+
+ expect(dropdown).to have_link('Report abuse to admin', href: abuse_report_path)
+
+ if type == 'issue' || type == 'merge_request'
+ expect(dropdown).to have_button('Delete comment')
+ else
+ expect(dropdown).to have_link('Delete comment', href: note_url(note, project))
+ end
+ end
+
+ it 'Report button links to a report page' do
+ dropdown = comment.find(more_actions_selector)
+ open_dropdown(dropdown)
+
+ dropdown.click_link('Report abuse to admin')
+
+ expect(find('#user_name')['value']).to match(note.author.username)
+ expect(find('#abuse_report_message')['value']).to match(noteable_note_url(note))
+ end
+
+ def open_dropdown(dropdown)
+ # make window wide enough that tooltip doesn't trigger horizontal scrollbar
+ restore_window_size
+
+ dropdown.find('.more-actions-toggle').click
+ dropdown.find('.dropdown-menu li', match: :first)
+ end
+end
diff --git a/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb b/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb
new file mode 100644
index 00000000000..06127f2ed8c
--- /dev/null
+++ b/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'creating an issue for a thread' do
+ it 'shows an issue with the title filled in' do
+ title_field = page.find_field('issue[title]')
+
+ expect(title_field.value).to include(merge_request.title)
+ end
+
+ it 'has a mention of the discussion in the description' do
+ description_field = page.find_field('issue[description]')
+
+ expect(description_field.value).to include(discussion.first_note.note)
+ end
+
+ it 'can create a new issue for the project' do
+ expect { click_button 'Submit issue' }.to change { project.issues.reload.size }.by(1)
+ end
+
+ it 'resolves the discussion in the merge request' do
+ click_button 'Submit issue'
+
+ discussion.first_note.reload
+
+ expect(discussion.resolved?).to eq(true)
+ end
+
+ it 'shows a flash messaage after resolving a discussion' do
+ click_button 'Submit issue'
+
+ page.within '.flash-notice' do
+ # Only check for the word 'Resolved' since the spec might have resolved
+ # multiple discussions
+ expect(page).to have_content('Resolved')
+ end
+ end
+
+ it 'has a hidden field for the merge request' do
+ merge_request_field = find('#merge_request_to_resolve_discussions_of', visible: false)
+
+ expect(merge_request_field.value).to eq(merge_request.iid.to_s)
+ end
+end
diff --git a/spec/support/shared_examples/features/rss_shared_examples.rb b/spec/support/shared_examples/features/rss_shared_examples.rb
new file mode 100644
index 00000000000..42df88ec08e
--- /dev/null
+++ b/spec/support/shared_examples/features/rss_shared_examples.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples "an autodiscoverable RSS feed with current_user's feed token" do
+ it "has an RSS autodiscovery link tag with current_user's feed token" do
+ expect(page).to have_css("link[type*='atom+xml'][href*='feed_token=#{user.feed_token}']", visible: false)
+ end
+end
+
+RSpec.shared_examples "it has an RSS button with current_user's feed token" do
+ it "shows the RSS button with current_user's feed token" do
+ expect(page)
+ .to have_css("a:has(.fa-rss)[href*='feed_token=#{user.feed_token}']")
+ .or have_css("a.js-rss-button[href*='feed_token=#{user.feed_token}']")
+ end
+end
+
+RSpec.shared_examples "an autodiscoverable RSS feed without a feed token" do
+ it "has an RSS autodiscovery link tag without a feed token" do
+ expect(page).to have_css("link[type*='atom+xml']:not([href*='feed_token'])", visible: false)
+ end
+end
+
+RSpec.shared_examples "it has an RSS button without a feed token" do
+ it "shows the RSS button without a feed token" do
+ expect(page)
+ .to have_css("a:has(.fa-rss):not([href*='feed_token'])")
+ .or have_css("a.js-rss-button:not([href*='feed_token'])")
+ end
+end
diff --git a/spec/support/shared_examples/features/search_shared_examples.rb b/spec/support/shared_examples/features/search_shared_examples.rb
index e27d6700cbf..c043b011e66 100644
--- a/spec/support/shared_examples/features/search_shared_examples.rb
+++ b/spec/support/shared_examples/features/search_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'top right search form' do
+RSpec.shared_examples 'top right search form' do
it 'does not show top right search form' do
expect(page).not_to have_selector('.search')
end
diff --git a/spec/support/shared_examples/showing_user_status_shared_examples.rb b/spec/support/shared_examples/features/showing_user_status_shared_examples.rb
index eef769de2fc..7906fc1f399 100644
--- a/spec/support/shared_examples/showing_user_status_shared_examples.rb
+++ b/spec/support/shared_examples/features/showing_user_status_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'showing user status' do
+RSpec.shared_examples 'showing user status' do
let!(:status) { create(:user_status, user: user_with_status, emoji: 'smirk', message: 'Authoring this object') }
it 'shows the status' do
diff --git a/spec/support/shared_examples/snippets_shared_examples.rb b/spec/support/shared_examples/features/snippets_shared_examples.rb
index 5c35617bd36..5c35617bd36 100644
--- a/spec/support/shared_examples/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/features/snippets_shared_examples.rb
diff --git a/spec/support/shared_examples/features/variable_list_shared_examples.rb b/spec/support/shared_examples/features/variable_list_shared_examples.rb
new file mode 100644
index 00000000000..4fd4d42003f
--- /dev/null
+++ b/spec/support/shared_examples/features/variable_list_shared_examples.rb
@@ -0,0 +1,388 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'variable list' do
+ it 'shows list of variables' do
+ page.within('.js-ci-variable-list-section') do
+ expect(first('.js-ci-variable-input-key').value).to eq(variable.key)
+ end
+ end
+
+ it 'adds new CI variable' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('key')
+ find('.js-ci-variable-input-value').set('key_value')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ # We check the first row because it re-sorts to alphabetical order on refresh
+ page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
+ expect(find('.js-ci-variable-input-key').value).to eq('key')
+ expect(find('.js-ci-variable-input-value', visible: false).value).to eq('key_value')
+ end
+ end
+
+ it 'adds a new protected variable' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('key')
+ find('.js-ci-variable-input-value').set('key_value')
+ find('.ci-variable-protected-item .js-project-feature-toggle').click
+
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ # We check the first row because it re-sorts to alphabetical order on refresh
+ page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
+ expect(find('.js-ci-variable-input-key').value).to eq('key')
+ expect(find('.js-ci-variable-input-value', visible: false).value).to eq('key_value')
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
+ end
+ end
+
+ it 'defaults to unmasked' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('key')
+ find('.js-ci-variable-input-value').set('key_value')
+
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('false')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ # We check the first row because it re-sorts to alphabetical order on refresh
+ page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
+ expect(find('.js-ci-variable-input-key').value).to eq('key')
+ expect(find('.js-ci-variable-input-value', visible: false).value).to eq('key_value')
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('false')
+ end
+ end
+
+ context 'defaults to the application setting' do
+ context 'application setting is true' do
+ before do
+ stub_application_setting(protected_ci_variables: true)
+
+ visit page_path
+ end
+
+ it 'defaults to protected' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('key')
+ end
+
+ values = all('.js-ci-variable-input-protected', visible: false).map(&:value)
+
+ expect(values).to eq %w(false true true)
+ end
+
+ it 'shows a message regarding the changed default' do
+ expect(page).to have_content 'Environment variables are configured by your administrator to be protected by default'
+ end
+ end
+
+ context 'application setting is false' do
+ before do
+ stub_application_setting(protected_ci_variables: false)
+
+ visit page_path
+ end
+
+ it 'defaults to unprotected' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('key')
+ end
+
+ values = all('.js-ci-variable-input-protected', visible: false).map(&:value)
+
+ expect(values).to eq %w(false false false)
+ end
+
+ it 'does not show a message regarding the default' do
+ expect(page).not_to have_content 'Environment variables are configured by your administrator to be protected by default'
+ end
+ end
+ end
+
+ it 'reveals and hides variables' do
+ page.within('.js-ci-variable-list-section') do
+ expect(first('.js-ci-variable-input-key').value).to eq(variable.key)
+ expect(first('.js-ci-variable-input-value', visible: false).value).to eq(variable.value)
+ expect(page).to have_content('*' * 17)
+
+ click_button('Reveal value')
+
+ expect(first('.js-ci-variable-input-key').value).to eq(variable.key)
+ expect(first('.js-ci-variable-input-value').value).to eq(variable.value)
+ expect(page).not_to have_content('*' * 17)
+
+ click_button('Hide value')
+
+ expect(first('.js-ci-variable-input-key').value).to eq(variable.key)
+ expect(first('.js-ci-variable-input-value', visible: false).value).to eq(variable.value)
+ expect(page).to have_content('*' * 17)
+ end
+ end
+
+ it 'deletes variable' do
+ page.within('.js-ci-variable-list-section') do
+ expect(page).to have_selector('.js-row', count: 2)
+
+ first('.js-row-remove-button').click
+
+ click_button('Save variables')
+ wait_for_requests
+
+ expect(page).to have_selector('.js-row', count: 1)
+ end
+ end
+
+ it 'edits variable' do
+ page.within('.js-ci-variable-list-section') do
+ click_button('Reveal value')
+
+ page.within('.js-row:nth-child(2)') do
+ find('.js-ci-variable-input-key').set('new_key')
+ find('.js-ci-variable-input-value').set('new_value')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ page.within('.js-row:nth-child(2)') do
+ expect(find('.js-ci-variable-input-key').value).to eq('new_key')
+ expect(find('.js-ci-variable-input-value', visible: false).value).to eq('new_value')
+ end
+ end
+ end
+
+ it 'edits variable to be protected' do
+ # Create the unprotected variable
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('unprotected_key')
+ find('.js-ci-variable-input-value').set('unprotected_value')
+
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('false')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ # We check the first row because it re-sorts to alphabetical order on refresh
+ page.within('.js-ci-variable-list-section .js-row:nth-child(3)') do
+ find('.ci-variable-protected-item .js-project-feature-toggle').click
+
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ # We check the first row because it re-sorts to alphabetical order on refresh
+ page.within('.js-ci-variable-list-section .js-row:nth-child(3)') do
+ expect(find('.js-ci-variable-input-key').value).to eq('unprotected_key')
+ expect(find('.js-ci-variable-input-value', visible: false).value).to eq('unprotected_value')
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
+ end
+ end
+
+ it 'edits variable to be unprotected' do
+ # Create the protected variable
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('protected_key')
+ find('.js-ci-variable-input-value').set('protected_value')
+ find('.ci-variable-protected-item .js-project-feature-toggle').click
+
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
+ find('.ci-variable-protected-item .js-project-feature-toggle').click
+
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('false')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
+ expect(find('.js-ci-variable-input-key').value).to eq('protected_key')
+ expect(find('.js-ci-variable-input-value', visible: false).value).to eq('protected_value')
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('false')
+ end
+ end
+
+ it 'edits variable to be unmasked' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('unmasked_key')
+ find('.js-ci-variable-input-value').set('unmasked_value')
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('false')
+
+ find('.ci-variable-masked-item .js-project-feature-toggle').click
+
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('true')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('true')
+
+ find('.ci-variable-masked-item .js-project-feature-toggle').click
+
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('false')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('false')
+ end
+ end
+
+ it 'edits variable to be masked' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('masked_key')
+ find('.js-ci-variable-input-value').set('masked_value')
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('false')
+
+ find('.ci-variable-masked-item .js-project-feature-toggle').click
+
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('true')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
+ expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('true')
+ end
+ end
+
+ it 'handles multiple edits and deletion in the middle' do
+ page.within('.js-ci-variable-list-section') do
+ # Create 2 variables
+ page.within('.js-row:last-child') do
+ find('.js-ci-variable-input-key').set('akey')
+ find('.js-ci-variable-input-value').set('akeyvalue')
+ end
+ page.within('.js-row:last-child') do
+ find('.js-ci-variable-input-key').set('zkey')
+ find('.js-ci-variable-input-value').set('zkeyvalue')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ expect(page).to have_selector('.js-row', count: 4)
+
+ # Remove the `akey` variable
+ page.within('.js-row:nth-child(3)') do
+ first('.js-row-remove-button').click
+ end
+
+ # Add another variable
+ page.within('.js-row:last-child') do
+ find('.js-ci-variable-input-key').set('ckey')
+ find('.js-ci-variable-input-value').set('ckeyvalue')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ # Expect to find 3 variables(4 rows) in alphbetical order
+ expect(page).to have_selector('.js-row', count: 4)
+ row_keys = all('.js-ci-variable-input-key')
+ expect(row_keys[0].value).to eq('ckey')
+ expect(row_keys[1].value).to eq('test_key')
+ expect(row_keys[2].value).to eq('zkey')
+ expect(row_keys[3].value).to eq('')
+ end
+ end
+
+ it 'shows validation error box about duplicate keys' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('samekey')
+ find('.js-ci-variable-input-value').set('value123')
+ end
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('samekey')
+ find('.js-ci-variable-input-value').set('value456')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ expect(all('.js-ci-variable-list-section .js-ci-variable-error-box ul li').count).to eq(1)
+
+ # We check the first row because it re-sorts to alphabetical order on refresh
+ page.within('.js-ci-variable-list-section') do
+ expect(find('.js-ci-variable-error-box')).to have_content(/Validation failed Variables have duplicate values \(.+\)/)
+ end
+ end
+
+ it 'shows validation error box about masking empty values' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('empty_value')
+ find('.js-ci-variable-input-value').set('')
+ find('.ci-variable-masked-item .js-project-feature-toggle').click
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ page.within('.js-ci-variable-list-section') do
+ expect(all('.js-ci-variable-error-box ul li').count).to eq(1)
+ expect(find('.js-ci-variable-error-box')).to have_content(/Validation failed Variables value is invalid/)
+ end
+ end
+
+ it 'shows validation error box about unmaskable values' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('unmaskable_value')
+ find('.js-ci-variable-input-value').set('???')
+ find('.ci-variable-masked-item .js-project-feature-toggle').click
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ page.within('.js-ci-variable-list-section') do
+ expect(all('.js-ci-variable-error-box ul li').count).to eq(1)
+ expect(find('.js-ci-variable-error-box')).to have_content(/Validation failed Variables value is invalid/)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/wiki_file_attachments_examples.rb b/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb
index 22fbfb48928..36d91d323b5 100644
--- a/spec/support/shared_examples/wiki_file_attachments_examples.rb
+++ b/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb
@@ -3,7 +3,7 @@
# Requires a context containing:
# project
-shared_examples 'wiki file attachments' do
+RSpec.shared_examples 'wiki file attachments' do
include DropzoneHelper
context 'uploading attachments', :js do
diff --git a/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb b/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb
index f1df1052ef2..96b05db4cd9 100644
--- a/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb
+++ b/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb
@@ -1,30 +1,30 @@
# frozen_string_literal: true
-shared_examples 'assignee ID filter' do
+RSpec.shared_examples 'assignee ID filter' do
it 'returns issuables assigned to that user' do
expect(issuables).to contain_exactly(*expected_issuables)
end
end
-shared_examples 'assignee NOT ID filter' do
+RSpec.shared_examples 'assignee NOT ID filter' do
it 'returns issuables not assigned to that user' do
expect(issuables).to contain_exactly(*expected_issuables)
end
end
-shared_examples 'assignee username filter' do
+RSpec.shared_examples 'assignee username filter' do
it 'returns issuables assigned to those users' do
expect(issuables).to contain_exactly(*expected_issuables)
end
end
-shared_examples 'assignee NOT username filter' do
+RSpec.shared_examples 'assignee NOT username filter' do
it 'returns issuables not assigned to those users' do
expect(issuables).to contain_exactly(*expected_issuables)
end
end
-shared_examples 'no assignee filter' do
+RSpec.shared_examples 'no assignee filter' do
let(:params) { { assignee_id: 'None' } }
it 'returns issuables not assigned to any assignee' do
@@ -38,7 +38,7 @@ shared_examples 'no assignee filter' do
end
end
-shared_examples 'any assignee filter' do
+RSpec.shared_examples 'any assignee filter' do
context '' do
let(:params) { { assignee_id: 'Any' } }
diff --git a/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb b/spec/support/shared_examples/finders/finder_with_external_authorization_enabled_shared_examples.rb
index b8b0079e36d..2671462ea4a 100644
--- a/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb
+++ b/spec/support/shared_examples/finders/finder_with_external_authorization_enabled_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples 'a finder with external authorization service' do
+RSpec.shared_examples 'a finder with external authorization service' do
include ExternalAuthorizationServiceHelpers
let(:user) { create(:user) }
diff --git a/spec/support/shared_examples/snippet_visibility_shared_examples.rb b/spec/support/shared_examples/finders/snippet_visibility_shared_examples.rb
index e2089ee623a..e2089ee623a 100644
--- a/spec/support/shared_examples/snippet_visibility_shared_examples.rb
+++ b/spec/support/shared_examples/finders/snippet_visibility_shared_examples.rb
diff --git a/spec/support/shared_examples/graphql/connection_paged_nodes.rb b/spec/support/shared_examples/graphql/connection_paged_nodes_shared_examples.rb
index 93de7f619f7..93de7f619f7 100644
--- a/spec/support/shared_examples/graphql/connection_paged_nodes.rb
+++ b/spec/support/shared_examples/graphql/connection_paged_nodes_shared_examples.rb
diff --git a/spec/support/shared_examples/graphql/failure_to_find_anything.rb b/spec/support/shared_examples/graphql/failure_to_find_anything_shared_examples.rb
index b2533c992c1..d27fdb1aa30 100644
--- a/spec/support/shared_examples/graphql/failure_to_find_anything.rb
+++ b/spec/support/shared_examples/graphql/failure_to_find_anything_shared_examples.rb
@@ -1,12 +1,10 @@
# frozen_string_literal: true
-require 'spec_helper'
-
# Shared example for legal queries that are expected to return nil.
# Requires the following let bindings to be defined:
# - post_query: action to send the query
# - path: array of keys from query root to the result
-shared_examples 'a failure to find anything' do
+RSpec.shared_examples 'a failure to find anything' do
it 'finds nothing' do
post_query
diff --git a/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb b/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb
index 9a60825855f..e1dd98814f1 100644
--- a/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-shared_context 'exposing regular notes on a noteable in GraphQL' do
+RSpec.shared_context 'exposing regular notes on a noteable in GraphQL' do
include GraphqlHelpers
let(:note) do
diff --git a/spec/support/shared_examples/uses_gitlab_url_blocker_examples.rb b/spec/support/shared_examples/initializers/uses_gitlab_url_blocker_shared_examples.rb
index 59c119e6d96..afa495fc9a4 100644
--- a/spec/support/shared_examples/uses_gitlab_url_blocker_examples.rb
+++ b/spec/support/shared_examples/initializers/uses_gitlab_url_blocker_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'a request using Gitlab::UrlBlocker' do
+RSpec.shared_examples 'a request using Gitlab::UrlBlocker' do
# Written to test internal patches against 3rd party libraries
#
# Expects the following to be available in the example contexts:
diff --git a/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb b/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb
deleted file mode 100644
index 22e5698825d..00000000000
--- a/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-shared_examples 'redirecting a legacy path' do |source, target|
- include RSpec::Rails::RequestExampleGroup
-
- it "redirects #{source} to #{target} when the resource does not exist" do
- expect(get(source)).to redirect_to(target)
- end
-
- it "does not redirect #{source} to #{target} when the resource exists" do
- resource
-
- expect(get(source)).not_to redirect_to(target)
- end
-end
-
-shared_examples 'redirecting a legacy project path' do |source, target|
- include RSpec::Rails::RequestExampleGroup
-
- it "redirects #{source} to #{target}" do
- expect(get(source)).to redirect_to(target)
- end
-end
diff --git a/spec/support/shared_examples/reference_parser_shared_examples.rb b/spec/support/shared_examples/lib/banzai/reference_parser_shared_examples.rb
index d903c0f10e0..d903c0f10e0 100644
--- a/spec/support/shared_examples/reference_parser_shared_examples.rb
+++ b/spec/support/shared_examples/lib/banzai/reference_parser_shared_examples.rb
diff --git a/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb b/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_shared_examples.rb
index 2cbc0c2bdf2..459d4f5cd3e 100644
--- a/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'backfill migration for project repositories' do |storage|
+RSpec.shared_examples 'backfill migration for project repositories' do |storage|
describe '#perform' do
let(:storage_versions) { storage == :legacy ? [nil, 0] : [1, 2] }
let(:storage_version) { storage_versions.first }
diff --git a/spec/support/shared_examples/ci_trace_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
index 441d3f4ccb9..db5e9461f3f 100644
--- a/spec/support/shared_examples/ci_trace_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'common trace features' do
+RSpec.shared_examples 'common trace features' do
describe '#html' do
before do
trace.set("12\n34")
@@ -284,7 +284,7 @@ shared_examples_for 'common trace features' do
end
end
-shared_examples_for 'trace with disabled live trace feature' do
+RSpec.shared_examples 'trace with disabled live trace feature' do
it_behaves_like 'common trace features'
describe '#read' do
@@ -618,7 +618,7 @@ shared_examples_for 'trace with disabled live trace feature' do
end
end
-shared_examples_for 'trace with enabled live trace feature' do
+RSpec.shared_examples 'trace with enabled live trace feature' do
it_behaves_like 'common trace features'
describe '#read' do
diff --git a/spec/support/shared_examples/cycle_analytics_event_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/cycle_analytics_event_shared_examples.rb
index 028b8da94a6..a00359ce979 100644
--- a/spec/support/shared_examples/cycle_analytics_event_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/cycle_analytics_event_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'cycle analytics event' do
+RSpec.shared_examples_for 'cycle analytics event' do
let(:params) { {} }
let(:instance) { described_class.new(params) }
diff --git a/spec/support/shared_examples/diff_file_collections.rb b/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb
index c8bd137bf84..a1cdd054f32 100644
--- a/spec/support/shared_examples/diff_file_collections.rb
+++ b/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'diff statistics' do |test_include_stats_flag: true|
+RSpec.shared_examples 'diff statistics' do |test_include_stats_flag: true|
subject { described_class.new(diffable, collection_default_args) }
def stub_stats_find_by_path(path, stats_mock)
@@ -42,7 +42,7 @@ shared_examples 'diff statistics' do |test_include_stats_flag: true|
end
end
-shared_examples 'unfoldable diff' do
+RSpec.shared_examples 'unfoldable diff' do
let(:subject) { described_class.new(diffable, diff_options: nil) }
it 'calls Gitlab::Diff::File#unfold_diff_lines with correct position' do
@@ -58,7 +58,7 @@ shared_examples 'unfoldable diff' do
end
end
-shared_examples 'cacheable diff collection' do
+RSpec.shared_examples 'cacheable diff collection' do
let(:cache) { instance_double(Gitlab::Diff::HighlightCache) }
before do
diff --git a/spec/support/shared_examples/file_finder.rb b/spec/support/shared_examples/lib/gitlab/file_finder_shared_examples.rb
index f4b28b94090..dce927c875e 100644
--- a/spec/support/shared_examples/file_finder.rb
+++ b/spec/support/shared_examples/lib/gitlab/file_finder_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'file finder' do
+RSpec.shared_examples 'file finder' do
let(:query) { 'files' }
let(:search_results) { subject.find(query) }
diff --git a/spec/support/shared_examples/gitlab_verify.rb b/spec/support/shared_examples/lib/gitlab/gitlab_verify_shared_examples.rb
index 721ea3b4c88..721ea3b4c88 100644
--- a/spec/support/shared_examples/gitlab_verify.rb
+++ b/spec/support/shared_examples/lib/gitlab/gitlab_verify_shared_examples.rb
diff --git a/spec/support/shared_examples/helm_generated_script.rb b/spec/support/shared_examples/lib/gitlab/helm_generated_script_shared_examples.rb
index 17f495ebe46..bbf8a946f8b 100644
--- a/spec/support/shared_examples/helm_generated_script.rb
+++ b/spec/support/shared_examples/lib/gitlab/helm_generated_script_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'helm commands' do
+RSpec.shared_examples 'helm commands' do
describe '#generate_script' do
let(:helm_setup) do
<<~EOS
diff --git a/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb
index 691564120cc..55bd2401db1 100644
--- a/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'log import failure' do |importable_column|
+RSpec.shared_examples 'log import failure' do |importable_column|
it 'tracks error' do
extra = {
relation_key: relation_key,
diff --git a/spec/support/shared_examples/ldap_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/ldap_shared_examples.rb
index 0a70ce7ea0c..cacefc63139 100644
--- a/spec/support/shared_examples/ldap_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/ldap_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'normalizes a DN' do
+RSpec.shared_examples 'normalizes a DN' do
using RSpec::Parameterized::TableSyntax
where(:test_description, :given, :expected) do
@@ -40,7 +40,7 @@ shared_examples_for 'normalizes a DN' do
end
end
-shared_examples_for 'normalizes a DN attribute value' do
+RSpec.shared_examples 'normalizes a DN attribute value' do
using RSpec::Parameterized::TableSyntax
where(:test_description, :given, :expected) do
diff --git a/spec/support/shared_examples/malicious_regexp_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/malicious_regexp_shared_examples.rb
index 96c02260d53..b124c91c0da 100644
--- a/spec/support/shared_examples/malicious_regexp_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/malicious_regexp_shared_examples.rb
@@ -2,7 +2,7 @@
require 'timeout'
-shared_examples 'malicious regexp' do
+RSpec.shared_examples 'malicious regexp' do
let(:malicious_text) { 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!' }
let(:malicious_regexp_re2) { '(?i)^(([a-z])+.)+[A-Z]([a-z])+$' }
let(:malicious_regexp_ruby) { '/^(([a-z])+.)+[A-Z]([a-z])+$/i' }
diff --git a/spec/support/shared_examples/migration_helpers_examples.rb b/spec/support/shared_examples/lib/gitlab/migration_helpers_shared_examples.rb
index 3587297a2d7..8893ed5504b 100644
--- a/spec/support/shared_examples/migration_helpers_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/migration_helpers_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'skips validation' do |validation_option|
+RSpec.shared_examples 'skips validation' do |validation_option|
it 'skips validation' do
expect(model).not_to receive(:disable_statement_timeout)
expect(model).to receive(:execute).with(/ADD CONSTRAINT/)
@@ -10,7 +10,7 @@ shared_examples 'skips validation' do |validation_option|
end
end
-shared_examples 'performs validation' do |validation_option|
+RSpec.shared_examples 'performs validation' do |validation_option|
it 'performs validation' do
expect(model).to receive(:disable_statement_timeout).and_call_original
expect(model).to receive(:execute).with(/statement_timeout/)
diff --git a/spec/support/shared_examples/position_formatters.rb b/spec/support/shared_examples/lib/gitlab/position_formatters_shared_examples.rb
index 30b6b8d24f0..c9300aff3e6 100644
--- a/spec/support/shared_examples/position_formatters.rb
+++ b/spec/support/shared_examples/lib/gitlab/position_formatters_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for "position formatter" do
+RSpec.shared_examples "position formatter" do
let(:formatter) { described_class.new(attrs) }
describe '#key' do
diff --git a/spec/support/shared_examples/repo_type_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
index e4f277650e5..f4960b9f134 100644
--- a/spec/support/shared_examples/repo_type_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'a repo type' do
+RSpec.shared_examples 'a repo type' do
describe "#identifier_for_repositorable" do
subject { described_class.identifier_for_repositorable(project) }
diff --git a/spec/support/shared_examples/unique_ip_check_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/unique_ip_check_shared_examples.rb
index 17777f2cc93..e42a927b5ba 100644
--- a/spec/support/shared_examples/unique_ip_check_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/unique_ip_check_shared_examples.rb
@@ -1,44 +1,6 @@
# frozen_string_literal: true
-shared_context 'unique ips sign in limit' do
- include StubENV
- let(:request_context) { Gitlab::RequestContext.instance }
-
- before do
- Gitlab::Redis::Cache.with(&:flushall)
- Gitlab::Redis::Queues.with(&:flushall)
- Gitlab::Redis::SharedState.with(&:flushall)
- end
-
- before do
- stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
-
- Gitlab::CurrentSettings.update!(
- unique_ips_limit_enabled: true,
- unique_ips_limit_time_window: 10000
- )
-
- # Make sure we're working with the same reqeust context everywhere
- allow(Gitlab::RequestContext).to receive(:instance).and_return(request_context)
- end
-
- def change_ip(ip)
- allow(request_context).to receive(:client_ip).and_return(ip)
- end
-
- def request_from_ip(ip)
- change_ip(ip)
- request
- response
- end
-
- def operation_from_ip(ip)
- change_ip(ip)
- operation
- end
-end
-
-shared_examples 'user login operation with unique ip limit' do
+RSpec.shared_examples 'user login operation with unique ip limit' do
include_context 'unique ips sign in limit' do
before do
Gitlab::CurrentSettings.update!(unique_ips_limit_per_user: 1)
@@ -56,7 +18,7 @@ shared_examples 'user login operation with unique ip limit' do
end
end
-shared_examples 'user login request with unique ip limit' do |success_status = 200|
+RSpec.shared_examples 'user login request with unique ip limit' do |success_status = 200|
include_context 'unique ips sign in limit' do
before do
Gitlab::CurrentSettings.update!(unique_ips_limit_per_user: 1)
diff --git a/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb b/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter_shared_examples.rb
index 91bf804978d..921afbc3e5e 100644
--- a/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb
+++ b/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'a redis usage counter' do |thing, event|
+RSpec.shared_examples 'a redis usage counter' do |thing, event|
describe ".count(#{event})", :clean_gitlab_redis_shared_state do
it "increments the #{thing} #{event} counter by 1" do
expect do
@@ -22,7 +22,7 @@ shared_examples 'a redis usage counter' do |thing, event|
end
end
-shared_examples 'a redis usage counter with totals' do |prefix, events|
+RSpec.shared_examples 'a redis usage counter with totals' do |prefix, events|
describe 'totals', :clean_gitlab_redis_shared_state do
before do
events.each do |k, n|
diff --git a/spec/support/shared_examples/mail_room_shared_examples.rb b/spec/support/shared_examples/mail_room_shared_examples.rb
deleted file mode 100644
index 4cca29250e2..00000000000
--- a/spec/support/shared_examples/mail_room_shared_examples.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-shared_examples_for 'only truthy if both enabled and address are truthy' do |target_proc|
- context 'with both enabled and address as truthy values' do
- it 'is truthy' do
- stub_config(enabled: true, address: 'localhost')
-
- expect(target_proc.call).to be_truthy
- end
- end
-
- context 'with address only as truthy' do
- it 'is falsey' do
- stub_config(enabled: false, address: 'localhost')
-
- expect(target_proc.call).to be_falsey
- end
- end
-
- context 'with enabled only as truthy' do
- it 'is falsey' do
- stub_config(enabled: true, address: nil)
-
- expect(target_proc.call).to be_falsey
- end
- end
-
- context 'with neither address nor enabled as truthy' do
- it 'is falsey' do
- stub_config(enabled: false, address: nil)
-
- expect(target_proc.call).to be_falsey
- end
- end
-end
diff --git a/spec/support/shared_examples/notify_shared_examples.rb b/spec/support/shared_examples/mailers/notify_shared_examples.rb
index ca031df000e..45987059123 100644
--- a/spec/support/shared_examples/notify_shared_examples.rb
+++ b/spec/support/shared_examples/mailers/notify_shared_examples.rb
@@ -1,36 +1,12 @@
# frozen_string_literal: true
-shared_context 'gitlab email notification' do
- set(:group) { create(:group) }
- set(:subgroup) { create(:group, parent: group) }
- set(:project) { create(:project, :repository, name: 'a-known-name', group: group) }
- set(:recipient) { create(:user, email: 'recipient@example.com') }
-
- let(:gitlab_sender_display_name) { Gitlab.config.gitlab.email_display_name }
- let(:gitlab_sender) { Gitlab.config.gitlab.email_from }
- let(:gitlab_sender_reply_to) { Gitlab.config.gitlab.email_reply_to }
- let(:new_user_address) { 'newguy@example.com' }
-
- before do
- email = recipient.emails.create(email: "notifications@example.com")
- recipient.update_attribute(:notification_email, email.email)
- stub_incoming_email_setting(enabled: true, address: "reply+%{key}@#{Gitlab.config.gitlab.host}")
- end
-end
-
-shared_context 'reply-by-email is enabled with incoming address without %{key}' do
- before do
- stub_incoming_email_setting(enabled: true, address: "reply@#{Gitlab.config.gitlab.host}")
- end
-end
-
-shared_examples 'a multiple recipients email' do
+RSpec.shared_examples 'a multiple recipients email' do
it 'is sent to the given recipient' do
is_expected.to deliver_to recipient.notification_email
end
end
-shared_examples 'an email sent from GitLab' do
+RSpec.shared_examples 'an email sent from GitLab' do
it 'has the characteristics of an email sent from GitLab' do
sender = subject.header[:from].addrs[0]
reply_to = subject.header[:reply_to].addresses
@@ -43,7 +19,7 @@ shared_examples 'an email sent from GitLab' do
end
end
-shared_examples 'an email sent to a user' do
+RSpec.shared_examples 'an email sent to a user' do
it 'is sent to user\'s global notification email address' do
expect(subject).to deliver_to(recipient.notification_email)
end
@@ -59,13 +35,13 @@ shared_examples 'an email sent to a user' do
end
end
-shared_examples 'an email that contains a header with author username' do
+RSpec.shared_examples 'an email that contains a header with author username' do
it 'has X-GitLab-Author header containing author\'s username' do
is_expected.to have_header 'X-GitLab-Author', user.username
end
end
-shared_examples 'an email with X-GitLab headers containing IDs' do
+RSpec.shared_examples 'an email with X-GitLab headers containing IDs' do
it 'has X-GitLab-*-ID header' do
is_expected.to have_header "X-GitLab-#{model.class.name}-ID", "#{model.id}"
end
@@ -79,7 +55,7 @@ shared_examples 'an email with X-GitLab headers containing IDs' do
end
end
-shared_examples 'an email with X-GitLab headers containing project details' do
+RSpec.shared_examples 'an email with X-GitLab headers containing project details' do
it 'has X-GitLab-Project headers' do
aggregate_failures do
full_path_as_domain = "#{project.name}.#{project.namespace.path}"
@@ -91,7 +67,7 @@ shared_examples 'an email with X-GitLab headers containing project details' do
end
end
-shared_examples 'a new thread email with reply-by-email enabled' do
+RSpec.shared_examples 'a new thread email with reply-by-email enabled' do
it 'has the characteristics of a threaded email' do
host = Gitlab.config.gitlab.host
route_key = "#{model.class.model_name.singular_route_key}_#{model.id}"
@@ -103,7 +79,7 @@ shared_examples 'a new thread email with reply-by-email enabled' do
end
end
-shared_examples 'a thread answer email with reply-by-email enabled' do
+RSpec.shared_examples 'a thread answer email with reply-by-email enabled' do
include_examples 'an email with X-GitLab headers containing project details'
include_examples 'an email with X-GitLab headers containing IDs'
@@ -120,7 +96,7 @@ shared_examples 'a thread answer email with reply-by-email enabled' do
end
end
-shared_examples 'an email starting a new thread with reply-by-email enabled' do
+RSpec.shared_examples 'an email starting a new thread with reply-by-email enabled' do
include_examples 'an email with X-GitLab headers containing project details'
include_examples 'an email with X-GitLab headers containing IDs'
include_examples 'a new thread email with reply-by-email enabled'
@@ -145,7 +121,7 @@ shared_examples 'an email starting a new thread with reply-by-email enabled' do
end
end
-shared_examples 'an answer to an existing thread with reply-by-email enabled' do
+RSpec.shared_examples 'an answer to an existing thread with reply-by-email enabled' do
include_examples 'an email with X-GitLab headers containing project details'
include_examples 'an email with X-GitLab headers containing IDs'
include_examples 'a thread answer email with reply-by-email enabled'
@@ -166,7 +142,7 @@ shared_examples 'an answer to an existing thread with reply-by-email enabled' do
end
end
-shared_examples 'it should have Gmail Actions links' do
+RSpec.shared_examples 'it should have Gmail Actions links' do
it do
aggregate_failures do
is_expected.to have_body_text('<script type="application/ld+json">')
@@ -175,7 +151,7 @@ shared_examples 'it should have Gmail Actions links' do
end
end
-shared_examples 'it should not have Gmail Actions links' do
+RSpec.shared_examples 'it should not have Gmail Actions links' do
it do
aggregate_failures do
is_expected.not_to have_body_text('<script type="application/ld+json">')
@@ -184,25 +160,25 @@ shared_examples 'it should not have Gmail Actions links' do
end
end
-shared_examples 'it should show Gmail Actions View Issue link' do
+RSpec.shared_examples 'it should show Gmail Actions View Issue link' do
it_behaves_like 'it should have Gmail Actions links'
it { is_expected.to have_body_text('View Issue') }
end
-shared_examples 'it should show Gmail Actions View Merge request link' do
+RSpec.shared_examples 'it should show Gmail Actions View Merge request link' do
it_behaves_like 'it should have Gmail Actions links'
it { is_expected.to have_body_text('View Merge request') }
end
-shared_examples 'it should show Gmail Actions View Commit link' do
+RSpec.shared_examples 'it should show Gmail Actions View Commit link' do
it_behaves_like 'it should have Gmail Actions links'
it { is_expected.to have_body_text('View Commit') }
end
-shared_examples 'an unsubscribeable thread' do
+RSpec.shared_examples 'an unsubscribeable thread' do
it_behaves_like 'an unsubscribeable thread with incoming address without %{key}'
it 'has a List-Unsubscribe header in the correct format, and a body link' do
@@ -215,7 +191,7 @@ shared_examples 'an unsubscribeable thread' do
end
end
-shared_examples 'an unsubscribeable thread with incoming address without %{key}' do
+RSpec.shared_examples 'an unsubscribeable thread with incoming address without %{key}' do
include_context 'reply-by-email is enabled with incoming address without %{key}'
it 'has a List-Unsubscribe header in the correct format, and a body link' do
@@ -228,7 +204,7 @@ shared_examples 'an unsubscribeable thread with incoming address without %{key}'
end
end
-shared_examples 'a user cannot unsubscribe through footer link' do
+RSpec.shared_examples 'a user cannot unsubscribe through footer link' do
it 'does not have a List-Unsubscribe header or a body link' do
aggregate_failures do
is_expected.not_to have_header('List-Unsubscribe', /unsubscribe/)
@@ -237,11 +213,11 @@ shared_examples 'a user cannot unsubscribe through footer link' do
end
end
-shared_examples 'an email with a labels subscriptions link in its footer' do
+RSpec.shared_examples 'an email with a labels subscriptions link in its footer' do
it { is_expected.to have_body_text('label subscriptions') }
end
-shared_examples 'a note email' do
+RSpec.shared_examples 'a note email' do
it_behaves_like 'it should have Gmail Actions links'
it 'is sent to the given recipient as the author' do
@@ -263,7 +239,7 @@ shared_examples 'a note email' do
end
end
-shared_examples 'appearance header and footer enabled' do
+RSpec.shared_examples 'appearance header and footer enabled' do
it "contains header and footer" do
create :appearance, header_message: "Foo", footer_message: "Bar", email_header_and_footer_enabled: true
@@ -277,7 +253,7 @@ shared_examples 'appearance header and footer enabled' do
end
end
-shared_examples 'appearance header and footer not enabled' do
+RSpec.shared_examples 'appearance header and footer not enabled' do
it "does not contain header and footer" do
create :appearance, header_message: "Foo", footer_message: "Bar", email_header_and_footer_enabled: false
diff --git a/spec/support/shared_examples/models/active_record_enum_shared_examples.rb b/spec/support/shared_examples/models/active_record_enum_shared_examples.rb
index fb1189c7f17..3d765b6ca93 100644
--- a/spec/support/shared_examples/models/active_record_enum_shared_examples.rb
+++ b/spec/support/shared_examples/models/active_record_enum_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'having unique enum values' do
+RSpec.shared_examples 'having unique enum values' do
described_class.defined_enums.each do |name, enum|
it "has unique values in #{name.inspect}" do
duplicated = enum.group_by(&:last).select { |key, value| value.size > 1 }
diff --git a/spec/support/shared_examples/application_setting_examples.rb b/spec/support/shared_examples/models/application_setting_shared_examples.rb
index a43d2a75082..a43d2a75082 100644
--- a/spec/support/shared_examples/application_setting_examples.rb
+++ b/spec/support/shared_examples/models/application_setting_shared_examples.rb
diff --git a/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb b/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb
index b837ca87256..62d56f2e86e 100644
--- a/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb
+++ b/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples_for 'AtomicInternalId' do |validate_presence: true|
+RSpec.shared_examples 'AtomicInternalId' do |validate_presence: true|
describe '.has_internal_id' do
describe 'Module inclusion' do
subject { described_class }
diff --git a/spec/support/shared_examples/models/chat_service_shared_examples.rb b/spec/support/shared_examples/models/chat_service_shared_examples.rb
index 7936a8eb974..1cc1a1c8176 100644
--- a/spec/support/shared_examples/models/chat_service_shared_examples.rb
+++ b/spec/support/shared_examples/models/chat_service_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require "spec_helper"
-
-shared_examples_for "chat service" do |service_name|
+RSpec.shared_examples "chat service" do |service_name|
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/support/shared_examples/chat_slash_commands_shared_examples.rb b/spec/support/shared_examples/models/chat_slash_commands_shared_examples.rb
index 370f2072705..6611a168c04 100644
--- a/spec/support/shared_examples/chat_slash_commands_shared_examples.rb
+++ b/spec/support/shared_examples/models/chat_slash_commands_shared_examples.rb
@@ -30,7 +30,7 @@ RSpec.shared_examples 'chat slash commands service' do
subject { described_class.new }
context 'no token is passed' do
- let(:params) { Hash.new }
+ let(:params) { {} }
it 'returns nil' do
expect(subject.trigger(params)).to be_nil
diff --git a/spec/support/shared_examples/models/ci_variable_shared_examples.rb b/spec/support/shared_examples/models/ci_variable_shared_examples.rb
index f93de8b6ff1..6cc922b4101 100644
--- a/spec/support/shared_examples/models/ci_variable_shared_examples.rb
+++ b/spec/support/shared_examples/models/ci_variable_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'CI variable' do
+RSpec.shared_examples 'CI variable' do
it { is_expected.to include_module(HasVariable) }
describe "variable type" do
diff --git a/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb
index affe88be475..85a7c90ee42 100644
--- a/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb
+++ b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'cluster application core specs' do |application_name|
+RSpec.shared_examples 'cluster application core specs' do |application_name|
it { is_expected.to belong_to(:cluster) }
it { is_expected.to validate_presence_of(:cluster) }
diff --git a/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb b/spec/support/shared_examples/models/cluster_application_helm_cert_shared_examples.rb
index 1c8c19acc74..d5c425dea51 100644
--- a/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb
+++ b/spec/support/shared_examples/models/cluster_application_helm_cert_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'cluster application helm specs' do |application_name|
+RSpec.shared_examples 'cluster application helm specs' do |application_name|
let(:application) { create(application_name) }
describe '#uninstall_command' do
diff --git a/spec/support/shared_examples/models/cluster_application_initial_status.rb b/spec/support/shared_examples/models/cluster_application_initial_status_shared_examples.rb
index 030974c9aa0..0b21e9a3aa7 100644
--- a/spec/support/shared_examples/models/cluster_application_initial_status.rb
+++ b/spec/support/shared_examples/models/cluster_application_initial_status_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'cluster application initial status specs' do
+RSpec.shared_examples 'cluster application initial status specs' do
describe '#status' do
let(:cluster) { create(:cluster, :provided_by_gcp) }
diff --git a/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb
index 4bca37a4cd0..e4e49b94e42 100644
--- a/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb
+++ b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'cluster application status specs' do |application_name|
+RSpec.shared_examples 'cluster application status specs' do |application_name|
describe '#status_states' do
let(:cluster) { create(:cluster, :provided_by_gcp) }
diff --git a/spec/support/shared_examples/models/cluster_application_version_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_version_shared_examples.rb
index ba02da41b53..e293467774e 100644
--- a/spec/support/shared_examples/models/cluster_application_version_shared_examples.rb
+++ b/spec/support/shared_examples/models/cluster_application_version_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'cluster application version specs' do |application_name|
+RSpec.shared_examples 'cluster application version specs' do |application_name|
describe 'update_available?' do
let(:version) { '0.0.0' }
diff --git a/spec/support/shared_examples/models/cluster_cleanup_worker_base_shared_examples.rb b/spec/support/shared_examples/models/cluster_cleanup_worker_base_shared_examples.rb
index 66bbd908ea8..2302a605be5 100644
--- a/spec/support/shared_examples/models/cluster_cleanup_worker_base_shared_examples.rb
+++ b/spec/support/shared_examples/models/cluster_cleanup_worker_base_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'cluster cleanup worker base specs' do
+RSpec.shared_examples 'cluster cleanup worker base specs' do
it 'transitions to errored if sidekiq retries exhausted' do
job = { 'args' => [cluster.id, 0], 'jid' => '123' }
diff --git a/spec/support/shared_examples/models/clusters/providers/provider_status.rb b/spec/support/shared_examples/models/clusters/providers/provider_status_shared_examples.rb
index 63cb9a56f5b..3ef1911ba99 100644
--- a/spec/support/shared_examples/models/clusters/providers/provider_status.rb
+++ b/spec/support/shared_examples/models/clusters/providers/provider_status_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'provider status' do |factory|
+RSpec.shared_examples 'provider status' do |factory|
describe 'state_machine' do
context 'when any => [:created]' do
let(:provider) { build(factory, :creating) }
diff --git a/spec/support/shared_examples/models/concerns/issuable_shared_examples.rb b/spec/support/shared_examples/models/concerns/issuable_shared_examples.rb
index 4978a403324..3a407088997 100644
--- a/spec/support/shared_examples/models/concerns/issuable_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/issuable_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'matches_cross_reference_regex? fails fast' do
+RSpec.shared_examples 'matches_cross_reference_regex? fails fast' do
it 'fails fast for long strings' do
# took well under 1 second in CI https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/3267#note_172823
expect do
@@ -9,7 +9,7 @@ shared_examples_for 'matches_cross_reference_regex? fails fast' do
end
end
-shared_examples_for 'validates description length with custom validation' do
+RSpec.shared_examples 'validates description length with custom validation' do
let(:issuable) { build(:issue, description: 'x' * (::Issuable::DESCRIPTION_LENGTH_MAX + 1)) }
let(:context) { :update }
@@ -48,7 +48,7 @@ shared_examples_for 'validates description length with custom validation' do
end
end
-shared_examples_for 'truncates the description to its allowed maximum length on import' do
+RSpec.shared_examples 'truncates the description to its allowed maximum length on import' do
before do
allow(issuable).to receive(:importing?).and_return(true)
end
diff --git a/spec/support/shared_examples/models/concerns/redactable_shared_examples.rb b/spec/support/shared_examples/models/concerns/redactable_shared_examples.rb
index c5c14901268..e196cf8f8da 100644
--- a/spec/support/shared_examples/models/concerns/redactable_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/redactable_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'model with redactable field' do
+RSpec.shared_examples 'model with redactable field' do
it 'redacts unsubscribe token' do
model[field] = 'some text /sent_notifications/00000000000000000000000000000000/unsubscribe more text'
diff --git a/spec/support/shared_examples/cycle_analytics_stage_shared_examples.rb b/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
index c781f72ff11..2548afc1570 100644
--- a/spec/support/shared_examples/cycle_analytics_stage_shared_examples.rb
+++ b/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'cycle analytics stage' do
+RSpec.shared_examples 'cycle analytics stage' do
let(:valid_params) do
{
name: 'My Stage',
@@ -111,7 +111,7 @@ shared_examples_for 'cycle analytics stage' do
end
end
-shared_examples_for 'cycle analytics label based stage' do
+RSpec.shared_examples 'cycle analytics label based stage' do
context 'when creating label based event' do
context 'when the label id is not passed' do
it 'returns validation error when `start_event_label_id` is missing' do
diff --git a/spec/support/shared_examples/models/diff_note_after_commit_shared_examples.rb b/spec/support/shared_examples/models/diff_note_after_commit_shared_examples.rb
index 835d2dfe757..8c3e073193c 100644
--- a/spec/support/shared_examples/models/diff_note_after_commit_shared_examples.rb
+++ b/spec/support/shared_examples/models/diff_note_after_commit_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'a valid diff note with after commit callback' do
+RSpec.shared_examples 'a valid diff note with after commit callback' do
context 'when diff file is fetched from repository' do
before do
allow_any_instance_of(::Gitlab::Diff::Position).to receive(:diff_file).with(project.repository).and_return(diff_file_from_repository)
diff --git a/spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb b/spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb
index 8b298c5c974..38a9f1fe098 100644
--- a/spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb
+++ b/spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'a valid diff positionable note' do |factory_on_commit|
+RSpec.shared_examples 'a valid diff positionable note' do |factory_on_commit|
context 'for commit' do
let(:project) { create(:project, :repository) }
let(:commit) { project.commit(sample_commit.id) }
diff --git a/spec/support/shared_examples/email_format_shared_examples.rb b/spec/support/shared_examples/models/email_format_shared_examples.rb
index 22d6c2b38e3..6797836e383 100644
--- a/spec/support/shared_examples/email_format_shared_examples.rb
+++ b/spec/support/shared_examples/models/email_format_shared_examples.rb
@@ -6,7 +6,7 @@
# Note: You have access to `email_value` which is the email address value
# being currently tested).
-shared_examples 'an object with email-formated attributes' do |*attributes|
+RSpec.shared_examples 'an object with email-formated attributes' do |*attributes|
attributes.each do |attribute|
describe "specifically its :#{attribute} attribute" do
%w[
diff --git a/spec/support/shared_examples/group_members_shared_example.rb b/spec/support/shared_examples/models/group_members_shared_example.rb
index 4f7d496741d..4f7d496741d 100644
--- a/spec/support/shared_examples/group_members_shared_example.rb
+++ b/spec/support/shared_examples/models/group_members_shared_example.rb
diff --git a/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb b/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb
index 7ea2bb265cc..ecf1640ef5d 100644
--- a/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb
+++ b/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
# This shared example requires a `builder` and `user` variable
-shared_examples 'issuable hook data' do |kind|
+RSpec.shared_examples 'issuable hook data' do |kind|
let(:data) { builder.build(user: user) }
include_examples 'project hook data' do
diff --git a/spec/support/shared_examples/issue_tracker_service_shared_example.rb b/spec/support/shared_examples/models/issue_tracker_service_shared_examples.rb
index 0a483fd30ba..0a483fd30ba 100644
--- a/spec/support/shared_examples/issue_tracker_service_shared_example.rb
+++ b/spec/support/shared_examples/models/issue_tracker_service_shared_examples.rb
diff --git a/spec/support/shared_examples/models/label_note_shared_examples.rb b/spec/support/shared_examples/models/label_note_shared_examples.rb
index 406385c13bd..73066fb631a 100644
--- a/spec/support/shared_examples/models/label_note_shared_examples.rb
+++ b/spec/support/shared_examples/models/label_note_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'label note created from events' do
+RSpec.shared_examples 'label note created from events' do
def create_event(params = {})
event_params = { action: :add, label: label, user: user }
resource_key = resource.class.name.underscore.to_s
diff --git a/spec/support/shared_examples/models/member_shared_examples.rb b/spec/support/shared_examples/models/member_shared_examples.rb
index e5375bc8280..9bf157212d3 100644
--- a/spec/support/shared_examples/models/member_shared_examples.rb
+++ b/spec/support/shared_examples/models/member_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'inherited access level as a member of entity' do
+RSpec.shared_examples 'inherited access level as a member of entity' do
let(:parent_entity) { create(:group) }
let(:user) { create(:user) }
let(:member) { entity.is_a?(Group) ? entity.group_member(user) : entity.project_member(user) }
@@ -57,7 +57,7 @@ shared_examples_for 'inherited access level as a member of entity' do
end
end
-shared_examples_for '#valid_level_roles' do |entity_name|
+RSpec.shared_examples '#valid_level_roles' do |entity_name|
let(:member_user) { create(:user) }
let(:group) { create(:group) }
let(:entity) { create(entity_name) }
diff --git a/spec/support/shared_examples/mentionable_shared_examples.rb b/spec/support/shared_examples/models/mentionable_shared_examples.rb
index 6efc471ce75..0c55e9de045 100644
--- a/spec/support/shared_examples/mentionable_shared_examples.rb
+++ b/spec/support/shared_examples/models/mentionable_shared_examples.rb
@@ -6,7 +6,7 @@
# - let(:backref_text) { "the way that +subject+ should refer to itself in backreferences " }
# - let(:set_mentionable_text) { lambda { |txt| "block that assigns txt to the subject's mentionable_text" } }
-shared_context 'mentionable context' do
+RSpec.shared_context 'mentionable context' do
let(:project) { subject.project }
let(:author) { subject.author }
@@ -59,7 +59,7 @@ shared_context 'mentionable context' do
end
end
-shared_examples 'a mentionable' do
+RSpec.shared_examples 'a mentionable' do
include_context 'mentionable context'
it 'generates a descriptive back-reference' do
@@ -115,7 +115,7 @@ shared_examples 'a mentionable' do
end
end
-shared_examples 'an editable mentionable' do
+RSpec.shared_examples 'an editable mentionable' do
include_context 'mentionable context'
it_behaves_like 'a mentionable'
@@ -196,7 +196,7 @@ shared_examples 'an editable mentionable' do
end
end
-shared_examples_for 'mentions in description' do |mentionable_type|
+RSpec.shared_examples 'mentions in description' do |mentionable_type|
describe 'when store_mentioned_users_to_db feature disabled' do
before do
stub_feature_flags(store_mentioned_users_to_db: false)
@@ -246,7 +246,7 @@ shared_examples_for 'mentions in description' do |mentionable_type|
end
end
-shared_examples_for 'mentions in notes' do |mentionable_type|
+RSpec.shared_examples 'mentions in notes' do |mentionable_type|
context 'when mentionable notes contain mentions' do
let(:user) { create(:user) }
let(:group) { create(:group) }
@@ -268,7 +268,7 @@ shared_examples_for 'mentions in notes' do |mentionable_type|
end
end
-shared_examples_for 'load mentions from DB' do |mentionable_type|
+RSpec.shared_examples 'load mentions from DB' do |mentionable_type|
context 'load stored mentions' do
let_it_be(:user) { create(:user) }
let_it_be(:mentioned_user) { create(:user) }
diff --git a/spec/support/shared_examples/models/project_hook_data_shared_examples.rb b/spec/support/shared_examples/models/project_hook_data_shared_examples.rb
index 03d10c10e3c..73a6fd7aeb8 100644
--- a/spec/support/shared_examples/models/project_hook_data_shared_examples.rb
+++ b/spec/support/shared_examples/models/project_hook_data_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'project hook data with deprecateds' do |project_key: :project|
+RSpec.shared_examples 'project hook data with deprecateds' do |project_key: :project|
it 'contains project data' do
expect(data[project_key][:name]).to eq(project.name)
expect(data[project_key][:description]).to eq(project.description)
@@ -19,7 +19,7 @@ shared_examples 'project hook data with deprecateds' do |project_key: :project|
end
end
-shared_examples 'project hook data' do |project_key: :project|
+RSpec.shared_examples 'project hook data' do |project_key: :project|
it 'contains project data' do
expect(data[project_key][:name]).to eq(project.name)
expect(data[project_key][:description]).to eq(project.description)
@@ -34,7 +34,7 @@ shared_examples 'project hook data' do |project_key: :project|
end
end
-shared_examples 'deprecated repository hook data' do
+RSpec.shared_examples 'deprecated repository hook data' do
it 'contains deprecated repository data' do
expect(data[:repository][:name]).to eq(project.name)
expect(data[:repository][:description]).to eq(project.description)
diff --git a/spec/support/shared_examples/project_latest_successful_build_for_examples.rb b/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb
index a9bd23e9fc9..7bbc0c5a364 100644
--- a/spec/support/shared_examples/project_latest_successful_build_for_examples.rb
+++ b/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'latest successful build for sha or ref' do
+RSpec.shared_examples 'latest successful build for sha or ref' do
context 'with many builds' do
let(:other_pipeline) { create_pipeline(project) }
let(:other_build) { create_build(other_pipeline, 'test') }
diff --git a/spec/support/shared_examples/relative_positioning_shared_examples.rb b/spec/support/shared_examples/models/relative_positioning_shared_examples.rb
index 99e62ebf422..99e62ebf422 100644
--- a/spec/support/shared_examples/relative_positioning_shared_examples.rb
+++ b/spec/support/shared_examples/models/relative_positioning_shared_examples.rb
diff --git a/spec/support/shared_examples/models/services_fields_shared_examples.rb b/spec/support/shared_examples/models/services_fields_shared_examples.rb
index 6fbd0da9383..cb36f74460d 100644
--- a/spec/support/shared_examples/models/services_fields_shared_examples.rb
+++ b/spec/support/shared_examples/models/services_fields_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issue tracker fields' do
+RSpec.shared_examples 'issue tracker fields' do
let(:title) { 'custom title' }
let(:description) { 'custom description' }
let(:url) { 'http://issue_tracker.example.com' }
diff --git a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb b/spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb
index 2b68e7bfa82..2b68e7bfa82 100644
--- a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb
+++ b/spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb
diff --git a/spec/support/shared_examples/taskable_shared_examples.rb b/spec/support/shared_examples/models/taskable_shared_examples.rb
index f04f509f3d2..34b1d735bcd 100644
--- a/spec/support/shared_examples/taskable_shared_examples.rb
+++ b/spec/support/shared_examples/models/taskable_shared_examples.rb
@@ -4,7 +4,7 @@
#
# Requires a context containing:
# subject { Issue or MergeRequest }
-shared_examples 'a Taskable' do
+RSpec.shared_examples 'a Taskable' do
describe 'with multiple tasks' do
before do
subject.description = <<-EOT.strip_heredoc
diff --git a/spec/support/shared_examples/throttled_touch.rb b/spec/support/shared_examples/models/throttled_touch_shared_examples.rb
index aaaa590862d..fc4f6053bb9 100644
--- a/spec/support/shared_examples/throttled_touch.rb
+++ b/spec/support/shared_examples/models/throttled_touch_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'throttled touch' do
+RSpec.shared_examples 'throttled touch' do
describe '#touch' do
it 'updates the updated_at timestamp' do
Timecop.freeze do
diff --git a/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb b/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
index e03435cafe8..7d70df82ec7 100644
--- a/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
+++ b/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples_for 'UpdateProjectStatistics' do
+RSpec.shared_examples 'UpdateProjectStatistics' do
let(:project) { subject.project }
let(:project_statistics_name) { described_class.project_statistics_name }
let(:statistic_attribute) { described_class.statistic_attribute }
diff --git a/spec/support/shared_examples/models/user_mentions_shared_examples.rb b/spec/support/shared_examples/models/user_mentions_shared_examples.rb
index b94994ea712..66c629cb4b8 100644
--- a/spec/support/shared_examples/models/user_mentions_shared_examples.rb
+++ b/spec/support/shared_examples/models/user_mentions_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples_for 'has user mentions' do
+RSpec.shared_examples 'has user mentions' do
describe '#has_mentions?' do
context 'when no mentions' do
it 'returns false' do
diff --git a/spec/support/shared_examples/versioned_description_shared_examples.rb b/spec/support/shared_examples/models/versioned_description_shared_examples.rb
index 59124af19ec..59124af19ec 100644
--- a/spec/support/shared_examples/versioned_description_shared_examples.rb
+++ b/spec/support/shared_examples/models/versioned_description_shared_examples.rb
diff --git a/spec/support/shared_examples/models/with_uploads_shared_examples.rb b/spec/support/shared_examples/models/with_uploads_shared_examples.rb
index 3d622ba8195..f2a4d9919b7 100644
--- a/spec/support/shared_examples/models/with_uploads_shared_examples.rb
+++ b/spec/support/shared_examples/models/with_uploads_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples_for 'model with uploads' do |supports_fileuploads|
+RSpec.shared_examples 'model with uploads' do |supports_fileuploads|
describe '.destroy' do
before do
stub_uploads_object_storage(uploader_class)
diff --git a/spec/support/shared_examples/policies/clusterable_shared_examples.rb b/spec/support/shared_examples/policies/clusterable_shared_examples.rb
index 0b427c23256..b96aa71acbe 100644
--- a/spec/support/shared_examples/policies/clusterable_shared_examples.rb
+++ b/spec/support/shared_examples/policies/clusterable_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples 'clusterable policies' do
+RSpec.shared_examples 'clusterable policies' do
describe '#add_cluster?' do
let(:current_user) { create(:user) }
diff --git a/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb
index f5a86e4dc2c..14b384b149d 100644
--- a/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'tag quick action' do
+RSpec.shared_examples 'tag quick action' do
context "post note to existing commit" do
it 'tags this commit' do
add_note("/tag #{tag_name} #{tag_message}")
diff --git a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
index 6e7eb78261a..e2582f20ece 100644
--- a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'close quick action' do |issuable_type|
+RSpec.shared_examples 'close quick action' do |issuable_type|
include Spec::Support::Helpers::Features::NotesHelpers
before do
diff --git a/spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb
index 439c068471b..4db52795cd4 100644
--- a/spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issuable quick actions' do
+RSpec.shared_examples 'issuable quick actions' do
QuickAction = Struct.new(:action_text, :expectation, :before_action, keyword_init: true) do
# Pass a block as :before_action if
# issuable state needs to be changed before
diff --git a/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb
index ed904c8d539..37a504cd56a 100644
--- a/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issuable time tracker' do |issuable_type|
+RSpec.shared_examples 'issuable time tracker' do |issuable_type|
before do
project.add_maintainer(maintainer)
gitlab_sign_in(maintainer)
diff --git a/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb
index 6edd20bb024..321e7d386c6 100644
--- a/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb
@@ -1,4 +1,4 @@
# frozen_string_literal: true
-shared_examples 'board_move quick action' do
+RSpec.shared_examples 'board_move quick action' do
end
diff --git a/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb
index 3e9ee9a633f..159660e7d1d 100644
--- a/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'create_merge_request quick action' do
+RSpec.shared_examples 'create_merge_request quick action' do
context 'create a merge request starting from an issue' do
def expect_mr_quickaction(success, branch_name = nil)
command_message = if branch_name
diff --git a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
index bebc8509d53..897a962fc56 100644
--- a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'move quick action' do
+RSpec.shared_examples 'move quick action' do
context 'move the issue to another project' do
let(:target_project) { create(:project, :public) }
diff --git a/spec/support/shared_examples/quick_actions/issue/zoom_quick_actions_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/zoom_quick_actions_shared_examples.rb
index 92bbc4abe77..1ea249d5f9d 100644
--- a/spec/support/shared_examples/quick_actions/issue/zoom_quick_actions_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issue/zoom_quick_actions_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'zoom quick actions' do
+RSpec.shared_examples 'zoom quick actions' do
let(:zoom_link) { 'https://zoom.us/j/123456789' }
let(:existing_zoom_link) { 'https://zoom.us/j/123456780' }
let(:invalid_zoom_link) { 'https://invalid-zoom' }
diff --git a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
index a77d729aa2c..fa163b54405 100644
--- a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'merge quick action' do
+RSpec.shared_examples 'merge quick action' do
context 'when the current user can merge the MR' do
before do
sign_in(user)
diff --git a/spec/support/shared_examples/award_emoji_todo_shared_examples.rb b/spec/support/shared_examples/requests/api/award_emoji_todo_shared_examples.rb
index 88ad37d232f..88ad37d232f 100644
--- a/spec/support/shared_examples/award_emoji_todo_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/award_emoji_todo_shared_examples.rb
diff --git a/spec/support/shared_examples/requests/api/boards_shared_examples.rb b/spec/support/shared_examples/requests/api/boards_shared_examples.rb
new file mode 100644
index 00000000000..2bc79a2ef4d
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/boards_shared_examples.rb
@@ -0,0 +1,189 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'group and project boards' do |route_definition, ee = false|
+ let(:root_url) { route_definition.gsub(":id", board_parent.id.to_s) }
+
+ before do
+ board_parent.add_reporter(user)
+ board_parent.add_guest(guest)
+ end
+
+ def expect_schema_match_for(response, schema_file, ee)
+ if ee
+ expect(response).to match_response_schema(schema_file, dir: "ee")
+ else
+ expect(response).to match_response_schema(schema_file)
+ end
+ end
+
+ it 'avoids N+1 queries' do
+ pat = create(:personal_access_token, user: user)
+ control = ActiveRecord::QueryRecorder.new { get api(root_url, personal_access_token: pat) }
+
+ create(:milestone, "#{board_parent.class.name.underscore}": board_parent)
+ create(:board, "#{board_parent.class.name.underscore}": board_parent)
+
+ expect { get api(root_url, personal_access_token: pat) }.not_to exceed_query_limit(control)
+ end
+
+ describe "GET #{route_definition}" do
+ context "when unauthenticated" do
+ it "returns authentication error" do
+ get api(root_url)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context "when authenticated" do
+ it "returns the issue boards" do
+ get api(root_url, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+
+ expect_schema_match_for(response, 'public_api/v4/boards', ee)
+ end
+
+ describe "GET #{route_definition}/:board_id" do
+ let(:url) { "#{root_url}/#{board.id}" }
+
+ it 'get a single board by id' do
+ get api(url, user)
+
+ expect_schema_match_for(response, 'public_api/v4/board', ee)
+ end
+ end
+ end
+ end
+
+ describe "GET #{route_definition}/:board_id/lists" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it 'returns issue board lists' do
+ get api(url, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(json_response.first['label']['name']).to eq(dev_label.title)
+ end
+
+ it 'returns 404 if board not found' do
+ get api("#{root_url}/22343/lists", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ describe "GET #{route_definition}/:board_id/lists/:list_id" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it 'returns a list' do
+ get api("#{url}/#{dev_list.id}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['id']).to eq(dev_list.id)
+ expect(json_response['label']['name']).to eq(dev_label.title)
+ expect(json_response['position']).to eq(1)
+ end
+
+ it 'returns 404 if list not found' do
+ get api("#{url}/5324", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ describe "POST #{route_definition}/lists" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it 'creates a new issue board list for labels' do
+ post api(url, user), params: { label_id: ux_label.id }
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['label']['name']).to eq(ux_label.title)
+ expect(json_response['position']).to eq(3)
+ end
+
+ it 'returns 400 when creating a new list if label_id is invalid' do
+ post api(url, user), params: { label_id: 23423 }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'returns 403 for members with guest role' do
+ put api("#{url}/#{test_list.id}", guest), params: { position: 1 }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ describe "PUT #{route_definition}/:board_id/lists/:list_id to update only position" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it "updates a list" do
+ put api("#{url}/#{test_list.id}", user), params: { position: 1 }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['position']).to eq(1)
+ end
+
+ it "returns 404 error if list id not found" do
+ put api("#{url}/44444", user), params: { position: 1 }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it "returns 403 for members with guest role" do
+ put api("#{url}/#{test_list.id}", guest), params: { position: 1 }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ describe "DELETE #{route_definition}/lists/:list_id" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it "rejects a non member from deleting a list" do
+ delete api("#{url}/#{dev_list.id}", non_member)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it "rejects a user with guest role from deleting a list" do
+ delete api("#{url}/#{dev_list.id}", guest)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it "returns 404 error if list id not found" do
+ delete api("#{url}/44444", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ context "when the user is parent owner" do
+ set(:owner) { create(:user) }
+
+ before do
+ if board_parent.try(:namespace)
+ board_parent.update(namespace: owner.namespace)
+ else
+ board.resource_parent.add_owner(owner)
+ end
+ end
+
+ it "deletes the list if an admin requests it" do
+ delete api("#{url}/#{dev_list.id}", owner)
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) { api("#{url}/#{dev_list.id}", owner) }
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/container_repositories_shared_examples.rb b/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb
index b4f45ba9a00..0f277c11913 100644
--- a/spec/support/shared_examples/container_repositories_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'rejected container repository access' do |user_type, status|
+RSpec.shared_examples 'rejected container repository access' do |user_type, status|
context "for #{user_type}" do
let(:api_user) { users[user_type] }
@@ -12,7 +12,7 @@ shared_examples 'rejected container repository access' do |user_type, status|
end
end
-shared_examples 'returns repositories for allowed users' do |user_type, scope|
+RSpec.shared_examples 'returns repositories for allowed users' do |user_type, scope|
context "for #{user_type}" do
it 'returns a list of repositories' do
subject
@@ -57,7 +57,7 @@ shared_examples 'returns repositories for allowed users' do |user_type, scope|
end
end
-shared_examples 'a gitlab tracking event' do |category, action|
+RSpec.shared_examples 'a gitlab tracking event' do |category, action|
it "creates a gitlab tracking event #{action}" do
expect(Gitlab::Tracking).to receive(:event).with(category, action, {})
diff --git a/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb b/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb
index 22bd6e9cdf7..8cbf11b6de1 100644
--- a/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'custom attributes endpoints' do |attributable_name|
+RSpec.shared_examples 'custom attributes endpoints' do |attributable_name|
let!(:custom_attribute1) { attributable.custom_attributes.create key: 'foo', value: 'foo' }
let!(:custom_attribute2) { attributable.custom_attributes.create key: 'bar', value: 'bar' }
diff --git a/spec/support/shared_examples/requests/api/diff_discussions.rb b/spec/support/shared_examples/requests/api/diff_discussions_shared_examples.rb
index 8ef3ed3f057..583475678f1 100644
--- a/spec/support/shared_examples/requests/api/diff_discussions.rb
+++ b/spec/support/shared_examples/requests/api/diff_discussions_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name|
+RSpec.shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name|
describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
it "includes diff discussions" do
get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user)
diff --git a/spec/support/shared_examples/requests/api/discussions.rb b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
index 232c8d20025..939ea405724 100644
--- a/spec/support/shared_examples/requests/api/discussions.rb
+++ b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'with cross-reference system notes' do
+RSpec.shared_examples 'with cross-reference system notes' do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:new_merge_request) { create(:merge_request) }
@@ -54,7 +54,7 @@ shared_examples 'with cross-reference system notes' do
end
end
-shared_examples 'discussions API' do |parent_type, noteable_type, id_name, can_reply_to_individual_notes: false|
+RSpec.shared_examples 'discussions API' do |parent_type, noteable_type, id_name, can_reply_to_individual_notes: false|
describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
it "returns an array of discussions" do
get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user)
diff --git a/spec/support/shared_examples/requests/api/issuable_participants_examples.rb b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb
index 013b135235c..e442b988349 100644
--- a/spec/support/shared_examples/requests/api/issuable_participants_examples.rb
+++ b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issuable participants endpoint' do
+RSpec.shared_examples 'issuable participants endpoint' do
let(:area) { entity.class.name.underscore.pluralize }
it 'returns participants' do
diff --git a/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb b/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
index 90c1ed8d09b..971b21b5b32 100644
--- a/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
@@ -4,7 +4,7 @@ def get_issue
json_response.is_a?(Array) ? json_response.detect {|issue| issue['id'] == target_issue.id} : json_response
end
-shared_examples 'accessible merge requests count' do
+RSpec.shared_examples 'accessible merge requests count' do
it 'returns anonymous accessible merge requests count' do
get api(api_url), params: { scope: 'all' }
diff --git a/spec/support/shared_examples/requests/api/issues_resolving_discussions_shared_examples.rb b/spec/support/shared_examples/requests/api/issues_resolving_discussions_shared_examples.rb
new file mode 100644
index 00000000000..b748d5f5eea
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/issues_resolving_discussions_shared_examples.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'creating an issue resolving discussions through the API' do
+ it 'creates a new project issue' do
+ expect(response).to have_gitlab_http_status(:created)
+ end
+
+ it 'resolves the discussions in a merge request' do
+ discussion.first_note.reload
+
+ expect(discussion.resolved?).to be(true)
+ end
+
+ it 'assigns a description to the issue mentioning the merge request' do
+ expect(json_response['description']).to include(merge_request.to_reference)
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/issues_shared_examples.rb b/spec/support/shared_examples/requests/api/issues_shared_examples.rb
index d22210edf99..991dbced02d 100644
--- a/spec/support/shared_examples/requests/api/issues_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/issues_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'labeled issues with labels and label_name params' do
+RSpec.shared_examples 'labeled issues with labels and label_name params' do
shared_examples 'returns label names' do
it 'returns label names' do
expect_paginated_array_response(issue.id)
diff --git a/spec/support/shared_examples/logging_application_context_shared_examples.rb b/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb
index 038ede884c8..038ede884c8 100644
--- a/spec/support/shared_examples/logging_application_context_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb
diff --git a/spec/support/shared_examples/requests/api/members_shared_examples.rb b/spec/support/shared_examples/requests/api/members_shared_examples.rb
new file mode 100644
index 00000000000..fce75c29971
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/members_shared_examples.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a 404 response when source is private' do
+ before do
+ source.update_column(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it 'returns 404' do
+ route
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/milestones_shared_examples.rb b/spec/support/shared_examples/requests/api/milestones_shared_examples.rb
new file mode 100644
index 00000000000..b7cc5f2ca6b
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/milestones_shared_examples.rb
@@ -0,0 +1,405 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'group and project milestones' do |route_definition|
+ let(:resource_route) { "#{route}/#{milestone.id}" }
+ let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
+ let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
+ let(:label_3) { create(:label, title: 'label_3', project: project) }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:another_merge_request) { create(:merge_request, :simple, source_project: project) }
+
+ describe "GET #{route_definition}" do
+ it 'returns milestones list' do
+ get api(route, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['title']).to eq(milestone.title)
+ end
+
+ it 'returns a 401 error if user not authenticated' do
+ get api(route)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'returns an array of active milestones' do
+ get api("#{route}/?state=active", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(milestone.id)
+ end
+
+ it 'returns an array of closed milestones' do
+ get api("#{route}/?state=closed", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(closed_milestone.id)
+ end
+
+ it 'returns an array of milestones specified by iids' do
+ other_milestone = create(:milestone, project: try(:project), group: try(:group))
+
+ get api(route, user), params: { iids: [closed_milestone.iid, other_milestone.iid] }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(json_response.map { |m| m['id'] }).to match_array([closed_milestone.id, other_milestone.id])
+ end
+
+ it 'does not return any milestone if none found' do
+ get api(route, user), params: { iids: [Milestone.maximum(:iid).succ] }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
+ end
+
+ it 'returns a milestone by iids array' do
+ get api("#{route}?iids=#{closed_milestone.iid}", user)
+
+ expect(response.status).to eq 200
+ expect(response).to include_pagination_headers
+ expect(json_response.size).to eq(1)
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['title']).to eq closed_milestone.title
+ expect(json_response.first['id']).to eq closed_milestone.id
+ end
+
+ it 'returns a milestone by title' do
+ get api(route, user), params: { title: 'version2' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['title']).to eq milestone.title
+ expect(json_response.first['id']).to eq milestone.id
+ end
+
+ it 'returns a milestone by searching for title' do
+ get api(route, user), params: { search: 'version2' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['title']).to eq milestone.title
+ expect(json_response.first['id']).to eq milestone.id
+ end
+
+ it 'returns a milestones by searching for description' do
+ get api(route, user), params: { search: 'open' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['title']).to eq milestone.title
+ expect(json_response.first['id']).to eq milestone.id
+ end
+ end
+
+ describe "GET #{route_definition}/:milestone_id" do
+ it 'returns a milestone by id' do
+ get api(resource_route, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['title']).to eq(milestone.title)
+ expect(json_response['iid']).to eq(milestone.iid)
+ end
+
+ it 'returns 401 error if user not authenticated' do
+ get api(resource_route)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'returns a 404 error if milestone id not found' do
+ get api("#{route}/1234", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ describe "POST #{route_definition}" do
+ it 'creates a new milestone' do
+ post api(route, user), params: { title: 'new milestone' }
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['title']).to eq('new milestone')
+ expect(json_response['description']).to be_nil
+ end
+
+ it 'creates a new milestone with description and dates' do
+ post api(route, user), params: { title: 'new milestone', description: 'release', due_date: '2013-03-02', start_date: '2013-02-02' }
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['description']).to eq('release')
+ expect(json_response['due_date']).to eq('2013-03-02')
+ expect(json_response['start_date']).to eq('2013-02-02')
+ end
+
+ it 'returns a 400 error if title is missing' do
+ post api(route, user)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'returns a 400 error if params are invalid (duplicate title)' do
+ post api(route, user), params: { title: milestone.title, description: 'release', due_date: '2013-03-02' }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'creates a new milestone with reserved html characters' do
+ post api(route, user), params: { title: 'foo & bar 1.1 -> 2.2' }
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['title']).to eq('foo & bar 1.1 -> 2.2')
+ expect(json_response['description']).to be_nil
+ end
+ end
+
+ describe "PUT #{route_definition}/:milestone_id" do
+ it 'updates a milestone' do
+ put api(resource_route, user), params: { title: 'updated title' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['title']).to eq('updated title')
+ end
+
+ it 'removes a due date if nil is passed' do
+ milestone.update!(due_date: "2016-08-05")
+
+ put api(resource_route, user), params: { due_date: nil }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['due_date']).to be_nil
+ end
+
+ it 'returns a 404 error if milestone id not found' do
+ put api("#{route}/1234", user), params: { title: 'updated title' }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'closes milestone' do
+ put api(resource_route, user), params: { state_event: 'close' }
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(json_response['state']).to eq('closed')
+ end
+
+ it 'updates milestone with only start date' do
+ put api(resource_route, user), params: { start_date: Date.tomorrow }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ describe "DELETE #{route_definition}/:milestone_id" do
+ it "rejects a member with reporter access from deleting a milestone" do
+ reporter = create(:user)
+ milestone.resource_parent.add_reporter(reporter)
+
+ delete api(resource_route, reporter)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'deletes the milestone when the user has developer access to the project' do
+ delete api(resource_route, user)
+
+ expect(project.milestones.find_by_id(milestone.id)).to be_nil
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+ end
+
+ describe "GET #{route_definition}/:milestone_id/issues" do
+ let(:issues_route) { "#{route}/#{milestone.id}/issues" }
+
+ before do
+ milestone.issues << create(:issue, project: project)
+ end
+ it 'returns issues for a particular milestone' do
+ get api(issues_route, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['milestone']['title']).to eq(milestone.title)
+ end
+
+ it 'returns issues sorted by label priority' do
+ issue_1 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_3])
+ issue_2 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_1])
+ issue_3 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_2])
+
+ get api(issues_route, user)
+
+ expect(json_response.first['id']).to eq(issue_2.id)
+ expect(json_response.second['id']).to eq(issue_3.id)
+ expect(json_response.third['id']).to eq(issue_1.id)
+ end
+
+ it 'matches V4 response schema for a list of issues' do
+ get api(issues_route, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/issues')
+ end
+
+ it 'returns a 401 error if user not authenticated' do
+ get api(issues_route)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ describe 'confidential issues' do
+ let!(:public_project) { create(:project, :public) }
+ let!(:context_group) { try(:group) }
+ let!(:milestone) do
+ context_group ? create(:milestone, group: context_group) : create(:milestone, project: public_project)
+ end
+ let!(:issue) { create(:issue, project: public_project) }
+ let!(:confidential_issue) { create(:issue, confidential: true, project: public_project) }
+ let!(:issues_route) do
+ if context_group
+ "#{route}/#{milestone.id}/issues"
+ else
+ "/projects/#{public_project.id}/milestones/#{milestone.id}/issues"
+ end
+ end
+
+ before do
+ # Add public project to the group in context
+ setup_for_group if context_group
+
+ public_project.add_developer(user)
+ milestone.issues << issue << confidential_issue
+ end
+
+ it 'returns confidential issues to team members' do
+ get api(issues_route, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ # 2 for projects, 3 for group(which has another project with an issue)
+ expect(json_response.size).to be_between(2, 3)
+ expect(json_response.map { |issue| issue['id'] }).to include(issue.id, confidential_issue.id)
+ end
+
+ it 'does not return confidential issues to team members with guest role' do
+ member = create(:user)
+ public_project.add_guest(member)
+
+ get api(issues_route, member)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(1)
+ expect(json_response.map { |issue| issue['id'] }).to include(issue.id)
+ end
+
+ it 'does not return confidential issues to regular users' do
+ get api(issues_route, create(:user))
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(1)
+ expect(json_response.map { |issue| issue['id'] }).to include(issue.id)
+ end
+
+ it 'returns issues ordered by label priority' do
+ issue.labels << label_2
+ confidential_issue.labels << label_1
+
+ get api(issues_route, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ # 2 for projects, 3 for group(which has another project with an issue)
+ expect(json_response.size).to be_between(2, 3)
+ expect(json_response.first['id']).to eq(confidential_issue.id)
+ expect(json_response.second['id']).to eq(issue.id)
+ end
+ end
+ end
+
+ describe "GET #{route_definition}/:milestone_id/merge_requests" do
+ let(:merge_requests_route) { "#{route}/#{milestone.id}/merge_requests" }
+
+ before do
+ milestone.merge_requests << merge_request
+ end
+
+ it 'returns merge_requests for a particular milestone' do
+ # eager-load another_merge_request
+ another_merge_request
+ get api(merge_requests_route, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['title']).to eq(merge_request.title)
+ expect(json_response.first['milestone']['title']).to eq(milestone.title)
+ end
+
+ it 'returns merge_requests sorted by label priority' do
+ merge_request_1 = create(:labeled_merge_request, source_branch: 'branch_1', source_project: project, milestone: milestone, labels: [label_2])
+ merge_request_2 = create(:labeled_merge_request, source_branch: 'branch_2', source_project: project, milestone: milestone, labels: [label_1])
+ merge_request_3 = create(:labeled_merge_request, source_branch: 'branch_3', source_project: project, milestone: milestone, labels: [label_3])
+
+ get api(merge_requests_route, user)
+
+ expect(json_response.first['id']).to eq(merge_request_2.id)
+ expect(json_response.second['id']).to eq(merge_request_1.id)
+ expect(json_response.third['id']).to eq(merge_request_3.id)
+ end
+
+ it 'returns a 404 error if milestone id not found' do
+ not_found_route = "#{route}/1234/merge_requests"
+
+ get api(not_found_route, user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns a 404 if the user has no access to the milestone' do
+ new_user = create :user
+ get api(merge_requests_route, new_user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns a 401 error if user not authenticated' do
+ get api(merge_requests_route)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'returns merge_requests ordered by position asc' do
+ milestone.merge_requests << another_merge_request
+ another_merge_request.labels << label_1
+ merge_request.labels << label_2
+
+ get api(merge_requests_route, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(2)
+ expect(json_response.first['id']).to eq(another_merge_request.id)
+ expect(json_response.second['id']).to eq(merge_request.id)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
index a793c23b809..bd38417a5db 100644
--- a/spec/support/shared_examples/requests/api/notes.rb
+++ b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
+RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
context 'sorting' do
before do
diff --git a/spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb b/spec/support/shared_examples/requests/api/pipelines/visibility_table_shared_examples.rb
index dfd07176b1c..8dd2ef6ccc6 100644
--- a/spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb
+++ b/spec/support/shared_examples/requests/api/pipelines/visibility_table_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'pipelines visibility table' do
+RSpec.shared_examples 'pipelines visibility table' do
using RSpec::Parameterized::TableSyntax
let(:ci_user) { create(:user) }
diff --git a/spec/support/shared_examples/requests/api/read_user_shared_examples.rb b/spec/support/shared_examples/requests/api/read_user_shared_examples.rb
new file mode 100644
index 00000000000..59cd0ab67b4
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/read_user_shared_examples.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'allows the "read_user" scope' do |api_version|
+ let(:version) { api_version || 'v4' }
+
+ context 'for personal access tokens' do
+ context 'when the requesting token has the "api" scope' do
+ let(:token) { create(:personal_access_token, scopes: ['api'], user: user) }
+
+ it 'returns a "200" response' do
+ get api_call.call(path, user, personal_access_token: token, version: version)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when the requesting token has the "read_user" scope' do
+ let(:token) { create(:personal_access_token, scopes: ['read_user'], user: user) }
+
+ it 'returns a "200" response' do
+ get api_call.call(path, user, personal_access_token: token, version: version)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when the requesting token does not have any required scope' do
+ let(:token) { create(:personal_access_token, scopes: ['read_registry'], user: user) }
+
+ before do
+ stub_container_registry_config(enabled: true)
+ end
+
+ it 'returns a "403" response' do
+ get api_call.call(path, user, personal_access_token: token, version: version)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
+ context 'for doorkeeper (OAuth) tokens' do
+ let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) }
+
+ context 'when the requesting token has the "api" scope' do
+ let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
+
+ it 'returns a "200" response' do
+ get api_call.call(path, user, oauth_access_token: token)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when the requesting token has the "read_user" scope' do
+ let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "read_user" }
+
+ it 'returns a "200" response' do
+ get api_call.call(path, user, oauth_access_token: token)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when the requesting token does not have any required scope' do
+ let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "invalid" }
+
+ it 'returns a "403" response' do
+ get api_call.call(path, user, oauth_access_token: token)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'does not allow the "read_user" scope' do
+ context 'when the requesting token has the "read_user" scope' do
+ let(:token) { create(:personal_access_token, scopes: ['read_user'], user: user) }
+
+ it 'returns a "403" response' do
+ post api_call.call(path, user, personal_access_token: token), params: attributes_for(:user, projects_limit: 3)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/repositories_shared_context.rb b/spec/support/shared_examples/requests/api/repositories_shared_context.rb
new file mode 100644
index 00000000000..cc3a495bec1
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/repositories_shared_context.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'disabled repository' do
+ before do
+ project.project_feature.update!(
+ repository_access_level: ProjectFeature::DISABLED,
+ merge_requests_access_level: ProjectFeature::DISABLED,
+ builds_access_level: ProjectFeature::DISABLED
+ )
+ expect(project.feature_available?(:repository, current_user)).to be false
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/resolvable_discussions.rb b/spec/support/shared_examples/requests/api/resolvable_discussions_shared_examples.rb
index dd764cf2d4d..8d2a3f13d8e 100644
--- a/spec/support/shared_examples/requests/api/resolvable_discussions.rb
+++ b/spec/support/shared_examples/requests/api/resolvable_discussions_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_name|
+RSpec.shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_name|
describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id" do
it "resolves discussion if resolved is true" do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
diff --git a/spec/support/shared_examples/resource_label_events_api.rb b/spec/support/shared_examples/requests/api/resource_label_events_api_shared_examples.rb
index d3d9b83764d..520c3ea8e47 100644
--- a/spec/support/shared_examples/resource_label_events_api.rb
+++ b/spec/support/shared_examples/requests/api/resource_label_events_api_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'resource_label_events API' do |parent_type, eventable_type, id_name|
+RSpec.shared_examples 'resource_label_events API' do |parent_type, eventable_type, id_name|
describe "GET /#{parent_type}/:id/#{eventable_type}/:noteable_id/resource_label_events" do
context "with local label reference" do
let!(:event) { create_event(label) }
diff --git a/spec/support/shared_examples/requests/api/status_shared_examples.rb b/spec/support/shared_examples/requests/api/status_shared_examples.rb
index d5845863a58..8207190b1dc 100644
--- a/spec/support/shared_examples/requests/api/status_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/status_shared_examples.rb
@@ -4,7 +4,7 @@
#
# Requires an API request:
# let(:request) { get api("/projects/#{project.id}/repository/branches", user) }
-shared_examples_for '400 response' do
+RSpec.shared_examples '400 response' do
let(:message) { nil }
before do
@@ -21,7 +21,7 @@ shared_examples_for '400 response' do
end
end
-shared_examples_for '403 response' do
+RSpec.shared_examples '403 response' do
before do
# Fires the request
request
@@ -32,7 +32,7 @@ shared_examples_for '403 response' do
end
end
-shared_examples_for '404 response' do
+RSpec.shared_examples '404 response' do
let(:message) { nil }
before do
@@ -50,7 +50,7 @@ shared_examples_for '404 response' do
end
end
-shared_examples_for '412 response' do
+RSpec.shared_examples '412 response' do
let(:params) { nil }
let(:success_status) { 204 }
diff --git a/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb b/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb
new file mode 100644
index 00000000000..30ba8d9b436
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb
@@ -0,0 +1,148 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'an unauthorized API user' do
+ it { is_expected.to eq(403) }
+end
+
+RSpec.shared_examples 'time tracking endpoints' do |issuable_name|
+ let(:non_member) { create(:user) }
+
+ issuable_collection_name = issuable_name.pluralize
+
+ describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_estimate" do
+ context 'with an unauthorized user' do
+ subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", non_member), params: { duration: '1w' }) }
+
+ it_behaves_like 'an unauthorized API user'
+ end
+
+ it "sets the time estimate for #{issuable_name}" do
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: '1w' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['human_time_estimate']).to eq('1w')
+ end
+
+ describe 'updating the current estimate' do
+ before do
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: '1w' }
+ end
+
+ context 'when duration has a bad format' do
+ it 'does not modify the original estimate' do
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: 'foo' }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(issuable.reload.human_time_estimate).to eq('1w')
+ end
+ end
+
+ context 'with a valid duration' do
+ it 'updates the estimate' do
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: '3w1h' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(issuable.reload.human_time_estimate).to eq('3w 1h')
+ end
+ end
+ end
+ end
+
+ describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/reset_time_estimate" do
+ context 'with an unauthorized user' do
+ subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/reset_time_estimate", non_member)) }
+
+ it_behaves_like 'an unauthorized API user'
+ end
+
+ it "resets the time estimate for #{issuable_name}" do
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/reset_time_estimate", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['time_estimate']).to eq(0)
+ end
+ end
+
+ describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/add_spent_time" do
+ context 'with an unauthorized user' do
+ subject do
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", non_member), params: { duration: '2h' }
+ end
+
+ it_behaves_like 'an unauthorized API user'
+ end
+
+ it "add spent time for #{issuable_name}" do
+ Timecop.travel(1.minute.from_now) do
+ expect do
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '2h' }
+ end.to change { issuable.reload.updated_at }
+ end
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['human_total_time_spent']).to eq('2h')
+ end
+
+ context 'when subtracting time' do
+ it 'subtracts time of the total spent time' do
+ Timecop.travel(1.minute.from_now) do
+ expect do
+ issuable.update!(spend_time: { duration: 7200, user_id: user.id })
+ end.to change { issuable.reload.updated_at }
+ end
+
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '-1h' }
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['total_time_spent']).to eq(3600)
+ end
+ end
+
+ context 'when time to subtract is greater than the total spent time' do
+ it 'does not modify the total time spent' do
+ issuable.update!(spend_time: { duration: 7200, user_id: user.id })
+
+ Timecop.travel(1.minute.from_now) do
+ expect do
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '-1w' }
+ end.not_to change { issuable.reload.updated_at }
+ end
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']['time_spent'].first).to match(/exceeds the total time spent/)
+ end
+ end
+ end
+
+ describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/reset_spent_time" do
+ context 'with an unauthorized user' do
+ subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/reset_spent_time", non_member)) }
+
+ it_behaves_like 'an unauthorized API user'
+ end
+
+ it "resets spent time for #{issuable_name}" do
+ Timecop.travel(1.minute.from_now) do
+ expect do
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/reset_spent_time", user)
+ end.to change { issuable.reload.updated_at }
+ end
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['total_time_spent']).to eq(0)
+ end
+ end
+
+ describe "GET /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_stats" do
+ it "returns the time stats for #{issuable_name}" do
+ issuable.update!(spend_time: { duration: 1800, user_id: user.id },
+ time_estimate: 3600)
+
+ get api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_stats", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['total_time_spent']).to eq(1800)
+ expect(json_response['time_estimate']).to eq(3600)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/graphql_shared_examples.rb b/spec/support/shared_examples/requests/graphql_shared_examples.rb
index 2a38d56141a..0045fe14501 100644
--- a/spec/support/shared_examples/requests/graphql_shared_examples.rb
+++ b/spec/support/shared_examples/requests/graphql_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
-
-shared_examples 'a working graphql query' do
+RSpec.shared_examples 'a working graphql query' do
include GraphqlHelpers
it 'returns a successful response', :aggregate_failures do
diff --git a/spec/support/shared_examples/lfs_http_shared_examples.rb b/spec/support/shared_examples/requests/lfs_http_shared_examples.rb
index bcd30fe9654..48c5a5933e6 100644
--- a/spec/support/shared_examples/lfs_http_shared_examples.rb
+++ b/spec/support/shared_examples/requests/lfs_http_shared_examples.rb
@@ -1,38 +1,38 @@
# frozen_string_literal: true
-shared_examples 'LFS http 200 response' do
+RSpec.shared_examples 'LFS http 200 response' do
it_behaves_like 'LFS http expected response code and message' do
let(:response_code) { 200 }
end
end
-shared_examples 'LFS http 401 response' do
+RSpec.shared_examples 'LFS http 401 response' do
it_behaves_like 'LFS http expected response code and message' do
let(:response_code) { 401 }
end
end
-shared_examples 'LFS http 403 response' do
+RSpec.shared_examples 'LFS http 403 response' do
it_behaves_like 'LFS http expected response code and message' do
let(:response_code) { 403 }
let(:message) { 'Access forbidden. Check your access level.' }
end
end
-shared_examples 'LFS http 501 response' do
+RSpec.shared_examples 'LFS http 501 response' do
it_behaves_like 'LFS http expected response code and message' do
let(:response_code) { 501 }
let(:message) { 'Git LFS is not enabled on this GitLab server, contact your admin.' }
end
end
-shared_examples 'LFS http 404 response' do
+RSpec.shared_examples 'LFS http 404 response' do
it_behaves_like 'LFS http expected response code and message' do
let(:response_code) { 404 }
end
end
-shared_examples 'LFS http expected response code and message' do
+RSpec.shared_examples 'LFS http expected response code and message' do
let(:response_code) { }
let(:message) { }
diff --git a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
index a864f3ac652..08ccbd4a9c1 100644
--- a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
+++ b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
@@ -8,7 +8,7 @@
# * requests_per_period
# * period_in_seconds
# * period
-shared_examples_for 'rate-limited token-authenticated requests' do
+RSpec.shared_examples 'rate-limited token-authenticated requests' do
let(:throttle_types) do
{
"throttle_protected_paths" => "throttle_authenticated_protected_paths_api",
@@ -134,7 +134,7 @@ end
# * requests_per_period
# * period_in_seconds
# * period
-shared_examples_for 'rate-limited web authenticated requests' do
+RSpec.shared_examples 'rate-limited web authenticated requests' do
let(:throttle_types) do
{
"throttle_protected_paths" => "throttle_authenticated_protected_paths_web",
diff --git a/spec/support/shared_examples/routing/legacy_path_redirect_shared_examples.rb b/spec/support/shared_examples/routing/legacy_path_redirect_shared_examples.rb
new file mode 100644
index 00000000000..808336db7b1
--- /dev/null
+++ b/spec/support/shared_examples/routing/legacy_path_redirect_shared_examples.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'redirecting a legacy project path' do |source, target|
+ include RSpec::Rails::RequestExampleGroup
+
+ it "redirects #{source} to #{target}" do
+ expect(get(source)).to redirect_to(target)
+ end
+end
diff --git a/spec/support/shared_examples/serializers/diff_file_entity_examples.rb b/spec/support/shared_examples/serializers/diff_file_entity_shared_examples.rb
index d2c269c597c..db5c4b45b70 100644
--- a/spec/support/shared_examples/serializers/diff_file_entity_examples.rb
+++ b/spec/support/shared_examples/serializers/diff_file_entity_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'diff file base entity' do
+RSpec.shared_examples 'diff file base entity' do
it 'exposes essential attributes' do
expect(subject).to include(:content_sha, :submodule, :submodule_link,
:submodule_tree_url, :old_path_html,
@@ -26,7 +26,7 @@ shared_examples 'diff file base entity' do
end
end
-shared_examples 'diff file entity' do
+RSpec.shared_examples 'diff file entity' do
it_behaves_like 'diff file base entity'
it 'exposes correct attributes' do
@@ -70,6 +70,6 @@ shared_examples 'diff file entity' do
end
end
-shared_examples 'diff file discussion entity' do
+RSpec.shared_examples 'diff file discussion entity' do
it_behaves_like 'diff file base entity'
end
diff --git a/spec/support/shared_examples/serializers/note_entity_examples.rb b/spec/support/shared_examples/serializers/note_entity_shared_examples.rb
index bfcaa2f1bd5..7b2ec02c7b6 100644
--- a/spec/support/shared_examples/serializers/note_entity_examples.rb
+++ b/spec/support/shared_examples/serializers/note_entity_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'note entity' do
+RSpec.shared_examples 'note entity' do
subject { entity.as_json }
context 'basic note' do
diff --git a/spec/support/shared_examples/services/base_helm_service_shared_examples.rb b/spec/support/shared_examples/services/base_helm_service_shared_examples.rb
index 19f5334b4b2..c2252c83140 100644
--- a/spec/support/shared_examples/services/base_helm_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/base_helm_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'logs kubernetes errors' do
+RSpec.shared_examples 'logs kubernetes errors' do
let(:error_hash) do
{
service: service.class.name,
diff --git a/spec/support/shared_examples/services/boards/boards_create_service.rb b/spec/support/shared_examples/services/boards/boards_create_service_shared_examples.rb
index 7fd69354c2d..fced2e59ace 100644
--- a/spec/support/shared_examples/services/boards/boards_create_service.rb
+++ b/spec/support/shared_examples/services/boards/boards_create_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'boards create service' do
+RSpec.shared_examples 'boards create service' do
context 'when parent does not have a board' do
it 'creates a new board' do
expect { service.execute }.to change(Board, :count).by(1)
diff --git a/spec/support/shared_examples/services/boards/boards_list_service.rb b/spec/support/shared_examples/services/boards/boards_list_service_shared_examples.rb
index 18d45ee324a..97fe39a4494 100644
--- a/spec/support/shared_examples/services/boards/boards_list_service.rb
+++ b/spec/support/shared_examples/services/boards/boards_list_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'boards list service' do
+RSpec.shared_examples 'boards list service' do
context 'when parent does not have a board' do
it 'creates a new parent board' do
expect { service.execute }.to change(parent.boards, :count).by(1)
@@ -30,7 +30,7 @@ shared_examples 'boards list service' do
end
end
-shared_examples 'multiple boards list service' do
+RSpec.shared_examples 'multiple boards list service' do
let(:service) { described_class.new(parent, double) }
let!(:board_B) { create(:board, resource_parent: parent, name: 'B-board') }
let!(:board_c) { create(:board, resource_parent: parent, name: 'c-board') }
diff --git a/spec/support/shared_examples/services/boards/issues_list_service.rb b/spec/support/shared_examples/services/boards/issues_list_service_shared_examples.rb
index 75733c774ef..56f9e811799 100644
--- a/spec/support/shared_examples/services/boards/issues_list_service.rb
+++ b/spec/support/shared_examples/services/boards/issues_list_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issues list service' do
+RSpec.shared_examples 'issues list service' do
it 'delegates search to IssuesFinder' do
params = { board_id: board.id, id: list1.id }
diff --git a/spec/support/shared_examples/services/boards/issues_move_service.rb b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
index d3fa8084185..f352b430cc7 100644
--- a/spec/support/shared_examples/services/boards/issues_move_service.rb
+++ b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issues move service' do |group|
+RSpec.shared_examples 'issues move service' do |group|
shared_examples 'updating timestamps' do
it 'updates updated_at' do
expect {described_class.new(parent, user, params).execute(issue)}
diff --git a/spec/support/shared_examples/services/boards/lists_destroy_service.rb b/spec/support/shared_examples/services/boards/lists_destroy_service_shared_examples.rb
index 95725078f9d..6a4f284ec54 100644
--- a/spec/support/shared_examples/services/boards/lists_destroy_service.rb
+++ b/spec/support/shared_examples/services/boards/lists_destroy_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'lists destroy service' do
+RSpec.shared_examples 'lists destroy service' do
context 'when list type is label' do
it 'removes list from board' do
list = create(:list, board: board)
diff --git a/spec/support/shared_examples/services/boards/lists_list_service.rb b/spec/support/shared_examples/services/boards/lists_list_service_shared_examples.rb
index 29784f6da08..1b7fe626aea 100644
--- a/spec/support/shared_examples/services/boards/lists_list_service.rb
+++ b/spec/support/shared_examples/services/boards/lists_list_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'lists list service' do
+RSpec.shared_examples 'lists list service' do
context 'when the board has a backlog list' do
let!(:backlog_list) { create(:backlog_list, board: board) }
diff --git a/spec/support/shared_examples/services/boards/lists_move_service.rb b/spec/support/shared_examples/services/boards/lists_move_service_shared_examples.rb
index 0b3bfd8e2a8..bf84b912610 100644
--- a/spec/support/shared_examples/services/boards/lists_move_service.rb
+++ b/spec/support/shared_examples/services/boards/lists_move_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'lists move service' do
+RSpec.shared_examples 'lists move service' do
let!(:planning) { create(:list, board: board, position: 0) }
let!(:development) { create(:list, board: board, position: 1) }
let!(:review) { create(:list, board: board, position: 2) }
diff --git a/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb b/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb
index 1e0ac8b7615..e1efe61cce3 100644
--- a/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'check ingress ip executions' do |app_name|
+RSpec.shared_examples 'check ingress ip executions' do |app_name|
describe '#execute' do
let(:application) { create(app_name, :installed) }
let(:service) { described_class.new(application) }
diff --git a/spec/support/shared_examples/common_system_notes_examples.rb b/spec/support/shared_examples/services/common_system_notes_shared_examples.rb
index ca79603a022..4ce3e32d774 100644
--- a/spec/support/shared_examples/common_system_notes_examples.rb
+++ b/spec/support/shared_examples/services/common_system_notes_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'system note creation' do |update_params, note_text|
+RSpec.shared_examples 'system note creation' do |update_params, note_text|
subject { described_class.new(project, user).execute(issuable, old_labels: []) }
before do
@@ -17,7 +17,7 @@ shared_examples 'system note creation' do |update_params, note_text|
end
end
-shared_examples 'WIP notes creation' do |wip_action|
+RSpec.shared_examples 'WIP notes creation' do |wip_action|
subject { described_class.new(project, user).execute(issuable, old_labels: []) }
it 'creates WIP toggle and title change notes' do
@@ -28,7 +28,7 @@ shared_examples 'WIP notes creation' do |wip_action|
end
end
-shared_examples_for 'a note with overridable created_at' do
+RSpec.shared_examples 'a note with overridable created_at' do
let(:noteable) { create(:issue, project: project, system_note_timestamp: Time.at(42)) }
it 'the note has the correct time' do
@@ -36,7 +36,7 @@ shared_examples_for 'a note with overridable created_at' do
end
end
-shared_examples_for 'a system note' do |params|
+RSpec.shared_examples 'a system note' do |params|
let(:expected_noteable) { noteable }
let(:commit_count) { nil }
diff --git a/spec/support/shared_examples/services/count_service_shared_examples.rb b/spec/support/shared_examples/services/count_service_shared_examples.rb
index 9bea180a778..54c6ff79976 100644
--- a/spec/support/shared_examples/services/count_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/count_service_shared_examples.rb
@@ -6,7 +6,7 @@
# describe MyCountService, :use_clean_rails_memory_store_caching do
# it_behaves_like 'a counter caching service'
# end
-shared_examples 'a counter caching service' do
+RSpec.shared_examples 'a counter caching service' do
describe '#count' do
it 'caches the count', :request_store do
subject.delete_cache
diff --git a/spec/support/shared_examples/services/error_tracking_service_shared_examples.rb b/spec/support/shared_examples/services/error_tracking_service_shared_examples.rb
index 83c6d89e560..c825a970b57 100644
--- a/spec/support/shared_examples/services/error_tracking_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/error_tracking_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'error tracking service data not ready' do |service_call|
+RSpec.shared_examples 'error tracking service data not ready' do |service_call|
context "when #{service_call} returns nil" do
before do
expect(error_tracking_setting)
@@ -14,7 +14,7 @@ shared_examples 'error tracking service data not ready' do |service_call|
end
end
-shared_examples 'error tracking service sentry error handling' do |service_call|
+RSpec.shared_examples 'error tracking service sentry error handling' do |service_call|
context "when #{service_call} returns error" do
before do
allow(error_tracking_setting)
@@ -35,7 +35,7 @@ shared_examples 'error tracking service sentry error handling' do |service_call|
end
end
-shared_examples 'error tracking service http status handling' do |service_call|
+RSpec.shared_examples 'error tracking service http status handling' do |service_call|
context "when #{service_call} returns error with http_status" do
before do
allow(error_tracking_setting)
@@ -56,7 +56,7 @@ shared_examples 'error tracking service http status handling' do |service_call|
end
end
-shared_examples 'error tracking service unauthorized user' do
+RSpec.shared_examples 'error tracking service unauthorized user' do
context 'with unauthorized user' do
let(:unauthorized_user) { create(:user) }
@@ -74,7 +74,7 @@ shared_examples 'error tracking service unauthorized user' do
end
end
-shared_examples 'error tracking service disabled' do
+RSpec.shared_examples 'error tracking service disabled' do
context 'with error tracking disabled' do
before do
error_tracking_setting.enabled = false
diff --git a/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb b/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb
index 1c3fa5644d3..2aac7e328f0 100644
--- a/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'gitlab projects import validations' do
+RSpec.shared_examples 'gitlab projects import validations' do
context 'with an invalid path' do
let(:path) { '/invalid-path/' }
diff --git a/spec/support/shared_examples/issuable_shared_examples.rb b/spec/support/shared_examples/services/issuable_shared_examples.rb
index 3460a8ba297..9eb66e33513 100644
--- a/spec/support/shared_examples/issuable_shared_examples.rb
+++ b/spec/support/shared_examples/services/issuable_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'cache counters invalidator' do
+RSpec.shared_examples 'cache counters invalidator' do
it 'invalidates counter cache for assignees' do
expect_any_instance_of(User).to receive(:invalidate_merge_request_cache_counts)
@@ -8,7 +8,7 @@ shared_examples 'cache counters invalidator' do
end
end
-shared_examples 'system notes for milestones' do
+RSpec.shared_examples 'system notes for milestones' do
def update_issuable(opts)
issuable = try(:issue) || try(:merge_request)
described_class.new(project, user, opts).execute(issuable)
@@ -39,7 +39,7 @@ shared_examples 'system notes for milestones' do
end
end
-shared_examples 'updating a single task' do
+RSpec.shared_examples 'updating a single task' do
def update_issuable(opts)
issuable = try(:issue) || try(:merge_request)
described_class.new(project, user, opts).execute(issuable)
diff --git a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
index 30d91346df3..66a6c073445 100644
--- a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
+++ b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'misconfigured dashboard service response' do |status_code, message = nil|
+RSpec.shared_examples 'misconfigured dashboard service response' do |status_code, message = nil|
it 'returns an appropriate message and status code', :aggregate_failures do
result = service_call
@@ -11,7 +11,7 @@ shared_examples_for 'misconfigured dashboard service response' do |status_code,
end
end
-shared_examples_for 'valid dashboard service response for schema' do
+RSpec.shared_examples 'valid dashboard service response for schema' do
it 'returns a json representation of the dashboard' do
result = service_call
@@ -22,13 +22,13 @@ shared_examples_for 'valid dashboard service response for schema' do
end
end
-shared_examples_for 'valid dashboard service response' do
+RSpec.shared_examples 'valid dashboard service response' do
let(:dashboard_schema) { JSON.parse(fixture_file('lib/gitlab/metrics/dashboard/schemas/dashboard.json')) }
it_behaves_like 'valid dashboard service response for schema'
end
-shared_examples_for 'caches the unprocessed dashboard for subsequent calls' do
+RSpec.shared_examples 'caches the unprocessed dashboard for subsequent calls' do
it do
expect(YAML).to receive(:safe_load).once.and_call_original
@@ -37,13 +37,13 @@ shared_examples_for 'caches the unprocessed dashboard for subsequent calls' do
end
end
-shared_examples_for 'valid embedded dashboard service response' do
+RSpec.shared_examples 'valid embedded dashboard service response' do
let(:dashboard_schema) { JSON.parse(fixture_file('lib/gitlab/metrics/dashboard/schemas/embedded_dashboard.json')) }
it_behaves_like 'valid dashboard service response for schema'
end
-shared_examples_for 'raises error for users with insufficient permissions' do
+RSpec.shared_examples 'raises error for users with insufficient permissions' do
context 'when the user does not have sufficient access' do
let(:user) { build(:user) }
diff --git a/spec/support/shared_examples/services/notification_service_shared_examples.rb b/spec/support/shared_examples/services/notification_service_shared_examples.rb
index ad580b581d6..b4d52d24de4 100644
--- a/spec/support/shared_examples/services/notification_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/notification_service_shared_examples.rb
@@ -3,7 +3,7 @@
# Note that we actually update the attribute on the target_project/group, rather than
# using `allow`. This is because there are some specs where, based on how the notification
# is done, using an `allow` doesn't change the correct object.
-shared_examples 'project emails are disabled' do
+RSpec.shared_examples 'project emails are disabled' do
let(:target_project) { notification_target.is_a?(Project) ? notification_target : notification_target.project }
before do
@@ -28,7 +28,7 @@ shared_examples 'project emails are disabled' do
end
end
-shared_examples 'group emails are disabled' do
+RSpec.shared_examples 'group emails are disabled' do
let(:target_group) { notification_target.is_a?(Group) ? notification_target : notification_target.project.group }
before do
@@ -53,7 +53,7 @@ shared_examples 'group emails are disabled' do
end
end
-shared_examples 'sends notification only to a maximum of ten, most recently active group owners' do
+RSpec.shared_examples 'sends notification only to a maximum of ten, most recently active group owners' do
let(:owners) { create_list(:user, 12, :with_sign_ins) }
before do
@@ -75,7 +75,7 @@ shared_examples 'sends notification only to a maximum of ten, most recently acti
end
end
-shared_examples 'sends notification only to a maximum of ten, most recently active project maintainers' do
+RSpec.shared_examples 'sends notification only to a maximum of ten, most recently active project maintainers' do
let(:maintainers) { create_list(:user, 12, :with_sign_ins) }
before do
diff --git a/spec/support/shared_examples/pages_size_limit_shared_examples.rb b/spec/support/shared_examples/services/pages_size_limit_shared_examples.rb
index c1e27194738..15bf0d3698a 100644
--- a/spec/support/shared_examples/pages_size_limit_shared_examples.rb
+++ b/spec/support/shared_examples/services/pages_size_limit_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'pages size limit is' do |size_limit|
+RSpec.shared_examples 'pages size limit is' do |size_limit|
context "when size is below the limit" do
before do
allow(metadata).to receive(:total_size).and_return(size_limit - 1.megabyte)
diff --git a/spec/support/shared_examples/updating_mentions_shared_examples.rb b/spec/support/shared_examples/services/updating_mentions_shared_examples.rb
index 84f6c4d136a..84f6c4d136a 100644
--- a/spec/support/shared_examples/updating_mentions_shared_examples.rb
+++ b/spec/support/shared_examples/services/updating_mentions_shared_examples.rb
diff --git a/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb b/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb
index 9263aaff89a..12bcbb8b812 100644
--- a/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb
+++ b/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples "matches the method pattern" do |method|
+RSpec.shared_examples "matches the method pattern" do |method|
let(:target) { subject }
let(:args) { nil }
let(:pattern) { patterns[method] }
@@ -12,7 +12,7 @@ shared_examples "matches the method pattern" do |method|
end
end
-shared_examples "builds correct paths" do |**patterns|
+RSpec.shared_examples "builds correct paths" do |**patterns|
let(:patterns) { patterns }
before do
diff --git a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
index 5d605dd811b..f8b00d1e4c0 100644
--- a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
+++ b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
@@ -1,12 +1,12 @@
# frozen_string_literal: true
-shared_context 'with storage' do |store, **stub_params|
+RSpec.shared_context 'with storage' do |store, **stub_params|
before do
subject.object_store = store
end
end
-shared_examples "migrates" do |to_store:, from_store: nil|
+RSpec.shared_examples "migrates" do |to_store:, from_store: nil|
let(:to) { to_store }
let(:from) { from_store || subject.object_store }
diff --git a/spec/support/shared_examples/uploaders/upload_type_shared_examples.rb b/spec/support/shared_examples/uploaders/upload_type_shared_examples.rb
index 91d2526cde2..6e5075e135d 100644
--- a/spec/support/shared_examples/uploaders/upload_type_shared_examples.rb
+++ b/spec/support/shared_examples/uploaders/upload_type_shared_examples.rb
@@ -5,13 +5,13 @@ def check_content_matches_extension!(file = double(read: nil, path: ''))
uploader.check_content_matches_extension!(magic_file)
end
-shared_examples 'upload passes content type check' do
+RSpec.shared_examples 'upload passes content type check' do
it 'does not raise error' do
expect { check_content_matches_extension! }.not_to raise_error
end
end
-shared_examples 'upload fails content type check' do
+RSpec.shared_examples 'upload fails content type check' do
it 'raises error' do
expect { check_content_matches_extension! }.to raise_error(CarrierWave::IntegrityError)
end
@@ -42,7 +42,7 @@ def upload_type_checked_fixtures(upload_fixtures)
end
end
-shared_examples 'type checked uploads' do |upload_fixtures = nil, filenames: nil|
+RSpec.shared_examples 'type checked uploads' do |upload_fixtures = nil, filenames: nil|
it 'check type' do
upload_fixtures = Array(upload_fixtures)
filenames = Array(filenames)
@@ -55,7 +55,7 @@ shared_examples 'type checked uploads' do |upload_fixtures = nil, filenames: nil
end
end
-shared_examples 'skipped type checked uploads' do |upload_fixtures = nil, filenames: nil|
+RSpec.shared_examples 'skipped type checked uploads' do |upload_fixtures = nil, filenames: nil|
it 'skip type check' do
expect(uploader).not_to receive(:check_content_matches_extension!)
diff --git a/spec/support/shared_examples/url_validator_examples.rb b/spec/support/shared_examples/validators/url_validator_shared_examples.rb
index c5a775fefb6..c5a775fefb6 100644
--- a/spec/support/shared_examples/url_validator_examples.rb
+++ b/spec/support/shared_examples/validators/url_validator_shared_examples.rb
diff --git a/spec/support/shared_examples/views/nav_sidebar.rb b/spec/support/shared_examples/views/nav_sidebar_shared_examples.rb
index 6ac5abe275d..fe9a681377c 100644
--- a/spec/support/shared_examples/views/nav_sidebar.rb
+++ b/spec/support/shared_examples/views/nav_sidebar_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'has nav sidebar' do
+RSpec.shared_examples 'has nav sidebar' do
it 'has collapsed nav sidebar on mobile' do
render
diff --git a/spec/support/shared_examples/workers/concerns/reenqueuer_shared_examples.rb b/spec/support/shared_examples/workers/concerns/reenqueuer_shared_examples.rb
index 7dffbb04fdc..50879969e90 100644
--- a/spec/support/shared_examples/workers/concerns/reenqueuer_shared_examples.rb
+++ b/spec/support/shared_examples/workers/concerns/reenqueuer_shared_examples.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
# Expects `worker_class` to be defined
-shared_examples_for 'reenqueuer' do
+RSpec.shared_examples 'reenqueuer' do
subject(:job) { worker_class.new }
before do
@@ -28,7 +28,7 @@ end
# let(:rate_limited_method) { subject.perform }
# end
#
-shared_examples_for 'it is rate limited to 1 call per' do |minimum_duration|
+RSpec.shared_examples 'it is rate limited to 1 call per' do |minimum_duration|
before do
# Allow Timecop freeze and travel without the block form
Timecop.safe_mode = false