Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-09-20 02:18:09 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-09-20 02:18:09 +0300
commit6ed4ec3e0b1340f96b7c043ef51d1b33bbe85fde (patch)
treedc4d20fe6064752c0bd323187252c77e0a89144b /spec/support/shared_examples
parent9868dae7fc0655bd7ce4a6887d4e6d487690eeed (diff)
Add latest changes from gitlab-org/gitlab@15-4-stable-eev15.4.0-rc42
Diffstat (limited to 'spec/support/shared_examples')
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/ci/edit_job_token_scope_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/controllers/concerns/web_hooks/integrations_hook_log_actions_shared_examples.rb47
-rw-r--r--spec/support/shared_examples/controllers/error_tracking_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb27
-rw-r--r--spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb2
-rw-r--r--spec/support/shared_examples/features/board_sidebar_labels_examples.rb2
-rw-r--r--spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/content_editor_shared_examples.rb121
-rw-r--r--spec/support/shared_examples/features/deploy_token_shared_examples.rb21
-rw-r--r--spec/support/shared_examples/features/discussion_comments_shared_example.rb4
-rw-r--r--spec/support/shared_examples/features/manage_applications_shared_examples.rb92
-rw-r--r--spec/support/shared_examples/features/packages_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/features/protected_branches_with_deploy_keys_examples.rb6
-rw-r--r--spec/support/shared_examples/features/rss_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/runners_shared_examples.rb44
-rw-r--r--spec/support/shared_examples/features/snippets_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/variable_list_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/finders/issues_finder_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/graphql/members_shared_examples.rb13
-rw-r--r--spec/support/shared_examples/graphql/n_plus_one_query_examples.rb2
-rw-r--r--spec/support/shared_examples/graphql/resolvers/issuable_resolvers_shared_examples.rb99
-rw-r--r--spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb26
-rw-r--r--spec/support/shared_examples/lib/cache_helpers_shared_examples.rb139
-rw-r--r--spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb126
-rw-r--r--spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb2
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/lib/gitlab/sql/set_operator_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/sentry/client_shared_examples.rb49
-rw-r--r--spec/support/shared_examples/models/chat_integration_shared_examples.rb51
-rw-r--r--spec/support/shared_examples/models/cluster_application_core_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb2
-rw-r--r--spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/label_note_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/members_notifications_shared_example.rb4
-rw-r--r--spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/synthetic_note_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/update_project_statistics_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/models/wiki_shared_examples.rb162
-rw-r--r--spec/support/shared_examples/namespaces/traversal_scope_examples.rb16
-rw-r--r--spec/support/shared_examples/policies/project_policy_shared_examples.rb150
-rw-r--r--spec/support/shared_examples/projects/container_repository/cleanup_tags_service_shared_examples.rb263
-rw-r--r--spec/support/shared_examples/quick_actions/incident/timeline_quick_action_shared_examples.rb82
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb54
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb17
-rw-r--r--spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb14
-rw-r--r--spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/requests/api/helm_packages_shared_examples.rb6
-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/labels_api_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/requests/api/packages_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/resource_state_events_api_shared_examples.rb82
-rw-r--r--spec/support/shared_examples/requests/api/rubygems_packages_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/requests/api/snippets_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/applications_controller_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/requests/lfs_http_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/projects/google_cloud/google_cloud_ff_examples.rb18
-rw-r--r--spec/support/shared_examples/requests/projects/google_cloud/google_cloud_role_examples.rb55
-rw-r--r--spec/support/shared_examples/requests/projects/google_cloud/google_oauth2_config_examples.rb22
-rw-r--r--spec/support/shared_examples/requests/projects/google_cloud/google_oauth2_token_examples.rb47
-rw-r--r--spec/support/shared_examples/requests/rack_attack_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/routing/resource_routing_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/routing/wiki_routing_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/security_training_providers_importer.rb14
-rw-r--r--spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb38
-rw-r--r--spec/support/shared_examples/services/common_system_notes_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb20
-rw-r--r--spec/support/shared_examples/services/feature_flags/client_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/services/issuable/update_service_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/services/issuable_links/create_links_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/merge_request_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/onboarding_progress_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/packages_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/services/resource_events/synthetic_notes_builder_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/snippets_shared_examples.rb5
-rw-r--r--spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/tasks/gitlab/uploads/migration_shared_examples.rb31
-rw-r--r--spec/support/shared_examples/uploaders/object_storage_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/users/migrate_records_to_ghost_user_service_shared_examples.rb39
100 files changed, 1813 insertions, 511 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 0e6f6f12c3f..fa048b76e18 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
@@ -125,6 +125,31 @@ RSpec.shared_examples 'multiple issue boards' do
wait_for_requests
end
+ it 'shows current board name' do
+ page.within('.boards-switcher') do
+ expect(page).to have_content(board.name)
+ end
+ end
+
+ it 'shows a list of boards' do
+ in_boards_switcher_dropdown do
+ expect(page).to have_content(board.name)
+ expect(page).to have_content(board2.name)
+ end
+ end
+
+ it 'switches current board' do
+ in_boards_switcher_dropdown do
+ click_button board2.name
+ end
+
+ wait_for_requests
+
+ page.within('.boards-switcher') do
+ expect(page).to have_content(board2.name)
+ end
+ end
+
it 'does not show action links' do
in_boards_switcher_dropdown do
expect(page).not_to have_content('Create new board')
diff --git a/spec/support/shared_examples/ci/edit_job_token_scope_shared_examples.rb b/spec/support/shared_examples/ci/edit_job_token_scope_shared_examples.rb
index 05b2b5f5de1..d8333ae25ad 100644
--- a/spec/support/shared_examples/ci/edit_job_token_scope_shared_examples.rb
+++ b/spec/support/shared_examples/ci/edit_job_token_scope_shared_examples.rb
@@ -8,14 +8,6 @@ RSpec.shared_examples 'editable job token scope' do
end
end
- context 'when job token scope is disabled for the given project' do
- before do
- allow(project).to receive(:ci_job_token_scope_enabled?).and_return(false)
- end
-
- it_behaves_like 'returns error', 'Job token scope is disabled for this project'
- end
-
context 'when user does not have permissions to edit the job token scope' do
it_behaves_like 'returns error', 'Insufficient permissions to modify the job token scope'
end
diff --git a/spec/support/shared_examples/controllers/concerns/web_hooks/integrations_hook_log_actions_shared_examples.rb b/spec/support/shared_examples/controllers/concerns/web_hooks/integrations_hook_log_actions_shared_examples.rb
new file mode 100644
index 00000000000..62c9c3508a8
--- /dev/null
+++ b/spec/support/shared_examples/controllers/concerns/web_hooks/integrations_hook_log_actions_shared_examples.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples WebHooks::HookLogActions do
+ let!(:show_path) { web_hook_log.present.details_path }
+ let!(:retry_path) { web_hook_log.present.retry_path }
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'GET #show' do
+ it 'renders a 200 if the hook exists' do
+ get show_path
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('hook_logs/show')
+ end
+
+ it 'renders a 404 if the hook does not exist' do
+ web_hook.destroy!
+ get show_path
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ describe 'POST #retry' do
+ it 'executes the hook and redirects to the service form' do
+ stub_request(:post, web_hook.url)
+
+ expect_next_found_instance_of(web_hook.class) do |hook|
+ expect(hook).to receive(:execute).and_call_original
+ end
+
+ post retry_path
+
+ expect(response).to redirect_to(edit_hook_path)
+ end
+
+ it 'renders a 404 if the hook does not exist' do
+ web_hook.destroy!
+ post retry_path
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+end
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 08e5efcf63c..1bf2f158504 100644
--- a/spec/support/shared_examples/controllers/error_tracking_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/error_tracking_shared_examples.rb
@@ -3,5 +3,5 @@
RSpec.shared_examples 'sets the polling header' do
subject { response.headers[Gitlab::PollingInterval::HEADER_NAME] }
- it { is_expected.to eq '1000'}
+ it { is_expected.to eq '1000' }
end
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
index 5faf462c23c..bbbe93a644f 100644
--- a/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
@@ -241,12 +241,11 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do
let(:provider_user) { double('user', login: provider_username) }
let(:project) { create(:project, import_type: provider, import_status: :finished, import_source: "#{provider_username}/vim") }
let(:provider_repo) do
- double(
- 'provider',
+ {
name: 'vim',
full_name: "#{provider_username}/vim",
owner: double('owner', login: provider_username)
- )
+ }
end
before do
@@ -256,7 +255,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do
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, type: provider, **access_params)
+ .to receive(:new).with(provider_repo, provider_repo[:name], user.namespace, user, type: provider, **access_params)
.and_return(double(execute: project))
post :create, format: :json
@@ -270,7 +269,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do
project.errors.add(:path, 'is old')
allow(Gitlab::LegacyGithubImport::ProjectCreator)
- .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, type: provider, **access_params)
+ .to receive(:new).with(provider_repo, provider_repo[:name], user.namespace, user, type: provider, **access_params)
.and_return(double(execute: project))
post :create, format: :json
@@ -281,7 +280,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do
it "touches the etag cache store" do
allow(Gitlab::LegacyGithubImport::ProjectCreator)
- .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, type: provider, **access_params)
+ .to receive(:new).with(provider_repo, provider_repo[:name], user.namespace, user, type: provider, **access_params)
.and_return(double(execute: project))
expect_next_instance_of(Gitlab::EtagCaching::Store) do |store|
expect(store).to receive(:touch) { "realtime_changes_import_#{provider}_path" }
@@ -294,7 +293,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' 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, type: provider, **access_params)
+ .to receive(:new).with(provider_repo, provider_repo[:name], user.namespace, user, type: provider, **access_params)
.and_return(double(execute: project))
post :create, format: :json
@@ -306,7 +305,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' 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, type: provider, **access_params)
+ .to receive(:new).with(provider_repo, provider_repo[:name], user.namespace, user, type: provider, **access_params)
.and_return(double(execute: project))
post :create, format: :json
@@ -331,7 +330,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do
it "takes the existing namespace" do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
- .to receive(:new).with(provider_repo, provider_repo.name, existing_namespace, user, type: provider, **access_params)
+ .to receive(:new).with(provider_repo, provider_repo[:name], existing_namespace, user, type: provider, **access_params)
.and_return(double(execute: project))
post :create, format: :json
@@ -343,7 +342,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do
create(:user, username: provider_username)
expect(Gitlab::LegacyGithubImport::ProjectCreator)
- .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, type: provider, **access_params)
+ .to receive(:new).with(provider_repo, provider_repo[:name], user.namespace, user, type: provider, **access_params)
.and_return(double(execute: project))
post :create, format: :json
@@ -357,15 +356,15 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' 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)
+ 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, type: provider, **access_params)
+ .to receive(:new).with(provider_repo, provider_repo[:name], an_instance_of(Group), user, type: provider, **access_params)
.and_return(double(execute: project))
- post :create, params: { target_namespace: provider_repo.name }, format: :json
+ post :create, params: { target_namespace: provider_repo[:name] }, format: :json
end
end
@@ -383,7 +382,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' 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, type: provider, **access_params)
+ .to receive(:new).with(provider_repo, provider_repo[:name], user.namespace, user, type: provider, **access_params)
.and_return(double(execute: project))
post :create, format: :json
diff --git a/spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb b/spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb
index aa4d78b23f4..112b9cbb204 100644
--- a/spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb
@@ -3,7 +3,7 @@
RSpec.shared_examples 'snippets sort order' do
let(:params) { {} }
let(:sort_argument) { {} }
- let(:sort_params) { params.merge(sort_argument)}
+ let(:sort_params) { params.merge(sort_argument) }
before do
sign_in(user)
diff --git a/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb b/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb
index 2e691d1b36f..4af3c0cc6cc 100644
--- a/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb
+++ b/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb
@@ -13,7 +13,7 @@
# - label
# - **extra
-shared_examples 'Snowplow event tracking' do |overrides: {}|
+RSpec.shared_examples 'Snowplow event tracking' do |overrides: {}|
let(:extra) { {} }
it 'is not emitted if FF is disabled' do
diff --git a/spec/support/shared_examples/features/board_sidebar_labels_examples.rb b/spec/support/shared_examples/features/board_sidebar_labels_examples.rb
index 520980c2615..4e5b371c18d 100644
--- a/spec/support/shared_examples/features/board_sidebar_labels_examples.rb
+++ b/spec/support/shared_examples/features/board_sidebar_labels_examples.rb
@@ -17,7 +17,7 @@ RSpec.shared_context 'labels from nested groups and projects' do
let_it_be(:maintainer) { create(:user) }
let(:labels_select) { find("[data-testid='sidebar-labels']") }
- let(:labels_dropdown) { labels_select.find('[data-testid="dropdown-content"]')}
+ let(:labels_dropdown) { labels_select.find('[data-testid="dropdown-content"]') }
before do
group.add_maintainer(maintainer)
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 8a07e52019c..f7cdc4c61ec 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,10 @@
# frozen_string_literal: true
RSpec.shared_examples 'comment on merge request file' do
+ before do
+ stub_feature_flags(remove_user_attributes_projects: false)
+ end
+
it 'adds a comment' do
click_diff_line(find_by_scrolling("[id='#{sample_commit.line_code}']"))
diff --git a/spec/support/shared_examples/features/content_editor_shared_examples.rb b/spec/support/shared_examples/features/content_editor_shared_examples.rb
index 3fa7beea97e..21f264a8b6a 100644
--- a/spec/support/shared_examples/features/content_editor_shared_examples.rb
+++ b/spec/support/shared_examples/features/content_editor_shared_examples.rb
@@ -1,22 +1,87 @@
# frozen_string_literal: true
RSpec.shared_examples 'edits content using the content editor' do
- content_editor_testid = '[data-testid="content-editor"] [contenteditable].ProseMirror'
+ let(:content_editor_testid) { '[data-testid="content-editor"] [contenteditable].ProseMirror' }
+
+ def switch_to_content_editor
+ find('[data-testid="toggle-editing-mode-button"] label', text: 'Rich text').click
+ end
+
+ def type_in_content_editor(keys)
+ find(content_editor_testid).send_keys keys
+ end
+
+ def open_insert_media_dropdown
+ page.find('svg[data-testid="media-icon"]').click
+ end
+
+ def set_source_editor_content(content)
+ find('.js-gfm-input').set content
+ end
+
+ def expect_formatting_menu_to_be_visible
+ expect(page).to have_css('[data-testid="formatting-bubble-menu"]')
+ end
+
+ def expect_formatting_menu_to_be_hidden
+ expect(page).not_to have_css('[data-testid="formatting-bubble-menu"]')
+ end
+
+ def expect_media_bubble_menu_to_be_visible
+ expect(page).to have_css('[data-testid="media-bubble-menu"]')
+ end
+
+ def upload_asset(fixture_name)
+ attach_file('content_editor_image', Rails.root.join('spec', 'fixtures', fixture_name), make_visible: true)
+ end
describe 'formatting bubble menu' do
- it 'shows a formatting bubble menu for a regular paragraph' do
+ it 'shows a formatting bubble menu for a regular paragraph and headings' do
+ switch_to_content_editor
+
expect(page).to have_css(content_editor_testid)
- find(content_editor_testid).send_keys 'Typing text in the content editor'
- find(content_editor_testid).send_keys [:shift, :left]
+ type_in_content_editor 'Typing text in the content editor'
+ type_in_content_editor [:shift, :left]
+
+ expect_formatting_menu_to_be_visible
+
+ type_in_content_editor [:right, :right, :enter, '## Heading']
- expect(page).to have_css('[data-testid="formatting-bubble-menu"]')
+ expect_formatting_menu_to_be_hidden
+
+ type_in_content_editor [:shift, :left]
+
+ expect_formatting_menu_to_be_visible
+ end
+ end
+
+ describe 'media elements bubble menu' do
+ before do
+ switch_to_content_editor
+
+ open_insert_media_dropdown
+ end
+
+ def test_displays_media_bubble_menu(media_element_selector, fixture_file)
+ upload_asset fixture_file
+
+ wait_for_requests
+
+ expect(page).to have_css(media_element_selector)
+
+ page.find(media_element_selector).click
+
+ expect_formatting_menu_to_be_hidden
+ expect_media_bubble_menu_to_be_visible
end
- it 'does not show a formatting bubble menu for code blocks' do
- find(content_editor_testid).send_keys '```js '
+ it 'displays correct media bubble menu for images', :js do
+ test_displays_media_bubble_menu '[data-testid="content_editor_editablebox"] img[src]', 'dk.png'
+ end
- expect(page).not_to have_css('[data-testid="formatting-bubble-menu"]')
+ it 'displays correct media bubble menu for video', :js do
+ test_displays_media_bubble_menu '[data-testid="content_editor_editablebox"] video', 'video_sample.mp4'
end
end
@@ -30,45 +95,50 @@ RSpec.shared_examples 'edits content using the content editor' do
page.go_back
refresh
+ switch_to_content_editor
end
it 'applies theme classes to code blocks' do
expect(page).not_to have_css('.content-editor-code-block.code.highlight.dark')
- find(content_editor_testid).send_keys [:enter, :enter]
- find(content_editor_testid).send_keys '```js ' # trigger input rule
- find(content_editor_testid).send_keys 'var a = 0'
+ type_in_content_editor [:enter, :enter]
+ type_in_content_editor '```js ' # trigger input rule
+ type_in_content_editor 'var a = 0'
expect(page).to have_css('.content-editor-code-block.code.highlight.dark')
end
end
describe 'code block bubble menu' do
+ before do
+ switch_to_content_editor
+ end
+
it 'shows a code block bubble menu for a code block' do
- find(content_editor_testid).send_keys [:enter, :enter]
+ type_in_content_editor [:enter, :enter]
- find(content_editor_testid).send_keys '```js ' # trigger input rule
- find(content_editor_testid).send_keys 'var a = 0'
- find(content_editor_testid).send_keys [:shift, :left]
+ type_in_content_editor '```js ' # trigger input rule
+ type_in_content_editor 'var a = 0'
+ type_in_content_editor [:shift, :left]
- expect(page).not_to have_css('[data-testid="formatting-bubble-menu"]')
+ expect_formatting_menu_to_be_hidden
expect(page).to have_css('[data-testid="code-block-bubble-menu"]')
end
it 'sets code block type to "javascript" for `js`' do
- find(content_editor_testid).send_keys [:enter, :enter]
+ type_in_content_editor [:enter, :enter]
- find(content_editor_testid).send_keys '```js '
- find(content_editor_testid).send_keys 'var a = 0'
+ type_in_content_editor '```js '
+ type_in_content_editor 'var a = 0'
expect(find('[data-testid="code-block-bubble-menu"]')).to have_text('Javascript')
end
it 'sets code block type to "Custom (nomnoml)" for `nomnoml`' do
- find(content_editor_testid).send_keys [:enter, :enter]
+ type_in_content_editor [:enter, :enter]
- find(content_editor_testid).send_keys '```nomnoml '
- find(content_editor_testid).send_keys 'test'
+ type_in_content_editor '```nomnoml '
+ type_in_content_editor 'test'
expect(find('[data-testid="code-block-bubble-menu"]')).to have_text('Custom (nomnoml)')
end
@@ -76,10 +146,11 @@ RSpec.shared_examples 'edits content using the content editor' do
describe 'mermaid diagram' do
before do
- find(content_editor_testid).send_keys [:enter, :enter]
+ switch_to_content_editor
- find(content_editor_testid).send_keys '```mermaid '
- find(content_editor_testid).send_keys ['graph TD;', :enter, ' JohnDoe12 --> HelloWorld34']
+ type_in_content_editor [:enter, :enter]
+ type_in_content_editor '```mermaid '
+ type_in_content_editor ['graph TD;', :enter, ' JohnDoe12 --> HelloWorld34']
end
it 'renders and updates the diagram correctly in a sandboxed iframe' do
diff --git a/spec/support/shared_examples/features/deploy_token_shared_examples.rb b/spec/support/shared_examples/features/deploy_token_shared_examples.rb
index 25dfe089f51..79ad5bd6c7f 100644
--- a/spec/support/shared_examples/features/deploy_token_shared_examples.rb
+++ b/spec/support/shared_examples/features/deploy_token_shared_examples.rb
@@ -30,6 +30,27 @@ RSpec.shared_examples 'a deploy token in settings' do
expect(page).to have_selector("input[name='deploy-token-user'][value='deployer']")
expect(page).to have_selector("input[name='deploy-token'][readonly='readonly']")
end
+
+ expect(find("input#deploy_token_name").value).to eq nil
+ expect(find("input#deploy_token_read_repository").checked?).to eq false
+ end
+
+ context "with form errors" do
+ before do
+ visit page_path
+ fill_in "deploy_token_name", with: "new_deploy_key"
+ fill_in "deploy_token_username", with: "deployer"
+ click_button "Create deploy token"
+ end
+
+ it "shows form errors" do
+ expect(page).to have_text("Scopes can't be blank")
+ end
+
+ it "keeps form inputs" do
+ expect(find("input#deploy_token_name").value).to eq "new_deploy_key"
+ expect(find("input#deploy_token_username").value).to eq "deployer"
+ end
end
context 'when User#time_display_relative is false', :js do
diff --git a/spec/support/shared_examples/features/discussion_comments_shared_example.rb b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
index 24dc4bcfc59..f209070d82a 100644
--- a/spec/support/shared_examples/features/discussion_comments_shared_example.rb
+++ b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
@@ -304,7 +304,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re
let(:reply_id) { find("#{comments_selector} .note:last-of-type", match: :first)['data-note-id'] }
it 'can be replied to after resolving' do
- find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
+ find('button[data-testid="resolve-discussion-button"]').click
wait_for_requests
refresh
@@ -316,7 +316,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re
it 'shows resolved thread when toggled' do
submit_reply('a')
- find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
+ find('button[data-testid="resolve-discussion-button"]').click
wait_for_requests
expect(page).to have_selector(".note-row-#{note_id}", visible: true)
diff --git a/spec/support/shared_examples/features/manage_applications_shared_examples.rb b/spec/support/shared_examples/features/manage_applications_shared_examples.rb
index 442264e7ae4..b59f3f1e27b 100644
--- a/spec/support/shared_examples/features/manage_applications_shared_examples.rb
+++ b/spec/support/shared_examples/features/manage_applications_shared_examples.rb
@@ -5,39 +5,87 @@ RSpec.shared_examples 'manage applications' do
let_it_be(:application_name_changed) { "#{application_name} changed" }
let_it_be(:application_redirect_uri) { 'https://foo.bar' }
- it 'allows user to manage applications', :js do
- visit new_application_path
+ context 'when hash_oauth_secrets flag set' do
+ before do
+ stub_feature_flags(hash_oauth_secrets: true)
+ end
+
+ it 'allows user to manage applications', :js do
+ visit new_application_path
- expect(page).to have_content 'Add new application'
+ expect(page).to have_content 'Add new application'
- fill_in :doorkeeper_application_name, with: application_name
- fill_in :doorkeeper_application_redirect_uri, with: application_redirect_uri
- check :doorkeeper_application_scopes_read_user
- click_on 'Save application'
+ fill_in :doorkeeper_application_name, with: application_name
+ fill_in :doorkeeper_application_redirect_uri, with: application_redirect_uri
+ check :doorkeeper_application_scopes_read_user
+ click_on 'Save application'
- validate_application(application_name, 'Yes')
- expect(page).to have_link('Continue', href: index_path)
+ validate_application(application_name, 'Yes')
+ expect(page).to have_content _('This is the only time the secret is accessible. Copy the secret and store it securely')
+ expect(page).to have_link('Continue', href: index_path)
- application = Doorkeeper::Application.find_by(name: application_name)
- expect(page).to have_css("button[title=\"Copy secret\"][data-clipboard-text=\"#{application.secret}\"]", text: 'Copy')
+ expect(page).to have_css("button[title=\"Copy secret\"]", text: 'Copy')
- click_on 'Edit'
+ click_on 'Edit'
- application_name_changed = "#{application_name} changed"
+ application_name_changed = "#{application_name} changed"
- fill_in :doorkeeper_application_name, with: application_name_changed
- uncheck :doorkeeper_application_confidential
- click_on 'Save application'
+ fill_in :doorkeeper_application_name, with: application_name_changed
+ uncheck :doorkeeper_application_confidential
+ click_on 'Save application'
+
+ validate_application(application_name_changed, 'No')
+ expect(page).not_to have_link('Continue')
+ expect(page).to have_content _('The secret is only available when you first create the application')
+
+ visit_applications_path
+
+ page.within '.oauth-applications' do
+ click_on 'Destroy'
+ end
+ expect(page.find('.oauth-applications')).not_to have_content 'test_changed'
+ end
+ end
+
+ context 'when hash_oauth_secrets flag not set' do
+ before do
+ stub_feature_flags(hash_oauth_secrets: false)
+ end
+
+ it 'allows user to manage applications', :js do
+ visit new_application_path
+
+ expect(page).to have_content 'Add new application'
+
+ fill_in :doorkeeper_application_name, with: application_name
+ fill_in :doorkeeper_application_redirect_uri, with: application_redirect_uri
+ check :doorkeeper_application_scopes_read_user
+ click_on 'Save application'
+
+ validate_application(application_name, 'Yes')
+ expect(page).to have_link('Continue', href: index_path)
+
+ application = Doorkeeper::Application.find_by(name: application_name)
+ expect(page).to have_css("button[title=\"Copy secret\"][data-clipboard-text=\"#{application.secret}\"]", text: 'Copy')
+
+ click_on 'Edit'
+
+ application_name_changed = "#{application_name} changed"
+
+ fill_in :doorkeeper_application_name, with: application_name_changed
+ uncheck :doorkeeper_application_confidential
+ click_on 'Save application'
- validate_application(application_name_changed, 'No')
- expect(page).not_to have_link('Continue')
+ validate_application(application_name_changed, 'No')
+ expect(page).not_to have_link('Continue')
- visit_applications_path
+ visit_applications_path
- page.within '.oauth-applications' do
- click_on 'Destroy'
+ page.within '.oauth-applications' do
+ click_on 'Destroy'
+ end
+ expect(page.find('.oauth-applications')).not_to have_content 'test_changed'
end
- expect(page.find('.oauth-applications')).not_to have_content 'test_changed'
end
context 'when scopes are blank' do
diff --git a/spec/support/shared_examples/features/packages_shared_examples.rb b/spec/support/shared_examples/features/packages_shared_examples.rb
index 323bd4f5171..7aad5e2de80 100644
--- a/spec/support/shared_examples/features/packages_shared_examples.rb
+++ b/spec/support/shared_examples/features/packages_shared_examples.rb
@@ -14,7 +14,7 @@ RSpec.shared_examples 'packages list' do |check_project_name: false|
end
def package_table_row(index)
- page.all("#{packages_table_selector} > [data-qa-selector=\"package_row\"]")[index].text # rubocop:disable QA/SelectorUsage
+ page.all("#{packages_table_selector} > [data-testid=\"package-row\"]")[index].text
end
end
@@ -84,7 +84,7 @@ RSpec.shared_examples 'shared package sorting' do
end
def packages_table_selector
- '[data-qa-selector="packages-table"]' # rubocop:disable QA/SelectorUsage
+ '[data-testid="packages-table"]'
end
def click_sort_option(option, ascending)
diff --git a/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
index 8212f14d6be..81d548e000a 100644
--- a/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
+++ b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
@@ -8,7 +8,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
set_protected_branch_name('master')
find(".js-allowed-to-merge").click
- within('.rspec-allowed-to-merge-dropdown') do
+ within('[data-testid="allowed-to-merge-dropdown"]') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
@@ -35,13 +35,13 @@ RSpec.shared_examples "protected branches > access control > CE" do
set_protected_branch_name('master')
find(".js-allowed-to-merge").click
- within('.rspec-allowed-to-merge-dropdown') do
+ within('[data-testid="allowed-to-merge-dropdown"]') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
find(".js-allowed-to-push").click
- within('.rspec-allowed-to-push-dropdown') do
+ within('[data-testid="allowed-to-push-dropdown"]') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
@@ -83,7 +83,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
end
find(".js-allowed-to-push").click
- within('.rspec-allowed-to-push-dropdown') do
+ within('[data-testid="allowed-to-push-dropdown"]') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
@@ -100,13 +100,13 @@ RSpec.shared_examples "protected branches > access control > CE" do
set_protected_branch_name('master')
find(".js-allowed-to-merge").click
- within('.rspec-allowed-to-merge-dropdown') do
+ within('[data-testid="allowed-to-merge-dropdown"]') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
find(".js-allowed-to-push").click
- within('.rspec-allowed-to-push-dropdown') do
+ within('[data-testid="allowed-to-push-dropdown"]') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
diff --git a/spec/support/shared_examples/features/protected_branches_with_deploy_keys_examples.rb b/spec/support/shared_examples/features/protected_branches_with_deploy_keys_examples.rb
index 14142793a0d..90b0e600228 100644
--- a/spec/support/shared_examples/features/protected_branches_with_deploy_keys_examples.rb
+++ b/spec/support/shared_examples/features/protected_branches_with_deploy_keys_examples.rb
@@ -23,7 +23,7 @@ RSpec.shared_examples 'Deploy keys with protected branches' do
find(".js-allowed-to-push").click
wait_for_requests
- within('.qa-allowed-to-push-dropdown') do # rubocop:disable QA/SelectorUsage
+ within('[data-testid="allowed-to-push-dropdown"]') do
dropdown_headers = page.all('.dropdown-header').map(&:text)
expect(dropdown_headers).to contain_exactly(*all_dropdown_sections)
@@ -38,7 +38,7 @@ RSpec.shared_examples 'Deploy keys with protected branches' do
find(".js-allowed-to-merge").click
wait_for_requests
- within('.qa-allowed-to-merge-dropdown') do # rubocop:disable QA/SelectorUsage
+ within('[data-testid="allowed-to-merge-dropdown"]') do
dropdown_headers = page.all('.dropdown-header').map(&:text)
expect(dropdown_headers).to contain_exactly(*dropdown_sections_minus_deploy_keys)
@@ -68,7 +68,7 @@ RSpec.shared_examples 'Deploy keys with protected branches' do
find(".js-allowed-to-push").click
wait_for_requests
- within('.qa-allowed-to-push-dropdown') do # rubocop:disable QA/SelectorUsage
+ within('[data-testid="allowed-to-push-dropdown"]') do
dropdown_headers = page.all('.dropdown-header').map(&:text)
expect(dropdown_headers).to contain_exactly(*dropdown_sections_minus_deploy_keys)
diff --git a/spec/support/shared_examples/features/rss_shared_examples.rb b/spec/support/shared_examples/features/rss_shared_examples.rb
index 0991de21d8d..ad865b084e1 100644
--- a/spec/support/shared_examples/features/rss_shared_examples.rb
+++ b/spec/support/shared_examples/features/rss_shared_examples.rb
@@ -9,7 +9,7 @@ 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(.qa-rss-icon)[href*='feed_token=#{user.feed_token}']") # rubocop:disable QA/SelectorUsage
+ .to have_css("a:has([data-testid='rss-icon'])[href*='feed_token=#{user.feed_token}']")
end
end
@@ -22,7 +22,7 @@ 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(.qa-rss-icon):not([href*='feed_token'])") # rubocop:disable QA/SelectorUsage
+ .to have_css("a:has([data-testid='rss-icon']):not([href*='feed_token'])")
end
end
diff --git a/spec/support/shared_examples/features/runners_shared_examples.rb b/spec/support/shared_examples/features/runners_shared_examples.rb
index 52f3fd60c07..31ee08ea9db 100644
--- a/spec/support/shared_examples/features/runners_shared_examples.rb
+++ b/spec/support/shared_examples/features/runners_shared_examples.rb
@@ -64,9 +64,9 @@ end
RSpec.shared_examples 'shows no runners registered' do
it 'shows counts with 0' do
- expect(page).to have_text "Online runners 0"
- expect(page).to have_text "Offline runners 0"
- expect(page).to have_text "Stale runners 0"
+ expect(page).to have_text "#{s_('Runners|Online')} 0"
+ expect(page).to have_text "#{s_('Runners|Offline')} 0"
+ expect(page).to have_text "#{s_('Runners|Stale')} 0"
end
it 'shows "no runners" message' do
@@ -101,7 +101,7 @@ RSpec.shared_examples 'pauses, resumes and deletes a runner' do
within_runner_row(runner.id) do
click_button "Pause"
- expect(page).to have_text 'paused'
+ expect(page).to have_text s_('Runners|Paused')
expect(page).to have_button 'Resume'
expect(page).not_to have_button 'Pause'
@@ -145,3 +145,39 @@ RSpec.shared_examples 'pauses, resumes and deletes a runner' do
end
end
end
+
+RSpec.shared_examples 'submits edit runner form' do
+ it 'breadcrumb contains runner id and token' do
+ page.within '[data-testid="breadcrumb-links"]' do
+ expect(page).to have_link("##{runner.id} (#{runner.short_sha})")
+ expect(page.find('[data-testid="breadcrumb-current-link"]')).to have_content("Edit")
+ end
+ end
+
+ describe 'runner header', :js do
+ it 'contains the runner id' do
+ expect(page).to have_content("Runner ##{runner.id} created")
+ end
+ end
+
+ context 'when a runner is updated', :js do
+ before do
+ find('[data-testid="runner-field-description"] input').set('new-runner-description')
+
+ click_on _('Save changes')
+ wait_for_requests
+ end
+
+ it 'redirects to runner page' do
+ expect(current_url).to match(runner_page_path)
+ end
+
+ it 'show success alert' do
+ expect(page.find('[data-testid="alert-success"]')).to have_content('saved')
+ end
+
+ it 'shows updated information' do
+ expect(page).to have_content("#{s_('Runners|Description')} new-runner-description")
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/snippets_shared_examples.rb b/spec/support/shared_examples/features/snippets_shared_examples.rb
index c402333107c..bf870b3ce66 100644
--- a/spec/support/shared_examples/features/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/features/snippets_shared_examples.rb
@@ -194,7 +194,7 @@ end
RSpec.shared_examples 'personal snippet with references' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
- let_it_be(:project_snippet) { create(:project_snippet, :repository, project: project)}
+ let_it_be(:project_snippet) { create(:project_snippet, :repository, project: project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:commit) { project.commit }
diff --git a/spec/support/shared_examples/features/variable_list_shared_examples.rb b/spec/support/shared_examples/features/variable_list_shared_examples.rb
index 9d81c0e9a3e..d1e5046a39e 100644
--- a/spec/support/shared_examples/features/variable_list_shared_examples.rb
+++ b/spec/support/shared_examples/features/variable_list_shared_examples.rb
@@ -91,7 +91,7 @@ RSpec.shared_examples 'variable list' do |is_admin|
end
page.within('#add-ci-variable') do
- find('[data-qa-selector="ci_variable_key_field"] input').set('new_key') # rubocop:disable QA/SelectorUsage
+ find('[data-testid="pipeline-form-ci-variable-key"] input').set('new_key')
click_button('Update variable')
end
@@ -173,7 +173,7 @@ RSpec.shared_examples 'variable list' do |is_admin|
click_button('Add variable')
page.within('#add-ci-variable') do
- find('[data-qa-selector="ci_variable_key_field"] input').set('empty_mask_key') # rubocop:disable QA/SelectorUsage
+ find('[data-testid="pipeline-form-ci-variable-key"] input').set('empty_mask_key')
find('[data-testid="ci-variable-protected-checkbox"]').click
find('[data-testid="ci-variable-masked-checkbox"]').click
@@ -290,8 +290,8 @@ RSpec.shared_examples 'variable list' do |is_admin|
wait_for_requests
page.within('#add-ci-variable') do
- find('[data-qa-selector="ci_variable_key_field"] input').set(key) # rubocop:disable QA/SelectorUsage
- find('[data-qa-selector="ci_variable_value_field"]').set(value) if value.present? # rubocop:disable QA/SelectorUsage
+ find('[data-testid="pipeline-form-ci-variable-key"] input').set(key)
+ find('[data-testid="pipeline-form-ci-variable-value"]').set(value) if value.present?
find('[data-testid="ci-variable-protected-checkbox"]').click if protected
find('[data-testid="ci-variable-masked-checkbox"]').click if masked
diff --git a/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb
index 2285d9a17e2..3e285bb8ad7 100644
--- a/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb
@@ -64,7 +64,7 @@ RSpec.shared_examples 'User previews wiki changes' do
end
it_behaves_like 'relative links' do
- let(:element) { page.find('[data-testid="wiki_page_content"]') }
+ let(:element) { page.find('[data-testid="wiki-page-content"]') }
end
end
diff --git a/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
index 87067336a36..5c63d6a973d 100644
--- a/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
@@ -137,16 +137,7 @@ RSpec.shared_examples 'User updates wiki page' do
end
end
- context 'when using the content editor' do
- context 'with feature flag on' do
- before do
- find('[data-testid="toggle-editing-mode-button"] label', text: 'Rich text').click
- end
-
- it_behaves_like 'edits content using the content editor'
- end
- end
-
+ it_behaves_like 'edits content using the content editor'
it_behaves_like 'autocompletes items'
end
diff --git a/spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb
index 6fdc5ecae73..fde38df558f 100644
--- a/spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
RSpec.shared_examples 'User views AsciiDoc page with includes' do
- let_it_be(:wiki_content_selector) { '[data-qa-selector=wiki_page_content]' } # rubocop:disable QA/SelectorUsage
- let!(:included_wiki_page) { create_wiki_page('included_page', content: 'Content from the included page')}
+ let_it_be(:wiki_content_selector) { '[data-testid=wiki-page-content]' }
+ let!(:included_wiki_page) { create_wiki_page('included_page', content: 'Content from the included page') }
let!(:wiki_page) { create_wiki_page('home', content: "Content from the main page.\ninclude::included_page.asciidoc[]") }
def create_wiki_page(title, content:)
diff --git a/spec/support/shared_examples/finders/issues_finder_shared_examples.rb b/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
index 049ead9fb89..f62c9c00006 100644
--- a/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
+++ b/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
@@ -365,7 +365,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
let!(:created_items) do
milestones.map do |milestone|
create(factory, project: milestone.project || project_in_group,
- milestone: milestone, author: user, assignees: [user])
+ milestone: milestone, author: user, assignees: [user])
end
end
diff --git a/spec/support/shared_examples/graphql/members_shared_examples.rb b/spec/support/shared_examples/graphql/members_shared_examples.rb
index 110706c730b..5cba8baa829 100644
--- a/spec/support/shared_examples/graphql/members_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/members_shared_examples.rb
@@ -40,7 +40,7 @@ RSpec.shared_examples 'querying members with a group' do
subject do
resolve(described_class, obj: resource, args: base_args.merge(args),
- ctx: { current_user: user_4 }, arg_style: :internal)
+ ctx: { current_user: user_4 }, arg_style: :internal)
end
describe '#resolve' do
@@ -52,6 +52,15 @@ RSpec.shared_examples 'querying members with a group' do
expect(subject).to contain_exactly(resource_member, group_1_member, root_group_member)
end
+ context 'with sort options' do
+ let(:args) { { sort: 'name_asc' } }
+
+ it 'searches users by user name' do
+ # the order is important here
+ expect(subject.items).to eq([root_group_member, resource_member, group_1_member])
+ end
+ end
+
context 'with search' do
context 'when the search term matches a user' do
let(:args) { { search: 'test' } }
@@ -75,7 +84,7 @@ RSpec.shared_examples 'querying members with a group' do
subject do
resolve(described_class, obj: resource, args: base_args.merge(args),
- ctx: { current_user: other_user }, arg_style: :internal)
+ ctx: { current_user: other_user }, arg_style: :internal)
end
it 'generates an error' do
diff --git a/spec/support/shared_examples/graphql/n_plus_one_query_examples.rb b/spec/support/shared_examples/graphql/n_plus_one_query_examples.rb
index 738edd43c92..faf1bb204c9 100644
--- a/spec/support/shared_examples/graphql/n_plus_one_query_examples.rb
+++ b/spec/support/shared_examples/graphql/n_plus_one_query_examples.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-shared_examples 'N+1 query check' do
+RSpec.shared_examples 'N+1 query check' do
it 'prevents N+1 queries' do
execute_query # "warm up" to prevent undeterministic counts
expect(graphql_errors).to be_blank # Sanity check - ex falso quodlibet!
diff --git a/spec/support/shared_examples/graphql/resolvers/issuable_resolvers_shared_examples.rb b/spec/support/shared_examples/graphql/resolvers/issuable_resolvers_shared_examples.rb
new file mode 100644
index 00000000000..25008bca619
--- /dev/null
+++ b/spec/support/shared_examples/graphql/resolvers/issuable_resolvers_shared_examples.rb
@@ -0,0 +1,99 @@
+# frozen_string_literal: true
+
+# Requires `parent`, issuable1`, `issuable2`, `issuable3`, `issuable4`,
+# `finder_class` and `optimization_param` bindings.
+RSpec.shared_examples 'graphql query for searching issuables' do
+ it 'uses search optimization' do
+ expected_arguments = a_hash_including(
+ search: 'text',
+ optimization_param => true
+ )
+ expect(finder_class).to receive(:new).with(anything, expected_arguments).and_call_original
+
+ resolve_issuables(search: 'text')
+ end
+
+ it 'filters issuables by title' do
+ issuables = resolve_issuables(search: 'created')
+
+ expect(issuables).to contain_exactly(issuable1, issuable2)
+ end
+
+ it 'filters issuables by description' do
+ issuables = resolve_issuables(search: 'text')
+
+ expect(issuables).to contain_exactly(issuable2, issuable3)
+ end
+
+ context 'with in param' do
+ it 'generates an error if param search is missing' do
+ error_message = "`search` should be present when including the `in` argument"
+
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, error_message) do
+ resolve_issuables(in: ['title'])
+ end
+ end
+
+ it 'filters issuables by title and description' do
+ issuable4.update!(title: 'fourth text')
+ issuables = resolve_issuables(search: 'text', in: %w[title description])
+
+ expect(issuables).to contain_exactly(issuable2, issuable3, issuable4)
+ end
+
+ it 'filters issuables by description only' do
+ with_text = resolve_issuables(search: 'text', in: ['description'])
+ with_created = resolve_issuables(search: 'created', in: ['description'])
+
+ expect(with_created).to be_empty
+ expect(with_text).to contain_exactly(issuable2, issuable3)
+ end
+
+ it 'filters issuables by title only' do
+ with_text = resolve_issuables(search: 'text', in: ['title'])
+ with_created = resolve_issuables(search: 'created', in: ['title'])
+
+ expect(with_created).to contain_exactly(issuable1, issuable2)
+ expect(with_text).to be_empty
+ end
+ end
+
+ context 'with anonymous user' do
+ let_it_be(:current_user) { nil }
+
+ context 'with disable_anonymous_search as `true`' do
+ before do
+ stub_feature_flags(disable_anonymous_search: true)
+ end
+
+ it 'returns an error' do
+ error_message = "User must be authenticated to include the `search` argument."
+
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, error_message) do
+ resolve_issuables(search: 'created')
+ end
+ end
+
+ it 'does not return error if search term is not present' do
+ expect(resolve_issuables).not_to be_instance_of(Gitlab::Graphql::Errors::ArgumentError)
+ end
+ end
+
+ context 'with disable_anonymous_search as `false`' do
+ before do
+ stub_feature_flags(disable_anonymous_search: false)
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ it 'filters issuables by search term' do
+ issuables = resolve_issuables(search: 'created')
+
+ expect(issuables).to contain_exactly(issuable1, issuable2)
+ end
+ end
+ end
+
+ def resolve_issuables(args = {}, obj = parent, context = { current_user: current_user })
+ resolve(described_class, obj: obj, args: args, ctx: context, arg_style: :internal)
+ end
+end
diff --git a/spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb b/spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb
index b5c07f45d59..47655f86558 100644
--- a/spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb
+++ b/spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb
@@ -45,62 +45,62 @@ RSpec.shared_examples 'XSS prevention' do
# Adapted from the Sanitize test suite: http://git.io/vczrM
protocols = {
'protocol-based JS injection: simple, no spaces' => {
- input: '<a href="javascript:alert(\'XSS\');">foo</a>',
+ input: '<a href="javascript:alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: simple, spaces before' => {
- input: '<a href="javascript :alert(\'XSS\');">foo</a>',
+ input: '<a href="javascript :alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: simple, spaces after' => {
- input: '<a href="javascript: alert(\'XSS\');">foo</a>',
+ input: '<a href="javascript: alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: simple, spaces before and after' => {
- input: '<a href="javascript : alert(\'XSS\');">foo</a>',
+ input: '<a href="javascript : alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: preceding colon' => {
- input: '<a href=":javascript:alert(\'XSS\');">foo</a>',
+ input: '<a href=":javascript:alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: UTF-8 encoding' => {
- input: '<a href="javascript&#58;">foo</a>',
+ input: '<a href="javascript&#58;">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: long UTF-8 encoding' => {
- input: '<a href="javascript&#0058;">foo</a>',
+ input: '<a href="javascript&#0058;">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: long UTF-8 encoding without semicolons' => {
- input: '<a href=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>foo</a>',
+ input: '<a href=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: hex encoding' => {
- input: '<a href="javascript&#x3A;">foo</a>',
+ input: '<a href="javascript&#x3A;">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: long hex encoding' => {
- input: '<a href="javascript&#x003A;">foo</a>',
+ input: '<a href="javascript&#x003A;">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: hex encoding without semicolons' => {
- input: '<a href=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>foo</a>',
+ input: '<a href=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: null char' => {
- input: "<a href=java\0script:alert(\"XSS\")>foo</a>",
+ input: "<a href=java\0script:alert(\"XSS\")>foo</a>",
output: '<a href="java"></a>'
},
@@ -115,7 +115,7 @@ RSpec.shared_examples 'XSS prevention' do
},
'protocol-based JS injection: spaces and entities' => {
- input: '<a href=" &#14; javascript:alert(\'XSS\');">foo</a>',
+ input: '<a href=" &#14; javascript:alert(\'XSS\');">foo</a>',
output: '<a href="">foo</a>'
},
diff --git a/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb b/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb
index 845fa78a827..82a9e8130f7 100644
--- a/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb
+++ b/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb
@@ -43,6 +43,54 @@ RSpec.shared_examples_for 'object cache helper' do
subject
end
end
+
+ context 'when a caller id is present' do
+ let(:transaction) { Gitlab::Metrics::WebTransaction.new({}) }
+ let(:caller_id) { 'caller_id' }
+
+ before do
+ allow(::Gitlab::Metrics::WebTransaction).to receive(:current).and_return(transaction)
+ allow(transaction).to receive(:increment)
+ allow(Gitlab::ApplicationContext).to receive(:current_context_attribute).with(:caller_id).and_return(caller_id)
+ end
+
+ context 'when feature flag is off' do
+ before do
+ stub_feature_flags(add_timing_to_certain_cache_actions: false)
+ end
+
+ it 'does not call increment' do
+ expect(transaction).not_to receive(:increment).with(:cached_object_operations_total, any_args)
+
+ subject
+ end
+
+ it 'does not call histogram' do
+ expect(Gitlab::Metrics).not_to receive(:histogram)
+
+ subject
+ end
+
+ it "is valid JSON" do
+ parsed = Gitlab::Json.parse(subject.to_s)
+
+ expect(parsed).to be_a(Hash)
+ expect(parsed["id"]).to eq(presentable.id)
+ end
+ end
+
+ it 'increments the counter' do
+ expect(transaction)
+ .to receive(:increment)
+ .with(:cached_object_operations_total, 1, { caller_id: caller_id, render_type: :object, cache_hit: false }).once
+
+ expect(transaction)
+ .to receive(:increment)
+ .with(:cached_object_operations_total, 0, { caller_id: caller_id, render_type: :object, cache_hit: true }).once
+
+ subject
+ end
+ end
end
RSpec.shared_examples_for 'collection cache helper' do
@@ -98,4 +146,95 @@ RSpec.shared_examples_for 'collection cache helper' do
subject
end
end
+
+ context 'when a caller id is present' do
+ let(:transaction) { Gitlab::Metrics::WebTransaction.new({}) }
+ let(:caller_id) { 'caller_id' }
+
+ before do
+ allow(::Gitlab::Metrics::WebTransaction).to receive(:current).and_return(transaction)
+ allow(transaction).to receive(:increment)
+ allow(Gitlab::ApplicationContext).to receive(:current_context_attribute).with(:caller_id).and_return(caller_id)
+ end
+
+ context 'when feature flag is off' do
+ before do
+ stub_feature_flags(add_timing_to_certain_cache_actions: false)
+ end
+
+ it 'does not call increment' do
+ expect(transaction).not_to receive(:increment).with(:cached_object_operations_total, any_args)
+
+ subject
+ end
+
+ it 'does not call histogram' do
+ expect(Gitlab::Metrics).not_to receive(:histogram)
+
+ subject
+ end
+
+ it "is valid JSON" do
+ parsed = Gitlab::Json.parse(subject.to_s)
+
+ expect(parsed).to be_an(Array)
+
+ presentable.each_with_index do |item, i|
+ expect(parsed[i]["id"]).to eq(item.id)
+ end
+ end
+ end
+
+ context 'when presentable has a group by clause' do
+ let(:presentable) { MergeRequest.group(:id) }
+
+ it "returns the presentables" do
+ expect(transaction)
+ .to receive(:increment)
+ .with(:cached_object_operations_total, 0, { caller_id: caller_id, render_type: :collection, cache_hit: true }).once
+
+ expect(transaction)
+ .to receive(:increment)
+ .with(:cached_object_operations_total, MergeRequest.count, { caller_id: caller_id, render_type: :collection, cache_hit: false }).once
+
+ parsed = Gitlab::Json.parse(subject.to_s)
+
+ expect(parsed).to be_an(Array)
+
+ presentable.each_with_index do |item, i|
+ expect(parsed[i]["id"]).to eq(item.id)
+ end
+ end
+ end
+
+ context 'when the presentables all miss' do
+ it 'increments the counters' do
+ expect(transaction)
+ .to receive(:increment)
+ .with(:cached_object_operations_total, 0, { caller_id: caller_id, render_type: :collection, cache_hit: true }).once
+
+ expect(transaction)
+ .to receive(:increment)
+ .with(:cached_object_operations_total, presentable.size, { caller_id: caller_id, render_type: :collection, cache_hit: false }).once
+
+ subject
+ end
+ end
+
+ context 'when the presents hit' do
+ it 'increments the counters' do
+ subject
+
+ expect(transaction)
+ .to receive(:increment)
+ .with(:cached_object_operations_total, presentable.size, { caller_id: caller_id, render_type: :collection, cache_hit: true }).once
+
+ expect(transaction)
+ .to receive(:increment)
+ .with(:cached_object_operations_total, 0, { caller_id: caller_id, render_type: :collection, cache_hit: false }).once
+
+ instance.public_send(method, presentable, **kwargs)
+ end
+ end
+ end
end
diff --git a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
index b786d7e5527..10f58748698 100644
--- a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
@@ -131,7 +131,7 @@ RSpec.shared_examples 'common trace features' do
end
context 'logs contains "section_start"' do
- let(:log) { "section_start:1506417476:a_section\r\033[0Klooks like a section_start:invalid\nsection_end:1506417477:a_section\r\033[0K"}
+ let(:log) { "section_start:1506417476:a_section\r\033[0Klooks like a section_start:invalid\nsection_end:1506417477:a_section\r\033[0K" }
it "returns only one section" do
expect(sections).not_to be_empty
@@ -144,7 +144,7 @@ RSpec.shared_examples 'common trace features' do
end
context 'missing section_end' do
- let(:log) { "section_start:1506417476:a_section\r\033[0KSome logs\nNo section_end\n"}
+ let(:log) { "section_start:1506417476:a_section\r\033[0KSome logs\nNo section_end\n" }
it "returns no sections" do
expect(sections).to be_empty
@@ -152,7 +152,7 @@ RSpec.shared_examples 'common trace features' do
end
context 'missing section_start' do
- let(:log) { "Some logs\nNo section_start\nsection_end:1506417476:a_section\r\033[0K"}
+ let(:log) { "Some logs\nNo section_start\nsection_end:1506417476:a_section\r\033[0K" }
it "returns no sections" do
expect(sections).to be_empty
@@ -160,7 +160,7 @@ RSpec.shared_examples 'common trace features' do
end
context 'inverted section_start section_end' do
- let(:log) { "section_end:1506417476:a_section\r\033[0Klooks like a section_start:invalid\nsection_start:1506417477:a_section\r\033[0K"}
+ let(:log) { "section_end:1506417476:a_section\r\033[0Klooks like a section_start:invalid\nsection_start:1506417477:a_section\r\033[0K" }
it "returns no sections" do
expect(sections).to be_empty
@@ -169,7 +169,7 @@ RSpec.shared_examples 'common trace features' do
end
describe '#write' do
- subject { trace.send(:write, mode) { } }
+ subject { trace.send(:write, mode) {} }
let(:mode) { 'wb' }
@@ -370,15 +370,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do
end
end
- shared_examples 'read successfully with StringIO' do
- it 'yields with source' do
- trace.read do |stream|
- expect(stream).to be_a(Gitlab::Ci::Trace::Stream)
- expect(stream.stream).to be_a(StringIO)
- end
- end
- end
-
shared_examples 'failed to read' do
it 'yields without source' do
trace.read do |stream|
@@ -404,14 +395,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do
it_behaves_like 'read successfully with IO'
end
- context 'when db trace exists' do
- before do
- build.send(:write_attribute, :trace, "data")
- end
-
- it_behaves_like 'read successfully with StringIO'
- end
-
context 'when no sources exist' do
it_behaves_like 'failed to read'
end
@@ -462,25 +445,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do
expect(trace.exist?).to be(false)
end
end
-
- context 'stored in database' do
- before do
- build.send(:write_attribute, :trace, "data")
- end
-
- it "trace exist" do
- expect(trace.exist?).to be(true)
- end
-
- it "can be erased" do
- trace.erase!
- expect(trace.exist?).to be(false)
- end
-
- it "returns database data" do
- expect(trace.raw).to eq("data")
- end
- end
end
describe '#archive!' do
@@ -520,24 +484,12 @@ RSpec.shared_examples 'trace with disabled live trace feature' do
expect(build.trace.exist?).to be_truthy
expect(build.job_artifacts_trace.file.exists?).to be_truthy
expect(build.job_artifacts_trace.file.filename).to eq('job.log')
- expect(build.old_trace).to be_nil
expect(src_checksum)
.to eq(described_class.sha256_hexdigest(build.job_artifacts_trace.file.path))
expect(build.job_artifacts_trace.file_sha256).to eq(src_checksum)
end
end
- shared_examples 'source trace in database stays intact' do |error:|
- it do
- expect { subject }.to raise_error(error)
-
- build.reload
- expect(build.trace.exist?).to be_truthy
- expect(build.job_artifacts_trace).to be_nil
- expect(build.old_trace).to eq(trace_content)
- end
- end
-
context 'when job does not have trace artifact' do
context 'when trace file stored in default path' do
let!(:build) { create(:ci_build, :success, :trace_live) }
@@ -564,58 +516,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do
it_behaves_like 'source trace file stays intact', error: ActiveRecord::RecordInvalid
end
end
-
- context 'when trace is stored in database' do
- let(:build) { create(:ci_build, :success) }
- let(:trace_content) { 'Sample trace' }
- let(:src_checksum) { Digest::SHA256.hexdigest(trace_content) }
-
- before do
- build.update_column(:trace, trace_content)
- end
-
- it_behaves_like 'archive trace in database'
-
- context 'when failed to create clone file' do
- before do
- allow(IO).to receive(:copy_stream).and_return(0)
- end
-
- it_behaves_like 'source trace in database stays intact', error: Gitlab::Ci::Trace::ArchiveError
- end
-
- context 'when failed to create job artifact record' do
- before do
- allow_any_instance_of(Ci::JobArtifact).to receive(:save).and_return(false)
- allow_any_instance_of(Ci::JobArtifact).to receive_message_chain(:errors, :full_messages)
- .and_return(%w[Error Error])
- end
-
- it_behaves_like 'source trace in database stays intact', error: ActiveRecord::RecordInvalid
- end
-
- context 'when there is a validation error on Ci::Build' do
- before do
- allow_any_instance_of(Ci::Build).to receive(:save).and_return(false)
- allow_any_instance_of(Ci::Build).to receive_message_chain(:errors, :full_messages)
- .and_return(%w[Error Error])
- end
-
- context "when erase old trace with 'save'" do
- before do
- build.send(:write_attribute, :trace, nil)
- build.save # rubocop:disable Rails/SaveBang
- end
-
- it 'old trace is not deleted' do
- build.reload
- expect(build.trace.raw).to eq(trace_content)
- end
- end
-
- it_behaves_like 'archive trace in database'
- end
- end
end
context 'when job has trace artifact' do
@@ -645,22 +545,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do
subject { trace.erase! }
context 'when it is a live trace' do
- context 'when trace is stored in database' do
- let(:build) { create(:ci_build) }
-
- before do
- build.update_column(:trace, 'sample trace')
- end
-
- it { expect(trace.raw).not_to be_nil }
-
- it "removes trace" do
- subject
-
- expect(trace.raw).to be_nil
- end
- end
-
context 'when trace is stored in file storage' do
let(:build) { create(:ci_build, :trace_live) }
diff --git a/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb b/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb
index beec072e474..9ffc55f7e7e 100644
--- a/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb
+++ b/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'deployment metrics examples' do
+RSpec.shared_examples 'deployment metrics examples' do
def create_deployment(args)
project = args[:project]
environment = project.environments.production.first || create(:environment, :production, project: project)
diff --git a/spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb
index 771ab89972c..a28fefcfc58 100644
--- a/spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb
@@ -3,7 +3,7 @@
RSpec.shared_examples 'marks background migration job records' do
it 'marks each job record as succeeded after processing' do
create(:background_migration_job, class_name: "::#{described_class.name.demodulize}",
- arguments: arguments)
+ arguments: arguments)
expect(::Gitlab::Database::BackgroundMigrationJob).to receive(:mark_all_as_succeeded).and_call_original
@@ -14,7 +14,7 @@ RSpec.shared_examples 'marks background migration job records' do
it 'returns the number of job records marked as succeeded' do
create(:background_migration_job, class_name: "::#{described_class.name.demodulize}",
- arguments: arguments)
+ arguments: arguments)
jobs_updated = subject.perform(*arguments)
diff --git a/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb
index 1f7325df11a..243dc1d195b 100644
--- a/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb
@@ -144,7 +144,7 @@ RSpec.shared_examples 'cacheable diff collection' do
end
end
-shared_examples_for 'sortable diff files' do
+RSpec.shared_examples_for 'sortable diff files' do
subject { described_class.new(diffable, **collection_default_args) }
describe '#raw_diff_files' do
@@ -170,7 +170,7 @@ shared_examples_for 'sortable diff files' do
end
end
-shared_examples_for 'unsortable diff files' do
+RSpec.shared_examples_for 'unsortable diff files' do
subject { described_class.new(diffable, **collection_default_args) }
describe '#raw_diff_files' do
diff --git a/spec/support/shared_examples/lib/gitlab/sql/set_operator_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/sql/set_operator_shared_examples.rb
index ead8b174d46..ec7b2794703 100644
--- a/spec/support/shared_examples/lib/gitlab/sql/set_operator_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/sql/set_operator_shared_examples.rb
@@ -25,7 +25,7 @@ RSpec.shared_examples 'SQL set operator' do |operator_keyword|
empty_relation = User.none.select(:id)
set_operator = described_class.new([empty_relation, relation_1, relation_2])
- expect {User.where("users.id IN (#{set_operator.to_sql})").to_a}.not_to raise_error
+ expect { User.where("users.id IN (#{set_operator.to_sql})").to_a }.not_to raise_error
expect(set_operator.to_sql).to eq("(#{to_sql(relation_1)})\n#{operator_keyword}\n(#{to_sql(relation_2)})")
end
diff --git a/spec/support/shared_examples/lib/sentry/client_shared_examples.rb b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb
index d73c7b6848d..1c0e0061385 100644
--- a/spec/support/shared_examples/lib/sentry/client_shared_examples.rb
+++ b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb
@@ -43,7 +43,7 @@ RSpec.shared_examples 'maps Sentry exceptions' do |http_method|
}
exceptions.each do |exception, message|
- context "#{exception}" do
+ context exception do
before do
stub_request(
http_method || :get,
@@ -58,3 +58,50 @@ RSpec.shared_examples 'maps Sentry exceptions' do |http_method|
end
end
end
+
+# Expects to following variables:
+# - subject
+# - sentry_api_response
+# - sentry_url, token - only if enabled_by_default: false
+RSpec.shared_examples 'Sentry API response size limit' do |enabled_by_default: false|
+ let(:invalid_deep_size) { instance_double(Gitlab::Utils::DeepSize, valid?: false) }
+
+ before do
+ allow(Gitlab::Utils::DeepSize)
+ .to receive(:new)
+ .with(sentry_api_response, any_args)
+ .and_return(invalid_deep_size)
+ end
+
+ if enabled_by_default
+ it 'raises an exception when response is too large' do
+ expect { subject }.to raise_error(ErrorTracking::SentryClient::ResponseInvalidSizeError,
+ 'Sentry API response is too big. Limit is 1 MB.')
+ end
+ else
+ context 'when guarded by feature flag' do
+ let(:client) do
+ ErrorTracking::SentryClient.new(sentry_url, token, validate_size_guarded_by_feature_flag: feature_flag)
+ end
+
+ context 'with feature flag enabled' do
+ let(:feature_flag) { true }
+
+ it 'raises an exception when response is too large' do
+ expect { subject }.to raise_error(ErrorTracking::SentryClient::ResponseInvalidSizeError,
+ 'Sentry API response is too big. Limit is 1 MB.')
+ end
+ end
+
+ context 'with feature flag disabled' do
+ let(:feature_flag) { false }
+
+ it 'does not check the limit and thus not raise' do
+ expect { subject }.not_to raise_error
+
+ expect(Gitlab::Utils::DeepSize).not_to have_received(:new)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/chat_integration_shared_examples.rb b/spec/support/shared_examples/models/chat_integration_shared_examples.rb
index fb08784f34f..6cfeeabc952 100644
--- a/spec/support/shared_examples/models/chat_integration_shared_examples.rb
+++ b/spec/support/shared_examples/models/chat_integration_shared_examples.rb
@@ -32,9 +32,11 @@ RSpec.shared_examples "chat integration" do |integration_name|
end
describe "#execute" do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project, :repository) }
+
let(:webhook_url) { "https://example.gitlab.com/" }
+ let(:webhook_url_regex) { /\A#{webhook_url}.*/ }
before do
allow(subject).to receive_messages(
@@ -44,7 +46,7 @@ RSpec.shared_examples "chat integration" do |integration_name|
webhook: webhook_url
)
- WebMock.stub_request(:post, webhook_url)
+ WebMock.stub_request(:post, webhook_url_regex)
end
shared_examples "triggered #{integration_name} integration" do |branches_to_be_notified: nil|
@@ -56,7 +58,7 @@ RSpec.shared_examples "chat integration" do |integration_name|
result = subject.execute(sample_data)
expect(result).to be(true)
- expect(WebMock).to have_requested(:post, webhook_url).once.with { |req|
+ expect(WebMock).to have_requested(:post, webhook_url_regex).once.with { |req|
json_body = Gitlab::Json.parse(req.body).with_indifferent_access
expect(json_body).to include(payload)
}
@@ -72,7 +74,7 @@ RSpec.shared_examples "chat integration" do |integration_name|
result = subject.execute(sample_data)
expect(result).to be_falsy
- expect(WebMock).not_to have_requested(:post, webhook_url)
+ expect(WebMock).not_to have_requested(:post, webhook_url_regex)
end
end
@@ -112,14 +114,14 @@ RSpec.shared_examples "chat integration" do |integration_name|
end
context "with protected branch" do
- before do
- create(:protected_branch, :create_branch_on_repository, project: project, name: "a-protected-branch")
- end
-
let(:sample_data) do
Gitlab::DataBuilder::Push.build(project: project, user: user, ref: "a-protected-branch")
end
+ before_all do
+ create(:protected_branch, :create_branch_on_repository, project: project, name: "a-protected-branch")
+ end
+
context "when only default branch are to be notified" do
it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "default"
end
@@ -214,7 +216,7 @@ RSpec.shared_examples "chat integration" do |integration_name|
let(:sample_data) { Gitlab::DataBuilder::Note.build(note, user) }
context "with commit comment" do
- let(:note) do
+ let_it_be(:note) do
create(:note_on_commit,
author: user,
project: project,
@@ -226,7 +228,7 @@ RSpec.shared_examples "chat integration" do |integration_name|
end
context "with merge request comment" do
- let(:note) do
+ let_it_be(:note) do
create(:note_on_merge_request, project: project, note: "merge request note")
end
@@ -234,7 +236,7 @@ RSpec.shared_examples "chat integration" do |integration_name|
end
context "with issue comment" do
- let(:note) do
+ let_it_be(:note) do
create(:note_on_issue, project: project, note: "issue note")
end
@@ -242,7 +244,7 @@ RSpec.shared_examples "chat integration" do |integration_name|
end
context "with snippet comment" do
- let(:note) do
+ let_it_be(:note) do
create(:note_on_project_snippet, project: project, note: "snippet note")
end
@@ -251,22 +253,24 @@ RSpec.shared_examples "chat integration" do |integration_name|
end
context "with pipeline events" do
- let(:pipeline) do
- create(:ci_pipeline,
- project: project, status: status,
- sha: project.commit.sha, ref: project.default_branch)
- end
-
let(:sample_data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
context "with failed pipeline" do
- let(:status) { "failed" }
+ let_it_be(:pipeline) do
+ create(:ci_pipeline,
+ project: project, status: "failed",
+ sha: project.commit.sha, ref: project.default_branch)
+ end
it_behaves_like "triggered #{integration_name} integration"
end
context "with succeeded pipeline" do
- let(:status) { "success" }
+ let_it_be(:pipeline) do
+ create(:ci_pipeline,
+ project: project, status: "success",
+ sha: project.commit.sha, ref: project.default_branch)
+ end
context "with default notify_only_broken_pipelines" do
it "does not call #{integration_name} API" do
@@ -308,7 +312,7 @@ RSpec.shared_examples "chat integration" do |integration_name|
end
context "with protected branch" do
- before do
+ before_all do
create(:protected_branch, :create_branch_on_repository, project: project, name: "a-protected-branch")
end
@@ -357,7 +361,8 @@ RSpec.shared_examples "chat integration" do |integration_name|
end
context 'deployment events' do
- let(:deployment) { create(:deployment) }
+ let_it_be(:deployment) { create(:deployment) }
+
let(:sample_data) { Gitlab::DataBuilder::Deployment.build(deployment, deployment.status, Time.now) }
it_behaves_like "untriggered #{integration_name} integration"
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 51071ae47c3..ca9122bf61f 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
@@ -37,7 +37,7 @@ RSpec.shared_examples 'cluster application core specs' do |application_name|
with_them do
subject { described_class.new(cluster: cluster).helm_command_module }
- let(:cluster) { build(:cluster, helm_major_version: helm_major_version)}
+ let(:cluster) { build(:cluster, helm_major_version: helm_major_version) }
it { is_expected.to eq(expected_helm_command_module) }
end
diff --git a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
index 8ff30021d6e..6f104f400bc 100644
--- a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
+++ b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
@@ -89,7 +89,7 @@ RSpec.shared_examples 'StageEventModel' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:user) }
let_it_be(:milestone) { create(:milestone) }
- let_it_be(:issuable_with_assignee) { create(issuable_factory, assignees: [user])}
+ let_it_be(:issuable_with_assignee) { create(issuable_factory, assignees: [user]) }
let_it_be(:record) { create(stage_event_factory, start_event_timestamp: 3.years.ago.to_date, end_event_timestamp: 2.years.ago.to_date) }
let_it_be(:record_with_author) { create(stage_event_factory, author_id: user.id) }
diff --git a/spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb b/spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb
index f4d5ab3d5c6..f3a12578912 100644
--- a/spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb
@@ -75,9 +75,9 @@ RSpec.shared_examples_for CounterAttribute do |counter_attributes|
end
context 'when attribute is not a counter attribute' do
- it 'delegates to ActiveRecord update!' do
+ it 'raises ArgumentError' do
expect { model.delayed_increment_counter(:unknown_attribute, 10) }
- .to raise_error(ActiveModel::MissingAttributeError)
+ .to raise_error(ArgumentError, 'unknown_attribute is not a counter attribute')
end
end
end
diff --git a/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb b/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb
index a403a27adef..0a07c9d677b 100644
--- a/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb
@@ -125,17 +125,17 @@ RSpec.shared_examples 'model with repository' do
end
describe '#valid_repo?' do
- it { expect(stubbed_container.valid_repo?).to be(false)}
+ it { expect(stubbed_container.valid_repo?).to be(false) }
it { expect(container.valid_repo?).to be(true) }
end
describe '#repository_exists?' do
- it { expect(stubbed_container.repository_exists?).to be(false)}
+ it { expect(stubbed_container.repository_exists?).to be(false) }
it { expect(container.repository_exists?).to be(true) }
end
describe '#repo_exists?' do
- it { expect(stubbed_container.repo_exists?).to be(false)}
+ it { expect(stubbed_container.repo_exists?).to be(false) }
it { expect(container.repo_exists?).to be(true) }
end
diff --git a/spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb b/spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb
index 8ee76efc896..a5970f134d9 100644
--- a/spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb
@@ -77,7 +77,7 @@ RSpec.shared_examples 'a model including Escalatable' do
end
context 'scopes' do
- let(:all_escalatables) { described_class.where(id: [triggered_escalatable, acknowledged_escalatable, ignored_escalatable, resolved_escalatable])}
+ let(:all_escalatables) { described_class.where(id: [triggered_escalatable, acknowledged_escalatable, ignored_escalatable, resolved_escalatable]) }
describe '.order_status' do
subject { all_escalatables.order_status(order) }
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 73066fb631a..f61007f57fd 100644
--- a/spec/support/shared_examples/models/label_note_shared_examples.rb
+++ b/spec/support/shared_examples/models/label_note_shared_examples.rb
@@ -12,7 +12,7 @@ RSpec.shared_examples 'label note created from events' do
def label_refs(events)
labels = events.map(&:label).compact
- labels.map { |l| l.to_reference}.sort.join(' ')
+ labels.map { |l| l.to_reference }.sort.join(' ')
end
let(:time) { Time.now }
diff --git a/spec/support/shared_examples/models/members_notifications_shared_example.rb b/spec/support/shared_examples/models/members_notifications_shared_example.rb
index 75eed0203a7..e74aab95e46 100644
--- a/spec/support/shared_examples/models/members_notifications_shared_example.rb
+++ b/spec/support/shared_examples/models/members_notifications_shared_example.rb
@@ -8,7 +8,7 @@ RSpec.shared_examples 'members notifications' do |entity_type|
end
describe "#after_create" do
- let(:member) { build(:"#{entity_type}_member") }
+ let(:member) { build(:"#{entity_type}_member", "#{entity_type}": create(entity_type.to_s)) }
it "sends email to user" do
expect(notification_service).to receive(:"new_#{entity_type}_member").with(member)
@@ -35,7 +35,7 @@ RSpec.shared_examples 'members notifications' do |entity_type|
describe '#after_commit' do
context 'on creation of a member requesting access' do
- let(:member) { build(:"#{entity_type}_member", :access_request) }
+ let(:member) { build(:"#{entity_type}_member", :access_request, "#{entity_type}": create(entity_type.to_s)) }
it "calls NotificationService.new_access_request" do
expect(notification_service).to receive(:new_access_request).with(member)
diff --git a/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb b/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb
index 6b0ae589efb..3d7d97bbeae 100644
--- a/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb
+++ b/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb
@@ -202,17 +202,17 @@ RSpec.shared_examples 'Debian Distribution' do |factory, container, can_freeze|
end
else
describe 'group distribution specifics' do
- let_it_be(:public_project) { create(:project, :public, group: distribution_with_suite.container)}
+ let_it_be(:public_project) { create(:project, :public, group: distribution_with_suite.container) }
let_it_be(:public_distribution_with_same_codename) { create(:debian_project_distribution, container: public_project, codename: distribution_with_suite.codename) }
- let_it_be(:public_package_with_same_codename) { create(:debian_package, project: public_project, published_in: public_distribution_with_same_codename)}
+ let_it_be(:public_package_with_same_codename) { create(:debian_package, project: public_project, published_in: public_distribution_with_same_codename) }
let_it_be(:public_distribution_with_same_suite) { create(:debian_project_distribution, container: public_project, suite: distribution_with_suite.suite) }
- let_it_be(:public_package_with_same_suite) { create(:debian_package, project: public_project, published_in: public_distribution_with_same_suite)}
+ let_it_be(:public_package_with_same_suite) { create(:debian_package, project: public_project, published_in: public_distribution_with_same_suite) }
- let_it_be(:private_project) { create(:project, :private, group: distribution_with_suite.container)}
+ let_it_be(:private_project) { create(:project, :private, group: distribution_with_suite.container) }
let_it_be(:private_distribution_with_same_codename) { create(:debian_project_distribution, container: private_project, codename: distribution_with_suite.codename) }
- let_it_be(:private_package_with_same_codename) { create(:debian_package, project: private_project, published_in: private_distribution_with_same_codename)}
+ let_it_be(:private_package_with_same_codename) { create(:debian_package, project: private_project, published_in: private_distribution_with_same_codename) }
let_it_be(:private_distribution_with_same_suite) { create(:debian_project_distribution, container: private_project, suite: distribution_with_suite.suite) }
- let_it_be(:private_package_with_same_suite) { create(:debian_package, project: private_project, published_in: private_distribution_with_same_codename)}
+ let_it_be(:private_package_with_same_suite) { create(:debian_package, project: private_project, published_in: private_distribution_with_same_codename) }
describe '#packages' do
subject { distribution_with_suite.packages }
diff --git a/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb b/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb
index 66cd8d1df12..9093b386a5d 100644
--- a/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb
+++ b/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb
@@ -64,7 +64,7 @@ RSpec.shared_examples 'latest successful build for sha or ref' do
context 'with build belonging to a child pipeline' do
let(:child_pipeline) { create_pipeline(project) }
let(:parent_bridge) { create(:ci_bridge, pipeline: pipeline, project: pipeline.project) }
- let!(:pipeline_source) { create(:ci_sources_pipeline, source_job: parent_bridge, pipeline: child_pipeline)}
+ let!(:pipeline_source) { create(:ci_sources_pipeline, source_job: parent_bridge, pipeline: child_pipeline) }
let!(:child_build) { create_build(child_pipeline, 'child-build') }
let(:build_name) { child_build.name }
diff --git a/spec/support/shared_examples/models/synthetic_note_shared_examples.rb b/spec/support/shared_examples/models/synthetic_note_shared_examples.rb
index a41ade2950a..12e865b1312 100644
--- a/spec/support/shared_examples/models/synthetic_note_shared_examples.rb
+++ b/spec/support/shared_examples/models/synthetic_note_shared_examples.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.shared_examples 'a synthetic note' do |action|
- it_behaves_like 'a system note', exclude_project: true do
+ it_behaves_like 'a system note', exclude_project: true, skip_persistence_check: true do
let(:action) { action }
end
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 ad0bbc0aeff..b81bd514d0a 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
@@ -26,9 +26,6 @@ RSpec.shared_examples 'UpdateProjectStatistics' do |with_counter_attribute|
expect(FlushCounterIncrementsWorker)
.to receive(:perform_in)
.with(CounterAttribute::WORKER_DELAY, project.statistics.class.name, project.statistics.id, project_statistics_name)
- expect(FlushCounterIncrementsWorker)
- .to receive(:perform_in)
- .with(CounterAttribute::WORKER_DELAY, project.statistics.class.name, project.statistics.id, :storage_size)
yield
diff --git a/spec/support/shared_examples/models/wiki_shared_examples.rb b/spec/support/shared_examples/models/wiki_shared_examples.rb
index 604c57768fe..5f6a10bd754 100644
--- a/spec/support/shared_examples/models/wiki_shared_examples.rb
+++ b/spec/support/shared_examples/models/wiki_shared_examples.rb
@@ -286,67 +286,134 @@ RSpec.shared_examples 'wiki model' do
end
describe '#find_page' do
- before do
- subject.create_page('index page', 'This is an awesome Gollum Wiki')
- end
+ shared_examples 'wiki model #find_page' do
+ before do
+ subject.create_page('index page', 'This is an awesome Gollum Wiki')
+ end
- it 'returns the latest version of the page if it exists' do
- page = subject.find_page('index page')
+ it 'returns the latest version of the page if it exists' do
+ page = subject.find_page('index page')
- expect(page.title).to eq('index page')
- end
+ expect(page.title).to eq('index page')
+ end
- it 'returns nil if the page or version does not exist' do
- expect(subject.find_page('non-existent')).to be_nil
- expect(subject.find_page('index page', 'non-existent')).to be_nil
- end
+ it 'returns nil if the page or version does not exist' do
+ expect(subject.find_page('non-existent')).to be_nil
+ expect(subject.find_page('index page', 'non-existent')).to be_nil
+ end
- it 'can find a page by slug' do
- page = subject.find_page('index-page')
+ it 'can find a page by slug' do
+ page = subject.find_page('index-page')
- expect(page.title).to eq('index page')
- end
+ expect(page.title).to eq('index page')
+ end
- it 'returns a WikiPage instance' do
- page = subject.find_page('index page')
+ it 'returns a WikiPage instance' do
+ page = subject.find_page('index page')
- expect(page).to be_a WikiPage
- end
+ expect(page).to be_a WikiPage
+ end
- context 'pages with multibyte-character title' do
- before do
- subject.create_page('autre pagé', "C'est un génial Gollum Wiki")
+ context 'pages with multibyte-character title' do
+ before do
+ subject.create_page('autre pagé', "C'est un génial Gollum Wiki")
+ end
+
+ it 'can find a page by slug' do
+ page = subject.find_page('autre pagé')
+
+ expect(page.title).to eq('autre pagé')
+ end
end
- it 'can find a page by slug' do
- page = subject.find_page('autre pagé')
+ context 'pages with invalidly-encoded content' do
+ before do
+ subject.create_page('encoding is fun', "f\xFCr".b)
+ end
+
+ it 'can find the page' do
+ page = subject.find_page('encoding is fun')
+
+ expect(page.content).to eq('fr')
+ end
+ end
+
+ context 'pages with different file extensions' do
+ where(:extension, :path, :title) do
+ [
+ [:md, "wiki-markdown.md", "wiki markdown"],
+ [:markdown, "wiki-markdown-2.md", "wiki markdown 2"],
+ [:rdoc, "wiki-rdoc.rdoc", "wiki rdoc"],
+ [:asciidoc, "wiki-asciidoc.asciidoc", "wiki asciidoc"],
+ [:adoc, "wiki-asciidoc-2.adoc", "wiki asciidoc 2"],
+ [:org, "wiki-org.org", "wiki org"],
+ [:textile, "wiki-textile.textile", "wiki textile"],
+ [:creole, "wiki-creole.creole", "wiki creole"],
+ [:rest, "wiki-rest.rest", "wiki rest"],
+ [:rst, "wiki-rest-2.rst", "wiki rest 2"],
+ [:mediawiki, "wiki-mediawiki.mediawiki", "wiki mediawiki"],
+ [:wiki, "wiki-mediawiki-2.wiki", "wiki mediawiki 2"],
+ [:pod, "wiki-pod.pod", "wiki pod"],
+ [:text, "wiki-text.txt", "wiki text"]
+ ]
+ end
- expect(page.title).to eq('autre pagé')
+ with_them do
+ before do
+ wiki.repository.create_file(
+ user, path, "content of wiki file",
+ branch_name: wiki.default_branch,
+ message: "created page #{path}",
+ author_email: user.email,
+ author_name: user.name
+ )
+ end
+
+ it "can find page with #{params[:extension]} extension" do
+ page = subject.find_page(title)
+
+ expect(page.content).to eq("content of wiki file")
+ end
+ end
end
end
- context 'pages with invalidly-encoded content' do
+ context 'find page with legacy wiki service' do
before do
- subject.create_page('encoding is fun', "f\xFCr".b)
+ stub_feature_flags(wiki_find_page_with_normal_repository_rpcs: false)
end
- it 'can find the page' do
- page = subject.find_page('encoding is fun')
+ it_behaves_like 'wiki model #find_page'
+ end
- expect(page.content).to eq('fr')
- end
+ context 'find page with normal repository RPCs' do
+ it_behaves_like 'wiki model #find_page'
end
end
describe '#find_sidebar' do
- before do
- subject.create_page(described_class::SIDEBAR, 'This is an awesome Sidebar')
+ shared_examples 'wiki model #find_sidebar' do
+ before do
+ subject.create_page(described_class::SIDEBAR, 'This is an awesome Sidebar')
+ end
+
+ it 'finds the page defined as _sidebar' do
+ page = subject.find_sidebar
+
+ expect(page.content).to eq('This is an awesome Sidebar')
+ end
end
- it 'finds the page defined as _sidebar' do
- page = subject.find_sidebar
+ context 'find sidebar with legacy wiki service' do
+ before do
+ stub_feature_flags(wiki_find_page_with_normal_repository_rpcs: false)
+ end
- expect(page.content).to eq('This is an awesome Sidebar')
+ it_behaves_like 'wiki model #find_sidebar'
+ end
+
+ context 'find sidebar with normal repository RPCs' do
+ it_behaves_like 'wiki model #find_sidebar'
end
end
@@ -450,9 +517,7 @@ RSpec.shared_examples 'wiki model' do
expect(subject.error_message).to match(/Duplicate page:/)
end
- end
- it_behaves_like 'create_page tests' do
it 'returns false if a page exists already in the repository', :aggregate_failures do
subject.create_page('test page', 'content')
@@ -540,6 +605,16 @@ RSpec.shared_examples 'wiki model' do
end
end
end
+
+ it_behaves_like 'create_page tests'
+
+ context 'create page with legacy find_page wiki service' do
+ it_behaves_like 'create_page tests' do
+ before do
+ stub_feature_flags(wiki_find_page_with_normal_repository_rpcs: false)
+ end
+ end
+ end
end
describe '#update_page' do
@@ -636,6 +711,17 @@ RSpec.shared_examples 'wiki model' do
include_context 'extended examples'
end
+ context 'update page with legacy find_page wiki service' do
+ it_behaves_like 'update_page tests' do
+ before do
+ stub_feature_flags(wiki_find_page_with_normal_repository_rpcs: false)
+ end
+
+ include_context 'common examples'
+ include_context 'extended examples'
+ end
+ end
+
context 'when format is invalid' do
let!(:page) { create(:wiki_page, wiki: subject, title: 'test page') }
diff --git a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
index 807295f8442..4afed5139d8 100644
--- a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
+++ b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
@@ -265,14 +265,6 @@ RSpec.shared_examples 'namespace traversal scopes' do
describe '.self_and_descendants' do
include_examples '.self_and_descendants'
-
- context 'with traversal_ids_btree feature flag disabled' do
- before do
- stub_feature_flags(traversal_ids_btree: false)
- end
-
- include_examples '.self_and_descendants'
- end
end
shared_examples '.self_and_descendant_ids' do
@@ -308,14 +300,6 @@ RSpec.shared_examples 'namespace traversal scopes' do
describe '.self_and_descendant_ids' do
include_examples '.self_and_descendant_ids'
-
- context 'with traversal_ids_btree feature flag disabled' do
- before do
- stub_feature_flags(traversal_ids_btree: false)
- end
-
- include_examples '.self_and_descendant_ids'
- end
end
shared_examples '.self_and_hierarchy' do
diff --git a/spec/support/shared_examples/policies/project_policy_shared_examples.rb b/spec/support/shared_examples/policies/project_policy_shared_examples.rb
index c4083df47e2..cfcc3615e13 100644
--- a/spec/support/shared_examples/policies/project_policy_shared_examples.rb
+++ b/spec/support/shared_examples/policies/project_policy_shared_examples.rb
@@ -107,70 +107,88 @@ RSpec.shared_examples 'deploy token does not get confused with user' do
end
RSpec.shared_examples 'project policies as guest' do
- context 'abilities for public projects' do
- let(:project) { public_project }
- let(:current_user) { guest }
-
- it do
- expect_allowed(*guest_permissions)
- expect_allowed(*public_permissions)
- expect_disallowed(*developer_permissions)
- expect_disallowed(*maintainer_permissions)
- expect_disallowed(*owner_permissions)
- end
+ let(:reporter_public_build_permissions) do
+ reporter_permissions - [:read_build, :read_pipeline]
end
- context 'abilities for non-public projects' do
- let(:project) { private_project }
- let(:current_user) { guest }
+ context 'as a direct project member' do
+ context 'abilities for public projects' do
+ let(:project) { public_project }
+ let(:current_user) { guest }
- let(:reporter_public_build_permissions) do
- reporter_permissions - [:read_build, :read_pipeline]
+ specify do
+ expect_allowed(*guest_permissions)
+ expect_allowed(*public_permissions)
+ expect_disallowed(*developer_permissions)
+ expect_disallowed(*maintainer_permissions)
+ expect_disallowed(*owner_permissions)
+ end
end
- it do
- expect_allowed(*guest_permissions)
- expect_disallowed(*reporter_public_build_permissions)
- expect_disallowed(*team_member_reporter_permissions)
- expect_disallowed(*developer_permissions)
- expect_disallowed(*maintainer_permissions)
- expect_disallowed(*owner_permissions)
- end
+ context 'abilities for non-public projects' do
+ let(:project) { private_project }
+ let(:current_user) { guest }
- it_behaves_like 'deploy token does not get confused with user' do
- let(:user_id) { guest.id }
- end
+ specify do
+ expect_allowed(*guest_permissions)
+ expect_disallowed(*reporter_public_build_permissions)
+ expect_disallowed(*team_member_reporter_permissions)
+ expect_disallowed(*developer_permissions)
+ expect_disallowed(*maintainer_permissions)
+ expect_disallowed(*owner_permissions)
+ end
- it_behaves_like 'archived project policies' do
- let(:regular_abilities) { guest_permissions }
- end
+ it_behaves_like 'deploy token does not get confused with user' do
+ let(:user_id) { guest.id }
+ end
- context 'public builds enabled' do
- it do
- expect_allowed(*guest_permissions)
- expect_allowed(:read_build, :read_pipeline)
+ it_behaves_like 'archived project policies' do
+ let(:regular_abilities) { guest_permissions }
end
- end
- context 'when public builds disabled' do
- before do
- project.update!(public_builds: false)
+ context 'public builds enabled' do
+ specify do
+ expect_allowed(*guest_permissions)
+ expect_allowed(:read_build, :read_pipeline)
+ end
end
- it do
- expect_allowed(*guest_permissions)
- expect_disallowed(:read_build, :read_pipeline)
+ context 'when public builds disabled' do
+ before do
+ project.update!(public_builds: false)
+ end
+
+ specify do
+ expect_allowed(*guest_permissions)
+ expect_disallowed(:read_build, :read_pipeline)
+ end
end
- end
- context 'when builds are disabled' do
- before do
- project.project_feature.update!(builds_access_level: ProjectFeature::DISABLED)
+ context 'when builds are disabled' do
+ before do
+ project.project_feature.update!(builds_access_level: ProjectFeature::DISABLED)
+ end
+
+ specify do
+ expect_disallowed(:read_build)
+ expect_allowed(:read_pipeline)
+ end
end
+ end
+ end
- it do
- expect_disallowed(:read_build)
- expect_allowed(:read_pipeline)
+ context 'as an inherited member from the group' do
+ context 'abilities for private projects' do
+ let(:project) { private_project_in_group }
+ let(:current_user) { inherited_guest }
+
+ specify do
+ expect_allowed(*guest_permissions)
+ expect_disallowed(*reporter_public_build_permissions)
+ expect_disallowed(*team_member_reporter_permissions)
+ expect_disallowed(*developer_permissions)
+ expect_disallowed(*maintainer_permissions)
+ expect_disallowed(*owner_permissions)
end
end
end
@@ -181,7 +199,7 @@ RSpec.shared_examples 'project policies as reporter' do
let(:project) { private_project }
let(:current_user) { reporter }
- it do
+ specify do
expect_allowed(*guest_permissions)
expect_allowed(*reporter_permissions)
expect_allowed(*team_member_reporter_permissions)
@@ -198,6 +216,22 @@ RSpec.shared_examples 'project policies as reporter' do
let(:regular_abilities) { reporter_permissions }
end
end
+
+ context 'as an inherited member from the group' do
+ context 'abilities for private projects' do
+ let(:project) { private_project_in_group }
+ let(:current_user) { inherited_reporter }
+
+ specify do
+ expect_allowed(*guest_permissions)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*team_member_reporter_permissions)
+ expect_disallowed(*developer_permissions)
+ expect_disallowed(*maintainer_permissions)
+ expect_disallowed(*owner_permissions)
+ end
+ end
+ end
end
RSpec.shared_examples 'project policies as developer' do
@@ -205,7 +239,7 @@ RSpec.shared_examples 'project policies as developer' do
let(:project) { private_project }
let(:current_user) { developer }
- it do
+ specify do
expect_allowed(*guest_permissions)
expect_allowed(*reporter_permissions)
expect_allowed(*team_member_reporter_permissions)
@@ -222,6 +256,22 @@ RSpec.shared_examples 'project policies as developer' do
let(:regular_abilities) { developer_permissions }
end
end
+
+ context 'as an inherited member from the group' do
+ context 'abilities for private projects' do
+ let(:project) { private_project_in_group }
+ let(:current_user) { inherited_developer }
+
+ specify do
+ expect_allowed(*guest_permissions)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*team_member_reporter_permissions)
+ expect_allowed(*developer_permissions)
+ expect_disallowed(*maintainer_permissions)
+ expect_disallowed(*owner_permissions)
+ end
+ end
+ end
end
RSpec.shared_examples 'project policies as maintainer' do
diff --git a/spec/support/shared_examples/projects/container_repository/cleanup_tags_service_shared_examples.rb b/spec/support/shared_examples/projects/container_repository/cleanup_tags_service_shared_examples.rb
new file mode 100644
index 00000000000..9c2d30a9c8c
--- /dev/null
+++ b/spec/support/shared_examples/projects/container_repository/cleanup_tags_service_shared_examples.rb
@@ -0,0 +1,263 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'handling invalid params' do |service_response_extra: {}, supports_caching: false|
+ context 'when no params are specified' do
+ let(:params) { {} }
+
+ it_behaves_like 'not removing anything',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching
+ end
+
+ context 'with invalid regular expressions' do
+ shared_examples 'handling an invalid regex' do
+ it 'keeps all tags' do
+ expect(Projects::ContainerRepository::DeleteTagsService)
+ .not_to receive(:new)
+ expect_no_caching unless supports_caching
+
+ subject
+ end
+
+ it { is_expected.to eq(status: :error, message: 'invalid regex') }
+
+ it 'calls error tracking service' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).and_call_original
+
+ subject
+ end
+ end
+
+ context 'when name_regex_delete is invalid' do
+ let(:params) { { 'name_regex_delete' => '*test*' } }
+
+ it_behaves_like 'handling an invalid regex'
+ end
+
+ context 'when name_regex is invalid' do
+ let(:params) { { 'name_regex' => '*test*' } }
+
+ it_behaves_like 'handling an invalid regex'
+ end
+
+ context 'when name_regex_keep is invalid' do
+ let(:params) { { 'name_regex_keep' => '*test*' } }
+
+ it_behaves_like 'handling an invalid regex'
+ end
+ end
+end
+
+RSpec.shared_examples 'when regex matching everything is specified' do
+ |service_response_extra: {}, supports_caching: false, delete_expectations:|
+ let(:params) do
+ { 'name_regex_delete' => '.*' }
+ end
+
+ it_behaves_like 'removing the expected tags',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching,
+ delete_expectations: delete_expectations
+
+ context 'with deprecated name_regex param' do
+ let(:params) do
+ { 'name_regex' => '.*' }
+ end
+
+ it_behaves_like 'removing the expected tags',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching,
+ delete_expectations: delete_expectations
+ end
+end
+
+RSpec.shared_examples 'when delete regex matching specific tags is used' do
+ |service_response_extra: {}, supports_caching: false|
+ let(:params) do
+ { 'name_regex_delete' => 'C|D' }
+ end
+
+ it_behaves_like 'removing the expected tags',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching,
+ delete_expectations: [%w[C D]]
+end
+
+RSpec.shared_examples 'when delete regex matching specific tags is used with overriding allow regex' do
+ |service_response_extra: {}, supports_caching: false|
+ let(:params) do
+ {
+ 'name_regex_delete' => 'C|D',
+ 'name_regex_keep' => 'C'
+ }
+ end
+
+ it_behaves_like 'removing the expected tags',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching,
+ delete_expectations: [%w[D]]
+
+ context 'with name_regex_delete overriding deprecated name_regex' do
+ let(:params) do
+ {
+ 'name_regex' => 'C|D',
+ 'name_regex_delete' => 'D'
+ }
+ end
+
+ it_behaves_like 'removing the expected tags',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching,
+ delete_expectations: [%w[D]]
+ end
+end
+
+RSpec.shared_examples 'with allow regex value' do
+ |service_response_extra: {}, supports_caching: false, delete_expectations:|
+ let(:params) do
+ {
+ 'name_regex_delete' => '.*',
+ 'name_regex_keep' => 'B.*'
+ }
+ end
+
+ it_behaves_like 'removing the expected tags',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching,
+ delete_expectations: delete_expectations
+end
+
+RSpec.shared_examples 'when keeping only N tags' do
+ |service_response_extra: {}, supports_caching: false, delete_expectations:|
+ let(:params) do
+ {
+ 'name_regex' => 'A|B.*|C',
+ 'keep_n' => 1
+ }
+ end
+
+ it 'sorts tags by date' do
+ delete_expectations.each { |expectation| expect_delete(expectation) }
+ expect_no_caching unless supports_caching
+
+ expect(service).to receive(:order_by_date_desc).at_least(:once).and_call_original
+
+ is_expected.to eq(expected_service_response(deleted: delete_expectations.flatten).merge(service_response_extra))
+ end
+end
+
+RSpec.shared_examples 'when not keeping N tags' do
+ |service_response_extra: {}, supports_caching: false, delete_expectations:|
+ let(:params) do
+ { 'name_regex' => 'A|B.*|C' }
+ end
+
+ it 'does not sort tags by date' do
+ delete_expectations.each { |expectation| expect_delete(expectation) }
+ expect_no_caching unless supports_caching
+
+ expect(service).not_to receive(:order_by_date_desc)
+
+ is_expected.to eq(expected_service_response(deleted: delete_expectations.flatten).merge(service_response_extra))
+ end
+end
+
+RSpec.shared_examples 'when removing keeping only 3' do
+ |service_response_extra: {}, supports_caching: false, delete_expectations:|
+ let(:params) do
+ { 'name_regex_delete' => '.*',
+ 'keep_n' => 3 }
+ end
+
+ it_behaves_like 'removing the expected tags',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching,
+ delete_expectations: delete_expectations
+end
+
+RSpec.shared_examples 'when removing older than 1 day' do
+ |service_response_extra: {}, supports_caching: false, delete_expectations:|
+ let(:params) do
+ {
+ 'name_regex_delete' => '.*',
+ 'older_than' => '1 day'
+ }
+ end
+
+ it_behaves_like 'removing the expected tags',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching,
+ delete_expectations: delete_expectations
+end
+
+RSpec.shared_examples 'when combining all parameters' do
+ |service_response_extra: {}, supports_caching: false, delete_expectations:|
+ let(:params) do
+ {
+ 'name_regex_delete' => '.*',
+ 'keep_n' => 1,
+ 'older_than' => '1 day'
+ }
+ end
+
+ it_behaves_like 'removing the expected tags',
+ service_response_extra: service_response_extra,
+ supports_caching: supports_caching,
+ delete_expectations: delete_expectations
+end
+
+RSpec.shared_examples 'when running a container_expiration_policy' do
+ |service_response_extra: {}, supports_caching: false, delete_expectations:|
+ let(:user) { nil }
+
+ context 'with valid container_expiration_policy param' do
+ let(:params) do
+ {
+ 'name_regex_delete' => '.*',
+ 'keep_n' => 1,
+ 'older_than' => '1 day',
+ 'container_expiration_policy' => true
+ }
+ end
+
+ it 'removes the expected tags' do
+ delete_expectations.each { |expectation| expect_delete(expectation, container_expiration_policy: true) }
+ expect_no_caching unless supports_caching
+
+ is_expected.to eq(expected_service_response(deleted: delete_expectations.flatten).merge(service_response_extra))
+ end
+ end
+
+ context 'without container_expiration_policy param' do
+ let(:params) do
+ {
+ 'name_regex_delete' => '.*',
+ 'keep_n' => 1,
+ 'older_than' => '1 day'
+ }
+ end
+
+ it 'fails' do
+ is_expected.to eq(status: :error, message: 'access denied')
+ end
+ end
+end
+
+RSpec.shared_examples 'not removing anything' do |service_response_extra: {}, supports_caching: false|
+ it 'does not remove anything' do
+ expect(Projects::ContainerRepository::DeleteTagsService).not_to receive(:new)
+ expect_no_caching unless supports_caching
+
+ is_expected.to eq(expected_service_response(deleted: []).merge(service_response_extra))
+ end
+end
+
+RSpec.shared_examples 'removing the expected tags' do
+ |service_response_extra: {}, supports_caching: false, delete_expectations:|
+ it 'removes the expected tags' do
+ delete_expectations.each { |expectation| expect_delete(expectation) }
+ expect_no_caching unless supports_caching
+
+ is_expected.to eq(expected_service_response(deleted: delete_expectations.flatten).merge(service_response_extra))
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/incident/timeline_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/incident/timeline_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..ae7e511a739
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/incident/timeline_quick_action_shared_examples.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'timeline quick action' do
+ describe '/timeline' do
+ context 'with valid args' do
+ where(:timeline_text, :date_time_arg) do
+ [
+ ['timeline comment', '2022-09-09 09:30'],
+ ['new timeline comment', '09:30'],
+ ['another timeline comment', ' 2022-09-09 09:15']
+ ]
+ end
+
+ with_them do
+ it 'adds a timeline event' do
+ add_note("/timeline #{timeline_text} | #{date_time_arg}")
+
+ expect(page).to have_content('Timeline event added successfully.')
+ expect(issue.incident_management_timeline_events.first.note).to eq(timeline_text)
+ expect(issue.incident_management_timeline_events.first.occurred_at).to eq(DateTime.parse(date_time_arg))
+ end
+ end
+
+ it 'adds a timeline event when no date is passed' do
+ freeze_time do
+ add_note('/timeline timeline event with not date')
+
+ expect(page).to have_content('Timeline event added successfully.')
+ expect(issue.incident_management_timeline_events.first.note).to eq('timeline event with not date')
+ expect(issue.incident_management_timeline_events.first.occurred_at).to eq(DateTime
+ .current.strftime("%Y-%m-%d %H:%M:00 UTC"))
+ end
+ end
+
+ it 'adds a timeline event when only date is passed' do
+ freeze_time do
+ add_note('/timeline timeline event with not date | 2022-10-11')
+
+ expect(page).to have_content('Timeline event added successfully.')
+ expect(issue.incident_management_timeline_events.first.note).to eq('timeline event with not date')
+ expect(issue.incident_management_timeline_events.first.occurred_at).to eq(DateTime
+ .current.strftime("%Y-%m-%d %H:%M:00 UTC"))
+ end
+ end
+ end
+
+ context 'with invalid args' do
+ where(:timeline_text, :date_time_arg) do
+ [
+ ['timeline comment', '2022-13-13 09:30'],
+ ['timeline comment 2', '2022-09-06 24:30']
+ ]
+ end
+
+ with_them do
+ it 'does not add a timeline event' do
+ add_note("/timeline #{timeline_text} | #{date_time_arg}")
+
+ expect(page).to have_content('Failed to apply commands.')
+ expect(issue.incident_management_timeline_events.length).to eq(0)
+ end
+ end
+ end
+
+ context 'when create service fails' do
+ before do
+ allow_next_instance_of(::IncidentManagement::TimelineEvents::CreateService) do |service|
+ allow(service).to receive(:execute).and_return(
+ ServiceResponse.error(payload: { timeline_event: nil }, message: 'Some error')
+ )
+ end
+ end
+
+ it 'does not add a timeline event' do
+ add_note('/timeline text | 2022-09-10 09:30')
+
+ expect(page).to have_content('Something went wrong while adding timeline event.')
+ expect(issue.incident_management_timeline_events.length).to eq(0)
+ end
+ end
+ end
+end
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 f414500f202..18304951e41 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,8 @@
# frozen_string_literal: true
RSpec.shared_examples 'issuable time tracker' do |issuable_type|
+ let_it_be(:time_tracker_selector) { '[data-testid="time-tracker"]' }
+
before do
project.add_maintainer(maintainer)
gitlab_sign_in(maintainer)
@@ -12,6 +14,14 @@ RSpec.shared_examples 'issuable time tracker' do |issuable_type|
wait_for_requests
end
+ def open_time_tracking_report
+ page.within time_tracker_selector do
+ click_link 'Time tracking report'
+
+ wait_for_requests
+ end
+ end
+
it 'renders the sidebar component empty state' do
page.within '[data-testid="noTrackingPane"]' do
expect(page).to have_content 'No estimate or time spent'
@@ -50,7 +60,7 @@ RSpec.shared_examples 'issuable time tracker' do |issuable_type|
submit_time('/estimate 3w 1d 1h')
submit_time('/remove_estimate')
- page.within '.time-tracking-component-wrap' do
+ page.within time_tracker_selector do
expect(page).to have_content 'No estimate or time spent'
end
end
@@ -59,13 +69,13 @@ RSpec.shared_examples 'issuable time tracker' do |issuable_type|
submit_time('/spend 3w 1d 1h')
submit_time('/remove_time_spent')
- page.within '.time-tracking-component-wrap' do
+ page.within time_tracker_selector do
expect(page).to have_content 'No estimate or time spent'
end
end
it 'shows the help state when icon is clicked' do
- page.within '.time-tracking-component-wrap' do
+ page.within time_tracker_selector do
find('[data-testid="helpButton"]').click
expect(page).to have_content 'Track time with quick actions'
expect(page).to have_content 'Learn more'
@@ -78,11 +88,7 @@ RSpec.shared_examples 'issuable time tracker' do |issuable_type|
wait_for_requests
- page.within '.time-tracking-component-wrap' do
- click_link 'Time tracking report'
-
- wait_for_requests
- end
+ open_time_tracking_report
page.within '#time-tracking-report' do
expect(find('tbody')).to have_content maintainer.name
@@ -90,8 +96,36 @@ RSpec.shared_examples 'issuable time tracker' do |issuable_type|
end
end
+ it 'removes time log when delete is clicked in time tracking report' do
+ submit_time('/estimate 1w')
+ submit_time('/spend 1d')
+ submit_time('/spend 3d')
+
+ wait_for_requests
+
+ open_time_tracking_report
+
+ page.within '#time-tracking-report tbody tr:nth-child(2)' do
+ click_button test_id: 'deleteButton'
+
+ wait_for_requests
+ end
+
+ # Assert that 2nd row was removed
+ expect(all('#time-tracking-report tbody tr').length).to eq(1)
+ expect(find('#time-tracking-report tbody')).not_to have_content('3d')
+
+ # Assert that summary line was updated
+ expect(find('#time-tracking-report tfoot')).to have_content('1d', exact: true)
+
+ # Assert that the time tracking widget was reactively updated
+ page.within '[data-testid="timeTrackingComparisonPane"]' do
+ expect(page).to have_content '1d'
+ end
+ end
+
it 'hides the help state when close icon is clicked' do
- page.within '.time-tracking-component-wrap' do
+ page.within time_tracker_selector do
find('[data-testid="helpButton"]').click
find('[data-testid="closeHelpButton"]').click
@@ -101,7 +135,7 @@ RSpec.shared_examples 'issuable time tracker' do |issuable_type|
end
it 'displays the correct help url' do
- page.within '.time-tracking-component-wrap' do
+ page.within time_tracker_selector do
find('[data-testid="helpButton"]').click
expect(find_link('Learn more')[:href]).to have_content('/help/user/project/time_tracking.md')
diff --git a/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb
index 2258bdd2c79..92705fc1b4d 100644
--- a/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb
@@ -75,7 +75,16 @@ RSpec.shared_examples 'rebase quick action' do
end
context 'when the merge request branch is protected from force push' do
- let!(:protected_branch) { create(:protected_branch, project: project, name: merge_request.source_branch, allow_force_push: false) }
+ let!(:protected_branch) do
+ ProtectedBranches::CreateService.new(
+ project,
+ user,
+ name: merge_request.source_branch,
+ allow_force_push: false,
+ push_access_levels_attributes: [{ access_level: Gitlab::Access::DEVELOPER }],
+ merge_access_levels_attributes: [{ access_level: Gitlab::Access::DEVELOPER }]
+ ).execute
+ end
it 'does not rebase the MR' do
add_note("/rebase")
diff --git a/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb b/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
index 6cd871d354c..017e6274cb0 100644
--- a/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
+++ b/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
@@ -108,18 +108,31 @@ RSpec.shared_examples 'PUT resource access tokens available' do
expect(resource.reload.bots).not_to include(bot_user)
end
- it 'converts issuables of the bot user to ghost user' do
- issue = create(:issue, author: bot_user)
+ context 'when user_destroy_with_limited_execution_time_worker is enabled' do
+ it 'creates GhostUserMigration records to handle migration in a worker' do
+ expect { subject }.to(
+ change { Users::GhostUserMigration.count }.from(0).to(1))
+ end
+ end
- subject
+ context 'when user_destroy_with_limited_execution_time_worker is disabled' do
+ before do
+ stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
+ end
- expect(issue.reload.author.ghost?).to be true
- end
+ it 'converts issuables of the bot user to ghost user' do
+ issue = create(:issue, author: bot_user)
- it 'deletes project bot user' do
- subject
+ subject
+
+ expect(issue.reload.author.ghost?).to be true
+ end
- expect(User.exists?(bot_user.id)).to be_falsy
+ it 'deletes project bot user' do
+ subject
+
+ expect(User.exists?(bot_user.id)).to be_falsy
+ end
end
context 'when unsuccessful' do
diff --git a/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb
index dc2c4f890b1..6a77de4266f 100644
--- a/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb
@@ -108,6 +108,7 @@ RSpec.shared_examples 'process Composer api request' do |user_type, status, add_
end
it_behaves_like 'returning response status', status
+ it_behaves_like 'bumping the package last downloaded at field' if status == :success
end
end
diff --git a/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb
index bb2f8965294..629d93676eb 100644
--- a/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb
@@ -355,7 +355,7 @@ RSpec.shared_examples 'recipe download_urls' do
it 'returns the download_urls for the recipe files' do
expected_response = {
- 'conanfile.py' => "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanfile.py",
+ 'conanfile.py' => "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanfile.py",
'conanmanifest.txt' => "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanmanifest.txt"
}
@@ -372,7 +372,7 @@ RSpec.shared_examples 'package download_urls' do
it 'returns the download_urls for the package files' do
expected_response = {
- 'conaninfo.txt' => "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conaninfo.txt",
+ 'conaninfo.txt' => "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conaninfo.txt",
'conanmanifest.txt' => "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conanmanifest.txt",
'conan_package.tgz' => "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conan_package.tgz"
}
@@ -412,7 +412,7 @@ RSpec.shared_examples 'recipe snapshot endpoint' do
conan_manifest_file = package.package_files.find_by(file_name: 'conanmanifest.txt')
expected_response = {
- 'conanfile.py' => conan_file_file.file_md5,
+ 'conanfile.py' => conan_file_file.file_md5,
'conanmanifest.txt' => conan_manifest_file.file_md5
}
@@ -435,7 +435,7 @@ RSpec.shared_examples 'package snapshot endpoint' do
context 'with existing package' do
it 'returns a hash of md5 values for the files' do
expected_response = {
- 'conaninfo.txt' => "12345abcde",
+ 'conaninfo.txt' => "12345abcde",
'conanmanifest.txt' => "12345abcde",
'conan_package.tgz' => "12345abcde"
}
@@ -486,7 +486,7 @@ RSpec.shared_examples 'recipe upload_urls endpoint' do
subject
expected_response = {
- 'conanfile.py': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanfile.py",
+ 'conanfile.py': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanfile.py",
'conanmanifest.txt': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanmanifest.txt"
}
@@ -505,7 +505,7 @@ RSpec.shared_examples 'recipe upload_urls endpoint' do
expected_response = {
'conan_sources.tgz': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conan_sources.tgz",
- 'conan_export.tgz': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conan_export.tgz",
+ 'conan_export.tgz': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conan_export.tgz",
'conanmanifest.txt': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanmanifest.txt"
}
@@ -547,7 +547,7 @@ RSpec.shared_examples 'package upload_urls endpoint' do
it 'returns a set of upload urls for the files requested' do
expected_response = {
- 'conaninfo.txt': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conaninfo.txt",
+ 'conaninfo.txt': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conaninfo.txt",
'conanmanifest.txt': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conanmanifest.txt",
'conan_package.tgz': "#{url_prefix}/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conan_package.tgz"
}
@@ -631,6 +631,7 @@ RSpec.shared_examples 'a public project with packages' do
end
it_behaves_like 'allows download with no token'
+ it_behaves_like 'bumping the package last downloaded at field'
it 'returns the file' do
subject
@@ -647,6 +648,7 @@ RSpec.shared_examples 'an internal project with packages' do
end
it_behaves_like 'denies download with no token'
+ it_behaves_like 'bumping the package last downloaded at field'
it 'returns the file' do
subject
@@ -662,6 +664,7 @@ RSpec.shared_examples 'a private project with packages' do
end
it_behaves_like 'denies download with no token'
+ it_behaves_like 'bumping the package last downloaded at field'
it 'returns the file' do
subject
diff --git a/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb
new file mode 100644
index 00000000000..22805cf7aed
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+# Requires `query(params)` , `user`, `issuable_data` and `issuable` bindings
+RSpec.shared_examples 'query with a search term' do
+ it 'returns only matching issuables' do
+ filter_params = { search: 'bar', in: [:DESCRIPTION] }
+ graphql_query = query(filter_params)
+
+ post_graphql(graphql_query, current_user: user)
+ ids = graphql_dig_at(issuable_data, :node, :id)
+
+ expect(ids).to contain_exactly(issuable.to_global_id.to_s)
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
index 9f7ec6e90e9..1b609915f32 100644
--- a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
@@ -9,9 +9,10 @@ RSpec.shared_examples 'group and project packages query' do
let_it_be(:composer_package) { create(:composer_package, project: project2, name: 'dab', version: '4.0.0', created_at: 3.days.ago) }
let_it_be(:debian_package) { create(:debian_package, project: project2, name: 'aab', version: '5.0.0', created_at: 2.days.ago) }
let_it_be(:composer_metadatum) do
- create(:composer_metadatum, package: composer_package,
- target_sha: 'afdeh',
- composer_json: { name: 'x', type: 'y', license: 'z', version: 1 })
+ create(:composer_metadatum,
+ package: composer_package,
+ target_sha: 'afdeh',
+ composer_json: { name: 'x', type: 'y', license: 'z', version: 1 })
end
let(:package_names) { graphql_data_at(resource_type, :packages, :nodes, :name) }
diff --git a/spec/support/shared_examples/requests/api/helm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/helm_packages_shared_examples.rb
index acbcf4f7f3d..06ed0448b50 100644
--- a/spec/support/shared_examples/requests/api/helm_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/helm_packages_shared_examples.rb
@@ -191,14 +191,15 @@ RSpec.shared_examples 'process helm download content request' do |user_type, sta
end
end
- it_behaves_like 'a package tracking event', 'API::HelmPackages', 'pull_package'
-
it 'returns expected status and a valid package archive' do
subject
expect(response).to have_gitlab_http_status(status)
expect(response.media_type).to eq('application/octet-stream')
end
+
+ it_behaves_like 'a package tracking event', 'API::HelmPackages', 'pull_package'
+ it_behaves_like 'bumping the package last downloaded at field'
end
end
@@ -278,7 +279,6 @@ RSpec.shared_examples 'handling helm chart index requests' do
end
it_behaves_like 'deploy token for package GET requests'
-
it_behaves_like 'rejects helm access with unknown project id' do
subject { get api(url) }
end
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 971b21b5b32..8c4ff120471 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
def get_issue
- json_response.is_a?(Array) ? json_response.detect {|issue| issue['id'] == target_issue.id} : json_response
+ json_response.is_a?(Array) ? json_response.detect { |issue| issue['id'] == target_issue.id } : json_response
end
RSpec.shared_examples 'accessible merge requests count' do
diff --git a/spec/support/shared_examples/requests/api/labels_api_shared_examples.rb b/spec/support/shared_examples/requests/api/labels_api_shared_examples.rb
index 02e50b789cc..41d21490343 100644
--- a/spec/support/shared_examples/requests/api/labels_api_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/labels_api_shared_examples.rb
@@ -9,6 +9,6 @@ RSpec.shared_examples 'fetches labels' do
expect(json_response).to be_an Array
expect(json_response).to all(match_schema('public_api/v4/labels/label'))
expect(json_response.size).to eq(expected_labels.size)
- expect(json_response.map {|r| r['name'] }).to match_array(expected_labels)
+ expect(json_response.map { |r| r['name'] }).to match_array(expected_labels)
end
end
diff --git a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
index 6568d51b90e..fdd55893deb 100644
--- a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
@@ -293,6 +293,8 @@ RSpec.shared_examples 'process nuget download content request' do |user_type, st
it_behaves_like 'a package tracking event', 'API::NugetPackages', 'pull_package'
+ it_behaves_like 'bumping the package last downloaded at field'
+
it 'returns a valid package archive' do
subject
@@ -315,6 +317,8 @@ RSpec.shared_examples 'process nuget download content request' do |user_type, st
end
it_behaves_like 'a package tracking event', 'API::NugetPackages', 'pull_symbol_package'
+
+ it_behaves_like 'bumping the package last downloaded at field'
end
context 'with lower case package name' do
diff --git a/spec/support/shared_examples/requests/api/packages_shared_examples.rb b/spec/support/shared_examples/requests/api/packages_shared_examples.rb
index eb650b7a09f..860cb1b1d86 100644
--- a/spec/support/shared_examples/requests/api/packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/packages_shared_examples.rb
@@ -165,3 +165,10 @@ RSpec.shared_examples 'not a package tracking event' do
expect_no_snowplow_event
end
end
+
+RSpec.shared_examples 'bumping the package last downloaded at field' do
+ it 'bumps last_downloaded_at' do
+ expect { subject }
+ .to change { package.reload.last_downloaded_at }.from(nil).to(instance_of(ActiveSupport::TimeWithZone))
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
index ba8311bf0be..f411b5699a9 100644
--- a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
@@ -167,6 +167,7 @@ RSpec.shared_examples 'PyPI package download' do |user_type, status, add_member
it_behaves_like 'returning response status', status
it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
+ it_behaves_like 'bumping the package last downloaded at field'
end
end
diff --git a/spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb b/spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb
index 3ca2b9fa6de..2d036cb2aa3 100644
--- a/spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb
@@ -70,7 +70,7 @@ RSpec.shared_examples 'repository_storage_moves API' do |container_type|
get_container_repository_storage_moves
- json_ids = json_response.map {|storage_move| storage_move['id'] }
+ json_ids = json_response.map { |storage_move| storage_move['id'] }
expect(json_ids).to eq([
storage_move.id,
storage_move_middle.id,
diff --git a/spec/support/shared_examples/requests/api/resource_state_events_api_shared_examples.rb b/spec/support/shared_examples/requests/api/resource_state_events_api_shared_examples.rb
new file mode 100644
index 00000000000..c1850a0d0c9
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/resource_state_events_api_shared_examples.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'resource_state_events API' do |parent_type, eventable_type, id_name|
+ let(:base_path) { "/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}" }
+
+ describe "GET /#{parent_type}/:id/#{eventable_type}/:noteable_id/resource_state_events" do
+ let!(:event) { create_event }
+
+ it "returns an array of resource state events" do
+ url = "#{base_path}/resource_state_events"
+ 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.first['id']).to eq(event.id)
+ expect(json_response.first['state']).to eq(event.state.to_s)
+ end
+
+ it "returns a 404 error when eventable id not found" do
+ get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{non_existing_record_id}/resource_state_events", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it "returns 404 when not authorized" do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ private_user = create(:user)
+
+ get api("#{base_path}/resource_state_events", private_user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ describe "GET /#{parent_type}/:id/#{eventable_type}/:noteable_id/resource_state_events/:event_id" do
+ let!(:event) { create_event }
+
+ it "returns a resource state event by id" do
+ get api("#{base_path}/resource_state_events/#{event.id}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['id']).to eq(event.id)
+ expect(json_response['state']).to eq(event.state.to_s)
+ end
+
+ it "returns 404 when not authorized" do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ private_user = create(:user)
+
+ get api("#{base_path}/resource_state_events/#{event.id}", private_user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it "returns a 404 error if resource state event not found" do
+ get api("#{base_path}/resource_state_events/#{non_existing_record_id}", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ describe 'pagination' do
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/220192
+ it 'returns the second page' do
+ create_event
+ event2 = create_event
+
+ get api("#{base_path}/resource_state_events?page=2&per_page=1", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(response.headers['X-Total']).to eq '2'
+ expect(json_response.count).to eq(1)
+ expect(json_response.first['id']).to eq(event2.id)
+ end
+ end
+
+ def create_event(state: :opened)
+ create(:resource_state_event, eventable.class.name.underscore => eventable, state: state)
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/rubygems_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/rubygems_packages_shared_examples.rb
index abdb468353a..f075927e7bf 100644
--- a/spec/support/shared_examples/requests/api/rubygems_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/rubygems_packages_shared_examples.rb
@@ -203,5 +203,6 @@ RSpec.shared_examples 'Rubygems gem download' do |user_type, status, add_member
end
it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
+ it_behaves_like 'bumping the package last downloaded at field'
end
end
diff --git a/spec/support/shared_examples/requests/api/snippets_shared_examples.rb b/spec/support/shared_examples/requests/api/snippets_shared_examples.rb
index 2b72c69cb37..1b92eb56f54 100644
--- a/spec/support/shared_examples/requests/api/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/snippets_shared_examples.rb
@@ -133,7 +133,7 @@ RSpec.shared_examples 'snippet file updates' do
context 'when save fails due to a repository commit error' do
before do
allow_next_instance_of(Repository) do |instance|
- allow(instance).to receive(:multi_action).and_raise(Gitlab::Git::CommitError)
+ allow(instance).to receive(:commit_files).and_raise(Gitlab::Git::CommitError)
end
update_snippet(params: { files: [create_action] })
diff --git a/spec/support/shared_examples/requests/applications_controller_shared_examples.rb b/spec/support/shared_examples/requests/applications_controller_shared_examples.rb
index 8f852d42c2c..642930dd982 100644
--- a/spec/support/shared_examples/requests/applications_controller_shared_examples.rb
+++ b/spec/support/shared_examples/requests/applications_controller_shared_examples.rb
@@ -11,6 +11,7 @@ RSpec.shared_examples 'applications controller - GET #show' do
context 'when application is viewed after being created' do
before do
create_application
+ stub_feature_flags(hash_oauth_secrets: false)
end
it 'sets `@created` instance variable to `true`' do
@@ -21,6 +22,10 @@ RSpec.shared_examples 'applications controller - GET #show' do
end
context 'when application is reviewed' do
+ before do
+ stub_feature_flags(hash_oauth_secrets: false)
+ end
+
it 'sets `@created` instance variable to `false`' do
get show_path
@@ -32,6 +37,7 @@ end
RSpec.shared_examples 'applications controller - POST #create' do
it "sets `#{OauthApplications::CREATED_SESSION_KEY}` session key to `true`" do
+ stub_feature_flags(hash_oauth_secrets: false)
create_application
expect(session[OauthApplications::CREATED_SESSION_KEY]).to eq(true)
diff --git a/spec/support/shared_examples/requests/lfs_http_shared_examples.rb b/spec/support/shared_examples/requests/lfs_http_shared_examples.rb
index 294ceffd77b..83be0cc1fe3 100644
--- a/spec/support/shared_examples/requests/lfs_http_shared_examples.rb
+++ b/spec/support/shared_examples/requests/lfs_http_shared_examples.rb
@@ -49,7 +49,7 @@ RSpec.shared_examples 'LFS http 404 response' do
end
RSpec.shared_examples 'LFS http expected response code and message' do
- let(:response_code) { }
+ let(:response_code) {}
let(:response_headers) { {} }
let(:content_type) { LfsRequest::CONTENT_TYPE }
let(:message) {}
diff --git a/spec/support/shared_examples/requests/projects/google_cloud/google_cloud_ff_examples.rb b/spec/support/shared_examples/requests/projects/google_cloud/google_cloud_ff_examples.rb
new file mode 100644
index 00000000000..d49fe517c60
--- /dev/null
+++ b/spec/support/shared_examples/requests/projects/google_cloud/google_cloud_ff_examples.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'requires feature flag `incubation_5mp_google_cloud` enabled' do
+ context 'when feature flag is disabled' do
+ before do
+ project.add_maintainer(user)
+ stub_feature_flags(incubation_5mp_google_cloud: false)
+ end
+
+ it 'renders not found' do
+ sign_in(user)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/projects/google_cloud/google_cloud_role_examples.rb b/spec/support/shared_examples/requests/projects/google_cloud/google_cloud_role_examples.rb
new file mode 100644
index 00000000000..4c616b59be0
--- /dev/null
+++ b/spec/support/shared_examples/requests/projects/google_cloud/google_cloud_role_examples.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'requires `admin_project_google_cloud` role' do
+ shared_examples 'returns not_found' do
+ it 'returns not found' do
+ sign_in(user)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ shared_examples 'redirects to authorize url' do
+ it 'redirects to authorize url' do
+ sign_in(user)
+
+ subject
+
+ expect(response).to redirect_to(assigns(:authorize_url))
+ end
+ end
+
+ context 'when requested by users with different roles' do
+ let_it_be(:guest) { create(:user) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+
+ before do
+ project.add_guest(guest)
+ project.add_developer(developer)
+ project.add_maintainer(maintainer)
+ end
+
+ context 'for unauthorized users' do
+ include_examples 'returns not_found' do
+ let(:user) { guest }
+ end
+
+ include_examples 'returns not_found' do
+ let(:user) { developer }
+ end
+ end
+
+ context 'for authorized users' do
+ include_examples 'redirects to authorize url' do
+ let(:user) { maintainer }
+ end
+
+ include_examples 'redirects to authorize url' do
+ let(:user) { project.owner }
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/projects/google_cloud/google_oauth2_config_examples.rb b/spec/support/shared_examples/requests/projects/google_cloud/google_oauth2_config_examples.rb
new file mode 100644
index 00000000000..63f6cffb3a0
--- /dev/null
+++ b/spec/support/shared_examples/requests/projects/google_cloud/google_oauth2_config_examples.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'requires valid Google OAuth2 configuration' do
+ context 'when GitLab instance does not have valid Google OAuth2 configuration ' do
+ before do
+ project.add_maintainer(user)
+ unconfigured_google_oauth2 = Struct.new(:app_id, :app_secret)
+ .new('', '')
+ allow(Gitlab::Auth::OAuth::Provider).to receive(:config_for)
+ .with('google_oauth2')
+ .and_return(unconfigured_google_oauth2)
+ end
+
+ it 'renders forbidden' do
+ sign_in(user)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/projects/google_cloud/google_oauth2_token_examples.rb b/spec/support/shared_examples/requests/projects/google_cloud/google_oauth2_token_examples.rb
new file mode 100644
index 00000000000..379327be0db
--- /dev/null
+++ b/spec/support/shared_examples/requests/projects/google_cloud/google_oauth2_token_examples.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'requires valid Google Oauth2 token' do
+ context 'when a valid Google OAuth2 token does not exist' do
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ it 'triggers Google OAuth2 flow on request' do
+ subject
+
+ expect(response).to redirect_to(assigns(:authorize_url))
+ end
+
+ context 'and a valid Google OAuth2 token gets created' do
+ before do
+ allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |client|
+ allow(client).to receive(:validate_token).and_return(true)
+ allow(client).to receive(:list_projects).and_return(mock_gcp_projects) if mock_gcp_projects
+ end
+
+ allow_next_instance_of(BranchesFinder) do |finder|
+ allow(finder).to receive(:execute).and_return(mock_branches) if mock_branches
+ end
+
+ allow_next_instance_of(TagsFinder) do |finder|
+ allow(finder).to receive(:execute).and_return(mock_branches) if mock_branches
+ end
+ end
+
+ it 'renders template as expected' do
+ if renders_template
+ subject
+ expect(response).to render_template(renders_template)
+ end
+ end
+
+ it 'redirects as expected' do
+ if redirects_to
+ subject
+ expect(response).to redirect_to(redirects_to)
+ end
+ end
+ end
+ end
+end
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 d4417b23a5f..11759b6671f 100644
--- a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
+++ b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
@@ -518,7 +518,7 @@ RSpec.shared_examples 'rate-limited unauthenticated requests' do
context 'when the request is to the api internal endpoints' do
it 'allows requests over the rate limit' do
(1 + requests_per_period).times do
- get '/api/v4/internal/check', params: { secret_token: Gitlab::Shell.secret_token }
+ get '/api/v4/internal/check', headers: GitlabShellHelpers.gitlab_shell_internal_api_request_header
expect(response).to have_gitlab_http_status(:ok)
end
end
diff --git a/spec/support/shared_examples/routing/resource_routing_shared_examples.rb b/spec/support/shared_examples/routing/resource_routing_shared_examples.rb
index b98901a57ea..d7a674f3522 100644
--- a/spec/support/shared_examples/routing/resource_routing_shared_examples.rb
+++ b/spec/support/shared_examples/routing/resource_routing_shared_examples.rb
@@ -43,12 +43,12 @@ RSpec.shared_examples 'resource routing' do
let(:default_actions) do
{
- index: [:get, ''],
- show: [:get, '/:id'],
- new: [:get, '/new'],
- create: [:post, ''],
- edit: [:get, '/:id/edit'],
- update: [:put, '/:id'],
+ index: [:get, ''],
+ show: [:get, '/:id'],
+ new: [:get, '/new'],
+ create: [:post, ''],
+ edit: [:get, '/:id/edit'],
+ update: [:put, '/:id'],
destroy: [:delete, '/:id']
}
end
diff --git a/spec/support/shared_examples/routing/wiki_routing_shared_examples.rb b/spec/support/shared_examples/routing/wiki_routing_shared_examples.rb
index 9289934677e..64f237f0d4d 100644
--- a/spec/support/shared_examples/routing/wiki_routing_shared_examples.rb
+++ b/spec/support/shared_examples/routing/wiki_routing_shared_examples.rb
@@ -6,9 +6,9 @@ RSpec.shared_examples 'wiki routing' do
let(:actions) { %i[show new create edit update destroy] }
let(:additional_actions) do
{
- pages: [:get, '/pages'],
- history: [:get, '/:id/history'],
- git_access: [:get, '/git_access'],
+ pages: [:get, '/pages'],
+ history: [:get, '/:id/history'],
+ git_access: [:get, '/git_access'],
preview_markdown: [:post, '/:id/preview_markdown']
}
end
diff --git a/spec/support/shared_examples/security_training_providers_importer.rb b/spec/support/shared_examples/security_training_providers_importer.rb
new file mode 100644
index 00000000000..568e3e1a4f2
--- /dev/null
+++ b/spec/support/shared_examples/security_training_providers_importer.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'security training providers importer' do
+ let(:security_training_providers) do
+ Class.new(ApplicationRecord) do
+ self.table_name = 'security_training_providers'
+ end
+ end
+
+ it 'upserts security training providers' do
+ expect { 2.times { subject } }.to change(security_training_providers, :count).from(0).to(2)
+ expect(security_training_providers.all.map(&:name)).to match_array(['Kontra', 'Secure Code Warrior'])
+ end
+end
diff --git a/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb b/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb
index 6d59943d91c..9eaad541df7 100644
--- a/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb
+++ b/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb
@@ -9,7 +9,8 @@ RSpec.shared_examples 'avoid N+1 on environments serialization' do
create_environment_with_associations(project)
# See issue: https://gitlab.com/gitlab-org/gitlab/-/issues/363317
- relax_count = 1
+ # See also: https://gitlab.com/gitlab-org/gitlab/-/issues/373151
+ relax_count = 4
expect { serialize(grouping: true) }.not_to exceed_query_limit(control.count + relax_count)
end
@@ -23,7 +24,8 @@ RSpec.shared_examples 'avoid N+1 on environments serialization' do
create_environment_with_associations(project)
# See issue: https://gitlab.com/gitlab-org/gitlab/-/issues/363317
- relax_count = 1
+ # See also: https://gitlab.com/gitlab-org/gitlab/-/issues/373151
+ relax_count = 5
expect { serialize(grouping: false) }.not_to exceed_query_limit(control.count + relax_count)
end
diff --git a/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb b/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
index 6cae7d8e00f..0db9519f760 100644
--- a/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
+++ b/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
@@ -23,12 +23,10 @@ RSpec.shared_examples 'creates an alert management alert or errors' do
end
context 'and fails to save' do
- let(:errors) { double(messages: { hosts: ['hosts array is over 255 chars'] }, '[]': [] )}
-
before do
- allow(service).to receive(:alert).and_call_original
- allow(service).to receive_message_chain(:alert, :save).and_return(false)
- allow(service).to receive_message_chain(:alert, :errors).and_return(errors)
+ allow(AlertManagement::Alert).to receive(:new).and_wrap_original do |m, **args|
+ m.call(**args, hosts: ['a' * 256]) # hosts should be 255
+ end
end
it_behaves_like 'alerts service responds with an error', :bad_request
diff --git a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
index a46c2f0ac5c..162be24fe8f 100644
--- a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
@@ -3,8 +3,8 @@
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)}
- .to change {issue.reload.updated_at}
+ expect { described_class.new(parent, user, params).execute(issue) }
+ .to change { issue.reload.updated_at }
end
end
@@ -140,6 +140,40 @@ RSpec.shared_examples 'issues move service' do |group|
expect(issue2.reload.updated_at.change(usec: 0)).to eq updated_at2.change(usec: 0)
end
+ context 'when moving to a specific list position' do
+ before do
+ [issue1, issue2, issue].each do |issue|
+ issue.move_to_end && issue.save!
+ end
+ end
+
+ it 'moves issue to the top of the list' do
+ described_class.new(parent, user, params.merge({ position_in_list: 0 })).execute(issue)
+
+ expect(issue.relative_position).to be < issue1.relative_position
+ end
+
+ it 'moves issue to a position in the middle of the list' do
+ described_class.new(parent, user, params.merge({ position_in_list: 1 })).execute(issue)
+
+ expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
+ end
+
+ it 'moves issue to the bottom of the list' do
+ described_class.new(parent, user, params.merge({ position_in_list: -1 })).execute(issue1)
+
+ expect(issue1.relative_position).to be > issue.relative_position
+ end
+
+ context 'when given position is greater than number of issues in the list' do
+ it 'moves the issue to the bottom of the list' do
+ described_class.new(parent, user, params.merge({ position_in_list: 5 })).execute(issue1)
+
+ expect(issue1.relative_position).to be > issue.relative_position
+ end
+ end
+ end
+
def reorder_issues(params, issues: [])
issues.each do |issue|
issue.move_to_end && issue.save!
diff --git a/spec/support/shared_examples/services/common_system_notes_shared_examples.rb b/spec/support/shared_examples/services/common_system_notes_shared_examples.rb
index ce412ef55de..1887b38b50e 100644
--- a/spec/support/shared_examples/services/common_system_notes_shared_examples.rb
+++ b/spec/support/shared_examples/services/common_system_notes_shared_examples.rb
@@ -42,6 +42,7 @@ RSpec.shared_examples 'a system note' do |params|
it 'has the correct attributes', :aggregate_failures do
exclude_project = !params.nil? && params[:exclude_project]
+ skip_persistence_check = !params.nil? && params[:skip_persistence_check]
expect(subject).to be_valid
expect(subject).to be_system
@@ -50,6 +51,7 @@ RSpec.shared_examples 'a system note' do |params|
expect(subject.project).to eq project unless exclude_project
expect(subject.author).to eq author
+ expect(subject.system_note_metadata).to be_persisted unless skip_persistence_check
expect(subject.system_note_metadata.action).to eq(action)
expect(subject.system_note_metadata.commit_count).to eq(commit_count)
end
diff --git a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
index 3be59af6a37..58659775d8c 100644
--- a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
@@ -54,6 +54,12 @@ RSpec.shared_examples 'a valid token' do
end
end
+RSpec.shared_examples 'with auth_type' do
+ let(:current_params) { super().merge(auth_type: :foo) }
+
+ it { expect(payload['auth_type']).to eq('foo') }
+end
+
RSpec.shared_examples 'a browsable' do
let(:access) do
[{ 'type' => 'registry',
@@ -199,8 +205,8 @@ RSpec.shared_examples 'a container registry auth service' do
describe '.import_access_token' do
let(:access) do
[{ 'type' => 'registry',
- 'name' => 'import',
- 'actions' => ['*'] }]
+ 'name' => 'import',
+ 'actions' => ['*'] }]
end
let(:token) { described_class.import_access_token }
@@ -286,6 +292,7 @@ RSpec.shared_examples 'a container registry auth service' do
shared_examples 'private project' do
context 'allow to use scope-less authentication' do
it_behaves_like 'a valid token'
+ it_behaves_like 'with auth_type'
end
context 'allow developer to push images' do
@@ -299,6 +306,7 @@ RSpec.shared_examples 'a container registry auth service' do
it_behaves_like 'a pushable'
it_behaves_like 'container repository factory'
+ it_behaves_like 'with auth_type'
end
context 'disallow developer to delete images' do
@@ -341,6 +349,7 @@ RSpec.shared_examples 'a container registry auth service' do
it_behaves_like 'a pullable'
it_behaves_like 'not a container repository factory'
+ it_behaves_like 'with auth_type'
end
end
@@ -381,6 +390,7 @@ RSpec.shared_examples 'a container registry auth service' do
it_behaves_like 'a pullable'
it_behaves_like 'not a container repository factory'
+ it_behaves_like 'with auth_type'
end
context 'disallow guest to pull or push images' do
@@ -445,6 +455,7 @@ RSpec.shared_examples 'a container registry auth service' do
it_behaves_like 'a pullable'
it_behaves_like 'not a container repository factory'
+ it_behaves_like 'with auth_type'
end
context 'disallow anyone to push images' do
@@ -495,6 +506,7 @@ RSpec.shared_examples 'a container registry auth service' do
it_behaves_like 'a pullable'
it_behaves_like 'not a container repository factory'
+ it_behaves_like 'with auth_type'
end
context 'disallow anyone to push images' do
@@ -600,6 +612,7 @@ RSpec.shared_examples 'a container registry auth service' do
end
it_behaves_like 'a valid token'
+ it_behaves_like 'with auth_type'
context 'allow to pull and push images' do
let(:current_params) do
@@ -944,10 +957,11 @@ RSpec.shared_examples 'a container registry auth service' do
shared_examples 'able to login' do
context 'registry provides read_container_image authentication_abilities' do
- let(:current_params) { { deploy_token: deploy_token } }
+ let(:current_params) { { deploy_token: deploy_token, auth_type: :deploy_token } }
let(:authentication_abilities) { [:read_container_image] }
it_behaves_like 'an authenticated'
+ it { expect(payload['auth_type']).to eq('deploy_token') }
end
end
diff --git a/spec/support/shared_examples/services/feature_flags/client_shared_examples.rb b/spec/support/shared_examples/services/feature_flags/client_shared_examples.rb
index a62cffc0e1b..73a02905914 100644
--- a/spec/support/shared_examples/services/feature_flags/client_shared_examples.rb
+++ b/spec/support/shared_examples/services/feature_flags/client_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'update feature flag client' do
+RSpec.shared_examples_for 'update feature flag client' do
let!(:client) { create(:operations_feature_flags_client, project: project) }
it 'updates last feature flag updated at' do
@@ -10,7 +10,7 @@ shared_examples_for 'update feature flag client' do
end
end
-shared_examples_for 'does not update feature flag client' do
+RSpec.shared_examples_for 'does not update feature flag client' do
let!(:client) { create(:operations_feature_flags_client, project: project) }
it 'does not update last feature flag updated at' do
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 2aac7e328f0..366fa4763e1 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
@@ -33,7 +33,7 @@ RSpec.shared_examples 'gitlab projects import validations' do
context 'when there is a project with the same path' do
let(:existing_project) { create(:project, namespace: namespace) }
- let(:path) { existing_project.path}
+ let(:path) { existing_project.path }
it 'does not create the project' do
project = subject.execute
diff --git a/spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb b/spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb
index 31571b1ffb9..92681b8ba79 100644
--- a/spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples_for 'service scheduling async deletes' do
+RSpec.shared_examples_for 'service scheduling async deletes' do
it 'destroys associated todos asynchronously' do
expect(worker_class)
.to receive(:perform_async)
@@ -20,13 +20,13 @@ shared_examples_for 'service scheduling async deletes' do
end
end
-shared_examples_for 'service deleting todos' do
+RSpec.shared_examples_for 'service deleting todos' do
it_behaves_like 'service scheduling async deletes' do
let(:worker_class) { TodosDestroyer::DestroyedIssuableWorker }
end
end
-shared_examples_for 'service deleting label links' do
+RSpec.shared_examples_for 'service deleting label links' do
it_behaves_like 'service scheduling async deletes' do
let(:worker_class) { Issuable::LabelLinksDestroyWorker }
end
diff --git a/spec/support/shared_examples/services/issuable/update_service_shared_examples.rb b/spec/support/shared_examples/services/issuable/update_service_shared_examples.rb
new file mode 100644
index 00000000000..3d90885dd6f
--- /dev/null
+++ b/spec/support/shared_examples/services/issuable/update_service_shared_examples.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples_for 'issuable update service updating last_edited_at values' do
+ context 'when updating the title of the issuable' do
+ let(:update_params) { { title: 'updated title' } }
+
+ it 'does not update last_edited values' do
+ expect { update_issuable }.to change(issuable, :title).from(issuable.title).to('updated title').and(
+ not_change(issuable, :last_edited_at)
+ ).and(
+ not_change(issuable, :last_edited_by)
+ )
+ end
+ end
+
+ context 'when updating the description of the issuable' do
+ let(:update_params) { { description: 'updated description' } }
+
+ it 'updates last_edited values' do
+ expect do
+ update_issuable
+ end.to change(issuable, :description).from(issuable.description).to('updated description').and(
+ change(issuable, :last_edited_at)
+ ).and(
+ change(issuable, :last_edited_by)
+ )
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/issuable_links/create_links_shared_examples.rb b/spec/support/shared_examples/services/issuable_links/create_links_shared_examples.rb
index 9610cdd18a3..65351ac94ab 100644
--- a/spec/support/shared_examples/services/issuable_links/create_links_shared_examples.rb
+++ b/spec/support/shared_examples/services/issuable_links/create_links_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issuable link creation' do
+RSpec.shared_examples 'issuable link creation' do
describe '#execute' do
subject { described_class.new(issuable, user, params).execute }
diff --git a/spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb b/spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb
index 53d637a9094..5e80014da1d 100644
--- a/spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb
+++ b/spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'a destroyable issuable link' do
+RSpec.shared_examples 'a destroyable issuable link' do
context 'when successfully removes an issuable link' do
before do
issuable_link.source.resource_parent.add_reporter(user)
diff --git a/spec/support/shared_examples/services/merge_request_shared_examples.rb b/spec/support/shared_examples/services/merge_request_shared_examples.rb
index d2595b92cbc..b3ba0a1be93 100644
--- a/spec/support/shared_examples/services/merge_request_shared_examples.rb
+++ b/spec/support/shared_examples/services/merge_request_shared_examples.rb
@@ -123,7 +123,7 @@ end
RSpec.shared_examples 'with an existing branch that has a merge request open' do |count|
let(:changes) { existing_branch_changes }
- let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
+ let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch) }
it_behaves_like 'a service that does not create a merge request'
it_behaves_like 'a service that can change assignees of a merge request', count
diff --git a/spec/support/shared_examples/services/onboarding_progress_shared_examples.rb b/spec/support/shared_examples/services/onboarding_progress_shared_examples.rb
index 8c6c2271af3..07025dac689 100644
--- a/spec/support/shared_examples/services/onboarding_progress_shared_examples.rb
+++ b/spec/support/shared_examples/services/onboarding_progress_shared_examples.rb
@@ -4,7 +4,7 @@ RSpec.shared_examples 'records an onboarding progress action' do |action|
include AfterNextHelpers
it do
- expect_next(OnboardingProgressService, namespace)
+ expect_next(Onboarding::ProgressService, namespace)
.to receive(:execute).with(action: action).and_call_original
subject
@@ -13,7 +13,7 @@ end
RSpec.shared_examples 'does not record an onboarding progress action' do
it do
- expect(OnboardingProgressService).not_to receive(:new)
+ expect(Onboarding::ProgressService).not_to receive(:new)
subject
end
diff --git a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
index 7fd20fc3909..ea79dc674a1 100644
--- a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
+++ b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
@@ -190,6 +190,7 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
Codename: unstable
Date: Sat, 25 Jan 2020 15:17:18 +0000
Valid-Until: Mon, 27 Jan 2020 15:17:18 +0000
+ Acquire-By-Hash: yes
Architectures: all amd64 arm64
Components: contrib main
MD5Sum:
@@ -249,6 +250,7 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
Codename: unstable
Date: Sat, 25 Jan 2020 15:17:18 +0000
Valid-Until: Mon, 27 Jan 2020 15:17:18 +0000
+ Acquire-By-Hash: yes
MD5Sum:
SHA256:
EOF
diff --git a/spec/support/shared_examples/services/packages_shared_examples.rb b/spec/support/shared_examples/services/packages_shared_examples.rb
index 704a4bbe0b8..ca4dea90c55 100644
--- a/spec/support/shared_examples/services/packages_shared_examples.rb
+++ b/spec/support/shared_examples/services/packages_shared_examples.rb
@@ -227,6 +227,7 @@ RSpec.shared_examples 'filters on each package_type' do |is_project: false|
let_it_be(:package10) { create(:rubygems_package, project: project) }
let_it_be(:package11) { create(:helm_package, project: project) }
let_it_be(:package12) { create(:terraform_module_package, project: project) }
+ let_it_be(:package13) { create(:rpm_package, project: project) }
Packages::Package.package_types.keys.each do |package_type|
context "for package type #{package_type}" do
diff --git a/spec/support/shared_examples/services/resource_events/synthetic_notes_builder_shared_examples.rb b/spec/support/shared_examples/services/resource_events/synthetic_notes_builder_shared_examples.rb
index 716bee39fca..a7e51408032 100644
--- a/spec/support/shared_examples/services/resource_events/synthetic_notes_builder_shared_examples.rb
+++ b/spec/support/shared_examples/services/resource_events/synthetic_notes_builder_shared_examples.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.shared_examples 'filters by paginated notes' do |event_type|
- let(:event) { create(event_type) } # rubocop:disable Rails/SaveBang
+ let(:event) { create(event_type, issue: create(:issue)) }
before do
create(event_type, issue: event.issue)
diff --git a/spec/support/shared_examples/services/snippets_shared_examples.rb b/spec/support/shared_examples/services/snippets_shared_examples.rb
index 5a44f739b27..65893d84798 100644
--- a/spec/support/shared_examples/services/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/services/snippets_shared_examples.rb
@@ -14,7 +14,8 @@ RSpec.shared_examples 'checking spam' do
spammable: kind_of(Snippet),
spam_params: spam_params,
user: an_instance_of(User),
- action: action
+ action: action,
+ extra_features: { files: an_instance_of(Array) }
}
) do |instance|
expect(instance).to receive(:execute)
@@ -24,7 +25,7 @@ RSpec.shared_examples 'checking spam' do
end
end
-shared_examples 'invalid params error response' do
+RSpec.shared_examples 'invalid params error response' do
before do
allow_next_instance_of(described_class) do |service|
allow(service).to receive(:valid_params?).and_return false
diff --git a/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb b/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb
index 0687be6f429..31919a4263d 100644
--- a/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb
+++ b/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-shared_examples 'issue_edit snowplow tracking' do
+RSpec.shared_examples 'issue_edit snowplow tracking' do
let(:category) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_CATEGORY }
let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_ACTION }
let(:label) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_LABEL }
diff --git a/spec/support/shared_examples/tasks/gitlab/uploads/migration_shared_examples.rb b/spec/support/shared_examples/tasks/gitlab/uploads/migration_shared_examples.rb
deleted file mode 100644
index b37a8059574..00000000000
--- a/spec/support/shared_examples/tasks/gitlab/uploads/migration_shared_examples.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-# Expects the calling spec to define:
-# - uploader_class
-# - model_class
-# - mounted_as
-RSpec.shared_examples 'enqueue upload migration jobs in batch' do |batch:|
- def run(task)
- args = [uploader_class.to_s, model_class.to_s, mounted_as].compact
- run_rake_task(task, *args)
- end
-
- it 'migrates local storage to remote object storage' do
- expect(ObjectStorage::MigrateUploadsWorker)
- .to receive(:perform_async).exactly(batch).times
- .and_return("A fake job.")
-
- run('gitlab:uploads:migrate')
- end
-
- it 'migrates remote object storage to local storage' do
- expect(Upload).to receive(:where).exactly(batch + 1).times { Upload.all }
- expect(ObjectStorage::MigrateUploadsWorker)
- .to receive(:perform_async)
- .with(anything, model_class.name, mounted_as, ObjectStorage::Store::LOCAL)
- .exactly(batch).times
- .and_return("A fake job.")
-
- run('gitlab:uploads:migrate_to_local')
- end
-end
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 f8b00d1e4c0..3c977e62a10 100644
--- a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
+++ b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
@@ -56,8 +56,8 @@ RSpec.shared_examples "migrates" do |to_store:, from_store: nil|
it 'can access to the original file during migration' do
file = subject.file
- allow(subject).to receive(:delete_migrated_file) { } # Remove as a callback of :migrate
- allow(subject).to receive(:record_upload) { } # Remove as a callback of :store (:record_upload)
+ allow(subject).to receive(:delete_migrated_file) {} # Remove as a callback of :migrate
+ allow(subject).to receive(:record_upload) {} # Remove as a callback of :store (:record_upload)
expect(file.exists?).to be_truthy
expect { migrate(to) }.not_to change { file.exists? }
diff --git a/spec/support/shared_examples/users/migrate_records_to_ghost_user_service_shared_examples.rb b/spec/support/shared_examples/users/migrate_records_to_ghost_user_service_shared_examples.rb
new file mode 100644
index 00000000000..eb03f0888b9
--- /dev/null
+++ b/spec/support/shared_examples/users/migrate_records_to_ghost_user_service_shared_examples.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'migrating records to the ghost user' do |record_class, fields|
+ record_class_name = record_class.to_s.titleize.downcase
+
+ let(:project) do
+ case record_class
+ when MergeRequest
+ create(:project, :repository)
+ else
+ create(:project)
+ end
+ end
+
+ before do
+ project.add_developer(user)
+ end
+
+ context "for a #{record_class_name} the user has created" do
+ let!(:record) { created_record }
+ let(:migrated_fields) { fields || [:author] }
+
+ it "does not delete the #{record_class_name}" do
+ service.execute
+
+ expect(record_class.find_by_id(record.id)).to be_present
+ end
+
+ it 'migrates all associated fields to the "Ghost user"' do
+ service.execute
+
+ migrated_record = record_class.find_by_id(record.id)
+
+ migrated_fields.each do |field|
+ expect(migrated_record.public_send(field)).to eq(User.ghost)
+ end
+ end
+ end
+end