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
path: root/qa
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 21:18:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 21:18:33 +0300
commitf64a639bcfa1fc2bc89ca7db268f594306edfd7c (patch)
treea2c3c2ebcc3b45e596949db485d6ed18ffaacfa1 /qa
parentbfbc3e0d6583ea1a91f627528bedc3d65ba4b10f (diff)
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc40
Diffstat (limited to 'qa')
-rw-r--r--qa/Dockerfile8
-rw-r--r--qa/Gemfile1
-rw-r--r--qa/Gemfile.lock22
-rw-r--r--qa/qa.rb12
-rw-r--r--qa/qa/fixtures/designs/testfile.pngbin0 -> 36978 bytes
-rw-r--r--qa/qa/fixtures/designs/update/testfile.pngbin0 -> 23741 bytes
-rw-r--r--qa/qa/page/admin/settings/component/ip_limits.rb6
-rw-r--r--qa/qa/page/admin/settings/component/outbound_requests.rb2
-rw-r--r--qa/qa/page/admin/settings/component/performance_bar.rb2
-rw-r--r--qa/qa/page/admin/settings/component/sign_up_restrictions.rb8
-rw-r--r--qa/qa/page/base.rb23
-rw-r--r--qa/qa/page/component/invite_members_modal.rb80
-rw-r--r--qa/qa/page/component/issue_board/show.rb8
-rw-r--r--qa/qa/page/component/new_snippet.rb6
-rw-r--r--qa/qa/page/component/note.rb3
-rw-r--r--qa/qa/page/component/wiki.rb74
-rw-r--r--qa/qa/page/component/wiki_page_form.rb52
-rw-r--r--qa/qa/page/component/wiki_sidebar.rb48
-rw-r--r--qa/qa/page/dashboard/snippet/edit.rb6
-rw-r--r--qa/qa/page/group/members.rb29
-rw-r--r--qa/qa/page/group/menu.rb13
-rw-r--r--qa/qa/page/group/settings/general.rb48
-rw-r--r--qa/qa/page/group/settings/package_registries.rb42
-rw-r--r--qa/qa/page/main/login.rb2
-rw-r--r--qa/qa/page/merge_request/show.rb72
-rw-r--r--qa/qa/page/project/import/github.rb39
-rw-r--r--qa/qa/page/project/issue/index.rb14
-rw-r--r--qa/qa/page/project/members.rb35
-rw-r--r--qa/qa/page/project/new.rb2
-rw-r--r--qa/qa/page/project/operations/kubernetes/add_existing.rb2
-rw-r--r--qa/qa/page/project/operations/kubernetes/index.rb4
-rw-r--r--qa/qa/page/project/registry/show.rb40
-rw-r--r--qa/qa/page/project/settings/auto_devops.rb4
-rw-r--r--qa/qa/page/project/settings/ci_variables.rb1
-rw-r--r--qa/qa/page/project/settings/incidents.rb2
-rw-r--r--qa/qa/page/project/settings/main.rb13
-rw-r--r--qa/qa/page/project/settings/merge_request.rb10
-rw-r--r--qa/qa/page/project/sub_menus/packages.rb19
-rw-r--r--qa/qa/page/project/sub_menus/settings.rb2
-rw-r--r--qa/qa/page/project/web_ide/edit.rb4
-rw-r--r--qa/qa/page/project/wiki/edit.rb40
-rw-r--r--qa/qa/page/project/wiki/show.rb64
-rw-r--r--qa/qa/page/project/wiki/sidebar.rb50
-rw-r--r--qa/qa/resource/clusters/agent_token.rb2
-rw-r--r--qa/qa/resource/members.rb13
-rw-r--r--qa/qa/resource/merge_request.rb10
-rw-r--r--qa/qa/resource/personal_access_token.rb52
-rw-r--r--qa/qa/resource/project.rb14
-rw-r--r--qa/qa/resource/project_imported_from_github.rb4
-rw-r--r--qa/qa/resource/project_snippet.rb6
-rw-r--r--qa/qa/resource/registry_repository.rb53
-rw-r--r--qa/qa/resource/snippet.rb37
-rw-r--r--qa/qa/resource/user.rb15
-rw-r--r--qa/qa/resource/wiki/group_page.rb48
-rw-r--r--qa/qa/runtime/api/client.rb38
-rw-r--r--qa/qa/runtime/api/repository_storage_moves.rb22
-rw-r--r--qa/qa/runtime/env.rb26
-rw-r--r--qa/qa/service/praefect_manager.rb42
-rw-r--r--qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb15
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb6
-rw-r--r--qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb45
-rw-r--r--qa/qa/specs/features/api/4_verify/.gitkeep0
-rw-r--r--qa/qa/specs/features/api/4_verify/pipeline_deletion_spec.rb82
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb12
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb84
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry_spec.rb77
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb149
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb12
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb2
-rw-r--r--qa/qa/support/api.rb1
-rw-r--r--qa/qa/support/ssh.rb14
-rw-r--r--qa/qa/tools/initialize_gitlab_auth.rb2
-rw-r--r--qa/spec/runtime/api/client_spec.rb2
-rw-r--r--qa/spec/runtime/env_spec.rb1
-rw-r--r--qa/spec/specs/helpers/quarantine_spec.rb73
-rw-r--r--qa/spec/support/matchers/have_matcher.rb1
-rw-r--r--qa/spec/support/ssh_spec.rb22
-rw-r--r--qa/tls_certificates/authority/ca.crt32
-rw-r--r--qa/tls_certificates/authority/ca.key51
-rw-r--r--qa/tls_certificates/authority/ca.pem83
114 files changed, 1607 insertions, 564 deletions
diff --git a/qa/Dockerfile b/qa/Dockerfile
index 76c81d03071..dda882dc5e6 100644
--- a/qa/Dockerfile
+++ b/qa/Dockerfile
@@ -38,6 +38,14 @@ RUN unzip chromedriver_linux64.zip -d /usr/local/bin
RUN rm -f chromedriver_linux64.zip
##
+# Install root certificate
+#
+RUN mkdir -p /usr/share/ca-certificates/gitlab
+ADD ./qa/tls_certificates/authority/ca.crt /usr/share/ca-certificates/gitlab/
+RUN echo 'gitlab/ca.crt' >> /etc/ca-certificates.conf
+RUN chmod -R 644 /usr/share/ca-certificates/gitlab && update-ca-certificates
+
+##
# Install gcloud and kubectl CLI used in Auto DevOps test to create K8s
# clusters
#
diff --git a/qa/Gemfile b/qa/Gemfile
index f55d27c159b..21ca945a500 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -21,6 +21,7 @@ gem 'rotp', '~> 3.1.0'
gem 'timecop', '~> 0.9.1'
gem 'parallel', '~> 1.19'
gem 'rspec-parameterized', '~> 0.4.2'
+gem 'github_api', '~> 0.18.2'
group :development do
gem 'pry-byebug', '~> 3.5.1', platform: :mri
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 3b532d90526..4eeaca1f1a6 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -39,19 +39,31 @@ GEM
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
concurrent-ruby (1.1.7)
+ descendants_tracker (0.0.4)
+ thread_safe (~> 0.3, >= 0.3.1)
diff-lcs (1.3)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
equalizer (0.0.11)
faker (1.9.3)
i18n (>= 0.7)
+ faraday (0.17.3)
+ multipart-post (>= 1.2, < 3)
+ github_api (0.18.2)
+ addressable (~> 2.4)
+ descendants_tracker (~> 0.0.4)
+ faraday (~> 0.8)
+ hashie (~> 3.5, >= 3.5.2)
+ oauth2 (~> 1.0)
gitlab-qa (4.0.0)
+ hashie (3.6.0)
http-accept (1.7.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
i18n (1.8.5)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
+ jwt (2.2.2)
knapsack (1.17.1)
rake
launchy (2.4.3)
@@ -65,10 +77,19 @@ GEM
mini_mime (1.0.2)
mini_portile2 (2.5.0)
minitest (5.14.2)
+ multi_json (1.15.0)
+ multi_xml (0.6.0)
+ multipart-post (2.1.1)
netrc (0.11.0)
nokogiri (1.11.1)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
+ oauth2 (1.4.4)
+ faraday (>= 0.8, < 2.0)
+ jwt (>= 1.0, < 3.0)
+ multi_json (~> 1.3)
+ multi_xml (~> 0.5)
+ rack (>= 1.2, < 3)
parallel (1.19.2)
parallel_tests (2.29.0)
parallel
@@ -155,6 +176,7 @@ DEPENDENCIES
capybara (~> 3.29.0)
capybara-screenshot (~> 1.0.23)
faker (~> 1.6, >= 1.6.6)
+ github_api (~> 0.18.2)
gitlab-qa
knapsack (~> 1.17)
nokogiri (~> 1.11.1)
diff --git a/qa/qa.rb b/qa/qa.rb
index 1cf6d7b79f7..2ac199c9d26 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -95,6 +95,7 @@ module QA
autoload :Visibility, 'qa/resource/visibility'
autoload :ProjectSnippet, 'qa/resource/project_snippet'
autoload :Design, 'qa/resource/design'
+ autoload :RegistryRepository, 'qa/resource/registry_repository'
module KubernetesCluster
autoload :Base, 'qa/resource/kubernetes_cluster/base'
@@ -120,6 +121,7 @@ module QA
module Wiki
autoload :ProjectPage, 'qa/resource/wiki/project_page'
+ autoload :GroupPage, 'qa/resource/wiki/group_page'
end
end
@@ -231,6 +233,7 @@ module QA
module Settings
autoload :General, 'qa/page/group/settings/general'
+ autoload :PackageRegistries, 'qa/page/group/settings/package_registries'
end
end
@@ -293,6 +296,10 @@ module QA
autoload :Show, 'qa/page/project/packages/show'
end
+ module Registry
+ autoload :Show, 'qa/page/project/registry/show'
+ end
+
module Settings
autoload :Advanced, 'qa/page/project/settings/advanced'
autoload :Main, 'qa/page/project/settings/main'
@@ -374,7 +381,6 @@ module QA
autoload :Edit, 'qa/page/project/wiki/edit'
autoload :Show, 'qa/page/project/wiki/show'
autoload :GitAccess, 'qa/page/project/wiki/git_access'
- autoload :Sidebar, 'qa/page/project/wiki/sidebar'
autoload :List, 'qa/page/project/wiki/list'
end
@@ -489,6 +495,10 @@ module QA
autoload :ProjectSelector, 'qa/page/component/project_selector'
autoload :Snippet, 'qa/page/component/snippet'
autoload :NewSnippet, 'qa/page/component/new_snippet'
+ autoload :InviteMembersModal, 'qa/page/component/invite_members_modal'
+ autoload :Wiki, 'qa/page/component/wiki'
+ autoload :WikiSidebar, 'qa/page/component/wiki_sidebar'
+ autoload :WikiPageForm, 'qa/page/component/wiki_page_form'
module Issuable
autoload :Common, 'qa/page/component/issuable/common'
diff --git a/qa/qa/fixtures/designs/testfile.png b/qa/qa/fixtures/designs/testfile.png
new file mode 100644
index 00000000000..9693153ca7b
--- /dev/null
+++ b/qa/qa/fixtures/designs/testfile.png
Binary files differ
diff --git a/qa/qa/fixtures/designs/update/testfile.png b/qa/qa/fixtures/designs/update/testfile.png
new file mode 100644
index 00000000000..fe0ad7f7a1a
--- /dev/null
+++ b/qa/qa/fixtures/designs/update/testfile.png
Binary files differ
diff --git a/qa/qa/page/admin/settings/component/ip_limits.rb b/qa/qa/page/admin/settings/component/ip_limits.rb
index 9db2ae8ba58..1f9bd113cab 100644
--- a/qa/qa/page/admin/settings/component/ip_limits.rb
+++ b/qa/qa/page/admin/settings/component/ip_limits.rb
@@ -14,9 +14,9 @@ module QA
end
def enable_throttles
- check_element :throttle_unauthenticated_checkbox
- check_element :throttle_authenticated_api_checkbox
- check_element :throttle_authenticated_web_checkbox
+ check_element(:throttle_unauthenticated_checkbox)
+ check_element(:throttle_authenticated_api_checkbox)
+ check_element(:throttle_authenticated_web_checkbox)
end
def save_settings
diff --git a/qa/qa/page/admin/settings/component/outbound_requests.rb b/qa/qa/page/admin/settings/component/outbound_requests.rb
index 248ea5b6715..c812c05f9c1 100644
--- a/qa/qa/page/admin/settings/component/outbound_requests.rb
+++ b/qa/qa/page/admin/settings/component/outbound_requests.rb
@@ -19,7 +19,7 @@ module QA
private
def check_allow_requests_to_local_network_from_services_checkbox
- check_element :allow_requests_from_services_checkbox
+ check_element(:allow_requests_from_services_checkbox)
end
def click_save_changes_button
diff --git a/qa/qa/page/admin/settings/component/performance_bar.rb b/qa/qa/page/admin/settings/component/performance_bar.rb
index bc29efb64c0..9e92fa362fb 100644
--- a/qa/qa/page/admin/settings/component/performance_bar.rb
+++ b/qa/qa/page/admin/settings/component/performance_bar.rb
@@ -12,7 +12,7 @@ module QA
end
def enable_performance_bar
- click_element :enable_performance_bar_checkbox
+ check_element(:enable_performance_bar_checkbox)
Capybara.current_session.driver.browser.manage.add_cookie(name: 'perf_bar_enabled', value: 'true')
end
diff --git a/qa/qa/page/admin/settings/component/sign_up_restrictions.rb b/qa/qa/page/admin/settings/component/sign_up_restrictions.rb
index 9526faf4126..9909155641f 100644
--- a/qa/qa/page/admin/settings/component/sign_up_restrictions.rb
+++ b/qa/qa/page/admin/settings/component/sign_up_restrictions.rb
@@ -13,13 +13,13 @@ module QA
end
def require_admin_approval_after_user_signup
- check_element :require_admin_approval_after_user_signup_checkbox
- click_element :save_changes_button
+ check_element(:require_admin_approval_after_user_signup_checkbox)
+ click_element(:save_changes_button)
end
def disable_signups
- uncheck_element :signup_enabled_checkbox
- click_element :save_changes_button
+ uncheck_element(:signup_enabled_checkbox)
+ click_element(:save_changes_button)
end
end
end
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index 99f73bbba48..d1b556b58fb 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -133,9 +133,15 @@ module QA
end
def check_element(name)
+ if find_element(name, visible: false).checked?
+ QA::Runtime::Logger.debug("#{name} is already checked")
+
+ return
+ end
+
retry_until(sleep_interval: 1) do
- find_element(name).set(true)
- checked = find_element(name).checked?
+ find_element(name, visible: false).click
+ checked = find_element(name, visible: false).checked?
QA::Runtime::Logger.debug(checked ? "#{name} was checked" : "#{name} was not checked")
@@ -144,10 +150,19 @@ module QA
end
def uncheck_element(name)
+ unless find_element(name, visible: false).checked?
+ QA::Runtime::Logger.debug("#{name} is already unchecked")
+
+ return
+ end
+
retry_until(sleep_interval: 1) do
- find_element(name).set(false)
+ find_element(name, visible: false).click
+ unchecked = !find_element(name, visible: false).checked?
+
+ QA::Runtime::Logger.debug(unchecked ? "#{name} was unchecked" : "#{name} was not unchecked")
- !find_element(name).checked?
+ unchecked
end
end
diff --git a/qa/qa/page/component/invite_members_modal.rb b/qa/qa/page/component/invite_members_modal.rb
new file mode 100644
index 00000000000..fbddb37f15e
--- /dev/null
+++ b/qa/qa/page/component/invite_members_modal.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module InviteMembersModal
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/assets/javascripts/invite_members/components/invite_members_modal.vue' do
+ element :invite_button
+ element :access_level_dropdown
+ element :invite_members_modal_content
+ end
+
+ base.view 'app/assets/javascripts/invite_members/components/group_select.vue' do
+ element :group_select_dropdown_search_field
+ end
+
+ base.view 'app/assets/javascripts/invite_members/components/invite_group_trigger.vue' do
+ element :invite_a_group_button
+ end
+
+ base.view 'app/assets/javascripts/invite_members/components/invite_members_trigger.vue' do
+ element :invite_members_button
+ end
+ end
+
+ def open_invite_members_modal
+ click_element :invite_members_button
+ end
+
+ def open_invite_group_modal
+ click_element :invite_a_group_button
+ end
+
+ def add_member(username, access_level = Resource::Members::AccessLevel::DEVELOPER)
+ open_invite_members_modal
+
+ within_element(:invite_members_modal_content) do
+ fill_element :access_level_dropdown, with: access_level
+
+ fill_in 'Search for members to invite', with: username
+
+ Support::WaitForRequests.wait_for_requests
+
+ click_button username
+
+ click_element :invite_button
+ end
+
+ Support::WaitForRequests.wait_for_requests
+
+ page.refresh
+ end
+
+ def invite_group(group_name, group_access = Resource::Members::AccessLevel::GUEST)
+ open_invite_group_modal
+
+ fill_element :access_level_dropdown, with: group_access
+
+ click_button 'Select a group'
+ fill_element :group_select_dropdown_search_field, group_name
+
+ Support::WaitForRequests.wait_for_requests
+
+ click_button group_name
+
+ click_element :invite_button
+
+ Support::WaitForRequests.wait_for_requests
+
+ page.refresh
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/component/issue_board/show.rb b/qa/qa/page/component/issue_board/show.rb
index 4c1f03fbe86..d7dfb0757bc 100644
--- a/qa/qa/page/component/issue_board/show.rb
+++ b/qa/qa/page/component/issue_board/show.rb
@@ -43,6 +43,10 @@ module QA
element :focus_mode_button
end
+ view 'app/assets/javascripts/boards/components/config_toggle.vue' do
+ element :boards_config_button
+ end
+
# The `focused_board` method does not use `find_element` with an element defined
# with the attribute `data-qa-selector` since such element is not unique when the
# `is-focused` class is not set, and it was not possible to find a better solution.
@@ -82,6 +86,10 @@ module QA
end
end
+ def click_boards_config_button
+ click_element(:boards_config_button)
+ end
+
def click_boards_dropdown_button
# The dropdown button comes from the `GlDropdown` component of `@gitlab/ui`,
# so it wasn't possible to add a `data-qa-selector` to it.
diff --git a/qa/qa/page/component/new_snippet.rb b/qa/qa/page/component/new_snippet.rb
index 741a3feb73b..673bc7ba44c 100644
--- a/qa/qa/page/component/new_snippet.rb
+++ b/qa/qa/page/component/new_snippet.rb
@@ -32,6 +32,10 @@ module QA
# This 'element' is here only to ensure the changes in the view source aren't mistakenly changed
element :_, "qa_selector = local_assigns.fetch(:qa_selector, '')" # rubocop:disable QA/ElementWithPattern
end
+
+ base.view 'app/assets/javascripts/snippets/components/snippet_visibility_edit.vue' do
+ element :visibility_content
+ end
end
def fill_title(title)
@@ -44,7 +48,7 @@ module QA
end
def set_visibility(visibility)
- choose visibility
+ click_element(:visibility_content, visibility: visibility)
end
def fill_file_name(name, file_number = nil)
diff --git a/qa/qa/page/component/note.rb b/qa/qa/page/component/note.rb
index 50567796bdb..67583f71bf3 100644
--- a/qa/qa/page/component/note.rb
+++ b/qa/qa/page/component/note.rb
@@ -17,7 +17,6 @@ module QA
element :comment_button
element :comment_field
element :discussion_menu_item
- element :note_dropdown
end
base.view 'app/assets/javascripts/notes/components/discussion_actions.vue' do
@@ -146,7 +145,7 @@ module QA
def start_discussion(text)
fill_element :comment_field, text
- click_element :note_dropdown
+ within_element(:comment_button) { click_button(class: 'dropdown-toggle-split') }
click_element :discussion_menu_item
click_element :comment_button
diff --git a/qa/qa/page/component/wiki.rb b/qa/qa/page/component/wiki.rb
new file mode 100644
index 00000000000..92eb25af247
--- /dev/null
+++ b/qa/qa/page/component/wiki.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module Wiki
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/views/shared/wikis/show.html.haml' do
+ element :wiki_page_title
+ element :wiki_page_content
+ element :edit_page_button
+ end
+
+ base.view 'app/views/shared/wikis/_main_links.html.haml' do
+ element :new_page_button
+ element :page_history_button
+ end
+
+ base.view 'app/views/shared/empty_states/_wikis.html.haml' do
+ element :create_first_page_link
+ end
+
+ base.view 'app/views/shared/empty_states/_wikis_layout.html.haml' do
+ element :svg_content
+ end
+ end
+
+ def click_create_your_first_page
+ # The svg takes a fraction of a second to load after which the
+ # "Create your first page" button shifts up a bit. This can cause
+ # webdriver to miss the hit so we wait for the svg to load before
+ # clicking the button.
+ within_element(:svg_content) do
+ has_element?(:js_lazy_loaded)
+ end
+
+ click_element(:create_first_page_link)
+ end
+
+ def click_new_page
+ click_element(:new_page_button)
+ end
+
+ def click_page_history
+ click_element(:page_history_button)
+ end
+
+ def click_edit
+ click_element(:edit_page_button)
+ end
+
+ def has_title?(title)
+ has_element?(:wiki_page_title, title)
+ end
+
+ def has_content?(content)
+ has_element?(:wiki_page_content, content)
+ end
+
+ def has_no_content?(content)
+ has_no_element?(:wiki_page_content, content)
+ end
+
+ def has_no_page?
+ has_element?(:create_first_page_link)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/component/wiki_page_form.rb b/qa/qa/page/component/wiki_page_form.rb
new file mode 100644
index 00000000000..e24b1b67af1
--- /dev/null
+++ b/qa/qa/page/component/wiki_page_form.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module WikiPageForm
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/views/shared/wikis/_form.html.haml' do
+ element :wiki_title_textbox
+ element :wiki_content_textarea
+ element :wiki_message_textbox
+ element :save_changes_button
+ element :create_page_button
+ end
+
+ base.view 'app/assets/javascripts/pages/shared/wikis/components/delete_wiki_modal.vue' do
+ element :delete_button
+ end
+ end
+
+ def set_title(title)
+ fill_element(:wiki_title_textbox, title)
+ end
+
+ def set_content(content)
+ fill_element(:wiki_content_textarea, content)
+ end
+
+ def set_message(message)
+ fill_element(:wiki_message_textbox, message)
+ end
+
+ def click_save_changes
+ click_element(:save_changes_button)
+ end
+
+ def click_create_page
+ click_element(:create_page_button)
+ end
+
+ def delete_page
+ click_element(:delete_button, Page::Modal::DeleteWiki)
+ Page::Modal::DeleteWiki.perform(&:confirm_deletion)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/component/wiki_sidebar.rb b/qa/qa/page/component/wiki_sidebar.rb
new file mode 100644
index 00000000000..dfb912a1d0b
--- /dev/null
+++ b/qa/qa/page/component/wiki_sidebar.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module WikiSidebar
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/views/shared/wikis/_sidebar.html.haml' do
+ element :clone_repository_link
+ element :view_all_pages_button
+ end
+
+ base.view 'app/views/shared/wikis/_sidebar_wiki_page.html.haml' do
+ element :wiki_page_link
+ end
+
+ base.view 'app/views/shared/wikis/_wiki_directory.html.haml' do
+ element :wiki_directory_content
+ end
+ end
+
+ def click_clone_repository
+ click_element(:clone_repository_link)
+ end
+
+ def click_view_all_pages
+ click_element(:view_all_pages_button)
+ end
+
+ def click_page_link(page_title)
+ click_element(:wiki_page_link, page_name: page_title)
+ end
+
+ def has_page_listed?(page_title)
+ has_element?(:wiki_page_link, page_name: page_title)
+ end
+
+ def has_directory?(directory)
+ has_element?(:wiki_directory_content, text: directory)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/dashboard/snippet/edit.rb b/qa/qa/page/dashboard/snippet/edit.rb
index 40add146e97..cd8ac77ae04 100644
--- a/qa/qa/page/dashboard/snippet/edit.rb
+++ b/qa/qa/page/dashboard/snippet/edit.rb
@@ -18,13 +18,17 @@ module QA
element :delete_file_button
end
+ view 'app/assets/javascripts/snippets/components/snippet_visibility_edit.vue' do
+ element :visibility_content
+ end
+
def add_to_file_content(content)
text_area.set content
text_area.has_text?(content) # wait for changes to take effect
end
def change_visibility_to(visibility_type)
- choose(visibility_type)
+ click_element(:visibility_content, visibility: visibility_type)
end
def click_add_file
diff --git a/qa/qa/page/group/members.rb b/qa/qa/page/group/members.rb
index 87423ae9d75..68a169d5a7f 100644
--- a/qa/qa/page/group/members.rb
+++ b/qa/qa/page/group/members.rb
@@ -4,18 +4,13 @@ module QA
module Page
module Group
class Members < Page::Base
- include QA::Page::Component::Select2
+ include Page::Component::InviteMembersModal
include Page::Component::UsersSelect
view 'app/assets/javascripts/vue_shared/components/remove_member_modal.vue' do
element :remove_member_modal_content
end
- view 'app/views/shared/members/_invite_member.html.haml' do
- element :member_select_field
- element :invite_member_button
- end
-
view 'app/assets/javascripts/pages/groups/group_members/index.js' do
element :member_row
element :groups_list
@@ -32,31 +27,9 @@ module QA
end
view 'app/views/groups/group_members/index.html.haml' do
- element :invite_group_tab
element :groups_list_tab
end
- view 'app/views/shared/members/_invite_group.html.haml' do
- element :group_select_field
- element :invite_group_button
- end
-
- def select_group(group_name)
- click_element :group_select_field
- search_and_select(group_name)
- end
-
- def invite_group(group_name)
- click_element :invite_group_tab
- select_group(group_name)
- click_element :invite_group_button
- end
-
- def add_member(username)
- select_user :member_select_field, username
- click_element :invite_member_button
- end
-
def update_access_level(username, access_level)
within_element(:member_row, text: username) do
click_element :access_level_dropdown
diff --git a/qa/qa/page/group/menu.rb b/qa/qa/page/group/menu.rb
index 7689dd7e5c8..10c0ee1f0a9 100644
--- a/qa/qa/page/group/menu.rb
+++ b/qa/qa/page/group/menu.rb
@@ -14,6 +14,10 @@ module QA
element :group_settings_item
end
+ view 'app/views/groups/sidebar/_packages_settings.html.haml' do
+ element :group_package_settings_link
+ end
+
view 'app/views/layouts/nav/sidebar/_analytics_links.html.haml' do
element :analytics_link
element :analytics_sidebar_submenu
@@ -55,6 +59,15 @@ module QA
end
end
+ def go_to_package_settings
+ scroll_to_element(:group_settings_item)
+ hover_element(:group_settings_item) do
+ within_submenu(:group_sidebar_submenu) do
+ click_element(:group_package_settings_link)
+ end
+ end
+ end
+
private
def hover_issues
diff --git a/qa/qa/page/group/settings/general.rb b/qa/qa/page/group/settings/general.rb
index 8f5267c3362..ced8bd5c812 100644
--- a/qa/qa/page/group/settings/general.rb
+++ b/qa/qa/page/group/settings/general.rb
@@ -54,57 +54,57 @@ module QA
end
def set_lfs_enabled
- expand_content :permission_lfs_2fa_content
- check_element :lfs_checkbox
- click_element :save_permissions_changes_button
+ expand_content(:permission_lfs_2fa_content)
+ check_element(:lfs_checkbox)
+ click_element(:save_permissions_changes_button)
end
def set_lfs_disabled
- expand_content :permission_lfs_2fa_content
- uncheck_element :lfs_checkbox
- click_element :save_permissions_changes_button
+ expand_content(:permission_lfs_2fa_content)
+ uncheck_element(:lfs_checkbox)
+ click_element(:save_permissions_changes_button)
end
def set_request_access_enabled
- expand_content :permission_lfs_2fa_content
- check_element :request_access_checkbox
- click_element :save_permissions_changes_button
+ expand_content(:permission_lfs_2fa_content)
+ check_element(:request_access_checkbox)
+ click_element(:save_permissions_changes_button)
end
def set_request_access_disabled
- expand_content :permission_lfs_2fa_content
- uncheck_element :request_access_checkbox
- click_element :save_permissions_changes_button
+ expand_content(:permission_lfs_2fa_content)
+ uncheck_element(:request_access_checkbox)
+ click_element(:save_permissions_changes_button)
end
def set_require_2fa_enabled
- expand_content :permission_lfs_2fa_content
- check_element :require_2fa_checkbox
- click_element :save_permissions_changes_button
+ expand_content(:permission_lfs_2fa_content)
+ check_element(:require_2fa_checkbox)
+ click_element(:save_permissions_changes_button)
end
def set_require_2fa_disabled
- expand_content :permission_lfs_2fa_content
- uncheck_element :require_2fa_checkbox
- click_element :save_permissions_changes_button
+ expand_content(:permission_lfs_2fa_content)
+ uncheck_element(:require_2fa_checkbox)
+ click_element(:save_permissions_changes_button)
end
def set_project_creation_level(value)
- expand_content :permission_lfs_2fa_content
+ expand_content(:permission_lfs_2fa_content)
select_element(:project_creation_level_dropdown, value)
- click_element :save_permissions_changes_button
+ click_element(:save_permissions_changes_button)
end
def toggle_request_access
- expand_content :permission_lfs_2fa_content
+ expand_content(:permission_lfs_2fa_content)
if find_element(:request_access_checkbox).checked?
- uncheck_element :request_access_checkbox
+ uncheck_element(:request_access_checkbox)
else
- check_element :request_access_checkbox
+ check_element(:request_access_checkbox)
end
- click_element :save_permissions_changes_button
+ click_element(:save_permissions_changes_button)
end
end
end
diff --git a/qa/qa/page/group/settings/package_registries.rb b/qa/qa/page/group/settings/package_registries.rb
new file mode 100644
index 00000000000..ee5ca849a47
--- /dev/null
+++ b/qa/qa/page/group/settings/package_registries.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module Settings
+ class PackageRegistries < QA::Page::Base
+ include ::QA::Page::Settings::Common
+
+ view 'app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue' do
+ element :package_registry_settings_content
+ end
+
+ view 'app/assets/javascripts/packages_and_registries/settings/group/components/maven_settings.vue' do
+ element :allow_duplicates_toggle
+ element :allow_duplicates_label
+ end
+
+ def set_allow_duplicates_disabled
+ expand_content :package_registry_settings_content do
+ click_element(:allow_duplicates_toggle) if duplicates_enabled?
+ end
+ end
+
+ def set_allow_duplicates_enabled
+ expand_content :package_registry_settings_content do
+ click_element(:allow_duplicates_toggle) if duplicates_disabled?
+ end
+ end
+
+ def duplicates_enabled?
+ has_element?(:allow_duplicates_label, text: 'Allow duplicates')
+ end
+
+ def duplicates_disabled?
+ has_element?(:allow_duplicates_label, text: 'Do not allow duplicates')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb
index 265e2b7573c..048119d65cb 100644
--- a/qa/qa/page/main/login.rb
+++ b/qa/qa/page/main/login.rb
@@ -52,7 +52,7 @@ module QA
using_wait_time 0 do
set_initial_password_if_present
- raise NotImplementedError if Runtime::User.ldap_user? && user&.credentials_given?
+ raise 'If an LDAP user is provided, it must be used for sign-in', QA::Resource::User::InvalidUserError if Runtime::User.ldap_user? && user && user.username != Runtime::User.ldap_username
if Runtime::User.ldap_user?
sign_in_using_ldap_credentials(user: user || Runtime::User)
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index 18676807fd6..0b6a3085a3a 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -9,8 +9,8 @@ module QA
view 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue' do
element :download_dropdown
- element :download_email_patches
- element :download_plain_diff
+ element :download_email_patches_menu_item
+ element :download_plain_diff_menu_item
element :open_in_web_ide_button
end
@@ -21,9 +21,13 @@ module QA
view 'app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue' do
element :merge_button
- element :fast_forward_message, 'Fast-forward merge without a merge commit' # rubocop:disable QA/ElementWithPattern
+ element :fast_forward_message_content
element :merge_moment_dropdown
- element :merge_immediately_option
+ element :merge_immediately_menu_item
+ end
+
+ view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue' do
+ element :merge_request_status_content
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue' do
@@ -36,7 +40,7 @@ module QA
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue' do
element :mr_rebase_button
- element :no_fast_forward_message, 'Fast-forward merge is not possible' # rubocop:disable QA/ElementWithPattern
+ element :no_fast_forward_message_content
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue' do
@@ -64,7 +68,8 @@ module QA
end
view 'app/assets/javascripts/diffs/components/inline_diff_table_row.vue' do
- element :new_diff_line
+ element :diff_comment_button
+ element :new_diff_line_link
end
view 'app/views/projects/merge_requests/_mr_title.html.haml' do
@@ -72,11 +77,11 @@ module QA
end
view 'app/assets/javascripts/batch_comments/components/publish_button.vue' do
- element :submit_review
+ element :submit_review_button
end
view 'app/assets/javascripts/batch_comments/components/review_bar.vue' do
- element :review_bar
+ element :review_bar_content
end
view 'app/assets/javascripts/notes/components/note_form.vue' do
@@ -124,18 +129,18 @@ module QA
end
def submit_pending_reviews
- within_element(:review_bar) do
+ within_element(:review_bar_content) do
click_element(:review_preview_toggle)
- click_element(:submit_review)
+ click_element(:submit_review_button)
# After clicking the button, wait for it to disappear
# before moving on to the next part of the test
- has_no_element?(:submit_review)
+ has_no_element?(:submit_review_button)
end
end
def discard_pending_reviews
- within_element(:review_bar) do
+ within_element(:review_bar_content) do
click_element(:discard_review)
end
click_element(:modal_delete_pending_comments)
@@ -154,8 +159,8 @@ module QA
wait_until(sleep_interval: 5) do
has_css?('a[data-linenumber="1"]')
end
- all_elements(:new_diff_line, minimum: 1).first.hover
- click_element(:diff_comment)
+ all_elements(:new_diff_line_link, minimum: 1).first.hover
+ click_element(:diff_comment_button)
fill_element(:reply_field, text)
end
@@ -179,7 +184,11 @@ module QA
end
def fast_forward_possible?
- has_no_text?('Fast-forward merge is not possible')
+ has_element?(:fast_forward_message_content)
+ end
+
+ def fast_forward_not_possible?
+ has_element?(:no_fast_forward_message_content)
end
def has_file?(file_name)
@@ -220,12 +229,12 @@ module QA
!find_element(:squash_checkbox).disabled?
end
+ # TODO: Fix workaround for data-qa-selector failure
click_element(:squash_checkbox)
end
def merge!
- wait_until_ready_to_merge
- click_element(:merge_button)
+ try_to_merge!
finished_loading?
raise "Merge did not appear to be successful" unless merged?
@@ -233,11 +242,21 @@ module QA
def merge_immediately!
click_element(:merge_moment_dropdown)
- click_element(:merge_immediately_option)
+ click_element(:merge_immediately_menu_item)
+ end
+
+ def merge_when_pipeline_succeeds!
+ wait_until_ready_to_merge
+
+ click_element(:merge_button, text: 'Merge when pipeline succeeds')
end
def merged?
- has_element?(:merged_status_content, text: 'The changes were merged into', wait: 60)
+ # Revisit after merge page re-architect is done https://gitlab.com/gitlab-org/gitlab/-/issues/300042
+ # To remove page refresh logic if possible
+ retry_until(max_attempts: 3, reload: true) do
+ has_element?(:merged_status_content, text: 'The changes were merged into', wait: 20)
+ end
end
# Check if the MR is able to be merged
@@ -249,6 +268,10 @@ module QA
has_element?(:merge_button, disabled: false)
end
+ def merge_request_status
+ find_element(:merge_request_status_content).text
+ end
+
# Waits up 60 seconds and raises an error if unable to merge
def wait_until_ready_to_merge
has_element?(:merge_button)
@@ -273,26 +296,29 @@ module QA
click_element(:mr_rebase_button)
success = wait_until do
- has_text?('Fast-forward merge without a merge commit')
+ fast_forward_possible?
end
raise "Rebase did not appear to be successful" unless success
end
def try_to_merge!
+ # Revisit after merge page re-architect is done https://gitlab.com/gitlab-org/gitlab/-/issues/300042
+ # To remove page refresh logic if possible
wait_until_ready_to_merge
+ wait_until { !find_element(:merge_button).has_text?("when pipeline succeeds") }
click_element(:merge_button)
end
def view_email_patches
click_element(:download_dropdown)
- visit_link_in_element(:download_email_patches)
+ visit_link_in_element(:download_email_patches_menu_item)
end
def view_plain_diff
click_element(:download_dropdown)
- visit_link_in_element(:download_plain_diff)
+ visit_link_in_element(:download_plain_diff_menu_item)
end
def wait_for_merge_request_error_message
@@ -315,7 +341,7 @@ module QA
def add_suggestion_to_diff(suggestion, line)
find("a[data-linenumber='#{line}']").hover
- click_element(:diff_comment)
+ click_element(:diff_comment_button)
click_element(:suggestion_button)
initial_content = find_element(:reply_field).value
fill_element(:reply_field, '')
diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb
index 6890c7de9f8..58c82fa14c1 100644
--- a/qa/qa/page/project/import/github.rb
+++ b/qa/qa/page/project/import/github.rb
@@ -17,28 +17,34 @@ module QA
element :project_namespace_select
element :project_path_field
element :import_button
+ element :project_path_content
+ element :go_to_project_button
end
def add_personal_access_token(personal_access_token)
+ # If for some reasons this process is retried, user cannot re-enter github token in the same group
+ # In this case skip this step and proceed to import project row
+ return unless has_element?(:personal_access_token_field)
+
fill_element(:personal_access_token_field, personal_access_token)
click_element(:authenticate_button)
finished_loading?
end
def import!(full_path, name)
- choose_test_namespace(full_path)
- set_path(full_path, name)
- import_project(full_path)
- wait_for_success
+ unless already_imported(full_path)
+ choose_test_namespace(full_path)
+ set_path(full_path, name)
+ import_project(full_path)
+ wait_for_success
+ end
+
+ go_to_project(name)
end
private
def within_repo_path(full_path)
- wait_until(reload: false) do
- has_element?(:project_import_row, text: full_path)
- end
-
project_import_row = find_element(:project_import_row, text: full_path)
within(project_import_row) do
@@ -68,9 +74,22 @@ module QA
def wait_for_success
# TODO: set reload:false and remove skip_finished_loading_check_on_refresh when
- # https://gitlab.com/gitlab-org/gitlab/-/issues/231542 is fixed
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/292861 is fixed
wait_until(max_duration: 60, sleep_interval: 5.0, reload: true, skip_finished_loading_check_on_refresh: true) do
- page.has_content?('Done', wait: 1.0)
+ page.has_no_content?('Importing 1 repository', wait: 3.0)
+ end
+ end
+
+ def go_to_project(name)
+ Page::Main::Menu.perform(&:go_to_projects)
+ Page::Dashboard::Projects.perform do |dashboard|
+ dashboard.go_to_project(name)
+ end
+ end
+
+ def already_imported(full_path)
+ within_repo_path(full_path) do
+ has_element?(:project_path_content) && has_element?(:go_to_project_button)
end
end
end
diff --git a/qa/qa/page/project/issue/index.rb b/qa/qa/page/project/issue/index.rb
index e85d10e4eb8..10ddd52719a 100644
--- a/qa/qa/page/project/issue/index.rb
+++ b/qa/qa/page/project/issue/index.rb
@@ -15,18 +15,14 @@ module QA
element :avatar_counter_content
end
- view 'app/views/shared/issuable/csv_export/_button.html.haml' do
- element :export_as_csv_button
- end
-
- view 'app/views/shared/issuable/csv_export/_modal.html.haml' do
- element :export_issues_button
+ view 'app/assets/javascripts/issuable/components/csv_export_modal.vue' do
element :export_issuable_modal
end
- view 'app/views/projects/issues/import_csv/_button.html.haml' do
- element :import_issues_button
+ view 'app/assets/javascripts/issuable/components/csv_import_export_buttons.vue' do
+ element :export_as_csv_button
element :import_from_jira_link
+ element :import_issues_dropdown
end
view 'app/views/shared/issuable/_nav.html.haml' do
@@ -60,7 +56,7 @@ module QA
def click_import_issues_dropdown
# When there are no issues, the image that loads causes the buttons to jump
has_loaded_all_images?
- click_element(:import_issues_button)
+ click_element(:import_issues_dropdown)
end
def export_issues_modal
diff --git a/qa/qa/page/project/members.rb b/qa/qa/page/project/members.rb
index 7e722e02ad0..09264d95aed 100644
--- a/qa/qa/page/project/members.rb
+++ b/qa/qa/page/project/members.rb
@@ -4,21 +4,18 @@ module QA
module Page
module Project
class Members < Page::Base
- include QA::Page::Component::Select2
-
- view 'app/views/shared/members/_invite_member.html.haml' do
- element :member_select_field
- element :invite_member_button
- end
+ include QA::Page::Component::InviteMembersModal
view 'app/views/projects/project_members/index.html.haml' do
- element :invite_group_tab
element :groups_list_tab
end
- view 'app/views/shared/members/_invite_group.html.haml' do
- element :group_select_field
- element :invite_group_button
+ view 'app/assets/javascripts/invite_members/components/invite_group_trigger.vue' do
+ element :invite_a_group_button
+ end
+
+ view 'app/assets/javascripts/invite_members/components/invite_members_trigger.vue' do
+ element :invite_members_button
end
view 'app/assets/javascripts/pages/projects/project_members/index.js' do
@@ -33,25 +30,7 @@ module QA
element :remove_group_link_modal_content
end
- def select_group(group_name)
- click_element :group_select_field
- search_and_select(group_name)
- end
-
- def invite_group(group_name)
- click_element :invite_group_tab
- select_group(group_name)
- click_element :invite_group_button
- end
-
- def add_member(username)
- click_element :member_select_field
- search_and_select username
- click_element :invite_member_button
- end
-
def remove_group(group_name)
- click_element :invite_group_tab
click_element :groups_list_tab
within_element(:group_row, text: group_name) do
diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb
index 7e296528795..d1033dbfca9 100644
--- a/qa/qa/page/project/new.rb
+++ b/qa/qa/page/project/new.rb
@@ -68,7 +68,7 @@ module QA
end
def enable_initialize_with_readme
- check_element :initialize_with_readme_checkbox
+ check_element(:initialize_with_readme_checkbox)
end
end
end
diff --git a/qa/qa/page/project/operations/kubernetes/add_existing.rb b/qa/qa/page/project/operations/kubernetes/add_existing.rb
index 1b9a451c47d..59f59ca9966 100644
--- a/qa/qa/page/project/operations/kubernetes/add_existing.rb
+++ b/qa/qa/page/project/operations/kubernetes/add_existing.rb
@@ -36,7 +36,7 @@ module QA
end
def uncheck_rbac!
- uncheck_element :rbac_checkbox
+ uncheck_element(:rbac_checkbox)
end
end
end
diff --git a/qa/qa/page/project/operations/kubernetes/index.rb b/qa/qa/page/project/operations/kubernetes/index.rb
index 114e3ddd46a..ca41dddaca2 100644
--- a/qa/qa/page/project/operations/kubernetes/index.rb
+++ b/qa/qa/page/project/operations/kubernetes/index.rb
@@ -7,11 +7,11 @@ module QA
module Kubernetes
class Index < Page::Base
view 'app/views/clusters/clusters/_empty_state.html.haml' do
- element :add_kubernetes_cluster_button, "link_to s_('ClusterIntegration|Integrate with a cluster certificate')" # rubocop:disable QA/ElementWithPattern
+ element :add_kubernetes_cluster_link
end
def add_kubernetes_cluster
- click_on 'Connect cluster with certificate'
+ click_element :add_kubernetes_cluster_link
end
def has_cluster?(cluster)
diff --git a/qa/qa/page/project/registry/show.rb b/qa/qa/page/project/registry/show.rb
new file mode 100644
index 00000000000..dffdb9eebba
--- /dev/null
+++ b/qa/qa/page/project/registry/show.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Registry
+ class Show < QA::Page::Base
+ view 'app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue' do
+ element :registry_image_content
+ end
+
+ view 'app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue' do
+ element :tag_delete_button
+ end
+
+ def has_registry_repository?(name)
+ find_element(:registry_image_content, text: name)
+ end
+
+ def click_on_image(name)
+ click_element(:registry_image_content, text: name)
+ end
+
+ def has_tag?(tag_name)
+ has_button?(tag_name)
+ end
+
+ def has_no_tag?(tag_name)
+ has_no_button?(tag_name)
+ end
+
+ def click_delete
+ click_element(:tag_delete_button)
+ find_button('Confirm').click
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/settings/auto_devops.rb b/qa/qa/page/project/settings/auto_devops.rb
index 827d5b072c3..9dffa010805 100644
--- a/qa/qa/page/project/settings/auto_devops.rb
+++ b/qa/qa/page/project/settings/auto_devops.rb
@@ -11,8 +11,8 @@ module QA
end
def enable_autodevops
- check_element :enable_autodevops_checkbox
- click_element :save_changes_button
+ check_element(:enable_autodevops_checkbox)
+ click_element(:save_changes_button)
end
end
end
diff --git a/qa/qa/page/project/settings/ci_variables.rb b/qa/qa/page/project/settings/ci_variables.rb
index f2ced668a60..2b8fad64afb 100644
--- a/qa/qa/page/project/settings/ci_variables.rb
+++ b/qa/qa/page/project/settings/ci_variables.rb
@@ -10,7 +10,6 @@ module QA
view 'app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue' do
element :ci_variable_key_field
element :ci_variable_value_field
- element :ci_variable_masked_checkbox
element :ci_variable_save_button
element :ci_variable_delete_button
end
diff --git a/qa/qa/page/project/settings/incidents.rb b/qa/qa/page/project/settings/incidents.rb
index 9b523e2aa9e..610129851d9 100644
--- a/qa/qa/page/project/settings/incidents.rb
+++ b/qa/qa/page/project/settings/incidents.rb
@@ -13,7 +13,7 @@ module QA
end
def enable_issues_for_incidents
- check_element :create_issue_checkbox
+ check_element(:create_issue_checkbox)
end
def select_issue_template(template)
diff --git a/qa/qa/page/project/settings/main.rb b/qa/qa/page/project/settings/main.rb
index 4db66543a25..48af635bb79 100644
--- a/qa/qa/page/project/settings/main.rb
+++ b/qa/qa/page/project/settings/main.rb
@@ -11,8 +11,9 @@ module QA
include Component::Breadcrumbs
view 'app/views/projects/edit.html.haml' do
- element :advanced_settings
- element :merge_request_settings
+ element :advanced_settings_content
+ element :merge_request_settings_content
+ element :visibility_features_permissions_content
end
view 'app/views/projects/settings/_general.html.haml' do
@@ -20,10 +21,6 @@ module QA
element :save_naming_topics_avatar_button
end
- view 'app/views/projects/edit.html.haml' do
- element :visibility_features_permissions_content
- end
-
def rename_project_to(name)
fill_project_name(name)
click_save_changes
@@ -38,13 +35,13 @@ module QA
end
def expand_advanced_settings(&block)
- expand_content(:advanced_settings) do
+ expand_content(:advanced_settings_content) do
Advanced.perform(&block)
end
end
def expand_merge_requests_settings(&block)
- expand_content(:merge_request_settings) do
+ expand_content(:merge_request_settings_content) do
MergeRequest.perform(&block)
end
end
diff --git a/qa/qa/page/project/settings/merge_request.rb b/qa/qa/page/project/settings/merge_request.rb
index ec8d73df1b3..fe5d629effe 100644
--- a/qa/qa/page/project/settings/merge_request.rb
+++ b/qa/qa/page/project/settings/merge_request.rb
@@ -8,11 +8,11 @@ module QA
include QA::Page::Settings::Common
view 'app/views/projects/edit.html.haml' do
- element :save_merge_request_changes
+ element :save_merge_request_changes_button
end
view 'app/views/projects/_merge_request_merge_method_settings.html.haml' do
- element :radio_button_merge_ff
+ element :merge_ff_radio_button
end
view 'app/views/projects/_merge_request_merge_checks_settings.html.haml' do
@@ -20,16 +20,16 @@ module QA
end
def click_save_changes
- click_element :save_merge_request_changes
+ click_element :save_merge_request_changes_button
end
def enable_ff_only
- click_element :radio_button_merge_ff
+ click_element :merge_ff_radio_button
click_save_changes
end
def enable_merge_if_all_disscussions_are_resolved
- click_element :allow_merge_if_all_discussions_are_resolved_checkbox
+ check_element(:allow_merge_if_all_discussions_are_resolved_checkbox)
click_save_changes
end
end
diff --git a/qa/qa/page/project/sub_menus/packages.rb b/qa/qa/page/project/sub_menus/packages.rb
index 9ea045a99f5..46eae01e10d 100644
--- a/qa/qa/page/project/sub_menus/packages.rb
+++ b/qa/qa/page/project/sub_menus/packages.rb
@@ -22,6 +22,25 @@ module QA
click_element :packages_link
end
end
+
+ def go_to_container_registry
+ hover_registry do
+ within_submenu do
+ click_link('Container Registry')
+ end
+ end
+ end
+
+ private
+
+ def hover_registry
+ within_sidebar do
+ scroll_to_element(:packages_link)
+ find_element(:packages_link).hover
+
+ yield
+ end
+ end
end
end
end
diff --git a/qa/qa/page/project/sub_menus/settings.rb b/qa/qa/page/project/sub_menus/settings.rb
index 47274c8db54..b5058bacccd 100644
--- a/qa/qa/page/project/sub_menus/settings.rb
+++ b/qa/qa/page/project/sub_menus/settings.rb
@@ -25,7 +25,7 @@ module QA
def go_to_ci_cd_settings
hover_settings do
within_submenu do
- click_link('CI / CD')
+ click_link('CI/CD')
end
end
end
diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb
index 45c46004790..fd68ac0de16 100644
--- a/qa/qa/page/project/web_ide/edit.rb
+++ b/qa/qa/page/project/web_ide/edit.rb
@@ -44,10 +44,6 @@ module QA
element :commit_button
end
- view 'app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue' do
- element :start_new_mr_checkbox
- end
-
view 'app/assets/javascripts/ide/components/repo_editor.vue' do
element :editor_container
end
diff --git a/qa/qa/page/project/wiki/edit.rb b/qa/qa/page/project/wiki/edit.rb
index 6f3be904eb3..70aa10cc43e 100644
--- a/qa/qa/page/project/wiki/edit.rb
+++ b/qa/qa/page/project/wiki/edit.rb
@@ -5,44 +5,8 @@ module QA
module Project
module Wiki
class Edit < Base
- include Wiki::Sidebar
-
- view 'app/views/shared/wikis/_form.html.haml' do
- element :wiki_title_textbox
- element :wiki_content_textarea
- element :wiki_message_textbox
- element :save_changes_button
- element :create_page_button
- end
-
- view 'app/assets/javascripts/pages/shared/wikis/components/delete_wiki_modal.vue' do
- element :delete_button
- end
-
- def set_title(title)
- fill_element :wiki_title_textbox, title
- end
-
- def set_content(content)
- fill_element :wiki_content_textarea, content
- end
-
- def set_message(message)
- fill_element :wiki_message_textbox, message
- end
-
- def click_save_changes
- click_element :save_changes_button
- end
-
- def click_create_page
- click_element :create_page_button
- end
-
- def delete_page
- click_element :delete_button, Page::Modal::DeleteWiki
- Page::Modal::DeleteWiki.perform(&:confirm_deletion)
- end
+ include Page::Component::WikiPageForm
+ include Page::Component::WikiSidebar
end
end
end
diff --git a/qa/qa/page/project/wiki/show.rb b/qa/qa/page/project/wiki/show.rb
index d9e0783a581..f3573e3cdd3 100644
--- a/qa/qa/page/project/wiki/show.rb
+++ b/qa/qa/page/project/wiki/show.rb
@@ -5,67 +5,9 @@ module QA
module Project
module Wiki
class Show < Base
- include Wiki::Sidebar
- include Component::LazyLoader
-
- view 'app/views/shared/wikis/show.html.haml' do
- element :wiki_page_title
- element :wiki_page_content
- element :edit_page_button
- end
-
- view 'app/views/shared/wikis/_main_links.html.haml' do
- element :new_page_button
- element :page_history_button
- end
-
- view 'app/views/shared/empty_states/_wikis.html.haml' do
- element :create_first_page_link
- end
-
- view 'app/views/shared/empty_states/_wikis_layout.html.haml' do
- element :svg_content
- end
-
- def click_create_your_first_page
- # The svg takes a fraction of a second to load after which the
- # "Create your first page" button shifts up a bit. This can cause
- # webdriver to miss the hit so we wait for the svg to load before
- # clicking the button.
- within_element(:svg_content) do
- has_element? :js_lazy_loaded
- end
-
- click_element :create_first_page_link
- end
-
- def click_new_page
- click_element(:new_page_button)
- end
-
- def click_page_history
- click_element(:page_history_button)
- end
-
- def click_edit
- click_element(:edit_page_button)
- end
-
- def has_title?(title)
- has_element?(:wiki_page_title, title)
- end
-
- def has_content?(content)
- has_element?(:wiki_page_content, content)
- end
-
- def has_no_content?(content)
- has_no_element?(:wiki_page_content, content)
- end
-
- def has_no_page?
- has_element? :create_first_page_link
- end
+ include Page::Component::Wiki
+ include Page::Component::WikiSidebar
+ include Page::Component::LazyLoader
end
end
end
diff --git a/qa/qa/page/project/wiki/sidebar.rb b/qa/qa/page/project/wiki/sidebar.rb
deleted file mode 100644
index 3e1edcbbefb..00000000000
--- a/qa/qa/page/project/wiki/sidebar.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module Wiki
- module Sidebar
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.view 'app/views/shared/wikis/_sidebar.html.haml' do
- element :clone_repository_link
- element :view_all_pages_button
- end
-
- base.view 'app/views/shared/wikis/_sidebar_wiki_page.html.haml' do
- element :wiki_page_link
- end
-
- base.view 'app/views/shared/wikis/_wiki_directory.html.haml' do
- element :wiki_directory_content
- end
- end
-
- def click_clone_repository
- click_element(:clone_repository_link)
- end
-
- def click_view_all_pages
- click_element(:view_all_pages_button)
- end
-
- def click_page_link(page_title)
- click_element :wiki_page_link, page_name: page_title
- end
-
- def has_page_listed?(page_title)
- has_element? :wiki_page_link, page_name: page_title
- end
-
- def has_directory?(directory)
- has_element? :wiki_directory_content, text: directory
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/resource/clusters/agent_token.rb b/qa/qa/resource/clusters/agent_token.rb
index 6a5e861b650..3286f46cdb2 100644
--- a/qa/qa/resource/clusters/agent_token.rb
+++ b/qa/qa/resource/clusters/agent_token.rb
@@ -32,7 +32,7 @@ module QA
def api_post_body
<<~GQL
mutation createToken {
- clusterAgentTokenCreate(input: { clusterAgentId: "gid://gitlab/Clusters::Agent/#{agent.id}" }) {
+ clusterAgentTokenCreate(input: { clusterAgentId: "gid://gitlab/Clusters::Agent/#{agent.id}" name: "token-#{agent.id}" }) {
secret # This is the value you need to use on the next step
token {
createdAt
diff --git a/qa/qa/resource/members.rb b/qa/qa/resource/members.rb
index a88980f26d8..c8f9feeca15 100644
--- a/qa/qa/resource/members.rb
+++ b/qa/qa/resource/members.rb
@@ -26,10 +26,23 @@ module QA
JSON.parse(get(Runtime::API::Request.new(api_client, api_members_path).url).body)
end
+ def invite_group(group, access_level = AccessLevel::GUEST)
+ Support::Retrier.retry_until do
+ QA::Runtime::Logger.debug(%Q[Sharing #{self.class.name} with #{group.name}])
+
+ response = post Runtime::API::Request.new(api_client, api_share_path).url, { group_id: group.id, group_access: access_level }
+ response.code == QA::Support::Api::HTTP_STATUS_CREATED
+ end
+ end
+
def api_members_path
"#{api_get_path}/members"
end
+ def api_share_path
+ "#{api_get_path}/share"
+ end
+
class AccessLevel
NO_ACCESS = 0
MINIMAL_ACCESS = 5
diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb
index fd5f454f134..fb450a61c9a 100644
--- a/qa/qa/resource/merge_request.rb
+++ b/qa/qa/resource/merge_request.rb
@@ -75,7 +75,7 @@ module QA
Page::MergeRequest::New.perform do |new_page|
new_page.fill_title(@title)
new_page.choose_template(@template) if @template
- new_page.fill_description(@description) unless @template
+ new_page.fill_description(@description) if @description && !@template
new_page.choose_milestone(@milestone) if @milestone
new_page.assign_to_me if @assignee == 'me'
labels.each do |label|
@@ -140,6 +140,14 @@ module QA
end
end
+ def reload!
+ # Refabricate so that we can return a new object with updated attributes
+ self.class.fabricate_via_api! do |resource|
+ resource.project = project
+ resource.id = api_resource[:iid]
+ end
+ end
+
private
def transform_api_resource(api_resource)
diff --git a/qa/qa/resource/personal_access_token.rb b/qa/qa/resource/personal_access_token.rb
index 6b2301ba916..59ae8f4de7a 100644
--- a/qa/qa/resource/personal_access_token.rb
+++ b/qa/qa/resource/personal_access_token.rb
@@ -4,17 +4,59 @@ require 'date'
module QA
module Resource
- ##
- # Create a personal access token that can be used by the api
- #
class PersonalAccessToken < Base
attr_accessor :name
- attribute :access_token do
+ # The user for which the personal access token is to be created
+ # This *could* be different than the api_client.user or the api_user provided by the QA::Resource::ApiFabricator module
+ attr_writer :user
+
+ attribute :token do
Page::Profile::PersonalAccessTokens.perform(&:created_access_token)
end
+ # Only Admins can create PAT via the API.
+ # If Runtime::Env.admin_personal_access_token is provided, fabricate via the API,
+ # else, fabricate via the browser.
+ def fabricate_via_api!
+ if Runtime::Env.admin_personal_access_token && !@user.nil?
+ self.api_client = Runtime::API::Client.as_admin
+
+ super
+ else
+ fabricate!
+ end
+ end
+
+ # When a user is not provided, use default user
+ def user
+ @user || Resource::User.default
+ end
+
+ def api_post_path
+ "/users/#{user.api_resource[:id]}/personal_access_tokens"
+ end
+
+ def api_get_path
+ '/personal_access_tokens'
+ end
+
+ def api_post_body
+ {
+ name: name || 'api-test-token',
+ scopes: ["api"]
+ }
+ end
+
+ def resource_web_url(resource)
+ super
+ rescue ResourceURLMissingError
+ # this particular resource does not expose a web_url property
+ end
+
def fabricate!
+ Flow::Login.sign_in_unless_signed_in(as: user)
+
Page::Main::Menu.perform(&:click_edit_profile_link)
Page::Profile::Menu.perform(&:click_access_tokens)
@@ -22,7 +64,7 @@ module QA
token_page.fill_token_name(name || 'api-test-token')
token_page.check_api
# Expire in 2 days just in case the token is created just before midnight
- token_page.fill_expiry_date(Date.today + 2)
+ token_page.fill_expiry_date(Time.now.utc.to_date + 2)
token_page.click_create_token_button
end
end
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index efb6c2c0591..23e2ec07491 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -151,6 +151,10 @@ module QA
"#{api_get_path}/runners"
end
+ def api_registry_repositories_path
+ "#{api_get_path}/registry/repositories"
+ end
+
def api_commits_path
"#{api_get_path}/repository/commits"
end
@@ -256,6 +260,12 @@ module QA
parse_body(response)
end
+ def registry_repositories
+ response = get Runtime::API::Request.new(api_client, "#{api_registry_repositories_path}").url
+
+ parse_body(response)
+ end
+
def repository_branches
parse_body(get(Runtime::API::Request.new(api_client, api_repository_branches_path).url))
end
@@ -272,10 +282,6 @@ module QA
parse_body(get(Runtime::API::Request.new(api_client, api_pipelines_path).url))
end
- def share_with_group(invitee, access_level = Resource::Members::AccessLevel::DEVELOPER)
- post Runtime::API::Request.new(api_client, "/projects/#{id}/share").url, { group_id: invitee.id, group_access: access_level }
- end
-
private
def transform_api_resource(api_resource)
diff --git a/qa/qa/resource/project_imported_from_github.rb b/qa/qa/resource/project_imported_from_github.rb
index 0b817b345fd..b06a7fe4e3d 100644
--- a/qa/qa/resource/project_imported_from_github.rb
+++ b/qa/qa/resource/project_imported_from_github.rb
@@ -12,7 +12,7 @@ module QA
group.visit!
Page::Group::Show.perform(&:go_to_new_project)
- go_to_import_tab
+ go_to_import_page
Page::Project::New.perform(&:click_github_link)
Page::Project::Import::Github.perform do |import_page|
@@ -21,7 +21,7 @@ module QA
end
end
- def go_to_import_tab
+ def go_to_import_page
Page::Project::New.perform(&:click_import_project)
end
end
diff --git a/qa/qa/resource/project_snippet.rb b/qa/qa/resource/project_snippet.rb
index c262499664e..9ab4612d117 100644
--- a/qa/qa/resource/project_snippet.rb
+++ b/qa/qa/resource/project_snippet.rb
@@ -33,12 +33,16 @@ module QA
end
def api_get_path
- "/projects/#{project.id}/snippets/#{snippet_id}"
+ "/projects/#{project.id}/snippets/#{id}"
end
def api_post_path
"/projects/#{project.id}/snippets"
end
+
+ def api_delete_path
+ "/projects/#{project.id}/snippets/#{id}"
+ end
end
end
end
diff --git a/qa/qa/resource/registry_repository.rb b/qa/qa/resource/registry_repository.rb
new file mode 100644
index 00000000000..1e43d93a784
--- /dev/null
+++ b/qa/qa/resource/registry_repository.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'securerandom'
+
+module QA
+ module Resource
+ class RegistryRepository < Base
+ attr_accessor :name,
+ :repository_id
+
+ attribute :project do
+ Project.fabricate_via_api! do |resource|
+ resource.name = 'project-with-registry'
+ resource.description = 'Project with Registry'
+ end
+ end
+
+ def initialize
+ @name = project.path_with_namespace
+ @repository_id = nil
+ end
+
+ def fabricate!
+ end
+
+ def fabricate_via_api!
+ resource_web_url(api_get)
+ rescue ResourceNotFoundError
+ super
+ end
+
+ def remove_via_api!
+ registry_repositories = project.registry_repositories
+ if registry_repositories && !registry_repositories.empty?
+ this_registry_repository = registry_repositories.find { |registry_repository| registry_repository[:path] == name }
+
+ @repository_id = this_registry_repository[:id]
+
+ QA::Runtime::Logger.debug("Deleting registry '#{name}'")
+ super
+ end
+ end
+
+ def api_delete_path
+ "/projects/#{project.id}/registry/repositories/#{@repository_id}"
+ end
+
+ def api_get_path
+ "/projects/#{project.id}/registry/repositories"
+ end
+ end
+ end
+end
diff --git a/qa/qa/resource/snippet.rb b/qa/qa/resource/snippet.rb
index 6fdcb1cd29b..6423dc7a41c 100644
--- a/qa/qa/resource/snippet.rb
+++ b/qa/qa/resource/snippet.rb
@@ -3,7 +3,10 @@
module QA
module Resource
class Snippet < Base
- attr_accessor :title, :description, :file_content, :visibility, :file_name, :snippet_id
+ attr_accessor :title, :description, :file_content, :visibility, :file_name
+
+ attribute :id
+ attribute :http_url_to_repo
def initialize
@title = 'New snippet title'
@@ -44,13 +47,17 @@ module QA
end
def api_get_path
- "/snippets/#{snippet_id}"
+ "/snippets/#{id}"
end
def api_post_path
'/snippets'
end
+ def api_put_path
+ "/snippets/#{id}"
+ end
+
def api_post_body
{
title: title,
@@ -60,12 +67,38 @@ module QA
}
end
+ def api_delete_path
+ "/snippets/#{id}"
+ end
+
def all_file_contents
@files.insert(0, { name: @file_name, content: @file_content })
@files.each do |file|
file[:file_path] = file.delete(:name)
end
end
+
+ def has_file?(file_path)
+ response = get Runtime::API::Request.new(api_client, api_get_path).url
+
+ raise ResourceNotFoundError, "Request returned (#{response.code}): `#{response}`." if response.code == HTTP_STATUS_NOT_FOUND
+
+ file_output = parse_body(response)[:files]
+ file_output.any? { |file| file[:path] == file_path }
+ end
+
+ def change_repository_storage(new_storage)
+ post_body = { destination_storage_name: new_storage }
+ response = post Runtime::API::Request.new(api_client, "/snippets/#{id}/repository_storage_moves").url, post_body
+
+ unless response.code.between?(200, 300)
+ raise ResourceUpdateFailedError, "Could not change repository storage to #{new_storage}. Request returned (#{response.code}): `#{response}`."
+ end
+
+ wait_until(sleep_interval: 1) { Runtime::API::RepositoryStorageMoves.has_status?(self, 'finished', new_storage) }
+ rescue Support::Repeater::RepeaterConditionExceededError
+ raise Runtime::API::RepositoryStorageMoves::RepositoryStorageMovesError, 'Timed out while waiting for the snippet repository storage move to finish'
+ end
end
end
end
diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb
index f95a68918dc..d1a310c7c43 100644
--- a/qa/qa/resource/user.rb
+++ b/qa/qa/resource/user.rb
@@ -5,6 +5,8 @@ require 'securerandom'
module QA
module Resource
class User < Base
+ InvalidUserError = Class.new(RuntimeError)
+
attr_reader :unique_id
attr_writer :username, :password
attr_accessor :admin, :provider, :extern_uid, :expect_fabrication_success
@@ -21,6 +23,13 @@ module QA
@expect_fabrication_success = true
end
+ def self.default
+ Resource::User.new.tap do |user|
+ user.username = Runtime::User.ldap_user? ? Runtime::User.ldap_username : Runtime::User.username
+ user.password = Runtime::User.ldap_user? ? Runtime::User.ldap_password : Runtime::User.password
+ end
+ end
+
def admin?
api_resource&.dig(:is_admin) || false
end
@@ -28,10 +37,12 @@ module QA
def username
@username || "qa-user-#{unique_id}"
end
+ alias_method :ldap_username, :username
def password
@password || 'password'
end
+ alias_method :ldap_password, :password
def name
@name ||= api_resource&.dig(:name) || "QA User #{unique_id}"
@@ -138,8 +149,8 @@ module QA
return {} unless extern_uid && provider
{
- extern_uid: extern_uid,
- provider: provider
+ extern_uid: extern_uid,
+ provider: provider
}
end
diff --git a/qa/qa/resource/wiki/group_page.rb b/qa/qa/resource/wiki/group_page.rb
new file mode 100644
index 00000000000..27150ecf6c7
--- /dev/null
+++ b/qa/qa/resource/wiki/group_page.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'securerandom'
+
+module QA
+ module Resource
+ module Wiki
+ class GroupPage < Base
+ attribute :title
+ attribute :content
+ attribute :slug
+
+ attribute :group do
+ Group.fabricate_via_api! do |group|
+ group.path = "group-with-wiki-#{SecureRandom.hex(8)}"
+ end
+ end
+
+ def initialize
+ @title = 'Home'
+ @content = 'This wiki page is created via API'
+ end
+
+ def resource_web_url(resource)
+ super
+ rescue ResourceURLMissingError
+ "#{group.web_url}/-/wikis/#{slug}"
+ end
+
+ def api_get_path
+ "/groups/#{group.id}/wikis/#{slug}"
+ end
+
+ def api_post_path
+ "/groups/#{group.id}/wikis"
+ end
+
+ def api_post_body
+ {
+ id: group.id,
+ content: content,
+ title: title
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/runtime/api/client.rb b/qa/qa/runtime/api/client.rb
index e4de033c309..4126ff9ff5a 100644
--- a/qa/qa/runtime/api/client.rb
+++ b/qa/qa/runtime/api/client.rb
@@ -23,22 +23,30 @@ module QA
# unless a specific user has been passed
@user.nil? ? Runtime::Env.personal_access_token ||= create_personal_access_token : create_personal_access_token
end
+
+ if @user&.admin?
+ Runtime::Env.admin_personal_access_token = @personal_access_token
+ end
+
+ @personal_access_token
end
def self.as_admin
- if Runtime::Env.admin_personal_access_token
- Runtime::API::Client.new(:gitlab, personal_access_token: Runtime::Env.admin_personal_access_token)
- else
- user = Resource::User.fabricate_via_api! do |user|
- user.username = Runtime::User.admin_username
- user.password = Runtime::User.admin_password
+ @admin_client ||= begin
+ if Runtime::Env.admin_personal_access_token
+ Runtime::API::Client.new(:gitlab, personal_access_token: Runtime::Env.admin_personal_access_token)
+ else
+ user = Resource::User.fabricate_via_api! do |user|
+ user.username = Runtime::User.admin_username
+ user.password = Runtime::User.admin_password
+ end
+
+ unless user.admin?
+ raise AuthorizationError, "User '#{user.username}' is not an administrator."
+ end
+
+ Runtime::API::Client.new(:gitlab, user: user)
end
-
- unless user.admin?
- raise AuthorizationError, "User '#{user.username}' is not an administrator."
- end
-
- Runtime::API::Client.new(:gitlab, user: user)
end
end
@@ -67,9 +75,9 @@ module QA
Page::Main::Menu.perform(&:sign_out) if @is_new_session && signed_in_initially
- Flow::Login.sign_in_unless_signed_in(as: @user)
-
- token = Resource::PersonalAccessToken.fabricate!.access_token
+ token = Resource::PersonalAccessToken.fabricate! do |pat|
+ pat.user = user
+ end.token
# If this is a new session, that tests that follow could fail if they
# try to sign in without starting a new session.
diff --git a/qa/qa/runtime/api/repository_storage_moves.rb b/qa/qa/runtime/api/repository_storage_moves.rb
index d0211d3f66d..5630a9c02c5 100644
--- a/qa/qa/runtime/api/repository_storage_moves.rb
+++ b/qa/qa/runtime/api/repository_storage_moves.rb
@@ -9,9 +9,9 @@ module QA
RepositoryStorageMovesError = Class.new(RuntimeError)
- def has_status?(project, status, destination_storage = Env.additional_repository_storage)
- find_any do |move|
- next unless move[:project][:path_with_namespace] == project.path_with_namespace
+ def has_status?(resource, status, destination_storage = Env.additional_repository_storage)
+ find_any(resource) do |move|
+ next unless resource_equals?(resource, move)
QA::Runtime::Logger.debug("Move data: #{move}")
@@ -20,16 +20,28 @@ module QA
end
end
- def find_any
+ def find_any(resource)
Logger.debug('Getting repository storage moves')
Support::Waiter.wait_until do
- with_paginated_response_body(Request.new(api_client, '/project_repository_storage_moves', per_page: '100').url) do |page|
+ with_paginated_response_body(Request.new(api_client, "/#{resource_name(resource)}_repository_storage_moves", per_page: '100').url) do |page|
break true if page.any? { |item| yield item }
end
end
end
+ def resource_equals?(resource, move)
+ if resource.class.name.include?('Snippet')
+ move[:snippet][:id] == resource.id
+ else
+ move[:project][:path_with_namespace] == resource.path_with_namespace
+ end
+ end
+
+ def resource_name(resource)
+ resource.class.name.split('::').last.downcase
+ end
+
private
def api_client
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index 6c4139da83f..7aa45204513 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -8,7 +8,7 @@ module QA
module Env
extend self
- attr_writer :personal_access_token
+ attr_writer :personal_access_token, :admin_personal_access_token
ENV_VARIABLES = Gitlab::QA::Runtime::Env::ENV_VARIABLES
@@ -78,18 +78,6 @@ module QA
ENV['QA_PRAEFECT_REPOSITORY_STORAGE']
end
- def admin_password
- ENV['GITLAB_ADMIN_PASSWORD']
- end
-
- def admin_username
- ENV['GITLAB_ADMIN_USERNAME']
- end
-
- def admin_personal_access_token
- ENV['GITLAB_QA_ADMIN_ACCESS_TOKEN']
- end
-
def ci_job_url
ENV['CI_JOB_URL']
end
@@ -140,6 +128,18 @@ module QA
enabled?(ENV['SIGNUP_DISABLED'], default: false)
end
+ def admin_password
+ ENV['GITLAB_ADMIN_PASSWORD']
+ end
+
+ def admin_username
+ ENV['GITLAB_ADMIN_USERNAME']
+ end
+
+ def admin_personal_access_token
+ @admin_personal_access_token ||= ENV['GITLAB_QA_ADMIN_ACCESS_TOKEN']
+ end
+
# specifies token that can be used for the api
def personal_access_token
@personal_access_token ||= ENV['GITLAB_QA_ACCESS_TOKEN']
diff --git a/qa/qa/service/praefect_manager.rb b/qa/qa/service/praefect_manager.rb
index ab4f28c292f..119013175c0 100644
--- a/qa/qa/service/praefect_manager.rb
+++ b/qa/qa/service/praefect_manager.rb
@@ -353,15 +353,47 @@ module QA
Support::Waiter.wait_until(sleep_interval: 1) { replication_queue_incomplete_count == 0 && replicated?(project_id) }
end
+ def replication_pending?
+ result = []
+ shell sql_to_docker_exec_cmd(
+ <<~SQL
+ select job from replication_queue
+ where state = 'ready'
+ and job ->> 'change' = 'update'
+ and job ->> 'source_node_storage' = '#{current_primary_node}'
+ and job ->> 'target_node_storage' = '#{@primary_node}';
+ SQL
+ ) do |line|
+ result << line
+ end
+
+ # The result looks like:
+ #
+ # job
+ # -----------
+ # {"change": "update", "params": null, "relative_path": "@hashed/4b/22/4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a.git", "virtual_storage": "default", "source_node_storage": "gitaly3", "target_node_storage": "gitaly1"}
+ # (1 row)
+ # <blank row>
+ #
+ # Therefore when replication is pending there is at least 1 row of data plus 4 rows of metadata/layout
+
+ result.size >= 5
+ end
+
private
def current_primary_node
- shell dataloss_command do |line|
- QA::Runtime::Logger.debug(line.chomp)
-
- match = line.match(/Primary: (.*)/)
- break match[1] if match
+ result = []
+ shell sql_to_docker_exec_cmd("select node_name from shard_primaries where shard_name = '#{@virtual_storage}';") do |line|
+ result << line
end
+ # The result looks like:
+ # node_name
+ # -----------
+ # gitaly1
+ # (1 row)
+
+ result[2].strip
end
def dataloss_command
diff --git a/qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb
index 89bf92cd3af..c90f8546f91 100644
--- a/qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb
+++ b/qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create' do
context 'Gitaly' do
- describe 'Backend node recovery', :orchestrated, :gitaly_cluster, :skip_live_env, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/238186', type: :investigating } do
+ describe 'Backend node recovery', :orchestrated, :gitaly_cluster, :skip_live_env, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/322647', type: :flaky } do
let(:praefect_manager) { Service::PraefectManager.new }
let(:project) do
Resource::Project.fabricate! do |project|
@@ -50,18 +50,17 @@ module QA
push.file_content = 'new file'
end
+ # Confirm that the commit is waiting to be replicated
+ expect(praefect_manager).to be_replication_pending
+
# Start the old primary node again
praefect_manager.start_primary_node
- praefect_manager.wait_for_health_check_current_primary_node
-
- # Confirm dataloss (i.e., inconsistent nodes)
- expect(praefect_manager.replicated?(project.id)).to be false
+ praefect_manager.wait_for_health_check_all_nodes
- # Reconcile nodes to recover from dataloss
- praefect_manager.reconcile_nodes
+ # Wait for automatic replication
praefect_manager.wait_for_replication(project.id)
- # Confirm that both commits are available after reconciliation
+ # Confirm that both commits are available
expect(project.commits.map { |commit| commit[:message].chomp })
.to include("Initial commit").and include("pushed after failover")
end
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
index d6bd668fa8a..bf2ecfdb513 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
@@ -38,7 +38,11 @@ module QA
end.merge_via_api!
expect(merge_request[:state]).to eq('merged')
- expect(project).not_to have_branch(branch)
+
+ # Retry in case the branch deletion takes more time to finish
+ QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 5) do
+ expect(project).not_to have_branch(branch)
+ end
end
end
end
diff --git a/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb b/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb
new file mode 100644
index 00000000000..4872acd1004
--- /dev/null
+++ b/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Snippet repository storage', :requires_admin, :orchestrated, :repository_storage do
+ let(:source_storage) { { type: :gitaly, name: 'default' } }
+ let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.additional_repository_storage } }
+
+ let(:snippet) do
+ Resource::Snippet.fabricate_via_api! do |snippet|
+ snippet.title = 'Snippet to move storage of'
+ snippet.file_name = 'original_file'
+ snippet.file_content = 'Original file content'
+ snippet.api_client = Runtime::API::Client.as_admin
+ end
+ end
+
+ praefect_manager = Service::PraefectManager.new
+
+ before do
+ praefect_manager.gitlab = 'gitlab'
+ end
+
+ it 'moves snippet repository from one Gitaly storage to another', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1700' do
+ expect(snippet).to have_file('original_file')
+ expect { snippet.change_repository_storage(destination_storage[:name]) }.not_to raise_error
+ expect { praefect_manager.verify_storage_move(source_storage, destination_storage) }.not_to raise_error
+
+ # verifies you can push commits to the moved snippet
+ Resource::Repository::Push.fabricate! do |push|
+ push.repository_http_uri = snippet.http_url_to_repo
+ push.file_name = 'new_file'
+ push.file_content = 'new file content'
+ push.commit_message = 'Adding a new snippet file'
+ push.new_branch = false
+ end
+
+ aggregate_failures do
+ expect(snippet).to have_file('original_file')
+ expect(snippet).to have_file('new_file')
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/api/4_verify/.gitkeep b/qa/qa/specs/features/api/4_verify/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/qa/qa/specs/features/api/4_verify/.gitkeep
diff --git a/qa/qa/specs/features/api/4_verify/pipeline_deletion_spec.rb b/qa/qa/specs/features/api/4_verify/pipeline_deletion_spec.rb
deleted file mode 100644
index 1d1b765bb9f..00000000000
--- a/qa/qa/specs/features/api/4_verify/pipeline_deletion_spec.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Verify' do
- include Support::Api
-
- let(:api_client) { Runtime::API::Client.new(:gitlab) }
-
- describe 'Pipeline', :runner do
- let(:project) do
- Resource::Project.fabricate_via_api! do |project|
- project.name = 'project-with-pipeline'
- end
- end
-
- let!(:runner) do
- Resource::Runner.fabricate! do |runner|
- runner.project = project
- runner.name = project.name
- runner.tags = [project.name]
- end
- end
-
- let!(:ci_file) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- commit.project = project
- commit.commit_message = 'Add .gitlab-ci.yml'
- commit.add_files(
- [
- {
- file_path: '.gitlab-ci.yml',
- content: <<~YAML
- job1:
- tags:
- - #{project.name}
- script: echo 'OK'
- YAML
- }
- ]
- )
- end
- end
-
- let!(:pipeline_id) do
- pipeline_create_request = Runtime::API::Request.new(api_client, "/projects/#{project.id}/pipeline?ref=#{project.default_branch}")
- JSON.parse(post(pipeline_create_request.url, nil))['id']
- end
-
- let(:pipeline_data_request) { Runtime::API::Request.new(api_client, "/projects/#{project.id}/pipelines/#{pipeline_id}") }
-
- before do
- Support::Waiter.wait_until(sleep_interval: 3) { !pipeline.empty? && pipeline['status'] != 'pending' }
- end
-
- after do
- runner.remove_via_api!
- end
-
- context 'when deleted via API' do
- it 'is not found', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/931' do
- delete(pipeline_data_request.url)
-
- deleted_pipeline = nil
- Support::Waiter.wait_until(sleep_interval: 3) do
- deleted_pipeline = pipeline
- !pipeline.empty?
- end
-
- raise "Pipeline response does not have a 'message' key: #{deleted_pipeline}" unless deleted_pipeline&.key?('message')
-
- expect(deleted_pipeline['message'].downcase).to have_content('404 not found')
- end
- end
-
- private
-
- def pipeline
- JSON.parse(get(pipeline_data_request.url))
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb
index 5f38907f89f..7ab5ffdf014 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb
@@ -44,8 +44,7 @@ module QA
end
it 'user transfers a project between groups',
- testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/406',
- quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/283925', type: :investigating, only: :production } do
+ testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1703' do
# Retry is needed here as the target group is not avaliable for transfer right away.
QA::Support::Retrier.retry_on_exception(reload_page: page) do
Page::File::Show.perform(&:go_to_general_settings)
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb
index e38a9f47bd6..8e03444b113 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb
@@ -29,6 +29,7 @@ module QA
end
before do
+ Runtime::Feature.enable(:invite_members_group_modal, group: group)
group.add_member(developer_user, Resource::Members::AccessLevel::DEVELOPER)
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
index 2fc3ff2f18f..a8650d633c8 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
@@ -31,6 +31,7 @@ module QA
let(:two_fa_expected_text) { /The group settings for.*require you to enable Two-Factor Authentication for your account.*You need to do this before/ }
before do
+ Runtime::Feature.enable(:invite_members_group_modal, group: group)
group.add_member(developer_user, Resource::Members::AccessLevel::DEVELOPER)
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
index ffc2290b644..4141060b6cb 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
@@ -23,6 +23,7 @@ module QA
@personal_access_token = Runtime::Env.personal_access_token
Runtime::Env.personal_access_token = nil
+
ldap_username = Runtime::Env.ldap_username
Runtime::Env.ldap_username = nil
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
index 85cfefd6c5c..bf59dcfcc4c 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
@@ -4,11 +4,7 @@ module QA
RSpec.describe 'Manage', :requires_admin do
describe 'Add project member' do
before do
- Runtime::Feature.enable('vue_project_members_list')
- end
-
- after do
- Runtime::Feature.disable('vue_project_members_list')
+ Runtime::Feature.enable(:invite_members_group_modal)
end
it 'user adds project member', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/482' do
@@ -16,9 +12,11 @@ module QA
user = Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1)
- Resource::Project.fabricate_via_api! do |project|
+ project = Resource::Project.fabricate_via_api! do |project|
project.name = 'add-member-project'
- end.visit!
+ end
+
+ project.visit!
Page::Project::Menu.perform(&:click_members)
Page::Project::Members.perform do |members|
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb
index f2822e3d368..95092fe6ba6 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb
@@ -47,7 +47,7 @@ module QA
end
end
- context 'when logged in as a new admin', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/463' do
+ context 'when logged in as a new admin', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1727' do
it_behaves_like 'loads all images' do
let(:new_user) { @new_admin }
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb
index d54ce0ac0fc..c8c483fc2aa 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb
@@ -21,6 +21,7 @@ module QA
end
before do
+ Runtime::Feature.enable(:invite_members_group_modal, group: group)
group.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb
index e40dde64675..714c4a2da67 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb
@@ -2,7 +2,8 @@
module QA
RSpec.describe 'Manage' do
- describe 'Repository tags' do
+ # TODO: Remove :requires_admin meta when the `Runtime::Feature.enable` method call is removed
+ describe 'Repository tags', :requires_admin do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project-for-tags'
@@ -10,6 +11,10 @@ module QA
end
end
+ before do
+ Runtime::Feature.enable(:invite_members_group_modal, project: project)
+ end
+
let(:developer_user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:maintainer_user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) }
let(:tag_name) { 'v0.0.1' }
diff --git a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
index f623efe5a3a..d352996f419 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
@@ -16,14 +16,10 @@ module QA
end
before do
- Runtime::Feature.enable('vue_project_members_list', project: project)
+ Runtime::Feature.enable(:invite_members_group_modal)
Flow::Login.sign_in
end
- after do
- Runtime::Feature.disable('vue_project_members_list', project: project)
- end
-
it 'is received by a user for project invitation', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/676' do
project.visit!
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
index a7f862e8911..9129584d110 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
@@ -18,6 +18,8 @@ module QA
describe 'check xss occurence in @mentions in issues', :requires_admin do
before do
+ Runtime::Feature.enable(:invite_members_group_modal)
+
Flow::Login.sign_in
project.add_member(user)
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
index cc815fd0e67..45222d2ec7e 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :smoke, :reliable do
+ # TODO: Remove :requires_admin meta when the `Runtime::Feature.enable` method call is removed
+ RSpec.describe 'Plan', :smoke, :reliable, :requires_admin do
describe 'mention' do
let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:project) do
@@ -13,6 +14,7 @@ module QA
before do
Flow::Login.sign_in
+ Runtime::Feature.enable(:invite_members_group_modal, project: project)
project.add_member(user)
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb
index 11f93d6a97e..2654531bc2c 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb
@@ -14,6 +14,7 @@ module QA
before do
Runtime::Feature.enable('real_time_issue_sidebar', project: project)
Runtime::Feature.enable('broadcast_issue_updates', project: project)
+ Runtime::Feature.enable(:invite_members_group_modal, project: project)
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb b/qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb
index 7090427e5a4..43cf701acdd 100644
--- a/qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb
@@ -15,7 +15,7 @@ module QA
let(:third_design) do
Resource::Design.fabricate! do |design|
design.issue = second_design.issue
- design.filename = 'tanuki.jpg'
+ design.filename = 'testfile.png'
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb b/qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb
index 135063b6644..9fbb0d69de1 100644
--- a/qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb
@@ -5,7 +5,7 @@ module QA
context 'Design Management' do
let(:design) do
Resource::Design.fabricate! do |design|
- design.filename = 'tanuki.jpg'
+ design.filename = 'testfile.png'
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb b/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb
index 0fec7bc9e9d..734ff160937 100644
--- a/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb
@@ -107,7 +107,7 @@ module QA
def fabricate_personal_access_token
login_to_gitlab
- token = Resource::PersonalAccessToken.fabricate!.access_token
+ token = Resource::PersonalAccessToken.fabricate!.token
Page::Main::Menu.perform(&:sign_out)
token
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
index d2ba97400e6..8d12042bd85 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
@@ -9,7 +9,7 @@ module QA
end
end
- it 'can merge feature branch fork to mainline', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/928' do
+ it 'can merge feature branch fork to mainline', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1701' do
Flow::Login.while_signed_in do
merge_request.visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
new file mode 100644
index 00000000000..2ddc59acd5c
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create', :runner do
+ describe 'Merge requests' do
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'merge-when-pipeline-succeeds'
+ project.initialize_with_readme = true
+ end
+ end
+
+ let!(:runner) do
+ Resource::Runner.fabricate! do |runner|
+ runner.project = project
+ runner.name = "runner-for-#{project.name}"
+ runner.tags = ["runner-for-#{project.name}"]
+ end
+ end
+
+ before do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add .gitlab-ci.yml'
+ commit.add_files(
+ [
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~EOF
+ test:
+ tags: ["runner-for-#{project.name}"]
+ script: sleep 5
+ only:
+ - merge_requests
+ EOF
+ }
+ ]
+ )
+ end
+
+ Flow::Login.sign_in
+ end
+
+ after do
+ runner&.remove_via_api!
+ project&.remove_via_api!
+ end
+
+ it 'merges when pipeline succeeds', :smoke, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1684' do
+ branch_name = "merge-request-test-#{SecureRandom.hex(8)}"
+
+ # Create a branch that will be merged into the default branch
+ Resource::Repository::ProjectPush.fabricate! do |project_push|
+ project_push.project = project
+ project_push.new_branch = true
+ project_push.branch_name = branch_name
+ project_push.file_name = "file-#{SecureRandom.hex(8)}.txt"
+ end
+
+ # Create a merge request to merge the branch we just created
+ merge_request = Resource::MergeRequest.fabricate_via_api! do |merge_request|
+ merge_request.project = project
+ merge_request.source_branch = branch_name
+ merge_request.no_preparation = true
+ end
+
+ merge_request.visit!
+
+ Page::MergeRequest::Show.perform do |mr|
+ mr.merge_when_pipeline_succeeds!
+
+ expect(mr.merge_request_status).to match(/to be merged automatically when the pipeline succeeds/)
+
+ Support::Waiter.wait_until(sleep_interval: 5) do
+ merge_request = merge_request.reload!
+ merge_request.state == 'merged'
+ end
+
+ expect(mr.merged?).to be_truthy, "Expected content 'The changes were merged' but it did not appear."
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
index 3414584bae3..34669eb3815 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/30226', type: :bug } do
+ RSpec.describe 'Create', quarantine: { only: { subdomain: :staging }, issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/323990', type: :flaky } do
describe 'Merge request rebasing' do
it 'user rebases source branch of merge request', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1274' do
Flow::Login.sign_in
@@ -34,7 +34,7 @@ module QA
Page::MergeRequest::Show.perform do |merge_request|
expect(merge_request).to have_content('Needs rebasing')
- expect(merge_request).not_to be_fast_forward_possible
+ expect(merge_request).to be_fast_forward_not_possible
expect(merge_request).not_to have_merge_button
merge_request.rebase!
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb
index 9edde7ac12f..fb9e42a6960 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Git clone over HTTP', :ldap_no_tls do
+ describe 'Git clone over HTTP' do
let(:project) do
Resource::Project.fabricate_via_api! do |scenario|
scenario.name = 'project-with-code'
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb
index 7a727ffb291..0f6edca654b 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb
@@ -19,6 +19,7 @@ module QA
end
before do
+ Runtime::Feature.enable(:invite_members_group_modal, project: parent_project)
parent_project.add_member(user)
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb
index 35ec2135491..2c0fb5ea290 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb
@@ -2,11 +2,11 @@
module QA
RSpec.describe 'Create' do
- describe 'Git push over HTTP', :ldap_no_tls, :smoke do
+ describe 'Git push over HTTP', :smoke do
it 'user using a personal access token pushes code to the repository', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1278' do
Flow::Login.sign_in
- access_token = Resource::PersonalAccessToken.fabricate!.access_token
+ access_token = Resource::PersonalAccessToken.fabricate!.token
user = Resource::User.new.tap do |user|
user.username = Runtime::User.username
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
index 222eb3771ad..1423e3c45ce 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
@@ -17,7 +17,7 @@ module QA
p.initialize_with_readme = true
end
- @api_client = Runtime::API::Client.new(:gitlab, personal_access_token: Runtime::Env.admin_personal_access_token)
+ @api_client = Runtime::API::Client.as_admin
end
after(:context) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
index cf14017b7f1..861efa8b45a 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
@@ -2,8 +2,8 @@
module QA
RSpec.describe 'Create' do
- describe 'Git push over HTTP', :ldap_no_tls do
- it 'user pushes code to the repository', :smoke, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/426' do
+ describe 'Git push over HTTP' do
+ it 'user pushes code to the repository', :smoke, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1702' do
Flow::Login.sign_in
Resource::Repository::ProjectPush.fabricate! do |push|
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb
index c56e6d1267c..9eeb762e548 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb
@@ -41,8 +41,7 @@ module QA
end
end
- it 'pushes multiple branches and tags together', :smoke, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1679
- ' do
+ it 'pushes multiple branches and tags together', :smoke, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1679' do
branches = []
tags = []
Git::Repository.perform do |repository|
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb
index 2b249f779d9..ce7fdf379a4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Protected branch support', :ldap_no_tls do
+ describe 'Protected branch support' do
let(:branch_name) { 'protected-branch' }
let(:commit_message) { 'Protected push commit message' }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
index a867d9cb973..6ab50ba56f2 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
@@ -23,6 +23,11 @@ module QA
Flow::Login.sign_in
end
+ after do
+ personal_snippet&.remove_via_api!
+ project_snippet&.remove_via_api!
+ end
+
shared_examples 'comments on snippets' do |snippet_type|
it "adds, edits, and deletes a comment on a #{snippet_type}" do
send(snippet_type)
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb
index 604c98ca21e..72d83eadde9 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Multiple file snippet', quarantine: { only: { pipeline: :master }, issue: 'https://gitlab.com/gitlab-org/gitaly/-/issues/3143', type: :bug } do
+ describe 'Multiple file snippet' do
let(:personal_snippet) do
Resource::Snippet.fabricate_via_api! do |snippet|
snippet.title = 'Personal snippet to add file to'
@@ -23,6 +23,11 @@ module QA
Flow::Login.sign_in
end
+ after do
+ personal_snippet&.remove_via_api!
+ project_snippet&.remove_via_api!
+ end
+
shared_examples 'adding file to snippet' do |snippet_type|
it "adds second file to an existing #{snippet_type} to make it multi-file" do
send(snippet_type).visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb
index 2940b2067a1..d44f5bc9e2e 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Version control for personal snippets', quarantine: { only: { pipeline: :master }, issue: 'https://gitlab.com/gitlab-org/gitaly/-/issues/3143', type: :bug } do
+ describe 'Version control for personal snippets' do
let(:new_file) { 'new_snippet_file' }
let(:changed_content) { 'changes' }
let(:commit_message) { 'Changes to snippets' }
@@ -66,6 +66,8 @@ module QA
expect(repository.commits.first).to include('Update snippet')
expect(repository.file_content(new_file)).to include("#{added_content}#{changed_content}")
end
+
+ snippet.remove_via_api!
end
it 'clones, pushes, and pulls a snippet over SSH, deletes via UI', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/825' do
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb
index b91424d5b65..b67e0e54aa0 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Version control for project snippets', quarantine: { only: { pipeline: :master }, issue: 'https://gitlab.com/gitlab-org/gitaly/-/issues/3143', type: :bug } do
+ describe 'Version control for project snippets' do
let(:new_file) { 'new_snippet_file' }
let(:changed_content) { 'changes' }
let(:commit_message) { 'Changes to snippets' }
@@ -40,7 +40,7 @@ module QA
ssh_key.remove_via_api!
end
- it 'clones, pushes, and pulls a project snippet over HTTP, edits via UI', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/833' do
+ it 'clones, pushes, and pulls a project snippet over HTTP, edits via UI', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1725' do
Resource::Repository::Push.fabricate! do |push|
push.repository_http_uri = repository_uri_http
push.file_name = new_file
@@ -67,6 +67,8 @@ module QA
expect(repository.commits.first).to include 'Update snippet'
expect(repository.file_content(new_file)).to include "#{added_content}#{changed_content}"
end
+
+ snippet.remove_via_api!
end
it 'clones, pushes, and pulls a project snippet over SSH, deletes via UI', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/832' do
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb
index 1670ba56064..29ddbb22a01 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb
@@ -54,6 +54,11 @@ module QA
Flow::Login.sign_in
end
+ after do
+ personal_snippet&.remove_via_api!
+ project_snippet&.remove_via_api!
+ end
+
shared_examples 'copying snippet file contents' do |snippet_type|
it "copies file contents of a multi-file #{snippet_type} to a comment and verifies them" do
send(snippet_type).visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb
index b74f27389a0..ddbc98c4a1a 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create', :smoke do
describe 'Personal snippet creation' do
- it 'user creates a personal snippet', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/840' do
+ it 'user creates a personal snippet', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1704' do
Flow::Login.sign_in
Page::Main::Menu.perform do |menu|
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb
index 5c0983dabb6..014c0ca4d48 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Multiple file snippet', quarantine: { only: { pipeline: :master }, issue: 'https://gitlab.com/gitlab-org/gitaly/-/issues/3143', type: :bug } do
+ describe 'Multiple file snippet' do
let(:personal_snippet) do
Resource::Snippet.fabricate_via_api! do |snippet|
snippet.title = 'Personal snippet to delete file from'
@@ -31,6 +31,11 @@ module QA
Flow::Login.sign_in
end
+ after do
+ personal_snippet&.remove_via_api!
+ project_snippet&.remove_via_api!
+ end
+
shared_examples 'deleting file from snippet' do |snippet_type|
it "deletes second file from an existing #{snippet_type} to make it single-file" do
send(snippet_type).visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb
index 751424222ba..3973e0aacad 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb
@@ -16,6 +16,10 @@ module QA
Flow::Login.sign_in
end
+ after do
+ snippet&.remove_via_api!
+ end
+
context 'when the snippet is public' do
it 'can be shared with not signed-in users', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1016' do
snippet.visit!
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry_spec.rb
new file mode 100644
index 00000000000..5e663d87ae3
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Package', :orchestrated do
+ describe 'Container Registry', only: { subdomain: :staging } do
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-with-registry'
+ project.template_name = 'express'
+ end
+ end
+
+ let(:registry_repository) do
+ Resource::RegistryRepository.fabricate! do |repository|
+ repository.name = "#{project.path_with_namespace}"
+ repository.project = project
+ end
+ end
+
+ let!(:gitlab_ci_yaml) do
+ <<~YAML
+ build:
+ image: docker:19.03.12
+ stage: build
+ services:
+ - docker:19.03.12-dind
+ variables:
+ IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
+ script:
+ - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ - docker build -t $IMAGE_TAG .
+ - docker push $IMAGE_TAG
+ YAML
+ end
+
+ after do
+ registry_repository&.remove_via_api!
+ end
+
+ it 'pushes project image to the container registry and deletes tag', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1699' do
+ Flow::Login.sign_in
+ project.visit!
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add .gitlab-ci.yml'
+ commit.add_files([{
+ file_path: '.gitlab-ci.yml',
+ content: gitlab_ci_yaml
+ }])
+ end
+
+ Flow::Pipeline.visit_latest_pipeline
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('build')
+ end
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful(timeout: 800)
+ end
+
+ Page::Project::Menu.perform(&:go_to_container_registry)
+
+ Page::Project::Registry::Show.perform do |registry|
+ expect(registry).to have_registry_repository(registry_repository.name)
+
+ registry.click_on_image(registry_repository.name)
+ expect(registry).to have_tag('master')
+
+ registry.click_delete
+ expect(registry).not_to have_tag('master')
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb
index 6ab4a957c57..b5b050a5dfe 100644
--- a/qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb
@@ -13,7 +13,7 @@ module QA
Flow::Login.sign_in
end
- Resource::PersonalAccessToken.fabricate!.access_token
+ Resource::PersonalAccessToken.fabricate!.token
end
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb
index 605248e33f7..2f508d00790 100644
--- a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb
@@ -1,19 +1,21 @@
# frozen_string_literal: true
+require 'securerandom'
+
module QA
RSpec.describe 'Package', :orchestrated, :packages do
describe 'Maven Repository' do
include Runtime::Fixtures
let(:group_id) { 'com.gitlab.qa' }
- let(:artifact_id) { 'maven' }
+ let(:artifact_id) { "maven-#{SecureRandom.hex(8)}" }
let(:package_name) { "#{group_id}/#{artifact_id}".tr('.', '/') }
let(:auth_token) do
unless Page::Main::Menu.perform(&:signed_in?)
Flow::Login.sign_in
end
- Resource::PersonalAccessToken.fabricate!.access_token
+ Resource::PersonalAccessToken.fabricate!.token
end
let(:project) do
@@ -22,12 +24,19 @@ module QA
end
end
+ let(:another_project) do
+ Resource::Project.fabricate_via_api! do |another_project|
+ another_project.name = 'another-maven-package-project'
+ another_project.group = project.group
+ end
+ end
+
let!(:runner) do
Resource::Runner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
- runner.tags = ["runner-for-#{project.name}"]
+ runner.tags = ["runner-for-#{project.group.name}"]
runner.executor = :docker
- runner.project = project
+ runner.token = project.group.sandbox.runners_token
end
end
@@ -90,6 +99,28 @@ module QA
}
end
+ let(:gitlab_ci_yaml) do
+ {
+ file_path: '.gitlab-ci.yml',
+ content:
+ <<~YAML
+ deploy:
+ image: maven:3.6-jdk-11
+ script:
+ - 'mvn deploy -s settings.xml'
+ - "mvn dependency:get -Dartifact=#{group_id}:#{artifact_id}:1.0"
+ only:
+ - "#{project.default_branch}"
+ tags:
+ - "runner-for-#{project.group.name}"
+ YAML
+ }
+ end
+
+ after do
+ runner.remove_via_api!
+ end
+
it 'publishes a maven package and deletes it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/943' do
# Use a maven docker container to deploy the package
with_fixtures([pom_xml, settings_xml]) do |dir|
@@ -122,23 +153,9 @@ module QA
commit.project = project
commit.commit_message = 'Add .gitlab-ci.yml'
commit.add_files([
- {
- file_path: '.gitlab-ci.yml',
- content:
- <<~YAML
- deploy:
- image: maven:3.6-jdk-11
- script:
- - 'mvn deploy -s settings.xml'
- - "mvn dependency:get -Dartifact=#{group_id}:#{artifact_id}:1.0"
- only:
- - "#{project.default_branch}"
- tags:
- - "runner-for-#{project.name}"
- YAML
- },
- settings_xml,
- pom_xml
+ gitlab_ci_yaml,
+ settings_xml,
+ pom_xml
])
end
@@ -153,6 +170,96 @@ module QA
expect(job).to be_successful(timeout: 800)
end
end
+
+ context 'when "allow duplicate" setting is disabled' do
+ before do
+ Flow::Login.sign_in
+
+ project.group.visit!
+
+ Page::Group::Menu.perform(&:go_to_package_settings)
+ Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled)
+ end
+
+ it 'prevents users from publishing duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1717' do
+ with_fixtures([pom_xml, settings_xml]) do |dir|
+ Service::DockerRun::Maven.new(dir).publish!
+ end
+
+ project.visit!
+ Page::Project::Menu.perform(&:click_packages_link)
+
+ Page::Project::Packages::Index.perform do |index|
+ expect(index).to have_package(package_name)
+ end
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = another_project
+ commit.commit_message = 'Add .gitlab-ci.yml'
+ commit.add_files([
+ gitlab_ci_yaml,
+ settings_xml,
+ pom_xml
+ ])
+ end
+
+ another_project.visit!
+ Flow::Pipeline.visit_latest_pipeline
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('deploy')
+ end
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).not_to be_successful(timeout: 800)
+ end
+ end
+ end
+
+ context 'when "allow duplicate" setting is enabled' do
+ before do
+ Flow::Login.sign_in
+
+ project.group.visit!
+
+ Page::Group::Menu.perform(&:go_to_package_settings)
+ Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled)
+ end
+
+ it 'allows users to publish duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1722' do
+ with_fixtures([pom_xml, settings_xml]) do |dir|
+ Service::DockerRun::Maven.new(dir).publish!
+ end
+
+ project.visit!
+ Page::Project::Menu.perform(&:click_packages_link)
+
+ Page::Project::Packages::Index.perform do |index|
+ expect(index).to have_package(package_name)
+ end
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = another_project
+ commit.commit_message = 'Add .gitlab-ci.yml'
+ commit.add_files([
+ gitlab_ci_yaml,
+ settings_xml,
+ pom_xml
+ ])
+ end
+
+ another_project.visit!
+ Flow::Pipeline.visit_latest_pipeline
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('deploy')
+ end
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful(timeout: 800)
+ end
+ end
+ end
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb
index fa88ace1556..97df8fedf87 100644
--- a/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Package', :orchestrated, :packages do
- describe 'NPM registry' do
+ describe 'npm registry' do
include Runtime::Fixtures
let(:registry_scope) { project.group.sandbox.path }
@@ -12,7 +12,7 @@ module QA
Flow::Login.sign_in
end
- Resource::PersonalAccessToken.fabricate!.access_token
+ Resource::PersonalAccessToken.fabricate!.token
end
let(:project) do
@@ -31,7 +31,7 @@ module QA
{
"name": "#{package_name}",
"version": "1.0.0",
- "description": "Example package for GitLab NPM registry",
+ "description": "Example package for GitLab npm registry",
"publishConfig": {
"@#{registry_scope}:registry": "#{gitlab_address_with_port}/api/v4/projects/#{project.id}/packages/npm/"
}
diff --git a/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb
index 8c3f0930207..f143bc52095 100644
--- a/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb
@@ -1,11 +1,13 @@
# frozen_string_literal: true
+require 'securerandom'
+
module QA
RSpec.describe 'Package', :orchestrated, :packages do
describe 'NuGet Repository' do
include Runtime::Fixtures
- let(:package_name) { 'dotnetcore' }
+ let(:package_name) { "dotnetcore-#{SecureRandom.hex(8)}" }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'nuget-package-project'
@@ -54,7 +56,7 @@ module QA
{
file_path: '.gitlab-ci.yml',
content: <<~YAML
- image: mcr.microsoft.com/dotnet/core/sdk:3.1
+ image: mcr.microsoft.com/dotnet/sdk:5.0
stages:
- deploy
@@ -64,7 +66,7 @@ module QA
script:
- dotnet restore -p:Configuration=Release
- dotnet build -c Release
- - dotnet pack -c Release
+ - dotnet pack -c Release -p:PackageID=#{package_name}
- dotnet nuget add source "$CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/packages/nuget/index.json" --name gitlab --username gitlab-ci-token --password $CI_JOB_TOKEN --store-password-in-clear-text
- dotnet nuget push "bin/Release/*.nupkg" --source gitlab
only:
@@ -102,7 +104,7 @@ module QA
<PropertyGroup>
<OutputType>Exe</OutputType>
- <TargetFramework>netcoreapp3.1</TargetFramework>
+ <TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>
@@ -115,7 +117,7 @@ module QA
{
file_path: '.gitlab-ci.yml',
content: <<~YAML
- image: mcr.microsoft.com/dotnet/core/sdk:3.1
+ image: mcr.microsoft.com/dotnet/sdk:5.0
stages:
- install
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index 171a4776eaf..e2cf5c5b195 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -23,9 +23,7 @@ module QA
cluster&.remove!
end
- it 'runs auto devops', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/702' do
- skip('Test requires tunnel: see https://gitlab.com/gitlab-org/gitlab/-/issues/251090')
-
+ it 'runs auto devops', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1715' do
Flow::Login.sign_in
# Set an application secret CI variable (prefixed with K8S_SECRET_)
diff --git a/qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb b/qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb
index 8dca0d6698e..302fec55c53 100644
--- a/qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb
+++ b/qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb
@@ -20,7 +20,7 @@ module QA
end
end
- it 'shows results for the original request and AJAX requests', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/478', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/247467', type: :investigating } do
+ it 'shows results for the original request and AJAX requests', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/478', quarantine: { only: { pipeline: :master }, issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/323051', type: :bug } do
# Issue pages always make AJAX requests
Resource::Issue.fabricate_via_browser_ui! do |issue|
issue.title = 'Performance bar test'
diff --git a/qa/qa/support/api.rb b/qa/qa/support/api.rb
index 5fc36b68e5c..de9da3171b0 100644
--- a/qa/qa/support/api.rb
+++ b/qa/qa/support/api.rb
@@ -9,6 +9,7 @@ module QA
HTTP_STATUS_CREATED = 201
HTTP_STATUS_NO_CONTENT = 204
HTTP_STATUS_ACCEPTED = 202
+ HTTP_STATUS_NOT_FOUND = 404
HTTP_STATUS_SERVER_ERROR = 500
def post(url, payload, args = {})
diff --git a/qa/qa/support/ssh.rb b/qa/qa/support/ssh.rb
index a5e8e96cb6c..1b53244d1e4 100644
--- a/qa/qa/support/ssh.rb
+++ b/qa/qa/support/ssh.rb
@@ -51,11 +51,21 @@ module QA
private
def uri_port
- uri.port && (uri.port != 80) ? uri.port : nil
+ use_typical_params? ? nil : uri.port
end
def git_user
- QA::Runtime::Env.running_in_ci? || [443, 80].include?(uri.port) ? 'git' : Etc.getlogin
+ QA::Runtime::Env.running_in_ci? || use_typical_params? ? 'git' : Etc.getlogin
+ end
+
+ # Checks if typical parameters should be used. That means the SSH port will not be
+ # needed because it's port 22, and the git user is named 'git'. We assume that
+ # typical parameters should be used if the host URI includes a typical HTTP(S)
+ # port (80 or 443)
+ #
+ # @return [Boolean] whether typical SSH port and git user parameters should be used
+ def use_typical_params?
+ [443, 80].include?(uri.port)
end
end
end
diff --git a/qa/qa/tools/initialize_gitlab_auth.rb b/qa/qa/tools/initialize_gitlab_auth.rb
index b06ddcab040..3ead8fc9bd4 100644
--- a/qa/qa/tools/initialize_gitlab_auth.rb
+++ b/qa/qa/tools/initialize_gitlab_auth.rb
@@ -23,7 +23,7 @@ module QA
Flow::Login.sign_in
puts "Creating an API scoped access token for the root user..."
- puts "Token: #{Resource::PersonalAccessToken.fabricate!.access_token}"
+ puts "Token: #{Resource::PersonalAccessToken.fabricate!.token}"
end
end
end
diff --git a/qa/spec/runtime/api/client_spec.rb b/qa/spec/runtime/api/client_spec.rb
index dd139fda980..36ee563de39 100644
--- a/qa/spec/runtime/api/client_spec.rb
+++ b/qa/spec/runtime/api/client_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe QA::Runtime::API::Client do
end
it 'returns a created token' do
- client = described_class.new(user: { username: 'foo' })
+ client = described_class.new(user: Struct.new(:username, :admin?).new('foo', false))
expect(client).to receive(:create_personal_access_token).and_return('created_token')
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
index 3396ae6f0b8..5a98721466f 100644
--- a/qa/spec/runtime/env_spec.rb
+++ b/qa/spec/runtime/env_spec.rb
@@ -232,6 +232,7 @@ RSpec.describe QA::Runtime::Env do
describe '.require_admin_access_token!' do
it 'raises ArgumentError if GITLAB_QA_ADMIN_ACCESS_TOKEN is not specified' do
+ described_class.instance_variable_set(:@admin_personal_access_token, nil)
stub_env('GITLAB_QA_ADMIN_ACCESS_TOKEN', nil)
expect { described_class.require_admin_access_token! }.to raise_error(ArgumentError)
diff --git a/qa/spec/specs/helpers/quarantine_spec.rb b/qa/spec/specs/helpers/quarantine_spec.rb
index 80fd65faeed..694c320ce3d 100644
--- a/qa/spec/specs/helpers/quarantine_spec.rb
+++ b/qa/spec/specs/helpers/quarantine_spec.rb
@@ -15,7 +15,7 @@ end
# expanding into the global state
# See: https://github.com/rspec/rspec-core/issues/2603
def describe_successfully(*args, &describe_body)
- example_group = RSpec.describe(*args, &describe_body)
+ example_group = RSpec.describe(*args, &describe_body)
ran_successfully = example_group.run RaiseOnFailuresReporter
expect(ran_successfully).to eq true
example_group
@@ -156,28 +156,51 @@ RSpec.describe QA::Specs::Helpers::Quarantine do
described_class.configure_rspec
end
- it 'is skipped when set on contexts or descriptions' do
- group = describe_successfully 'Quarantined in staging', quarantine: { only: { subdomain: :staging } } do
- it('runs in staging') {}
+ context 'no pipeline specified' do
+ it 'is skipped when set on contexts or descriptions' do
+ group = describe_successfully 'Quarantined in staging', quarantine: { only: { subdomain: :staging } } do
+ it('runs in staging') {}
+ end
+
+ expect(group.examples.first.execution_result.status).to eq(:pending)
+ expect(group.examples.first.execution_result.pending_message)
+ .to eq('In quarantine')
end
- expect(group.examples.first.execution_result.status).to eq(:pending)
- expect(group.examples.first.execution_result.pending_message)
- .to eq('In quarantine')
+ it 'is skipped only in staging' do
+ group = describe_successfully do
+ it('skipped in staging', quarantine: { only: { subdomain: :staging } }) {}
+ it('runs in staging', quarantine: { only: :production }) {}
+ it('skipped in staging also', quarantine: { only: { subdomain: %i[release staging] } }) {}
+ it('runs in any env') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ expect(group.examples[2].execution_result.status).to eq(:pending)
+ expect(group.examples[3].execution_result.status).to eq(:passed)
+ end
end
- it 'is skipped only in staging' do
- group = describe_successfully do
- it('skipped in staging', quarantine: { only: { subdomain: :staging } }) {}
- it('runs in staging', quarantine: { only: :production }) {}
- it('skipped in staging also', quarantine: { only: { subdomain: %i[release staging] } }) {}
- it('runs in any env') {}
+ context 'multiple pipelines specified' do
+ shared_examples 'skipped in project' do |project|
+ before do
+ stub_env('CI_PROJECT_NAME', project)
+ described_class.configure_rspec
+ end
+
+ it "is skipped in #{project}" do
+ group = describe_successfully do
+ it('does not run in specified projects', quarantine: { only: { pipeline: [:staging, :canary, :production] } }) {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ end
end
- expect(group.examples[0].execution_result.status).to eq(:pending)
- expect(group.examples[1].execution_result.status).to eq(:passed)
- expect(group.examples[2].execution_result.status).to eq(:pending)
- expect(group.examples[3].execution_result.status).to eq(:passed)
+ it_behaves_like 'skipped in project', 'STAGING'
+ it_behaves_like 'skipped in project', 'CANARY'
+ it_behaves_like 'skipped in project', 'PRODUCTION'
end
end
@@ -368,8 +391,8 @@ RSpec.describe QA::Specs::Helpers::Quarantine do
it 'runs on a custom environment' do
group = describe_successfully do
- it('runs on release gitlab net', only: { tld: '.net', subdomain: :release, domain: 'gitlab' } ) {}
- it('does not run on release', only: :production ) {}
+ it('runs on release gitlab net', only: { tld: '.net', subdomain: :release, domain: 'gitlab' }) {}
+ it('does not run on release', only: :production) {}
end
expect(group.examples.first.execution_result.status).to eq(:passed)
@@ -384,7 +407,7 @@ RSpec.describe QA::Specs::Helpers::Quarantine do
it 'runs on production' do
group = describe_successfully do
- it('runs on prod', only: :production ) {}
+ it('runs on prod', only: :production) {}
it('does not run in prod', only: { subdomain: :staging }) {}
it('runs in prod and staging', only: { subdomain: /(staging.)?/, domain: 'gitlab' }) {}
end
@@ -412,7 +435,7 @@ RSpec.describe QA::Specs::Helpers::Quarantine do
it 'runs on any pipeline' do
group = describe_successfully do
- it('runs given a single named pipeline', only: { pipeline: :nightly } ) {}
+ it('runs given a single named pipeline', only: { pipeline: :nightly }) {}
it('runs given an array of pipelines', only: { pipeline: [:canary, :not_nightly] }) {}
end
@@ -431,9 +454,9 @@ RSpec.describe QA::Specs::Helpers::Quarantine do
it 'runs on default branch pipelines' do
group = describe_successfully do
- it('runs on master pipeline given a single pipeline', only: { pipeline: :master } ) {}
+ it('runs on master pipeline given a single pipeline', only: { pipeline: :master }) {}
it('runs in master given an array of pipelines', only: { pipeline: [:canary, :master] }) {}
- it('does not run in non-default pipelines', only: { pipeline: [:nightly, :not_nightly, :not_master] } ) {}
+ it('does not run in non-default pipelines', only: { pipeline: [:nightly, :not_nightly, :not_master] }) {}
end
aggregate_failures do
@@ -452,8 +475,8 @@ RSpec.describe QA::Specs::Helpers::Quarantine do
it 'runs on designated pipeline' do
group = describe_successfully do
- it('runs on nightly', only: { pipeline: :nightly } ) {}
- it('does not run in not_nightly', only: { pipeline: :not_nightly } ) {}
+ it('runs on nightly', only: { pipeline: :nightly }) {}
+ it('does not run in not_nightly', only: { pipeline: :not_nightly }) {}
it('runs on nightly given an array', only: { pipeline: [:canary, :nightly] }) {}
it('does not run in not_nightly given an array', only: { pipeline: [:not_nightly, :canary] }) {}
end
diff --git a/qa/spec/support/matchers/have_matcher.rb b/qa/spec/support/matchers/have_matcher.rb
index 43ae27f8796..81288b97e6f 100644
--- a/qa/spec/support/matchers/have_matcher.rb
+++ b/qa/spec/support/matchers/have_matcher.rb
@@ -15,6 +15,7 @@ module Matchers
pipeline
related_issue_item
snippet_description
+ tag
].each do |predicate|
RSpec::Matchers.define "have_#{predicate}" do |*args, **kwargs|
match do |page_object|
diff --git a/qa/spec/support/ssh_spec.rb b/qa/spec/support/ssh_spec.rb
index f4d382f8adc..2edff824fd6 100644
--- a/qa/spec/support/ssh_spec.rb
+++ b/qa/spec/support/ssh_spec.rb
@@ -26,6 +26,16 @@ RSpec.describe QA::Support::SSH do
end
end
+ context 'when no port specified in https uri' do
+ let(:uri) { 'https://foo.com' }
+
+ it 'does not provide port in ssh command' do
+ expect(ssh).to receive(:run).with(expected_ssh_command_no_port, any_args).and_return(result)
+
+ call_method
+ end
+ end
+
context 'when port 80 specified in uri' do
let(:uri) { 'http://foo.com:80' }
@@ -86,6 +96,18 @@ RSpec.describe QA::Support::SSH do
end
end
+ context 'when running on a review app in CI' do
+ let(:uri) { 'https://gitlab-review.app' }
+
+ before do
+ allow(QA::Runtime::Env).to receive(:running_in_ci?).and_return(true)
+ end
+
+ it 'returns git user' do
+ expect(ssh.send(:git_user)).to eq('git')
+ end
+ end
+
context 'when running against environment on a port other than 80 or 443' do
let(:uri) { 'http://localhost:3000' }
diff --git a/qa/tls_certificates/authority/ca.crt b/qa/tls_certificates/authority/ca.crt
new file mode 100644
index 00000000000..8812d718ede
--- /dev/null
+++ b/qa/tls_certificates/authority/ca.crt
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFizCCA3OgAwIBAgIUJBX+SiNuqUYjf33EuMObynTcKx0wDQYJKoZIhvcNAQEL
+BQAwVTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
+DVNhbiBGcmFuY2lzY28xGTAXBgNVBAoMEEdpdExhYiBBdXRob3JpdHkwHhcNMjEw
+MjExMDYyMTUzWhcNMzEwMjA5MDYyMTUzWjBVMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZMBcGA1UECgwQ
+R2l0TGFiIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+ALxpL/dfJwhIWGYK93ovIVj+gqvJI58Sga7eWlp2LpuFQZETjJBA79R0gcwr42ph
+ch1BuxoxkYizM8sqIyFa5aW8SCWmO+IQzedKWZv+UWZg6pG+Fzyp6GO1wmXZdeXw
+xRiXp2qV+rqA8DaL2g1c2u6TB/mcfNTrfsSP3045yQW+4mdNx/g4wBf0dMpHe5DJ
+5jIvowa2O0kesq1UQ1eM9IMNSwW8fMQenV+F41LWE1NO726ksglih9TQjAIrlX6I
+XVmw0lgYegt2G+YQJ68nf2UmvK+C0KqzTZgqmzNMQnuSiJXMnlZvlgdLXTyTWCuq
+tyxp3+Z2Wshk/Cghic2MCm2XwWBIqYGu+20qoPM61c3Rk5++2VOcajD1yCYxVtM2
+akVP/e9arlCdi/CtJh3qvOlj9Uhs6a1UR/ZngpPLOa3r4JazZc04pK7q3ZynmoUL
+oDPF9AKOikvhYKxTYsgZ65VhI3myTBjQFk9qX++z2HF9UImGblqUtckn3eIoI8n2
+wd4pO/OFeFSXpR7jMywCwXTpC8yTTbuVzHEz8H83/qtsbjtw961g4kb8Vzh1zy73
+PFiJNI7hZlP1I5dqNTOAv+GnwiSnF28i7xbdkIfmjYqwcwGhAO7rjifq8ygBH3sF
+0I/6dnw4BvNlSgSJlJ1+2eH1uiaikpuOGtQAttz536dNAgMBAAGjUzBRMB0GA1Ud
+DgQWBBQSNZ46Xu4rfGVIPIQJpduWHJ+AQjAfBgNVHSMEGDAWgBQSNZ46Xu4rfGVI
+PIQJpduWHJ+AQjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQC1
+4REbDKF1tdYeCxpmQHXLHu7OkrgKIea6eKxf8mI+ZsJA4iNr3aiZYU5Wm+uAq3mK
+x6mrQRaqoo6JNbie5Tw8fU2c71EO4t3vwB7YOsBtcV0YrMtg316UE0lk+6kL0TRD
+tV7dAGCB3wXZVLPolC26/kecc258p6h4rCJ8Gi6FsIKGBisTFk3QOdLG3DQNulPF
+2bZaJjs/6HqLL+QMdChUfJP3i71LdNxzwXNPbjJ3fm5f9RNeOcWo6oI2fkQArl2i
+vcP/QtuqeOoJusbeL9zaF/EFlOggjkEtzFWCB05d6J7dMKYp5Lg4eMZQHPw6ycdk
+Ek/XTupvBk+8UiXeHLvX6II9zww9+gm3uycPiO/CSPNw4yQBPPGW+30WznbedsuY
+m79rxuq50KYvseJSPv7lw8v77ajQbRQzFi4frAFR+A1g8FArLxdpIptI9E+ekmaB
+UMhCmi17mEuBtj8Hc3VrokTFtAJV6YNIk1X+Q/zLh4TaR5mm6C/82j/ZvkSm5OX7
+TfaayRWDr7AfDKeG5Amt52BmYncsPUXnOofSz5UkqpeOWr0rKn+A7f2BeUP9R2nY
+6DncxYA+yOgU7RpnMBscsW6SkVIMJKFrfeZ1SbvZGRJd4L1PwfeaU+3yEG6oAfMa
+CFquw23nWhjvUlnCe9BaUiEtOJ2ruGjdu2sdvXPcnw==
+-----END CERTIFICATE-----
diff --git a/qa/tls_certificates/authority/ca.key b/qa/tls_certificates/authority/ca.key
new file mode 100644
index 00000000000..b465551e841
--- /dev/null
+++ b/qa/tls_certificates/authority/ca.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/qa/tls_certificates/authority/ca.pem b/qa/tls_certificates/authority/ca.pem
new file mode 100644
index 00000000000..51c2c7a20e7
--- /dev/null
+++ b/qa/tls_certificates/authority/ca.pem
@@ -0,0 +1,83 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIFizCCA3OgAwIBAgIUJBX+SiNuqUYjf33EuMObynTcKx0wDQYJKoZIhvcNAQEL
+BQAwVTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
+DVNhbiBGcmFuY2lzY28xGTAXBgNVBAoMEEdpdExhYiBBdXRob3JpdHkwHhcNMjEw
+MjExMDYyMTUzWhcNMzEwMjA5MDYyMTUzWjBVMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZMBcGA1UECgwQ
+R2l0TGFiIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+ALxpL/dfJwhIWGYK93ovIVj+gqvJI58Sga7eWlp2LpuFQZETjJBA79R0gcwr42ph
+ch1BuxoxkYizM8sqIyFa5aW8SCWmO+IQzedKWZv+UWZg6pG+Fzyp6GO1wmXZdeXw
+xRiXp2qV+rqA8DaL2g1c2u6TB/mcfNTrfsSP3045yQW+4mdNx/g4wBf0dMpHe5DJ
+5jIvowa2O0kesq1UQ1eM9IMNSwW8fMQenV+F41LWE1NO726ksglih9TQjAIrlX6I
+XVmw0lgYegt2G+YQJ68nf2UmvK+C0KqzTZgqmzNMQnuSiJXMnlZvlgdLXTyTWCuq
+tyxp3+Z2Wshk/Cghic2MCm2XwWBIqYGu+20qoPM61c3Rk5++2VOcajD1yCYxVtM2
+akVP/e9arlCdi/CtJh3qvOlj9Uhs6a1UR/ZngpPLOa3r4JazZc04pK7q3ZynmoUL
+oDPF9AKOikvhYKxTYsgZ65VhI3myTBjQFk9qX++z2HF9UImGblqUtckn3eIoI8n2
+wd4pO/OFeFSXpR7jMywCwXTpC8yTTbuVzHEz8H83/qtsbjtw961g4kb8Vzh1zy73
+PFiJNI7hZlP1I5dqNTOAv+GnwiSnF28i7xbdkIfmjYqwcwGhAO7rjifq8ygBH3sF
+0I/6dnw4BvNlSgSJlJ1+2eH1uiaikpuOGtQAttz536dNAgMBAAGjUzBRMB0GA1Ud
+DgQWBBQSNZ46Xu4rfGVIPIQJpduWHJ+AQjAfBgNVHSMEGDAWgBQSNZ46Xu4rfGVI
+PIQJpduWHJ+AQjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQC1
+4REbDKF1tdYeCxpmQHXLHu7OkrgKIea6eKxf8mI+ZsJA4iNr3aiZYU5Wm+uAq3mK
+x6mrQRaqoo6JNbie5Tw8fU2c71EO4t3vwB7YOsBtcV0YrMtg316UE0lk+6kL0TRD
+tV7dAGCB3wXZVLPolC26/kecc258p6h4rCJ8Gi6FsIKGBisTFk3QOdLG3DQNulPF
+2bZaJjs/6HqLL+QMdChUfJP3i71LdNxzwXNPbjJ3fm5f9RNeOcWo6oI2fkQArl2i
+vcP/QtuqeOoJusbeL9zaF/EFlOggjkEtzFWCB05d6J7dMKYp5Lg4eMZQHPw6ycdk
+Ek/XTupvBk+8UiXeHLvX6II9zww9+gm3uycPiO/CSPNw4yQBPPGW+30WznbedsuY
+m79rxuq50KYvseJSPv7lw8v77ajQbRQzFi4frAFR+A1g8FArLxdpIptI9E+ekmaB
+UMhCmi17mEuBtj8Hc3VrokTFtAJV6YNIk1X+Q/zLh4TaR5mm6C/82j/ZvkSm5OX7
+TfaayRWDr7AfDKeG5Amt52BmYncsPUXnOofSz5UkqpeOWr0rKn+A7f2BeUP9R2nY
+6DncxYA+yOgU7RpnMBscsW6SkVIMJKFrfeZ1SbvZGRJd4L1PwfeaU+3yEG6oAfMa
+CFquw23nWhjvUlnCe9BaUiEtOJ2ruGjdu2sdvXPcnw==
+-----END CERTIFICATE-----