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:
Diffstat (limited to 'spec/support/shared_examples')
-rw-r--r--spec/support/shared_examples/ci/stage_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/controllers/internal_event_tracking_examples.rb50
-rw-r--r--spec/support/shared_examples/controllers/metrics_dashboard_shared_examples.rb44
-rw-r--r--spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/features/cascading_settings_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/features/content_editor_shared_examples.rb32
-rw-r--r--spec/support/shared_examples/features/discussion_comments_shared_example.rb57
-rw-r--r--spec/support/shared_examples/features/editable_merge_request_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/features/inviting_members_shared_examples.rb34
-rw-r--r--spec/support/shared_examples/features/milestone_editing_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/nav_sidebar_shared_examples.rb16
-rw-r--r--spec/support/shared_examples/features/packages_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/project_upload_files_shared_examples.rb16
-rw-r--r--spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/rss_shared_examples.rb14
-rw-r--r--spec/support/shared_examples/features/sidebar/sidebar_due_date_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/work_items_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/finders/assignees_filter_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/finders/issues_finder_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/graphql/label_fields.rb2
-rw-r--r--spec/support/shared_examples/graphql/mutations/boards_list_create_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb15
-rw-r--r--spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/foreign_key_validators_shared_examples.rb48
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb38
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/table_validators_shared_examples.rb84
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb33
-rw-r--r--spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb23
-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/protected_ref_access_examples.rb30
-rw-r--r--spec/support/shared_examples/models/concerns/protected_ref_deploy_key_access_examples.rb132
-rw-r--r--spec/support/shared_examples/models/database_event_tracking_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/namespaces/traversal_examples.rb8
-rw-r--r--spec/support/shared_examples/namespaces/traversal_scope_examples.rb7
-rw-r--r--spec/support/shared_examples/nav_sidebar_shared_examples.rb36
-rw-r--r--spec/support/shared_examples/npm_sync_metadata_cache_worker_shared_examples.rb30
-rw-r--r--spec/support/shared_examples/observability/csp_shared_examples.rb172
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/quick_actions/work_item/type_change_quick_actions_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb48
-rw-r--r--spec/support/shared_examples/requests/api/graphql/remote_development_shared_examples.rb50
-rw-r--r--spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb18
-rw-r--r--spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb80
-rw-r--r--spec/support/shared_examples/requests/response_status_with_error_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/services/auto_merge_shared_examples.rb182
-rw-r--r--spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/boards/lists_list_service_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/services/issuable/issuable_import_csv_service_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/views/nav_sidebar_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/views/pipeline_status_changes_email.rb8
-rw-r--r--spec/support/shared_examples/views/preferred_language.rb19
63 files changed, 991 insertions, 537 deletions
diff --git a/spec/support/shared_examples/ci/stage_shared_examples.rb b/spec/support/shared_examples/ci/stage_shared_examples.rb
index a2849e00d27..cdb1058e584 100644
--- a/spec/support/shared_examples/ci/stage_shared_examples.rb
+++ b/spec/support/shared_examples/ci/stage_shared_examples.rb
@@ -21,7 +21,7 @@ RSpec.shared_examples 'manual playable stage' do |stage_type|
context 'when is skipped' do
let(:status) { 'skipped' }
- it { is_expected.to be_truthy }
+ it { is_expected.to be_falsy }
end
end
end
diff --git a/spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb b/spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb
index c8eaef764af..e61c884cd2b 100644
--- a/spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb
+++ b/spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb
@@ -113,7 +113,8 @@ RSpec.shared_examples 'every metric definition' do
Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric,
Gitlab::Usage::Metrics::Instrumentations::RedisMetric,
Gitlab::Usage::Metrics::Instrumentations::RedisHLLMetric,
- Gitlab::Usage::Metrics::Instrumentations::NumbersMetric
+ Gitlab::Usage::Metrics::Instrumentations::NumbersMetric,
+ Gitlab::Usage::Metrics::Instrumentations::PrometheusMetric
]
end
diff --git a/spec/support/shared_examples/controllers/internal_event_tracking_examples.rb b/spec/support/shared_examples/controllers/internal_event_tracking_examples.rb
new file mode 100644
index 00000000000..e2a4fb31361
--- /dev/null
+++ b/spec/support/shared_examples/controllers/internal_event_tracking_examples.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# - subject
+# - action
+# - user
+# Optionally, the context can contain:
+# - project
+# - namespace
+
+RSpec.shared_examples 'internal event tracking' do
+ let(:fake_tracker) { instance_spy(Gitlab::Tracking::Destinations::Snowplow) }
+ let(:namespace) { nil }
+ let(:proejct) { nil }
+
+ before do
+ allow(Gitlab::Tracking).to receive(:tracker).and_return(fake_tracker)
+
+ allow(Gitlab::Tracking::StandardContext).to receive(:new).and_call_original
+ allow(Gitlab::Tracking::ServicePingContext).to receive(:new).and_call_original
+ end
+
+ it 'logs to Snowplow', :aggregate_failures do
+ subject
+
+ expect(Gitlab::Tracking::StandardContext)
+ .to have_received(:new)
+ .with(
+ project_id: project&.id,
+ user_id: user.id,
+ namespace_id: namespace&.id,
+ plan_name: namespace&.actual_plan_name
+ )
+
+ expect(Gitlab::Tracking::ServicePingContext)
+ .to have_received(:new)
+ .with(data_source: :redis_hll, event: action)
+
+ expect(fake_tracker).to have_received(:event)
+ .with(
+ 'InternalEventTracking',
+ action,
+ context: [
+ an_instance_of(SnowplowTracker::SelfDescribingJson),
+ an_instance_of(SnowplowTracker::SelfDescribingJson)
+ ]
+ )
+ .exactly(:once)
+ end
+end
diff --git a/spec/support/shared_examples/controllers/metrics_dashboard_shared_examples.rb b/spec/support/shared_examples/controllers/metrics_dashboard_shared_examples.rb
deleted file mode 100644
index 5b63ef10c85..00000000000
--- a/spec/support/shared_examples/controllers/metrics_dashboard_shared_examples.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples_for 'GET #metrics_dashboard correctly formatted response' do
- it 'returns a json object with the correct keys' do
- get :metrics_dashboard, params: metrics_dashboard_req_params, format: :json
-
- # Exclude `all_dashboards` to handle separately, at spec/controllers/projects/environments_controller_spec.rb:565
- # because `all_dashboards` key is not part of expected shared behavior
- found_keys = json_response.keys - ['all_dashboards']
-
- expect(response).to have_gitlab_http_status(status_code)
- expect(found_keys).to contain_exactly(*expected_keys)
- end
-end
-
-RSpec.shared_examples_for 'GET #metrics_dashboard for dashboard' do |dashboard_name|
- let(:expected_keys) { %w(dashboard status metrics_data) }
- let(:status_code) { :ok }
-
- before do
- stub_feature_flags(remove_monitor_metrics: false)
- end
-
- it_behaves_like 'GET #metrics_dashboard correctly formatted response'
-
- it 'returns correct dashboard' do
- get :metrics_dashboard, params: metrics_dashboard_req_params, format: :json
-
- expect(json_response['dashboard']['dashboard']).to eq(dashboard_name)
- end
-
- context 'when metrics dashboard feature is unavailable' do
- before do
- stub_feature_flags(remove_monitor_metrics: true)
- end
-
- it 'returns 404 not found' do
- get :metrics_dashboard, params: metrics_dashboard_req_params, format: :json
-
- expect(response).to have_gitlab_http_status(:not_found)
- expect(response.body).to be_empty
- end
- end
-end
diff --git a/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb b/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb
index 9cf35325202..ba3b08751da 100644
--- a/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb
@@ -75,7 +75,7 @@ RSpec.shared_examples 'a controller that can serve LFS files' do |options = {}|
file_uri = URI.parse(response.location)
params = CGI.parse(file_uri.query)
- expect(params["response-content-disposition"].first).to eq(%Q(attachment; filename="#{filename}"; filename*=UTF-8''#{filename}))
+ expect(params["response-content-disposition"].first).to eq(%(attachment; filename="#{filename}"; filename*=UTF-8''#{filename}))
end
end
end
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 ba00e3e0610..3d3b619451d 100644
--- a/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb
+++ b/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb
@@ -6,7 +6,7 @@
# - category
# - action
# - namespace
-# Optionaly, the context can contain:
+# Optionally, the context can contain:
# - project
# - property
# - user
diff --git a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
index 0792ac14e47..772e03950da 100644
--- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
@@ -94,14 +94,6 @@ RSpec.shared_examples 'handle uploads' do
expect(response).to have_gitlab_http_status(:not_found)
end
-
- it 'is a working exploit without the validation' do
- allow_any_instance_of(FileUploader).to receive(:secret) { secret }
-
- show_upload
-
- expect(response).to have_gitlab_http_status(:ok)
- end
end
context 'when accessing a specific upload via different model' do
diff --git a/spec/support/shared_examples/features/cascading_settings_shared_examples.rb b/spec/support/shared_examples/features/cascading_settings_shared_examples.rb
index cb80751ff49..2bda352c11f 100644
--- a/spec/support/shared_examples/features/cascading_settings_shared_examples.rb
+++ b/spec/support/shared_examples/features/cascading_settings_shared_examples.rb
@@ -24,14 +24,6 @@ RSpec.shared_examples 'a cascading setting' do
include_examples 'subgroup settings are disabled'
- context 'when use_traversal_ids_for_ancestors is disabled' do
- before do
- stub_feature_flags(use_traversal_ids_for_ancestors: false)
- end
-
- include_examples 'subgroup settings are disabled'
- end
-
it 'does not show enforcement checkbox in subgroups' do
visit subgroup_path
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 f70288168d7..254bc3c83ac 100644
--- a/spec/support/shared_examples/features/content_editor_shared_examples.rb
+++ b/spec/support/shared_examples/features/content_editor_shared_examples.rb
@@ -506,6 +506,8 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { wi
switch_to_content_editor
type_in_content_editor :enter
+
+ stub_feature_flags(disable_all_mention: false)
end
if params[:with_expanded_references]
@@ -545,12 +547,32 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { wi
expect(page).to have_text('@abc123')
end
+ context 'when `disable_all_mention` is enabled' do
+ before do
+ stub_feature_flags(disable_all_mention: true)
+ end
+
+ it 'shows suggestions for members with descriptions' do
+ type_in_content_editor '@a'
+
+ expect(find(suggestions_dropdown)).to have_text('abc123')
+ expect(find(suggestions_dropdown)).not_to have_text('All Group Members')
+
+ type_in_content_editor 'bc'
+
+ send_keys [:arrow_down, :enter]
+
+ expect(page).not_to have_css(suggestions_dropdown)
+ expect(page).to have_text('@abc123')
+ end
+ end
+
it 'shows suggestions for merge requests' do
type_in_content_editor '!'
expect(find(suggestions_dropdown)).to have_text('My Cool Merge Request')
- send_keys :enter
+ send_keys [:arrow_down, :enter]
expect(page).not_to have_css(suggestions_dropdown)
expect(page).to have_text('!1')
@@ -561,7 +583,7 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { wi
expect(find(suggestions_dropdown)).to have_text('My Cool Linked Issue')
- send_keys :enter
+ send_keys [:arrow_down, :enter]
expect(page).not_to have_css(suggestions_dropdown)
expect(page).to have_text('#1')
@@ -572,7 +594,7 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { wi
expect(find(suggestions_dropdown)).to have_text('My Cool Milestone')
- send_keys :enter
+ send_keys [:arrow_down, :enter]
expect(page).not_to have_css(suggestions_dropdown)
expect(page).to have_text('%My Cool Milestone')
@@ -584,7 +606,7 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { wi
expect(find(suggestions_dropdown)).to have_text('🙂 slight_smile')
expect(find(suggestions_dropdown)).to have_text('😸 smile_cat')
- send_keys :enter
+ send_keys [:arrow_down, :enter]
expect(page).not_to have_css(suggestions_dropdown)
@@ -614,7 +636,7 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { wi
end
def dropdown_scroll_top
- evaluate_script("document.querySelector('#{suggestions_dropdown} .gl-dropdown-inner').scrollTop")
+ evaluate_script("document.querySelector('#{suggestions_dropdown}').scrollTop")
end
end
end
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 d6f1efc09fc..430a8ac39d7 100644
--- a/spec/support/shared_examples/features/discussion_comments_shared_example.rb
+++ b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
@@ -3,8 +3,8 @@
RSpec.shared_examples 'thread comments for commit and snippet' do |resource_name|
let(:form_selector) { '.js-main-target-form' }
let(:dropdown_selector) { "#{form_selector} .comment-type-dropdown" }
- let(:toggle_selector) { "#{dropdown_selector} .gl-dropdown-toggle" }
- let(:menu_selector) { "#{dropdown_selector} .dropdown-menu" }
+ let(:toggle_selector) { "#{dropdown_selector} .gl-new-dropdown-toggle" }
+ let(:menu_selector) { "#{dropdown_selector} .gl-new-dropdown-contents" }
let(:submit_selector) { "#{form_selector} .js-comment-submit-button > button:first-child" }
let(:close_selector) { "#{form_selector} .btn-comment-and-close" }
let(:comments_selector) { '.timeline > .note.timeline-entry:not(.being-posted)' }
@@ -63,33 +63,6 @@ RSpec.shared_examples 'thread comments for commit and snippet' do |resource_name
expect(page).not_to have_selector menu_selector
end
- it 'clicking the ul padding or divider should not change the text' do
- execute_script("document.querySelector('#{menu_selector}').click()")
-
- # on issues page, the menu closes when clicking anywhere, on other pages it will
- # remain open if clicking divider or menu padding, but should not change button action
- #
- # if dropdown menu is not toggled (and also not present),
- # it's "issue-type" dropdown
- if first(menu_selector, minimum: 0).nil?
- expect(find(dropdown_selector)).to have_content 'Comment'
-
- find(toggle_selector).click
- execute_script("document.querySelector('#{menu_selector} .dropdown-divider').click()")
- else
- execute_script("document.querySelector('#{menu_selector}').click()")
-
- expect(page).to have_selector menu_selector
- expect(find(dropdown_selector)).to have_content 'Comment'
-
- execute_script("document.querySelector('#{menu_selector} .dropdown-divider').click()")
-
- expect(page).to have_selector menu_selector
- end
-
- expect(find(dropdown_selector)).to have_content 'Comment'
- end
-
describe 'when selecting "Start thread"' do
before do
find("#{menu_selector} li", match: :first)
@@ -177,21 +150,27 @@ RSpec.shared_examples 'thread comments for commit and snippet' do |resource_name
end
RSpec.shared_examples 'thread comments for issue, epic and merge request' do |resource_name|
+ include ContentEditorHelpers
+
let(:form_selector) { '.js-main-target-form' }
- let(:dropdown_selector) { "#{form_selector} [data-testid='comment-button']" }
- let(:submit_button_selector) { "#{dropdown_selector} .split-content-button" }
- let(:toggle_selector) { "#{dropdown_selector} .dropdown-toggle-split" }
- let(:menu_selector) { "#{dropdown_selector} .dropdown-menu" }
+ let(:dropdown_selector) { "#{form_selector} .comment-type-dropdown" }
+ let(:toggle_selector) { "#{dropdown_selector} .gl-new-dropdown-toggle" }
+ let(:menu_selector) { "#{dropdown_selector} .gl-new-dropdown-contents" }
+ let(:submit_selector) { "#{form_selector} .js-comment-submit-button > button:first-child" }
let(:close_selector) { "#{form_selector} .btn-comment-and-close" }
let(:comments_selector) { '.timeline > .note.timeline-entry:not(.being-posted)' }
let(:comment) { 'My comment' }
+ before do
+ close_rich_text_promo_popover_if_present
+ end
+
it 'clicking "Comment" will post a comment' do
expect(page).to have_selector toggle_selector
find("#{form_selector} .note-textarea").send_keys(comment)
- find(submit_button_selector).click
+ find(submit_selector).click
wait_for_all_requests
@@ -260,7 +239,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re
describe 'creating a thread' do
before do
- find(submit_button_selector).click
+ find(submit_selector).click
wait_for_requests
find(comments_selector, match: :first)
@@ -284,7 +263,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re
expect(new_comment).to have_css('.discussion-with-resolve-btn')
end
- if resource_name =~ /(issue|merge request)/
+ if /(issue|merge request)/.match?(resource_name)
it 'can be replied to' do
submit_reply('some text')
@@ -366,14 +345,14 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re
end
it 'updates the submit button text and closes the dropdown' do
- button = find(submit_button_selector)
+ button = find(submit_selector)
expect(button).to have_content 'Comment'
expect(page).not_to have_selector menu_selector
end
- if resource_name =~ /(issue|merge request)/
+ if /(issue|merge request)/.match?(resource_name)
it 'updates the close button text' do
expect(find(close_selector)).to have_content "Comment & close #{resource_name}"
end
@@ -402,7 +381,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re
end
end
- if resource_name =~ /(issue|merge request)/
+ if /(issue|merge request)/.match?(resource_name)
describe "on a closed #{resource_name}" do
before do
find("#{form_selector} .js-note-target-close").click
diff --git a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb
index 14e53dc8655..f802404518b 100644
--- a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb
+++ b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb
@@ -125,7 +125,11 @@ RSpec.shared_examples 'an editable merge request' do
it 'allows to unselect "Remove source branch"', :js do
expect(merge_request.merge_params['force_remove_source_branch']).to be_truthy
- visit edit_project_merge_request_path(target_project, merge_request)
+ begin
+ visit edit_project_merge_request_path(target_project, merge_request)
+ rescue Selenium::WebDriver::Error::UnexpectedAlertOpenError
+ end
+
uncheck 'Delete source branch when merge request is accepted'
click_button 'Save changes'
diff --git a/spec/support/shared_examples/features/inviting_members_shared_examples.rb b/spec/support/shared_examples/features/inviting_members_shared_examples.rb
index 2eca2a72997..178f85cb85b 100644
--- a/spec/support/shared_examples/features/inviting_members_shared_examples.rb
+++ b/spec/support/shared_examples/features/inviting_members_shared_examples.rb
@@ -159,6 +159,40 @@ RSpec.shared_examples 'inviting members' do |snowplow_invite_label|
end
end
+ context 'when a user already exists, and private email is used' do
+ it 'fails with an error', :js do
+ visit subentity_members_page_path
+
+ invite_member(user2.email, role: role)
+
+ invite_modal = page.find(invite_modal_selector)
+ expect(invite_modal).to have_content "#{user2.email}: Access level should be greater than or equal to " \
+ "Developer inherited membership from group #{group.name}"
+
+ page.refresh
+
+ page.within find_invited_member_row(user2.name) do
+ expect(page).to have_content('Developer')
+ expect(page).not_to have_button('Developer')
+ end
+ end
+
+ it 'does not allow inviting of an email that has spaces', :js do
+ visit subentity_members_page_path
+
+ click_on _('Invite members')
+
+ page.within invite_modal_selector do
+ choose_options(role, nil)
+ find(member_dropdown_selector).set("#{user2.email} ")
+ wait_for_requests
+
+ expect(page).to have_content('No matches found')
+ expect(page).not_to have_button("#{user2.email} ")
+ end
+ end
+ end
+
context 'when there are multiple users invited with errors' do
let_it_be(:user3) { create(:user) }
diff --git a/spec/support/shared_examples/features/milestone_editing_shared_examples.rb b/spec/support/shared_examples/features/milestone_editing_shared_examples.rb
index d21bf62ecfa..53498a1bb39 100644
--- a/spec/support/shared_examples/features/milestone_editing_shared_examples.rb
+++ b/spec/support/shared_examples/features/milestone_editing_shared_examples.rb
@@ -1,7 +1,9 @@
# frozen_string_literal: true
RSpec.shared_examples 'milestone handling version conflicts' do
- it 'warns about version conflict when milestone has been updated in the background' do
+ it 'warns about version conflict when milestone has been updated in the background', :js do
+ wait_for_all_requests
+
# Update the milestone in the background in order to trigger a version conflict
milestone.update!(title: "New title")
diff --git a/spec/support/shared_examples/features/nav_sidebar_shared_examples.rb b/spec/support/shared_examples/features/nav_sidebar_shared_examples.rb
new file mode 100644
index 00000000000..34821fb9eda
--- /dev/null
+++ b/spec/support/shared_examples/features/nav_sidebar_shared_examples.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'page has active tab' do |title|
+ it "activates #{title} tab" do
+ expect(page).to have_selector('.sidebar-top-level-items > li.active', count: 1)
+ expect(find('.sidebar-top-level-items > li.active')).to have_content(title)
+ end
+end
+
+RSpec.shared_examples 'page has active sub tab' do |title|
+ it "activates #{title} sub tab" do
+ expect(page).to have_selector('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)', count: 1)
+ expect(find('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)'))
+ .to have_content(title)
+ end
+end
diff --git a/spec/support/shared_examples/features/packages_shared_examples.rb b/spec/support/shared_examples/features/packages_shared_examples.rb
index 5126e849c2e..8e8e7e8ad05 100644
--- a/spec/support/shared_examples/features/packages_shared_examples.rb
+++ b/spec/support/shared_examples/features/packages_shared_examples.rb
@@ -9,7 +9,7 @@ RSpec.shared_examples 'packages list' do |check_project_name: false|
expect(package_row).to have_content(pkg.name)
expect(package_row).to have_content(pkg.version)
- expect(package_row).to have_content(pkg.project.path) if check_project_name
+ expect(package_row).to have_content(pkg.project.name) if check_project_name
end
end
diff --git a/spec/support/shared_examples/features/project_upload_files_shared_examples.rb b/spec/support/shared_examples/features/project_upload_files_shared_examples.rb
index 7737f8a73c5..806ffdad2f1 100644
--- a/spec/support/shared_examples/features/project_upload_files_shared_examples.rb
+++ b/spec/support/shared_examples/features/project_upload_files_shared_examples.rb
@@ -4,8 +4,8 @@ RSpec.shared_examples 'it uploads and commits a new text file' do |drop: false|
it 'uploads and commits a new text file', :js do
find('.add-to-tree').click
- page.within('.dropdown-menu') do
- click_link('Upload file')
+ page.within('.repo-breadcrumb') do
+ click_button('Upload file')
wait_for_requests
end
@@ -40,8 +40,8 @@ RSpec.shared_examples 'it uploads and commits a new image file' do |drop: false|
it 'uploads and commits a new image file', :js do
find('.add-to-tree').click
- page.within('.dropdown-menu') do
- click_link('Upload file')
+ page.within('.repo-breadcrumb') do
+ click_button('Upload file')
wait_for_requests
end
@@ -70,8 +70,8 @@ RSpec.shared_examples 'it uploads and commits a new pdf file' do |drop: false|
it 'uploads and commits a new pdf file', :js do
find('.add-to-tree').click
- page.within('.dropdown-menu') do
- click_link('Upload file')
+ page.within('.repo-breadcrumb') do
+ click_button('Upload file')
wait_for_requests
end
@@ -111,7 +111,7 @@ RSpec.shared_examples 'it uploads and commits a new file to a forked project' do
wait_for_all_requests
find('.add-to-tree').click
- click_link('Upload file')
+ click_button('Upload file')
if drop
find(".upload-dropzone-card").drop(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt'))
@@ -149,7 +149,7 @@ RSpec.shared_examples 'it uploads a file to a sub-directory' do |drop: false|
end
find('.add-to-tree').click
- click_link('Upload file')
+ click_button('Upload file')
if drop
find(".upload-dropzone-card").drop(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt'))
diff --git a/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb b/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb
index 337b3f3cbd0..7e3b507c1ba 100644
--- a/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb
+++ b/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb
@@ -24,6 +24,6 @@ RSpec.shared_examples 'creating an issue for a thread' do
expect(discussion.resolved?).to eq(true)
# Issue title inludes MR title
- expect(page).to have_content(%Q(Follow-up from "#{merge_request.title}"))
+ expect(page).to have_content(%(Follow-up from "#{merge_request.title}"))
end
end
diff --git a/spec/support/shared_examples/features/rss_shared_examples.rb b/spec/support/shared_examples/features/rss_shared_examples.rb
index f6566214e32..a6b9c98923a 100644
--- a/spec/support/shared_examples/features/rss_shared_examples.rb
+++ b/spec/support/shared_examples/features/rss_shared_examples.rb
@@ -2,20 +2,20 @@
RSpec.shared_examples "an autodiscoverable RSS feed with current_user's feed token" do
it "has an RSS autodiscovery link tag with current_user's feed token" do
- expect(page).to have_css("link[type*='atom+xml'][href*='feed_token=#{user.feed_token}']", visible: false)
+ expect(page).to have_css("link[type*='atom+xml'][href*='feed_token=glft-'][href*='-#{user.id}']", visible: false)
end
end
RSpec.shared_examples "it has an RSS button with current_user's feed token" do
it "shows the RSS button with current_user's feed token" do
expect(page)
- .to have_css("a:has([data-testid='rss-icon'])[href*='feed_token=#{user.feed_token}']")
+ .to have_css("a:has([data-testid='rss-icon'])[href*='feed_token=glft-'][href*='-#{user.id}']")
end
end
RSpec.shared_examples "it has an RSS link with current_user's feed token" do
it "shows the RSS link with current_user's feed token" do
- expect(page).to have_link 'Subscribe to RSS feed', href: /feed_token=#{user.feed_token}/
+ expect(page).to have_link 'Subscribe to RSS feed', href: /feed_token=glft-.*-#{user.id}/
end
end
@@ -51,11 +51,17 @@ RSpec.shared_examples "updates atom feed link" do |type|
auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
expected = {
- 'feed_token' => [user.feed_token],
'assignee_id' => [user.id.to_s]
}
expect(params).to include(expected)
+ feed_token_param = params['feed_token']
+ expect(feed_token_param).to match([Gitlab::Auth::AuthFinders::PATH_DEPENDENT_FEED_TOKEN_REGEX])
+ expect(feed_token_param.first).to end_with(user.id.to_s)
+
expect(auto_discovery_params).to include(expected)
+ feed_token_param = auto_discovery_params['feed_token']
+ expect(feed_token_param).to match([Gitlab::Auth::AuthFinders::PATH_DEPENDENT_FEED_TOKEN_REGEX])
+ expect(feed_token_param.first).to end_with(user.id.to_s)
end
end
diff --git a/spec/support/shared_examples/features/sidebar/sidebar_due_date_shared_examples.rb b/spec/support/shared_examples/features/sidebar/sidebar_due_date_shared_examples.rb
index 206116d66c8..865f5aff476 100644
--- a/spec/support/shared_examples/features/sidebar/sidebar_due_date_shared_examples.rb
+++ b/spec/support/shared_examples/features/sidebar/sidebar_due_date_shared_examples.rb
@@ -26,7 +26,7 @@ RSpec.shared_examples 'date sidebar widget' do
wait_for_requests
- expect(page).to have_content(today.to_s(:medium))
+ expect(page).to have_content(today.to_fs(:medium))
expect(due_date_value.text).to have_content Time.current.strftime('%b %-d, %Y')
end
end
diff --git a/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb
index ed885d7a226..c3df89c8002 100644
--- a/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb
@@ -6,6 +6,7 @@
RSpec.shared_examples 'User creates wiki page' do
include WikiHelpers
+ include ContentEditorHelpers
before do
sign_in(user)
@@ -18,6 +19,7 @@ RSpec.shared_examples 'User creates wiki page' do
wait_for_svg_to_be_loaded(example)
click_link "Create your first page"
+ close_rich_text_promo_popover_if_present
end
it 'shows all available formats in the dropdown' do
@@ -190,6 +192,7 @@ RSpec.shared_examples 'User creates wiki page' do
context "via the `new wiki page` page", :js do
it "creates a page with a single word" do
click_link("New page")
+ close_rich_text_promo_popover_if_present
page.within(".wiki-form") do
fill_in(:wiki_title, with: "foo")
@@ -208,6 +211,7 @@ RSpec.shared_examples 'User creates wiki page' do
it "creates a page with spaces in the name", :js do
click_link("New page")
+ close_rich_text_promo_popover_if_present
page.within(".wiki-form") do
fill_in(:wiki_title, with: "Spaces in the name")
@@ -226,6 +230,7 @@ RSpec.shared_examples 'User creates wiki page' do
it "creates a page with hyphens in the name", :js do
click_link("New page")
+ close_rich_text_promo_popover_if_present
page.within(".wiki-form") do
fill_in(:wiki_title, with: "hyphens-in-the-name")
@@ -249,6 +254,7 @@ RSpec.shared_examples 'User creates wiki page' do
context 'when a server side validation error is returned' do
it "still displays edit form", :js do
click_link("New page")
+ close_rich_text_promo_popover_if_present
page.within(".wiki-form") do
fill_in(:wiki_title, with: "home")
@@ -266,6 +272,7 @@ RSpec.shared_examples 'User creates wiki page' do
it "shows the emoji autocompletion dropdown", :js do
click_link("New page")
+ close_rich_text_promo_popover_if_present
page.within(".wiki-form") do
find("#wiki_content").native.send_keys("")
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 ca68df9a89b..827c875494a 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
@@ -5,6 +5,8 @@
# user
RSpec.shared_examples 'User previews wiki changes' do
+ include ContentEditorHelpers
+
let(:wiki_page) { build(:wiki_page, wiki: wiki) }
before do
@@ -74,6 +76,7 @@ RSpec.shared_examples 'User previews wiki changes' do
before do
wiki_page.create # rubocop:disable Rails/SaveBang
visit wiki_page_path(wiki, wiki_page, action: :edit)
+ close_rich_text_promo_popover_if_present
end
it_behaves_like 'relative links' do
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 91cacaf9209..d06f04db1ce 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
@@ -6,6 +6,8 @@
RSpec.shared_examples 'User updates wiki page' do
include WikiHelpers
+ include ContentEditorHelpers
+
let(:diagramsnet_url) { 'https://embed.diagrams.net' }
before do
@@ -21,6 +23,7 @@ RSpec.shared_examples 'User updates wiki page' do
wait_for_svg_to_be_loaded(example)
click_link "Create your first page"
+ close_rich_text_promo_popover_if_present
end
it 'redirects back to the home edit page' do
@@ -67,6 +70,7 @@ RSpec.shared_examples 'User updates wiki page' do
visit(wiki_path(wiki))
click_link('Edit')
+ close_rich_text_promo_popover_if_present
end
it 'updates a page', :js do
@@ -126,10 +130,6 @@ RSpec.shared_examples 'User updates wiki page' do
expect(page).to have_content('Updated Wiki Content')
end
- it 'focuses on the content field', :js do
- expect(page).to have_selector '.note-textarea:focus'
- end
-
it 'cancels editing of a page' do
page.within(:css, '.wiki-form .form-actions') do
click_on('Cancel')
@@ -164,6 +164,7 @@ RSpec.shared_examples 'User updates wiki page' do
before do
visit wiki_page_path(wiki, wiki_page, action: :edit)
+ close_rich_text_promo_popover_if_present
end
it 'moves the page to the root folder', :js do
@@ -234,6 +235,7 @@ RSpec.shared_examples 'User updates wiki page' do
stub_application_setting(wiki_page_max_content_bytes: 10)
visit wiki_page_path(wiki_page.wiki, wiki_page, action: :edit)
+ close_rich_text_promo_popover_if_present
end
it 'allows changing the title if the content does not change', :js do
diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb
index 767caffd417..3ee7725305e 100644
--- a/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb
@@ -6,6 +6,7 @@
RSpec.shared_examples 'User views a wiki page' do
include WikiHelpers
+ include ContentEditorHelpers
let(:path) { 'image.png' }
let(:wiki_page) do
@@ -269,6 +270,7 @@ RSpec.shared_examples 'User views a wiki page' do
wait_for_svg_to_be_loaded
click_link "Create your first page"
+ close_rich_text_promo_popover_if_present
expect(page).to have_content('Create New Page')
end
diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb
index 128bd28410c..4c15b682458 100644
--- a/spec/support/shared_examples/features/work_items_shared_examples.rb
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -166,7 +166,8 @@ RSpec.shared_examples 'work items comments' do |type|
end
RSpec.shared_examples 'work items assignees' do
- it 'successfully assigns the current user by searching' do
+ it 'successfully assigns the current user by searching',
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/413074' do
# The button is only when the mouse is over the input
find('[data-testid="work-item-assignees-input"]').fill_in(with: user.username)
wait_for_requests
diff --git a/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb b/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb
index 5cbbed1468f..38954e6f9cc 100644
--- a/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb
+++ b/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb
@@ -42,6 +42,12 @@ RSpec.shared_examples 'no assignee filter' do
expect(issuables).to contain_exactly(*expected_issuables)
end
+
+ it 'returns issuables not assigned to any assignee' do
+ params[:assignee_wildcard_id] = 'none'
+
+ expect(issuables).to contain_exactly(*expected_issuables)
+ end
end
RSpec.shared_examples 'any assignee filter' do
@@ -57,5 +63,11 @@ RSpec.shared_examples 'any assignee filter' do
expect(issuables).to contain_exactly(*expected_issuables)
end
+
+ it 'returns issuables assigned to any assignee' do
+ params[:assignee_wildcard_id] = 'any'
+
+ expect(issuables).to contain_exactly(*expected_issuables)
+ end
end
end
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 67fed00b5ca..30041456d00 100644
--- a/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
+++ b/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
@@ -663,18 +663,6 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
expect(items).to contain_exactly(japanese)
end
end
-
- context 'when full-text search is disabled' do
- let(:search_term) { 'ometh' }
-
- before do
- stub_feature_flags(issues_full_text_search: false)
- end
-
- it 'allows partial word matches' do
- expect(items).to contain_exactly(english)
- end
- end
end
context 'filtering by item term in title' do
diff --git a/spec/support/shared_examples/graphql/label_fields.rb b/spec/support/shared_examples/graphql/label_fields.rb
index 030a2feafcd..809c801de62 100644
--- a/spec/support/shared_examples/graphql/label_fields.rb
+++ b/spec/support/shared_examples/graphql/label_fields.rb
@@ -93,7 +93,7 @@ RSpec.shared_examples 'querying a GraphQL type with labels' do
describe 'performance' do
def query_for(*labels)
selections = labels.map do |label|
- %Q[#{label.title.gsub(/:+/, '_')}: label(title: "#{label.title}") { description }]
+ %[#{label.title.gsub(/:+/, '_')}: label(title: "#{label.title}") { description }]
end
make_query(selections)
diff --git a/spec/support/shared_examples/graphql/mutations/boards_list_create_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/boards_list_create_shared_examples.rb
index b096a5e17c0..13d2447754c 100644
--- a/spec/support/shared_examples/graphql/mutations/boards_list_create_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/mutations/boards_list_create_shared_examples.rb
@@ -33,6 +33,10 @@ RSpec.shared_examples 'board lists create mutation' do
describe 'backlog list' do
let(:list_create_params) { { backlog: true } }
+ before do
+ board.lists.backlog.delete_all
+ end
+
it 'creates one and only one backlog' do
expect { subject }.to change { board.lists.backlog.count }.by(1)
expect(board.lists.backlog.first.list_type).to eq 'backlog'
diff --git a/spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb b/spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb
index 30212e44c6a..c666b72d492 100644
--- a/spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb
@@ -157,10 +157,10 @@ RSpec.shared_examples 'work item supports type change via quick actions' do
let_it_be(:assignee) { create(:user) }
let_it_be(:task_type) { WorkItems::Type.default_by_type(:task) }
- let(:body) { "Updating type.\n/type Issue" }
+ let(:body) { "Updating type.\n/type issue" }
before do
- noteable.update!(work_item_type: task_type, issue_type: task_type.base_type)
+ noteable.update!(work_item_type: task_type)
end
it 'updates type' do
@@ -211,4 +211,15 @@ RSpec.shared_examples 'work item supports type change via quick actions' do
.to include("Commands only Type changed successfully. Assigned @#{assignee.username}.")
end
end
+
+ context 'when the type name is upper case' do
+ let(:body) { "Updating type.\n/type Issue" }
+
+ it 'changes type to issue' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ noteable.reload
+ end.to change { noteable.work_item_type.base_type }.from('task').to('issue')
+ end
+ end
end
diff --git a/spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb b/spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb
index d8cc6f697d7..c32e758d921 100644
--- a/spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb
@@ -50,6 +50,8 @@ RSpec.shared_examples "a user type with merge request interaction type" do
organization
jobTitle
createdAt
+ pronouns
+ ide
]
# TODO: 'workspaces' needs to be included, but only when this spec is run in EE context, to account for the
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 47655f86558..e6433f963f4 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
@@ -25,7 +25,7 @@ RSpec.shared_examples 'default allowlist' do
expect(filter(act).to_html).to eq exp
end
- it 'allows whitelisted HTML tags from the user' do
+ it 'allows allowlisted HTML tags from the user' do
exp = act = "<dl>\n<dt>Term</dt>\n<dd>Definition</dd>\n</dl>"
expect(filter(act).to_html).to eq exp
end
@@ -110,7 +110,7 @@ RSpec.shared_examples 'XSS prevention' do
},
'protocol-based JS injection: Unicode' => {
- input: %Q(<a href="\u0001java\u0003script:alert('XSS')">foo</a>),
+ input: %(<a href="\u0001java\u0003script:alert('XSS')">foo</a>),
output: '<a>foo</a>'
},
diff --git a/spec/support/shared_examples/lib/gitlab/database/foreign_key_validators_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/foreign_key_validators_shared_examples.rb
deleted file mode 100644
index a1e75e4af7e..00000000000
--- a/spec/support/shared_examples/lib/gitlab/database/foreign_key_validators_shared_examples.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.shared_examples 'foreign key validators' do |validator, expected_result|
- subject(:result) { validator.new(structure_file, database).execute }
-
- let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
- let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, schema) }
- let(:inconsistency_type) { validator.name.demodulize.underscore }
- let(:database_name) { 'main' }
- let(:schema) { 'public' }
- let(:database_model) { Gitlab::Database.database_base_models[database_name] }
- let(:connection) { database_model.connection }
- let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
-
- let(:database_query) do
- [
- {
- 'schema' => schema,
- 'table_name' => 'web_hooks',
- 'foreign_key_name' => 'web_hooks_project_id_fkey',
- 'foreign_key_definition' => 'FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE'
- },
- {
- 'schema' => schema,
- 'table_name' => 'issues',
- 'foreign_key_name' => 'wrong_definition_fk',
- 'foreign_key_definition' => 'FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE'
- },
- {
- 'schema' => schema,
- 'table_name' => 'projects',
- 'foreign_key_name' => 'extra_fk',
- 'foreign_key_definition' => 'FOREIGN KEY (creator_id) REFERENCES users(id) ON DELETE CASCADE'
- }
- ]
- end
-
- before do
- allow(connection).to receive(:exec_query).and_return(database_query)
- end
-
- it 'returns trigger inconsistencies' do
- expect(result.map(&:object_name)).to match_array(expected_result)
- expect(result.map(&:type)).to all(eql inconsistency_type)
- end
-end
diff --git a/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb
deleted file mode 100644
index 6f0cede7130..00000000000
--- a/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.shared_examples "index validators" do |validator, expected_result|
- let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
- let(:database_indexes) do
- [
- ['wrong_index', 'CREATE UNIQUE INDEX wrong_index ON public.table_name (column_name)'],
- ['extra_index', 'CREATE INDEX extra_index ON public.table_name (column_name)'],
- ['index', 'CREATE UNIQUE INDEX "index" ON public.achievements USING btree (namespace_id, lower(name))']
- ]
- end
-
- let(:inconsistency_type) { validator.name.demodulize.underscore }
-
- let(:database_name) { 'main' }
-
- let(:database_model) { Gitlab::Database.database_base_models[database_name] }
-
- let(:connection) { database_model.connection }
-
- let(:schema) { connection.current_schema }
-
- let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
- let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, schema) }
-
- subject(:result) { validator.new(structure_file, database).execute }
-
- before do
- allow(connection).to receive(:select_rows).and_return(database_indexes)
- end
-
- it 'returns index inconsistencies' do
- expect(result.map(&:object_name)).to match_array(expected_result)
- expect(result.map(&:type)).to all(eql inconsistency_type)
- end
-end
diff --git a/spec/support/shared_examples/lib/gitlab/database/table_validators_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/table_validators_shared_examples.rb
deleted file mode 100644
index 96e58294675..00000000000
--- a/spec/support/shared_examples/lib/gitlab/database/table_validators_shared_examples.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.shared_examples "table validators" do |validator, expected_result|
- subject(:result) { validator.new(structure_file, database).execute }
-
- let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
- let(:inconsistency_type) { validator.name.demodulize.underscore }
- let(:database_model) { Gitlab::Database.database_base_models['main'] }
- let(:connection) { database_model.connection }
- let(:schema) { connection.current_schema }
- let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
- let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, schema) }
- let(:database_tables) do
- [
- {
- 'table_name' => 'wrong_table',
- 'column_name' => 'id',
- 'not_null' => true,
- 'data_type' => 'integer',
- 'column_default' => "nextval('audit_events_id_seq'::regclass)"
- },
- {
- 'table_name' => 'wrong_table',
- 'column_name' => 'description',
- 'not_null' => true,
- 'data_type' => 'character varying',
- 'column_default' => nil
- },
- {
- 'table_name' => 'extra_table',
- 'column_name' => 'id',
- 'not_null' => true,
- 'data_type' => 'integer',
- 'column_default' => "nextval('audit_events_id_seq'::regclass)"
- },
- {
- 'table_name' => 'extra_table',
- 'column_name' => 'email',
- 'not_null' => true,
- 'data_type' => 'character varying',
- 'column_default' => nil
- },
- {
- 'table_name' => 'extra_table_columns',
- 'column_name' => 'id',
- 'not_null' => true,
- 'data_type' => 'bigint',
- 'column_default' => "nextval('audit_events_id_seq'::regclass)"
- },
- {
- 'table_name' => 'extra_table_columns',
- 'column_name' => 'name',
- 'not_null' => true,
- 'data_type' => 'character varying(255)',
- 'column_default' => nil
- },
- {
- 'table_name' => 'extra_table_columns',
- 'column_name' => 'extra_column',
- 'not_null' => true,
- 'data_type' => 'character varying(255)',
- 'column_default' => nil
- },
- {
- 'table_name' => 'missing_table_columns',
- 'column_name' => 'id',
- 'not_null' => true,
- 'data_type' => 'bigint',
- 'column_default' => 'NOT NULL'
- }
- ]
- end
-
- before do
- allow(connection).to receive(:exec_query).and_return(database_tables)
- end
-
- it 'returns table inconsistencies' do
- expect(result.map(&:object_name)).to match_array(expected_result)
- expect(result.map(&:type)).to all(eql inconsistency_type)
- end
-end
diff --git a/spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb
deleted file mode 100644
index 13a112275c2..00000000000
--- a/spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.shared_examples 'trigger validators' do |validator, expected_result|
- subject(:result) { validator.new(structure_file, database).execute }
-
- let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
- let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, schema) }
- let(:inconsistency_type) { validator.name.demodulize.underscore }
- let(:database_name) { 'main' }
- let(:schema) { 'public' }
- let(:database_model) { Gitlab::Database.database_base_models[database_name] }
- let(:connection) { database_model.connection }
- let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
-
- let(:database_triggers) do
- [
- ['trigger', 'CREATE TRIGGER trigger AFTER INSERT ON public.t1 FOR EACH ROW EXECUTE FUNCTION t1()'],
- ['wrong_trigger', 'CREATE TRIGGER wrong_trigger BEFORE UPDATE ON public.t2 FOR EACH ROW EXECUTE FUNCTION t2()'],
- ['extra_trigger', 'CREATE TRIGGER extra_trigger BEFORE INSERT ON public.t4 FOR EACH ROW EXECUTE FUNCTION t4()']
- ]
- end
-
- before do
- allow(connection).to receive(:select_rows).and_return(database_triggers)
- end
-
- it 'returns trigger inconsistencies' do
- expect(result.map(&:object_name)).to match_array(expected_result)
- expect(result.map(&:type)).to all(eql inconsistency_type)
- end
-end
diff --git a/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
index 169fceced7a..9dc18555340 100644
--- a/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples 'tracked issuable snowplow and service ping events for given event params' do
+RSpec.shared_examples 'tracked issuable events' do
before do
stub_application_setting(usage_ping_enabled: true)
end
@@ -21,6 +21,10 @@ RSpec.shared_examples 'tracked issuable snowplow and service ping events for giv
it 'does not track edit actions if author is not present' do
expect(track_action({ author: nil }.merge(track_params))).to be_nil
end
+end
+
+RSpec.shared_examples 'tracked issuable snowplow and service ping events for given event params' do
+ it_behaves_like 'tracked issuable events'
it 'emits snowplow event' do
track_action({ author: user1 }.merge(track_params))
@@ -29,6 +33,23 @@ RSpec.shared_examples 'tracked issuable snowplow and service ping events for giv
end
end
+RSpec.shared_examples 'tracked issuable internal event for given event params' do
+ it_behaves_like 'tracked issuable events'
+
+ it_behaves_like 'internal event tracking' do
+ subject(:track_event) { track_action({ author: user1 }.merge(track_params)) }
+
+ let(:user) { user1 }
+ let(:namespace) { project&.namespace }
+ end
+end
+
+RSpec.shared_examples 'tracked issuable internal event with project' do
+ it_behaves_like 'tracked issuable internal event for given event params' do
+ let(:track_params) { original_params || { project: project } }
+ end
+end
+
RSpec.shared_examples 'tracked issuable snowplow and service ping events with project' do
it_behaves_like 'tracked issuable snowplow and service ping events for given event params' do
let(:context) do
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 6f104f400bc..52f0e7847b0 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
@@ -2,7 +2,7 @@
RSpec.shared_examples 'StageEventModel' do
describe '.upsert_data' do
- let(:time) { Time.parse(Time.current.to_s(:db)) } # truncating the timestamp so we can compare it with the timestamp loaded from the DB
+ let(:time) { Time.parse(Time.current.to_fs(:db)) } # truncating the timestamp so we can compare it with the timestamp loaded from the DB
let(:input_data) do
[
{
diff --git a/spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb b/spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb
index 4753d7a4556..0e9200f1fd9 100644
--- a/spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb
+++ b/spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb
@@ -6,16 +6,34 @@ RSpec.shared_examples 'protected ref access' do |association|
let_it_be(:project) { create(:project) }
let_it_be(:protected_ref) { create(association, project: project) } # rubocop:disable Rails/SaveBang
- it { is_expected.to validate_inclusion_of(:access_level).in_array(described_class.allowed_access_levels) }
+ describe 'validations' do
+ subject { build(described_class.model_name.singular) }
- it { is_expected.to validate_presence_of(:access_level) }
+ context 'when role?' do
+ it { is_expected.to validate_inclusion_of(:access_level).in_array(described_class.allowed_access_levels) }
- context 'when not role?' do
- before do
- allow(subject).to receive(:role?).and_return(false)
+ it { is_expected.to validate_presence_of(:access_level) }
+
+ it do
+ is_expected.to validate_uniqueness_of(:access_level)
+ .scoped_to("#{described_class.module_parent.model_name.singular}_id")
+ end
end
- it { is_expected.not_to validate_presence_of(:access_level) }
+ context 'when not role?' do
+ before do
+ allow(subject).to receive(:role?).and_return(false)
+ end
+
+ it { is_expected.not_to validate_presence_of(:access_level) }
+
+ it { is_expected.not_to validate_inclusion_of(:access_level).in_array(described_class.allowed_access_levels) }
+
+ it do
+ is_expected.not_to validate_uniqueness_of(:access_level)
+ .scoped_to("#{described_class.module_parent.model_name.singular}_id")
+ end
+ end
end
describe '::human_access_levels' do
diff --git a/spec/support/shared_examples/models/concerns/protected_ref_deploy_key_access_examples.rb b/spec/support/shared_examples/models/concerns/protected_ref_deploy_key_access_examples.rb
new file mode 100644
index 00000000000..f2e79dc377b
--- /dev/null
+++ b/spec/support/shared_examples/models/concerns/protected_ref_deploy_key_access_examples.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'protected ref deploy_key access' do
+ let_it_be(:described_instance) { described_class.model_name.singular }
+ let_it_be(:protected_ref_name) { described_class.module_parent.model_name.singular }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:protected_ref) { create(protected_ref_name, project: project) } # rubocop:disable Rails/SaveBang
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:deploy_key) }
+ end
+
+ describe 'validations' do
+ context 'when deploy_key?' do
+ context 'when deploy key enabled for the project' do
+ let(:deploy_key) do
+ create(:deploy_keys_project, :write_access, project: project).deploy_key
+ end
+
+ it 'is valid' do
+ level = build(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+
+ expect(level).to be_valid
+ end
+ end
+
+ context 'when a deploy key already added for this access level' do
+ let(:deploy_key) { create(:deploy_keys_project, :write_access, project: project).deploy_key }
+
+ before do
+ create(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+ end
+
+ subject(:access_level) do
+ build(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+ end
+
+ it 'is not valid', :aggregate_failures do
+ is_expected.to be_invalid
+ expect(access_level.errors.full_messages).to contain_exactly('Deploy key has already been taken')
+ end
+ end
+
+ context 'when deploy key is not enabled for the project' do
+ subject(:access_level) do
+ build(described_instance, protected_ref_name => protected_ref, deploy_key: create(:deploy_key))
+ end
+
+ it 'is not valid', :aggregate_failures do
+ is_expected.to be_invalid
+ expect(access_level.errors.full_messages).to contain_exactly('Deploy key is not enabled for this project')
+ end
+ end
+
+ context 'when deploy key is not active for the project' do
+ subject(:access_level) do
+ deploy_key = create(:deploy_keys_project, :readonly_access, project: project).deploy_key
+ build(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+ end
+
+ it 'is not valid', :aggregate_failures do
+ is_expected.to be_invalid
+ expect(access_level.errors.full_messages).to contain_exactly('Deploy key is not enabled for this project')
+ end
+ end
+ end
+ end
+
+ describe '#check_access' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:deploy_key) { create(:deploy_key, user: user) }
+ let_it_be(:deploy_keys_project) do
+ create(:deploy_keys_project, :write_access, project: project, deploy_key: deploy_key)
+ end
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ context "when this #{described_class.model_name.singular} is tied to a deploy key" do
+ let!(:access_level) do
+ create(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+ end
+
+ context 'when the deploy key is among the active keys for this project' do
+ it { expect(access_level.check_access(user)).to be_truthy }
+ end
+
+ context 'when user is missing' do
+ it { expect(access_level.check_access(nil)).to be_falsey }
+ end
+
+ context 'when deploy key does not belong to the user' do
+ let(:another_user) { create(:user) }
+
+ it { expect(access_level.check_access(another_user)).to be_falsey }
+ end
+
+ context 'when user cannot access the project' do
+ before do
+ allow(user).to receive(:can?).with(:read_project, project).and_return(false)
+ end
+
+ it { expect(access_level.check_access(user)).to be_falsey }
+ end
+
+ context 'when the deploy key is not among the active keys of this project' do
+ before do
+ deploy_keys_project.update!(can_push: false)
+ end
+
+ after do
+ deploy_keys_project.update!(can_push: true)
+ end
+
+ it { expect(access_level.check_access(user)).to be_falsey }
+ end
+ end
+ end
+
+ describe '#type' do
+ let(:access_level) { build(described_instance) }
+
+ context 'when deploy_key?' do
+ let(:access_level) { build(described_instance, deploy_key: build(:deploy_key)) }
+
+ it 'returns :deploy_key' do
+ expect(access_level.type).to eq(:deploy_key)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/database_event_tracking_shared_examples.rb b/spec/support/shared_examples/models/database_event_tracking_shared_examples.rb
index 3d98d9136e2..56b36b3ea07 100644
--- a/spec/support/shared_examples/models/database_event_tracking_shared_examples.rb
+++ b/spec/support/shared_examples/models/database_event_tracking_shared_examples.rb
@@ -12,7 +12,6 @@ RSpec.shared_examples 'database events tracking' do
let(:category) { described_class.to_s }
let(:label) { described_class.table_name }
let(:action) { "database_event_#{property}" }
- let(:feature_flag_name) { :product_intelligence_database_event_tracking }
let(:record_tracked_attributes) { record.attributes.slice(*described_class::SNOWPLOW_ATTRIBUTES.map(&:to_s)) }
let(:base_extra) { record_tracked_attributes.merge(project: try(:project), namespace: try(:namespace)) }
@@ -48,9 +47,3 @@ RSpec.shared_examples 'database events tracking' do
end
end
end
-
-RSpec.shared_examples 'database events tracking batch 2' do
- it_behaves_like 'database events tracking' do
- let(:feature_flag_name) { :product_intelligence_database_event_tracking_batch2 }
- end
-end
diff --git a/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb b/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb
index 0cf109ce5c5..ff3cc1841b4 100644
--- a/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb
+++ b/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb
@@ -122,7 +122,7 @@ RSpec.shared_examples Integrations::BaseSlashCommands do
end
it_behaves_like 'blocks command execution' do
- let(:error_message) { 'your account has been deactivated by your administrator' }
+ let(:error_message) { "your #{Gitlab.config.gitlab.url} account needs to be reactivated" }
end
end
end
diff --git a/spec/support/shared_examples/namespaces/traversal_examples.rb b/spec/support/shared_examples/namespaces/traversal_examples.rb
index 600539f7d0a..4dff4f68995 100644
--- a/spec/support/shared_examples/namespaces/traversal_examples.rb
+++ b/spec/support/shared_examples/namespaces/traversal_examples.rb
@@ -239,13 +239,11 @@ RSpec.shared_examples 'namespace traversal' do
end
describe '#ancestors_upto' do
- context 'with use_traversal_ids_for_ancestors_upto enabled' do
- include_examples '#ancestors_upto'
- end
+ include_examples '#ancestors_upto'
- context 'with use_traversal_ids_for_ancestors_upto disabled' do
+ context 'with use_traversal_ids disabled' do
before do
- stub_feature_flags(use_traversal_ids_for_ancestors_upto: false)
+ stub_feature_flags(use_traversal_ids: false)
end
include_examples '#ancestors_upto'
diff --git a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
index 0c4e5ce51fc..b308295b5fb 100644
--- a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
+++ b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
@@ -70,10 +70,9 @@ RSpec.shared_examples 'namespace traversal scopes' do
end
describe '.roots' do
- context "use_traversal_ids_roots feature flag is true" do
+ context "use_traversal_ids feature flag is true" do
before do
stub_feature_flags(use_traversal_ids: true)
- stub_feature_flags(use_traversal_ids_roots: true)
end
it_behaves_like '.roots'
@@ -83,9 +82,9 @@ RSpec.shared_examples 'namespace traversal scopes' do
end
end
- context "use_traversal_ids_roots feature flag is false" do
+ context "use_traversal_ids feature flag is false" do
before do
- stub_feature_flags(use_traversal_ids_roots: false)
+ stub_feature_flags(use_traversal_ids: false)
end
it_behaves_like '.roots'
diff --git a/spec/support/shared_examples/nav_sidebar_shared_examples.rb b/spec/support/shared_examples/nav_sidebar_shared_examples.rb
deleted file mode 100644
index 4b815988bc5..00000000000
--- a/spec/support/shared_examples/nav_sidebar_shared_examples.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'has nav sidebar' do
- it 'has collapsed nav sidebar on mobile' do
- render
-
- expect(rendered).to have_selector('.nav-sidebar')
- expect(rendered).not_to have_selector('.sidebar-collapsed-desktop')
- expect(rendered).not_to have_selector('.sidebar-expanded-mobile')
- end
-end
-
-RSpec.shared_examples 'page has active tab' do |title|
- it "activates #{title} tab" do
- expect(page).to have_selector('.sidebar-top-level-items > li.active', count: 1)
- expect(find('.sidebar-top-level-items > li.active')).to have_content(title)
- end
-end
-
-RSpec.shared_examples 'page has active sub tab' do |title|
- it "activates #{title} sub tab" do
- expect(page).to have_selector('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)', count: 1)
- expect(find('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)'))
- .to have_content(title)
- end
-end
-
-RSpec.shared_examples 'sidebar includes snowplow attributes' do |track_action, track_label, track_property|
- specify do
- stub_application_setting(snowplow_enabled: true)
-
- render
-
- expect(rendered).to have_css(".nav-sidebar[data-track-action=\"#{track_action}\"][data-track-label=\"#{track_label}\"][data-track-property=\"#{track_property}\"]")
- end
-end
diff --git a/spec/support/shared_examples/npm_sync_metadata_cache_worker_shared_examples.rb b/spec/support/shared_examples/npm_sync_metadata_cache_worker_shared_examples.rb
new file mode 100644
index 00000000000..de2dc4c3725
--- /dev/null
+++ b/spec/support/shared_examples/npm_sync_metadata_cache_worker_shared_examples.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'does not enqueue a worker to sync a metadata cache' do
+ it 'does not enqueue a worker to sync a metadata cache' do
+ expect(Packages::Npm::CreateMetadataCacheWorker).not_to receive(:perform_async)
+
+ subject
+ end
+end
+
+RSpec.shared_examples 'enqueue a worker to sync a metadata cache' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'enqueues a worker to create a metadata cache' do
+ expect(Packages::Npm::CreateMetadataCacheWorker)
+ .to receive(:perform_async).with(project.id, package_name)
+
+ subject
+ end
+
+ context 'with npm_metadata_cache disabled' do
+ before do
+ stub_feature_flags(npm_metadata_cache: false)
+ end
+
+ it_behaves_like 'does not enqueue a worker to sync a metadata cache'
+ end
+end
diff --git a/spec/support/shared_examples/observability/csp_shared_examples.rb b/spec/support/shared_examples/observability/csp_shared_examples.rb
index 9d6e7e75f4d..9002ccd5878 100644
--- a/spec/support/shared_examples/observability/csp_shared_examples.rb
+++ b/spec/support/shared_examples/observability/csp_shared_examples.rb
@@ -5,23 +5,28 @@
# It requires the following variables declared in the context including this example:
#
# - `tested_path`: the path under test
-# - `user`: the test user
-# - `group`: the test group
#
# e.g.
#
# ```
-# let_it_be(:group) { create(:group) }
-# let_it_be(:user) { create(:user) }
# it_behaves_like "observability csp policy" do
# let(:tested_path) { ....the path under test }
# end
# ```
#
+# Note that the context's user is expected to be logged-in and the
+# related resources (group, project, etc) are supposed to be provided with proper
+# permissions already, e.g.
+#
+# before do
+# login_as(user)
+# group.add_developer(user)
+# end
+#
# It optionally supports specifying the controller class handling the tested path as a parameter, e.g.
#
# ```
-# it_behaves_like "observability csp policy", Groups::ObservabilityController
+# it_behaves_like "observability csp policy", Projects::TracingController
# ```
# (If not specified it will default to `described_class`)
#
@@ -41,9 +46,6 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
before do
setup_csp_for_controller(controller_class, csp, any_time: true)
- group.add_developer(user)
- login_as(user)
- stub_feature_flags(observability_group_tab: true)
end
subject do
@@ -59,93 +61,127 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
end
end
- context 'when observability is disabled' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.frame_src 'https://something.test'
+ describe 'frame-src' do
+ context 'when frame-src exists in the CSP config' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.frame_src 'https://something.test'
+ end
end
- end
- before do
- stub_feature_flags(observability_group_tab: false)
+ it 'appends the proper url to frame-src CSP directives' do
+ expect(subject).to include(
+ "frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
+ end
end
- it 'does not add observability urls to the csp header' do
- expect(subject).to include("frame-src https://something.test")
- expect(subject).not_to include("#{observability_url} #{signin_url} #{oauth_url}")
- end
- end
+ context 'when signin url is already present in the policy' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.frame_src signin_url
+ end
+ end
- context 'when frame-src exists in the CSP config' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.frame_src 'https://something.test'
+ it 'does not append signin again' do
+ expect(subject).to include(
+ "frame-src #{signin_url} #{observability_url} #{oauth_url};")
end
end
- it 'appends the proper url to frame-src CSP directives' do
- expect(subject).to include(
- "frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
- end
- end
+ context 'when oauth url is already present in the policy' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.frame_src oauth_url
+ end
+ end
- context 'when signin is already present in the policy' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.frame_src signin_url
+ it 'does not append oauth again' do
+ expect(subject).to include(
+ "frame-src #{oauth_url} #{observability_url} #{signin_url};")
end
end
- it 'does not append signin again' do
- expect(subject).to include(
- "frame-src #{signin_url} #{observability_url} #{oauth_url};")
- end
- end
+ context 'when default-src exists in the CSP config' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.default_src 'https://something.test'
+ end
+ end
+
+ it 'does not change default-src' do
+ expect(subject).to include(
+ "default-src https://something.test;")
+ end
- context 'when oauth is already present in the policy' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.frame_src oauth_url
+ it 'appends the proper url to frame-src CSP directives' do
+ expect(subject).to include(
+ "frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
end
end
- it 'does not append oauth again' do
- expect(subject).to include(
- "frame-src #{oauth_url} #{observability_url} #{signin_url};")
+ context 'when frame-src and default-src exist in the CSP config' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.default_src 'https://something_default.test'
+ p.frame_src 'https://something.test'
+ end
+ end
+
+ it 'appends to frame-src CSP directives' do
+ expect(subject).to include(
+ "frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
+ expect(subject).to include(
+ "default-src https://something_default.test")
+ end
end
end
- context 'when default-src exists in the CSP config' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.default_src 'https://something.test'
+ describe 'connect-src' do
+ context 'when connect-src exists in the CSP config' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.connect_src 'https://something.test'
+ end
end
- end
- it 'does not change default-src' do
- expect(subject).to include(
- "default-src https://something.test;")
+ it 'appends the proper url to connect-src CSP directives' do
+ expect(subject).to include(
+ "connect-src https://something.test localhost #{observability_url}")
+ end
end
- it 'appends the proper url to frame-src CSP directives' do
- expect(subject).to include(
- "frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
- end
- end
+ context 'when default-src exists in the CSP config' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.default_src 'https://something.test'
+ end
+ end
+
+ it 'does not change default-src' do
+ expect(subject).to include(
+ "default-src https://something.test;")
+ end
- context 'when frame-src and default-src exist in the CSP config' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.default_src 'https://something_default.test'
- p.frame_src 'https://something.test'
+ it 'appends the proper url to connect-src CSP directives' do
+ expect(subject).to include(
+ "connect-src https://something.test localhost #{observability_url}")
end
end
- it 'appends to frame-src CSP directives' do
- expect(subject).to include(
- "frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
- expect(subject).to include(
- "default-src https://something_default.test")
+ context 'when connect-src and default-src exist in the CSP config' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.default_src 'https://something_default.test'
+ p.connect_src 'https://something.test'
+ end
+ end
+
+ it 'appends to connect-src CSP directives' do
+ expect(subject).to include(
+ "connect-src https://something.test localhost #{observability_url}")
+ expect(subject).to include(
+ "default-src https://something_default.test")
+ end
end
end
end
diff --git a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
index 7cbaf40721a..4b27f1f2520 100644
--- a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
@@ -2,6 +2,7 @@
RSpec.shared_examples 'close quick action' do |issuable_type|
include Features::NotesHelpers
+ include ContentEditorHelpers
before do
project.add_maintainer(maintainer)
@@ -76,6 +77,7 @@ RSpec.shared_examples 'close quick action' do |issuable_type|
context "preview of note on #{issuable_type}", :js do
it 'explains close quick action' do
visit public_send("project_#{issuable_type}_path", project, issuable)
+ close_rich_text_promo_popover_if_present
preview_note("this is done, close\n/close") do
expect(page).not_to have_content '/close'
diff --git a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
index acbc6429646..cf5a67f6096 100644
--- a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
@@ -41,7 +41,13 @@ RSpec.shared_examples 'merge quick action' do
it 'schedules to merge the MR' do
add_note("/merge")
- expect(page).to have_content "Scheduled to merge this merge request (Merge when pipeline succeeds)."
+ if Gitlab.ee?
+ expect(page).to(
+ have_content("Scheduled to merge this merge request (Merge when checks pass).")
+ )
+ else
+ expect(page).to have_content "Scheduled to merge this merge request (Merge when pipeline succeeds)."
+ end
expect(merge_request.reload).to be_auto_merge_enabled
expect(merge_request.reload).not_to be_merged
diff --git a/spec/support/shared_examples/quick_actions/work_item/type_change_quick_actions_shared_examples.rb b/spec/support/shared_examples/quick_actions/work_item/type_change_quick_actions_shared_examples.rb
index 9ccb7c0ae42..0fc914d71d5 100644
--- a/spec/support/shared_examples/quick_actions/work_item/type_change_quick_actions_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/work_item/type_change_quick_actions_shared_examples.rb
@@ -20,7 +20,7 @@ RSpec.shared_examples 'quick actions that change work item type' do
end
context 'when new type is the same as current type' do
- let(:command) { '/type Issue' }
+ let(:command) { '/type issue' }
it_behaves_like 'quick command error', 'Types are the same'
end
@@ -57,7 +57,7 @@ RSpec.shared_examples 'quick actions that change work item type' do
it 'populates :issue_type: and :work_item_type' do
_, updates, message = service.execute(command, work_item)
- expect(message).to eq(_('Work Item promoted successfully.'))
+ expect(message).to eq(_('Work item promoted successfully.'))
expect(updates).to eq({ issue_type: 'incident', work_item_type: WorkItems::Type.default_by_type(:incident) })
end
@@ -73,7 +73,7 @@ RSpec.shared_examples 'quick actions that change work item type' do
it 'populates :issue_type: and :work_item_type' do
_, updates, message = service.execute(command, work_item)
- expect(message).to eq(_('Work Item promoted successfully.'))
+ expect(message).to eq(_('Work item promoted successfully.'))
expect(updates).to eq({ issue_type: 'issue', work_item_type: WorkItems::Type.default_by_type(:issue) })
end
diff --git a/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
index 5cb6c3d310f..513f9802b34 100644
--- a/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
@@ -20,7 +20,6 @@ RSpec.shared_examples 'Debian packages upload request' do |status, body = nil|
if status == :created
it 'creates package files', :aggregate_failures do
expect(::Packages::Debian::CreatePackageFileService).to receive(:new).with(package: be_a(Packages::Package), current_user: be_an(User), params: be_an(Hash)).and_call_original
- expect(::Packages::Debian::ProcessChangesWorker).not_to receive(:perform_async)
if extra_params[:distribution] || file_name.end_with?('.changes')
expect(::Packages::Debian::FindOrCreateIncomingService).not_to receive(:new)
diff --git a/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
index 930c47dac52..6eceb7c350d 100644
--- a/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
@@ -17,6 +17,10 @@ RSpec.shared_examples 'graphql issue list request spec' do
end
describe 'filters' do
+ let(:mutually_exclusive_error) do
+ 'only one of [assigneeUsernames, assigneeUsername, assigneeWildcardId] arguments is allowed at the same time.'
+ end
+
before_all do
issue_a.assignee_ids = current_user.id
issue_b.assignee_ids = another_user.id
@@ -31,9 +35,45 @@ RSpec.shared_examples 'graphql issue list request spec' do
it 'returns a mutually exclusive param error' do
post_query
- expect_graphql_errors_to_include(
- 'only one of [assigneeUsernames, assigneeUsername] arguments is allowed at the same time.'
- )
+ expect_graphql_errors_to_include(mutually_exclusive_error)
+ end
+ end
+
+ context 'when both assignee_username and assignee_wildcard_id filters are provided' do
+ let(:issue_filter_params) do
+ { assignee_username: current_user.username, assignee_wildcard_id: :ANY }
+ end
+
+ it 'returns a mutually exclusive param error' do
+ post_query
+
+ expect_graphql_errors_to_include(mutually_exclusive_error)
+ end
+ end
+
+ context 'when filtering by assignee_wildcard_id' do
+ context 'when filtering for all issues with assignees' do
+ let(:issue_filter_params) do
+ { assignee_wildcard_id: :ANY }
+ end
+
+ it 'returns all issues with assignees' do
+ post_query
+
+ expect(issue_ids).to match_array([issue_a, issue_b].map { |i| i.to_gid.to_s })
+ end
+ end
+
+ context 'when filtering for issues without assignees' do
+ let(:issue_filter_params) do
+ { assignee_wildcard_id: :NONE }
+ end
+
+ it 'returns all issues without assignees' do
+ post_query
+
+ expect(issue_ids).to match_array([issue_c, issue_d, issue_e].map { |i| i.to_gid.to_s })
+ end
end
end
@@ -492,7 +532,7 @@ RSpec.shared_examples 'graphql issue list request spec' do
end
before do
- issue_a.update_columns(issue_type: WorkItems::Type.base_types[:incident], work_item_type_id: incident_type.id)
+ issue_a.update_columns(work_item_type_id: incident_type.id)
end
it 'returns the escalation status values' do
diff --git a/spec/support/shared_examples/requests/api/graphql/remote_development_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/remote_development_shared_examples.rb
new file mode 100644
index 00000000000..7c32c7bf2a9
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/remote_development_shared_examples.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'workspaces query in licensed environment and with feature flag on' do
+ describe 'when licensed and remote_development_feature_flag feature flag is enabled' do
+ before do
+ stub_licensed_features(remote_development: true)
+
+ post_graphql(query, current_user: current_user)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ # noinspection RubyResolve
+ it { is_expected.to match_array(a_hash_including('name' => workspace.name)) }
+ # noinspection RubyResolve
+
+ context 'when user is not authorized' do
+ let(:current_user) { create(:user) }
+
+ it { is_expected.to eq([]) }
+ end
+ end
+end
+
+RSpec.shared_examples 'workspaces query in unlicensed environment and with feature flag off' do
+ describe 'when remote_development feature is unlicensed' do
+ before do
+ stub_licensed_features(remote_development: false)
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'returns an error' do
+ expect(subject).to be_nil
+ expect_graphql_errors_to_include(/'remote_development' licensed feature is not available/)
+ end
+ end
+
+ describe 'when remote_development_feature_flag feature flag is disabled' do
+ before do
+ stub_licensed_features(remote_development: true)
+ stub_feature_flags(remote_development_feature_flag: false)
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'returns an error' do
+ expect(subject).to be_nil
+ expect_graphql_errors_to_include(/'remote_development_feature_flag' feature flag is disabled/)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb
index 81ff004779a..47cbd268a65 100644
--- a/spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/ml_model_packages_shared_examples.rb
@@ -27,7 +27,7 @@ RSpec.shared_examples 'creates model experiments package files' do
end
it 'returns bad request if package creation fails' do
- allow_next_instance_of(::Packages::MlModel::CreatePackageFileService) do |instance|
+ expect_next_instance_of(::Packages::MlModel::CreatePackageFileService) do |instance|
expect(instance).to receive(:execute).and_return(nil)
end
@@ -106,3 +106,19 @@ RSpec.shared_examples 'process ml model package upload' do
end
end
end
+
+RSpec.shared_examples 'process ml model package download' do
+ context 'when package file exists' do
+ it { is_expected.to have_gitlab_http_status(:success) }
+ end
+
+ context 'when record does not exist' do
+ it 'response is not found' do
+ expect_next_instance_of(::Packages::MlModel::PackageFinder) do |instance|
+ expect(instance).to receive(:execute!).and_raise(ActiveRecord::RecordNotFound)
+ end
+
+ expect(api_response).to have_gitlab_http_status(:not_found)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
index 5284ed2de21..6b6bf375827 100644
--- a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
@@ -44,11 +44,7 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
end
shared_examples 'reject metadata request' do |status:|
- it 'rejects the metadata request' do
- subject
-
- expect(response).to have_gitlab_http_status(status)
- end
+ it_behaves_like 'returning response status', status
end
shared_examples 'redirect metadata request' do |status:|
@@ -280,13 +276,15 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
example_name = 'redirect metadata request'
status = :redirected
else
- example_name = 'reject metadata request'
status = :not_found
end
end
status = :not_found if scope == :group && params[:package_name_type] == :non_existing && !params[:request_forward]
+ # Check the error message for :not_found
+ example_name = 'returning response status with error' if status == :not_found
+
it_behaves_like example_name, status: status
end
end
@@ -361,11 +359,11 @@ RSpec.shared_examples 'handling audit request' do |path:, scope: :project|
end
shared_examples 'reject audit request' do |status:|
- it 'rejects the audit request' do
- subject
+ it_behaves_like 'returning response status', status
+ end
- expect(response).to have_gitlab_http_status(status)
- end
+ shared_examples 'reject audit request with error' do |status:|
+ it_behaves_like 'returning response status with error', status: status, error: 'Project not found'
end
shared_examples 'redirect audit request' do |status:|
@@ -464,7 +462,7 @@ RSpec.shared_examples 'handling audit request' do |path:, scope: :project|
example_name = 'redirect audit request'
status = :temporary_redirect
else
- example_name = 'reject audit request'
+ example_name = 'reject audit request with error'
status = :not_found
end
end
@@ -633,12 +631,12 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project|
example_name = "#{params[:expected_result]} package tags request"
status = params[:expected_status]
- if scope == :instance && params[:package_name_type] != :scoped_naming_convention
- example_name = 'reject package tags request'
+ if (scope == :instance && params[:package_name_type] != :scoped_naming_convention) || (scope == :group && params[:package_name_type] == :non_existing)
status = :not_found
end
- status = :not_found if scope == :group && params[:package_name_type] == :non_existing
+ # Check the error message for :not_found
+ example_name = 'returning response status with error' if status == :not_found
it_behaves_like example_name, status: status
end
@@ -858,6 +856,9 @@ RSpec.shared_examples 'handling different package names, visibilities and user r
status = :not_found if scope == :group && params[:package_name_type] == :non_existing && params[:auth].present?
+ # Check the error message for :not_found
+ example_name = 'returning response status with error' if status == :not_found
+
it_behaves_like example_name, status: status
end
end
diff --git a/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb
index 7c20ea661b5..403344efe03 100644
--- a/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb
@@ -36,18 +36,18 @@ RSpec.shared_examples 'accept package tags request' do |status:|
end
context 'with invalid package name' do
- where(:package_name, :status) do
- '%20' | :bad_request
- nil | :not_found
+ where(:package_name, :status, :error) do
+ '%20' | :bad_request | '"Package Name" not given'
+ nil | :not_found | %r{\A(Packages|Project) not found\z}
end
with_them do
- it_behaves_like 'returning response status', params[:status]
+ it_behaves_like 'returning response status with error', status: params[:status], error: params[:error]
end
end
end
-RSpec.shared_examples 'accept create package tag request' do |user_type|
+RSpec.shared_examples 'accept create package tag request' do |status:|
using RSpec::Parameterized::TableSyntax
context 'with valid package name' do
@@ -92,45 +92,55 @@ RSpec.shared_examples 'accept create package tag request' do |user_type|
expect(response.body).to be_empty
end
end
+
+ context 'with ActiveRecord::RecordInvalid error' do
+ before do
+ allow_next_instance_of(Packages::Tag) do |tag|
+ allow(tag).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
+ end
+ end
+
+ it_behaves_like 'returning response status with error', status: :bad_request, error: 'Record invalid'
+ end
end
context 'with invalid package name' do
- where(:package_name, :status) do
- 'unknown' | :not_found
- '' | :not_found
- '%20' | :bad_request
+ where(:package_name, :status, :error) do
+ 'unknown' | :not_found | %r{\A(Package|Project) not found\z}
+ '' | :not_found | '404 Not Found'
+ '%20' | :bad_request | '"Package Name" not given'
end
with_them do
- it_behaves_like 'returning response status', params[:status]
+ it_behaves_like 'returning response status with error', status: params[:status], error: params[:error]
end
end
context 'with invalid tag name' do
- where(:tag_name, :status) do
- '' | :not_found
- '%20' | :bad_request
+ where(:tag_name, :status, :error) do
+ '' | :not_found | '404 Not Found'
+ '%20' | :bad_request | '"Tag" not given'
end
with_them do
- it_behaves_like 'returning response status', params[:status]
+ it_behaves_like 'returning response status with error', status: params[:status], error: params[:error]
end
end
context 'with invalid version' do
- where(:version, :status) do
- ' ' | :bad_request
- '' | :bad_request
- nil | :bad_request
+ where(:version, :status, :error) do
+ ' ' | :bad_request | '"Version" not given'
+ '' | :bad_request | '"Version" not given'
+ nil | :bad_request | '"Version" not given'
end
with_them do
- it_behaves_like 'returning response status', params[:status]
+ it_behaves_like 'returning response status with error', status: params[:status], error: params[:error]
end
end
end
-RSpec.shared_examples 'accept delete package tag request' do |user_type|
+RSpec.shared_examples 'accept delete package tag request' do |status:|
using RSpec::Parameterized::TableSyntax
context 'with valid package name' do
@@ -159,29 +169,39 @@ RSpec.shared_examples 'accept delete package tag request' do |user_type|
it_behaves_like 'returning response status', :not_found
end
+
+ context 'with ActiveRecord::RecordInvalid error' do
+ before do
+ allow_next_instance_of(::Packages::RemoveTagService) do |service|
+ allow(service).to receive(:execute).and_raise(ActiveRecord::RecordInvalid)
+ end
+ end
+
+ it_behaves_like 'returning response status with error', status: :bad_request, error: 'Record invalid'
+ end
end
context 'with invalid package name' do
- where(:package_name, :status) do
- 'unknown' | :not_found
- '' | :not_found
- '%20' | :bad_request
+ where(:package_name, :status, :error) do
+ 'unknown' | :not_found | %r{\A(Package tag|Project) not found\z}
+ '' | :not_found | '404 Not Found'
+ '%20' | :bad_request | '"Package Name" not given'
end
with_them do
- it_behaves_like 'returning response status', params[:status]
+ it_behaves_like 'returning response status with error', status: params[:status], error: params[:error]
end
end
context 'with invalid tag name' do
- where(:tag_name, :status) do
- 'unknown' | :not_found
- '' | :not_found
- '%20' | :bad_request
+ where(:tag_name, :status, :error) do
+ 'unknown' | :not_found | %r{\A(Package tag|Project) not found\z}
+ '' | :not_found | '404 Not Found'
+ '%20' | :bad_request | '"Tag" not given'
end
with_them do
- it_behaves_like 'returning response status', params[:status]
+ it_behaves_like 'returning response status with error', status: params[:status], error: params[:error]
end
end
end
diff --git a/spec/support/shared_examples/requests/response_status_with_error_shared_examples.rb b/spec/support/shared_examples/requests/response_status_with_error_shared_examples.rb
new file mode 100644
index 00000000000..de012aebaad
--- /dev/null
+++ b/spec/support/shared_examples/requests/response_status_with_error_shared_examples.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'returning response status with error' do |status:, error: nil|
+ it "returns #{status} and error message" do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+ expect(json_response['error']).to be_present
+ expect(json_response['error']).to match(error) if error
+ end
+end
diff --git a/spec/support/shared_examples/services/auto_merge_shared_examples.rb b/spec/support/shared_examples/services/auto_merge_shared_examples.rb
new file mode 100644
index 00000000000..b295b65fdd1
--- /dev/null
+++ b/spec/support/shared_examples/services/auto_merge_shared_examples.rb
@@ -0,0 +1,182 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'for auto_merge strategy context' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+
+ let(:mr_merge_if_green_enabled) do
+ create(:merge_request,
+ merge_when_pipeline_succeeds: true,
+ merge_user: user,
+ source_branch: 'master', target_branch: 'feature',
+ source_project: project, target_project: project,
+ state: 'opened')
+ end
+
+ let(:pipeline) { create(:ci_pipeline, ref: mr_merge_if_green_enabled.source_branch, project: project) }
+
+ let(:service) { described_class.new(project, user, commit_message: 'Awesome message') }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ before do
+ allow(MergeWorker).to receive(:with_status).and_return(MergeWorker)
+ end
+end
+
+RSpec.shared_examples 'auto_merge service #execute' do
+ let(:merge_request) do
+ create(:merge_request, target_project: project, source_project: project,
+ source_branch: 'feature', target_branch: 'master')
+ end
+
+ context 'when first time enabling' do
+ before do
+ allow(merge_request)
+ .to receive_messages(head_pipeline: pipeline, actual_head_pipeline: pipeline)
+ allow(MailScheduler::NotificationServiceWorker).to receive(:perform_async)
+
+ service.execute(merge_request)
+ end
+
+ it 'sets the params, merge_user, and flag' do
+ expect(merge_request).to be_valid
+ expect(merge_request.merge_when_pipeline_succeeds).to be_truthy
+ expect(merge_request.merge_params).to include 'commit_message' => 'Awesome message'
+ expect(merge_request.merge_user).to be user
+ expect(merge_request.auto_merge_strategy).to eq auto_merge_strategy
+ end
+
+ it 'schedules a notification' do
+ expect(MailScheduler::NotificationServiceWorker).to have_received(:perform_async).with(
+ 'merge_when_pipeline_succeeds', merge_request, user).once
+ end
+
+ it 'creates a system note' do
+ pipeline = build(:ci_pipeline)
+ allow(merge_request).to receive(:actual_head_pipeline) { pipeline }
+
+ note = merge_request.notes.last
+ expect(note.note).to match expected_note
+ end
+ end
+
+ context 'when already approved' do
+ let(:service) { described_class.new(project, user, should_remove_source_branch: true) }
+ let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch) }
+
+ before do
+ allow(mr_merge_if_green_enabled)
+ .to receive_messages(head_pipeline: pipeline, actual_head_pipeline: pipeline)
+
+ allow(mr_merge_if_green_enabled).to receive(:mergeable?)
+ .and_return(true)
+
+ allow(pipeline).to receive(:success?).and_return(true)
+ end
+
+ it 'updates the merge params' do
+ expect(SystemNoteService).not_to receive(:merge_when_pipeline_succeeds)
+ expect(MailScheduler::NotificationServiceWorker).not_to receive(:perform_async).with(
+ 'merge_when_pipeline_succeeds', any_args)
+
+ service.execute(mr_merge_if_green_enabled)
+ expect(mr_merge_if_green_enabled.merge_params).to have_key('should_remove_source_branch')
+ end
+ end
+end
+
+RSpec.shared_examples 'auto_merge service #process' do
+ let(:merge_request_ref) { mr_merge_if_green_enabled.source_branch }
+ let(:merge_request_head) do
+ project.commit(mr_merge_if_green_enabled.source_branch).id
+ end
+
+ context 'when triggered by pipeline with valid ref and sha' do
+ let(:triggering_pipeline) do
+ create(:ci_pipeline, project: project, ref: merge_request_ref,
+ sha: merge_request_head, status: 'success',
+ head_pipeline_of: mr_merge_if_green_enabled)
+ end
+
+ it "merges all merge requests with merge when the pipeline succeeds enabled" do
+ allow(mr_merge_if_green_enabled)
+ .to receive_messages(head_pipeline: triggering_pipeline, actual_head_pipeline: triggering_pipeline)
+
+ expect(MergeWorker).to receive(:perform_async)
+ service.process(mr_merge_if_green_enabled)
+ end
+ end
+
+ context 'when triggered by an old pipeline' do
+ let(:old_pipeline) do
+ create(:ci_pipeline, project: project, ref: merge_request_ref,
+ sha: '1234abcdef', status: 'success')
+ end
+
+ it 'does not merge request' do
+ expect(MergeWorker).not_to receive(:perform_async)
+ service.process(mr_merge_if_green_enabled)
+ end
+ end
+
+ context 'when triggered by pipeline from a different branch' do
+ let(:unrelated_pipeline) do
+ create(:ci_pipeline, project: project, ref: 'feature',
+ sha: merge_request_head, status: 'success')
+ end
+
+ it 'does not merge request' do
+ expect(MergeWorker).not_to receive(:perform_async)
+ service.process(mr_merge_if_green_enabled)
+ end
+ end
+
+ context 'when pipeline is merge request pipeline' do
+ let(:pipeline) do
+ create(:ci_pipeline, :success,
+ source: :merge_request_event,
+ ref: mr_merge_if_green_enabled.merge_ref_path,
+ merge_request: mr_merge_if_green_enabled,
+ merge_requests_as_head_pipeline: [mr_merge_if_green_enabled])
+ end
+
+ it 'merges the associated merge request' do
+ allow(mr_merge_if_green_enabled)
+ .to receive_messages(head_pipeline: pipeline, actual_head_pipeline: pipeline)
+
+ expect(MergeWorker).to receive(:perform_async)
+ service.process(mr_merge_if_green_enabled)
+ end
+ end
+end
+
+RSpec.shared_examples 'auto_merge service #cancel' do
+ before do
+ service.cancel(mr_merge_if_green_enabled)
+ end
+
+ it "resets all the pipeline succeeds params" do
+ expect(mr_merge_if_green_enabled.merge_when_pipeline_succeeds).to be_falsey
+ expect(mr_merge_if_green_enabled.merge_params).to eq({})
+ expect(mr_merge_if_green_enabled.merge_user).to be nil
+ end
+
+ it 'posts a system note' do
+ note = mr_merge_if_green_enabled.notes.last
+ expect(note.note).to include 'canceled the automatic merge'
+ end
+end
+
+RSpec.shared_examples 'auto_merge service #abort' do
+ before do
+ service.abort(mr_merge_if_green_enabled, 'an error')
+ end
+
+ it 'posts a system note' do
+ note = mr_merge_if_green_enabled.notes.last
+ expect(note.note).to include 'aborted the automatic merge'
+ end
+end
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 162be24fe8f..9d016e4830e 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
@@ -54,7 +54,7 @@ RSpec.shared_examples 'issues move service' do |group|
context 'when moving to backlog' do
let(:milestone) { create(:milestone, project: project) }
- let!(:backlog) { create(:backlog_list, board: board1) }
+ let!(:backlog) { board1.lists.backlog.first }
let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing, regression], milestone: milestone) }
let(:params) { { board_id: board1.id, from_list_id: list2.id, to_list_id: backlog.id } }
diff --git a/spec/support/shared_examples/services/boards/lists_list_service_shared_examples.rb b/spec/support/shared_examples/services/boards/lists_list_service_shared_examples.rb
index b9f28fab558..716ed482b4b 100644
--- a/spec/support/shared_examples/services/boards/lists_list_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/boards/lists_list_service_shared_examples.rb
@@ -2,7 +2,7 @@
RSpec.shared_examples 'lists list service' do
context 'when the board has a backlog list' do
- let!(:backlog_list) { create_backlog_list(board) }
+ let(:backlog_list) { board.lists.backlog.first }
it 'does not create a backlog list' do
expect { service.execute(board) }.not_to change { board.lists.count }
@@ -34,6 +34,10 @@ RSpec.shared_examples 'lists list service' do
end
context 'when the board does not have a backlog list' do
+ before do
+ board.lists.backlog.delete_all
+ end
+
it 'creates a backlog list' do
expect { service.execute(board) }.to change { board.lists.count }.by(1)
end
diff --git a/spec/support/shared_examples/services/issuable/issuable_import_csv_service_shared_examples.rb b/spec/support/shared_examples/services/issuable/issuable_import_csv_service_shared_examples.rb
index 5336e0f4c2f..8a3ab07bbfe 100644
--- a/spec/support/shared_examples/services/issuable/issuable_import_csv_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/issuable/issuable_import_csv_service_shared_examples.rb
@@ -30,6 +30,7 @@ RSpec.shared_examples 'issuable import csv service' do |issuable_type|
context 'with a file generated by Gitlab CSV export' do
let(:file) { fixture_file_upload('spec/fixtures/csv_gitlab_export.csv') }
+ let!(:test_milestone) { create(:milestone, project: project, title: 'v1.0') }
it 'imports the CSV without errors' do
expect(subject[:success]).to eq(4)
diff --git a/spec/support/shared_examples/views/nav_sidebar_shared_examples.rb b/spec/support/shared_examples/views/nav_sidebar_shared_examples.rb
new file mode 100644
index 00000000000..d4c00738bdb
--- /dev/null
+++ b/spec/support/shared_examples/views/nav_sidebar_shared_examples.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'has nav sidebar' do
+ it 'has collapsed nav sidebar on mobile' do
+ render
+
+ expect(rendered).to have_selector('.nav-sidebar')
+ expect(rendered).not_to have_selector('.sidebar-collapsed-desktop')
+ expect(rendered).not_to have_selector('.sidebar-expanded-mobile')
+ end
+end
+
+RSpec.shared_examples 'sidebar includes snowplow attributes' do |track_action, track_label, track_property|
+ specify do
+ stub_application_setting(snowplow_enabled: true)
+
+ render
+
+ expect(rendered)
+ .to have_css(
+ ".nav-sidebar[data-track-action=\"#{track_action}\"]" \
+ "[data-track-label=\"#{track_label}\"][data-track-property=\"#{track_property}\"]"
+ )
+ end
+end
diff --git a/spec/support/shared_examples/views/pipeline_status_changes_email.rb b/spec/support/shared_examples/views/pipeline_status_changes_email.rb
index fe6cc5e03d2..a2db05c319e 100644
--- a/spec/support/shared_examples/views/pipeline_status_changes_email.rb
+++ b/spec/support/shared_examples/views/pipeline_status_changes_email.rb
@@ -25,6 +25,8 @@ RSpec.shared_examples 'pipeline status changes email' do
end
shared_examples_for 'renders the pipeline status changes email correctly' do
+ let(:pipeline_name_or_id) { pipeline.name || "##{pipeline.id}" }
+
context 'pipeline with user' do
it 'renders the email correctly' do
render
@@ -33,11 +35,12 @@ RSpec.shared_examples 'pipeline status changes email' do
expect(rendered).to have_content pipeline.project.name
expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub(/\s+/, ' ')
expect(rendered).to have_content pipeline.commit.author_name
- expect(rendered).to have_content "##{pipeline.id}"
+ expect(rendered).to have_content pipeline_name_or_id
expect(rendered).to have_content pipeline.user.name
if status == :failed
expect(rendered).to have_content build.name
+ expect(rendered).to include("#{build.project.full_path}/-/jobs/#{build.id}") unless build.is_a?(Ci::Bridge)
end
end
@@ -56,11 +59,12 @@ RSpec.shared_examples 'pipeline status changes email' do
expect(rendered).to have_content pipeline.project.name
expect(rendered).to have_content pipeline.git_commit_message.truncate(50).gsub(/\s+/, ' ')
expect(rendered).to have_content pipeline.commit.author_name
- expect(rendered).to have_content "##{pipeline.id}"
+ expect(rendered).to have_content pipeline_name_or_id
expect(rendered).to have_content "by API"
if status == :failed
expect(rendered).to have_content build.name
+ expect(rendered).to include("#{build.project.full_path}/-/jobs/#{build.id}") unless build.is_a?(Ci::Bridge)
end
end
end
diff --git a/spec/support/shared_examples/views/preferred_language.rb b/spec/support/shared_examples/views/preferred_language.rb
new file mode 100644
index 00000000000..bd6c34bfcc7
--- /dev/null
+++ b/spec/support/shared_examples/views/preferred_language.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a layout which reflects the preferred language' do
+ context 'when changing the a preferred language' do
+ before do
+ Gitlab::I18n.locale = :es
+ end
+
+ after do
+ Gitlab::I18n.use_default_locale
+ end
+
+ it 'renders the correct `lang` attribute in the html element' do
+ render
+
+ expect(rendered).to have_css('html[lang=es]')
+ end
+ end
+end