summaryrefslogtreecommitdiff
path: root/qa/qa
diff options
context:
space:
mode:
Diffstat (limited to 'qa/qa')
-rw-r--r--qa/qa/ce/knapsack/nightly_master_report.json46
-rw-r--r--qa/qa/page/admin/menu.rb12
-rw-r--r--qa/qa/page/base.rb19
-rw-r--r--qa/qa/page/component/note.rb22
-rw-r--r--qa/qa/page/component/select2.rb4
-rw-r--r--qa/qa/page/element.rb4
-rw-r--r--qa/qa/page/main/login.rb39
-rw-r--r--qa/qa/page/main/menu.rb20
-rw-r--r--qa/qa/page/main/oauth.rb4
-rw-r--r--qa/qa/page/main/sign_up.rb26
-rw-r--r--qa/qa/page/project/import/github.rb2
-rw-r--r--qa/qa/page/project/issue/new.rb4
-rw-r--r--qa/qa/page/project/issue/show.rb7
-rw-r--r--qa/qa/page/project/menu.rb2
-rw-r--r--qa/qa/page/project/new.rb2
-rw-r--r--qa/qa/page/project/operations/kubernetes/show.rb8
-rw-r--r--qa/qa/page/project/settings/ci_cd.rb21
-rw-r--r--qa/qa/page/project/sub_menus/common.rb6
-rw-r--r--qa/qa/page/project/sub_menus/issues.rb9
-rw-r--r--qa/qa/page/project/sub_menus/project.rb4
-rw-r--r--qa/qa/page/project/web_ide/edit.rb5
-rw-r--r--qa/qa/page/search/results.rb33
-rw-r--r--qa/qa/page/validator.rb6
-rw-r--r--qa/qa/resource/issue.rb6
-rw-r--r--qa/qa/resource/kubernetes_cluster.rb2
-rw-r--r--qa/qa/resource/label.rb1
-rw-r--r--qa/qa/resource/merge_request.rb28
-rw-r--r--qa/qa/resource/project.rb6
-rw-r--r--qa/qa/runtime/api/request.rb4
-rw-r--r--qa/qa/runtime/env.rb4
-rw-r--r--qa/qa/runtime/fixtures.rb13
-rw-r--r--qa/qa/runtime/logger.rb1
-rw-r--r--qa/qa/scenario/test/sanity/selectors.rb10
-rw-r--r--qa/qa/service/cluster_provider/base.rb41
-rw-r--r--qa/qa/service/cluster_provider/gcloud.rb87
-rw-r--r--qa/qa/service/cluster_provider/k3d.rb131
-rw-r--r--qa/qa/service/cluster_provider/minikube.rb26
-rw-r--r--qa/qa/service/kubernetes_cluster.rb132
-rw-r--r--qa/qa/service/omnibus.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/create_group_with_mattermost_team_spec.rb (renamed from qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb)4
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb8
-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.rb10
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_spec.rb3
-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/import_github_repo_spec.rb12
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb28
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb41
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb33
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb33
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb33
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb13
-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.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb34
-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/user_views_commit_diff_patch_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb4
-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/6_release/deploy_key/add_deploy_key_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb23
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb3
-rw-r--r--qa/qa/support/retrier.rb19
-rw-r--r--qa/qa/vendor/saml_idp/page/login.rb8
71 files changed, 852 insertions, 322 deletions
diff --git a/qa/qa/ce/knapsack/nightly_master_report.json b/qa/qa/ce/knapsack/nightly_master_report.json
new file mode 100644
index 00000000000..08694f706de
--- /dev/null
+++ b/qa/qa/ce/knapsack/nightly_master_report.json
@@ -0,0 +1,46 @@
+{
+ "qa/specs/features/api/1_manage/users_spec.rb": 0.6089541912078857,
+ "qa/specs/features/api/3_create/repository/files_spec.rb": 5.015859127044678,
+ "qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb": 1.0199065208435059,
+ "qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb": 33.54091453552246,
+ "qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb": 3.438166856765747,
+ "qa/specs/features/browser_ui/1_manage/login/login_via_oauth_spec.rb": 20.58603596687317,
+ "qa/specs/features/browser_ui/1_manage/login/register_spec.rb": 22.320587396621704,
+ "qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb": 8.490083694458008,
+ "qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb": 10.214765310287476,
+ "qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb": 100.28881478309631,
+ "qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb": 7.882027864456177,
+ "qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb": 13.739388942718506,
+ "qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb": 13.403101205825806,
+ "qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb": 10.989444971084595,
+ "qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb": 10.811973810195923,
+ "qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb": 12.63524317741394,
+ "qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb": 11.280649185180664,
+ "qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb": 41.76726770401001,
+ "qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb": 32.5517954826355,
+ "qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb": 46.54227638244629,
+ "qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb": 27.943300485610962,
+ "qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb": 3.705310821533203,
+ "qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb": 40.09336972236633,
+ "qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb": 31.49540114402771,
+ "qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb": 16.18057894706726,
+ "qa/specs/features/browser_ui/3_create/repository/clone_spec.rb": 0.7397980690002441,
+ "qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb": 18.047621726989746,
+ "qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb": 9.48607873916626,
+ "qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb": 23.710937023162842,
+ "qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb": 19.459370374679565,
+ "qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb": 7.730542182922363,
+ "qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb": 29.76174831390381,
+ "qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb": 22.800872802734375,
+ "qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb": 6.731764793395996,
+ "qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb": 5.812374591827393,
+ "qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb": 25.460349321365356,
+ "qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb": 17.273863554000854,
+ "qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb": 8.31815505027771,
+ "qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb": 18.679633855819702,
+ "qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb": 15.342933893203735,
+ "qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb": 92.46774697303772,
+ "qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb": 20.252174615859985,
+ "qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb": 8.281434059143066,
+ "qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb": 8.810423135757446
+} \ No newline at end of file
diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb
index eea5717f5a7..61ec9854726 100644
--- a/qa/qa/page/admin/menu.rb
+++ b/qa/qa/page/admin/menu.rb
@@ -13,6 +13,10 @@ module QA
element :admin_settings_metrics_and_profiling_item
end
+ view 'app/views/layouts/nav/sidebar/_admin.html.haml' do
+ element :integration_settings_link
+ end
+
def go_to_repository_settings
hover_settings do
within_submenu do
@@ -21,6 +25,14 @@ module QA
end
end
+ def go_to_integration_settings
+ hover_settings do
+ within_submenu do
+ click_element :integration_settings_link
+ end
+ end
+ end
+
def go_to_general_settings
hover_settings do
within_submenu do
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index d0fe2987b0a..45496c6b245 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -25,19 +25,10 @@ module QA
end
end
- def retry_until(max_attempts: 3, reload: false)
- attempts = 0
-
- while attempts < max_attempts
- result = yield
- return result if result
-
- refresh if reload
-
- attempts += 1
+ def retry_until(max_attempts: 3, reload: false, sleep_interval: 0)
+ QA::Support::Retrier.retry_until(max_attempts: max_attempts, reload_page: (reload && self), sleep_interval: sleep_interval) do
+ yield
end
-
- false
end
def retry_on_exception(max_attempts: 3, reload: false, sleep_interval: 0.5)
@@ -190,11 +181,11 @@ module QA
return ["Page class does not have views / elements defined!"]
end
- views.map(&:errors).flatten
+ views.flat_map(&:errors)
end
def self.elements
- views.map(&:elements).flatten
+ views.flat_map(&:elements)
end
def send_keys_to_element(name, keys)
diff --git a/qa/qa/page/component/note.rb b/qa/qa/page/component/note.rb
index 07e191f1c9b..34fde045091 100644
--- a/qa/qa/page/component/note.rb
+++ b/qa/qa/page/component/note.rb
@@ -10,19 +10,27 @@ module QA
element :discussion_option
end
+ base.view 'app/assets/javascripts/notes/components/note_actions.vue' do
+ element :note_edit_button
+ end
+
base.view 'app/assets/javascripts/notes/components/note_form.vue' do
element :reply_input
element :reply_comment_button
end
base.view 'app/assets/javascripts/notes/components/discussion_actions.vue' do
- element :discussion_reply
+ element :discussion_reply_tab
end
base.view 'app/assets/javascripts/notes/components/toggle_replies_widget.vue' do
element :expand_replies
element :collapse_replies
end
+
+ base.view 'app/assets/javascripts/diffs/components/diff_file_header.vue' do
+ element :toggle_comments_button
+ end
end
def start_discussion(text)
@@ -32,8 +40,12 @@ module QA
click_element :comment_button
end
+ def toggle_comments
+ all_elements(:toggle_comments_button).last.click
+ end
+
def type_reply_to_discussion(reply_text)
- all_elements(:discussion_reply).last.click
+ all_elements(:discussion_reply_tab).last.click
fill_element :reply_input, reply_text
end
@@ -49,6 +61,12 @@ module QA
def expand_replies
click_element :expand_replies
end
+
+ def edit_comment(text)
+ click_element :note_edit_button
+ fill_element :reply_input, text
+ click_element :reply_comment_button
+ end
end
end
end
diff --git a/qa/qa/page/component/select2.rb b/qa/qa/page/component/select2.rb
index 85d4abcde9b..d05c44d22b2 100644
--- a/qa/qa/page/component/select2.rb
+++ b/qa/qa/page/component/select2.rb
@@ -8,6 +8,10 @@ module QA
find('.select2-result-label', text: item_text, match: :prefer_exact).click
end
+ def current_selection
+ find('.select2-chosen').text
+ end
+
def clear_current_selection_if_present
if has_css?('a > abbr.select2-search-choice-close', wait: 1.0)
find('a > abbr.select2-search-choice-close').click
diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb
index 7a01320901d..9e6fd2fdd4f 100644
--- a/qa/qa/page/element.rb
+++ b/qa/qa/page/element.rb
@@ -28,7 +28,7 @@ module QA
end
def selector_css
- ".#{selector}"
+ %Q([data-qa-selector="#{@name}"],.#{selector})
end
def expression
@@ -40,7 +40,7 @@ module QA
end
def matches?(line)
- !!(line =~ expression)
+ !!(line =~ /["']#{name}['"]|#{expression}/)
end
end
end
diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb
index 8970eeb6678..94245bbfcba 100644
--- a/qa/qa/page/main/login.rb
+++ b/qa/qa/page/main/login.rb
@@ -6,7 +6,7 @@ module QA
class Login < Page::Base
view 'app/views/devise/passwords/edit.html.haml' do
element :password_field
- element :password_confirmation
+ element :password_confirmation_field
element :change_password_button
end
@@ -44,7 +44,7 @@ module QA
def sign_in_using_credentials(user = nil)
# Don't try to log-in if we're already logged-in
- return if Page::Main::Menu.act { has_personal_area?(wait: 0) }
+ return if Page::Main::Menu.perform { |menu| menu.has_personal_area?(wait: 0) }
using_wait_time 0 do
set_initial_password_if_present
@@ -52,13 +52,11 @@ module QA
raise NotImplementedError if Runtime::User.ldap_user? && user&.credentials_given?
if Runtime::User.ldap_user?
- sign_in_using_ldap_credentials
+ sign_in_using_ldap_credentials(user || Runtime::User)
else
sign_in_using_gitlab_credentials(user || Runtime::User)
end
end
-
- Page::Main::Menu.act { has_personal_area? }
end
def sign_in_using_admin_credentials
@@ -73,7 +71,26 @@ module QA
sign_in_using_gitlab_credentials(admin)
end
- Page::Main::Menu.act { has_personal_area? }
+ Page::Main::Menu.perform(&:has_personal_area?)
+ end
+
+ def sign_in_using_ldap_credentials(user)
+ # Log out if already logged in
+ Page::Main::Menu.perform do |menu|
+ menu.sign_out if menu.has_personal_area?(wait: 0)
+ end
+
+ using_wait_time 0 do
+ set_initial_password_if_present
+
+ switch_to_ldap_tab
+
+ fill_element :username_field, user.ldap_username
+ fill_element :password_field, user.ldap_password
+ click_element :sign_in_button
+ end
+
+ Page::Main::Menu.perform(&:has_personal_area?)
end
def self.path
@@ -133,14 +150,6 @@ module QA
private
- def sign_in_using_ldap_credentials
- switch_to_ldap_tab
-
- fill_element :username_field, Runtime::User.ldap_username
- fill_element :password_field, Runtime::User.ldap_password
- click_element :sign_in_button
- end
-
def sign_in_using_gitlab_credentials(user)
switch_to_sign_in_tab if has_sign_in_tab?
switch_to_standard_tab if has_standard_tab?
@@ -154,7 +163,7 @@ module QA
return unless has_content?('Change your password')
fill_element :password_field, Runtime::User.password
- fill_element :password_confirmation, Runtime::User.password
+ fill_element :password_confirmation_field, Runtime::User.password
click_element :change_password_button
end
end
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index 5eb24d2d2ba..e3039149ab4 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -5,14 +5,14 @@ module QA
module Main
class Menu < Page::Base
view 'app/views/layouts/header/_current_user_dropdown.html.haml' do
- element :user_sign_out_link, 'link_to _("Sign out")' # rubocop:disable QA/ElementWithPattern
- element :settings_link, 'link_to s_("CurrentUser|Settings")' # rubocop:disable QA/ElementWithPattern
+ element :sign_out_link
+ element :settings_link
end
view 'app/views/layouts/header/_default.html.haml' do
element :navbar, required: true
element :user_avatar, required: true
- element :user_menu, '.dropdown-menu' # rubocop:disable QA/ElementWithPattern
+ element :user_menu, required: true
end
view 'app/views/layouts/nav/_dashboard.html.haml' do
@@ -27,6 +27,10 @@ module QA
element :your_projects_link
end
+ view 'app/views/layouts/_search.html.haml' do
+ element :search_term_field
+ end
+
def go_to_groups
within_top_menu do
click_element :groups_dropdown
@@ -53,7 +57,7 @@ module QA
def sign_out
within_user_menu do
- click_link 'Sign out'
+ click_element :sign_out_link
end
end
@@ -71,6 +75,10 @@ module QA
click_element :snippets_link
end
+ def search_for(term)
+ fill_element :search_term_field, "#{term}\n"
+ end
+
def has_personal_area?(wait: Capybara.default_max_wait_time)
has_element?(:user_avatar, wait: wait)
end
@@ -82,7 +90,7 @@ module QA
private
def within_top_menu
- page.within('.qa-navbar') do
+ within_element(:navbar) do
yield
end
end
@@ -91,7 +99,7 @@ module QA
within_top_menu do
click_element :user_avatar
- page.within('.dropdown-menu') do
+ within_element(:user_menu) do
yield
end
end
diff --git a/qa/qa/page/main/oauth.rb b/qa/qa/page/main/oauth.rb
index 5f6ddb9a114..2b1a9ab2b6a 100644
--- a/qa/qa/page/main/oauth.rb
+++ b/qa/qa/page/main/oauth.rb
@@ -5,7 +5,7 @@ module QA
module Main
class OAuth < Page::Base
view 'app/views/doorkeeper/authorizations/new.html.haml' do
- element :authorization_button, 'submit_tag _("Authorize")' # rubocop:disable QA/ElementWithPattern
+ element :authorization_button
end
def needs_authorization?
@@ -13,7 +13,7 @@ module QA
end
def authorize!
- click_button 'Authorize'
+ click_element :authorization_button
end
end
end
diff --git a/qa/qa/page/main/sign_up.rb b/qa/qa/page/main/sign_up.rb
index 46a105003d0..c47d2ce9c74 100644
--- a/qa/qa/page/main/sign_up.rb
+++ b/qa/qa/page/main/sign_up.rb
@@ -5,28 +5,28 @@ module QA
module Main
class SignUp < Page::Base
view 'app/views/devise/shared/_signup_box.html.haml' do
- element :new_user_name
- element :new_user_username
- element :new_user_email
- element :new_user_email_confirmation
- element :new_user_password
+ element :new_user_name_field
+ element :new_user_username_field
+ element :new_user_email_field
+ element :new_user_email_confirmation_field
+ element :new_user_password_field
element :new_user_register_button
- element :new_user_accept_terms
+ element :new_user_accept_terms_checkbox
end
def sign_up!(user)
- fill_element :new_user_name, user.name
- fill_element :new_user_username, user.username
- fill_element :new_user_email, user.email
- fill_element :new_user_email_confirmation, user.email
- fill_element :new_user_password, user.password
+ fill_element :new_user_name_field, user.name
+ fill_element :new_user_username_field, user.username
+ fill_element :new_user_email_field, user.email
+ fill_element :new_user_email_confirmation_field, user.email
+ fill_element :new_user_password_field, user.password
- check_element :new_user_accept_terms if has_element?(:new_user_accept_terms)
+ check_element :new_user_accept_terms_checkbox if has_element?(:new_user_accept_terms_checkbox)
signed_in = retry_until do
click_element :new_user_register_button
- Page::Main::Menu.act { has_personal_area? }
+ Page::Main::Menu.perform(&:has_personal_area?)
end
raise "Failed to register and sign in" unless signed_in
diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb
index 5973a5a958e..cc0c4e1e835 100644
--- a/qa/qa/page/project/import/github.rb
+++ b/qa/qa/page/project/import/github.rb
@@ -9,7 +9,7 @@ module QA
view 'app/views/import/github/new.html.haml' do
element :personal_access_token_field, 'text_field_tag :personal_access_token' # rubocop:disable QA/ElementWithPattern
- element :list_repos_button, "submit_tag _('List your GitHub repositories')" # rubocop:disable QA/ElementWithPattern
+ element :authenticate_button, "submit_tag _('Authenticate')" # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/import_projects/components/provider_repo_table_row.vue' do
diff --git a/qa/qa/page/project/issue/new.rb b/qa/qa/page/project/issue/new.rb
index 0d138417176..65c02801d67 100644
--- a/qa/qa/page/project/issue/new.rb
+++ b/qa/qa/page/project/issue/new.rb
@@ -6,7 +6,7 @@ module QA
module Issue
class New < Page::Base
view 'app/views/shared/issuable/_form.html.haml' do
- element :submit_issue_button, 'form.submit "Submit' # rubocop:disable QA/ElementWithPattern
+ element :issuable_create_button
end
view 'app/views/shared/issuable/form/_title.html.haml' do
@@ -26,7 +26,7 @@ module QA
end
def create_new_issue
- click_on 'Submit issue'
+ click_element :issuable_create_button, Page::Project::Issue::Show
end
end
end
diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb
index b59540d0377..45dad9bc0ae 100644
--- a/qa/qa/page/project/issue/show.rb
+++ b/qa/qa/page/project/issue/show.rb
@@ -14,7 +14,7 @@ module QA
end
view 'app/assets/javascripts/notes/components/discussion_filter.vue' do
- element :discussion_filter
+ element :discussion_filter, required: true
element :filter_options
end
@@ -70,7 +70,10 @@ module QA
end
def select_labels_and_refresh(labels)
- click_element(:edit_link_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
diff --git a/qa/qa/page/project/menu.rb b/qa/qa/page/project/menu.rb
index 3fe048f752a..838d59b59cb 100644
--- a/qa/qa/page/project/menu.rb
+++ b/qa/qa/page/project/menu.rb
@@ -5,7 +5,7 @@ module QA
module Project
class Menu < Page::Base
include SubMenus::Common
-
+ include SubMenus::Project
include SubMenus::CiCd
include SubMenus::Issues
include SubMenus::Operations
diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb
index 0918445d119..64aab9be056 100644
--- a/qa/qa/page/project/new.rb
+++ b/qa/qa/page/project/new.rb
@@ -59,7 +59,7 @@ module QA
end
def set_visibility(visibility)
- choose visibility
+ choose visibility.capitalize
end
def click_github_link
diff --git a/qa/qa/page/project/operations/kubernetes/show.rb b/qa/qa/page/project/operations/kubernetes/show.rb
index 4f625c5f0f0..eb30e0ea02a 100644
--- a/qa/qa/page/project/operations/kubernetes/show.rb
+++ b/qa/qa/page/project/operations/kubernetes/show.rb
@@ -28,16 +28,12 @@ module QA
end
end
- def await_installed(application_name, button_text: 'Installed')
+ def await_installed(application_name)
within(".js-cluster-application-row-#{application_name}") do
- page.has_text?(button_text, wait: 300)
+ page.has_text?(/Installed|Uninstall/, wait: 300)
end
end
- def await_uninstallable(application_name)
- await_installed(application_name, button_text: 'Uninstall')
- end
-
def ingress_ip
# We need to wait longer since it can take some time before the
# ip address is assigned for the ingress controller
diff --git a/qa/qa/page/project/settings/ci_cd.rb b/qa/qa/page/project/settings/ci_cd.rb
index b8c5c563da6..ae826fb3a32 100644
--- a/qa/qa/page/project/settings/ci_cd.rb
+++ b/qa/qa/page/project/settings/ci_cd.rb
@@ -8,33 +8,32 @@ module QA
include Common
view 'app/views/projects/settings/ci_cd/show.html.haml' do
- element :autodevops_settings
- element :runners_settings
- element :variables_settings
+ element :autodevops_settings_content
+ element :runners_settings_content
+ element :variables_settings_content
end
view 'app/views/projects/settings/ci_cd/_autodevops_form.html.haml' do
- element :enable_auto_devops_field, 'check_box :enabled' # rubocop:disable QA/ElementWithPattern
- element :enable_auto_devops_button, "%strong= s_('CICD|Default to Auto DevOps pipeline')" # rubocop:disable QA/ElementWithPattern
- element :save_changes_button, "submit _('Save changes')" # rubocop:disable QA/ElementWithPattern
+ element :enable_autodevops_checkbox
+ element :save_changes_button
end
def expand_runners_settings(&block)
- expand_section(:runners_settings) do
+ expand_section(:runners_settings_content) do
Settings::Runners.perform(&block)
end
end
def expand_ci_variables(&block)
- expand_section(:variables_settings) do
+ expand_section(:variables_settings_content) do
Settings::CiVariables.perform(&block)
end
end
def enable_auto_devops
- expand_section(:autodevops_settings) do
- check 'Default to Auto DevOps pipeline'
- click_on 'Save changes'
+ expand_section(:autodevops_settings_content) do
+ check_element :enable_autodevops_checkbox
+ click_element :save_changes_button
end
end
end
diff --git a/qa/qa/page/project/sub_menus/common.rb b/qa/qa/page/project/sub_menus/common.rb
index c94e1e85256..3c9e8085748 100644
--- a/qa/qa/page/project/sub_menus/common.rb
+++ b/qa/qa/page/project/sub_menus/common.rb
@@ -12,7 +12,11 @@ module QA
end
def within_submenu
- within('.fly-out-list') do
+ if has_css?('.fly-out-list')
+ within('.fly-out-list') do
+ yield
+ end
+ else
yield
end
end
diff --git a/qa/qa/page/project/sub_menus/issues.rb b/qa/qa/page/project/sub_menus/issues.rb
index 8fb8fa06346..d27a250a300 100644
--- a/qa/qa/page/project/sub_menus/issues.rb
+++ b/qa/qa/page/project/sub_menus/issues.rb
@@ -10,6 +10,7 @@ module QA
def self.included(base)
base.class_eval do
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
+ element :issue_boards_link
element :issues_item
element :labels_link
element :milestones_link
@@ -29,6 +30,14 @@ module QA
end
end
+ def go_to_boards
+ hover_issues do
+ within_submenu do
+ click_element(:issue_boards_link)
+ end
+ end
+ end
+
def go_to_labels
hover_issues do
within_submenu do
diff --git a/qa/qa/page/project/sub_menus/project.rb b/qa/qa/page/project/sub_menus/project.rb
index 5e0ee3c274a..6f1bc131f84 100644
--- a/qa/qa/page/project/sub_menus/project.rb
+++ b/qa/qa/page/project/sub_menus/project.rb
@@ -10,7 +10,7 @@ module QA
def self.included(base)
base.class_eval do
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
- element :link_project
+ element :project_link
end
end
end
@@ -18,7 +18,7 @@ module QA
def click_project
retry_on_exception do
within_sidebar do
- click_element(:link_project)
+ click_element(:project_link)
end
end
end
diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb
index b5a36862389..37bca97fec7 100644
--- a/qa/qa/page/project/web_ide/edit.rb
+++ b/qa/qa/page/project/web_ide/edit.rb
@@ -39,6 +39,10 @@ module QA
element :commit_button
end
+ view 'app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue' do
+ element :start_new_mr_checkbox
+ end
+
def has_file?(file_name)
within_element(:file_list) do
page.has_content? file_name
@@ -100,6 +104,7 @@ module QA
# animation is still in process even when the buttons have the
# expected visibility.
commit_success_msg_shown = retry_until do
+ uncheck_element :start_new_mr_checkbox
click_element :commit_button
wait(reload: false) do
diff --git a/qa/qa/page/search/results.rb b/qa/qa/page/search/results.rb
new file mode 100644
index 00000000000..b9b18abf660
--- /dev/null
+++ b/qa/qa/page/search/results.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module QA::Page
+ module Search
+ class Results < QA::Page::Base
+ view 'app/views/search/_category.html.haml' do
+ element :code_tab
+ end
+
+ view 'app/views/search/results/_blob_data.html.haml' do
+ element :result_item_content
+ element :file_title_content
+ element :file_text_content
+ end
+
+ def switch_to_code
+ click_element(:code_tab)
+ end
+
+ def has_file_in_project?(file_name, project_name)
+ has_element? :result_item_content, text: "#{project_name}: #{file_name}"
+ end
+
+ def has_file_with_content?(file_name, file_text)
+ within_element_by_index :result_item_content, 0 do
+ false unless has_element? :file_title_content, text: file_name
+
+ has_element? :file_text_content, text: file_text
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/validator.rb b/qa/qa/page/validator.rb
index edd12665f1e..9b2d0a1a41d 100644
--- a/qa/qa/page/validator.rb
+++ b/qa/qa/page/validator.rb
@@ -22,16 +22,14 @@ module QA
end
def descendants
- @descendants ||= constants.map do |const|
+ @descendants ||= constants.flat_map do |const|
case const
when Class
const if const < Page::Base
when Module
Page::Validator.new(const).descendants
end
- end
-
- @descendants.flatten.compact
+ end.compact
end
def errors
diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb
index 51b2af8b4ef..16ab59352f3 100644
--- a/qa/qa/resource/issue.rb
+++ b/qa/qa/resource/issue.rb
@@ -3,7 +3,7 @@
module QA
module Resource
class Issue < Base
- attr_writer :description
+ attr_writer :description, :milestone
attribute :project do
Project.fabricate! do |resource|
@@ -44,7 +44,9 @@ module QA
{
labels: labels,
title: title
- }
+ }.tap do |hash|
+ hash[:milestone_id] = @milestone.id if @milestone
+ end
end
end
end
diff --git a/qa/qa/resource/kubernetes_cluster.rb b/qa/qa/resource/kubernetes_cluster.rb
index 1dd93dd5b88..27ab7b60211 100644
--- a/qa/qa/resource/kubernetes_cluster.rb
+++ b/qa/qa/resource/kubernetes_cluster.rb
@@ -47,7 +47,7 @@ module QA
page.install!(:runner) if @install_runner
page.await_installed(:ingress) if @install_ingress
- page.await_uninstallable(:prometheus) if @install_prometheus
+ page.await_installed(:prometheus) if @install_prometheus
page.await_installed(:runner) if @install_runner
if @install_ingress
diff --git a/qa/qa/resource/label.rb b/qa/qa/resource/label.rb
index 3750725c440..b5e88d8aefc 100644
--- a/qa/qa/resource/label.rb
+++ b/qa/qa/resource/label.rb
@@ -7,6 +7,7 @@ module QA
class Label < Base
attr_accessor :description, :color
+ attribute :id
attribute :title
attribute :project do
diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb
index 45cb317e0eb..45ab2396a04 100644
--- a/qa/qa/resource/merge_request.rb
+++ b/qa/qa/resource/merge_request.rb
@@ -5,10 +5,12 @@ require 'securerandom'
module QA
module Resource
class MergeRequest < Base
- attr_accessor :title,
+ attr_accessor :id,
+ :title,
:description,
:source_branch,
:target_branch,
+ :target_new_branch,
:assignee,
:milestone,
:labels,
@@ -27,6 +29,7 @@ module QA
Repository::ProjectPush.fabricate! do |resource|
resource.project = project
resource.branch_name = 'master'
+ resource.new_branch = @target_new_branch
resource.remote_branch = target_branch
end
end
@@ -52,6 +55,7 @@ module QA
@labels = []
@file_name = "added_file.txt"
@file_content = "File Added"
+ @target_new_branch = true
end
def fabricate!
@@ -71,6 +75,28 @@ module QA
page.create_merge_request
end
end
+
+ def fabricate_via_api!
+ populate(:target, :source)
+ super
+ end
+
+ def api_get_path
+ "/projects/#{project.id}/merge_requests/#{id}"
+ end
+
+ def api_post_path
+ "/projects/#{project.id}/merge_requests"
+ end
+
+ def api_post_body
+ {
+ description: @description,
+ source_branch: @source_branch,
+ target_branch: @target_branch,
+ title: @title
+ }
+ end
end
end
end
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index c0a6004fe27..93a82094776 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -8,6 +8,7 @@ module QA
include Events::Project
attr_writer :initialize_with_readme
+ attr_writer :visibility
attribute :id
attribute :name
@@ -44,6 +45,7 @@ module QA
@standalone = false
@description = 'My awesome project'
@initialize_with_readme = false
+ @visibility = 'public'
end
def name=(raw_name)
@@ -60,7 +62,7 @@ module QA
page.choose_test_namespace
page.choose_name(@name)
page.add_description(@description)
- page.set_visibility('Public')
+ page.set_visibility(@visibility)
page.enable_initialize_with_readme if @initialize_with_readme
page.create_new_project
end
@@ -88,7 +90,7 @@ module QA
post_body = {
name: name,
description: description,
- visibility: 'public',
+ visibility: @visibility,
initialize_with_readme: @initialize_with_readme
}
diff --git a/qa/qa/runtime/api/request.rb b/qa/qa/runtime/api/request.rb
index 310c1dfeeb4..724b499d32f 100644
--- a/qa/qa/runtime/api/request.rb
+++ b/qa/qa/runtime/api/request.rb
@@ -12,6 +12,10 @@ module QA
@session_address = Runtime::Address.new(api_client.address, request_path)
end
+ def mask_url
+ @session_address.address.sub(/private_token=.*/, "private_token=[****]")
+ end
+
def url
@session_address.address
end
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index e78b9bece19..b184eeb1701 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -181,6 +181,10 @@ module QA
ENV.fetch('GCLOUD_REGION')
end
+ def gcloud_num_nodes
+ ENV.fetch('GCLOUD_NUM_NODES', 1)
+ end
+
def has_gcloud_credentials?
%w[GCLOUD_ACCOUNT_KEY GCLOUD_ACCOUNT_EMAIL].none? { |var| ENV[var].to_s.empty? }
end
diff --git a/qa/qa/runtime/fixtures.rb b/qa/qa/runtime/fixtures.rb
index 72004d5b00a..02cecffd4df 100644
--- a/qa/qa/runtime/fixtures.rb
+++ b/qa/qa/runtime/fixtures.rb
@@ -3,10 +3,19 @@
module QA
module Runtime
module Fixtures
+ include Support::Api
+
+ TemplateNotFoundError = Class.new(RuntimeError)
+
def fetch_template_from_api(api_path, key)
request = Runtime::API::Request.new(api_client, "/templates/#{api_path}/#{key}")
- get request.url
- json_body[:content]
+ response = get(request.url)
+
+ unless response.code == HTTP_STATUS_OK
+ raise TemplateNotFoundError, "Template at #{request.mask_url} could not be found (#{response.code}): `#{response}`."
+ end
+
+ parse_body(response)[:content]
end
private
diff --git a/qa/qa/runtime/logger.rb b/qa/qa/runtime/logger.rb
index bd5c4fe5bf5..7f73f1bd01b 100644
--- a/qa/qa/runtime/logger.rb
+++ b/qa/qa/runtime/logger.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'logger'
+require 'forwardable'
module QA
module Runtime
diff --git a/qa/qa/scenario/test/sanity/selectors.rb b/qa/qa/scenario/test/sanity/selectors.rb
index e05269e8d55..632a0f5f2a9 100644
--- a/qa/qa/scenario/test/sanity/selectors.rb
+++ b/qa/qa/scenario/test/sanity/selectors.rb
@@ -7,14 +7,16 @@ module QA
class Selectors < Scenario::Template
include Scenario::Bootable
- PAGES = [QA::Page].freeze
+ def pages
+ @pages ||= [QA::Page]
+ end
def perform(*)
- validators = PAGES.map do |pages|
- Page::Validator.new(pages)
+ validators = pages.map do |page|
+ Page::Validator.new(page)
end
- validators.map(&:errors).flatten.tap do |errors|
+ validators.flat_map(&:errors).tap do |errors|
break if errors.none?
warn <<~EOS
diff --git a/qa/qa/service/cluster_provider/base.rb b/qa/qa/service/cluster_provider/base.rb
new file mode 100644
index 00000000000..a9678557aca
--- /dev/null
+++ b/qa/qa/service/cluster_provider/base.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module ClusterProvider
+ class Base
+ include Service::Shellout
+
+ attr_reader :rbac
+
+ def initialize(rbac:)
+ @rbac = rbac
+ end
+
+ def cluster_name
+ @cluster_name ||= "qa-cluster-#{Time.now.utc.strftime("%Y%m%d%H%M%S")}-#{SecureRandom.hex(4)}"
+ end
+
+ def set_credentials(admin_user)
+ raise NotImplementedError
+ end
+
+ def validate_dependencies
+ raise NotImplementedError
+ end
+
+ def setup
+ raise NotImplementedError
+ end
+
+ def teardown
+ raise NotImplementedError
+ end
+
+ def filter_credentials(credentials)
+ credentials
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/service/cluster_provider/gcloud.rb b/qa/qa/service/cluster_provider/gcloud.rb
new file mode 100644
index 00000000000..9c82151666c
--- /dev/null
+++ b/qa/qa/service/cluster_provider/gcloud.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module ClusterProvider
+ class Gcloud < Base
+ def validate_dependencies
+ find_executable('gcloud') || raise("You must first install `gcloud` executable to run these tests.")
+ end
+
+ def set_credentials(admin_user)
+ master_auth = JSON.parse(`gcloud container clusters describe #{cluster_name} --region #{Runtime::Env.gcloud_region} --format 'json(masterAuth.username, masterAuth.password)'`)
+
+ shell <<~CMD.tr("\n", ' ')
+ kubectl config set-credentials #{admin_user}
+ --username #{master_auth['masterAuth']['username']}
+ --password #{master_auth['masterAuth']['password']}
+ CMD
+ end
+
+ def setup
+ login_if_not_already_logged_in
+ create_cluster
+ end
+
+ def teardown
+ delete_cluster
+ end
+
+ private
+
+ def login_if_not_already_logged_in
+ if Runtime::Env.has_gcloud_credentials?
+ attempt_login_with_env_vars
+ else
+ account = `gcloud auth list --filter=status:ACTIVE --format="value(account)"`
+ if account.empty?
+ raise "Failed to login to gcloud. No credentials provided in environment and no credentials found locally."
+ else
+ puts "gcloud account found. Using: #{account} for creating K8s cluster."
+ end
+ end
+ end
+
+ def attempt_login_with_env_vars
+ puts "No gcloud account. Attempting to login from env vars GCLOUD_ACCOUNT_EMAIL and GCLOUD_ACCOUNT_KEY."
+ gcloud_account_key = Tempfile.new('gcloud-account-key')
+ gcloud_account_key.write(Runtime::Env.gcloud_account_key)
+ gcloud_account_key.close
+ gcloud_account_email = Runtime::Env.gcloud_account_email
+ shell("gcloud auth activate-service-account #{gcloud_account_email} --key-file #{gcloud_account_key.path}")
+ ensure
+ gcloud_account_key && gcloud_account_key.unlink
+ end
+
+ def auth_options
+ "--enable-legacy-authorization" unless rbac
+ end
+
+ def create_cluster
+ shell <<~CMD.tr("\n", ' ')
+ gcloud container clusters
+ create #{cluster_name}
+ #{auth_options}
+ --enable-basic-auth
+ --region #{Runtime::Env.gcloud_region}
+ --disk-size 10GB
+ --num-nodes #{Runtime::Env.gcloud_num_nodes}
+ && gcloud container clusters
+ get-credentials
+ --region #{Runtime::Env.gcloud_region}
+ #{cluster_name}
+ CMD
+ end
+
+ def delete_cluster
+ shell <<~CMD.tr("\n", ' ')
+ gcloud container clusters delete
+ --region #{Runtime::Env.gcloud_region}
+ #{cluster_name}
+ --quiet --async
+ CMD
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/service/cluster_provider/k3d.rb b/qa/qa/service/cluster_provider/k3d.rb
new file mode 100644
index 00000000000..8e117c2dbd5
--- /dev/null
+++ b/qa/qa/service/cluster_provider/k3d.rb
@@ -0,0 +1,131 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module ClusterProvider
+ class K3d < Base
+ def validate_dependencies
+ find_executable('k3d') || raise("You must first install `k3d` executable to run these tests.")
+ end
+
+ def set_credentials(admin_user)
+ end
+
+ def setup
+ shell "k3d create --workers 1 --name #{cluster_name} --wait 0"
+
+ @old_kubeconfig = ENV['KUBECONFIG']
+ ENV['KUBECONFIG'] = fetch_kubeconfig
+ raise "Could not fetch kubeconfig" unless ENV['KUBECONFIG']
+
+ install_local_storage
+ end
+
+ def teardown
+ ENV['KUBECONFIG'] = @old_kubeconfig
+ shell "k3d delete --name #{cluster_name}"
+ end
+
+ # Fetch "real" certificate
+ # See https://github.com/rancher/k3s/issues/27
+ def filter_credentials(credentials)
+ kubeconfig = YAML.load_file(ENV['KUBECONFIG'])
+ ca_certificate = kubeconfig.dig('clusters', 0, 'cluster', 'certificate-authority-data')
+
+ credentials.merge('data' => credentials['data'].merge('ca.crt' => ca_certificate))
+ end
+
+ private
+
+ def retry_until(max_attempts: 10, wait: 1)
+ max_attempts.times do
+ result = yield
+ return result if result
+
+ sleep wait
+ end
+
+ raise "Retried #{max_attempts} times. Aborting"
+ end
+
+ def fetch_kubeconfig
+ retry_until do
+ config = `k3d get-kubeconfig --name #{cluster_name}`.chomp
+ config if config =~ /kubeconfig.yaml/
+ end
+ end
+
+ def install_local_storage
+ shell('kubectl apply -f -', stdin_data: local_storage_config)
+ end
+
+ # See https://github.com/rancher/k3d/issues/67
+ def local_storage_config
+ <<~YAML
+ ---
+ apiVersion: v1
+ kind: ServiceAccount
+ metadata:
+ name: storage-provisioner
+ namespace: kube-system
+ ---
+ apiVersion: rbac.authorization.k8s.io/v1
+ kind: ClusterRoleBinding
+ metadata:
+ name: storage-provisioner
+ roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: system:persistent-volume-provisioner
+ subjects:
+ - kind: ServiceAccount
+ name: storage-provisioner
+ namespace: kube-system
+ ---
+ apiVersion: v1
+ kind: Pod
+ metadata:
+ name: storage-provisioner
+ namespace: kube-system
+ spec:
+ serviceAccountName: storage-provisioner
+ tolerations:
+ - effect: NoExecute
+ key: node.kubernetes.io/not-ready
+ operator: Exists
+ tolerationSeconds: 300
+ - effect: NoExecute
+ key: node.kubernetes.io/unreachable
+ operator: Exists
+ tolerationSeconds: 300
+ hostNetwork: true
+ containers:
+ - name: storage-provisioner
+ image: gcr.io/k8s-minikube/storage-provisioner:v1.8.1
+ command: ["/storage-provisioner"]
+ imagePullPolicy: IfNotPresent
+ volumeMounts:
+ - mountPath: /tmp
+ name: tmp
+ volumes:
+ - name: tmp
+ hostPath:
+ path: /tmp
+ type: Directory
+ ---
+ kind: StorageClass
+ apiVersion: storage.k8s.io/v1
+ metadata:
+ name: standard
+ namespace: kube-system
+ annotations:
+ storageclass.kubernetes.io/is-default-class: "true"
+ labels:
+ addonmanager.kubernetes.io/mode: EnsureExists
+ provisioner: k8s.io/minikube-hostpath
+ YAML
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/service/cluster_provider/minikube.rb b/qa/qa/service/cluster_provider/minikube.rb
new file mode 100644
index 00000000000..fc916245357
--- /dev/null
+++ b/qa/qa/service/cluster_provider/minikube.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module ClusterProvider
+ class Minikube < Base
+ def validate_dependencies
+ find_executable('minikube') || raise("You must first install `minikube` executable to run these tests.")
+ end
+
+ def set_credentials(admin_user)
+ end
+
+ def setup
+ shell 'minikube stop'
+ shell "minikube profile #{cluster_name}"
+ shell 'minikube start'
+ end
+
+ def teardown
+ shell 'minikube delete'
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/service/kubernetes_cluster.rb b/qa/qa/service/kubernetes_cluster.rb
index 40263e94065..26b5f58d2d3 100644
--- a/qa/qa/service/kubernetes_cluster.rb
+++ b/qa/qa/service/kubernetes_cluster.rb
@@ -9,88 +9,63 @@ module QA
class KubernetesCluster
include Service::Shellout
- attr_reader :api_url, :ca_certificate, :token, :rbac
+ attr_reader :api_url, :ca_certificate, :token, :rbac, :provider
- def initialize(rbac: true)
+ def initialize(rbac: true, provider_class: QA::Service::ClusterProvider::Gcloud)
@rbac = rbac
- end
-
- def cluster_name
- @cluster_name ||= "qa-cluster-#{SecureRandom.hex(4)}-#{Time.now.utc.strftime("%Y%m%d%H%M%S")}"
+ @provider = provider_class.new(rbac: rbac)
end
def create!
validate_dependencies
- login_if_not_already_logged_in
-
- shell <<~CMD.tr("\n", ' ')
- gcloud container clusters
- create #{cluster_name}
- #{auth_options}
- --enable-basic-auth
- --region #{Runtime::Env.gcloud_region}
- && gcloud container clusters
- get-credentials
- --region #{Runtime::Env.gcloud_region}
- #{cluster_name}
- CMD
-
- @api_url = `kubectl config view --minify -o jsonpath='{.clusters[].cluster.server}'`
-
- @admin_user = "#{cluster_name}-admin"
- master_auth = JSON.parse(`gcloud container clusters describe #{cluster_name} --region #{Runtime::Env.gcloud_region} --format 'json(masterAuth.username, masterAuth.password)'`)
- shell <<~CMD.tr("\n", ' ')
- kubectl config set-credentials #{@admin_user}
- --username #{master_auth['masterAuth']['username']}
- --password #{master_auth['masterAuth']['password']}
- CMD
-
- if rbac
- create_service_account
-
- secrets = JSON.parse(`kubectl get secrets -o json`)
- gitlab_account = secrets['items'].find do |item|
- item['metadata']['annotations']['kubernetes.io/service-account.name'] == 'gitlab-account'
- end
-
- @ca_certificate = Base64.decode64(gitlab_account['data']['ca.crt'])
- @token = Base64.decode64(gitlab_account['data']['token'])
- else
- @ca_certificate = Base64.decode64(`kubectl get secrets -o jsonpath="{.items[0].data['ca\\.crt']}"`)
- @token = Base64.decode64(`kubectl get secrets -o jsonpath='{.items[0].data.token}'`)
- end
+
+ @provider.validate_dependencies
+ @provider.setup
+
+ @api_url = fetch_api_url
+
+ credentials = @provider.filter_credentials(fetch_credentials)
+ @ca_certificate = Base64.decode64(credentials.dig('data', 'ca.crt'))
+ @token = Base64.decode64(credentials.dig('data', 'token'))
self
end
def remove!
- shell <<~CMD.tr("\n", ' ')
- gcloud container clusters delete
- --region #{Runtime::Env.gcloud_region}
- #{cluster_name}
- --quiet --async
- CMD
+ @provider.teardown
+ end
+
+ def cluster_name
+ @provider.cluster_name
end
private
- def create_service_account
- shell('kubectl create -f -', stdin_data: service_account)
- shell("kubectl --user #{@admin_user} create -f -", stdin_data: service_account_role_binding)
+ def fetch_api_url
+ `kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'`
+ end
+
+ def fetch_credentials
+ return global_credentials unless rbac
+
+ @provider.set_credentials(admin_user)
+ create_service_account(admin_user)
+ account_credentials
end
- def service_account
- <<~YAML
+ def admin_user
+ @admin_user ||= "#{@provider.cluster_name}-admin"
+ end
+
+ def create_service_account(user)
+ service_account = <<~YAML
+ ---
apiVersion: v1
kind: ServiceAccount
metadata:
name: gitlab-account
namespace: default
- YAML
- end
-
- def service_account_role_binding
- <<~YAML
+ ---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
@@ -104,39 +79,24 @@ module QA
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
YAML
- end
- def auth_options
- "--enable-legacy-authorization" unless rbac
+ shell('kubectl apply -f -', stdin_data: service_account)
end
- def validate_dependencies
- find_executable('gcloud') || raise("You must first install `gcloud` executable to run these tests.")
- find_executable('kubectl') || raise("You must first install `kubectl` executable to run these tests.")
- end
+ def account_credentials
+ secrets = JSON.parse(`kubectl get secrets -o json`)
- def login_if_not_already_logged_in
- if Runtime::Env.has_gcloud_credentials?
- attempt_login_with_env_vars
- else
- account = `gcloud auth list --filter=status:ACTIVE --format="value(account)"`
- if account.empty?
- raise "Failed to login to gcloud. No credentials provided in environment and no credentials found locally."
- else
- puts "gcloud account found. Using: #{account} for creating K8s cluster."
- end
+ secrets['items'].find do |item|
+ item['metadata']['annotations']['kubernetes.io/service-account.name'] == 'gitlab-account'
end
end
- def attempt_login_with_env_vars
- puts "No gcloud account. Attempting to login from env vars GCLOUD_ACCOUNT_EMAIL and GCLOUD_ACCOUNT_KEY."
- gcloud_account_key = Tempfile.new('gcloud-account-key')
- gcloud_account_key.write(Runtime::Env.gcloud_account_key)
- gcloud_account_key.close
- gcloud_account_email = Runtime::Env.gcloud_account_email
- shell("gcloud auth activate-service-account #{gcloud_account_email} --key-file #{gcloud_account_key.path}")
- ensure
- gcloud_account_key && gcloud_account_key.unlink
+ def global_credentials
+ JSON.parse(`kubectl get secrets -o jsonpath='{.items[0]}'`)
+ end
+
+ def validate_dependencies
+ find_executable('kubectl') || raise("You must first install `kubectl` executable to run these tests.")
end
end
end
diff --git a/qa/qa/service/omnibus.rb b/qa/qa/service/omnibus.rb
index b54fd5628f2..c5cddff56cd 100644
--- a/qa/qa/service/omnibus.rb
+++ b/qa/qa/service/omnibus.rb
@@ -11,11 +11,12 @@ module QA
end
def gitlab_ctl(command, input: nil)
- if input.nil?
- shell "docker exec #{@name} gitlab-ctl #{command}"
- else
- shell "docker exec #{@name} bash -c '#{input} | gitlab-ctl #{command}'"
- end
+ docker_exec("gitlab-ctl #{command}", input: input)
+ end
+
+ def docker_exec(command, input: nil)
+ command = "#{input} | #{command}" if input
+ shell "docker exec #{@name} bash -c '#{command}'"
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/7_configure/mattermost/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 8383dcdb983..94d20106de4 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/group/create_group_with_mattermost_team_spec.rb
@@ -5,8 +5,8 @@ module QA
describe 'Mattermost support' do
it 'user creates a group with a mattermost team' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
- Page::Main::Menu.act { go_to_groups }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
+ Page::Main::Menu.perform(&:go_to_groups)
Page::Dashboard::Groups.perform do |page|
page.click_new_group
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 2363836d5e3..c9acd7df776 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
@@ -5,7 +5,7 @@ module QA
describe 'Project transfer between groups' do
it 'user transfers a project between groups' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
source_group = Resource::Group.fabricate_via_api! do |group|
group.path = 'source-group'
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 cf225a639b6..6556c28ccab 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
@@ -5,14 +5,16 @@ module QA
describe 'basic user login' do
it 'user logs in using basic credentials and logs out' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
Page::Main::Menu.perform do |menu|
expect(menu).to have_personal_area
end
- Page::Main::Menu.perform do |menu|
- menu.sign_out
+ Support::Retrier.retry_until(sleep_interval: 0.5) do
+ Page::Main::Menu.perform(&:sign_out)
+
+ Page::Main::Login.perform(&:has_sign_in_tab?)
end
Page::Main::Login.perform do |form|
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 72dde4e5bd8..10cd8470a8f 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
@@ -5,7 +5,7 @@ module QA
describe 'LDAP login' do
it 'user logs into GitLab using LDAP credentials' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
Page::Main::Menu.perform do |menu|
expect(menu).to have_personal_area
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 67610b62ed7..0a999cf00fa 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
@@ -7,11 +7,13 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
- Runtime::Browser.visit(:mattermost, Page::Mattermost::Login)
- Page::Mattermost::Login.perform(&:sign_in_using_oauth)
+ Support::Retrier.retry_on_exception do
+ Runtime::Browser.visit(:mattermost, Page::Mattermost::Login)
+ Page::Mattermost::Login.perform(&:sign_in_using_oauth)
- Page::Mattermost::Main.perform do |page|
- expect(page).to have_content(/(Welcome to: Mattermost|Logout GitLab Mattermost)/)
+ Page::Mattermost::Main.perform do |page|
+ expect(page).to have_content(/(Welcome to: Mattermost|Logout GitLab Mattermost)/)
+ end
end
end
end
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 87f0e9030d2..101143399f6 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
@@ -6,9 +6,9 @@ module QA
it 'User logs in to gitlab with SAML SSO' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_with_saml }
+ Page::Main::Login.perform(&:sign_in_with_saml)
- Vendor::SAMLIdp::Page::Login.act { login }
+ Vendor::SAMLIdp::Page::Login.perform(&:login)
expect(page).to have_content('Welcome to GitLab')
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_spec.rb
index a118176eb8a..db99488160b 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
module QA
- context 'Manage', :orchestrated, :oauth do
+ # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/121
+ context 'Manage', :orchestrated, :oauth, :quarantine do
describe 'OAuth login' do
it 'User logs in to GitLab with GitHub OAuth' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
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 f51c16f472c..1c1f552e224 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
@@ -19,7 +19,7 @@ module QA
page.add_member(user.username)
end
- expect(page).to have_content(/#{user.name} (. )?@#{user.username} Given access/)
+ expect(page).to have_content(/@#{user.username}(\n| )?Given access/)
end
end
end
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 6632c2977ef..fbe857dc2a5 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
@@ -5,7 +5,7 @@ module QA
describe 'Project creation' do
it 'user creates a new project' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
created_project = Resource::Project.fabricate_via_browser_ui! do |project|
project.name = 'awesome-project'
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 a9eafd61a91..4f8c46cbd5f 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
@@ -24,16 +24,16 @@ module QA
it 'user imports a GitHub repo' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
imported_project # import the project
- Page::Main::Menu.act { go_to_projects }
+ Page::Main::Menu.perform(&:go_to_projects)
Page::Dashboard::Projects.perform do |dashboard|
dashboard.go_to_project(imported_project.name)
end
- Page::Project::Show.act { wait_for_import }
+ Page::Project::Show.perform(&:wait_for_import)
verify_repository_import
verify_issues_import
@@ -50,7 +50,7 @@ module QA
def verify_issues_import
QA::Support::Retrier.retry_on_exception do
- Page::Project::Menu.act { click_issues }
+ Page::Project::Menu.perform(&:click_issues)
expect(page).to have_content('This is a sample issue')
click_link 'This is a sample issue'
@@ -73,7 +73,7 @@ module QA
end
def verify_merge_requests_import
- Page::Project::Menu.act { click_merge_requests }
+ Page::Project::Menu.perform(&:click_merge_requests)
expect(page).to have_content('Improve README.md')
click_link 'Improve README.md'
@@ -108,7 +108,7 @@ module QA
end
def verify_wiki_import
- Page::Project::Menu.act { click_wiki }
+ Page::Project::Menu.perform(&:click_wiki)
expect(page).to have_content('Welcome to the test-project wiki!')
end
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 5eceeb9661c..70c03e10449 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
@@ -3,17 +3,27 @@
module QA
context 'Plan' do
describe 'check xss occurence in @mentions in issues' do
- let(:issue_title) { 'issue title' }
-
it 'user mentions a user in comment' do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.perform(&:sign_in_using_credentials)
+ QA::Runtime::Env.personal_access_token = QA::Runtime::Env.admin_personal_access_token
+
+ unless QA::Runtime::Env.personal_access_token
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.perform(&:sign_in_using_admin_credentials)
+ end
user = Resource::User.fabricate_via_api! do |user|
user.name = "eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;"
user.password = "test1234"
end
+ QA::Runtime::Env.personal_access_token = nil
+
+ Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
+
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+
+ Page::Main::Login.perform(&:sign_in_using_credentials)
+
project = Resource::Project.fabricate_via_api! do |resource|
resource.name = 'xss-test-for-mentions-project'
end
@@ -25,17 +35,17 @@ module QA
end
issue = Resource::Issue.fabricate_via_api! do |issue|
- issue.title = issue_title
+ issue.title = 'issue title'
issue.project = project
end
issue.visit!
- Page::Project::Issue::Show.perform do |show_page|
- show_page.select_all_activities_filter
- show_page.comment('cc-ing you here @eve')
+ Page::Project::Issue::Show.perform do |show|
+ show.select_all_activities_filter
+ show.comment('cc-ing you here @eve')
expect do
- expect(show_page).to have_content("cc-ing you here")
+ expect(show).to have_content("cc-ing you here")
end.not_to raise_error # Selenium::WebDriver::Error::UnhandledAlertError
end
end
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 2101311f065..ad70f6813fb 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
@@ -3,39 +3,40 @@
module QA
context 'Plan' do
describe 'collapse comments in issue discussions' do
- let(:issue_title) { 'issue title' }
+ let(:my_first_reply) { 'My first reply' }
- it 'user collapses reply for comments in an issue' do
+ before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
issue = Resource::Issue.fabricate_via_api! do |issue|
- issue.title = issue_title
+ issue.title = 'issue title'
end
issue.visit!
- expect(page).to have_content(issue_title)
+ Page::Project::Issue::Show.perform do |show|
+ my_first_discussion = 'My first discussion'
- Page::Project::Issue::Show.perform do |show_page|
- my_first_discussion = "My first discussion"
- my_first_reply = "My First Reply"
- one_reply = "1 reply"
-
- show_page.select_all_activities_filter
- show_page.start_discussion(my_first_discussion)
- expect(show_page).to have_content(my_first_discussion)
+ show.select_all_activities_filter
+ show.start_discussion(my_first_discussion)
+ page.assert_text(my_first_discussion)
+ show.reply_to_discussion(my_first_reply)
+ page.assert_text(my_first_reply)
+ end
+ end
- show_page.reply_to_discussion(my_first_reply)
- expect(show_page).to have_content(my_first_reply)
+ it 'user collapses and expands reply for comments in an issue' do
+ Page::Project::Issue::Show.perform do |show|
+ one_reply = "1 reply"
- show_page.collapse_replies
- expect(show_page).to have_content(one_reply)
- expect(show_page).not_to have_content(my_first_reply)
+ show.collapse_replies
+ expect(show).to have_content(one_reply)
+ expect(show).not_to have_content(my_first_reply)
- show_page.expand_replies
- expect(show_page).to have_content(my_first_reply)
- expect(show_page).not_to have_content(one_reply)
+ show.expand_replies
+ expect(show).to have_content(my_first_reply)
+ expect(show).not_to have_content(one_reply)
end
end
end
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
new file mode 100644
index 00000000000..0b1bd00ac8d
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Plan' do
+ describe 'Issue comments' do
+ before do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.perform(&:sign_in_using_credentials)
+
+ issue = Resource::Issue.fabricate_via_api! do |issue|
+ issue.title = 'issue title'
+ end
+ issue.visit!
+ end
+
+ it 'user comments on an issue and edits the comment' do
+ Page::Project::Issue::Show.perform do |show|
+ first_version_of_comment = 'First version of the comment'
+ second_version_of_comment = 'Second version of the comment'
+
+ show.comment(first_version_of_comment)
+
+ expect(show).to have_content(first_version_of_comment)
+
+ show.edit_comment(second_version_of_comment)
+
+ expect(show).to have_content(second_version_of_comment)
+ expect(show).not_to have_content(first_version_of_comment)
+ end
+ end
+ end
+ end
+end
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 1eea3efec7f..04ae4963d3a 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
@@ -5,23 +5,35 @@ module QA
describe 'Issue creation' do
let(:issue_title) { 'issue title' }
+ before do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.perform(&:sign_in_using_credentials)
+ end
+
it 'user creates an issue' do
- create_issue
+ Resource::Issue.fabricate_via_browser_ui! do |issue|
+ issue.title = issue_title
+ end
- Page::Project::Menu.act { click_issues }
+ Page::Project::Menu.perform(&:click_issues)
expect(page).to have_content(issue_title)
end
- # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/101
- context 'when using attachments in comments', :object_storage, :quarantine do
+ context 'when using attachments in comments', :object_storage do
let(:file_to_attach) do
File.absolute_path(File.join('spec', 'fixtures', 'banana_sample.gif'))
end
- it 'user comments on an issue with an attachment' do
- create_issue
+ before do
+ issue = Resource::Issue.fabricate_via_api! do |issue|
+ issue.title = issue_title
+ end
+
+ issue.visit!
+ end
+ it 'user comments on an issue with an attachment' do
Page::Project::Issue::Show.perform do |show|
show.comment('See attached banana for scale', attachment: file_to_attach)
@@ -37,15 +49,6 @@ module QA
end
end
end
-
- def create_issue
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- Resource::Issue.fabricate_via_browser_ui! do |issue|
- issue.title = issue_title
- end
- end
end
end
end
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 301836f5ce8..cdb85902758 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,41 +1,42 @@
# frozen_string_literal: true
module QA
- context 'Plan' do
+ # Failure issue https://gitlab.com/gitlab-org/quality/staging/issues/68
+ context 'Plan', :quarantine do
describe 'filter issue comments activities' do
let(:issue_title) { 'issue title' }
- it 'user filters comments and activities in an issue' do
+ before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
issue = Resource::Issue.fabricate_via_api! do |issue|
issue.title = issue_title
end
issue.visit!
+ end
- expect(page).to have_content(issue_title)
-
- Page::Project::Issue::Show.perform do |show_page|
+ it 'user filters comments and activities in an issue' do
+ Page::Project::Issue::Show.perform do |show|
my_own_comment = "My own comment"
made_the_issue_confidential = "made the issue confidential"
- show_page.comment('/confidential', filter: :comments_only)
- show_page.comment(my_own_comment, filter: :comments_only)
+ show.comment('/confidential', filter: :comments_only)
+ show.comment(my_own_comment, filter: :comments_only)
- expect(show_page).not_to have_content(made_the_issue_confidential)
- expect(show_page).to have_content(my_own_comment)
+ expect(show).not_to have_content(made_the_issue_confidential)
+ expect(show).to have_content(my_own_comment)
- show_page.select_all_activities_filter
+ show.select_all_activities_filter
- expect(show_page).to have_content(made_the_issue_confidential)
- expect(show_page).to have_content(my_own_comment)
+ expect(show).to have_content(made_the_issue_confidential)
+ expect(show).to have_content(my_own_comment)
- show_page.select_history_only_filter
+ show.select_history_only_filter
- expect(show_page).to have_content(made_the_issue_confidential)
- expect(show_page).not_to have_content(my_own_comment)
+ expect(show).to have_content(made_the_issue_confidential)
+ expect(show).not_to have_content(my_own_comment)
end
end
end
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 24dcb32f63f..c42c2cedde0 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
@@ -5,7 +5,7 @@ module QA
describe 'issue suggestions' do
let(:issue_title) { 'Issue Lists are awesome' }
- it 'user sees issue suggestions when creating a new issue' do
+ before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
@@ -20,14 +20,16 @@ module QA
end
project.visit!
+ end
+ it 'user sees issue suggestions when creating a new issue' do
Page::Project::Show.perform(&:go_to_new_issue)
- Page::Project::Issue::New.perform do |new_issue_page|
- new_issue_page.add_title("issue")
- expect(new_issue_page).to have_content(issue_title)
+ Page::Project::Issue::New.perform do |new|
+ new.add_title("issue")
+ expect(new).to have_content(issue_title)
- new_issue_page.add_title("Issue Board")
- expect(new_issue_page).not_to have_content(issue_title)
+ new.add_title("Issue Board")
+ expect(new).not_to have_content(issue_title)
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
index 7a36f9ea420..3ce291bf8bc 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,8 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ # Failure issue: https://gitlab.com/gitlab-org/quality/staging/issues/66
+ context 'Create', :quarantine do
describe 'Merge request rebasing' do
it 'user rebases source branch of merge request' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
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 9e48ee7ca2a..891cef6c420 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
@@ -7,13 +7,18 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
- @merge_request = Resource::MergeRequest.fabricate! do |merge_request|
+ project = Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project'
+ end
+
+ @merge_request = Resource::MergeRequest.fabricate_via_api! do |merge_request|
+ merge_request.project = project
merge_request.title = 'This is a merge request'
- merge_request.description = 'For downloading patches and diffs'
+ merge_request.description = '... for downloading patches and diffs'
end
end
- it 'user views merge request email patches' do
+ it 'views the merge request email patches' do
@merge_request.visit!
Page::MergeRequest::Show.perform(&:view_email_patches)
@@ -22,7 +27,7 @@ module QA
expect(page).to have_content('diff --git a/added_file.txt b/added_file.txt')
end
- it 'user views merge request plain diff' do
+ it 'views the merge request plain diff' do
@merge_request.visit!
Page::MergeRequest::Show.perform(&:view_plain_diff)
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 2b3d9b1711d..36cbd1b81f0 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
@@ -56,7 +56,7 @@ module QA
project.visit!
end
- it 'branches are correctly listed after CRUD operations' do
+ it 'lists branches correctly after CRUD operations' do
Page::Project::Menu.perform(&:go_to_repository_branches)
expect(page).to have_content(master_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
index f41240b7605..56a7a04e840 100644
--- 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
@@ -7,7 +7,7 @@ module QA
it 'user adds and then removes an SSH key', :smoke do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
key = Resource::SSHKey.fabricate! do |resource|
resource.title = key_title
@@ -16,8 +16,8 @@ module QA
expect(page).to have_content("Title: #{key_title}")
expect(page).to have_content(key.fingerprint)
- Page::Main::Menu.act { click_settings_link }
- Page::Profile::Menu.act { click_ssh_keys }
+ 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)
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 d345fbfe995..51a1c19f0f7 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
@@ -5,7 +5,7 @@ module QA
describe 'Files management' do
it 'user creates, edits and deletes a file via the Web' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
# Create
file_name = 'QA Test - File name'
@@ -27,7 +27,7 @@ module QA
updated_file_content = 'QA Test - Updated file content'
commit_message_for_update = 'QA Test - Update file'
- Page::File::Show.act { click_edit }
+ Page::File::Show.perform(&:click_edit)
Page::File::Form.act do
remove_content
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 11fd570d131..2027a3c16aa 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,8 +1,7 @@
# frozen_string_literal: true
module QA
- # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/113
- context 'Create', :requires_admin, :quarantine do
+ context 'Create', :requires_admin do
describe 'push after setting the file size limit via admin/application_settings' do
before(:context) do
@project = Resource::Project.fabricate_via_api! do |p|
@@ -21,14 +20,21 @@ module QA
it 'push successful when the file size is under the limit' do
set_file_size_limit(5)
- push = push_new_file('oversize_file_1.bin', wait_for_push: true)
- expect(push.output).not_to have_content 'remote: fatal: pack exceeds maximum allowed size'
+
+ retry_on_fail do
+ push = push_new_file('oversize_file_1.bin', wait_for_push: true)
+
+ expect(push.output).not_to have_content 'remote: fatal: pack exceeds maximum allowed size'
+ end
end
it 'push fails when the file size is above the limit' do
set_file_size_limit(1)
- expect { push_new_file('oversize_file_2.bin', wait_for_push: false) }
- .to raise_error(QA::Git::Repository::RepositoryCommandError, /remote: fatal: pack exceeds maximum allowed size/)
+
+ retry_on_fail do
+ expect { push_new_file('oversize_file_2.bin', wait_for_push: false) }
+ .to raise_error(QA::Git::Repository::RepositoryCommandError, /remote: fatal: pack exceeds maximum allowed size/)
+ end
end
def set_file_size_limit(limit)
@@ -54,6 +60,22 @@ module QA
output
end
+
+ # Application settings are cached for up to a minute. So when we change
+ # the `receive_max_input_size` setting, the setting might not be applied
+ # for minute. This caused the tests to intermittently fail.
+ # See https://gitlab.com/gitlab-org/quality/nightly/issues/113
+ #
+ # Instead of waiting a minute after changing the setting, we retry the
+ # attempt to push if it fails. Most of the time the setting is updated in
+ # under a minute, i.e., in fewer than 6 attempts with a 10 second sleep
+ # between attempts.
+ # See https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30233#note_188616863
+ def retry_on_fail
+ Support::Retrier.retry_on_exception(max_attempts: 6, reload_page: nil, sleep_interval: 10) do
+ yield
+ end
+ end
end
end
end
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 6aebd04af03..e159e517cbb 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
@@ -13,7 +13,7 @@ module QA
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
end
after do
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 680c5e21fa4..21785ca3ed3 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
@@ -2,8 +2,7 @@
module QA
context 'Create' do
- # failure reported: https://gitlab.com/gitlab-org/quality/nightly/issues/42
- describe 'Commit data', :quarantine do
+ describe 'Commit data' do
before(:context) do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
@@ -50,7 +49,7 @@ module QA
Page::Project::Commit::Show.perform(&:select_email_patches)
- expect(page).to have_content("From: #{@user.name} <#{@user.public_email}>")
+ expect(page).to have_content(/From: "?#{Regexp.escape(@user.name)}"? <#{@user.public_email}>/)
expect(page).to have_content('Subject: [PATCH] Add second file')
expect(page).to have_content('diff --git a/second b/second')
end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb
index b060f15168c..b2c70547421 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb
@@ -7,12 +7,12 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
- project = Resource::Project.fabricate! do |project|
+ project = Resource::Project.fabricate_via_api! do |project|
project.name = 'project-with-ci-variables'
project.description = 'project with CI variables'
end
- Resource::CiVariable.fabricate! do |resource|
+ Resource::CiVariable.fabricate_via_api! do |resource|
resource.project = project
resource.key = 'VARIABLE_KEY'
resource.value = 'some_CI_variable'
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 3af7db751e7..33744236dd4 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
@@ -11,7 +11,7 @@ module QA
it 'user registers a new specific runner' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
Resource::Runner.fabricate! do |runner|
runner.name = executor
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 aa01e5a618e..6f39a755392 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,8 +1,7 @@
# frozen_string_literal: true
module QA
- # Failure issue: https://gitlab.com/gitlab-org/quality/staging/issues/26
- context 'Release', :quarantine do
+ context 'Release' do
describe 'Deploy key creation' do
it 'user adds a deploy key' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
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 2fe4e4d9d1f..f6411d8c5ad 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,36 +3,29 @@
require 'digest/sha1'
module QA
- # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/70
- context 'Release', :docker, :quarantine do
+ context 'Release', :docker do
describe 'Git clone using a deploy key' do
- def login
+ before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
- end
-
- before(:all) do
- login
@runner_name = "qa-runner-#{Time.now.to_i}"
- @project = Resource::Project.fabricate! do |resource|
+ @project = Resource::Project.fabricate_via_api! do |resource|
resource.name = 'deploy-key-clone-project'
end
@repository_location = @project.repository_ssh_location
- Resource::Runner.fabricate! do |resource|
+ Resource::Runner.fabricate_via_browser_ui! do |resource|
resource.project = @project
resource.name = @runner_name
resource.tags = %w[qa docker]
resource.image = 'gitlab/gitlab-runner:ubuntu'
end
-
- Page::Main::Menu.perform(&:sign_out)
end
- after(:all) do
+ after do
Service::Runner.new(@runner_name).remove!
end
@@ -46,9 +39,7 @@ module QA
it "user sets up a deploy key with #{key_class}(#{bits}) to clone code using pipelines" do
key = key_class.new(*bits)
- login
-
- Resource::DeployKey.fabricate! do |resource|
+ Resource::DeployKey.fabricate_via_browser_ui! do |resource|
resource.project = @project
resource.title = "deploy key #{key.name}(#{key.bits})"
resource.key = key.public_key
@@ -56,7 +47,7 @@ module QA
deploy_key_name = "DEPLOY_KEY_#{key.name}_#{key.bits}"
- Resource::CiVariable.fabricate! do |resource|
+ Resource::CiVariable.fabricate_via_browser_ui! do |resource|
resource.project = @project
resource.key = deploy_key_name
resource.value = key.private_key
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 caa9be341b4..ec0c45652fd 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
@@ -5,12 +5,12 @@ module QA
describe 'Deploy token creation' do
it 'user adds a deploy token' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
deploy_token_name = 'deploy token name'
one_week_from_now = Date.today + 7
- deploy_token = Resource::DeployToken.fabricate! do |resource|
+ deploy_token = Resource::DeployToken.fabricate_via_browser_ui! do |resource|
resource.name = deploy_token_name
resource.expires_at = one_week_from_now
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 99f0838b864..60c1e105ae6 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
@@ -55,8 +55,7 @@ module QA
end
end
- # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/108
- describe 'Auto DevOps support', :orchestrated, :kubernetes, :quarantine do
+ describe 'Auto DevOps support', :orchestrated, :kubernetes do
context 'when rbac is enabled' do
before(:all) do
@cluster = Service::KubernetesCluster.new.create!
diff --git a/qa/qa/support/retrier.rb b/qa/qa/support/retrier.rb
index 8be4e9f5365..720f1d17037 100644
--- a/qa/qa/support/retrier.rb
+++ b/qa/qa/support/retrier.rb
@@ -23,6 +23,25 @@ module QA
raise
end
end
+
+ def retry_until(max_attempts: 3, reload_page: nil, sleep_interval: 0)
+ QA::Runtime::Logger.debug("with retry_until: max_attempts #{max_attempts}; sleep_interval #{sleep_interval}; reload_page:#{reload_page}")
+ attempts = 0
+
+ while attempts < max_attempts
+ QA::Runtime::Logger.debug("Attempt number #{attempts + 1}")
+ result = yield
+ return result if result
+
+ sleep sleep_interval
+
+ reload_page.refresh if reload_page
+
+ attempts += 1
+ end
+
+ false
+ end
end
end
end
diff --git a/qa/qa/vendor/saml_idp/page/login.rb b/qa/qa/vendor/saml_idp/page/login.rb
index 9c1f9904a7a..1b8c926532a 100644
--- a/qa/qa/vendor/saml_idp/page/login.rb
+++ b/qa/qa/vendor/saml_idp/page/login.rb
@@ -12,6 +12,14 @@ module QA
fill_in 'password', with: 'user1pass'
click_on 'Login'
end
+
+ def login_if_required
+ login if login_required?
+ end
+
+ def login_required?
+ page.has_text?('Enter your username and password')
+ end
end
end
end