summaryrefslogtreecommitdiff
path: root/qa
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 12:26:25 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 12:26:25 +0000
commita09983ae35713f5a2bbb100981116d31ce99826e (patch)
tree2ee2af7bd104d57086db360a7e6d8c9d5d43667a /qa
parent18c5ab32b738c0b6ecb4d0df3994000482f34bd8 (diff)
downloadgitlab-ce-a09983ae35713f5a2bbb100981116d31ce99826e.tar.gz
Add latest changes from gitlab-org/gitlab@13-2-stable-ee
Diffstat (limited to 'qa')
-rw-r--r--qa/Dockerfile11
-rw-r--r--qa/Gemfile1
-rw-r--r--qa/Gemfile.lock2
-rwxr-xr-xqa/bin/rubymine9
-rw-r--r--qa/qa.rb34
-rw-r--r--qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml338
-rw-r--r--qa/qa/flow/login.rb4
-rw-r--r--qa/qa/git/repository.rb4
-rw-r--r--qa/qa/page/component/ci_badge_link.rb2
-rw-r--r--qa/qa/page/component/dropdown_filter.rb2
-rw-r--r--qa/qa/page/component/issuable/sidebar.rb129
-rw-r--r--qa/qa/page/component/issue_board/show.rb5
-rw-r--r--qa/qa/page/component/new_snippet.rb80
-rw-r--r--qa/qa/page/component/project_selector.rb28
-rw-r--r--qa/qa/page/component/snippet.rb180
-rw-r--r--qa/qa/page/component/web_ide/modal/create_new_file.rb2
-rw-r--r--qa/qa/page/dashboard/snippet/new.rb65
-rw-r--r--qa/qa/page/dashboard/snippet/show.rb97
-rw-r--r--qa/qa/page/group/menu.rb25
-rw-r--r--qa/qa/page/group/milestone/index.rb19
-rw-r--r--qa/qa/page/group/milestone/new.rb29
-rw-r--r--qa/qa/page/group/sub_menus/members.rb14
-rw-r--r--qa/qa/page/issuable/sidebar.rb27
-rw-r--r--qa/qa/page/main/menu.rb9
-rw-r--r--qa/qa/page/main/two_factor_auth.rb22
-rw-r--r--qa/qa/page/merge_request/show.rb18
-rw-r--r--qa/qa/page/milestone/index.rb21
-rw-r--r--qa/qa/page/milestone/new.rb22
-rw-r--r--qa/qa/page/milestone/show.rb33
-rw-r--r--qa/qa/page/modal/delete_wiki.rb17
-rw-r--r--qa/qa/page/profile/two_factor_auth.rb26
-rw-r--r--qa/qa/page/project/issue/index.rb20
-rw-r--r--qa/qa/page/project/issue/jira_import.rb25
-rw-r--r--qa/qa/page/project/issue/show.rb81
-rw-r--r--qa/qa/page/project/job/show.rb3
-rw-r--r--qa/qa/page/project/menu.rb5
-rw-r--r--qa/qa/page/project/milestone/index.rb20
-rw-r--r--qa/qa/page/project/milestone/new.rb29
-rw-r--r--qa/qa/page/project/operations/kubernetes/show.rb33
-rw-r--r--qa/qa/page/project/operations/metrics/show.rb4
-rw-r--r--qa/qa/page/project/pipeline/index.rb4
-rw-r--r--qa/qa/page/project/pipeline/show.rb5
-rw-r--r--qa/qa/page/project/settings/incidents.rb6
-rw-r--r--qa/qa/page/project/settings/operations.rb2
-rw-r--r--qa/qa/page/project/settings/protected_tags.rb46
-rw-r--r--qa/qa/page/project/settings/repository.rb10
-rw-r--r--qa/qa/page/project/settings/runners.rb2
-rw-r--r--qa/qa/page/project/settings/services/jira.rb18
-rw-r--r--qa/qa/page/project/show.rb5
-rw-r--r--qa/qa/page/project/snippet/new.rb3
-rw-r--r--qa/qa/page/project/snippet/show.rb17
-rw-r--r--qa/qa/page/project/sub_menus/issues.rb8
-rw-r--r--qa/qa/page/project/sub_menus/repository.rb15
-rw-r--r--qa/qa/page/project/tag/index.rb19
-rw-r--r--qa/qa/page/project/tag/new.rb41
-rw-r--r--qa/qa/page/project/tag/show.rb29
-rw-r--r--qa/qa/page/project/web_ide/edit.rb17
-rw-r--r--qa/qa/page/project/wiki/edit.rb13
-rw-r--r--qa/qa/page/project/wiki/list.rb23
-rw-r--r--qa/qa/page/project/wiki/show.rb19
-rw-r--r--qa/qa/page/project/wiki/sidebar.rb42
-rw-r--r--qa/qa/resource/api_fabricator.rb14
-rw-r--r--qa/qa/resource/group.rb13
-rw-r--r--qa/qa/resource/group_milestone.rb57
-rw-r--r--qa/qa/resource/issue.rb1
-rw-r--r--qa/qa/resource/members.rb4
-rw-r--r--qa/qa/resource/project.rb6
-rw-r--r--qa/qa/resource/project_milestone.rb20
-rw-r--r--qa/qa/resource/repository/commit.rb24
-rw-r--r--qa/qa/resource/sandbox.rb1
-rw-r--r--qa/qa/resource/user.rb5
-rw-r--r--qa/qa/resource/wiki/project_page.rb2
-rw-r--r--qa/qa/runtime/env.rb42
-rw-r--r--qa/qa/service/praefect_manager.rb176
-rw-r--r--qa/qa/service/shellout.rb7
-rw-r--r--qa/qa/specs/features/api/1_manage/rate_limits_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/users_spec.rb9
-rw-r--r--qa/qa/specs/features/api/2_plan/.gitkeep0
-rw-r--r--qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/repository/changing_repository_storage_spec.rb10
-rw-r--r--qa/qa/specs/features/api/3_create/repository/files_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/repository/praefect_replication_queue_spec.rb64
-rw-r--r--qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb21
-rw-r--r--qa/qa/specs/features/api/4_verify/.gitkeep0
-rw-r--r--qa/qa/specs/features/api/4_verify/pipeline_deletion_spec.rb63
-rw-r--r--qa/qa/specs/features/api/8_monitor/.gitkeep (renamed from qa/qa/specs/features/api/1_manage/.gitkeep)0
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/create_group_with_mattermost_team_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb26
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb110
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb2
-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.rb17
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb109
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb2
-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/collapse_comments_in_discussions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/jira_issue_import_spec.rb77
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb85
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb41
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb41
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/gitaly/high_availability_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/jira/jira_basic_integration_spec.rb23
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb45
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb15
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb24
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb20
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb30
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb16
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb2
-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.rb2
-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/repository/ssh_key_support_spec.rb35
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb81
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb15
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_creation_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_manipulation_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/wiki/project_based_list_spec.rb73
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/wiki/project_based_page_deletion_spec.rb26
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb15
-rw-r--r--qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb4
-rw-r--r--qa/qa/specs/helpers/quarantine.rb34
-rw-r--r--qa/qa/support/dates.rb5
-rw-r--r--qa/qa/support/otp.rb25
-rw-r--r--qa/spec/runtime/api/request_spec.rb6
-rw-r--r--qa/spec/runtime/env_spec.rb42
-rw-r--r--qa/spec/specs/helpers/quarantine_spec.rb123
168 files changed, 2740 insertions, 965 deletions
diff --git a/qa/Dockerfile b/qa/Dockerfile
index 7f90e4bf5bf..6310e4b290d 100644
--- a/qa/Dockerfile
+++ b/qa/Dockerfile
@@ -3,11 +3,10 @@ LABEL maintainer="GitLab Quality Department <quality@gitlab.com>"
ENV DEBIAN_FRONTEND="noninteractive"
ENV DOCKER_VERSION="17.09.0-ce"
-ENV CHROME_VERSION="83.0.4103.61-1"
-ENV CHROME_DRIVER_VERSION="83.0.4103.39"
+ENV CHROME_VERSION="84.0.4147.89-1"
+ENV CHROME_DRIVER_VERSION="84.0.4147.30"
ENV CHROME_DEB="google-chrome-stable_${CHROME_VERSION}_amd64.deb"
ENV CHROME_URL="https://s3.amazonaws.com/gitlab-google-chrome-stable/${CHROME_DEB}"
-ENV K3D_VERSION="1.3.4"
##
# Add support for stretch-backports
@@ -49,12 +48,6 @@ RUN unzip chromedriver_linux64.zip -d /usr/local/bin
RUN rm -f chromedriver_linux64.zip
##
-# Install K3d local cluster support
-# https://github.com/rancher/k3d
-#
-RUN curl -s https://raw.githubusercontent.com/rancher/k3d/master/install.sh | TAG="v${K3D_VERSION}" bash
-
-##
# Install gcloud and kubectl CLI used in Auto DevOps test to create K8s
# clusters
#
diff --git a/qa/Gemfile b/qa/Gemfile
index d5c682ef76f..e2951db534a 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -15,6 +15,7 @@ gem 'rspec_junit_formatter', '~> 0.4.1'
gem 'faker', '~> 1.6', '>= 1.6.6'
gem 'knapsack', '~> 1.17'
gem 'parallel_tests', '~> 2.29'
+gem 'rotp', '~> 3.1.0'
group :test do
gem 'pry-byebug', '~> 3.5.1', platform: :mri
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 23324fccdec..c2b876e3b04 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -78,6 +78,7 @@ GEM
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
+ rotp (3.1.0)
rspec (3.9.0)
rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0)
@@ -129,6 +130,7 @@ DEPENDENCIES
pry-byebug (~> 3.5.1)
rake (~> 12.3.0)
rest-client (~> 2.1.0)
+ rotp (~> 3.1.0)
rspec (~> 3.7)
rspec-retry (~> 0.6.1)
rspec_junit_formatter (~> 0.4.1)
diff --git a/qa/bin/rubymine b/qa/bin/rubymine
new file mode 100755
index 00000000000..0be0cf0ec33
--- /dev/null
+++ b/qa/bin/rubymine
@@ -0,0 +1,9 @@
+#!/usr/bin/env ruby
+
+require_relative '../qa'
+
+ARGV.unshift('Test::Instance::All', ENV['GITLAB_URL'], '--')
+
+QA::Scenario
+ .const_get(ARGV.shift)
+ .launch!(ARGV)
diff --git a/qa/qa.rb b/qa/qa.rb
index 4649f452c6f..823adade6f3 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -79,6 +79,7 @@ module QA
autoload :PersonalAccessToken, 'qa/resource/personal_access_token'
autoload :User, 'qa/resource/user'
autoload :ProjectMilestone, 'qa/resource/project_milestone'
+ autoload :GroupMilestone, 'qa/resource/group_milestone'
autoload :Members, 'qa/resource/members'
autoload :File, 'qa/resource/file'
autoload :Fork, 'qa/resource/fork'
@@ -181,6 +182,7 @@ module QA
autoload :Login, 'qa/page/main/login'
autoload :Menu, 'qa/page/main/menu'
autoload :OAuth, 'qa/page/main/oauth'
+ autoload :TwoFactorAuth, 'qa/page/main/two_factor_auth'
autoload :SignUp, 'qa/page/main/sign_up'
autoload :Terms, 'qa/page/main/terms'
end
@@ -207,6 +209,11 @@ module QA
autoload :Show, 'qa/page/group/show'
autoload :Menu, 'qa/page/group/menu'
+ module Milestone
+ autoload :Index, 'qa/page/group/milestone/index'
+ autoload :New, 'qa/page/group/milestone/new'
+ end
+
module SubMenus
autoload :Common, 'qa/page/group/sub_menus/common'
autoload :Members, 'qa/page/group/sub_menus/members'
@@ -217,6 +224,12 @@ module QA
end
end
+ module Milestone
+ autoload :Index, 'qa/page/milestone/index'
+ autoload :New, 'qa/page/milestone/new'
+ autoload :Show, 'qa/page/milestone/show'
+ end
+
module File
autoload :Form, 'qa/page/file/form'
autoload :Show, 'qa/page/file/show'
@@ -254,6 +267,12 @@ module QA
autoload :Show, 'qa/page/project/pipeline/show'
end
+ module Tag
+ autoload :Index, 'qa/page/project/tag/index'
+ autoload :New, 'qa/page/project/tag/new'
+ autoload :Show, 'qa/page/project/tag/show'
+ end
+
module Job
autoload :Show, 'qa/page/project/job/show'
end
@@ -273,6 +292,7 @@ module QA
autoload :Runners, 'qa/page/project/settings/runners'
autoload :MergeRequest, 'qa/page/project/settings/merge_request'
autoload :MirroringRepositories, 'qa/page/project/settings/mirroring_repositories'
+ autoload :ProtectedTags, 'qa/page/project/settings/protected_tags'
autoload :VisibilityFeaturesPermissions, 'qa/page/project/settings/visibility_features_permissions'
module Services
@@ -301,6 +321,7 @@ module QA
autoload :New, 'qa/page/project/issue/new'
autoload :Show, 'qa/page/project/issue/show'
autoload :Index, 'qa/page/project/issue/index'
+ autoload :JiraImport, 'qa/page/project/issue/jira_import'
end
module Fork
@@ -334,6 +355,8 @@ 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
module WebIDE
@@ -342,6 +365,7 @@ module QA
module Snippet
autoload :New, 'qa/page/project/snippet/new'
+ autoload :Show, 'qa/page/project/snippet/show'
end
end
@@ -356,7 +380,6 @@ module QA
module Issuable
autoload :New, 'qa/page/issuable/new'
- autoload :Sidebar, 'qa/page/issuable/sidebar'
end
module Alert
@@ -439,9 +462,13 @@ module QA
autoload :ConfirmModal, 'qa/page/component/confirm_modal'
autoload :CustomMetric, 'qa/page/component/custom_metric'
autoload :DesignManagement, 'qa/page/component/design_management'
+ autoload :ProjectSelector, 'qa/page/component/project_selector'
+ autoload :Snippet, 'qa/page/component/snippet'
+ autoload :NewSnippet, 'qa/page/component/new_snippet'
module Issuable
autoload :Common, 'qa/page/component/issuable/common'
+ autoload :Sidebar, 'qa/page/component/issuable/sidebar'
end
module IssueBoard
@@ -460,6 +487,10 @@ module QA
autoload :Templates, 'qa/page/component/project/templates'
end
end
+
+ module Modal
+ autoload :DeleteWiki, 'qa/page/modal/delete_wiki'
+ end
end
##
@@ -555,6 +586,7 @@ module QA
autoload :Retrier, 'qa/support/retrier'
autoload :Waiter, 'qa/support/waiter'
autoload :WaitForRequests, 'qa/support/wait_for_requests'
+ autoload :OTP, 'qa/support/otp'
end
end
diff --git a/qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml b/qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml
deleted file mode 100644
index 052ba1c14fb..00000000000
--- a/qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml
+++ /dev/null
@@ -1,338 +0,0 @@
-# This is stripped down version of the .gitlab-ci.yml found
-# here: https://gitlab.com/joshlambert/autodevops-deploy.
-#
-# It performs only the deploy stage.
-
-image: alpine:latest
-
-variables:
- # AUTO_DEVOPS_DOMAIN is the application deployment domain and should be set as a variable at the group or project level.
- AUTO_DEVOPS_DOMAIN: $AUTO_DEVOPS_DOMAIN
-
- POSTGRES_USER: user
- POSTGRES_PASSWORD: testing-password
- POSTGRES_ENABLED: 'false'
- POSTGRES_DB: $CI_ENVIRONMENT_SLUG
-
- KUBERNETES_VERSION: 1.11.6
- HELM_VERSION: 2.12.2
-
- DOCKER_DRIVER: overlay2
-
-stages:
- - production
-
-# This job continuously deploys to production on every push to `master`.
-
-production:
- stage: production
- tags:
- - qa
- script:
- - check_kube_domain
- - install_dependencies
- - download_chart
- - ensure_namespace
- - initialize_tiller
- - create_secret
- - deploy
- environment:
- name: production
- url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN
- artifacts:
- paths: [environment_url.txt]
- only:
- refs:
- - master
- kubernetes: active
-
-# ---------------------------------------------------------------------------
-
-.auto_devops: &auto_devops |
- # Auto DevOps variables and functions
- [[ "$TRACE" ]] && set -x
- auto_database_url=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${CI_ENVIRONMENT_SLUG}-postgres:5432/${POSTGRES_DB}
- export DATABASE_URL=${DATABASE_URL-$auto_database_url}
- export CI_APPLICATION_REPOSITORY=$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG
- export CI_APPLICATION_TAG=$CI_COMMIT_SHA
- export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID}
- export TILLER_NAMESPACE=$KUBE_NAMESPACE
- # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable" for Security Products
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
-
-
- function get_replicas() {
- track="${1:-stable}"
- percentage="${2:-100}"
-
- env_track=$( echo $track | tr -s '[:lower:]' '[:upper:]' )
- env_slug=$( echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]' )
-
- if [[ "$track" == "stable" ]] || [[ "$track" == "rollout" ]]; then
- # for stable track get number of replicas from `PRODUCTION_REPLICAS`
- eval new_replicas=\$${env_slug}_REPLICAS
- if [[ -z "$new_replicas" ]]; then
- new_replicas=$REPLICAS
- fi
- else
- # for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS`
- eval new_replicas=\$${env_track}_${env_slug}_REPLICAS
- if [[ -z "$new_replicas" ]]; then
- eval new_replicas=\${env_track}_REPLICAS
- fi
- fi
-
- replicas="${new_replicas:-1}"
- replicas="$(($replicas * $percentage / 100))"
-
- # always return at least one replicas
- if [[ $replicas -gt 0 ]]; then
- echo "$replicas"
- else
- echo 1
- fi
- }
-
-
- # Extracts variables prefixed with K8S_SECRET_
- # and creates a Kubernetes secret.
- #
- # e.g. If we have the following environment variables:
- # K8S_SECRET_A=value1
- # K8S_SECRET_B=multi\ word\ value
- #
- # Then we will create a secret with the following key-value pairs:
- # data:
- # A: dmFsdWUxCg==
- # B: bXVsdGkgd29yZCB2YWx1ZQo=
- function create_application_secret() {
- track="${1-stable}"
- export APPLICATION_SECRET_NAME=$(application_secret_name "$track")
-
- env | sed -n "s/^K8S_SECRET_\(.*\)$/\1/p" > k8s_prefixed_variables
-
- kubectl create secret \
- -n "$KUBE_NAMESPACE" generic "$APPLICATION_SECRET_NAME" \
- --from-env-file k8s_prefixed_variables -o yaml --dry-run |
- kubectl replace -n "$KUBE_NAMESPACE" --force -f -
-
- export APPLICATION_SECRET_CHECKSUM=$(cat k8s_prefixed_variables | sha256sum | cut -d ' ' -f 1)
-
- rm k8s_prefixed_variables
- }
-
- function deploy_name() {
- name="$CI_ENVIRONMENT_SLUG"
- track="${1-stable}"
-
- if [[ "$track" != "stable" ]]; then
- name="$name-$track"
- fi
-
- echo $name
- }
-
- function application_secret_name() {
- track="${1-stable}"
- name=$(deploy_name "$track")
-
- echo "${name}-secret"
- }
-
-
- function deploy() {
- track="${1-stable}"
- percentage="${2:-100}"
- name=$(deploy_name "$track")
-
- replicas="1"
- service_enabled="true"
- postgres_enabled="$POSTGRES_ENABLED"
-
- # if track is different than stable,
- # re-use all attached resources
- if [[ "$track" != "stable" ]]; then
- service_enabled="false"
- postgres_enabled="false"
- fi
-
- replicas=$(get_replicas "$track" "$percentage")
-
- if [[ "$CI_PROJECT_VISIBILITY" != "public" ]]; then
- secret_name='gitlab-registry'
- else
- secret_name=''
- fi
-
- create_application_secret "$track"
-
- env_slug=$(echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]')
- eval env_ADDITIONAL_HOSTS=\$${env_slug}_ADDITIONAL_HOSTS
- if [ -n "$env_ADDITIONAL_HOSTS" ]; then
- additional_hosts="{$env_ADDITIONAL_HOSTS}"
- elif [ -n "$ADDITIONAL_HOSTS" ]; then
- additional_hosts="{$ADDITIONAL_HOSTS}"
- fi
-
- if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then
- echo "Deploying first release with database initialization..."
- helm upgrade --install \
- --wait \
- --set service.enabled="$service_enabled" \
- --set releaseOverride="$CI_ENVIRONMENT_SLUG" \
- --set image.repository="registry.gitlab.com/joshlambert/ruby-gke/master" \
- --set image.tag="63492726c2264a0277141d6a6573c3d22ecd7de3" \
- --set image.pullPolicy=IfNotPresent \
- --set image.secrets[0].name="$secret_name" \
- --set application.track="$track" \
- --set application.database_url="$DATABASE_URL" \
- --set application.secretName="$APPLICATION_SECRET_NAME" \
- --set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \
- --set service.url="$CI_ENVIRONMENT_URL" \
- --set service.additionalHosts="$additional_hosts" \
- --set replicaCount="$replicas" \
- --set postgresql.enabled="$postgres_enabled" \
- --set postgresql.nameOverride="postgres" \
- --set postgresql.postgresUser="$POSTGRES_USER" \
- --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \
- --set postgresql.postgresDatabase="$POSTGRES_DB" \
- --set application.initializeCommand="$DB_INITIALIZE" \
- --set gitlab.app="$CI_PROJECT_PATH_SLUG" \
- --set gitlab.env="$CI_ENVIRONMENT_SLUG" \
- --namespace="$KUBE_NAMESPACE" \
- "$name" \
- chart/
-
- echo "Deploying second release..."
- helm upgrade --reuse-values \
- --wait \
- --set application.initializeCommand="" \
- --set application.migrateCommand="$DB_MIGRATE" \
- --namespace="$KUBE_NAMESPACE" \
- "$name" \
- chart/
- else
- echo "Deploying new release..."
- helm upgrade --install \
- --wait \
- --set service.enabled="$service_enabled" \
- --set releaseOverride="$CI_ENVIRONMENT_SLUG" \
- --set image.repository="registry.gitlab.com/joshlambert/ruby-gke/master" \
- --set image.tag="63492726c2264a0277141d6a6573c3d22ecd7de3" \
- --set image.pullPolicy=IfNotPresent \
- --set image.secrets[0].name="$secret_name" \
- --set application.track="$track" \
- --set application.database_url="$DATABASE_URL" \
- --set application.secretName="$APPLICATION_SECRET_NAME" \
- --set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \
- --set service.url="$CI_ENVIRONMENT_URL" \
- --set service.additionalHosts="$additional_hosts" \
- --set replicaCount="$replicas" \
- --set postgresql.enabled="$postgres_enabled" \
- --set postgresql.nameOverride="postgres" \
- --set postgresql.postgresUser="$POSTGRES_USER" \
- --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \
- --set postgresql.postgresDatabase="$POSTGRES_DB" \
- --set application.migrateCommand="$DB_MIGRATE" \
- --set gitlab.app="$CI_PROJECT_PATH_SLUG" \
- --set gitlab.env="$CI_ENVIRONMENT_SLUG" \
- --namespace="$KUBE_NAMESPACE" \
- "$name" \
- chart/
- fi
-
- kubectl rollout status -n "$KUBE_NAMESPACE" -w "deployment/$name"
- }
-
-
- function install_dependencies() {
- apk add -U openssl curl tar gzip bash ca-certificates git
- wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
- wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.23-r3/glibc-2.23-r3.apk
- apk add glibc-2.23-r3.apk
- rm glibc-2.23-r3.apk
-
- curl "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx
- mv linux-amd64/helm /usr/bin/
- mv linux-amd64/tiller /usr/bin/
- helm version --client
- tiller -version
-
- curl -L -o /usr/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl"
- chmod +x /usr/bin/kubectl
- kubectl version --client
- }
-
- function download_chart() {
- if [[ ! -d chart ]]; then
- auto_chart=${AUTO_DEVOPS_CHART:-gitlab/auto-deploy-app}
- auto_chart_name=$(basename $auto_chart)
- auto_chart_name=${auto_chart_name%.tgz}
- else
- auto_chart="chart"
- auto_chart_name="chart"
- fi
-
- helm init --client-only
- helm repo add gitlab https://charts.gitlab.io
- if [[ ! -d "$auto_chart" ]]; then
- helm fetch ${auto_chart} --untar
- fi
- if [ "$auto_chart_name" != "chart" ]; then
- mv ${auto_chart_name} chart
- fi
-
- helm dependency update chart/
- helm dependency build chart/
- }
-
- function ensure_namespace() {
- kubectl describe namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE"
- }
-
- function check_kube_domain() {
- if [ -z ${AUTO_DEVOPS_DOMAIN+x} ]; then
- echo "In order to deploy or use Review Apps, AUTO_DEVOPS_DOMAIN variable must be set"
- echo "You can do it in Auto DevOps project settings or defining a secret variable at group or project level"
- echo "You can also manually add it in .gitlab-ci.yml"
- false
- else
- true
- fi
- }
-
- function initialize_tiller() {
- echo "Checking Tiller..."
-
- export HELM_HOST="localhost:44134"
- tiller -listen ${HELM_HOST} -alsologtostderr > /dev/null 2>&1 &
- echo "Tiller is listening on ${HELM_HOST}"
-
- if ! helm version --debug; then
- echo "Failed to init Tiller."
- return 1
- fi
- echo ""
- }
-
- function create_secret() {
- echo "Create secret..."
- if [[ "$CI_PROJECT_VISIBILITY" == "public" ]]; then
- return
- fi
-
- kubectl create secret -n "$KUBE_NAMESPACE" \
- docker-registry gitlab-registry \
- --docker-server="$CI_REGISTRY" \
- --docker-username="$CI_REGISTRY_USER" \
- --docker-password="$CI_REGISTRY_PASSWORD" \
- --docker-email="$GITLAB_USER_EMAIL" \
- -o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f -
- }
-
- function persist_environment_url() {
- echo $CI_ENVIRONMENT_URL > environment_url.txt
- }
-
-before_script:
- - *auto_devops
diff --git a/qa/qa/flow/login.rb b/qa/qa/flow/login.rb
index 8ad303df4de..d4d5cc2dcfc 100644
--- a/qa/qa/flow/login.rb
+++ b/qa/qa/flow/login.rb
@@ -22,9 +22,9 @@ module QA
end
end
- def sign_in(as: nil, address: :gitlab)
+ def sign_in(as: nil, address: :gitlab, skip_page_validation: false)
Runtime::Browser.visit(address, Page::Main::Login)
- Page::Main::Login.perform { |login| login.sign_in_using_credentials(user: as) }
+ Page::Main::Login.perform { |login| login.sign_in_using_credentials(user: as, skip_page_validation: skip_page_validation) }
end
def sign_in_as_admin(address: :gitlab)
diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb
index 43608827b2e..2c8e362edd6 100644
--- a/qa/qa/git/repository.rb
+++ b/qa/qa/git/repository.rb
@@ -118,6 +118,10 @@ module QA
run("git push #{uri} #{branch}", max_attempts: 3).to_s
end
+ def push_all_branches
+ run("git push --all").to_s
+ end
+
def merge(branch)
run("git merge #{branch}")
end
diff --git a/qa/qa/page/component/ci_badge_link.rb b/qa/qa/page/component/ci_badge_link.rb
index 8629399e911..4c053f1d6a9 100644
--- a/qa/qa/page/component/ci_badge_link.rb
+++ b/qa/qa/page/component/ci_badge_link.rb
@@ -43,7 +43,7 @@ module QA
private
def completed?(timeout: 60)
- wait_until(reload: false, max_duration: timeout) do
+ wait_until(reload: false, sleep_interval: 3.0, max_duration: timeout) do
COMPLETED_STATUSES.include?(status_badge)
end
end
diff --git a/qa/qa/page/component/dropdown_filter.rb b/qa/qa/page/component/dropdown_filter.rb
index a39a04a668d..30c6f13eaf7 100644
--- a/qa/qa/page/component/dropdown_filter.rb
+++ b/qa/qa/page/component/dropdown_filter.rb
@@ -8,7 +8,7 @@ module QA
page.has_css?('.dropdown-input-field', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
find('.dropdown-input-field').set(item)
- click_link item
+ click_on item
end
end
end
diff --git a/qa/qa/page/component/issuable/sidebar.rb b/qa/qa/page/component/issuable/sidebar.rb
new file mode 100644
index 00000000000..4e94049efe7
--- /dev/null
+++ b/qa/qa/page/component/issuable/sidebar.rb
@@ -0,0 +1,129 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module Issuable
+ module Sidebar
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue' do
+ element :avatar_image
+ end
+
+ base.view 'app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue' do
+ element :more_assignees_link
+ end
+
+ base.view 'app/helpers/dropdowns_helper.rb' do
+ element :dropdown_input_field
+ end
+
+ base.view 'app/views/shared/issuable/_sidebar.html.haml' do
+ element :assignee_block
+ element :dropdown_menu_labels
+ element :edit_labels_link
+ element :edit_milestone_link
+ element :labels_block
+ element :milestone_block
+ element :milestone_link
+ end
+ end
+
+ def assign_milestone(milestone)
+ click_element(:edit_milestone_link)
+ within_element(:milestone_block) do
+ click_link("#{milestone.title}")
+ end
+
+ wait_until(reload: false) do
+ has_element?(:milestone_block, text: milestone.title, wait: 0)
+ end
+
+ refresh
+ end
+
+ def click_milestone_link
+ click_element(:milestone_link)
+ end
+
+ def has_assignee?(username)
+ page.within(element_selector_css(:assignee_block)) do
+ has_text?(username)
+ end
+ end
+
+ def has_avatar_image_count?(count)
+ wait_assignees_block_finish_loading do
+ all_elements(:avatar_image, count: count)
+ end
+ end
+
+ def has_label?(label)
+ within_element(:labels_block) do
+ !!has_element?(:label, label_name: label)
+ end
+ end
+
+ def has_milestone?(milestone_title)
+ wait_milestone_block_finish_loading do
+ has_element?(:milestone_link, title: milestone_title)
+ end
+ end
+
+ def more_assignees_link
+ find_element(:more_assignees_link)
+ end
+
+ def select_labels_and_refresh(labels)
+ Support::Retrier.retry_until do
+ click_element(:edit_labels_link)
+ has_element?(:dropdown_menu_labels, text: labels.first)
+ end
+
+ labels.each do |label|
+ within_element(:dropdown_menu_labels, text: label) do
+ send_keys_to_element(:dropdown_input_field, [label, :enter])
+ end
+ end
+
+ click_element(:edit_labels_link)
+
+ labels.each do |label|
+ has_element?(:labels_block, text: label, wait: 0)
+ end
+
+ refresh
+ end
+
+ def toggle_more_assignees_link
+ click_element(:more_assignees_link)
+ end
+
+ private
+
+ def wait_assignees_block_finish_loading
+ within_element(:assignee_block) do
+ wait_until(reload: false, max_duration: 10, sleep_interval: 1) do
+ finished_loading_block?
+ yield
+ end
+ end
+ end
+
+ def wait_milestone_block_finish_loading
+ within_element(:milestone_block) do
+ wait_until(reload: false, max_duration: 10, sleep_interval: 1) do
+ finished_loading_block?
+ yield
+ end
+ end
+ end
+ 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 0c840eba7ce..9e843630115 100644
--- a/qa/qa/page/component/issue_board/show.rb
+++ b/qa/qa/page/component/issue_board/show.rb
@@ -39,11 +39,6 @@ module QA
element :boards_list
end
- view 'app/views/shared/boards/components/_board.html.haml' do
- element :board_list
- element :board_list_header
- end
-
view 'app/assets/javascripts/boards/toggle_focus.js' do
element :focus_mode_button
end
diff --git a/qa/qa/page/component/new_snippet.rb b/qa/qa/page/component/new_snippet.rb
new file mode 100644
index 00000000000..18f2e237097
--- /dev/null
+++ b/qa/qa/page/component/new_snippet.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module NewSnippet
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/assets/javascripts/snippets/components/edit.vue' do
+ element :snippet_title_field, required: true
+ element :submit_button
+ end
+
+ base.view 'app/assets/javascripts/snippets/components/snippet_description_edit.vue' do
+ element :snippet_description_field
+ element :description_placeholder, required: true
+ end
+
+ base.view 'app/assets/javascripts/snippets/components/snippet_blob_edit.vue' do
+ element :file_name_field
+ end
+
+ base.view 'app/views/shared/form_elements/_description.html.haml' do
+ element :issuable_form_description
+ end
+
+ base.view 'app/views/shared/snippets/_form.html.haml' do
+ element :snippet_description_field
+ element :description_placeholder
+ element :snippet_title_field
+ element :file_name_field
+ element :submit_button
+ end
+
+ base.view 'app/views/shared/_zen.html.haml' do
+ # 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
+ end
+
+ def fill_title(title)
+ fill_element :snippet_title_field, title
+ end
+
+ def fill_description(description)
+ click_element :description_placeholder
+ fill_element :snippet_description_field, description
+ end
+
+ def set_visibility(visibility)
+ choose visibility
+ end
+
+ def fill_file_name(name)
+ finished_loading?
+ fill_element :file_name_field, name
+ end
+
+ def fill_file_content(content)
+ finished_loading?
+ text_area.set content
+ end
+
+ def click_create_snippet_button
+ wait_until(reload: false) { !find_element(:submit_button).disabled? }
+ click_element(:submit_button, Page::Dashboard::Snippet::Show)
+ end
+
+ private
+
+ def text_area
+ find('#editor textarea', visible: false)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/component/project_selector.rb b/qa/qa/page/component/project_selector.rb
new file mode 100644
index 00000000000..80ed6b8e53b
--- /dev/null
+++ b/qa/qa/page/component/project_selector.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module ProjectSelector
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/assets/javascripts/vue_shared/components/project_selector/project_selector.vue' do
+ element :project_search_field
+ element :project_list_item
+ end
+ end
+
+ def fill_project_search_input(project_name)
+ fill_element :project_search_field, project_name
+ end
+
+ def select_project
+ click_element :project_list_item
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/component/snippet.rb b/qa/qa/page/component/snippet.rb
new file mode 100644
index 00000000000..4ff19c01f1f
--- /dev/null
+++ b/qa/qa/page/component/snippet.rb
@@ -0,0 +1,180 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module Snippet
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/assets/javascripts/snippets/components/snippet_title.vue' do
+ element :snippet_title_content, required: true
+ end
+
+ base.view 'app/assets/javascripts/snippets/components/snippet_description_view.vue' do
+ element :snippet_description_content
+ end
+
+ base.view 'app/assets/javascripts/snippets/components/snippet_header.vue' do
+ element :snippet_container
+ end
+
+ base.view 'app/assets/javascripts/blob/components/blob_header_filepath.vue' do
+ element :file_title_content
+ end
+
+ base.view 'app/assets/javascripts/vue_shared/components/blob_viewers/simple_viewer.vue' do
+ element :file_content
+ end
+
+ base.view 'app/assets/javascripts/blob/components/blob_content.vue' do
+ element :file_content
+ end
+
+ base.view 'app/assets/javascripts/snippets/components/snippet_header.vue' do
+ element :snippet_action_button
+ element :delete_snippet_button
+ end
+
+ base.view 'app/assets/javascripts/snippets/components/snippet_blob_view.vue' do
+ element :clone_button
+ end
+
+ base.view 'app/assets/javascripts/vue_shared/components/clone_dropdown.vue' do
+ element :copy_http_url_button
+ element :copy_ssh_url_button
+ end
+
+ base.view 'app/views/shared/notes/_comment_button.html.haml' do
+ element :comment_button
+ end
+
+ base.view 'app/views/shared/notes/_form.html.haml' do
+ element :note_field
+ end
+
+ base.view 'app/views/snippets/notes/_actions.html.haml' do
+ element :edit_comment_button
+ end
+
+ base.view 'app/views/shared/notes/_edit_form.html.haml' do
+ element :edit_note_field
+ element :save_comment_button
+ end
+
+ base.view 'app/views/shared/notes/_note.html.haml' do
+ element :note_content
+ element :note_author_content
+ end
+
+ base.view 'app/views/projects/notes/_more_actions_dropdown.html.haml' do
+ element :more_actions_dropdown
+ element :delete_comment_button
+ end
+ end
+
+ def has_snippet_title?(snippet_title)
+ has_element? :snippet_title_content, text: snippet_title
+ end
+
+ def has_snippet_description?(snippet_description)
+ has_element? :snippet_description_content, text: snippet_description
+ end
+
+ def has_no_snippet_description?
+ has_no_element?(:snippet_description_field)
+ end
+
+ def has_visibility_type?(visibility_type)
+ within_element(:snippet_container) do
+ has_text?(visibility_type)
+ end
+ end
+
+ def has_file_name?(file_name)
+ within_element(:file_title_content) do
+ has_text?(file_name)
+ end
+ end
+
+ def has_file_content?(file_content)
+ finished_loading?
+ within_element(:file_content) do
+ has_text?(file_content)
+ end
+ end
+
+ def click_edit_button
+ finished_loading?
+ click_element(:snippet_action_button, action: 'Edit')
+ end
+
+ def click_delete_button
+ finished_loading?
+ click_element(:snippet_action_button, action: 'Delete')
+ click_element(:delete_snippet_button)
+ # wait for the page to reload after deletion
+ wait_until(reload: false) do
+ has_no_element?(:delete_snippet_button) &&
+ has_no_element?(:snippet_action_button, action: 'Delete')
+ end
+ end
+
+ def get_repository_uri_http
+ finished_loading?
+ click_element(:clone_button)
+ Git::Location.new(find_element(:copy_http_url_button)['data-clipboard-text']).uri.to_s
+ end
+
+ def get_repository_uri_ssh
+ finished_loading?
+ click_element(:clone_button)
+ Git::Location.new(find_element(:copy_ssh_url_button)['data-clipboard-text']).uri.to_s
+ end
+
+ def add_comment(comment)
+ finished_loading?
+ fill_element(:note_field, comment)
+ click_element(:comment_button)
+ end
+
+ def has_comment_author?(author_username)
+ finished_loading?
+ within_element(:note_author_content) do
+ has_text?('@' + author_username)
+ end
+ end
+
+ def has_comment_content?(comment_content)
+ finished_loading?
+ within_element(:note_content) do
+ has_text?(comment_content)
+ end
+ end
+
+ def has_syntax_highlighting?(language)
+ within_element(:file_content) do
+ find('.line')['lang'].to_s == language
+ end
+ end
+
+ def edit_comment(comment)
+ finished_loading?
+ click_element(:edit_comment_button)
+ fill_element(:edit_note_field, comment)
+ click_element(:save_comment_button)
+ end
+
+ def delete_comment(comment)
+ finished_loading?
+ click_element(:more_actions_dropdown)
+ accept_alert do
+ click_element(:delete_comment_button)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/component/web_ide/modal/create_new_file.rb b/qa/qa/page/component/web_ide/modal/create_new_file.rb
index 48eb32fefd6..7c55f775476 100644
--- a/qa/qa/page/component/web_ide/modal/create_new_file.rb
+++ b/qa/qa/page/component/web_ide/modal/create_new_file.rb
@@ -9,7 +9,7 @@ module QA
view 'app/assets/javascripts/ide/components/new_dropdown/modal.vue' do
element :file_name_field, required: true
element :new_file_modal, required: true
- element :template_list, required: true
+ element :template_list
end
end
end
diff --git a/qa/qa/page/dashboard/snippet/new.rb b/qa/qa/page/dashboard/snippet/new.rb
index bcfb4734b59..683e118aa19 100644
--- a/qa/qa/page/dashboard/snippet/new.rb
+++ b/qa/qa/page/dashboard/snippet/new.rb
@@ -5,70 +5,7 @@ module QA
module Dashboard
module Snippet
class New < Page::Base
- view 'app/assets/javascripts/snippets/components/edit.vue' do
- element :snippet_title_field, required: true
- element :submit_button
- end
-
- view 'app/assets/javascripts/snippets/components/snippet_description_edit.vue' do
- element :snippet_description_field
- element :description_placeholder, required: true
- end
-
- view 'app/assets/javascripts/snippets/components/snippet_blob_edit.vue' do
- element :file_name_field
- end
-
- view 'app/views/shared/form_elements/_description.html.haml' do
- element :issuable_form_description
- end
-
- view 'app/views/shared/snippets/_form.html.haml' do
- element :snippet_description_field
- element :description_placeholder
- element :snippet_title_field
- element :file_name_field
- element :submit_button
- end
-
- view 'app/views/shared/_zen.html.haml' do
- # 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
-
- def fill_title(title)
- fill_element :snippet_title_field, title
- end
-
- def fill_description(description)
- click_element :description_placeholder
- fill_element :snippet_description_field, description
- end
-
- def set_visibility(visibility)
- choose visibility
- end
-
- def fill_file_name(name)
- finished_loading?
- fill_element :file_name_field, name
- end
-
- def fill_file_content(content)
- finished_loading?
- text_area.set content
- end
-
- def click_create_snippet_button
- wait_until(reload: false) { !find_element(:submit_button).disabled? }
- click_element :submit_button
- end
-
- private
-
- def text_area
- find('#editor textarea', visible: false)
- end
+ include Page::Component::NewSnippet
end
end
end
diff --git a/qa/qa/page/dashboard/snippet/show.rb b/qa/qa/page/dashboard/snippet/show.rb
index da494ae70ec..73e6abe174f 100644
--- a/qa/qa/page/dashboard/snippet/show.rb
+++ b/qa/qa/page/dashboard/snippet/show.rb
@@ -5,102 +5,7 @@ module QA
module Dashboard
module Snippet
class Show < Page::Base
- view 'app/assets/javascripts/snippets/components/snippet_description_view.vue' do
- element :snippet_description_content
- end
-
- view 'app/assets/javascripts/snippets/components/snippet_title.vue' do
- element :snippet_title_content, required: true
- end
-
- view 'app/assets/javascripts/snippets/components/snippet_header.vue' do
- element :snippet_container
- end
-
- view 'app/assets/javascripts/blob/components/blob_header_filepath.vue' do
- element :file_title_content
- end
-
- view 'app/assets/javascripts/vue_shared/components/blob_viewers/simple_viewer.vue' do
- element :file_content
- end
-
- view 'app/assets/javascripts/blob/components/blob_content.vue' do
- element :file_content
- end
-
- view 'app/assets/javascripts/snippets/components/snippet_header.vue' do
- element :snippet_action_button
- element :delete_snippet_button
- end
-
- view 'app/assets/javascripts/snippets/components/snippet_blob_view.vue' do
- element :clone_button
- end
-
- view 'app/assets/javascripts/vue_shared/components/clone_dropdown.vue' do
- element :copy_http_url_button
- element :copy_ssh_url_button
- end
-
- def has_snippet_title?(snippet_title)
- has_element? :snippet_title_content, text: snippet_title
- end
-
- def has_snippet_description?(snippet_description)
- has_element? :snippet_description_content, text: snippet_description
- end
-
- def has_no_snippet_description?
- has_no_element?(:snippet_description_field)
- end
-
- def has_visibility_type?(visibility_type)
- within_element(:snippet_container) do
- has_text?(visibility_type)
- end
- end
-
- def has_file_name?(file_name)
- within_element(:file_title_content) do
- has_text?(file_name)
- end
- end
-
- def has_file_content?(file_content)
- finished_loading?
- within_element(:file_content) do
- has_text?(file_content)
- end
- end
-
- def click_edit_button
- finished_loading?
- click_element(:snippet_action_button, action: 'Edit')
- end
-
- def click_delete_button
- finished_loading?
- click_element(:snippet_action_button, action: 'Delete')
- click_element(:delete_snippet_button)
- # wait for the page to reload after deletion
- wait_until(reload: false) do
- has_no_element?(:delete_snippet_button) &&
- has_no_element?(:snippet_action_button, action: 'Delete')
- end
- end
-
- def get_repository_uri_http
- finished_loading?
- click_element(:clone_button)
- Git::Location.new(find_element(:copy_http_url_button)['data-clipboard-text']).uri.to_s
- end
-
- def get_repository_uri_ssh
- finished_loading?
- click_element(:clone_button)
- Git::Location.new(find_element(:copy_ssh_url_button)['data-clipboard-text']).uri.to_s
- end
+ include Page::Component::Snippet
end
end
end
diff --git a/qa/qa/page/group/menu.rb b/qa/qa/page/group/menu.rb
index 380984c283e..7689dd7e5c8 100644
--- a/qa/qa/page/group/menu.rb
+++ b/qa/qa/page/group/menu.rb
@@ -7,9 +7,11 @@ module QA
include SubMenus::Common
view 'app/views/layouts/nav/sidebar/_group.html.haml' do
- element :group_settings_item
- element :group_members_item
element :general_settings_link
+ element :group_issues_item
+ element :group_members_item
+ element :group_milestones_link
+ element :group_settings_item
end
view 'app/views/layouts/nav/sidebar/_analytics_links.html.haml' do
@@ -44,6 +46,25 @@ module QA
end
end
end
+
+ def go_to_milestones
+ hover_issues do
+ within_submenu do
+ click_element(:group_milestones_link)
+ end
+ end
+ end
+
+ private
+
+ def hover_issues
+ within_sidebar do
+ scroll_to_element(:group_issues_item)
+ find_element(:group_issues_item).hover
+
+ yield
+ end
+ end
end
end
end
diff --git a/qa/qa/page/group/milestone/index.rb b/qa/qa/page/group/milestone/index.rb
new file mode 100644
index 00000000000..a86772a070d
--- /dev/null
+++ b/qa/qa/page/group/milestone/index.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module Milestone
+ class Index < Page::Milestone::Index
+ view 'app/views/groups/milestones/index.html.haml' do
+ element :new_group_milestone_link
+ end
+
+ def click_new_milestone_link
+ click_element(:new_group_milestone_link)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/group/milestone/new.rb b/qa/qa/page/group/milestone/new.rb
new file mode 100644
index 00000000000..451117a2163
--- /dev/null
+++ b/qa/qa/page/group/milestone/new.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module Milestone
+ class New < Page::Milestone::New
+ view 'app/views/groups/milestones/_form.html.haml' do
+ element :create_milestone_button
+ element :milestone_description_field
+ element :milestone_title_field
+ end
+
+ def click_create_milestone_button
+ click_element(:create_milestone_button)
+ end
+
+ def set_description(description)
+ fill_element(:milestone_description_field, description)
+ end
+
+ def set_title(title)
+ fill_element(:milestone_title_field, title)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/group/sub_menus/members.rb b/qa/qa/page/group/sub_menus/members.rb
index 33c4caaddcb..895da639c02 100644
--- a/qa/qa/page/group/sub_menus/members.rb
+++ b/qa/qa/page/group/sub_menus/members.rb
@@ -7,6 +7,10 @@ module QA
class Members < Page::Base
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
@@ -32,10 +36,12 @@ module QA
end
def remove_member(username)
- page.accept_confirm do
- within_element(:member_row, text: username) do
- click_element :delete_member_button
- end
+ within_element(:member_row, text: username) do
+ click_element :delete_member_button
+ end
+
+ within_element(:remove_member_modal_content) do
+ click_button("Remove member")
end
end
end
diff --git a/qa/qa/page/issuable/sidebar.rb b/qa/qa/page/issuable/sidebar.rb
deleted file mode 100644
index af5eee35a2d..00000000000
--- a/qa/qa/page/issuable/sidebar.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Issuable
- class Sidebar < Page::Base
- view 'app/views/shared/issuable/_sidebar.html.haml' do
- element :labels_block
- element :milestone_block
- element :milestone_link
- end
-
- def has_label?(label)
- within_element(:labels_block) do
- has_element?(:label, label_name: label)
- end
- end
-
- def has_milestone?(milestone_title)
- within_element(:milestone_block) do
- has_element?(:milestone_link, title: milestone_title)
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index 6af18cb1d2b..416946f44f0 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -22,6 +22,9 @@ module QA
element :groups_dropdown, required: true
element :more_dropdown
element :snippets_link
+ element :groups_link
+ element :activity_link
+ element :milestones_link
end
view 'app/views/layouts/nav/projects_dropdown/_show.html.haml' do
@@ -53,10 +56,10 @@ module QA
end
end
- def go_to_snippets
+ def go_to_more_dropdown_option(option_name)
within_top_menu do
click_element :more_dropdown
- click_element :snippets_link
+ click_element option_name
end
end
@@ -148,3 +151,5 @@ module QA
end
end
end
+
+QA::Page::Main::Menu.prepend_if_ee('QA::EE::Page::Main::Menu')
diff --git a/qa/qa/page/main/two_factor_auth.rb b/qa/qa/page/main/two_factor_auth.rb
new file mode 100644
index 00000000000..003bd8dd1b1
--- /dev/null
+++ b/qa/qa/page/main/two_factor_auth.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Main
+ class TwoFactorAuth < Page::Base
+ view 'app/views/devise/sessions/two_factor.html.haml' do
+ element :verify_code_button
+ element :two_fa_code_field
+ end
+
+ def click_verify_code_button
+ click_element :verify_code_button
+ end
+
+ def set_2fa_code(code)
+ fill_element(:two_fa_code_field, code)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index 07f8e568b2a..b9a2bf4ee69 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -5,6 +5,7 @@ module QA
module MergeRequest
class Show < Page::Base
include Page::Component::Note
+ include Page::Component::Issuable::Sidebar
view 'app/assets/javascripts/mr_tabs_popover/components/popover.vue' do
element :dismiss_popover_button
@@ -64,11 +65,6 @@ module QA
element :new_diff_line
end
- view 'app/views/shared/issuable/_sidebar.html.haml' do
- element :assignee_block
- element :labels_block
- end
-
view 'app/views/projects/merge_requests/_mr_title.html.haml' do
element :edit_button
end
@@ -178,18 +174,6 @@ module QA
has_element?(:merge_button)
end
- def has_assignee?(username)
- page.within(element_selector_css(:assignee_block)) do
- has_text?(username)
- end
- end
-
- def has_label?(label)
- within_element(:labels_block) do
- !!has_element?(:label, label_name: label)
- end
- end
-
def has_pipeline_status?(text)
# Pipelines can be slow, so we wait a bit longer than the usual 10 seconds
has_element?(:merge_request_pipeline_info_content, text: text, wait: 30)
diff --git a/qa/qa/page/milestone/index.rb b/qa/qa/page/milestone/index.rb
new file mode 100644
index 00000000000..2e86dd4c0ab
--- /dev/null
+++ b/qa/qa/page/milestone/index.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Milestone
+ class Index < Page::Base
+ view 'app/views/shared/milestones/_milestone.html.haml' do
+ element :milestone_link
+ end
+
+ def click_milestone(milestone)
+ click_element(:milestone_link, milestone_title: milestone.title)
+ end
+
+ def has_milestone?(milestone)
+ has_element?(:milestone_link, milestone_title: milestone.title)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/milestone/new.rb b/qa/qa/page/milestone/new.rb
new file mode 100644
index 00000000000..655254d74fa
--- /dev/null
+++ b/qa/qa/page/milestone/new.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Milestone
+ class New < Page::Base
+ view 'app/views/shared/milestones/_form_dates.html.haml' do
+ element :due_date_field
+ element :start_date_field
+ end
+
+ def set_due_date(due_date)
+ fill_element(:due_date_field, due_date.to_s + "\n")
+ end
+
+ def set_start_date(start_date)
+ fill_element(:start_date_field, start_date.to_s + "\n")
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/milestone/show.rb b/qa/qa/page/milestone/show.rb
new file mode 100644
index 00000000000..42efbd4ea30
--- /dev/null
+++ b/qa/qa/page/milestone/show.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Milestone
+ class Show < Page::Base
+ include Support::Dates
+
+ view 'app/views/shared/milestones/_description.html.haml' do
+ element :milestone_description_content
+ element :milestone_title_content, required: true
+ end
+
+ view 'app/views/shared/milestones/_sidebar.html.haml' do
+ element :due_date_content
+ element :start_date_content
+ end
+
+ def has_due_date?(due_date)
+ formatted_due_date = format_date(due_date)
+ has_element?(:due_date_content, text: formatted_due_date)
+ end
+
+ def has_start_date?(start_date)
+ formatted_start_date = format_date(start_date)
+ has_element?(:start_date_content, text: formatted_start_date)
+ end
+ end
+ end
+ end
+end
+
+QA::Page::Milestone::Show.prepend_if_ee('QA::EE::Page::Milestone::Show')
diff --git a/qa/qa/page/modal/delete_wiki.rb b/qa/qa/page/modal/delete_wiki.rb
new file mode 100644
index 00000000000..4f0bc34ee88
--- /dev/null
+++ b/qa/qa/page/modal/delete_wiki.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Modal
+ class DeleteWiki < Base
+ view 'app/assets/javascripts/pages/shared/wikis/components/delete_wiki_modal.vue' do
+ element :confirm_deletion_button, required: true
+ end
+
+ def confirm_deletion
+ click_element :confirm_deletion_button
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/profile/two_factor_auth.rb b/qa/qa/page/profile/two_factor_auth.rb
index a3ff5f603fa..b5a4d04b377 100644
--- a/qa/qa/page/profile/two_factor_auth.rb
+++ b/qa/qa/page/profile/two_factor_auth.rb
@@ -8,9 +8,35 @@ module QA
element :configure_it_later_button
end
+ view 'app/views/profiles/two_factor_auths/show.html.haml' do
+ element :otp_secret_content
+ element :pin_code_field
+ element :register_2fa_app_button
+ end
+
+ view 'app/views/profiles/two_factor_auths/_codes.html.haml' do
+ element :proceed_button
+ end
+
def click_configure_it_later_button
click_element :configure_it_later_button
end
+
+ def otp_secret_content
+ find_element(:otp_secret_content).text.gsub('Key:', '').delete(' ')
+ end
+
+ def set_pin_code(pin_code)
+ fill_element(:pin_code_field, pin_code)
+ end
+
+ def click_register_2fa_app_button
+ click_element :register_2fa_app_button
+ end
+
+ def click_proceed_button
+ click_element :proceed_button
+ end
end
end
end
diff --git a/qa/qa/page/project/issue/index.rb b/qa/qa/page/project/issue/index.rb
index ace2537fc0e..e0c10220fbc 100644
--- a/qa/qa/page/project/issue/index.rb
+++ b/qa/qa/page/project/issue/index.rb
@@ -18,6 +18,11 @@ module QA
element :export_issues_modal
end
+ view 'app/views/projects/issues/import_csv/_button.html.haml' do
+ element :import_issues_button
+ element :import_from_jira_link
+ end
+
view 'app/views/projects/issues/_issue.html.haml' do
element :issue
element :issue_link, 'link_to issue.title' # rubocop:disable QA/ElementWithPattern
@@ -51,10 +56,25 @@ module QA
click_element(:export_issues_button)
end
+ def click_import_from_jira_link
+ click_element(:import_from_jira_link)
+ end
+
+ 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)
+ end
+
def export_issues_modal
find_element(:export_issues_modal)
end
+ def go_to_jira_import_form
+ click_import_issues_dropdown
+ click_import_from_jira_link
+ end
+
def has_assignee_link_count?(count)
all_elements(:assignee_link, count: count)
end
diff --git a/qa/qa/page/project/issue/jira_import.rb b/qa/qa/page/project/issue/jira_import.rb
new file mode 100644
index 00000000000..d3be24464ab
--- /dev/null
+++ b/qa/qa/page/project/issue/jira_import.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Issue
+ class JiraImport < Page::Base
+ view 'app/assets/javascripts/jira_import/components/jira_import_form.vue' do
+ element :jira_project_dropdown
+ element :jira_issues_import_button
+ end
+
+ def select_jira_project(jira_project)
+ select_element(:jira_project_dropdown, jira_project)
+ end
+
+ def select_project_and_import(jira_project)
+ select_jira_project(jira_project)
+ click_element(:jira_issues_import_button)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb
index dd74ff28763..04f0f34cbbb 100644
--- a/qa/qa/page/project/issue/show.rb
+++ b/qa/qa/page/project/issue/show.rb
@@ -8,6 +8,7 @@ module QA
include Page::Component::Issuable::Common
include Page::Component::Note
include Page::Component::DesignManagement
+ include Page::Component::Issuable::Sidebar
view 'app/assets/javascripts/notes/components/comment_form.vue' do
element :comment_button
@@ -23,45 +24,25 @@ module QA
element :noteable_note_item
end
- view 'app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue' do
- element :avatar_image
- end
-
- view 'app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue' do
- element :more_assignees_link
- end
-
view 'app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue' do
element :remove_related_issue_button
end
- view 'app/helpers/dropdowns_helper.rb' do
- element :dropdown_input_field
- end
-
view 'app/views/shared/issuable/_close_reopen_button.html.haml' do
element :close_issue_button
element :reopen_issue_button
end
- view 'app/views/shared/issuable/_sidebar.html.haml' do
- element :assignee_block
- element :labels_block
- element :edit_link_labels
- element :dropdown_menu_labels
- element :milestone_link
- end
-
view 'app/views/shared/notes/_form.html.haml' do
element :new_note_form, 'new-note' # rubocop:disable QA/ElementWithPattern
element :new_note_form, 'attr: :note' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/issues/_tabs.html.haml' do
- element :discussion_tab_link
- element :discussion_tab_content
- element :designs_tab_link
element :designs_tab_content
+ element :designs_tab_link
+ element :discussion_tab_content
+ element :discussion_tab_link
end
def click_discussion_tab
@@ -74,10 +55,6 @@ module QA
active_element?(:designs_tab_content)
end
- def click_milestone_link
- click_element(:milestone_link)
- end
-
def click_remove_related_issue_button
click_element(:remove_related_issue_button)
end
@@ -90,7 +67,7 @@ module QA
# attachment option should be an absolute path
def comment(text, attachment: nil, filter: :all_activities)
method("select_#{filter}_filter").call
- fill_element :comment_input, text
+ fill_element :comment_input, "#{text}\n"
unless attachment.nil?
QA::Page::Component::Dropzone.new(self, '.new-note')
@@ -100,20 +77,10 @@ module QA
click_element :comment_button
end
- def has_avatar_image_count?(count)
- wait_assignees_block_finish_loading do
- all_elements(:avatar_image, count: count)
- end
- end
-
def has_comment?(comment_text)
has_element?(:noteable_note_item, text: comment_text, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
end
- def more_assignees_link
- find_element(:more_assignees_link)
- end
-
def noteable_note_item
find_element(:noteable_note_item)
end
@@ -130,35 +97,6 @@ module QA
select_filter_with_text('Show history only')
end
- def select_labels_and_refresh(labels)
- Support::Retrier.retry_until do
- click_element(:edit_link_labels)
- has_element?(:dropdown_menu_labels, text: labels.first)
- end
-
- labels.each do |label|
- within_element(:dropdown_menu_labels, text: label) do
- send_keys_to_element(:dropdown_input_field, [label, :enter])
- end
- end
-
- click_element(:edit_link_labels)
-
- labels.each do |label|
- has_element?(:labels_block, text: label, wait: 0)
- end
-
- refresh
- end
-
- def text_of_labels_block
- find_element(:labels_block)
- end
-
- def toggle_more_assignees_link
- click_element(:more_assignees_link)
- end
-
private
def select_filter_with_text(text)
@@ -168,15 +106,6 @@ module QA
find_element(:filter_options, text: text).click
end
end
-
- def wait_assignees_block_finish_loading
- within_element(:assignee_block) do
- wait_until(reload: false, max_duration: 10, sleep_interval: 1) do
- finished_loading_block?
- yield
- end
- end
- end
end
end
end
diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb
index 971b8c5e5f8..6243dc92b45 100644
--- a/qa/qa/page/project/job/show.rb
+++ b/qa/qa/page/project/job/show.rb
@@ -23,6 +23,9 @@ module QA
raise "Timed out waiting for the build trace to load" unless loaded?
raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout)
+ job_log = find_element(:job_log_content).text
+ QA::Runtime::Logger.debug(" \n\n ------- Job log: ------- \n\n #{job_log} \n -------")
+
passed?
end
diff --git a/qa/qa/page/project/menu.rb b/qa/qa/page/project/menu.rb
index 3d4d0ff9d22..9faf1bd5f8f 100644
--- a/qa/qa/page/project/menu.rb
+++ b/qa/qa/page/project/menu.rb
@@ -15,11 +15,14 @@ module QA
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :activity_link
element :merge_requests_link
- element :wiki_link
element :snippets_link
element :members_link
end
+ view 'app/views/layouts/nav/sidebar/_wiki_link.html.haml' do
+ element :wiki_link
+ end
+
def click_merge_requests
within_sidebar do
click_element(:merge_requests_link)
diff --git a/qa/qa/page/project/milestone/index.rb b/qa/qa/page/project/milestone/index.rb
index 6895c44f72f..d25a3389ae8 100644
--- a/qa/qa/page/project/milestone/index.rb
+++ b/qa/qa/page/project/milestone/index.rb
@@ -4,13 +4,25 @@ module QA
module Page
module Project
module Milestone
- class Index < Page::Base
+ class Index < Page::Milestone::Index
view 'app/views/projects/milestones/index.html.haml' do
- element :new_project_milestone
+ element :new_project_milestone_link
end
- def click_new_milestone
- click_element :new_project_milestone
+ view 'app/views/shared/milestones/_milestone.html.haml' do
+ element :milestone_link
+ end
+
+ def click_new_milestone_link
+ click_element :new_project_milestone_link
+ end
+
+ def has_milestone?(milestone)
+ has_element? :milestone_link, milestone_title: milestone.title
+ end
+
+ def click_milestone(milestone)
+ click_element :milestone_link, milestone_title: milestone.title
end
end
end
diff --git a/qa/qa/page/project/milestone/new.rb b/qa/qa/page/project/milestone/new.rb
index 751fb141684..98f3a0ef4ab 100644
--- a/qa/qa/page/project/milestone/new.rb
+++ b/qa/qa/page/project/milestone/new.rb
@@ -4,23 +4,36 @@ module QA
module Page
module Project
module Milestone
- class New < Page::Base
+ class New < Page::Milestone::New
view 'app/views/projects/milestones/_form.html.haml' do
- element :milestone_create_button
- element :milestone_title
- element :milestone_description
+ element :create_milestone_button
+ element :milestone_description_field
+ element :milestone_title_field
+ end
+
+ view 'app/views/shared/milestones/_form_dates.html.haml' do
+ element :due_date_field
+ element :start_date_field
+ end
+
+ def click_create_milestone_button
+ click_element :create_milestone_button
end
def set_title(title)
- fill_element :milestone_title, title
+ fill_element :milestone_title_field, title
end
def set_description(description)
- fill_element :milestone_description, description
+ fill_element :milestone_description_field, description
+ end
+
+ def set_due_date(due_date)
+ fill_element :due_date_field, due_date.to_s + "\n"
end
- def click_milestone_create_button
- click_element :milestone_create_button
+ def set_start_date(start_date)
+ fill_element :start_date_field, start_date.to_s + "\n"
end
end
end
diff --git a/qa/qa/page/project/operations/kubernetes/show.rb b/qa/qa/page/project/operations/kubernetes/show.rb
index 46fddfa6078..e1612718883 100644
--- a/qa/qa/page/project/operations/kubernetes/show.rb
+++ b/qa/qa/page/project/operations/kubernetes/show.rb
@@ -29,6 +29,14 @@ module QA
element :uninstall_button
end
+ view 'app/views/clusters/clusters/_health.html.haml' do
+ element :cluster_health_section
+ end
+
+ view 'app/views/clusters/clusters/_health_tab.html.haml' do
+ element :health, required: true
+ end
+
def open_details
has_element?(:details, wait: 30)
click_element :details
@@ -71,11 +79,32 @@ module QA
def save_domain
click_element :save_changes_button, Page::Project::Operations::Kubernetes::Show
end
+
+ def wait_for_cluster_health
+ wait_until(max_duration: 120, sleep_interval: 3, reload: true) do
+ has_cluster_health_graphs?
+ end
+ end
+
+ def open_health
+ has_element?(:health, wait: 30)
+ click_element :health
+ end
+
+ def has_cluster_health_graphs?
+ within_cluster_health_section do
+ has_text?('CPU Usage')
+ end
+ end
+
+ def within_cluster_health_section
+ within_element :cluster_health_section do
+ yield
+ end
+ end
end
end
end
end
end
end
-
-QA::Page::Project::Operations::Kubernetes::Show.prepend_if_ee('QA::EE::Page::Project::Operations::Kubernetes::Show')
diff --git a/qa/qa/page/project/operations/metrics/show.rb b/qa/qa/page/project/operations/metrics/show.rb
index a1c15e72f44..e9e4923a0e2 100644
--- a/qa/qa/page/project/operations/metrics/show.rb
+++ b/qa/qa/page/project/operations/metrics/show.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'securerandom'
+
module QA
module Page
module Project
@@ -60,7 +62,7 @@ module QA
def duplicate_dashboard(save_as = 'test_duplication.yml', commit_option = 'Commit to master branch')
click_element :dashboards_filter_dropdown
click_on 'Duplicate dashboard'
- fill_element :duplicate_dashboard_filename_field, save_as
+ fill_element :duplicate_dashboard_filename_field, "#{SecureRandom.hex(8)}-#{save_as}"
choose commit_option
within('.modal-content') { click_button(class: 'btn-success') }
end
diff --git a/qa/qa/page/project/pipeline/index.rb b/qa/qa/page/project/pipeline/index.rb
index 54e4d0fb2fc..aa2ef2f058f 100644
--- a/qa/qa/page/project/pipeline/index.rb
+++ b/qa/qa/page/project/pipeline/index.rb
@@ -5,11 +5,11 @@ module QA
module Project
module Pipeline
class Index < QA::Page::Base
- view 'app/assets/javascripts/pipelines/components/pipeline_url.vue' do
+ view 'app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue' do
element :pipeline_url_link
end
- view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do
+ view 'app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue' do
element :pipeline_commit_status
element :pipeline_retry_button
end
diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb
index d22dfefc096..43003fe1953 100644
--- a/qa/qa/page/project/pipeline/show.rb
+++ b/qa/qa/page/project/pipeline/show.rb
@@ -22,6 +22,7 @@ module QA
view 'app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
element :linked_pipeline_button
+ element :child_pipeline
end
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
@@ -60,6 +61,10 @@ module QA
end
end
+ def has_child_pipeline?
+ has_element? :child_pipeline
+ end
+
def click_job(job_name)
click_element(:job_link, text: job_name)
end
diff --git a/qa/qa/page/project/settings/incidents.rb b/qa/qa/page/project/settings/incidents.rb
index 94d5fc369ad..9b523e2aa9e 100644
--- a/qa/qa/page/project/settings/incidents.rb
+++ b/qa/qa/page/project/settings/incidents.rb
@@ -5,10 +5,11 @@ module QA
module Project
module Settings
class Incidents < Page::Base
- view 'app/views/projects/settings/operations/_incidents.html.haml' do
+ view 'app/assets/javascripts/incidents_settings/components/alerts_form.vue' do
element :create_issue_checkbox
element :incident_templates_dropdown
element :save_changes_button
+ element :incident_templates_item
end
def enable_issues_for_incidents
@@ -16,8 +17,9 @@ module QA
end
def select_issue_template(template)
+ click_element(:incident_templates_dropdown)
within_element :incident_templates_dropdown do
- find(:option, template).select_option
+ find_element(:incident_templates_item, text: template).click
end
end
diff --git a/qa/qa/page/project/settings/operations.rb b/qa/qa/page/project/settings/operations.rb
index f6e005d3189..b39b8f92cc7 100644
--- a/qa/qa/page/project/settings/operations.rb
+++ b/qa/qa/page/project/settings/operations.rb
@@ -7,7 +7,7 @@ module QA
class Operations < Page::Base
include QA::Page::Settings::Common
- view 'app/views/projects/settings/operations/_incidents.html.haml' do
+ view 'app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue' do
element :incidents_settings_content
end
diff --git a/qa/qa/page/project/settings/protected_tags.rb b/qa/qa/page/project/settings/protected_tags.rb
new file mode 100644
index 00000000000..bf8f349cfd5
--- /dev/null
+++ b/qa/qa/page/project/settings/protected_tags.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Settings
+ class ProtectedTags < Page::Base
+ include Page::Component::DropdownFilter
+
+ view 'app/views/projects/protected_tags/shared/_dropdown.html.haml' do
+ element :tags_dropdown
+ end
+
+ view 'app/views/projects/protected_tags/_create_protected_tag.html.haml' do
+ element :access_levels_content
+ element :access_levels_dropdown
+ end
+
+ view 'app/views/projects/protected_tags/shared/_create_protected_tag.html.haml' do
+ element :protect_tag_button
+ end
+
+ def set_tag(tag_name)
+ click_element :tags_dropdown
+ filter_and_select(tag_name)
+ end
+
+ def choose_access_level_role(role)
+ return if find_element(:access_levels_dropdown).text == role
+
+ click_element :access_levels_dropdown
+ within_element(:access_levels_content) do
+ click_on role
+ end
+ end
+
+ def click_protect_tag_button
+ click_element :protect_tag_button
+ end
+ end
+ end
+ end
+ end
+end
+
+QA::Page::Project::Settings::ProtectedTags.prepend_if_ee('QA::EE::Page::Project::Settings::ProtectedTags')
diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb
index 8e9a24a4741..fd3a590c2c1 100644
--- a/qa/qa/page/project/settings/repository.rb
+++ b/qa/qa/page/project/settings/repository.rb
@@ -23,6 +23,10 @@ module QA
element :deploy_keys_settings
end
+ view 'app/views/projects/protected_tags/shared/_index.html.haml' do
+ element :protected_tag_settings_content
+ end
+
def expand_deploy_tokens(&block)
expand_section(:deploy_tokens_settings) do
Settings::DeployTokens.perform(&block)
@@ -46,6 +50,12 @@ module QA
MirroringRepositories.perform(&block)
end
end
+
+ def expand_protected_tags(&block)
+ expand_section(:protected_tag_settings_content) do
+ ProtectedTags.perform(&block)
+ end
+ end
end
end
end
diff --git a/qa/qa/page/project/settings/runners.rb b/qa/qa/page/project/settings/runners.rb
index adc92b4acaf..af4dbb08430 100644
--- a/qa/qa/page/project/settings/runners.rb
+++ b/qa/qa/page/project/settings/runners.rb
@@ -13,7 +13,7 @@ module QA
##
# TODO, phase-out CSS classes added in Ruby helpers.
#
- view 'app/helpers/runners_helper.rb' do
+ view 'app/helpers/ci/runners_helper.rb' do
# rubocop:disable Lint/InterpolationCheck
element :runner_status, 'runner-status-#{status}' # rubocop:disable QA/ElementWithPattern
# rubocop:enable Lint/InterpolationCheck
diff --git a/qa/qa/page/project/settings/services/jira.rb b/qa/qa/page/project/settings/services/jira.rb
index 9f9331bac94..75baedb1b0f 100644
--- a/qa/qa/page/project/settings/services/jira.rb
+++ b/qa/qa/page/project/settings/services/jira.rb
@@ -6,11 +6,11 @@ module QA
module Settings
module Services
class Jira < QA::Page::Base
- view 'app/views/shared/_field.html.haml' do
- element :url_field, 'data: { qa_selector: "#{name.downcase.gsub' # rubocop:disable QA/ElementWithPattern
- element :username_field, 'data: { qa_selector: "#{name.downcase.gsub' # rubocop:disable QA/ElementWithPattern
- element :password_field, 'data: { qa_selector: "#{name.downcase.gsub' # rubocop:disable QA/ElementWithPattern
- element :jira_issue_transition_id_field, 'data: { qa_selector: "#{name.downcase.gsub' # rubocop:disable QA/ElementWithPattern
+ view 'app/assets/javascripts/integrations/edit/components/dynamic_field.vue' do
+ element :service_url_field, ':data-qa-selector="`${fieldId}_field`"' # rubocop:disable QA/ElementWithPattern
+ element :service_username_field, ':data-qa-selector="`${fieldId}_field`"' # rubocop:disable QA/ElementWithPattern
+ element :service_password_field, ':data-qa-selector="`${fieldId}_field`"' # rubocop:disable QA/ElementWithPattern
+ element :service_jira_issue_transition_id_field, ':data-qa-selector="`${fieldId}_field`"' # rubocop:disable QA/ElementWithPattern
end
view 'app/helpers/services_helper.rb' do
@@ -34,19 +34,19 @@ module QA
private
def set_jira_server_url(url)
- fill_element(:url_field, url)
+ fill_element(:service_url_field, url)
end
def set_username(username)
- fill_element(:username_field, username)
+ fill_element(:service_username_field, username)
end
def set_password(password)
- fill_element(:password_field, password)
+ fill_element(:service_password_field, password)
end
def set_transaction_ids(transaction_ids)
- fill_element(:jira_issue_transition_id_field, transaction_ids)
+ fill_element(:service_jira_issue_transition_id_field, transaction_ids)
end
def click_save_changes_button
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index 00298ff9fb5..2354a0d9332 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -51,9 +51,12 @@ module QA
element :quick_actions
end
- view 'app/views/projects/tree/_tree_header.html.haml' do
+ view 'app/assets/javascripts/repository/components/breadcrumbs.vue' do
element :add_to_tree
element :new_file_option
+ end
+
+ view 'app/assets/javascripts/repository/components/web_ide_link.vue' do
element :web_ide_button
end
diff --git a/qa/qa/page/project/snippet/new.rb b/qa/qa/page/project/snippet/new.rb
index 1463dfc2c7f..7431d6c1bf8 100644
--- a/qa/qa/page/project/snippet/new.rb
+++ b/qa/qa/page/project/snippet/new.rb
@@ -4,7 +4,8 @@ module QA
module Page
module Project
module Snippet
- class New < Page::Dashboard::Snippet::New
+ class New < Page::Base
+ include Page::Component::NewSnippet
include Component::LazyLoader
view 'app/views/shared/empty_states/_snippets.html.haml' do
element :create_first_snippet_link
diff --git a/qa/qa/page/project/snippet/show.rb b/qa/qa/page/project/snippet/show.rb
new file mode 100644
index 00000000000..f66fa2cbe51
--- /dev/null
+++ b/qa/qa/page/project/snippet/show.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Snippet
+ class Show < Page::Base
+ include Page::Component::Snippet
+
+ view 'app/views/projects/notes/_actions.html.haml' do
+ element :edit_comment_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/issues.rb b/qa/qa/page/project/sub_menus/issues.rb
index c15a8ec4cc7..124faf0d346 100644
--- a/qa/qa/page/project/sub_menus/issues.rb
+++ b/qa/qa/page/project/sub_menus/issues.rb
@@ -50,6 +50,14 @@ module QA
end
end
+ def go_to_milestones
+ hover_issues do
+ within_submenu do
+ click_element(:milestones_link)
+ end
+ end
+ end
+
private
def hover_issues
diff --git a/qa/qa/page/project/sub_menus/repository.rb b/qa/qa/page/project/sub_menus/repository.rb
index 38d6b8e50f4..c78c7521b64 100644
--- a/qa/qa/page/project/sub_menus/repository.rb
+++ b/qa/qa/page/project/sub_menus/repository.rb
@@ -14,15 +14,16 @@ module QA
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
- element :project_menu_repo
+ element :repository_link
element :branches_link
+ element :tags_link
end
end
end
def click_repository
within_sidebar do
- click_element(:project_menu_repo)
+ click_element(:repository_link)
end
end
@@ -34,11 +35,19 @@ module QA
end
end
+ def go_to_repository_tags
+ hover_repository do
+ within_submenu do
+ click_element(:tags_link)
+ end
+ end
+ end
+
private
def hover_repository
within_sidebar do
- find_element(:project_menu_repo).hover
+ find_element(:repository_link).hover
yield
end
diff --git a/qa/qa/page/project/tag/index.rb b/qa/qa/page/project/tag/index.rb
new file mode 100644
index 00000000000..b8f7bd3b0b4
--- /dev/null
+++ b/qa/qa/page/project/tag/index.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Tag
+ class Index < Page::Base
+ view 'app/views/projects/tags/index.html.haml' do
+ element :new_tag_button
+ end
+
+ def click_new_tag_button
+ click_element :new_tag_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/tag/new.rb b/qa/qa/page/project/tag/new.rb
new file mode 100644
index 00000000000..dc59c07ec98
--- /dev/null
+++ b/qa/qa/page/project/tag/new.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Tag
+ class New < Page::Base
+ view 'app/views/projects/tags/new.html.haml' do
+ element :tag_name_field
+ element :tag_message_field
+ element :release_notes_field
+ element :create_tag_button
+ end
+
+ view 'app/views/shared/_zen.html.haml' do
+ # This partial adds the `release_notes_field` selector passed from 'app/views/projects/tags/new.html.haml'
+ # The checks below ensure that required lines are not removed without updating this page object
+ element :_, "qa_selector = local_assigns.fetch(:qa_selector, '')" # rubocop:disable QA/ElementWithPattern
+ element :_, "text_area_tag attr, current_text, data: { qa_selector: qa_selector }" # rubocop:disable QA/ElementWithPattern
+ end
+
+ def fill_tag_name(text)
+ fill_element(:tag_name_field, text)
+ end
+
+ def fill_tag_message(text)
+ fill_element(:tag_message_field, text)
+ end
+
+ def fill_release_notes(text)
+ fill_element(:release_notes_field, text)
+ end
+
+ def click_create_tag_button
+ click_element :create_tag_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/tag/show.rb b/qa/qa/page/project/tag/show.rb
new file mode 100644
index 00000000000..1974448a7c5
--- /dev/null
+++ b/qa/qa/page/project/tag/show.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Tag
+ class Show < Page::Base
+ view 'app/views/projects/tags/show.html.haml' do
+ element :tag_name_content
+ element :tag_message_content
+ element :tag_release_notes_content
+ end
+
+ def has_tag_name?(text)
+ has_element?(:tag_name_content, text: text)
+ end
+
+ def has_tag_message?(text)
+ has_element?(:tag_message_content, text: text)
+ end
+
+ def has_tag_release_notes?(text)
+ has_element?(:tag_release_notes_content, text: text)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb
index 29f431d81df..b46d2d32f1f 100644
--- a/qa/qa/page/project/web_ide/edit.rb
+++ b/qa/qa/page/project/web_ide/edit.rb
@@ -50,6 +50,15 @@ module QA
element :first_file_button
end
+ view 'app/assets/javascripts/vue_shared/components/file_row.vue' do
+ element :file_name_content
+ end
+
+ view 'app/assets/javascripts/ide/components/new_dropdown/index.vue' do
+ element :dropdown_button
+ element :rename_move_button
+ end
+
def has_file?(file_name)
within_element(:file_list) do
page.has_content? file_name
@@ -132,6 +141,14 @@ module QA
fill_element(:file_name_field, file_name)
click_button('Create file')
end
+
+ def rename_file(file_name, new_file_name)
+ click_element(:file_name_content, text: file_name)
+ click_element(:dropdown_button)
+ click_element(:rename_move_button, Page::Component::WebIDE::Modal::CreateNewFile)
+ fill_element(:file_name_field, new_file_name)
+ click_button('Rename file')
+ end
end
end
end
diff --git a/qa/qa/page/project/wiki/edit.rb b/qa/qa/page/project/wiki/edit.rb
index 96301e33733..6f3be904eb3 100644
--- a/qa/qa/page/project/wiki/edit.rb
+++ b/qa/qa/page/project/wiki/edit.rb
@@ -4,7 +4,9 @@ module QA
module Page
module Project
module Wiki
- class Edit < Page::Base
+ class Edit < Base
+ include Wiki::Sidebar
+
view 'app/views/shared/wikis/_form.html.haml' do
element :wiki_title_textbox
element :wiki_content_textarea
@@ -13,6 +15,10 @@ module QA
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
@@ -32,6 +38,11 @@ module QA
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
diff --git a/qa/qa/page/project/wiki/list.rb b/qa/qa/page/project/wiki/list.rb
new file mode 100644
index 00000000000..785847011bf
--- /dev/null
+++ b/qa/qa/page/project/wiki/list.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Wiki
+ class List < Base
+ view 'app/views/shared/wikis/_pages_wiki_page.html.haml' do
+ element :wiki_page_link
+ 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
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/wiki/show.rb b/qa/qa/page/project/wiki/show.rb
index 7e4e714f4a6..cdd18e420d1 100644
--- a/qa/qa/page/project/wiki/show.rb
+++ b/qa/qa/page/project/wiki/show.rb
@@ -4,13 +4,10 @@ module QA
module Page
module Project
module Wiki
- class Show < Page::Base
+ class Show < Base
+ include Wiki::Sidebar
include Component::LazyLoader
- view 'app/views/shared/wikis/_sidebar.html.haml' do
- element :clone_repository_link
- end
-
view 'app/views/shared/wikis/show.html.haml' do
element :wiki_page_title
element :wiki_page_content
@@ -54,14 +51,6 @@ module QA
click_element(:edit_page_button)
end
- def click_clone_repository
- click_element(:clone_repository_link)
- end
-
- def wiki_text
- find_element(:wiki_page_content).text
- end
-
def has_title?(title)
has_element?(:wiki_page_title, title)
end
@@ -69,6 +58,10 @@ module QA
def has_content?(content)
has_element?(:wiki_page_content, content)
end
+
+ def has_no_page?
+ has_element? :create_first_page_link
+ end
end
end
end
diff --git a/qa/qa/page/project/wiki/sidebar.rb b/qa/qa/page/project/wiki/sidebar.rb
new file mode 100644
index 00000000000..dc27c23e4c3
--- /dev/null
+++ b/qa/qa/page/project/wiki/sidebar.rb
@@ -0,0 +1,42 @@
+# 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
+ 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
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb
index 591aa449219..babdfc96265 100644
--- a/qa/qa/resource/api_fabricator.rb
+++ b/qa/qa/resource/api_fabricator.rb
@@ -83,13 +83,13 @@ module QA
end
def api_get_from(get_path)
- url = Runtime::API::Request.new(api_client, get_path).url
- response = get(url)
+ request = Runtime::API::Request.new(api_client, get_path)
+ response = get(request.url)
if response.code == HTTP_STATUS_SERVER_ERROR
- raise InternalServerError, "Failed to GET #{url} - (#{response.code}): `#{response}`."
+ raise InternalServerError, "Failed to GET #{request.mask_url} - (#{response.code}): `#{response}`."
elsif response.code != HTTP_STATUS_OK
- raise ResourceNotFoundError, "Resource at #{url} could not be found (#{response.code}): `#{response}`."
+ raise ResourceNotFoundError, "Resource at #{request.mask_url} could not be found (#{response.code}): `#{response}`."
end
response
@@ -108,11 +108,11 @@ module QA
end
def api_delete
- url = Runtime::API::Request.new(api_client, api_delete_path).url
- response = delete(url)
+ request = Runtime::API::Request.new(api_client, api_delete_path)
+ response = delete(request.url)
unless [HTTP_STATUS_NO_CONTENT, HTTP_STATUS_ACCEPTED].include? response.code
- raise ResourceNotDeletedError, "Resource at #{url} could not be deleted (#{response.code}): `#{response}`."
+ raise ResourceNotDeletedError, "Resource at #{request.mask_url} could not be deleted (#{response.code}): `#{response}`."
end
response
diff --git a/qa/qa/resource/group.rb b/qa/qa/resource/group.rb
index 850d6205305..75dcb4db55f 100644
--- a/qa/qa/resource/group.rb
+++ b/qa/qa/resource/group.rb
@@ -59,6 +59,10 @@ module QA
"/groups/#{CGI.escape("#{sandbox.path}/#{path}")}"
end
+ def api_put_path
+ "/groups/#{id}"
+ end
+
def api_post_path
'/groups'
end
@@ -75,6 +79,15 @@ module QA
def api_delete_path
"/groups/#{id}"
end
+
+ def set_require_two_factor_authentication(value:)
+ put_body = { require_two_factor_authentication: value }
+ response = put Runtime::API::Request.new(api_client, api_put_path).url, put_body
+
+ unless response.code == HTTP_STATUS_OK
+ raise ResourceUpdateFailedError, "Could not update require_two_factor_authentication to #{value}. Request returned (#{response.code}): `#{response}`."
+ end
+ end
end
end
end
diff --git a/qa/qa/resource/group_milestone.rb b/qa/qa/resource/group_milestone.rb
new file mode 100644
index 00000000000..1fb07fdbd0b
--- /dev/null
+++ b/qa/qa/resource/group_milestone.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ class GroupMilestone < Base
+ attr_writer :start_date, :due_date
+
+ attribute :id
+ attribute :title
+ attribute :description
+
+ attribute :group do
+ Group.fabricate_via_api! do |resource|
+ resource.name = 'group-with-milestone'
+ end
+ end
+
+ def initialize
+ @title = "group-milestone-#{SecureRandom.hex(4)}"
+ @description = "My awesome group milestone."
+ end
+
+ def api_get_path
+ "/groups/#{group.id}/milestones/#{id}"
+ end
+
+ def api_post_path
+ "/groups/#{group.id}/milestones"
+ end
+
+ def api_post_body
+ {
+ title: title,
+ description: description
+ }.tap do |hash|
+ hash[:start_date] = @start_date if @start_date
+ hash[:due_date] = @due_date if @due_date
+ end
+ end
+
+ def fabricate!
+ group.visit!
+
+ Page::Group::Menu.perform(&:go_to_milestones)
+ Page::Group::Milestone::Index.perform(&:click_new_milestone_link)
+
+ Page::Group::Milestone::New.perform do |new_milestone|
+ new_milestone.set_title(@title)
+ new_milestone.set_description(@description)
+ new_milestone.set_start_date(@start_date) if @start_date
+ new_milestone.set_due_date(@due_date) if @due_date
+ new_milestone.click_create_milestone_button
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb
index b4295a35263..d96d8d744d2 100644
--- a/qa/qa/resource/issue.rb
+++ b/qa/qa/resource/issue.rb
@@ -34,6 +34,7 @@ module QA
Page::Project::Issue::New.perform do |new_page|
new_page.fill_title(@title)
new_page.fill_description(@description)
+ new_page.choose_milestone(@milestone) if @milestone
new_page.create_new_issue
end
end
diff --git a/qa/qa/resource/members.rb b/qa/qa/resource/members.rb
index 38a620a5427..4ebed37ca23 100644
--- a/qa/qa/resource/members.rb
+++ b/qa/qa/resource/members.rb
@@ -8,10 +8,14 @@ module QA
#
module Members
def add_member(user, access_level = AccessLevel::DEVELOPER)
+ QA::Runtime::Logger.debug(%Q[Adding user #{user.username} to #{full_path} #{self.class.name}])
+
post Runtime::API::Request.new(api_client, api_members_path).url, { user_id: user.id, access_level: access_level }
end
def remove_member(user)
+ QA::Runtime::Logger.debug(%Q[Removing user #{user.username} from #{full_path} #{self.class.name}])
+
delete Runtime::API::Request.new(api_client, "#{api_members_path}/#{user.id}").url
end
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index 645f4e97ee0..358e87b0eb9 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -96,7 +96,11 @@ module QA
end
def has_file?(file_path)
- repository_tree.any? { |file| file[:path] == file_path }
+ response = repository_tree
+
+ raise ResourceNotFoundError, "#{response[:message]}" if response.is_a?(Hash) && response.has_key?(:message)
+
+ response.any? { |file| file[:path] == file_path }
end
def api_get_path
diff --git a/qa/qa/resource/project_milestone.rb b/qa/qa/resource/project_milestone.rb
index 385b9f0c96b..c9218e03e35 100644
--- a/qa/qa/resource/project_milestone.rb
+++ b/qa/qa/resource/project_milestone.rb
@@ -7,6 +7,7 @@ module QA
attribute :id
attribute :title
+ attribute :description
attribute :project do
Project.fabricate_via_api! do |resource|
@@ -16,6 +17,7 @@ module QA
def initialize
@title = "project-milestone-#{SecureRandom.hex(4)}"
+ @description = "My awesome project milestone."
end
def api_get_path
@@ -28,12 +30,28 @@ module QA
def api_post_body
{
- title: title
+ title: title,
+ description: description
}.tap do |hash|
hash[:start_date] = @start_date if @start_date
hash[:due_date] = @due_date if @due_date
end
end
+
+ def fabricate!
+ project.visit!
+
+ Page::Project::Menu.perform(&:go_to_milestones)
+ Page::Project::Milestone::Index.perform(&:click_new_milestone_link)
+
+ Page::Project::Milestone::New.perform do |new_milestone|
+ new_milestone.set_title(@title)
+ new_milestone.set_description(@description)
+ new_milestone.set_start_date(@start_date) if @start_date
+ new_milestone.set_due_date(@due_date) if @due_date
+ new_milestone.click_create_milestone_button
+ end
+ end
end
end
end
diff --git a/qa/qa/resource/repository/commit.rb b/qa/qa/resource/repository/commit.rb
index e3fb5bf486d..3243eacdb28 100644
--- a/qa/qa/resource/repository/commit.rb
+++ b/qa/qa/resource/repository/commit.rb
@@ -29,6 +29,30 @@ module QA
@add_files = files
end
+ def add_directory(dir)
+ raise "Must set directory as a Pathname" unless dir.is_a?(Pathname)
+
+ files_to_add = []
+
+ dir.each_child do |child|
+ case child.ftype?
+ when "file"
+ files_to_add.append({
+ file_path: child.to_s,
+ content: child.read
+ })
+ when "directory"
+ add_directory(child)
+ else
+ continue
+ end
+ end
+
+ validate_files!(files_to_add)
+
+ @add_files.merge(files_to_add)
+ end
+
def update_files(files)
validate_files!(files)
diff --git a/qa/qa/resource/sandbox.rb b/qa/qa/resource/sandbox.rb
index 032ff65c58b..b351d92092f 100644
--- a/qa/qa/resource/sandbox.rb
+++ b/qa/qa/resource/sandbox.rb
@@ -14,6 +14,7 @@ module QA
attribute :id
attribute :runners_token
attribute :name
+ attribute :full_path
def initialize
@path = Runtime::Namespace.sandbox_name
diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb
index e6dbe3faa61..41908a71cf9 100644
--- a/qa/qa/resource/user.rb
+++ b/qa/qa/resource/user.rb
@@ -117,7 +117,10 @@ module QA
user.password = password
end
else
- self.fabricate!
+ self.fabricate! do |user|
+ user.username = username if username
+ user.password = password if password
+ end
end
end
diff --git a/qa/qa/resource/wiki/project_page.rb b/qa/qa/resource/wiki/project_page.rb
index 5d0a0a37765..8bcc4bfe220 100644
--- a/qa/qa/resource/wiki/project_page.rb
+++ b/qa/qa/resource/wiki/project_page.rb
@@ -34,7 +34,7 @@ module QA
rescue ResourceURLMissingError
# TODO
# workaround
- project.web_url.concat("/-/wikis/#{slug}")
+ "#{project.web_url}/-/wikis/#{slug}"
end
def api_get_path
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index 677fba7ced7..804ebf27851 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'gitlab/qa'
+require 'uri'
module QA
module Runtime
@@ -23,10 +24,39 @@ module QA
SUPPORTED_FEATURES
end
- def dot_com?
- Runtime::Scenario.gitlab_address.include?(".com")
+ def address_matches?(*options)
+ return false unless Runtime::Scenario.attributes[:gitlab_address]
+
+ opts = {}
+ opts[:domain] = '.+'
+ opts[:tld] = '.com'
+
+ uri = URI(Runtime::Scenario.gitlab_address)
+
+ if options.any?
+ options.each do |option|
+ opts[:domain] = 'gitlab' if option == :production
+
+ if option.is_a?(Hash) && !option[:subdomain].nil?
+ opts.merge!(option)
+
+ opts[:subdomain] = case option[:subdomain]
+ when Array
+ "(#{option[:subdomain].join("|")})."
+ when Regexp
+ option[:subdomain]
+ else
+ "(#{option[:subdomain]})."
+ end
+ end
+ end
+ end
+
+ uri.host.match?(/^#{opts[:subdomain]}#{opts[:domain]}#{opts[:tld]}$/)
end
+ alias_method :dot_com?, :address_matches?
+
def additional_repository_storage
ENV['QA_ADDITIONAL_REPOSITORY_STORAGE']
end
@@ -194,6 +224,14 @@ module QA
ENV['GITLAB_QA_PASSWORD_6']
end
+ def gitlab_qa_2fa_owner_username_1
+ ENV['GITLAB_QA_2FA_OWNER_USERNAME_1'] || 'gitlab-qa-2fa-owner-user1'
+ end
+
+ def gitlab_qa_2fa_owner_password_1
+ ENV['GITLAB_QA_2FA_OWNER_PASSWORD_1']
+ end
+
def gitlab_qa_1p_email
ENV['GITLAB_QA_1P_EMAIL']
end
diff --git a/qa/qa/service/praefect_manager.rb b/qa/qa/service/praefect_manager.rb
index d8fa72456ad..a0433689e99 100644
--- a/qa/qa/service/praefect_manager.rb
+++ b/qa/qa/service/praefect_manager.rb
@@ -6,21 +6,177 @@ module QA
include Service::Shellout
def initialize
+ @gitlab = 'gitlab-gitaly-ha'
@praefect = 'praefect'
- @first_node = 'gitaly1'
- @second_node = 'gitaly2'
- @primary_node = @first_node
- @secondary_node = @second_node
+ @postgres = 'postgres'
+ @primary_node = 'gitaly1'
+ @secondary_node = 'gitaly2'
+ @tertiary_node = 'gitaly3'
+ @virtual_storage = 'default'
end
- def stop_primary_node
- shell "docker stop #{@primary_node}"
- @secondary_node, @primary_node = @primary_node, @secondary_node
+ def enable_writes
+ shell "docker exec #{@praefect} bash -c '/opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml enable-writes -virtual-storage #{@virtual_storage}'"
end
- def reset
- shell "docker start #{@primary_node}"
- shell "docker start #{@secondary_node}"
+ def replicated?(project_id)
+ shell %(docker exec gitlab-gitaly-ha bash -c 'gitlab-rake "gitlab:praefect:replicas[#{project_id}]"') do |line|
+ # The output of the rake task looks something like this:
+ #
+ # Project name | gitaly1 (primary) | gitaly2 | gitaly3
+ # ----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ # gitaly_cluster-3aff1f2bd14e6c98 | 23c4422629234d62b62adacafd0a33a8364e8619 | 23c4422629234d62b62adacafd0a33a8364e8619 | 23c4422629234d62b62adacafd0a33a8364e8619
+ #
+ # We want to confirm that the checksums are identical
+ break line.split('|').map(&:strip)[1..3].uniq.one? if line.start_with?("gitaly_cluster")
+ end
+ end
+
+ def start_praefect
+ start_node(@praefect)
+ end
+
+ def stop_praefect
+ stop_node(@praefect)
+ end
+
+ def start_node(name)
+ shell "docker start #{name}"
+ end
+
+ def stop_node(name)
+ shell "docker stop #{name}"
+ end
+
+ def trigger_failover_by_stopping_primary_node
+ stop_node(@primary_node)
+ end
+
+ def clear_replication_queue
+ QA::Runtime::Logger.debug("Clearing the replication queue")
+ shell <<~CMD
+ docker exec --env PGPASSWORD=SQL_PASSWORD #{@postgres} \
+ bash -c "psql -U postgres -d praefect_production -h postgres.test \
+ -c \\"delete from replication_queue_job_lock; delete from replication_queue_lock; delete from replication_queue;\\""
+ CMD
+ end
+
+ def create_stalled_replication_queue
+ QA::Runtime::Logger.debug("Setting jobs in replication queue to `in_progress` and acquiring locks")
+ shell <<~CMD
+ docker exec --env PGPASSWORD=SQL_PASSWORD #{@postgres} \
+ bash -c "psql -U postgres -d praefect_production -h postgres.test \
+ -c \\"update replication_queue set state = 'in_progress';
+ insert into replication_queue_job_lock (job_id, lock_id, triggered_at)
+ select id, rq.lock_id, created_at from replication_queue rq
+ left join replication_queue_job_lock rqjl on rq.id = rqjl.job_id
+ where state = 'in_progress' and rqjl.job_id is null;
+ update replication_queue_lock set acquired = 't';\\""
+ CMD
+ end
+
+ def replication_queue_lock_count
+ result = []
+ cmd = <<~CMD
+ docker exec --env PGPASSWORD=SQL_PASSWORD #{@postgres} \
+ bash -c "psql -U postgres -d praefect_production -h postgres.test \
+ -c \\"select count(*) from replication_queue_lock where acquired = 't';\\""
+ CMD
+ shell cmd do |line|
+ result << line
+ end
+ # The result looks like:
+ # count
+ # -----
+ # 1
+ result[2].to_i
+ end
+
+ def reset_cluster
+ start_node(@praefect)
+ start_node(@primary_node)
+ start_node(@secondary_node)
+ start_node(@tertiary_node)
+ enable_writes
+ end
+
+ def wait_for_praefect
+ wait_until_shell_command_matches(
+ "docker exec #{@praefect} bash -c 'cat /var/log/gitlab/praefect/current'",
+ /listening at tcp address/
+ )
+ end
+
+ def wait_for_sql_ping
+ wait_until_shell_command_matches(
+ "docker exec #{@praefect} bash -c '/opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-ping'",
+ /praefect sql-ping: OK/
+ )
+ end
+
+ def wait_for_storage_nodes
+ nodes_confirmed = {
+ @primary_node => false,
+ @secondary_node => false,
+ @tertiary_node => false
+ }
+
+ wait_until_shell_command("docker exec #{@praefect} bash -c '/opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes'") do |line|
+ QA::Runtime::Logger.info(line.chomp)
+
+ nodes_confirmed.each_key do |node|
+ nodes_confirmed[node] = true if line =~ /SUCCESS: confirmed Gitaly storage "#{node}" in virtual storages \[#{@virtual_storage}\] is served/
+ end
+
+ nodes_confirmed.values.all?
+ end
+ end
+
+ def wait_for_gitaly_check
+ storage_ok = false
+ check_finished = false
+
+ wait_until_shell_command("docker exec #{@gitlab} bash -c 'gitlab-rake gitlab:gitaly:check'") do |line|
+ QA::Runtime::Logger.info(line.chomp)
+
+ storage_ok = true if line =~ /Gitaly: ... #{@virtual_storage} ... OK/
+ check_finished = true if line =~ /Checking Gitaly ... Finished/
+
+ storage_ok && check_finished
+ end
+ end
+
+ def wait_for_gitlab_shell_check
+ wait_until_shell_command_matches(
+ "docker exec #{@gitlab} bash -c 'gitlab-rake gitlab:gitlab_shell:check'",
+ /Checking GitLab Shell ... Finished/
+ )
+ end
+
+ def wait_for_reliable_connection
+ wait_for_praefect
+ wait_for_sql_ping
+ wait_for_storage_nodes
+ wait_for_gitaly_check
+ wait_for_gitlab_shell_check
+ end
+
+ private
+
+ def wait_until_shell_command(cmd)
+ Support::Waiter.wait_until do
+ shell cmd do |line|
+ break true if yield line
+ end
+ end
+ end
+
+ def wait_until_shell_command_matches(cmd, regex)
+ wait_until_shell_command(cmd) do |line|
+ QA::Runtime::Logger.info(line.chomp)
+
+ line =~ regex
+ end
end
end
end
diff --git a/qa/qa/service/shellout.rb b/qa/qa/service/shellout.rb
index 217df669db3..6efe50c4ae2 100644
--- a/qa/qa/service/shellout.rb
+++ b/qa/qa/service/shellout.rb
@@ -19,6 +19,13 @@ module QA
Open3.popen2e(*command) do |stdin, out, wait|
stdin.puts(stdin_data) if stdin_data
stdin.close if stdin_data
+
+ if block_given?
+ out.each do |line|
+ yield line
+ end
+ end
+
out.each_char { |char| print char }
if wait.value.exited? && wait.value.exitstatus.nonzero?
diff --git a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
index 1bf435014af..d836bdde9d5 100644
--- a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
@@ -3,7 +3,7 @@
require 'airborne'
module QA
- context 'Manage with IP rate limits', :requires_admin do
+ RSpec.describe 'Manage with IP rate limits', :requires_admin do
describe 'Users API' do
let(:api_client) { Runtime::API::Client.new(:gitlab, ip_limits: true) }
let(:request) { Runtime::API::Request.new(api_client, '/users') }
diff --git a/qa/qa/specs/features/api/1_manage/users_spec.rb b/qa/qa/specs/features/api/1_manage/users_spec.rb
index fbc26e81b69..0bd52cbdaa4 100644
--- a/qa/qa/specs/features/api/1_manage/users_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/users_spec.rb
@@ -3,13 +3,10 @@
require 'airborne'
module QA
- context 'Manage' do
+ RSpec.describe 'Manage' do
describe 'Users API' do
- before(:context) do
- @api_client = Runtime::API::Client.new(:gitlab)
- end
-
- let(:request) { Runtime::API::Request.new(@api_client, '/users') }
+ let(:api_client) { Runtime::API::Client.new(:gitlab) }
+ let(:request) { Runtime::API::Request.new(api_client, '/users') }
it 'GET /users' do
get request.url
diff --git a/qa/qa/specs/features/api/2_plan/.gitkeep b/qa/qa/specs/features/api/2_plan/.gitkeep
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/qa/qa/specs/features/api/2_plan/.gitkeep
+++ /dev/null
diff --git a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
index 58d716f759e..d72389f1d9d 100644
--- a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
+++ b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
@@ -3,7 +3,7 @@
require 'airborne'
module QA
- context 'Plan' do
+ RSpec.describe 'Plan' do
include Support::Api
describe 'Issue' do
diff --git a/qa/qa/specs/features/api/3_create/repository/changing_repository_storage_spec.rb b/qa/qa/specs/features/api/3_create/repository/changing_repository_storage_spec.rb
index d5ab6a3544d..11e7db5b097 100644
--- a/qa/qa/specs/features/api/3_create/repository/changing_repository_storage_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/changing_repository_storage_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
module QA
- context 'Create' do
- describe 'Changing Gitaly repository storage', :orchestrated, :requires_admin do
+ RSpec.describe 'Create' do
+ describe 'Changing Gitaly repository storage', :requires_admin do
shared_examples 'repository storage move' do
it 'confirms a `finished` status after moving project repository storage' do
expect(project).to have_file('README.md')
@@ -24,7 +24,7 @@ module QA
end
end
- context 'when moving from one Gitaly storage to another', :repository_storage do
+ context 'when moving from one Gitaly storage to another', :orchestrated, :repository_storage do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'repo-storage-move-status'
@@ -36,7 +36,9 @@ module QA
it_behaves_like 'repository storage move'
end
- context 'when moving from Gitaly to Gitaly Cluster', :requires_praefect do
+ # Note: This test doesn't have the :orchestrated tag because it runs in the Test::Integration::Praefect
+ # scenario with other tests that aren't considered orchestrated.
+ context 'when moving from Gitaly to Gitaly Cluster', :requires_praefect, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/227127', type: :investigating } do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'repo-storage-move'
diff --git a/qa/qa/specs/features/api/3_create/repository/files_spec.rb b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
index 92858ba4107..1a74b2c9da7 100644
--- a/qa/qa/specs/features/api/3_create/repository/files_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
@@ -4,7 +4,7 @@ require 'airborne'
require 'securerandom'
module QA
- describe 'API basics' do
+ RSpec.describe 'API basics' do
before(:context) do
@api_client = Runtime::API::Client.new(:gitlab)
end
diff --git a/qa/qa/specs/features/api/3_create/repository/praefect_replication_queue_spec.rb b/qa/qa/specs/features/api/3_create/repository/praefect_replication_queue_spec.rb
new file mode 100644
index 00000000000..a4040a46b84
--- /dev/null
+++ b/qa/qa/specs/features/api/3_create/repository/praefect_replication_queue_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require 'parallel'
+
+module QA
+ RSpec.describe 'Create' do
+ context 'Gitaly Cluster replication queue', :orchestrated, :gitaly_ha, :skip_live_env do
+ let(:praefect_manager) { Service::PraefectManager.new }
+ let(:project) do
+ Resource::Project.fabricate! do |project|
+ project.name = "gitaly_cluster"
+ project.initialize_with_readme = true
+ end
+ end
+
+ after do
+ praefect_manager.reset_cluster
+ praefect_manager.clear_replication_queue
+ end
+
+ it 'allows replication of different repository after interruption' do
+ # We want to fill the replication queue with 10 `in_progress` jobs,
+ # while a lock has been acquired, which is when the problem occurred
+ # as reported in https://gitlab.com/gitlab-org/gitaly/-/issues/2801
+ #
+ # We'll do this by creating 10 branches and pushing them all at once,
+ # and then stop Praefect when a lock is acquired, set all the jobs
+ # to `in_progress`, and create a job lock for each one.
+ queue_size_target = 10
+
+ Git::Repository.perform do |repository|
+ repository.uri = project.repository_http_location.uri
+ repository.use_default_credentials
+ repository.clone
+ repository.configure_identity('GitLab QA', 'root@gitlab.com')
+ 1.upto(queue_size_target) do |i|
+ repository.checkout("branch#{i}", new_branch: true)
+ repository.commit_file("file#{i}", SecureRandom.random_bytes(10000000), "Add file#{i}")
+ end
+ repository.push_all_branches
+ end
+
+ count = 0
+ while count < 1
+ count = praefect_manager.replication_queue_lock_count
+ QA::Runtime::Logger.debug("Lock count: #{count}")
+ end
+
+ praefect_manager.stop_praefect
+ praefect_manager.create_stalled_replication_queue
+
+ praefect_manager.start_praefect
+ praefect_manager.wait_for_reliable_connection
+
+ # Create a new project, push to it, and check that replication occurs
+ project_push = Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project_name = "gitaly_cluster"
+ end
+
+ expect(praefect_manager.replicated?(project_push.project.id)).to be true
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
index 3ad56e21ad4..e66e8f8c9d4 100644
--- a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
@@ -5,33 +5,36 @@ require 'securerandom'
require 'digest'
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Compare archives of different user projects with the same name and check they\'re different' do
include Support::Api
+ let(:project_name) { "project-archive-download-#{SecureRandom.hex(8)}" }
- before do
- @project_name = "project-archive-download-#{SecureRandom.hex(8)}"
- @archive_types = %w(tar.gz tar.bz2 tar zip)
- @users = {
+ let(:archive_types) { %w(tar.gz tar.bz2 tar zip) }
+
+ let(:users) do
+ {
user1: { username: Runtime::Env.gitlab_qa_username_1, password: Runtime::Env.gitlab_qa_password_1 },
user2: { username: Runtime::Env.gitlab_qa_username_2, password: Runtime::Env.gitlab_qa_password_2 }
}
+ end
- @users.each do |_, user_info|
+ before do
+ users.each do |_, user_info|
user_info[:user] = Resource::User.fabricate_or_use(user_info[:username], user_info[:password])
user_info[:api_client] = Runtime::API::Client.new(:gitlab, user: user_info[:user])
user_info[:api_client].personal_access_token
- user_info[:project] = create_project(user_info[:user], user_info[:api_client], @project_name)
+ user_info[:project] = create_project(user_info[:user], user_info[:api_client], project_name)
end
end
it 'download archives of each user project then check they are different' do
archive_checksums = {}
- @users.each do |user_key, user_info|
+ users.each do |user_key, user_info|
archive_checksums[user_key] = {}
- @archive_types.each do |type|
+ archive_types.each do |type|
archive_path = download_project_archive_via_api(user_info[:api_client], user_info[:project], type).path
archive_checksums[user_key][type] = Digest::MD5.hexdigest(File.read(archive_path))
end
diff --git a/qa/qa/specs/features/api/4_verify/.gitkeep b/qa/qa/specs/features/api/4_verify/.gitkeep
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/qa/qa/specs/features/api/4_verify/.gitkeep
+++ /dev/null
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
new file mode 100644
index 00000000000..a406fa409d5
--- /dev/null
+++ b/qa/qa/specs/features/api/4_verify/pipeline_deletion_spec.rb
@@ -0,0 +1,63 @@
+# 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=master")
+ 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}") }
+
+ after do
+ runner.remove_via_api!
+ end
+
+ context 'when deleted via API' do
+ it 'is not found' do
+ delete(pipeline_data_request.url)
+ expect(JSON.parse(get(pipeline_data_request.url))['message'].downcase).to have_content('404 not found')
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/api/1_manage/.gitkeep b/qa/qa/specs/features/api/8_monitor/.gitkeep
index e69de29bb2d..e69de29bb2d 100644
--- a/qa/qa/specs/features/api/1_manage/.gitkeep
+++ b/qa/qa/specs/features/api/8_monitor/.gitkeep
diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/create_group_with_mattermost_team_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/create_group_with_mattermost_team_spec.rb
index 7143cc574b8..5b89bcc7375 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/group/create_group_with_mattermost_team_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/group/create_group_with_mattermost_team_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Configure', :orchestrated, :mattermost do
+ RSpec.describe 'Configure', :orchestrated, :mattermost do
describe 'Mattermost support' do
it 'user creates a group with a mattermost team' do
Flow::Login.sign_in
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 9eab03323a8..f307d286587 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
@@ -1,24 +1,32 @@
# frozen_string_literal: true
module QA
- context 'Manage' do
+ RSpec.describe 'Manage' do
describe 'Project transfer between groups' do
- it 'user transfers a project between groups' do
- Flow::Login.sign_in
-
- source_group = Resource::Group.fabricate_via_api! do |group|
+ let(:source_group) do
+ Resource::Group.fabricate_via_api! do |group|
group.path = 'source-group'
end
+ end
- target_group = Resource::Group.fabricate_via_api! do |group|
+ let(:target_group) do
+ Resource::Group.fabricate_via_api! do |group|
group.path = 'target-group'
end
+ end
- project = Resource::Project.fabricate_via_api! do |project|
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
project.group = source_group
project.name = 'transfer-project'
project.initialize_with_readme = true
end
+ end
+
+ let(:edited_readme_content) { 'Here is the edited content.' }
+
+ before do
+ Flow::Login.sign_in
project.visit!
@@ -28,14 +36,14 @@ module QA
Page::File::Show.perform(&:click_edit)
- edited_readme_content = 'Here is the edited content.'
-
Page::File::Edit.perform do |file|
file.remove_content
file.add_content(edited_readme_content)
file.commit_changes
end
+ end
+ it 'user transfers a project between groups' do
Page::File::Show.perform(&:go_to_general_settings)
Page::Project::Settings::Main.perform(&:expand_advanced_settings)
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
index 1050005a231..9cb765705e0 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Manage', :smoke do
+ RSpec.describe 'Manage', :smoke do
describe 'basic user login' do
it 'user logs in using basic credentials and logs out' do
Flow::Login.sign_in
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
new file mode 100644
index 00000000000..d0ab945124b
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Manage', :requires_admin, :skip_live_env do
+ describe '2FA' do
+ let(:owner_user) do
+ Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_2fa_owner_username_1, Runtime::Env.gitlab_qa_2fa_owner_password_1)
+ end
+
+ let(:sandbox_group) do
+ Resource::Sandbox.fabricate! do |sandbox_group|
+ sandbox_group.path = "gitlab-qa-2fa-sandbox-group"
+ sandbox_group.api_client = owner_api_client
+ end
+ end
+
+ let(:group) do
+ QA::Resource::Group.fabricate_via_api! do |group|
+ group.sandbox = sandbox_group
+ group.api_client = owner_api_client
+ group.name = 'group-with-2fa'
+ end
+ end
+
+ let(:developer_user) do
+ Resource::User.fabricate_via_api! do |resource|
+ resource.api_client = admin_api_client
+ end
+ end
+
+ 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
+ group.add_member(developer_user, Resource::Members::AccessLevel::DEVELOPER)
+ end
+
+ it 'allows enforcing 2FA via UI and logging in with 2FA' do
+ enforce_two_factor_authentication_on_group(group)
+
+ enable_two_factor_authentication_for_user(developer_user)
+
+ Flow::Login.sign_in(as: developer_user, skip_page_validation: true)
+
+ Page::Main::TwoFactorAuth.perform do |two_fa_auth|
+ two_fa_auth.set_2fa_code('000000')
+ two_fa_auth.click_verify_code_button
+ end
+
+ expect(page).to have_text('Invalid two-factor code')
+
+ Page::Main::TwoFactorAuth.perform do |two_fa_auth|
+ two_fa_auth.set_2fa_code(@otp.fresh_otp)
+ two_fa_auth.click_verify_code_button
+ end
+
+ expect(Page::Main::Menu.perform(&:signed_in?)).to be_truthy
+ end
+
+ after do
+ group.set_require_two_factor_authentication(value: 'false')
+ group.remove_via_api! do |resource|
+ resource.api_client = admin_api_client
+ end
+ developer_user.remove_via_api!
+ end
+
+ def admin_api_client
+ @admin_api_client ||= Runtime::API::Client.as_admin
+ end
+
+ def owner_api_client
+ @owner_api_client ||= Runtime::API::Client.new(:gitlab, user: owner_user)
+ end
+
+ # We are intentionally using the UI to enforce 2FA to exercise the flow with UI.
+ # Any future tests should use the API for this purpose.
+ def enforce_two_factor_authentication_on_group(group)
+ Flow::Login.while_signed_in(as: owner_user) do
+ group.visit!
+
+ Page::Group::Menu.perform(&:click_group_general_settings_item)
+ Page::Group::Settings::General.perform(&:set_require_2fa_enabled)
+
+ expect(page).to have_text(two_fa_expected_text)
+
+ Page::Profile::TwoFactorAuth.perform(&:click_configure_it_later_button)
+
+ expect(page).not_to have_text(two_fa_expected_text)
+ end
+ end
+
+ def enable_two_factor_authentication_for_user(user)
+ Flow::Login.while_signed_in(as: user) do
+ expect(page).to have_text(two_fa_expected_text)
+
+ Page::Profile::TwoFactorAuth.perform do |two_fa_auth|
+ @otp = QA::Support::OTP.new(two_fa_auth.otp_secret_content)
+
+ two_fa_auth.set_pin_code(@otp.fresh_otp)
+ two_fa_auth.click_register_2fa_app_button
+
+ expect(two_fa_auth).to have_text('Congratulations! You have enabled Two-factor Authentication!')
+
+ two_fa_auth.click_proceed_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb
index 46a0f1a4c8b..5933637045f 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Manage', :orchestrated, :ldap_no_tls, :ldap_tls do
+ RSpec.describe 'Manage', :orchestrated, :ldap_no_tls, :ldap_tls do
describe 'LDAP login' do
it 'user logs into GitLab using LDAP credentials' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb
index a680cfa96bd..c7bd372c144 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Manage', :orchestrated, :mattermost do
+ RSpec.describe 'Manage', :orchestrated, :mattermost do
describe 'Mattermost login' do
it 'user logs into Mattermost using GitLab OAuth' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb
index ad67f02eaca..505da623d66 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Manage', :orchestrated, :instance_saml do
+ RSpec.describe 'Manage', :orchestrated, :instance_saml do
describe 'Instance wide SAML SSO' do
it 'User logs in to gitlab with SAML SSO' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
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 a0e3fe0d91a..9dfeec37869 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- shared_examples 'registration and login' do
+ RSpec.shared_examples 'registration and login' do
it 'user registers and logs in' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
@@ -13,13 +13,13 @@ module QA
end
end
- context 'Manage', :skip_signup_disabled do
+ RSpec.describe 'Manage', :skip_signup_disabled do
describe 'standard' do
it_behaves_like 'registration and login'
end
end
- context 'Manage', :orchestrated, :ldap_no_tls, :skip_signup_disabled do
+ RSpec.describe 'Manage', :orchestrated, :ldap_no_tls, :skip_signup_disabled do
describe 'while LDAP is enabled' do
it_behaves_like 'registration and login'
end
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 67055537567..8d1fa3ee62d 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Manage' do
+ RSpec.describe 'Manage' do
describe 'Add project member' do
it 'user adds project member' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
index 9ca933a957f..80b5e332abe 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Manage', :smoke do
+ RSpec.describe 'Manage', :smoke do
describe 'Project creation' do
it 'user creates a new project' do
Flow::Login.sign_in
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 1f1adf9afb4..6ce97188d66 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
@@ -3,7 +3,7 @@
require 'nokogiri'
module QA
- context 'Manage', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/212145', type: :stale } do
+ RSpec.describe 'Manage', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/212145', type: :stale } do
describe 'Check for broken images', :requires_admin do
before(:context) do
admin = QA::Resource::User.new.tap do |user|
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 409d67d51b1..94cf1fe1f8c 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Manage', :github, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/issues/26952', type: :bug } do
+ RSpec.describe 'Manage', :github, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/issues/26952', type: :bug } do
describe 'Project import from GitHub' do
let(:imported_project) do
Resource::ProjectImportedFromGithub.fabricate! do |project|
@@ -62,12 +62,9 @@ module QA
Page::Project::Issue::Show.perform do |issue_page|
expect(issue_page).to have_comment(comment_text)
- end
-
- Page::Issuable::Sidebar.perform do |issuable|
- expect(issuable).to have_label('enhancement')
- expect(issuable).to have_label('help wanted')
- expect(issuable).to have_label('good first issue')
+ expect(issue_page).to have_label('enhancement')
+ expect(issue_page).to have_label('help wanted')
+ expect(issue_page).to have_label('good first issue')
end
end
end
@@ -91,9 +88,9 @@ module QA
expect(page).to have_content('[Review comment] Nice blank line.')
expect(page).to have_content('[Single diff comment] Much better without this line!')
- Page::Issuable::Sidebar.perform do |issuable|
- expect(issuable).to have_label('bug')
- expect(issuable).to have_label('enhancement')
+ Page::MergeRequest::Show.perform do |merge_request|
+ expect(merge_request).to have_label('bug')
+ expect(merge_request).to have_label('enhancement')
end
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
new file mode 100644
index 00000000000..e40dde64675
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Manage' do
+ describe 'Repository tags' do
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-for-tags'
+ project.initialize_with_readme = true
+ end
+ 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' }
+ let(:tag_message) { 'Version 0.0.1' }
+ let(:tag_release_notes) { 'Release It!' }
+
+ shared_examples 'successful tag creation' do |user|
+ it "can be created by #{user}" do
+ Flow::Login.sign_in(as: send(user))
+
+ create_tag_for_project(project, tag_name, tag_message, tag_release_notes)
+
+ Page::Project::Tag::Show.perform do |show|
+ expect(show).to have_tag_name(tag_name)
+ expect(show).to have_tag_message(tag_message)
+ expect(show).to have_tag_release_notes(tag_release_notes)
+ expect(show).not_to have_element(:create_tag_button)
+ end
+ end
+ end
+
+ shared_examples 'unsuccessful tag creation' do |user|
+ it "cannot be created by an unauthorized #{user}" do
+ Flow::Login.sign_in(as: send(user))
+
+ create_tag_for_project(project, tag_name, tag_message, tag_release_notes)
+
+ Page::Project::Tag::New.perform do |new_tag|
+ expect(new_tag).to have_content('You are not allowed to create this tag as it is protected.')
+ expect(new_tag).to have_element(:create_tag_button)
+ end
+ end
+ end
+
+ context 'when not protected' do
+ before do
+ add_members_to_project(project)
+ end
+
+ it_behaves_like 'successful tag creation', :developer_user
+ it_behaves_like 'successful tag creation', :maintainer_user
+ end
+
+ context 'when protected' do
+ before do
+ add_members_to_project(project)
+
+ Flow::Login.sign_in
+
+ protect_tag_for_project(project, 'v*', 'Maintainers')
+
+ Page::Main::Menu.perform(&:sign_out)
+ end
+
+ it_behaves_like 'unsuccessful tag creation', :developer_user
+ it_behaves_like 'successful tag creation', :maintainer_user
+ end
+
+ def create_tag_for_project(project, name, message, release_notes)
+ project.visit!
+
+ Page::Project::Menu.perform(&:go_to_repository_tags)
+ Page::Project::Tag::Index.perform(&:click_new_tag_button)
+
+ Page::Project::Tag::New.perform do |new_tag|
+ new_tag.fill_tag_name(name)
+ new_tag.fill_tag_message(message)
+ new_tag.fill_release_notes(release_notes)
+ new_tag.click_create_tag_button
+ end
+ end
+
+ def protect_tag_for_project(project, tag, role)
+ project.visit!
+
+ Page::Project::Menu.perform(&:go_to_repository_settings)
+
+ Page::Project::Settings::Repository.perform do |setting|
+ setting.expand_protected_tags do |protected_tags|
+ protected_tags.set_tag(tag)
+ protected_tags.choose_access_level_role(role)
+
+ protected_tags.click_protect_tag_button
+ end
+ end
+ end
+
+ def add_members_to_project(project)
+ @developer_user = developer_user
+ @maintainer_user = maintainer_user
+
+ project.add_member(@developer_user, Resource::Members::AccessLevel::DEVELOPER)
+ project.add_member(@maintainer_user, Resource::Members::AccessLevel::MAINTAINER)
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb
index d483dcc97a7..b98d2982684 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Manage' do
+ RSpec.describe 'Manage' do
describe 'Project activity' do
it 'user creates an event in the activity page upon Git push' do
Flow::Login.sign_in
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 0a577aa07f8..3717bc8a9ff 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Plan', :orchestrated, :smtp do
+ RSpec.describe 'Plan', :orchestrated, :smtp do
describe 'Email Notification' do
include Support::Api
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 57d2c02a27b..784f474a7d5 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable do
describe 'check xss occurence in @mentions in issues', :requires_admin do
it 'mentions a user in a comment' do
QA::Runtime::Env.personal_access_token = QA::Runtime::Env.admin_personal_access_token
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
index 33d2c7026b3..478f6b8177c 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable do
describe 'collapse comments in issue discussions' do
let(:my_first_reply) { 'My first reply' }
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
index 4667eb6c587..0347de42b96 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable do
describe 'Issue comments' do
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
index 57b0859856e..e41024e5d14 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Plan', :smoke do
+ RSpec.describe 'Plan', :smoke do
describe 'Issue creation' do
let(:closed_issue) { Resource::Issue.fabricate_via_api! }
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb
index 3727aae2270..aa03a514f04 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb
@@ -3,7 +3,7 @@
require 'securerandom'
module QA
- context 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable do
describe 'Issues list' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
index b7687f785a8..082933e9878 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable do
describe 'filter issue comments activities' do
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
index 623573a1397..43f4415c90d 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable do
describe 'issue suggestions' do
let(:issue_title) { 'Issue Lists are awesome' }
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/jira_issue_import_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/jira_issue_import_spec.rb
new file mode 100644
index 00000000000..a2e7d10f313
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/jira_issue_import_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Plan' do
+ describe 'Jira issue import', :jira, :orchestrated, :requires_admin do
+ let(:jira_project_key) { "JITD" }
+ let(:jira_issue_title) { "[#{jira_project_key}-1] Jira to GitLab Test Issue" }
+ let(:jira_issue_description) { "This issue is for testing importing Jira issues to GitLab." }
+ let(:jira_issue_label_1) { "jira-import::#{jira_project_key}-1" }
+ let(:jira_issue_label_2) { "QA" }
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = "jira_issue_import"
+ end
+ end
+
+ it 'imports issues from Jira' do
+ set_up_jira_integration
+ import_jira_issues
+
+ QA::Support::Retrier.retry_on_exception do
+ Page::Project::Menu.perform(&:click_issues)
+
+ Page::Project::Issue::Index.perform do |issues_page|
+ expect(issues_page).to have_content("2 issues successfully imported")
+
+ issues_page.click_issue_link(jira_issue_title)
+ end
+ end
+
+ expect(page).to have_content(jira_issue_description)
+
+ Page::Project::Issue::Show.perform do |issue|
+ expect(issue).to have_label(jira_issue_label_1)
+ expect(issue).to have_label(jira_issue_label_2)
+ end
+ end
+
+ private
+
+ def set_up_jira_integration
+ # Retry is required because allow_local_requests_from_web_hooks_and_services
+ # takes some time to get enabled.
+ # Bug issue: https://gitlab.com/gitlab-org/gitlab/-/issues/217010
+ QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 3) do
+ Runtime::ApplicationSettings.set_application_settings(allow_local_requests_from_web_hooks_and_services: true)
+
+ page.visit Runtime::Scenario.gitlab_address
+ Flow::Login.sign_in_unless_signed_in
+
+ project.visit!
+
+ Page::Project::Menu.perform(&:go_to_integrations_settings)
+ QA::Page::Project::Settings::Integrations.perform(&:click_jira_link)
+
+ QA::Page::Project::Settings::Services::Jira.perform do |jira|
+ jira.setup_service_with(url: Vendor::Jira::JiraAPI.perform(&:base_url))
+ end
+
+ expect(page).not_to have_text("Url is blocked")
+ expect(page).to have_text("Jira activated")
+ end
+ end
+
+ def import_jira_issues
+ Page::Project::Menu.perform(&:click_issues)
+ Page::Project::Issue::Index.perform(&:go_to_jira_import_form)
+
+ Page::Project::Issue::JiraImport.perform do |form|
+ form.select_project_and_import(jira_project_key)
+ end
+
+ expect(page).to have_content("Import in progress")
+ end
+ end
+ end
+end
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 3e575517ecb..50df1c3ef01 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,7 @@
# frozen_string_literal: true
module QA
- context 'Plan', :smoke, :reliable do
+ RSpec.describe 'Plan', :smoke, :reliable do
describe 'mention' do
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb
index c81a6f9281c..932eef8e38b 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable do
describe 'Issue board focus mode' do
let(:project) do
QA::Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb
new file mode 100644
index 00000000000..115701c5c02
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Plan' do
+ describe 'Milestones' do
+ include Support::Dates
+
+ let(:start_date) { current_date_yyyy_mm_dd }
+ let(:due_date) { next_month_yyyy_mm_dd }
+
+ let(:group) do
+ Resource::Group.fabricate_via_api! do |group|
+ group.name = 'group-to-test-milestones'
+ end
+ end
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-to-test-milestones'
+ end
+ end
+
+ let(:issue) do
+ Resource::Issue.fabricate_via_api! do |issue|
+ issue.project = project
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ shared_examples 'milestone assigned to existing issue' do
+ it 'is assigned to an existing issue' do
+ issue.visit!
+
+ Page::Project::Issue::Show.perform do |existing_issue|
+ existing_issue.assign_milestone(milestone)
+
+ expect(existing_issue).to have_milestone(milestone.title)
+ end
+ end
+ end
+
+ shared_examples 'milestone assigned to new issue' do
+ it 'is assigned to a new issue' do
+ Resource::Issue.fabricate_via_browser_ui! do |new_issue|
+ new_issue.project = project
+ new_issue.milestone = milestone
+ end
+
+ Page::Project::Issue::Show.perform do |issue|
+ expect(issue).to have_milestone(milestone.title)
+ end
+ end
+ end
+
+ context 'Group milestone' do
+ let(:milestone) do
+ Resource::GroupMilestone.fabricate_via_api! do |milestone|
+ milestone.group = group
+ milestone.start_date = start_date
+ milestone.due_date = due_date
+ end
+ end
+
+ it_behaves_like 'milestone assigned to existing issue'
+ it_behaves_like 'milestone assigned to new issue'
+ end
+
+ context 'Project milestone' do
+ let(:milestone) do
+ Resource::ProjectMilestone.fabricate_via_api! do |milestone|
+ milestone.project = project
+ milestone.start_date = start_date
+ milestone.due_date = due_date
+ end
+ end
+
+ it_behaves_like 'milestone assigned to existing issue'
+ it_behaves_like 'milestone assigned to new issue'
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb
new file mode 100644
index 00000000000..35c42796aeb
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Plan' do
+ describe 'Group milestone' do
+ include Support::Dates
+
+ let(:title) { 'Group milestone' }
+ let(:description) { 'This milestone tests out group milestones.' }
+ let(:start_date) { current_date_yyyy_mm_dd }
+ let(:due_date) { next_month_yyyy_mm_dd }
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ it 'creates a group milestone' do
+ group_milestone = Resource::GroupMilestone.fabricate_via_browser_ui! do |milestone|
+ milestone.title = title
+ milestone.description = description
+ milestone.start_date = start_date
+ milestone.due_date = due_date
+ end
+
+ Page::Group::Menu.perform(&:go_to_milestones)
+ Page::Group::Milestone::Index.perform do |milestone_list|
+ expect(milestone_list).to have_milestone(group_milestone)
+
+ milestone_list.click_milestone(group_milestone)
+ end
+
+ Page::Milestone::Show.perform do |milestone|
+ expect(milestone).to have_element(:milestone_title_content, text: title)
+ expect(milestone).to have_element(:milestone_description_content, text: description)
+ expect(milestone).to have_start_date(start_date)
+ expect(milestone).to have_due_date(due_date)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb
new file mode 100644
index 00000000000..143fdf5728b
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Plan' do
+ describe 'Project milestone' do
+ include Support::Dates
+
+ let(:title) { 'Project milestone' }
+ let(:description) { 'This issue tests out project milestones.' }
+ let(:start_date) { current_date_yyyy_mm_dd }
+ let(:due_date) { next_month_yyyy_mm_dd }
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ it 'creates a project milestone' do
+ project_milestone = Resource::ProjectMilestone.fabricate_via_browser_ui! do |milestone|
+ milestone.title = title
+ milestone.description = description
+ milestone.start_date = start_date
+ milestone.due_date = due_date
+ end
+
+ Page::Project::Menu.perform(&:go_to_milestones)
+ Page::Project::Milestone::Index.perform do |milestone_list|
+ expect(milestone_list).to have_milestone(project_milestone)
+
+ milestone_list.click_milestone(project_milestone)
+ end
+
+ Page::Milestone::Show.perform do |milestone|
+ expect(milestone).to have_element(:milestone_title_content, text: title)
+ expect(milestone).to have_element(:milestone_description_content, text: description)
+ expect(milestone).to have_start_date(start_date)
+ expect(milestone).to have_due_date(due_date)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/gitaly/high_availability_spec.rb b/qa/qa/specs/features/browser_ui/3_create/gitaly/high_availability_spec.rb
index 3bb03f68d51..97a76c1aa01 100644
--- a/qa/qa/specs/features/browser_ui/3_create/gitaly/high_availability_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/gitaly/high_availability_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
context 'Gitaly' do
describe 'High Availability', :orchestrated, :gitaly_ha do
let(:project) do
@@ -10,15 +10,15 @@ module QA
end
end
let(:initial_file) { 'pushed_to_primary.txt' }
- let(:final_file) { 'pushed_to_secondary.txt' }
+ let(:final_file) { 'committed_to_primary.txt' }
+ let(:praefect_manager) { Service::PraefectManager.new }
before do
- @praefect_manager = Service::PraefectManager.new
Flow::Login.sign_in
end
after do
- @praefect_manager.reset
+ praefect_manager.reset_cluster
end
it 'makes sure that automatic failover is happening' do
@@ -30,7 +30,7 @@ module QA
push.file_content = "This should exist on both nodes"
end
- @praefect_manager.stop_primary_node
+ praefect_manager.trigger_failover_by_stopping_primary_node
project.visit!
@@ -41,11 +41,13 @@ module QA
expect(show).to have_file(initial_file)
end
+ praefect_manager.enable_writes
+
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.project = project
commit.add_files([
{
- file_path: 'committed_to_primary.txt',
+ file_path: final_file,
content: 'This should exist on both nodes too'
}
])
diff --git a/qa/qa/specs/features/browser_ui/3_create/jira/jira_basic_integration_spec.rb b/qa/qa/specs/features/browser_ui/3_create/jira/jira_basic_integration_spec.rb
index 05a932fd53e..28338475cb5 100644
--- a/qa/qa/specs/features/browser_ui/3_create/jira/jira_basic_integration_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/jira/jira_basic_integration_spec.rb
@@ -1,23 +1,24 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
include Support::Api
describe 'Jira integration', :jira, :orchestrated, :requires_admin do
let(:jira_project_key) { 'JITP' }
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = "project_with_jira_integration"
+ end
+ end
- before(:all) do
+ before do
page.visit Vendor::Jira::JiraAPI.perform(&:base_url)
QA::Support::Retrier.retry_until(sleep_interval: 3, reload_page: page, max_attempts: 20, raise_on_failure: true) do
page.has_text? 'Welcome to Jira'
end
- @project = Resource::Project.fabricate_via_api! do |project|
- project.name = "project_with_jira_integration"
- end
-
# Retry is required because allow_local_requests_from_web_hooks_and_services
# takes some time to get enabled.
# Bug issue: https://gitlab.com/gitlab-org/gitlab/-/issues/217010
@@ -27,7 +28,7 @@ module QA
page.visit Runtime::Scenario.gitlab_address
Flow::Login.sign_in_unless_signed_in
- @project.visit!
+ project.visit!
Page::Project::Menu.perform(&:go_to_integrations_settings)
QA::Page::Project::Settings::Integrations.perform(&:click_jira_link)
@@ -67,9 +68,11 @@ module QA
expect_issue_done(issue_key)
end
+ private
+
def create_mr_with_description(description)
Resource::MergeRequest.fabricate! do |merge_request|
- merge_request.project = @project
+ merge_request.project = project
merge_request.target_new_branch = !master_branch_exists?
merge_request.description = description
end
@@ -80,7 +83,7 @@ module QA
push.branch_name = 'master'
push.commit_message = commit_message
push.file_content = commit_message
- push.project = @project
+ push.project = project
push.new_branch = !master_branch_exists?
end
end
@@ -98,7 +101,7 @@ module QA
end
def master_branch_exists?
- @project.repository_branches.map { |item| item[:name] }.include?("master")
+ project.repository_branches.map { |item| item[:name] }.include?("master")
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
index 4a9901f2a84..a002779d7d9 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
@@ -1,29 +1,31 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Create a new merge request' do
- before do
- Flow::Login.sign_in
-
- @project = Resource::Project.fabricate_via_api! do |project|
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
project.name = 'project'
end
+ end
+
+ let(:merge_request_title) { 'One merge request to rule them all' }
+ let(:merge_request_description) { '... to find them, to bring them all, and in the darkness bind them' }
- @merge_request_title = 'One merge request to rule them all'
- @merge_request_description = '... to find them, to bring them all, and in the darkness bind them'
+ before do
+ Flow::Login.sign_in
end
it 'creates a basic merge request' do
Resource::MergeRequest.fabricate_via_browser_ui! do |merge_request|
- merge_request.project = @project
- merge_request.title = @merge_request_title
- merge_request.description = @merge_request_description
+ merge_request.project = project
+ merge_request.title = merge_request_title
+ merge_request.description = merge_request_description
end
Page::MergeRequest::Show.perform do |merge_request|
- expect(merge_request).to have_title(@merge_request_title)
- expect(merge_request).to have_description(@merge_request_description)
+ expect(merge_request).to have_title(merge_request_title)
+ expect(merge_request).to have_description(merge_request_description)
end
end
@@ -31,32 +33,29 @@ module QA
gitlab_account_username = "@#{Runtime::User.username}"
milestone = Resource::ProjectMilestone.fabricate_via_api! do |milestone|
- milestone.project = @project
+ milestone.project = project
end
label = Resource::Label.fabricate_via_api! do |label|
- label.project = @project
+ label.project = project
label.title = 'label'
end
Resource::MergeRequest.fabricate_via_browser_ui! do |merge_request|
- merge_request.title = @merge_request_title
- merge_request.description = @merge_request_description
- merge_request.project = @project
+ merge_request.title = merge_request_title
+ merge_request.description = merge_request_description
+ merge_request.project = project
merge_request.milestone = milestone
merge_request.assignee = 'me'
merge_request.labels.push(label)
end
Page::MergeRequest::Show.perform do |merge_request|
- expect(merge_request).to have_title(@merge_request_title)
- expect(merge_request).to have_description(@merge_request_description)
+ expect(merge_request).to have_title(merge_request_title)
+ expect(merge_request).to have_description(merge_request_description)
expect(merge_request).to have_assignee(gitlab_account_username)
expect(merge_request).to have_label(label.title)
- end
-
- Page::Issuable::Sidebar.perform do |sidebar|
- expect(sidebar).to have_milestone(milestone.title)
+ expect(merge_request).to have_milestone(milestone.title)
end
end
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 3964ae7eada..5b89bf046fb 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
@@ -1,19 +1,16 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Merge request creation from fork' do
- it 'user forks a project, submits a merge request and maintainer merges it' do
- Flow::Login.sign_in
-
- merge_request = Resource::MergeRequestFromFork.fabricate_via_browser_ui! do |merge_request|
+ let(:merge_request) do
+ Resource::MergeRequestFromFork.fabricate_via_api! do |merge_request|
merge_request.fork_branch = 'feature-branch'
end
+ end
- merge_request.project.api_put(auto_devops_enabled: false)
-
- Page::Main::Menu.perform(&:sign_out)
- Page::Main::Login.perform(&:sign_in_using_credentials)
+ it 'can merge feature branch fork to mainline' do
+ Flow::Login.sign_in
merge_request.visit!
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 4e189faec6e..a1c604bdcfc 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
- context 'Create', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/30226', type: :bug } do
+ RSpec.describe 'Create', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/30226', type: :bug } do
describe 'Merge request rebasing' do
it 'user rebases source branch of merge request' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
index 9236609934e..cb660a3e40b 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
@@ -1,19 +1,23 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Merge request squashing' do
- it 'user squashes commits while merging' do
- Flow::Login.sign_in
-
- project = Resource::Project.fabricate_via_api! do |project|
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
project.name = "squash-before-merge"
end
+ end
- merge_request = Resource::MergeRequest.fabricate! do |merge_request|
+ let(:merge_request) do
+ Resource::MergeRequest.fabricate_via_api! do |merge_request|
merge_request.project = project
merge_request.title = 'Squashing commits'
end
+ end
+
+ before do
+ Flow::Login.sign_in
Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project
@@ -25,7 +29,9 @@ module QA
end
merge_request.visit!
+ end
+ it 'user squashes commits while merging' do
Page::MergeRequest::Show.perform do |merge_request_page|
merge_request_page.retry_on_exception(reload: true) do
expect(merge_request_page).to have_text('to be squashed')
@@ -34,13 +40,9 @@ module QA
merge_request_page.mark_to_squash
merge_request_page.merge!
- merge_request.project.visit!
-
Git::Repository.perform do |repository|
- repository.uri = merge_request.project.repository_http_location.uri
-
+ repository.uri = project.repository_http_location.uri
repository.use_default_credentials
-
repository.clone
expect(repository.commits.size).to eq 3
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
index 604b6c10aee..3c2c068dfd1 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Download merge request patch and diff' do
before(:context) do
@merge_request = Resource::MergeRequest.fabricate_via_api! do |merge_request|
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
index d5346546efe..c02632c2c60 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
@@ -1,12 +1,14 @@
# frozen_string_literal: true
+require 'securerandom'
+
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'File templates' do
include Runtime::Fixtures
- before(:all) do
- @project = Resource::Project.fabricate_via_api! do |project|
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
project.name = 'file-template-project'
project.description = 'Add file templates via the Files view'
project.initialize_with_readme = true
@@ -46,7 +48,7 @@ module QA
Flow::Login.sign_in
- @project.visit!
+ project.visit!
Page::Project::Show.perform(&:create_new_file!)
Page::File::Form.perform do |form|
@@ -54,12 +56,14 @@ module QA
expect(form).to have_normalized_ws_text(content[0..100])
+ form.add_name("#{SecureRandom.hex(8)}/#{template[:file_name]}")
form.commit_changes
- expect(form).to have_content('The file has been successfully created.')
- expect(form).to have_content(template[:file_name])
- expect(form).to have_content('Add new file')
- expect(form).to have_normalized_ws_text(content[0..100])
+ aggregate_failures "indications of file created" do
+ expect(form).to have_content(template[:file_name])
+ expect(form).to have_normalized_ws_text(content[0..100])
+ expect(form).to have_content('Add new file')
+ end
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
index bf5a9501cba..cab909756c1 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Create, list, and delete branches via web' do
master_branch = 'master'
second_branch = 'second-branch'
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
deleted file mode 100644
index 68bbc1719fc..00000000000
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- context 'Create' do
- describe 'SSH keys support' do
- let(:key_title) { "key for ssh tests #{Time.now.to_f}" }
-
- it 'user adds and then removes an SSH key', :smoke do
- Flow::Login.sign_in
-
- key = Resource::SSHKey.fabricate_via_browser_ui! do |resource|
- resource.title = key_title
- end
-
- expect(page).to have_content(key.title)
- expect(page).to have_content(key.md5_fingerprint)
-
- Page::Main::Menu.perform(&:click_settings_link)
- Page::Profile::Menu.perform(&:click_ssh_keys)
-
- Page::Profile::SSHKeys.perform do |ssh_keys|
- ssh_keys.remove_key(key_title)
- end
-
- expect(page).not_to have_content("Title: #{key_title}")
- expect(page).not_to have_content(key.md5_fingerprint)
- end
- end
- end
-end
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 0650c8395c7..c9cbc68c254 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
@@ -1,16 +1,18 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Git clone over HTTP', :ldap_no_tls do
- before(:all) do
- @project = Resource::Project.fabricate_via_api! do |scenario|
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |scenario|
scenario.name = 'project-with-code'
scenario.description = 'project for git clone tests'
end
+ end
+ before do
Git::Repository.perform do |repository|
- repository.uri = @project.repository_http_location.uri
+ repository.uri = project.repository_http_location.uri
repository.use_default_credentials
repository.act do
@@ -21,12 +23,12 @@ module QA
push_changes
end
end
- @project.wait_for_push_new_branch
+ project.wait_for_push_new_branch
end
it 'user performs a deep clone' do
Git::Repository.perform do |repository|
- repository.uri = @project.repository_http_location.uri
+ repository.uri = project.repository_http_location.uri
repository.use_default_credentials
repository.clone
@@ -37,7 +39,7 @@ module QA
it 'user performs a shallow clone' do
Git::Repository.perform do |repository|
- repository.uri = @project.repository_http_location.uri
+ repository.uri = project.repository_http_location.uri
repository.use_default_credentials
repository.shallow_clone
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb
index 51a1c19f0f7..d66f0ddcda6 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Files management' do
it 'user creates, edits and deletes a file via the Web' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
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 d0123da53bb..f586c25165c 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/217002', type: :investigating } do
+ RSpec.describe 'Create', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/217002', type: :investigating } do
describe 'Gitaly repository storage', :orchestrated, :repository_storage, :requires_admin do
let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:parent_project) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb
index b210e747614..e3b0d7de9ec 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Push over HTTP using Git protocol version 2', :requires_git_protocol_v2 do
it 'user pushes to the repository' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb
index e3d5b755317..90beff343ab 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Push over SSH using Git protocol version 2', :requires_git_protocol_v2 do
# Note: If you run this test against GDK make sure you've enabled sshd and
# enabled setting the Git protocol by adding `AcceptEnv GIT_PROTOCOL` to
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 d8aaffc3713..c01558d3702 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Git push over HTTP', :ldap_no_tls do
it 'user using a personal access token pushes code to the repository' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
index ae95f5a7a44..254e32a88ce 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Push mirror a repository over HTTP' do
it 'configures and syncs a (push) mirrored repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
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 21ae10774c9..443ace0c9f0 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create', :requires_admin do
+ RSpec.describe 'Create', :requires_admin do
describe 'push after setting the file size limit via admin/application_settings' do
# Note: The file size limits in this test should be greater than the limits in
# ee/browser_ui/3_create/repository/push_rules_spec to prevent that test from
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 6c0d55cc69a..b918b2ff268 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Git push over HTTP', :ldap_no_tls do
it 'user pushes code to the repository' do
Flow::Login.sign_in
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 455db4d811d..3e1e470d8c3 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Protected branch support', :ldap_no_tls do
let(:branch_name) { 'protected-branch' }
let(:commit_message) { 'Protected push commit message' }
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/ssh_key_support_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/ssh_key_support_spec.rb
new file mode 100644
index 00000000000..d67e4a4ea83
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/ssh_key_support_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'SSH keys support', :smoke do
+ key_title = "key for ssh tests #{Time.now.to_f}"
+ key = nil
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ it 'user can add an SSH key' do
+ key = Resource::SSHKey.fabricate_via_browser_ui! do |resource|
+ resource.title = key_title
+ end
+
+ expect(page).to have_content(key.title)
+ expect(page).to have_content(key.md5_fingerprint)
+ end
+
+ # Note this context ensures that the example it contains is executed after the example above. Be aware of the order of execution if you add new examples in either context.
+ context 'after adding an ssh key' do
+ it 'can delete an ssh key' do
+ Page::Main::Menu.perform(&:click_settings_link)
+ Page::Profile::Menu.perform(&:click_ssh_keys)
+ Page::Profile::SSHKeys.perform do |ssh_keys|
+ ssh_keys.remove_key(key_title)
+ end
+
+ expect(page).not_to have_content("Title: #{key_title}")
+ expect(page).not_to have_content(key.md5_fingerprint)
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb
index 1a3c6d03098..e91717b0f5f 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'SSH key support' do
# Note: If you run this test against GDK make sure you've enabled sshd
# See: https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/run_qa_against_gdk.md
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb
index aee62bacfa8..cf91b829817 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Commit data' do
before(:context) do
# Get the user's details to confirm they're included in the email patch
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
new file mode 100644
index 00000000000..a867d9cb973
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Adding comments on snippets' do
+ let(:comment_author) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
+ let(:comment_content) { 'Comment 123' }
+ let(:edited_comment_content) { 'Nice snippet!' }
+
+ let(:personal_snippet) do
+ Resource::Snippet.fabricate! do |snippet|
+ snippet.title = 'Personal snippet with a comment'
+ end
+ end
+
+ let(:project_snippet) do
+ Resource::ProjectSnippet.fabricate! do |snippet|
+ snippet.title = 'Project snippet with a comment'
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ shared_examples 'comments on snippets' do |snippet_type|
+ it "adds, edits, and deletes a comment on a #{snippet_type}" do
+ send(snippet_type)
+
+ Page::Main::Menu.perform(&:sign_out)
+
+ Flow::Login.sign_in(as: comment_author)
+
+ send(snippet_type).visit!
+
+ create_comment
+ verify_comment_content(comment_author.username, comment_content)
+
+ edit_comment
+ verify_comment_content(comment_author.username, edited_comment_content)
+
+ delete_comment
+ verify_comment_deleted
+ end
+ end
+
+ it_behaves_like 'comments on snippets', :personal_snippet
+ it_behaves_like 'comments on snippets', :project_snippet
+
+ def create_comment
+ Page::Dashboard::Snippet::Show.perform do |snippet|
+ snippet.add_comment(comment_content)
+ end
+ end
+
+ def edit_comment
+ Page::Dashboard::Snippet::Show.perform do |snippet|
+ snippet.edit_comment(edited_comment_content)
+ end
+ end
+
+ def delete_comment
+ Page::Dashboard::Snippet::Show.perform do |snippet|
+ snippet.delete_comment(edited_comment_content)
+ end
+ end
+
+ def verify_comment_content(author, comment_content)
+ Page::Dashboard::Snippet::Show.perform do |comment|
+ expect(comment).to have_comment_author(author)
+ expect(comment).to have_comment_content(comment_content)
+ end
+ end
+
+ def verify_comment_deleted
+ expect(page).not_to have_content(comment_author.username)
+ expect(page).not_to have_content(edited_comment_content)
+ end
+ end
+ end
+end
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 341ff39fdf1..e6589851dd9 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Version control for personal snippets' do
let(:new_file) { 'new_snippet_file' }
let(:changed_content) { 'changes' }
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 a3011550db8..1660944fccd 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Version control for project snippets' do
let(:new_file) { 'new_snippet_file' }
let(:changed_content) { 'changes' }
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 451a7847f8b..d2b86904cd3 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
@@ -1,27 +1,30 @@
# frozen_string_literal: true
module QA
- context 'Create', :smoke do
+ RSpec.describe 'Create', :smoke do
describe 'Personal snippet creation' do
it 'User creates a personal snippet' do
Flow::Login.sign_in
- Page::Main::Menu.perform(&:go_to_snippets)
+ Page::Main::Menu.perform do |menu|
+ menu.go_to_more_dropdown_option(:snippets_link)
+ end
Resource::Snippet.fabricate_via_browser_ui! do |snippet|
snippet.title = 'Snippet title'
snippet.description = 'Snippet description'
snippet.visibility = 'Private'
- snippet.file_name = 'New snippet file name'
- snippet.file_content = 'Snippet file text'
+ snippet.file_name = 'ruby_file.rb'
+ snippet.file_content = 'File.read("test.txt").split(/\n/)'
end
Page::Dashboard::Snippet::Show.perform do |snippet|
expect(snippet).to have_snippet_title('Snippet title')
expect(snippet).to have_snippet_description('Snippet description')
expect(snippet).to have_visibility_type(/private/i)
- expect(snippet).to have_file_name('New snippet file name')
- expect(snippet).to have_file_content('Snippet file text')
+ expect(snippet).to have_file_name('ruby_file.rb')
+ expect(snippet).to have_file_content('File.read("test.txt").split(/\n/)')
+ expect(snippet).to have_syntax_highlighting('ruby')
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb
index 8fc4427bda7..05795e9b51e 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do # to be converted to a smoke test once proved to be stable
+ RSpec.describe 'Create' do # to be converted to a smoke test once proved to be stable
describe 'Project snippet creation' do
it 'User creates a project snippet' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
index 7c9db5ee496..1e3cb0e2ffc 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
@@ -1,7 +1,9 @@
# frozen_string_literal: true
+require 'securerandom'
+
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Web IDE file templates' do
include Runtime::Fixtures
@@ -53,10 +55,11 @@ module QA
ide.create_new_file_from_template template[:file_name], template[:name]
expect(ide.has_file?(template[:file_name])).to be_truthy
-
expect(ide).to have_button('Undo')
expect(ide).to have_normalized_ws_text(content[0..100])
+ ide.rename_file(template[:file_name], "#{SecureRandom.hex(8)}/#{template[:file_name]}")
+
ide.commit_changes
expect(ide).to have_content(template[:file_name])
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
index 3bf6e156967..fbf70153e1d 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'First file using Web IDE' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb
index ed988bdf046..7e0d8822101 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
describe 'Review a merge request in Web IDE' do
let(:new_file) { 'awesome_new_file.txt' }
let(:original_text) { 'Text' }
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_creation_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_creation_spec.rb
index 1d0c8ee60d4..77a5998362c 100644
--- a/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_creation_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_creation_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
context 'Wiki' do
describe 'testing wiki content creation inside a project' do
let(:new_wiki_title) { "just_another_wiki_page" }
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_manipulation_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_manipulation_spec.rb
index 10370c80476..dbc7798a594 100644
--- a/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_manipulation_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_content_manipulation_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ RSpec.describe 'Create' do
context 'Wiki' do
describe 'testing wiki content manipulation inside a project' do
let(:new_wiki_title) { "just_another_wiki_page" }
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_list_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_list_spec.rb
new file mode 100644
index 00000000000..d7f59abc361
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_list_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ context 'Wiki' do
+ let(:small_number_of_pages) { 5 }
+ let(:large_number_of_pages) { 15 }
+ let(:random_page) { "bulk_#{rand(0..4)}" }
+
+ let(:small_wiki) { create_wiki_pages small_number_of_pages }
+ let(:large_wiki) { create_wiki_pages large_number_of_pages }
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ context 'Sidebar' do
+ it 'has all expected links that work' do
+ small_wiki.visit!
+
+ small_number_of_pages.times do |index|
+ Page::Project::Wiki::Show.perform do |list|
+ expect(list).to have_page_listed "bulk_#{index}"
+ end
+ end
+
+ Page::Project::Wiki::Show.perform do |list|
+ list.click_page_link random_page
+ end
+
+ Page::Project::Wiki::Show.perform do |wiki|
+ expect(wiki).to have_title random_page
+ end
+ end
+ end
+
+ context 'Page List' do
+ it 'has all expected links that work' do
+ large_wiki.visit!
+
+ Page::Project::Wiki::Show.perform(&:click_view_all_pages)
+
+ large_number_of_pages.times do |index|
+ Page::Project::Wiki::List.perform do |list|
+ expect(list).to have_page_listed "bulk_#{index}"
+ end
+ end
+
+ Page::Project::Wiki::List.perform do |list|
+ list.click_page_link random_page
+ end
+
+ Page::Project::Wiki::Show.perform do |wiki|
+ expect(wiki).to have_title random_page
+ end
+ end
+ end
+
+ private
+
+ def create_wiki_pages(no_of_pages)
+ wiki = Resource::Wiki::ProjectPage.fabricate_via_api!
+ no_of_pages.times do |index|
+ Resource::Wiki::ProjectPage.fabricate_via_api! do |page|
+ page.title = "bulk_#{index}"
+ page.project = wiki.project
+ end
+ end
+ wiki
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_page_deletion_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_page_deletion_spec.rb
new file mode 100644
index 00000000000..923c7332748
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_page_deletion_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ context 'Wiki' do
+ let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ context 'Page deletion' do
+ it 'has removed the deleted page correctly' do
+ initial_wiki.visit!
+
+ Page::Project::Wiki::Show.perform(&:click_edit)
+ Page::Project::Wiki::Edit.perform(&:delete_page)
+
+ Page::Project::Wiki::Show.perform do |wiki|
+ expect(wiki).to have_no_page
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
index f05634bc3c8..41baaa02544 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Verify' do
+ RSpec.describe 'Verify', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/229724', type: :investigating } do
describe 'Add or Remove CI variable via UI', :smoke do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
index 2502e8beda7..68b4a38a043 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Verify', :docker, :runner do
+ RSpec.describe 'Verify', :docker, :runner do
describe 'Pipeline creation and processing' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:max_wait) { 30 }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb
index f8a589ad93b..82b15acb664 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Verify', :docker, :runner do
+ RSpec.describe 'Verify', :docker, :runner do
describe 'Runner registration' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let!(:runner) do
diff --git a/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb
index 4d549dde858..0436da40982 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Verify', :docker, :runner do
+ RSpec.describe 'Verify', :docker, :runner do
describe 'Code coverage statistics' do
let(:simplecov) { '\(\d+.\d+\%\) covered' }
let(:executor) { "qa-runner-#{Time.now.to_i}" }
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
index 89aba112407..d67fd96d338 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Release' do
+ RSpec.describe 'Release' do
describe 'Deploy key creation' do
it 'user adds a deploy key' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
index 73f2fef5f1d..18eb52830a2 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
@@ -3,7 +3,7 @@
require 'digest/sha1'
module QA
- context 'Release', :docker, :runner do
+ RSpec.describe 'Release', :docker, :runner do
describe 'Git clone using a deploy key' do
before do
Flow::Login.sign_in
@@ -20,7 +20,7 @@ module QA
resource.project = @project
resource.name = @runner_name
resource.tags = %w[qa docker]
- resource.image = 'gitlab/gitlab-runner:ubuntu'
+ resource.image = 'gitlab/gitlab-runner:alpine'
end
end
@@ -51,6 +51,7 @@ module QA
gitlab_ci = <<~YAML
cat-config:
script:
+ - apk add --update --no-cache openssh-client
- mkdir -p ~/.ssh
- ssh-keyscan -p #{@repository_location.port} #{@repository_location.host} >> ~/.ssh/known_hosts
- eval $(ssh-agent -s)
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
index a07f0bd5e54..9bee5c5ee08 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Release', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/213222', type: :flaky } do
+ RSpec.describe 'Release', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/213222', type: :flaky } do
describe 'Deploy token creation' do
it 'user adds a deploy token' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb
index e1d8c50ab75..673125c90f2 100644
--- a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Release', :docker, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/217250', type: :investigating } do
+ RSpec.describe 'Release', :docker, :runner, :reliable do
describe 'Parent-child pipelines dependent relationship' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
@@ -29,12 +29,8 @@ module QA
view_pipelines
Page::Project::Pipeline::Show.perform do |parent_pipeline|
+ expect(parent_pipeline).to have_child_pipeline
expect(parent_pipeline).to have_passed
-
- parent_pipeline.retry_on_exception(sleep_interval: 1.0) do
- parent_pipeline.click_linked_job(project.name)
- end
- expect(parent_pipeline).to have_job("child_job")
end
end
@@ -43,12 +39,8 @@ module QA
view_pipelines
Page::Project::Pipeline::Show.perform do |parent_pipeline|
+ expect(parent_pipeline).to have_child_pipeline
expect(parent_pipeline).to have_failed
-
- parent_pipeline.retry_on_exception(sleep_interval: 1.0) do
- parent_pipeline.click_linked_job(project.name)
- end
- expect(parent_pipeline).to have_job("child_job")
end
end
diff --git a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb
index c365e084991..05b9859f112 100644
--- a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Release', :docker, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/217250', type: :investigating } do
+ RSpec.describe 'Release', :docker, :runner, :reliable do
describe 'Parent-child pipelines independent relationship' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
@@ -29,12 +29,8 @@ module QA
view_pipelines
Page::Project::Pipeline::Show.perform do |parent_pipeline|
+ expect(parent_pipeline).to have_child_pipeline
expect(parent_pipeline).to have_passed
-
- parent_pipeline.retry_on_exception(reload: true, sleep_interval: 1.0) do
- parent_pipeline.click_linked_job(project.name)
- end
- expect(parent_pipeline).to have_job("child_job")
end
end
@@ -43,12 +39,8 @@ module QA
view_pipelines
Page::Project::Pipeline::Show.perform do |parent_pipeline|
+ expect(parent_pipeline).to have_child_pipeline
expect(parent_pipeline).to have_passed
-
- parent_pipeline.retry_on_exception(reload: true, sleep_interval: 1.0) do
- parent_pipeline.click_linked_job(project.name)
- end
- expect(parent_pipeline).to have_job("child_job")
end
end
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 292fc40bec4..ad87ee173f5 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
@@ -3,7 +3,7 @@
require 'pathname'
module QA
- context 'Configure' do
+ RSpec.describe 'Configure' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = Runtime::Env.auto_devops_project_name || 'autodevops-project'
diff --git a/qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb
index 0e9c369e97f..5073b715341 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
module QA
- context 'Configure' do
- describe 'Kubernetes Cluster Integration', :orchestrated, :kubernetes, :requires_admin, :skip_live_env do
+ RSpec.describe 'Configure' do
+ describe 'Kubernetes Cluster Integration', :orchestrated, :kubernetes, :requires_admin, :skip_live_env, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/225315', type: :flaky } do
context 'Project Clusters' do
let!(:cluster) { Service::KubernetesCluster.new(provider_class: Service::ClusterProvider::K3s).create! }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
index a9ed6651069..9cfdc4277a7 100644
--- a/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
+++ b/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Monitor' do
+ RSpec.describe 'Monitor' do
describe 'with Prometheus in a Gitlab-managed cluster', :orchestrated, :kubernetes do
before :all do
@cluster = Service::KubernetesCluster.new.create!
@@ -64,6 +64,19 @@ module QA
end
end
+ it 'observes cluster health graph' do
+ Page::Project::Menu.perform(&:go_to_operations_kubernetes)
+
+ Page::Project::Operations::Kubernetes::Index.perform do |cluster_list|
+ cluster_list.click_on_cluster(@cluster)
+ end
+
+ Page::Project::Operations::Kubernetes::Show.perform do |cluster_panel|
+ cluster_panel.open_health
+ cluster_panel.wait_for_cluster_health
+ end
+ end
+
private
def deploy_project_with_prometheus
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 c6d5fba919b..73bb6aeb5fd 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
@@ -1,8 +1,8 @@
# frozen_string_literal: true
module QA
- context 'Non-devops' do
- describe 'Performance bar display', :requires_admin do
+ RSpec.describe 'Non-devops' do
+ describe 'Performance bar display', :requires_admin, :skip_live_env do
context 'when logged in as an admin user' do
# performance metrics: pg, gitaly, redis, rugged (feature flagged), total (not always provided)
let(:minimum_metrics_count) { 3 }
diff --git a/qa/qa/specs/helpers/quarantine.rb b/qa/qa/specs/helpers/quarantine.rb
index dd3a50ac128..6a3becf0ee5 100644
--- a/qa/qa/specs/helpers/quarantine.rb
+++ b/qa/qa/specs/helpers/quarantine.rb
@@ -18,6 +18,10 @@ module QA
config.before do |example|
Quarantine.skip_or_run_quarantined_tests_or_contexts(config.inclusion_filter.rules, example)
+
+ if example.metadata.key?(:only)
+ skip('Test is not compatible with this environment') unless Runtime::Env.address_matches?(example.metadata[:only])
+ end
end
end
end
@@ -46,21 +50,15 @@ module QA
skip("Only running tests tagged with :quarantine and any of #{included_filters.keys}") if should_skip_when_focused?(example.metadata, included_filters)
else
if example.metadata.key?(:quarantine)
- quarantine_message = %w(In quarantine)
quarantine_tag = example.metadata[:quarantine]
- if !!quarantine_tag
- quarantine_message << case quarantine_tag
- when String
- ": #{quarantine_tag}"
- when Hash
- ": #{quarantine_tag[:issue]}"
- else
- ''
- end
+ if quarantine_tag&.is_a?(Hash) && quarantine_tag&.key?(:only)
+ # If the :quarantine hash contains :only, we respect that.
+ # For instance `quarantine: { only: { subdomain: :staging } }` will only quarantine the test when it runs against staging.
+ return unless Runtime::Env.address_matches?(quarantine_tag[:only])
end
- skip(quarantine_message.join(' ').strip)
+ skip(quarantine_message(quarantine_tag))
end
end
end
@@ -69,6 +67,20 @@ module QA
filter.reject { |key, _| key == :quarantine }
end
+ def quarantine_message(quarantine_tag)
+ quarantine_message = %w(In quarantine)
+ quarantine_message << case quarantine_tag
+ when String
+ ": #{quarantine_tag}"
+ when Hash
+ quarantine_tag.key?(:issue) ? ": #{quarantine_tag[:issue]}" : ''
+ else
+ ''
+ end
+
+ quarantine_message.join(' ').strip
+ end
+
# Checks if a test or context should be skipped.
#
# Returns true if
diff --git a/qa/qa/support/dates.rb b/qa/qa/support/dates.rb
index 47fc721afc1..3d1f146730b 100644
--- a/qa/qa/support/dates.rb
+++ b/qa/qa/support/dates.rb
@@ -11,6 +11,11 @@ module QA
current_date.next_month.strftime("%Y/%m/%d")
end
+ def format_date(date)
+ new_date = DateTime.strptime(date, "%Y/%m/%d")
+ new_date.strftime("%b %-d, %Y")
+ end
+
private
def current_date
diff --git a/qa/qa/support/otp.rb b/qa/qa/support/otp.rb
new file mode 100644
index 00000000000..0d7c394cf69
--- /dev/null
+++ b/qa/qa/support/otp.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+require 'rotp'
+
+module QA
+ module Support
+ class OTP
+ def initialize(secret)
+ @rotp = ROTP::TOTP.new(secret)
+ end
+
+ def fresh_otp
+ otps = []
+
+ # Fetches a fresh OTP and returns it only after rotp provides the same OTP twice
+ # An OTP is valid for 30 seconds so 70 attempts with 0.5 interval would ensure we complete 1 cycle
+ Support::Retrier.retry_until(max_attempts: 70, sleep_interval: 0.5) do
+ otps << @rotp.now
+ otps.size >= 3 && otps[-1] == otps[-2] && otps[-1] != otps[-3]
+ end
+
+ otps.last
+ end
+ end
+ end
+end
diff --git a/qa/spec/runtime/api/request_spec.rb b/qa/spec/runtime/api/request_spec.rb
index a20f1cf8559..8354eff6234 100644
--- a/qa/spec/runtime/api/request_spec.rb
+++ b/qa/spec/runtime/api/request_spec.rb
@@ -22,6 +22,12 @@ describe QA::Runtime::API::Request do
end
end
+ describe '#mask_url' do
+ it 'returns the full API request url with the token masked' do
+ expect(request.mask_url).to eq 'http://example.com/api/v4/users?private_token=[****]'
+ end
+ end
+
describe '#request_path' do
it 'prepends the api path' do
expect(request.request_path('/users')).to eq '/api/v4/users'
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
index f2e5eb35871..0cfb9a70c88 100644
--- a/qa/spec/runtime/env_spec.rb
+++ b/qa/spec/runtime/env_spec.rb
@@ -341,7 +341,7 @@ describe QA::Runtime::Env do
end
end
- describe '.dot_com?' do
+ describe '.address_matches?' do
it 'returns true when url has .com' do
QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
@@ -351,7 +351,45 @@ describe QA::Runtime::Env do
it 'returns false when url does not have .com' do
QA::Runtime::Scenario.define(:gitlab_address, "https://gitlab.test")
- expect(described_class.dot_com?).to be_falsy
+ expect(described_class.dot_com?).to be_falsey
+ end
+
+ context 'with arguments' do
+ it 'returns true when :subdomain is set' do
+ QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
+
+ expect(described_class.dot_com?(subdomain: :staging)).to be_truthy
+ end
+
+ it 'matches multiple subdomains' do
+ QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
+
+ expect(described_class.address_matches?(subdomain: [:release, :staging])).to be_truthy
+ expect(described_class.address_matches?(:production, subdomain: [:release, :staging])).to be_truthy
+ end
+
+ it 'matches :production' do
+ QA::Runtime::Scenario.define(:gitlab_address, "https://gitlab.com/")
+
+ expect(described_class.address_matches?(:production)).to be_truthy
+ end
+
+ it 'doesnt match with mismatching switches' do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.test')
+
+ aggregate_failures do
+ expect(described_class.address_matches?(tld: '.net')).to be_falsey
+ expect(described_class.address_matches?(:production)).to be_falsey
+ expect(described_class.address_matches?(subdomain: [:staging])).to be_falsey
+ expect(described_class.address_matches?(domain: 'example')).to be_falsey
+ end
+ end
+ end
+
+ it 'returns false for mismatching' do
+ QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
+
+ expect(described_class.address_matches?(:production)).to be_falsey
end
end
end
diff --git a/qa/spec/specs/helpers/quarantine_spec.rb b/qa/spec/specs/helpers/quarantine_spec.rb
index 1f09c3f73ac..9686a9771c4 100644
--- a/qa/spec/specs/helpers/quarantine_spec.rb
+++ b/qa/spec/specs/helpers/quarantine_spec.rb
@@ -124,7 +124,7 @@ describe QA::Specs::Helpers::Quarantine do
end
end
- describe '.skip_or_run_quarantined_tests' do
+ describe '.skip_or_run_quarantined_tests_or_contexts' do
context 'with no tag focused' do
before do
described_class.configure_rspec
@@ -148,6 +148,37 @@ describe QA::Specs::Helpers::Quarantine do
expect(group.examples.first.execution_result.status).to eq(:passed)
end
+ context 'with environment set' do
+ before do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://staging.gitlab.com')
+ 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') {}
+ end
+
+ expect(group.examples.first.execution_result.status).to eq(:pending)
+ expect(group.examples.first.execution_result.pending_message)
+ .to eq('In quarantine')
+ 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') {}
+ 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
+
context 'quarantine message' do
shared_examples 'test with quarantine message' do |quarantine_tag|
it 'outputs the quarantine message' do
@@ -280,4 +311,94 @@ describe QA::Specs::Helpers::Quarantine do
end
end
end
+
+ describe 'running against specific environments' do
+ before do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://staging.gitlab.com')
+ described_class.configure_rspec
+ end
+
+ describe 'description and context blocks' do
+ context 'with environment set' do
+ it 'can apply to contexts or descriptions' do
+ group = describe_successfully 'Runs in staging', only: { subdomain: :staging } do
+ it('runs in staging') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ end
+ end
+
+ context 'with different environment set' do
+ before do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.com')
+ described_class.configure_rspec
+ end
+
+ it 'does not run against production' do
+ group = describe_successfully 'Runs in staging', :something, only: { subdomain: :staging } do
+ it('runs in staging') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ end
+ end
+ end
+
+ it 'runs only in staging' do
+ group = describe_successfully do
+ it('runs in staging', only: { subdomain: :staging }) {}
+ it('doesnt run in staging', only: :production) {}
+ it('runs in staging also', only: { subdomain: %i[release staging] }) {}
+ it('runs in any env') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:pending)
+ expect(group.examples[2].execution_result.status).to eq(:passed)
+ expect(group.examples[3].execution_result.status).to eq(:passed)
+ end
+
+ context 'custom env' do
+ before do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://release.gitlab.net')
+ end
+
+ 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 ) {}
+ end
+
+ expect(group.examples.first.execution_result.status).to eq(:passed)
+ expect(group.examples.last.execution_result.status).to eq(:pending)
+ end
+ end
+
+ context 'production' do
+ before do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.com/')
+ end
+
+ it 'runs on production' do
+ group = describe_successfully do
+ 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
+
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:pending)
+ expect(group.examples[2].execution_result.status).to eq(:passed)
+ end
+ end
+
+ it 'outputs a message for invalid environments' do
+ group = describe_successfully do
+ it('will skip', only: :production) {}
+ end
+
+ expect(group.examples.first.execution_result.pending_message).to match(/[Tt]est.*not compatible.*environment/)
+ end
+ end
end