diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-20 14:43:17 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-20 14:43:17 +0300 |
commit | dfc94207fec2d84314b1a5410cface22e8b369bd (patch) | |
tree | c54022f61ced104305889a64de080998a0dc773b /qa | |
parent | b874efeff674f6bf0355d5d242ecf81c6f7155df (diff) |
Add latest changes from gitlab-org/gitlab@15-11-stable-eev15.11.0-rc42
Diffstat (limited to 'qa')
155 files changed, 2147 insertions, 1038 deletions
diff --git a/qa/Dockerfile b/qa/Dockerfile index 6efc8ac09fa..2bf668abc49 100644 --- a/qa/Dockerfile +++ b/qa/Dockerfile @@ -22,6 +22,13 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* ## +# Install 1Password CLI +# +RUN wget -P /tmp/ https://downloads.1password.com/linux/debian/$(dpkg --print-architecture)/stable/1password-cli-$(dpkg --print-architecture)-latest.deb +RUN dpkg -i /tmp/1password-cli-$(dpkg --print-architecture)-latest.deb +RUN op --version + +## # Install root certificate # RUN mkdir -p /usr/share/ca-certificates/gitlab diff --git a/qa/Gemfile b/qa/Gemfile index 9e35c619c5b..abb654b4a96 100644 --- a/qa/Gemfile +++ b/qa/Gemfile @@ -2,26 +2,26 @@ source 'https://rubygems.org' -gem 'gitlab-qa', '~> 9', '>= 9.1.2', require: 'gitlab/qa' +gem 'gitlab-qa', '~> 10', '>= 10.3.0', require: 'gitlab/qa' gem 'activesupport', '~> 6.1.7.2' # This should stay in sync with the root's Gemfile gem 'allure-rspec', '~> 2.20.0' -gem 'capybara', '~> 3.38.0' +gem 'capybara', '~> 3.39.0' gem 'capybara-screenshot', '~> 1.0.26' gem 'rake', '~> 13', '>= 13.0.6' gem 'rspec', '~> 3.12' -gem 'selenium-webdriver', '~> 4.8', '>= 4.8.1' +gem 'selenium-webdriver', '~> 4.8', '>= 4.8.6' gem 'airborne', '~> 0.3.7', require: false # airborne is messing with rspec sandboxed mode so not requiring by default gem 'rest-client', '~> 2.1.0' gem 'rspec-retry', '~> 0.6.2', require: 'rspec/retry' gem 'rspec_junit_formatter', '~> 0.6.0' -gem 'faker', '~> 3.1', '>= 3.1.1' +gem 'faker', '~> 3.2' gem 'knapsack', '~> 4.0' gem 'parallel_tests', '~> 4.2' gem 'rotp', '~> 6.2.2' -gem 'parallel', '~> 1.22', '>= 1.22.1' +gem 'parallel', '~> 1.23' gem 'rainbow', '~> 3.1.1' gem 'rspec-parameterized', '~> 1.0.0' -gem 'octokit', '~> 6.1.0' +gem 'octokit', '~> 6.1.1' gem "faraday-retry", "~> 2.1" gem 'webdrivers', '~> 5.2' gem 'zeitwerk', '~> 2.6', '>= 2.6.7' @@ -38,7 +38,7 @@ gem 'chemlab', '~> 0.10' gem 'chemlab-library-www-gitlab-com', '~> 0.1', '>= 0.1.1' # dependencies for jenkins client -gem 'nokogiri', '~> 1.14', '>= 1.14.2' +gem 'nokogiri', '~> 1.14', '>= 1.14.3' gem 'deprecation_toolkit', '~> 2.0.3', require: false diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index c3faf5841fc..e86a5526fc8 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -29,7 +29,7 @@ GEM debug_inspector (>= 0.0.1) builder (3.2.4) byebug (11.1.3) - capybara (3.38.0) + capybara (3.39.0) addressable matrix mini_mime (>= 0.1.3) @@ -63,7 +63,7 @@ GEM domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) excon (0.92.4) - faker (3.1.1) + faker (3.2.0) i18n (>= 1.8.11, < 2) faraday (2.5.2) faraday-net_http (>= 2.0, < 3.1) @@ -102,7 +102,7 @@ GEM gitlab (4.18.0) httparty (~> 0.18) terminal-table (>= 1.5.1) - gitlab-qa (9.1.2) + gitlab-qa (10.3.0) activesupport (~> 6.1) gitlab (~> 4.18.0) http (~> 5.0) @@ -181,15 +181,15 @@ GEM multi_json (1.15.0) multi_xml (0.6.0) netrc (0.11.0) - nokogiri (1.14.2) + nokogiri (1.14.3) mini_portile2 (~> 2.8.0) racc (~> 1.4) - octokit (6.1.0) + octokit (6.1.1) faraday (>= 1, < 3) sawyer (~> 0.9) oj (3.13.23) os (1.1.4) - parallel (1.22.1) + parallel (1.23.0) parallel_tests (4.2.0) parallel parser (3.1.3.0) @@ -260,7 +260,7 @@ GEM sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) - selenium-webdriver (4.8.1) + selenium-webdriver (4.8.6) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) @@ -308,22 +308,22 @@ DEPENDENCIES activesupport (~> 6.1.7.2) airborne (~> 0.3.7) allure-rspec (~> 2.20.0) - capybara (~> 3.38.0) + capybara (~> 3.39.0) capybara-screenshot (~> 1.0.26) chemlab (~> 0.10) chemlab-library-www-gitlab-com (~> 0.1, >= 0.1.1) confiner (~> 0.4) deprecation_toolkit (~> 2.0.3) - faker (~> 3.1, >= 3.1.1) + faker (~> 3.2) faraday-retry (~> 2.1) fog-core (= 2.1.0) fog-google (~> 1.19) - gitlab-qa (~> 9, >= 9.1.2) + gitlab-qa (~> 10, >= 10.3.0) influxdb-client (~> 2.9) knapsack (~> 4.0) - nokogiri (~> 1.14, >= 1.14.2) - octokit (~> 6.1.0) - parallel (~> 1.22, >= 1.22.1) + nokogiri (~> 1.14, >= 1.14.3) + octokit (~> 6.1.1) + parallel (~> 1.23) parallel_tests (~> 4.2) pry-byebug (~> 3.10.1) rainbow (~> 3.1.1) @@ -335,7 +335,7 @@ DEPENDENCIES rspec-retry (~> 0.6.2) rspec_junit_formatter (~> 0.6.0) ruby-debug-ide (~> 0.7.3) - selenium-webdriver (~> 4.8, >= 4.8.1) + selenium-webdriver (~> 4.8, >= 4.8.6) slack-notifier (~> 2.4) terminal-table (~> 3.0.2) warning (~> 1.3) @@ -343,4 +343,4 @@ DEPENDENCIES zeitwerk (~> 2.6, >= 2.6.7) BUNDLED WITH - 2.4.8 + 2.4.12 diff --git a/qa/README.md b/qa/README.md index e6520867642..d8670d4da02 100644 --- a/qa/README.md +++ b/qa/README.md @@ -48,6 +48,37 @@ Tests are executed in merge request pipelines as part of the development lifecyc - [Review app environment](../doc/development/testing_guide/review_apps.md) - [e2e:package-and-test](../doc/development/testing_guide/end_to_end/index.md#testing-code-in-merge-requests) +### Including tests in other projects + +Pipeline template for `package-and-test` E2E tests is designed in a way so it can be included as a child pipeline in other projects. + +Minimal configuration example would look like this: + +```yaml +qa-test: + stage: test + variables: + RELEASE: EE + trigger: + strategy: depend + forward: + yaml_variables: true + pipeline_variables: true + include: + - project: gitlab-org/gitlab + ref: master + file: .gitlab/ci/package-and-test/main.gitlab-ci.yml +``` + +To set GitLab version used for testing, following environment variables can be used: + +- `RELEASE`: `omnibus` release, can be string value `EE` or `CE` for nightly release of enterprise or community edition of GitLab or can be fully qualified Docker image name +- `QA_IMAGE`: Docker image of qa code. By default inferred from `RELEASE` but can be explicitly overridden with this variable + +#### Test specific environment variables + +Special GitLab configurations require various specific environment variables to be present for tests to work. These can be provisioned automatically using `terraform` setup in [engineering-productivity-infrastructure](https://gitlab.com/gitlab-org/quality/engineering-productivity-infrastructure/-/tree/main/qa-resources/modules/e2e-ci) project. + ### Logging By default tests on CI use `info` log level. `debug` level is still available in case of failure debugging. Logs are stored in jobs artifacts. @@ -98,7 +129,7 @@ See the section above for situations that might require adjustment to the comman 1. Use the following command to start an instance that you can visit at `http://127.0.0.1`: - ``` + ```bash docker run \ --hostname 127.0.0.1 \ --publish 80:80 --publish 22:22 \ @@ -137,7 +168,7 @@ See the section above for situations that might require adjustment to the comman 2. Use the following command to start an instance that you can visit at `http://127.0.0.1`. You might need to grant admin rights if asked: - ``` + ```bash docker run --hostname 127.0.0.1 --publish 80:80 --publish 22:22 --name gitlab --shm-size 256m --env GITLAB_OMNIBUS_CONFIG="gitlab_rails['initial_root_password']='5iveL\!fe';" gitlab/gitlab-ee:nightly ``` @@ -184,7 +215,7 @@ Those tests are tagged `:transient` and therefore can be run via: bundle exec rspec --tag transient ``` -#### Overriding gitlab address +#### Overriding GitLab address When running tests against GDK, the default address is `http://127.0.0.1:3000`. This value can be overridden by providing environment variable `QA_GITLAB_URL`: @@ -228,7 +259,7 @@ All [supported environment variables are here](https://gitlab.com/gitlab-org/git #### Sending additional cookies The environment variable `QA_COOKIES` can be set to send additional cookies -on every request. This is necessary on gitlab.com to direct traffic to the +on every request. This is necessary on `gitlab.com` to direct traffic to the canary fleet. To do this set `QA_COOKIES="gitlab_canary=true"`. To set multiple cookies, separate them with the `;` character, for example: `QA_COOKIES="cookie1=value;cookie2=value2"` @@ -274,7 +305,7 @@ bundle exec rspec --tag quarantine ### Running tests with a custom bin/qa test runner -`bin/qa` is an additional custom wrapper script that abstracts away some of the more complicated setups that some tests require. This option requires test scenario and test instance's Gitlab address to be specified in the command. For example, to run any `Instance` scenario test, the following command can be used: +`bin/qa` is an additional custom wrapper script that abstracts away some of the more complicated setups that some tests require. This option requires test scenario and test instance's GitLab address to be specified in the command. For example, to run any `Instance` scenario test, the following command can be used: ```shell bundle exec bin/qa Test::Instance::All http://localhost:3000 diff --git a/qa/gdk/launch b/qa/gdk/launch index 4b1fc6ae191..8ad2ce7e5ad 100755 --- a/qa/gdk/launch +++ b/qa/gdk/launch @@ -1,6 +1,6 @@ #!/bin/bash -COMMIT_REF=${1:-$CI_COMMIT_REF_SLUG} +COMMIT_REF=${1:-$CI_COMMIT_SHA} RSPEC_ARGS=$2 if [ -z "${COMMIT_REF}" ]; then @@ -83,7 +83,8 @@ module QA "vscode" => "VSCode", "registry_with_cdn" => "RegistryWithCDN", "fips" => "FIPS", - "ci_cd_settings" => "CICDSettings" + "ci_cd_settings" => "CICDSettings", + "cli" => "CLI" ) loader.setup diff --git a/qa/qa/ce/strategy.rb b/qa/qa/ce/strategy.rb index 8143595a18b..2587da17739 100644 --- a/qa/qa/ce/strategy.rb +++ b/qa/qa/ce/strategy.rb @@ -16,6 +16,9 @@ module QA QA::Runtime::Env.personal_access_token) end + QA::Runtime::Logger.info("Browser: #{QA::Runtime::Env.browser}") + QA::Runtime::Logger.info("Browser version: #{QA::Runtime::Env.browser_version}") + # The login page could take some time to load the first time it is visited. # We visit the login page and wait for it to properly load only once before the tests. QA::Runtime::Logger.info("Performing sanity check for environment!") diff --git a/qa/qa/flow/pipeline.rb b/qa/qa/flow/pipeline.rb index 0765a8758ec..d1cfe8dae09 100644 --- a/qa/qa/flow/pipeline.rb +++ b/qa/qa/flow/pipeline.rb @@ -9,7 +9,7 @@ module QA # canceled, created, failed, manual, passed # pending, running, skipped def visit_latest_pipeline(status: nil, wait: nil, skip_wait: true) - Page::Project::Menu.perform(&:click_ci_cd_pipelines) + Page::Project::Menu.perform(&:go_to_pipelines) Page::Project::Pipeline::Index.perform do |index| index.has_any_pipeline?(wait: wait) index.wait_for_latest_pipeline(status: status, wait: wait) if status || !skip_wait @@ -18,7 +18,7 @@ module QA end def wait_for_latest_pipeline(status: nil, wait: nil) - Page::Project::Menu.perform(&:click_ci_cd_pipelines) + Page::Project::Menu.perform(&:go_to_pipelines) Page::Project::Pipeline::Index.perform do |index| index.has_any_pipeline?(wait: wait) index.wait_for_latest_pipeline(status: status, wait: wait) diff --git a/qa/qa/flow/user_onboarding.rb b/qa/qa/flow/user_onboarding.rb index 8c6a50f251f..a04c29389f5 100644 --- a/qa/qa/flow/user_onboarding.rb +++ b/qa/qa/flow/user_onboarding.rb @@ -9,7 +9,7 @@ module QA Page::Registration::Welcome.perform do |welcome_page| if welcome_page.has_get_started_button? welcome_page.select_role('Other') - welcome_page.choose_setup_for_company_if_available + welcome_page.choose_setup_for_just_me_if_available welcome_page.choose_create_a_new_project_if_available welcome_page.click_get_started_button end diff --git a/qa/qa/page/admin/applications.rb b/qa/qa/page/admin/applications.rb new file mode 100644 index 00000000000..56880a4b22c --- /dev/null +++ b/qa/qa/page/admin/applications.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module QA + module Page + module Admin + class Applications < Page::Base + view 'app/views/admin/applications/index.html.haml' do + element :new_application_button + end + + view 'app/views/admin/applications/_form.html.haml' do + element :name_field + element :redirect_uri_field + element :trusted_checkbox + element :save_application_button + end + + view 'app/views/shared/tokens/_scopes_form.html.haml' do + element :api_label, '#{scope}_label' # rubocop:disable QA/ElementWithPattern, Lint/InterpolationCheck + end + + view 'app/views/shared/doorkeeper/applications/_show.html.haml' do + element :application_id_field + element :id_of_application_field + end + + view 'app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue' do + element :clipboard_button + end + + def click_new_application_button + click_element :new_application_button + end + + def fill_name(name) + fill_element :name_field, name + end + + def fill_redirect_uri(redirect_uri) + fill_element :redirect_uri_field, redirect_uri + end + + def set_trusted_checkbox(value) + check_element :trusted_checkbox, value + end + + def set_scope(scope) + click_element "#{scope}_label".to_sym + end + + def save_application + click_element :save_application_button + end + + def get_secret_id + find_element(:clipboard_button)['data-clipboard-text'] + end + + def get_application_id + find_element(:application_id_field).value + end + + # Returns the ID of the resource + def get_id_of_application + find_element(:id_of_application_field, visible: false).value + end + end + end + end +end diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb index 42dd1083bbe..6ef59e118fb 100644 --- a/qa/qa/page/admin/menu.rb +++ b/qa/qa/page/admin/menu.rb @@ -4,81 +4,71 @@ module QA module Page module Admin class Menu < Page::Base - view 'app/views/layouts/nav/sidebar/_admin.html.haml' do - element :admin_sidebar_content - element :admin_monitoring_menu_link - element :admin_monitoring_submenu_content + include SubMenus::Common + + if QA::Runtime::Env.super_sidebar_enabled? + prepend Sidebar::Overview + prepend Sidebar::Settings + end + + view 'lib/sidebars/admin/menus/admin_overview_menu.rb' do element :admin_overview_submenu_content - element :admin_overview_users_link - element :admin_overview_groups_link - element :admin_settings_menu_link - element :admin_settings_submenu_content - element :admin_settings_general_link - element :admin_settings_integrations_link - element :admin_settings_metrics_and_profiling_link - element :admin_settings_network_link - element :admin_settings_preferences_link - element :admin_settings_repository_link + end + + view 'lib/sidebars/admin/menus/analytics_menu.rb' do + element :admin_sidebar_analytics_submenu_content + end + + view 'lib/sidebars/admin/menus/monitoring_menu.rb' do + element :admin_monitoring_menu_link end def go_to_preferences_settings hover_element(:admin_settings_menu_link) do - within_submenu(:admin_settings_submenu_content) do - click_element :admin_settings_preferences_link - end + click_element :admin_settings_preferences_link end end def go_to_repository_settings hover_element(:admin_settings_menu_link) do - within_submenu(:admin_settings_submenu_content) do - click_element :admin_settings_repository_link - end + click_element :admin_settings_repository_link end end def go_to_integration_settings hover_element(:admin_settings_menu_link) do - within_submenu(:admin_settings_submenu_content) do - click_element :admin_settings_integrations_link - end + click_element :admin_settings_integrations_link end end def go_to_general_settings hover_element(:admin_settings_menu_link) do - within_submenu(:admin_settings_submenu_content) do - click_element :admin_settings_general_link - end + click_element :admin_settings_general_link end end def go_to_metrics_and_profiling_settings hover_element(:admin_settings_menu_link) do - within_submenu(:admin_settings_submenu_content) do - click_element :admin_settings_metrics_and_profiling_link - end + click_element :admin_settings_metrics_and_profiling_link end end def go_to_network_settings hover_element(:admin_settings_menu_link) do - within_submenu(:admin_settings_submenu_content) do - click_element :admin_settings_network_link - end + click_element :admin_settings_network_link end end def go_to_users_overview - within_submenu(:admin_overview_submenu_content) do - click_element :admin_overview_users_link - end + click_element :admin_overview_users_link end def go_to_groups_overview - within_submenu(:admin_overview_submenu_content) do - click_element :admin_overview_groups_link - end + click_element :admin_overview_groups_link + end + + def go_to_applications + click_element(:sidebar_menu_link, menu_item: 'Applications') end private @@ -93,7 +83,7 @@ module QA end def within_sidebar(&block) - within_element(:admin_sidebar_content, &block) + page.within('.sidebar-top-level-items', &block) end def within_submenu(element, &block) diff --git a/qa/qa/page/admin/sidebar/overview.rb b/qa/qa/page/admin/sidebar/overview.rb new file mode 100644 index 00000000000..5bd542a2e52 --- /dev/null +++ b/qa/qa/page/admin/sidebar/overview.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module QA + module Page + module Admin + module Sidebar + module Overview + def go_to_users_overview + open_overview_submenu("Users") + end + + def go_to_groups_overview + open_overview_submenu("Groups") + end + + private + + def open_overview_submenu(sub_menu) + open_submenu("Overview", sub_menu) + end + end + end + end + end +end diff --git a/qa/qa/page/admin/sidebar/settings.rb b/qa/qa/page/admin/sidebar/settings.rb new file mode 100644 index 00000000000..1eb6ac2c119 --- /dev/null +++ b/qa/qa/page/admin/sidebar/settings.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module QA + module Page + module Admin + module Sidebar + module Settings + def go_to_preferences_settings + open_settings_submenu("Preferences") + end + + def go_to_repository_settings + open_settings_submenu("Repository") + end + + def go_to_integration_settings + open_settings_submenu("Integration") + end + + def go_to_general_settings + open_settings_submenu("General") + end + + def go_to_metrics_and_profiling_settings + open_settings_submenu("Metrics and profiling") + end + + def go_to_network_settings + open_settings_submenu("Network") + end + + private + + def open_settings_submenu(sub_menu) + open_submenu("Settings", sub_menu) + end + end + end + end + end +end diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index ab83da7dacf..616c12bd900 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -6,7 +6,7 @@ module QA module Page class Base prepend Support::Page::Logging - prepend Mobile::Page::Base if QA::Runtime::Env.remote_mobile_device_name + prepend Mobile::Page::Base if QA::Runtime::Env.mobile_layout? include Capybara::DSL include Scenario::Actable @@ -234,13 +234,14 @@ module QA page.validate_elements_present! if page end - # Uses capybara to locate and click an element instead of `click_element`. - # This can be used when it's not possible to add a QA selector but we still want to log the click + # Uses capybara to locate and interact with an element instead of using `*_element`. + # This can be used when it's not possible to add a QA selector but we still want to log the action # # @param [String] method the capybara method to use # @param [String] locator the selector used to find the element - def click_via_capybara(method, locator) - page.public_send(method, locator) + # @param [Hash] **kwargs optional arguments + def act_via_capybara(method, locator, **kwargs) + page.public_send(method, locator, **kwargs) end def fill_element(name, content) diff --git a/qa/qa/page/component/breadcrumbs.rb b/qa/qa/page/component/breadcrumbs.rb index 2576e376e4e..f2343da489e 100644 --- a/qa/qa/page/component/breadcrumbs.rb +++ b/qa/qa/page/component/breadcrumbs.rb @@ -9,7 +9,7 @@ module QA def self.included(base) super - base.view 'app/views/layouts/nav/_breadcrumbs.html.haml' do + base.view 'app/views/layouts/nav/breadcrumbs/_breadcrumbs.html.haml' do element :breadcrumb_links_content end end diff --git a/qa/qa/page/component/content_editor.rb b/qa/qa/page/component/content_editor.rb index a9abda42610..f2733e4b065 100644 --- a/qa/qa/page/component/content_editor.rb +++ b/qa/qa/page/component/content_editor.rb @@ -17,7 +17,7 @@ module QA element :text_style_dropdown end - base.view 'app/assets/javascripts/content_editor/components/toolbar_image_button.vue' do + base.view 'app/assets/javascripts/content_editor/components/toolbar_attachment_button.vue' do element :file_upload_field end diff --git a/qa/qa/page/component/groups_filter.rb b/qa/qa/page/component/groups_filter.rb index 14e49e53b75..266c0dfa1af 100644 --- a/qa/qa/page/component/groups_filter.rb +++ b/qa/qa/page/component/groups_filter.rb @@ -34,7 +34,8 @@ module QA # @return [Boolean] whether the filter returned any group def filter_group(name) fill_element(:groups_filter_field, name).send_keys(:return) - finished_loading? + # Loading starts a moment after `return` is sent. We mustn't jump ahead + wait_for_requests if spinner_exists? has_element?(:groups_list_tree_container, wait: 1) end end diff --git a/qa/qa/page/component/snippet.rb b/qa/qa/page/component/snippet.rb index 4e1c7f3e2bb..b1d83a6e2d0 100644 --- a/qa/qa/page/component/snippet.rb +++ b/qa/qa/page/component/snippet.rb @@ -84,7 +84,7 @@ module QA element :copy_contents_button end - base.view 'app/views/layouts/nav/_breadcrumbs.html.haml' do + base.view 'app/views/layouts/nav/breadcrumbs/_breadcrumbs.html.haml' do element :breadcrumb_links_content element :breadcrumb_current_link end diff --git a/qa/qa/page/dashboard/snippet/index.rb b/qa/qa/page/dashboard/snippet/index.rb index 088fff17578..51d7bd3f20b 100644 --- a/qa/qa/page/dashboard/snippet/index.rb +++ b/qa/qa/page/dashboard/snippet/index.rb @@ -5,25 +5,12 @@ module QA module Dashboard module Snippet class Index < Page::Base - view 'app/views/layouts/header/_new_dropdown.html.haml' do - element :new_menu_toggle - end - - view 'app/helpers/nav/new_dropdown_helper.rb' do - element :global_new_snippet_link - end - view 'app/views/shared/snippets/_snippet.html.haml' do element :snippet_link element :snippet_visibility_content element :snippet_file_count_content end - def go_to_new_snippet_page - click_element :new_menu_toggle - click_element :global_new_snippet_link - end - def has_snippet_title?(snippet_title) has_element?(:snippet_link, snippet_title: snippet_title) end diff --git a/qa/qa/page/file/show.rb b/qa/qa/page/file/show.rb index 31899d9a0c7..011b1ea5d81 100644 --- a/qa/qa/page/file/show.rb +++ b/qa/qa/page/file/show.rb @@ -5,8 +5,6 @@ module QA module File class Show < Page::Base include Shared::CommitMessage - include Project::SubMenus::Settings - include Project::SubMenus::Common include Layout::Flash include Page::Component::BlobContent diff --git a/qa/qa/page/group/menu.rb b/qa/qa/page/group/menu.rb index 9418593133e..490b16a53fd 100644 --- a/qa/qa/page/group/menu.rb +++ b/qa/qa/page/group/menu.rb @@ -6,6 +6,14 @@ module QA class Menu < Page::Base include SubMenus::Common + if Runtime::Env.super_sidebar_enabled? + prepend Page::SubMenus::SuperSidebar::Manage + prepend Page::SubMenus::SuperSidebar::Plan + prepend Page::SubMenus::SuperSidebar::Settings + prepend SubMenus::SuperSidebar::Main + prepend SubMenus::SuperSidebar::Build + end + def click_group_members_item hover_group_information do within_submenu do @@ -15,6 +23,8 @@ module QA end def click_subgroup_members_item + return go_to_members if Runtime::Env.super_sidebar_enabled? + hover_subgroup_information do within_submenu do click_element(:sidebar_menu_item_link, menu_item: 'Members') @@ -29,6 +39,8 @@ module QA end def click_group_general_settings_item + return go_to_general_settings if Runtime::Env.super_sidebar_enabled? + hover_group_settings do within_submenu do click_element(:sidebar_menu_item_link, menu_item: 'General') diff --git a/qa/qa/page/group/sub_menus/super_sidebar/build.rb b/qa/qa/page/group/sub_menus/super_sidebar/build.rb new file mode 100644 index 00000000000..0b8bf030622 --- /dev/null +++ b/qa/qa/page/group/sub_menus/super_sidebar/build.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module QA + module Page + module Group + module SubMenus + module SuperSidebar + module Build + extend QA::Page::PageConcern + + def go_to_runners + open_build_submenu("Runners") + end + + private + + def open_build_submenu(sub_menu) + open_submenu("Build", sub_menu) + end + end + end + end + end + end +end diff --git a/qa/qa/page/group/sub_menus/super_sidebar/main.rb b/qa/qa/page/group/sub_menus/super_sidebar/main.rb new file mode 100644 index 00000000000..e470c03b9e5 --- /dev/null +++ b/qa/qa/page/group/sub_menus/super_sidebar/main.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module QA + module Page + module Group + module SubMenus + module SuperSidebar + module Main + extend QA::Page::PageConcern + + def self.included(base) + super + + base.class_eval do + include QA::Page::SubMenus::SuperSidebar::Main + end + end + + def go_to_group_overview + click_element(:nav_item_link, submenu_item: 'Group overview') + end + end + end + end + end + end +end diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb index 7532154f0cc..59371dbed39 100644 --- a/qa/qa/page/main/login.rb +++ b/qa/qa/page/main/login.rb @@ -40,6 +40,8 @@ module QA view 'app/helpers/auth_helper.rb' do element :saml_login_button + element :github_login_button + element :oidc_login_button end view 'app/views/layouts/devise.html.haml' do @@ -106,7 +108,7 @@ module QA # Happens on clean GDK installations when seeded root admin password is expired # def set_up_new_password_if_required(user:, skip_page_validation:) - return unless has_content?('Set up new password') + return unless has_content?('Set up new password', wait: 1) Profile::Password.perform do |new_password_page| password = user&.password || Runtime::User.password @@ -177,11 +179,21 @@ module QA click_element :standard_tab end + def sign_in_with_github + set_initial_password_if_present + click_element :github_login_button + end + def sign_in_with_saml set_initial_password_if_present click_element :saml_login_button end + def sign_in_with_oidc + set_initial_password_if_present + click_element :oidc_login_button + end + def sign_out_and_sign_in_as(user:) Menu.perform(&:sign_out_if_signed_in) has_sign_in_tab? @@ -226,6 +238,10 @@ module QA Support::WaitForRequests.wait_for_requests + wait_until(sleep_interval: 5, message: '502 - GitLab is taking too much time to respond') do + has_no_text?('GitLab is taking too much time to respond') + end + # For debugging invalid login attempts has_notice?('Invalid login or password') @@ -233,7 +249,7 @@ module QA terms.accept_terms if terms.visible? end - Page::Main::Menu.perform(&:enable_new_navigation) if Runtime::Env.super_sidebar_enabled? + Page::Main::Menu.perform(&:enable_new_navigation) if Runtime::Env.super_sidebar_enabled? && !on_login_page? Page::Main::Menu.validate_elements_present! unless skip_page_validation end diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index f86849061e8..a46b2057327 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -4,14 +4,21 @@ module QA module Page module Main class Menu < Page::Base - prepend Mobile::Page::Main::Menu if Runtime::Env.mobile_layout? + # We need to check phone_layout? instead of mobile_layout? here + # since tablets have the regular top navigation bar + prepend Mobile::Page::Main::Menu if Runtime::Env.phone_layout? + + if Runtime::Env.super_sidebar_enabled? + prepend SubMenus::CreateNewMenu + include SubMenus::SuperSidebar::ContextSwitcher + end if QA::Runtime::Env.super_sidebar_enabled? # Define alternative navbar (super sidebar) which does not yet implement all the same elements view 'app/assets/javascripts/super_sidebar/components/super_sidebar.vue' do element :navbar, required: true # TODO: rename to sidebar once it's default implementation - element :user_menu, required: !QA::Runtime::Env.mobile_layout? - element :user_avatar_content, required: !QA::Runtime::Env.mobile_layout? + element :user_menu, required: !Runtime::Env.phone_layout? + element :user_avatar_content, required: !Runtime::Env.phone_layout? end view 'app/assets/javascripts/super_sidebar/components/user_menu.vue' do @@ -22,12 +29,12 @@ module QA view 'app/views/layouts/header/_default.html.haml' do element :navbar, required: true element :canary_badge_link - element :user_avatar_content, required: !QA::Runtime::Env.mobile_layout? - element :user_menu, required: !QA::Runtime::Env.mobile_layout? + element :user_avatar_content, required: !Runtime::Env.phone_layout? + element :user_menu, required: !Runtime::Env.phone_layout? element :stop_impersonation_link - element :issues_shortcut_button, required: !QA::Runtime::Env.mobile_layout? - element :merge_requests_shortcut_button, required: !QA::Runtime::Env.mobile_layout? - element :todos_shortcut_button, required: !QA::Runtime::Env.mobile_layout? + element :issues_shortcut_button, required: !Runtime::Env.phone_layout? + element :merge_requests_shortcut_button, required: !Runtime::Env.phone_layout? + element :todos_shortcut_button, required: !Runtime::Env.phone_layout? end view 'app/views/layouts/header/_current_user_dropdown.html.haml' do @@ -56,10 +63,6 @@ module QA element :menu_item_link end - view 'app/views/layouts/_search.html.haml' do - element :search_term_field - end - view 'app/views/layouts/_header_search.html.haml' do element :search_box end @@ -75,30 +78,38 @@ module QA view 'app/helpers/nav/new_dropdown_helper.rb' do element :global_new_group_link element :global_new_project_link + element :global_new_snippet_link end view 'app/assets/javascripts/nav/components/new_nav_toggle.vue' do element :new_navigation_toggle end - def go_to_groups - within_groups_menu do - click_element(:menu_item_link, title: 'View all groups') - end - end + def go_to_projects + return click_element(:nav_item_link, submenu_item: 'Projects') if Runtime::Env.super_sidebar_enabled? - def go_to_create_group - click_element(:new_menu_toggle) - click_element(:global_new_group_link) + click_element(:sidebar_menu_link, menu_item: 'Projects') end - def go_to_projects - within_projects_menu do - click_element(:menu_item_link, title: 'View all projects') + def go_to_groups + return click_element(:nav_item_link, submenu_item: 'Groups') if Runtime::Env.super_sidebar_enabled? + + # Use new functionality to visit Groups where possible + if has_element?(:sidebar_menu_link, menu_item: 'Groups') + click_element(:sidebar_menu_link, menu_item: 'Groups') + else + # Otherwise fallback to previous functionality + # See https://gitlab.com/gitlab-org/gitlab/-/issues/403589 + # and related issues + within_groups_menu do + click_element(:menu_item_link, title: 'View all groups') + end end end def go_to_snippets + return click_element(:nav_item_link, submenu_item: 'Snippets') if Runtime::Env.super_sidebar_enabled? + click_element(:sidebar_menu_link, menu_item: 'Snippets') end @@ -107,6 +118,16 @@ module QA click_element(:global_new_project_link) end + def go_to_create_group + click_element(:new_menu_toggle) + click_element(:global_new_group_link) + end + + def go_to_create_snippet + click_element(:new_menu_toggle) + click_element(:global_new_snippet_link) + end + def go_to_menu_dropdown_option(option_name) return click_element(option_name) if QA::Runtime::Env.super_sidebar_enabled? @@ -129,7 +150,7 @@ module QA end def go_to_admin_area - click_admin_area + Runtime::Env.super_sidebar_enabled? ? super : click_admin_area return unless has_text?('Enter Admin Mode', wait: 1.0) @@ -146,7 +167,7 @@ module QA end def signed_in_as_user?(user) - return false if has_no_personal_area? + return false unless has_personal_area? within_user_menu do has_element?(:user_profile_link, text: /#{user.username}/) diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb index 451a9c3ee6e..d96acc36b2e 100644 --- a/qa/qa/page/merge_request/show.rb +++ b/qa/qa/page/merge_request/show.rb @@ -199,7 +199,15 @@ module QA end def click_diffs_tab - click_element(:diffs_tab) + # Do not wait for spinner due to https://gitlab.com/gitlab-org/gitlab/-/issues/398584 + click_element(:diffs_tab, skip_finished_loading_check: true) + + # If the diff isn't available when we navigate to the Changes tab + # we must reload the page. https://gitlab.com/gitlab-org/gitlab/-/issues/398557 + wait_until(reload: true, skip_finished_loading_check_on_refresh: true) do + QA::Runtime::Logger.debug('Ensuring that diff has loaded async') + has_element?(:file_tree_button, skip_finished_loading_check: true, wait: 1) + end end def click_pipeline_link diff --git a/qa/qa/page/profile/menu.rb b/qa/qa/page/profile/menu.rb index 651603a77db..f9493dbefcc 100644 --- a/qa/qa/page/profile/menu.rb +++ b/qa/qa/page/profile/menu.rb @@ -4,9 +4,9 @@ module QA module Page module Profile class Menu < Page::Base - # We need to check remote_mobile_device_name instead of mobile_layout? here - # since tablets have the regular top navigation bar but still close the left nav - prepend QA::Mobile::Page::SubMenus::Common if QA::Runtime::Env.remote_mobile_device_name + prepend QA::Mobile::Page::SubMenus::Common if QA::Runtime::Env.mobile_layout? + # TODO: integrate back once super sidebar becomes default + prepend QA::Page::Profile::SuperSidebar::Menu if QA::Runtime::Env.super_sidebar_enabled? view 'lib/sidebars/user_settings/menus/access_tokens_menu.rb' do element :access_token_link @@ -60,10 +60,8 @@ module QA private - def within_sidebar - page.within('.sidebar-top-level-items') do - yield - end + def within_sidebar(&block) + page.within('.sidebar-top-level-items', &block) end end end diff --git a/qa/qa/page/profile/super_sidebar/menu.rb b/qa/qa/page/profile/super_sidebar/menu.rb new file mode 100644 index 00000000000..ade9c47313d --- /dev/null +++ b/qa/qa/page/profile/super_sidebar/menu.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module QA + module Page + module Profile + module SuperSidebar + module Menu + def click_ssh_keys + click_element(:nav_item_link, submenu_item: 'SSH Keys') + end + + def click_account + click_element(:nav_item_link, submenu_item: 'Account') + end + + def click_emails + click_element(:nav_item_link, submenu_item: 'Emails') + end + + def click_password + click_element(:nav_item_link, submenu_item: 'Password') + end + + def click_access_tokens + click_element(:nav_item_link, submenu_item: 'Access Tokens') + end + end + end + end + end +end diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb index bb1095371a8..759729f0abf 100644 --- a/qa/qa/page/project/import/github.rb +++ b/qa/qa/page/project/import/github.rb @@ -32,6 +32,8 @@ module QA # In this case skip this step and proceed to import project row return unless has_element?(:personal_access_token_field) + raise ArgumentError, "No personal access token was provided" if personal_access_token.empty? + fill_element(:personal_access_token_field, personal_access_token) click_element(:authenticate_button) finished_loading? @@ -71,7 +73,11 @@ module QA # @param [String] source_project_name # @param [Integer] wait # @return [Boolean] - def has_imported_project?(gh_project_name, wait: QA::Support::WaitForRequests::DEFAULT_MAX_WAIT_TIME) + def has_imported_project?( + gh_project_name, + wait: QA::Support::WaitForRequests::DEFAULT_MAX_WAIT_TIME, + allow_partial_import: false + ) within_element(:project_import_row, source_project: gh_project_name, skip_finished_loading_check: true) do wait_until( max_duration: wait, @@ -80,18 +86,12 @@ module QA skip_finished_loading_check_on_refresh: true ) do status_selector = 'import_status_indicator' - is_partial_import = has_css?(status_selector, text: "Partial import") - # Temporarily adding this for investigation purposes. This makes sure that the details section is - # expanded when the screenshot is taken when the test fails. This can be removed or repurposed later - # after investigation. Related: https://gitlab.com/gitlab-org/gitlab/-/issues/385252#note_1211218434 - if is_partial_import - within_element_by_index(:import_status_indicator, 0) do - find('button').click - end - end + return has_element?(status_selector, text: "Complete", wait: 1) unless allow_partial_import # rubocop:disable Cop/AvoidReturnFromBlocks - has_element?(status_selector, text: "Complete") + ["Partially completed", "Complete"].any? do |status| + has_element?(status_selector, text: status, wait: 1) + end end end end diff --git a/qa/qa/page/project/import/repo_by_url.rb b/qa/qa/page/project/import/repo_by_url.rb index 4a8d08d6499..42e701bf882 100644 --- a/qa/qa/page/project/import/repo_by_url.rb +++ b/qa/qa/page/project/import/repo_by_url.rb @@ -17,8 +17,6 @@ module QA click_create_button wait_for_success - - go_to_project(name) end private @@ -52,13 +50,6 @@ module QA page.has_no_content?('Import in progress', wait: 3.0) end end - - def go_to_project(name) - Page::Main::Menu.perform(&:go_to_projects) - Page::Dashboard::Projects.perform do |dashboard| - dashboard.go_to_project(name) - end - end end end end diff --git a/qa/qa/page/project/issue/new.rb b/qa/qa/page/project/issue/new.rb index c90a09dce2e..7f52cda7c15 100644 --- a/qa/qa/page/project/issue/new.rb +++ b/qa/qa/page/project/issue/new.rb @@ -17,3 +17,5 @@ module QA end end end + +QA::Page::Project::Issue::New.prepend_mod_with('Page::Project::Issue::New', namespace: QA) diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb index 2f8ffc634ac..20dce1b3639 100644 --- a/qa/qa/page/project/issue/show.rb +++ b/qa/qa/page/project/issue/show.rb @@ -8,7 +8,9 @@ module QA include Page::Component::Note include Page::Component::DesignManagement include Page::Component::Issuable::Sidebar - prepend Mobile::Page::Project::Issue::Show if Runtime::Env.mobile_layout? + # We need to check phone_layout? instead of mobile_layout? here + # since tablets have the regular top navigation bar + prepend Mobile::Page::Project::Issue::Show if Runtime::Env.phone_layout? view 'app/assets/javascripts/issuable/components/related_issuable_item.vue' do element :remove_related_issue_button diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb index 444c67cfe4f..41a2986e300 100644 --- a/qa/qa/page/project/job/show.rb +++ b/qa/qa/page/project/job/show.rb @@ -69,11 +69,11 @@ module QA end def has_locked_artifact? - has_text?('will not be deleted') + has_element? :artifacts_locked_message_content end def has_unlocked_artifact? - has_text?('will be removed') + has_element? :artifacts_unlocked_message_content end private diff --git a/qa/qa/page/project/menu.rb b/qa/qa/page/project/menu.rb index db70d3e1d02..23b3ee61077 100644 --- a/qa/qa/page/project/menu.rb +++ b/qa/qa/page/project/menu.rb @@ -14,20 +14,38 @@ module QA include SubMenus::Repository include SubMenus::Settings include SubMenus::Packages + include SubMenus::CreateNewMenu + + if Runtime::Env.super_sidebar_enabled? + include Page::SubMenus::SuperSidebar::Manage + include SubMenus::SuperSidebar::Plan + include SubMenus::SuperSidebar::Settings + include SubMenus::SuperSidebar::Code + include SubMenus::SuperSidebar::Build + include SubMenus::SuperSidebar::Operate + include SubMenus::SuperSidebar::Monitor + include SubMenus::SuperSidebar::Main + end def click_merge_requests + return go_to_merge_requests if Runtime::Env.super_sidebar_enabled? + within_sidebar do click_element(:sidebar_menu_link, menu_item: 'Merge requests') end end def click_wiki + return go_to_wiki if Runtime::Env.super_sidebar_enabled? + within_sidebar do click_element(:sidebar_menu_link, menu_item: 'Wiki') end end def click_activity + return go_to_activity if Runtime::Env.super_sidebar_enabled? + hover_project_information do within_submenu do click_element(:sidebar_menu_item_link, menu_item: 'Activity') @@ -36,12 +54,16 @@ module QA end def click_snippets + return go_to_snippets if Runtime::Env.super_sidebar_enabled? + within_sidebar do click_element(:sidebar_menu_link, menu_item: 'Snippets') end end def click_members + return go_to_members if Runtime::Env.super_sidebar_enabled? + hover_project_information do within_submenu do click_element(:sidebar_menu_item_link, menu_item: 'Members') diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb index 25d62ac59af..2455555f06c 100644 --- a/qa/qa/page/project/pipeline/show.rb +++ b/qa/qa/page/project/pipeline/show.rb @@ -44,7 +44,7 @@ module QA element :jobs_dropdown_menu end - view 'app/views/layouts/nav/_breadcrumbs.html.haml' do + view 'app/views/layouts/nav/breadcrumbs/_breadcrumbs.html.haml' do element :breadcrumb_links_content element :breadcrumb_current_link end diff --git a/qa/qa/page/project/settings/branch_rules.rb b/qa/qa/page/project/settings/branch_rules.rb new file mode 100644 index 00000000000..b01f493addf --- /dev/null +++ b/qa/qa/page/project/settings/branch_rules.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module Settings + class BranchRules < Page::Base + view 'app/assets/javascripts/projects/settings/repository/branch_rules/app.vue' do + element :add_branch_rule_button + end + + view 'app/assets/javascripts/projects/settings/repository/branch_rules/components/branch_rule.vue' do + element :branch_content + element :details_button + end + + def click_add_branch_rule + click_element(:add_branch_rule_button) + click_button('Create protected branch') + end + + def navigate_to_branch_rules_details(branch_name) + within_element(:branch_content, branch_name: branch_name) do + click_element(:details_button) + end + end + end + end + end + end +end + +QA::Page::Project::Settings::BranchRules.prepend_mod_with('Page::Project::Settings::BranchRules', namespace: QA) diff --git a/qa/qa/page/project/settings/branch_rules_details.rb b/qa/qa/page/project/settings/branch_rules_details.rb new file mode 100644 index 00000000000..f6806a30efa --- /dev/null +++ b/qa/qa/page/project/settings/branch_rules_details.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module Settings + class BranchRulesDetails < Page::Base + view 'app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue' do + element :allowed_to_push_content + element :allowed_to_merge_content + end + + view 'app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue' do + element :access_level_content + end + + def has_allowed_to_push?(role) + within_element(:allowed_to_push_content) do + has_element?(:access_level_content, role: role) + end + end + + def has_allowed_to_merge?(role) + within_element(:allowed_to_merge_content) do + has_element?(:access_level_content, role: role) + end + end + end + end + end + end +end + +QA::Page::Project::Settings::BranchRulesDetails.prepend_mod_with( # rubocop:disable Cop/InjectEnterpriseEditionModule + 'Page::Project::Settings::BranchRulesDetails', namespace: QA) diff --git a/qa/qa/page/project/settings/ci_variables.rb b/qa/qa/page/project/settings/ci_variables.rb index 8df0aaa9f27..1315ed8ca73 100644 --- a/qa/qa/page/project/settings/ci_variables.rb +++ b/qa/qa/page/project/settings/ci_variables.rb @@ -11,7 +11,6 @@ module QA element :ci_variable_key_field element :ci_variable_value_field element :ci_variable_save_button - element :ci_variable_delete_button end def fill_variable(key, value, masked = false) @@ -37,14 +36,6 @@ module QA def click_ci_variable_save_button click_element :ci_variable_save_button end - - def click_reveal_ci_variable_value_button - click_element :reveal_ci_variable_value_button - end - - def click_ci_variable_delete_button - click_element :ci_variable_delete_button - end end end end diff --git a/qa/qa/page/project/settings/deploy_keys.rb b/qa/qa/page/project/settings/deploy_keys.rb index 297d29550e3..b94dbbea533 100644 --- a/qa/qa/page/project/settings/deploy_keys.rb +++ b/qa/qa/page/project/settings/deploy_keys.rb @@ -13,6 +13,7 @@ module QA view 'app/views/shared/deploy_keys/_project_group_form.html.haml' do element :deploy_key_title_field element :deploy_key_field + element :deploy_key_expires_at_field element :add_deploy_key_button end diff --git a/qa/qa/page/project/settings/main.rb b/qa/qa/page/project/settings/main.rb index 8b9b72758d8..0d45efdcb70 100644 --- a/qa/qa/page/project/settings/main.rb +++ b/qa/qa/page/project/settings/main.rb @@ -6,7 +6,6 @@ module QA module Settings class Main < Page::Base include QA::Page::Settings::Common - include SubMenus::Project include Component::Breadcrumbs include Layout::Flash diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb index 6931d26b259..d9aaacbde32 100644 --- a/qa/qa/page/project/settings/repository.rb +++ b/qa/qa/page/project/settings/repository.rb @@ -27,6 +27,10 @@ module QA element :protected_tag_settings_content end + view 'app/views/projects/branch_rules/_show.html.haml' do + element :branch_rules_content + end + def expand_deploy_tokens(&block) expand_content(:deploy_tokens_settings_content) do Settings::DeployTokens.perform(&block) @@ -57,6 +61,10 @@ module QA end end + def expand_branch_rules + expand_content(:branch_rules_content) + end + def expand_default_branch(&block) within('#branch-defaults-settings') do find('.btn-default').click do diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index b89e17910c9..a76717f4760 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -7,9 +7,11 @@ module QA include Layout::Flash include Page::Component::ClonePanel include Page::Component::Breadcrumbs - include Page::Project::SubMenus::Settings include Page::File::Shared::CommitMessage - prepend Mobile::Page::Project::Show if Runtime::Env.mobile_layout? + include Page::Component::Dropdown + # We need to check phone_layout? instead of mobile_layout? here + # since tablets have the regular top navigation bar + prepend Mobile::Page::Project::Show if Runtime::Env.phone_layout? view 'app/assets/javascripts/repository/components/preview/index.vue' do element :blob_viewer_content @@ -27,10 +29,6 @@ module QA element :new_menu_toggle end - view 'app/helpers/nav/new_dropdown_helper.rb' do - element :new_issue_link - end - view 'app/views/projects/_last_push.html.haml' do element :create_merge_request_button end @@ -68,11 +66,6 @@ module QA element :web_ide_button end - view 'app/views/shared/_ref_switcher.html.haml' do - element :branches_dropdown - element :branches_dropdown_content - end - view 'app/views/projects/blob/viewers/_loading.html.haml' do element :spinner_placeholder end @@ -122,11 +115,6 @@ module QA end end - def go_to_new_issue - click_element(:new_menu_toggle) - click_element(:new_issue_link) - end - def has_create_merge_request_button? has_css?(element_selector_css(:create_merge_request_button)) end @@ -184,11 +172,8 @@ module QA end def switch_to_branch(branch_name) - find_element(:branches_dropdown).click - - within_element(:branches_dropdown_content) do - click_on branch_name - end + expand_select_list + select_item(branch_name) end def wait_for_import diff --git a/qa/qa/page/project/sub_menus/ci_cd.rb b/qa/qa/page/project/sub_menus/ci_cd.rb index 4ae51798e54..3547ea76182 100644 --- a/qa/qa/page/project/sub_menus/ci_cd.rb +++ b/qa/qa/page/project/sub_menus/ci_cd.rb @@ -15,7 +15,7 @@ module QA end end - def click_ci_cd_pipelines + def go_to_pipelines within_sidebar do click_element(:sidebar_menu_link, menu_item: 'CI/CD') end diff --git a/qa/qa/page/project/sub_menus/common.rb b/qa/qa/page/project/sub_menus/common.rb index 79054ec9802..e8952f9e064 100644 --- a/qa/qa/page/project/sub_menus/common.rb +++ b/qa/qa/page/project/sub_menus/common.rb @@ -20,7 +20,7 @@ module QA element :sidebar_menu_link end - view 'app/views/layouts/nav/_breadcrumbs.html.haml' do + view 'app/views/layouts/nav/_top_bar.html.haml' do element :toggle_mobile_nav_button end end diff --git a/qa/qa/page/project/sub_menus/create_new_menu.rb b/qa/qa/page/project/sub_menus/create_new_menu.rb new file mode 100644 index 00000000000..cfb91c29d5e --- /dev/null +++ b/qa/qa/page/project/sub_menus/create_new_menu.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module SubMenus + module CreateNewMenu + extend QA::Page::PageConcern + + def self.included(base) + super + + base.class_eval do + # TODO: remove this when the super sidebar is enabled by default + view 'app/helpers/nav/new_dropdown_helper.rb' do + element :new_issue_link + end + + view 'app/helpers/sidebars_helper.rb' do + element :create_menu_item + end + end + end + + def go_to_new_issue + within_new_item_menu do + next click_element(:new_issue_link) unless QA::Runtime::Env.super_sidebar_enabled? + + click_element(:create_menu_item, create_menu_item: 'new_issue') + end + end + + def go_to_new_merge_request + within_new_item_menu do + click_element(:create_menu_item, create_menu_item: 'new_mr') + end + end + + def go_to_new_project_snippet + within_new_item_menu do + click_element(:create_menu_item, create_menu_item: 'new_snippet') + end + end + + def go_to_invite_members + within_new_item_menu do + click_element(:create_menu_item, create_menu_item: 'invite') + end + 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 7fa19063653..b5b918e076d 100644 --- a/qa/qa/page/project/sub_menus/issues.rb +++ b/qa/qa/page/project/sub_menus/issues.rb @@ -15,7 +15,7 @@ module QA end end - def click_issues + def go_to_issues within_sidebar do click_element(:sidebar_menu_link, menu_item: 'Issues') end @@ -27,7 +27,7 @@ module QA end end - def go_to_boards + def go_to_issue_boards hover_issues do within_submenu do click_element(:sidebar_menu_item_link, menu_item: 'Boards') diff --git a/qa/qa/page/project/sub_menus/packages.rb b/qa/qa/page/project/sub_menus/packages.rb index 9600540c5bc..aaa4a2d2f66 100644 --- a/qa/qa/page/project/sub_menus/packages.rb +++ b/qa/qa/page/project/sub_menus/packages.rb @@ -26,7 +26,7 @@ module QA def go_to_infrastructure_registry hover_registry do within_submenu do - click_link('Infrastructure Registry') + click_link('Terraform modules') end end end diff --git a/qa/qa/page/project/sub_menus/super_sidebar/build.rb b/qa/qa/page/project/sub_menus/super_sidebar/build.rb new file mode 100644 index 00000000000..7d772d9d192 --- /dev/null +++ b/qa/qa/page/project/sub_menus/super_sidebar/build.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module SubMenus + module SuperSidebar + module Build + extend QA::Page::PageConcern + + def go_to_pipelines + open_build_submenu('Pipelines') + end + + def go_to_pipeline_editor + open_build_submenu('Pipeline editor') + end + + def go_to_jobs + open_build_submenu('Jobs') + end + + def go_to_schedules + open_build_submenu('Pipeline schedules') + end + + def go_to_environments + open_operations_submenu('Environments') + end + + def go_to_feature_flags + open_operations_submenu('Feature Flags') + end + + def go_to_releases + open_operations_submenu('Releases') + end + + private + + def open_build_submenu(sub_menu) + open_submenu('Build', sub_menu) + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/sub_menus/super_sidebar/code.rb b/qa/qa/page/project/sub_menus/super_sidebar/code.rb new file mode 100644 index 00000000000..44d46725b47 --- /dev/null +++ b/qa/qa/page/project/sub_menus/super_sidebar/code.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module SubMenus + module SuperSidebar + module Code + extend QA::Page::PageConcern + + def go_to_repository + open_code_submenu('Repository') + end + + def go_to_repository_commits + open_code_submenu('Commits') + end + + def go_to_repository_branches + open_code_submenu('Branches') + end + + def go_to_repository_tags + open_code_submenu('Tags') + end + + def go_to_snippets + open_code_submenu('Snippets') + end + + def go_to_graph + open_code_submenu('Repository graph') + end + + def go_to_compare_revisions + open_code_submenu('Compare revisions') + end + + private + + def open_code_submenu(sub_menu) + open_submenu('Code', sub_menu) + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/sub_menus/super_sidebar/main.rb b/qa/qa/page/project/sub_menus/super_sidebar/main.rb new file mode 100644 index 00000000000..63641248b15 --- /dev/null +++ b/qa/qa/page/project/sub_menus/super_sidebar/main.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module SubMenus + module SuperSidebar + module Main + extend QA::Page::PageConcern + + def self.included(base) + super + + base.class_eval do + include QA::Page::SubMenus::SuperSidebar::Main + end + end + + def click_project + click_element(:nav_item_link, submenu_item: 'Project overview') + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/sub_menus/super_sidebar/monitor.rb b/qa/qa/page/project/sub_menus/super_sidebar/monitor.rb new file mode 100644 index 00000000000..745dda06bb5 --- /dev/null +++ b/qa/qa/page/project/sub_menus/super_sidebar/monitor.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module SubMenus + module SuperSidebar + module Monitor + extend QA::Page::PageConcern + + def go_to_monitor_metrics + open_monitor_submenu('Metrics') + end + + def go_to_monitor_error_tracking + open_monitor_submenu('Error tracking') + end + + def go_to_monitor_alerts + open_monitor_submenu('Alerts') + end + + def go_to_monitor_incidents + open_monitor_submenu('Incidents') + end + + def go_to_monitor_escalation_policies + open_monitor_submenu('Escalation Policies') + end + + def go_to_monitor_on_call_schedules + open_monitor_submenu('On-call Schedules') + end + + private + + def open_monitor_submenu(sub_menu) + open_submenu('Monitor', sub_menu) + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/sub_menus/super_sidebar/operate.rb b/qa/qa/page/project/sub_menus/super_sidebar/operate.rb new file mode 100644 index 00000000000..316987733ab --- /dev/null +++ b/qa/qa/page/project/sub_menus/super_sidebar/operate.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module SubMenus + module SuperSidebar + module Operate + extend QA::Page::PageConcern + + def go_to_package_registry + open_operate_submenu('Package Registry') + end + + def go_to_infrastructure_registry + open_operate_submenu('Terraform modules') + end + + def go_to_kubernetes_clusters + open_operate_submenu('Kubernetes clusters') + end + + def go_to_terraform + open_operate_submenu('Terraform') + end + + private + + def open_operate_submenu(sub_menu) + open_submenu('Operate', sub_menu) + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/sub_menus/super_sidebar/plan.rb b/qa/qa/page/project/sub_menus/super_sidebar/plan.rb new file mode 100644 index 00000000000..ca81837b2e2 --- /dev/null +++ b/qa/qa/page/project/sub_menus/super_sidebar/plan.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module SubMenus + module SuperSidebar + module Plan + def self.included(base) + super + + base.class_eval do + include QA::Page::SubMenus::SuperSidebar::Plan + end + end + + def go_to_requirements + open_plan_submenu("Requirements") + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/sub_menus/super_sidebar/secure.rb b/qa/qa/page/project/sub_menus/super_sidebar/secure.rb new file mode 100644 index 00000000000..ab1717a447a --- /dev/null +++ b/qa/qa/page/project/sub_menus/super_sidebar/secure.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module SubMenus + module SuperSidebar + module Secure + extend QA::Page::PageConcern + + def go_to_security_configuration + open_secure_submenu('Security configuration') + end + + private + + def open_secure_submenu(sub_menu) + open_submenu('Secure', sub_menu) + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/sub_menus/super_sidebar/settings.rb b/qa/qa/page/project/sub_menus/super_sidebar/settings.rb new file mode 100644 index 00000000000..3aca6cf00af --- /dev/null +++ b/qa/qa/page/project/sub_menus/super_sidebar/settings.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module SubMenus + module SuperSidebar + module Settings + extend QA::Page::PageConcern + + def self.included(base) + super + + base.class_eval do + include QA::Page::SubMenus::SuperSidebar::Settings + end + end + + def go_to_merge_request_settings + open_settings_submenu('Merge requests') + end + + def go_to_pages_settings + open_settings_submenu('Pages') + end + + def go_to_monitor_settings + open_settings_submenu('Monitor') + end + + private + + def open_settings_submenu(sub_menu) + open_submenu('Settings', sub_menu) + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/tag/show.rb b/qa/qa/page/project/tag/show.rb index 1974448a7c5..b9703f46a50 100644 --- a/qa/qa/page/project/tag/show.rb +++ b/qa/qa/page/project/tag/show.rb @@ -8,7 +8,6 @@ module QA 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) @@ -18,10 +17,6 @@ module QA 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 diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb index 975d3c8ea14..dda329ab582 100644 --- a/qa/qa/page/project/web_ide/edit.rb +++ b/qa/qa/page/project/web_ide/edit.rb @@ -111,7 +111,7 @@ module QA # Used for stablility, due to feature_caching of vscode_web_ide def wait_until_ide_loads - Support::Waiter.wait_until(sleep_interval: 2, max_duration: 60, reload_page: page, + Support::Waiter.wait_until(sleep_interval: 2, max_duration: 120, reload_page: page, retry_on_exception: true) do has_element?(:commit_mode_tab) end diff --git a/qa/qa/page/project/web_ide/vscode.rb b/qa/qa/page/project/web_ide/vscode.rb index dd5222cfd93..1a9fad56a10 100644 --- a/qa/qa/page/project/web_ide/vscode.rb +++ b/qa/qa/page/project/web_ide/vscode.rb @@ -57,7 +57,7 @@ module QA page.has_content?(folder_name) # Commit Button - page.find('a.monaco-description-button').click + page.find('a.monaco-text-button').click page.has_css?('.notification-list-item-details-row', visible: true) end end diff --git a/qa/qa/page/registration/welcome.rb b/qa/qa/page/registration/welcome.rb index 77cdbe8fd9e..4150208e7ce 100644 --- a/qa/qa/page/registration/welcome.rb +++ b/qa/qa/page/registration/welcome.rb @@ -17,7 +17,7 @@ module QA select_element(:role_dropdown, role) end - def choose_setup_for_company_if_available + def choose_setup_for_just_me_if_available # Only implemented in EE end diff --git a/qa/qa/page/sub_menus/common.rb b/qa/qa/page/sub_menus/common.rb index 518b3b4e84e..bbd886706ba 100644 --- a/qa/qa/page/sub_menus/common.rb +++ b/qa/qa/page/sub_menus/common.rb @@ -4,9 +4,7 @@ module QA module Page module SubMenus module Common - # We need to check remote_mobile_device_name instead of mobile_layout? here - # since tablets have the regular top navigation bar but still close the left nav - prepend Mobile::Page::SubMenus::Common if QA::Runtime::Env.remote_mobile_device_name + prepend Mobile::Page::SubMenus::Common if QA::Runtime::Env.mobile_layout? def hover_element(element) within_sidebar do @@ -15,38 +13,49 @@ module QA end end - def within_sidebar + def within_sidebar(&block) wait_for_requests - within_element(sidebar_element) do - yield - end + within_element(sidebar_element, &block) end - def within_submenu(element = nil) + def within_submenu(element = nil, &block) if element - within_element(element) do - yield - end + within_element(element, &block) else - within_submenu_without_element do - yield - end + within_submenu_without_element(&block) end end private - def within_submenu_without_element - if has_css?('.fly-out-list') - within('.fly-out-list') do - yield - end - else - yield + # Opens the new item menu and yields to the block + # + # @return [void] + def within_new_item_menu + click_element(:new_menu_toggle) + + yield + end + + # Implementation for super-sidebar, will replace within_submenu + # + # @param [String] parent_menu_name + # @param [String] parent_section_id + # @param [String] sub_menu + # @return [void] + def open_submenu(parent_menu_name, sub_menu) + click_element(:nav_item_link, menu_item: parent_menu_name) + + within_element(:menu_section, section: parent_menu_name) do + click_element(:nav_item_link, submenu_item: sub_menu) end end + def within_submenu_without_element(&block) + has_css?('.fly-out-list') ? within('.fly-out-list', &block) : yield + end + def sidebar_element raise NotImplementedError end diff --git a/qa/qa/page/sub_menus/create_new_menu.rb b/qa/qa/page/sub_menus/create_new_menu.rb new file mode 100644 index 00000000000..1f8641827be --- /dev/null +++ b/qa/qa/page/sub_menus/create_new_menu.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module QA + module Page + module SubMenus + module CreateNewMenu + extend QA::Page::PageConcern + + def self.prepended(base) + super + + base.class_eval do + include QA::Page::SubMenus::Common + + view 'app/helpers/sidebars_helper.rb' do + element :create_menu_item + end + end + end + + def go_to_create_project + within_new_item_menu do + click_element(:create_menu_item, create_menu_item: 'general_new_project') + end + end + + def go_to_create_snippet + within_new_item_menu do + click_element(:create_menu_item, create_menu_item: 'general_new_snippet') + end + end + + def go_to_create_group + within_new_item_menu do + click_element(:create_menu_item, create_menu_item: 'general_new_group') + end + end + end + end + end +end diff --git a/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb b/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb new file mode 100644 index 00000000000..fcfc1e1c76c --- /dev/null +++ b/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module QA + module Page + module SubMenus + module SuperSidebar + module ContextSwitcher + extend QA::Page::PageConcern + + def self.prepended(base) + super + + base.class_eval do + view 'app/assets/javascripts/super_sidebar/components/super_sidebar.vue' do + element :context_switcher + element :context_section + end + end + end + + def go_to_your_work + go_to_context("Your work") + end + + def go_to_explore + go_to_context("Explore") + end + + def go_to_admin_area + go_to_context("Admin") + end + + private + + def go_to_context(sub_menu) + click_element(:context_switcher) unless has_element?(:context_section, wait: 0) + + within_element(:context_section) do + click_element(:nav_item_link, submenu_item: sub_menu) + end + end + end + end + end + end +end diff --git a/qa/qa/page/sub_menus/super_sidebar/main.rb b/qa/qa/page/sub_menus/super_sidebar/main.rb new file mode 100644 index 00000000000..aadb24369ea --- /dev/null +++ b/qa/qa/page/sub_menus/super_sidebar/main.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module QA + module Page + module SubMenus + module SuperSidebar + module Main + extend QA::Page::PageConcern + + def go_to_issues + click_element(:nav_item_link, submenu_item: 'Issues') + end + + def go_to_merge_requests + click_element(:nav_item_link, submenu_item: 'Merge requests') + end + end + end + end + end +end diff --git a/qa/qa/page/sub_menus/super_sidebar/manage.rb b/qa/qa/page/sub_menus/super_sidebar/manage.rb new file mode 100644 index 00000000000..535b29e607f --- /dev/null +++ b/qa/qa/page/sub_menus/super_sidebar/manage.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module QA + module Page + module SubMenus + module SuperSidebar + module Manage + extend QA::Page::PageConcern + + def go_to_activity + open_manage_submenu('Activity') + end + + def go_to_members + open_manage_submenu('Members') + end + + def go_to_labels + open_manage_submenu('Labels') + end + + def go_to_milestones + open_manage_submenu('Milestones') + end + + private + + def open_manage_submenu(sub_menu) + open_submenu('Manage', sub_menu) + end + end + end + end + end +end diff --git a/qa/qa/page/sub_menus/super_sidebar/plan.rb b/qa/qa/page/sub_menus/super_sidebar/plan.rb new file mode 100644 index 00000000000..e4b9fcf099c --- /dev/null +++ b/qa/qa/page/sub_menus/super_sidebar/plan.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module QA + module Page + module SubMenus + module SuperSidebar + module Plan + extend QA::Page::PageConcern + + def go_to_issue_boards + open_plan_submenu("Issue boards") + end + + def go_to_service_desk + open_plan_submenu("Service Desk") + end + + def go_to_wiki + open_plan_submenu("Wiki") + end + + private + + def open_plan_submenu(sub_menu) + open_submenu("Plan", sub_menu) + end + end + end + end + end +end diff --git a/qa/qa/page/sub_menus/super_sidebar/settings.rb b/qa/qa/page/sub_menus/super_sidebar/settings.rb new file mode 100644 index 00000000000..910e1c2ffdf --- /dev/null +++ b/qa/qa/page/sub_menus/super_sidebar/settings.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module QA + module Page + module SubMenus + module SuperSidebar + module Settings + extend QA::Page::PageConcern + + def go_to_general_settings + open_settings_submenu('General') + end + + def go_to_integrations_settings + open_settings_submenu('Integrations') + end + + def go_to_webhooks_settings + open_settings_submenu('Webhooks') + end + + def go_to_access_token_settings + open_settings_submenu('Access Tokens') + end + + def go_to_repository_settings + open_settings_submenu('Repository') + end + + def go_to_ci_cd_settings + open_settings_submenu('CI/CD') + end + + private + + def open_settings_submenu(sub_menu) + open_submenu('Settings', sub_menu) + end + end + end + end + end +end diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb index cbb68cccdf1..3f9d2b92a0a 100644 --- a/qa/qa/resource/api_fabricator.rb +++ b/qa/qa/resource/api_fabricator.rb @@ -114,8 +114,9 @@ module QA body = flatten_hash(parse_body(graphql_response)) unless graphql_response.code == HTTP_STATUS_OK && (body[:errors].nil? || body[:errors].empty?) + action = post_body =~ /mutation {\s+destroy/ ? 'Deletion' : 'Fabrication' raise(ResourceFabricationFailedError, <<~MSG.strip) - Fabrication of #{self.class.name} using the API failed (#{graphql_response.code}) with `#{graphql_response}`. + #{action} of #{self.class.name} using the API failed (#{graphql_response.code}) with `#{graphql_response}`. #{QA::Support::Loglinking.failure_metadata(graphql_response.headers[:x_request_id])} MSG end @@ -157,17 +158,21 @@ module QA end def api_delete - request = Runtime::API::Request.new(api_client, api_delete_path) - response = delete(request.url) + if api_delete_path == "/graphql" + api_post_to(api_delete_path, api_delete_body) + else + 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, <<~MSG.strip) - Resource at #{request.mask_url} could not be deleted (#{response.code}): `#{response}`. - #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])} - MSG - end + unless [HTTP_STATUS_NO_CONTENT, HTTP_STATUS_ACCEPTED].include? response.code + raise(ResourceNotDeletedError, <<~MSG.strip) + Resource at #{request.mask_url} could not be deleted (#{response.code}): `#{response}`. + #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])} + MSG + end - response + response + end end def resource_web_url(resource) diff --git a/qa/qa/resource/ci_variable.rb b/qa/qa/resource/ci_variable.rb index b632446623d..4123b8fe62b 100644 --- a/qa/qa/resource/ci_variable.rb +++ b/qa/qa/resource/ci_variable.rb @@ -18,19 +18,6 @@ module QA @variable_type = 'env_var' end - def fabricate! - project.visit! - - Page::Project::Menu.perform(&:go_to_ci_cd_settings) - - Page::Project::Settings::CiCd.perform do |setting| - setting.expand_ci_variables do |page| - page.click_add_variable - page.fill_variable(key, value, masked) - end - end - end - def fabricate_via_api! resource_web_url(api_get) rescue ResourceNotFoundError diff --git a/qa/qa/resource/events/project.rb b/qa/qa/resource/events/project.rb index 410edd417c1..c1bd921c3cf 100644 --- a/qa/qa/resource/events/project.rb +++ b/qa/qa/resource/events/project.rb @@ -7,32 +7,32 @@ module QA include Events::Base def push_events(commit_message) - QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait for and fetch push events"]) + QA::Runtime::Logger.info(%Q[#{self.class.name} - wait for and fetch push events"]) fetch_events do events(action: 'pushed').select { |event| event.dig(:push_data, :commit_title) == commit_message } end end def wait_for_merge(title) - QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait_for_merge with title "#{title}"]) + QA::Runtime::Logger.info(%Q[#{self.class.name} - wait_for_merge with title "#{title}"]) wait_for_event do events(action: 'accepted', target_type: 'merge_request').any? { |event| event[:target_title] == title } end end def wait_for_push(commit_message) - QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait_for_push with commit message "#{commit_message}"]) + QA::Runtime::Logger.info(%Q[#{self.class.name} - wait_for_push with commit message "#{commit_message}"]) wait_for_event do events(action: 'pushed').any? { |event| event.dig(:push_data, :commit_title) == commit_message } end rescue EventNotFoundError - QA::Runtime::Logger.debug("Push events: #{events(action: 'pushed')}") + QA::Runtime::Logger.info("Push events: #{events(action: 'pushed')}") raise end def wait_for_push_new_branch(branch_name = self.default_branch) - QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait_for_push_new_branch with branch_name "#{branch_name}"]) + QA::Runtime::Logger.info(%Q[#{self.class.name} - wait_for_push_new_branch with branch_name "#{branch_name}"]) wait_for_event do events(action: 'pushed').any? { |event| event.dig(:push_data, :ref) == branch_name } end diff --git a/qa/qa/resource/group.rb b/qa/qa/resource/group.rb index f53bb531d9a..c88cf4aca10 100644 --- a/qa/qa/resource/group.rb +++ b/qa/qa/resource/group.rb @@ -57,6 +57,10 @@ module QA sandbox.visit! end + unless group_show.has_subgroup?(path) + raise ResourceFabricationFailedError, "Resource at #{path} could not be found under #{sandbox.path}" + end + group_show.click_subgroup(path) @id = group_show.group_id end diff --git a/qa/qa/resource/instance_oauth_application.rb b/qa/qa/resource/instance_oauth_application.rb new file mode 100644 index 00000000000..7aa3661717b --- /dev/null +++ b/qa/qa/resource/instance_oauth_application.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module QA + module Resource + class InstanceOauthApplication < Base + attr_accessor :name, :redirect_uri, :scopes, :trusted + + attributes :id, :application_id, :application_secret + + def initialize + @name = "Instance OAuth Application #{SecureRandom.hex(8)}" + @redirect_uri = '' + @scopes = [] + @trusted = true + end + + def resource_web_url(resource) + super + rescue ResourceURLMissingError + # this particular resource does not expose a web_url property + end + + def api_get_path + '/applications' + end + + def api_delete_path + "/applications/#{id}" + end + + def fabricate! + Flow::Login.sign_in_as_admin + Page::Main::Menu.perform(&:go_to_admin_area) + Page::Admin::Menu.perform(&:go_to_applications) + Page::Admin::Applications.perform do |app| + app.click_new_application_button + app.fill_name(name) + app.fill_redirect_uri(redirect_uri) + app.set_trusted_checkbox(trusted) + scopes.each { |scope| app.set_scope(scope) } + app.save_application + self.application_id = app.get_application_id + self.application_secret = app.get_secret_id + self.id = app.get_id_of_application + end + end + end + end +end diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb index 15c2c25757f..fb957ccf285 100644 --- a/qa/qa/resource/issue.rb +++ b/qa/qa/resource/issue.rb @@ -30,7 +30,7 @@ module QA def fabricate! project.visit! - Page::Project::Show.perform(&:go_to_new_issue) + Page::Project::Menu.perform(&:go_to_new_issue) Page::Project::Issue::New.perform do |new_page| new_page.fill_title(@title) diff --git a/qa/qa/resource/pipeline.rb b/qa/qa/resource/pipeline.rb index 7d5036c5cf4..e57784ca3b5 100644 --- a/qa/qa/resource/pipeline.rb +++ b/qa/qa/resource/pipeline.rb @@ -28,7 +28,7 @@ module QA def fabricate! project.visit! - Page::Project::Menu.perform(&:click_ci_cd_pipelines) + Page::Project::Menu.perform(&:go_to_pipelines) Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button) Page::Project::Pipeline::New.perform(&:click_run_pipeline_button) end diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb index 019617325e0..37ff2315329 100644 --- a/qa/qa/resource/project.rb +++ b/qa/qa/resource/project.rb @@ -123,12 +123,13 @@ module QA resource_web_url(api_get) rescue ResourceNotFoundError response = super + return response unless template_name || import # If a project is being imported, wait until it completes before we let the test continue. # Otherwise we see Git repository errors # See https://gitlab.com/gitlab-org/gitlab/-/issues/356101 - Support::Retrier.retry_until(max_duration: 60, sleep_interval: 5) do - %w[none finished].include?(reload!.api_resource[:import_status]) + Support::Retrier.retry_until(max_duration: 60, sleep_interval: 5, retry_on_exception: true) do + reload!.api_resource[:import_status] == "finished" end response diff --git a/qa/qa/resource/project_imported_from_github.rb b/qa/qa/resource/project_imported_from_github.rb index 1e6b2ff620e..ed8074b1440 100644 --- a/qa/qa/resource/project_imported_from_github.rb +++ b/qa/qa/resource/project_imported_from_github.rb @@ -3,7 +3,7 @@ module QA module Resource class ProjectImportedFromGithub < Resource::Project - attr_accessor :issue_events_import, :full_notes_import, :attachments_import + attr_accessor :issue_events_import, :full_notes_import, :attachments_import, :allow_partial_import attribute :github_repo_id do github_client.repository(github_repository_path).id @@ -24,7 +24,7 @@ module QA import_page.select_advanced_option(:attachments_import) if attachments_import import_page.import!(github_repository_path, group.full_path, name) - import_page.wait_for_success(github_repository_path, wait: 240) + import_page.wait_for_success(github_repository_path, wait: 240, allow_partial_import: allow_partial_import) end reload! diff --git a/qa/qa/resource/runner_base.rb b/qa/qa/resource/runner_base.rb index 9e38ba9ab64..278729eb50f 100644 --- a/qa/qa/resource/runner_base.rb +++ b/qa/qa/resource/runner_base.rb @@ -36,7 +36,8 @@ module QA @run_untagged = nil @name = "qa-runner-#{SecureRandom.hex(4)}" @executor = :shell - @executor_image = 'registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7' + @executor_image = "#{QA::Runtime::Env.container_registry_host}/ + gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7" end # Initially we only support fabricate via API diff --git a/qa/qa/resource/snippet.rb b/qa/qa/resource/snippet.rb index 84711075442..df9843bcfca 100644 --- a/qa/qa/resource/snippet.rb +++ b/qa/qa/resource/snippet.rb @@ -22,9 +22,7 @@ module QA end def fabricate! - Page::Main::Menu.perform(&:go_to_snippets) - - Page::Dashboard::Snippet::Index.perform(&:go_to_new_snippet_page) + Page::Main::Menu.perform(&:go_to_create_snippet) Page::Dashboard::Snippet::New.perform do |new_page| new_page.fill_title(@title) diff --git a/qa/qa/runtime/application_settings.rb b/qa/qa/runtime/application_settings.rb index 53ed6a9266b..4cbce0972b6 100644 --- a/qa/qa/runtime/application_settings.rb +++ b/qa/qa/runtime/application_settings.rb @@ -22,7 +22,8 @@ module QA r = put(Runtime::API::Request.new(api_client, APPLICATION_SETTINGS_PATH).url, **application_settings) return if r.code == QA::Support::API::HTTP_STATUS_OK - raise "Couldn't set application settings #{application_settings.inspect}" + body = parse_body(r) + raise("Couldn't set application settings #{application_settings.inspect}, code: '#{r.code}', body: #{body}") end def get_application_settings(api_client: admin_api_client) diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index 945823fb9c0..b67db792419 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -17,6 +17,9 @@ module QA NotRespondingError = Class.new(RuntimeError) CAPYBARA_MAX_WAIT_TIME = Env.max_capybara_wait_time + DEFAULT_WINDOW_SIZE = '1480,2200' + PHONE_VIDEO_SIZE = '500x900' + TABLET_VIDEO_SIZE = '800x1100' def self.blank_page? ['', 'about:blank', 'data:,'].include?(Capybara.current_session.driver.browser.current_url) @@ -96,11 +99,14 @@ module QA capabilities['goog:chromeOptions'][:args] << 'disable-dev-shm-usage' if QA::Runtime::Env.disable_dev_shm? # Set chrome default download path - - capabilities['goog:chromeOptions'][:prefs] = { - 'download.default_directory' => File.expand_path(QA::Runtime::Env.chrome_default_download_path), - 'download.prompt_for_download' => false - } + # TODO: Set for remote grid as well once Sauce Labs tests are deprecated and Options.chrome is added + # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112258 + unless QA::Runtime::Env.remote_grid + capabilities['goog:chromeOptions'][:prefs] = { + 'download.default_directory' => File.expand_path(QA::Runtime::Env.chrome_default_download_path), + 'download.prompt_for_download' => false + } + end # Specify the user-agent to allow challenges to be bypassed # See https://gitlab.com/gitlab-com/gl-infra/infrastructure/-/issues/11938 @@ -114,7 +120,7 @@ module QA capabilities['appium:deviceName'] = QA::Runtime::Env.remote_mobile_device_name capabilities['appium:platformVersion'] = 'latest' else - capabilities['goog:chromeOptions'][:args] << 'window-size=1480,2200' + capabilities['goog:chromeOptions'][:args] << "window-size=#{DEFAULT_WINDOW_SIZE}" end # Slack tries to open an external URL handler @@ -159,6 +165,9 @@ module QA when :firefox capabilities['acceptInsecureCerts'] = true if QA::Runtime::Env.accept_insecure_certs? + + when :edge + capabilities['ms:edgeOptions'] = { args: ["--window-size=#{DEFAULT_WINDOW_SIZE}"] } end # Use the same profile on QA runs if CHROME_REUSE_PROFILE is true. @@ -174,10 +183,21 @@ module QA if QA::Runtime::Env.remote_grid selenium_options[:browser] = :remote selenium_options[:url] = QA::Runtime::Env.remote_grid - capabilities[:browserVersion] = 'latest' + capabilities[:browserVersion] = QA::Runtime::Env.browser_version + end + + if QA::Runtime::Env.remote_tunnel_id capabilities['sauce:options'] = { tunnelIdentifier: QA::Runtime::Env.remote_tunnel_id } end + if QA::Runtime::Env.record_video? + capabilities['selenoid:options'] = { + enableVideo: true, + videoScreenSize: video_screen_size, + videoName: "#{QA::Runtime::Env.browser}-#{QA::Runtime::Env.browser_version}-#{Time.now}.mp4" + } + end + Capybara::Selenium::Driver.new( app, **selenium_options @@ -233,6 +253,16 @@ module QA ::File.expand_path('../../tmp/qa-profile', __dir__) end + def self.video_screen_size + if QA::Runtime::Env.phone_layout? + PHONE_VIDEO_SIZE + elsif QA::Runtime::Env.tablet_layout? + TABLET_VIDEO_SIZE + else + '' + end + end + class Session include Capybara::DSL diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index 810912c7ccf..cde36ba80c4 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -58,6 +58,22 @@ module QA browser == :chrome && interception_enabled? end + def release + ENV['RELEASE'] + end + + def release_registry_url + ENV['RELEASE_REGISTRY_URL'] + end + + def release_registry_username + ENV['RELEASE_REGISTRY_USERNAME'] + end + + def release_registry_password + ENV['RELEASE_REGISTRY_PASSWORD'] + end + def ci_job_url ENV['CI_JOB_URL'] end @@ -187,14 +203,38 @@ module QA ENV['QA_BROWSER'].nil? ? :chrome : ENV['QA_BROWSER'].to_sym end + def browser_version + ENV['QA_BROWSER_VERSION'] || 'latest' + end + def remote_mobile_device_name - ENV['QA_REMOTE_MOBILE_DEVICE_NAME'] + ENV['QA_REMOTE_MOBILE_DEVICE_NAME']&.downcase + end + + def layout + ENV['QA_LAYOUT']&.downcase || '' + end + + def tablet_layout? + return true if remote_mobile_device_name && !phone_layout? + + layout.include?('tablet') + end + + def phone_layout? + return true if layout.include?('phone') + + return false unless remote_mobile_device_name + + !(remote_mobile_device_name.include?('ipad') || remote_mobile_device_name.include?('tablet')) end def mobile_layout? - return false if ENV['QA_REMOTE_MOBILE_DEVICE_NAME'].blank? + phone_layout? || tablet_layout? || remote_mobile_device_name + end - !(ENV['QA_REMOTE_MOBILE_DEVICE_NAME'].downcase.include?('ipad') || ENV['QA_REMOTE_MOBILE_DEVICE_NAME'].downcase.include?('tablet')) + def record_video? + enabled?(ENV['QA_RECORD_VIDEO'], default: false) end def user_username @@ -210,11 +250,11 @@ module QA end def github_username - ENV['GITHUB_USERNAME'] + ENV['QA_GITHUB_USERNAME'] end def github_password - ENV['GITHUB_PASSWORD'] + ENV['QA_GITHUB_PASSWORD'] end def forker? @@ -282,11 +322,11 @@ module QA end def jira_admin_username - ENV['JIRA_ADMIN_USERNAME'] + ENV['QA_JIRA_ADMIN_USERNAME'] end def jira_admin_password - ENV['JIRA_ADMIN_PASSWORD'] + ENV['QA_JIRA_ADMIN_PASSWORD'] end def jira_hostname @@ -489,6 +529,10 @@ module QA enabled?(ENV['QA_SKIP_SMOKE_RELIABLE'], default: false) end + def container_registry_host + ENV.fetch('QA_CONTAINER_REGISTRY_HOST', 'registry.gitlab.com') + end + # ENV variables for authenticating against a private container registry # These need to be set if using the # Service::DockerRun::Mixins::ThirdPartyDocker module @@ -537,6 +581,22 @@ module QA raise "Missing Slack env: #{missing_env.map(&:upcase).join(', ')}" end + def one_p_email + ENV['QA_1P_EMAIL'] + end + + def one_p_password + ENV['QA_1P_PASSWORD'] + end + + def one_p_secret + ENV['QA_1P_SECRET'] + end + + def one_p_github_uuid + ENV['QA_1P_GITHUB_UUID'] + end + private def remote_grid_credentials diff --git a/qa/qa/service/docker_run/base.rb b/qa/qa/service/docker_run/base.rb index bf85b640586..ce558849abd 100644 --- a/qa/qa/service/docker_run/base.rb +++ b/qa/qa/service/docker_run/base.rb @@ -85,6 +85,10 @@ module QA shell "docker restart #{@name}" end + + def health + shell("docker inspect --format='{{json .State.Health.Status}}' #{@name}").delete('"') + end end end end diff --git a/qa/qa/service/docker_run/gitlab.rb b/qa/qa/service/docker_run/gitlab.rb new file mode 100644 index 00000000000..4fbe6603d5b --- /dev/null +++ b/qa/qa/service/docker_run/gitlab.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module QA + module Service + module DockerRun + class Gitlab < Base + def initialize(name:, omnibus_config: '', image: '') + @image = image + @name = name + @omnibus_configuration = omnibus_config + super() + end + + def login + super(Runtime::Env.release_registry_url, + user: Runtime::Env.release_registry_username, + password: Runtime::Env.release_registry_password) + end + + def register! + shell <<~CMD.tr("\n", ' ') + docker run -d --rm + --network #{network} + --hostname #{host_name} + --publish 80:80 + #{RUBY_PLATFORM.include?('arm64') ? '--platform linux/amd64' : ''} + --env GITLAB_OMNIBUS_CONFIG="#{@omnibus_configuration}" + --name #{@name} + #{@image} + CMD + end + end + end + end +end diff --git a/qa/qa/service/docker_run/gitlab_runner.rb b/qa/qa/service/docker_run/gitlab_runner.rb index d40517ae535..078a3048cad 100644 --- a/qa/qa/service/docker_run/gitlab_runner.rb +++ b/qa/qa/service/docker_run/gitlab_runner.rb @@ -16,11 +16,12 @@ module QA MSG def initialize(name) - @image = 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine' + @image = "#{QA::Runtime::Env.container_registry_host}/gitlab-org/gitlab-runner:alpine" @name = name || "qa-runner-#{SecureRandom.hex(4)}" @run_untagged = true @executor = :shell - @executor_image = 'registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7' + @executor_image = "#{QA::Runtime::Env.container_registry_host}/ + gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7" super() end @@ -104,7 +105,15 @@ module QA # Ping Cloudflare DNS, should fail # Ping Registry, should fail to resolve def prove_airgap - gitlab_ip = Resolv.getaddress 'registry.gitlab.com' + begin + gitlab_ip = Resolv.getaddress 'registry.gitlab.com' + rescue Resolv::ResolvError => e + Runtime::Logger.debug("prove_airgap unable to get ip address for endpoint - #{e.message}") + # If Resolv.getaddress fails, it implies we cannot access the URL in question + # This may occur in offline-environment/airgapped testing + return 'true' + end + <<~CMD echo "Checking airgapped connectivity..." nc -zv -w 10 #{gitlab_ip} 80 && (echo "Airgapped network faulty. Connectivity netcat check failed." && exit 1) || (echo "Connectivity netcat check passed." && exit 0) diff --git a/qa/qa/service/docker_run/k3s.rb b/qa/qa/service/docker_run/k3s.rb index a09b62cb613..f2463c39639 100644 --- a/qa/qa/service/docker_run/k3s.rb +++ b/qa/qa/service/docker_run/k3s.rb @@ -7,7 +7,8 @@ module QA attr_accessor :cni_enabled def initialize - @image = 'registry.gitlab.com/gitlab-org/cluster-integration/test-utils/k3s-gitlab-ci/releases/v0.9.1' + @image = "#{QA::Runtime::Env.container_registry_host}/ + gitlab-org/cluster-integration/test-utils/k3s-gitlab-ci/releases/v0.9.1" @name = 'k3s' @cni_enabled = false super diff --git a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb index e0db758dde3..fc400fbb9c7 100644 --- a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb +++ b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb @@ -26,6 +26,9 @@ module QA file.name = "text-#{SecureRandom.hex(8)}.txt" file.content = 'New file' end + rescue StandardError => e + QA::Runtime::Logger.error("Full failure message: #{e.message}") + raise end.not_to raise_error end @@ -42,6 +45,9 @@ module QA commit.commit_message = 'Add new file' commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }]) end + rescue StandardError => e + QA::Runtime::Logger.error("Full failure message: #{e.message}") + raise end.not_to raise_error end end diff --git a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb index 407e479bda2..ed26061f3f8 100644 --- a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb +++ b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb @@ -1,7 +1,11 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', product_group: :import do + RSpec.describe 'Manage', product_group: :import, + quarantine: { + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/407297', + type: :investigating + } do describe 'GitHub import' do include_context 'with github import' diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb index 43701a6b740..040c92f296f 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb @@ -6,19 +6,19 @@ module QA include_context 'with gitlab project migration' # this spec is used as a sanity test for gitlab migration because it can run outside of orchestrated setup - context 'with import within same instance', :reliable, orchestrated: false, import: false do + context 'with import within same instance', orchestrated: false, import: false do let!(:source_project_with_readme) { true } let!(:source_gitlab_address) { Runtime::Scenario.gitlab_address } let!(:source_admin_api_client) { admin_api_client } + # do not use top level group (sandbox) to avoid issues when applying permissions etc. because it will contain + # a lot subgroups and projects on live envs let!(:source_sandbox) do - Resource::Sandbox.fabricate_via_api! do |group| + Resource::Group.fabricate_via_api! do |group| group.api_client = admin_api_client end end - let!(:target_sandbox) { source_sandbox } - let!(:source_group) do Resource::Group.fabricate_via_api! do |group| group.api_client = admin_api_client @@ -28,6 +28,8 @@ module QA end end + let!(:target_sandbox) { source_sandbox } + let(:destination_group_path) { "target-group-for-import-#{SecureRandom.hex(4)}" } let(:cleanup!) { user.remove_via_api! } diff --git a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb index d693bbd43ff..eeeb78e17d7 100644 --- a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb +++ b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb @@ -24,6 +24,9 @@ module QA file.name = "text-#{SecureRandom.hex(8)}.txt" file.content = 'New file' end + rescue StandardError => e + QA::Runtime::Logger.error("Full failure message: #{e.message}") + raise end.not_to raise_error end @@ -37,6 +40,9 @@ module QA commit.commit_message = 'Add new file' commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }]) end + rescue StandardError => e + QA::Runtime::Logger.error("Full failure message: #{e.message}") + raise end.not_to raise_error end end diff --git a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb b/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb index b7d0d72297a..8759c36f43f 100644 --- a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb +++ b/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb @@ -2,7 +2,8 @@ module QA RSpec.describe 'Manage' do - describe 'User', :requires_admin, :reliable, product_group: :authentication_and_authorization do + # TODO: `:reliable` should be added back once https://gitlab.com/gitlab-org/gitlab/-/issues/359278 is resolved + describe 'User', :requires_admin, product_group: :authentication_and_authorization do before(:all) do admin_api_client = Runtime::API::Client.as_admin @@ -12,14 +13,20 @@ module QA @user_api_client = Runtime::API::Client.new(:gitlab, user: @user) - @group = QA::Resource::Group.fabricate_via_api! do |group| + @sandbox = Resource::Sandbox.fabricate! do |sandbox_group| + sandbox_group.path = "sandbox-for-access-termination-#{SecureRandom.hex(4)}" + sandbox_group.api_client = admin_api_client + end + + group = QA::Resource::Group.fabricate_via_api! do |group| group.path = "group-to-test-access-termination-#{SecureRandom.hex(8)}" + group.sandbox = @sandbox end - @group.sandbox.add_member(@user) + @sandbox.add_member(@user) @project = Resource::Project.fabricate_via_api! do |project| - project.group = @group + project.group = group project.name = "project-for-user-group-access-termination" project.initialize_with_readme = true end @@ -27,7 +34,7 @@ module QA context 'after parent group membership termination' do before do - @group.sandbox.remove_member(@user) + @sandbox.remove_member(@user) end it 'is not allowed to push code via the CLI', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347863' do @@ -77,9 +84,7 @@ module QA end after(:all) do - @user.remove_via_api! - @project.remove_via_api! - @group.remove_via_api! + @sandbox.remove_via_api! end end end diff --git a/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb b/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb index c50eb2f4fdf..48e9d3dc164 100644 --- a/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb +++ b/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'User', :requires_admin, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'User', :requires_admin, product_group: :tenant_scale do let(:admin_api_client) { Runtime::API::Client.as_admin } let!(:parent_group) do @@ -41,6 +41,10 @@ module QA parent_group.add_member(parent_group_user) end + after do + parent_group_user.remove_via_api! + end + it( 'is allowed to push code to sub-group project via the CLI', :reliable, @@ -98,10 +102,6 @@ module QA end.not_to raise_error end end - - after do - parent_group_user.remove_via_api! - end end context 'when added to sub-group' do @@ -127,6 +127,10 @@ module QA sub_group.add_member(sub_group_user) end + after do + sub_group_user.remove_via_api! + end + it( 'is not allowed to push code to parent group project via the CLI', :reliable, @@ -177,10 +181,6 @@ module QA end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden - You are not allowed to push into this branch/) end - - after do - sub_group_user.remove_via_api! - end end end end diff --git a/qa/qa/specs/features/api/1_manage/users_spec.rb b/qa/qa/specs/features/api/9_data_stores/users_spec.rb index 08e1b7a1e0c..4be20bd1932 100644 --- a/qa/qa/specs/features/api/1_manage/users_spec.rb +++ b/qa/qa/specs/features/api/9_data_stores/users_spec.rb @@ -3,8 +3,8 @@ require 'airborne' module QA - RSpec.describe 'Manage' do - describe 'Users API', :reliable, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'Users API', :reliable, product_group: :tenant_scale do let(:api_client) { Runtime::API::Client.new(:gitlab) } let(:request) { Runtime::API::Request.new(api_client, '/users') } @@ -14,7 +14,8 @@ module QA expect_status(200) end - it 'GET /users/:username with a valid username', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347886' do + it 'GET /users/:username with a valid username', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347886' do get request.url, { params: { username: Runtime::User.username } } expect_status(200) @@ -23,7 +24,8 @@ module QA ) end - it 'GET /users/:username with an invalid username', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347883' do + it 'GET /users/:username with an invalid username', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347883' do get request.url, { params: { username: SecureRandom.hex(10) } } expect_status(200) diff --git a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb index b5a8df15ddc..d92d8de5567 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb @@ -37,7 +37,11 @@ module QA end end - it 'imports a project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347877' do + it 'imports a project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347877', + quarantine: { + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/405127', + type: :investigating + } do Page::Project::Import::Github.perform do |import_page| import_page.add_personal_access_token(Runtime::Env.github_access_token) diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_issue_import_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_issue_import_spec.rb index 7e46276be92..f4042795995 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_issue_import_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_issue_import_spec.rb @@ -18,14 +18,12 @@ module QA 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 + Page::Project::Menu.perform(&:go_to_issues) + Page::Project::Issue::Index.perform do |issues_page| + expect { issues_page }.to eventually_have_content(jira_issue_title).within( + max_attempts: 5, sleep_interval: 1, reload_page: issues_page + ) + issues_page.click_issue_link(jira_issue_title) end expect(page).to have_content(jira_issue_description) @@ -58,7 +56,7 @@ module QA end def import_jira_issues - Page::Project::Menu.perform(&:click_issues) + Page::Project::Menu.perform(&:go_to_issues) Page::Project::Issue::Index.perform(&:go_to_jira_import_form) Page::Project::Issue::JiraImport.perform do |form| diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oidc_with_gitlab_as_idp_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oidc_with_gitlab_as_idp_spec.rb new file mode 100644 index 00000000000..268bd6fdbf0 --- /dev/null +++ b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oidc_with_gitlab_as_idp_spec.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Manage', :skip_live_env, requires_admin: 'creates users and instance OAuth application', + product_group: :authentication_and_authorization do + let!(:user) { Resource::User.fabricate_via_api! } + let(:oidc_consumer_name) { 'gitlab-oidc-consumer' } + let(:oidc_consumer_host) { "http://#{oidc_consumer_name}.#{Runtime::Env.running_in_ci? ? 'test' : 'bridge'}" } + let(:instance_oauth_app) do + Resource::InstanceOauthApplication.fabricate! do |application| + application.redirect_uri = "#{oidc_consumer_host}/users/auth/openid_connect/callback" + application.scopes = %w[openid profile email] + end + end + + after do + instance_oauth_app.remove_via_api! + remove_gitlab_service(oidc_consumer_name) + end + + # The host GitLab instance with address Runtime::Scenario.gitlab_address is the OIDC idP - OIDC application will be + # created here. + # GitLab instance stood up in docker with address gitlab-oidc-consumer.test (or gitlab-oidc-consumer.bridge) is + # the consumer - The GitLab OIDC Login button will be displayed here. + describe 'OIDC' do + it( + 'creates GitLab OIDC application and uses it to login', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/405137' + ) do + instance_oauth_app + + Page::Main::Menu.perform(&:sign_out_if_signed_in) + + app_id = instance_oauth_app.application_id + app_secret = instance_oauth_app.application_secret + + consumer_gitlab_service = run_gitlab_service(name: oidc_consumer_name, app_id: app_id, app_secret: app_secret) + + wait_for_service(consumer_gitlab_service) + + page.visit oidc_consumer_host + + expect(page.driver.current_url).to include(oidc_consumer_host) + + Page::Main::Login.perform(&:sign_in_with_oidc) + + expect(page.driver.current_url).to include(Runtime::Scenario.gitlab_address) + + Flow::Login.sign_in(as: user) + + expect(page.driver.current_url).to include(oidc_consumer_host) + + Page::Dashboard::Welcome.perform do |welcome| + expect(welcome).to have_welcome_title("Welcome to GitLab") + end + end + + def run_gitlab_service(name:, app_id:, app_secret:) + Service::DockerRun::Gitlab.new( + image: Runtime::Env.release, + name: name, + omnibus_config: omnibus_configuration(app_id: app_id, app_secret: app_secret)).tap do |gitlab| + gitlab.login + gitlab.pull + gitlab.register! + end + end + + def remove_gitlab_service(name) + Service::DockerRun::Gitlab.new(name: name).remove! + end + + def wait_for_service(service) + Support::Waiter.wait_until(max_duration: 900, sleep_interval: 5, raise_on_failure: true) do + service.health == "healthy" + end + end + + def omnibus_configuration(app_id:, app_secret:) + <<~OMNIBUS + gitlab_rails['initial_root_password']='5iveL\!fe'; + gitlab_rails['omniauth_enabled'] = true; + gitlab_rails['omniauth_allow_single_sign_on'] = true; + gitlab_rails['omniauth_block_auto_created_users'] = false; + gitlab_rails['omniauth_providers'] = [ + { + name: 'openid_connect', + label: 'GitLab OIDC', + args: { + name: 'openid_connect', + scope: ['openid','profile','email'], + response_type: 'code', + issuer: '#{Runtime::Scenario.gitlab_address}', + discovery: false, + uid_field: 'preferred_username', + send_scope_to_token_endpoint: 'false', + client_options: { + identifier: '#{app_id}', + secret: '#{app_secret}', + redirect_uri: '#{oidc_consumer_host}/users/auth/openid_connect/callback', + jwks_uri: '#{Runtime::Scenario.gitlab_address}/oauth/discovery/keys', + userinfo_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/userinfo', + token_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/token', + authorization_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/authorize' + } + } + } + ]; + OMNIBUS + end + end + end +end diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/oauth_login_with_github_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/oauth_login_with_github_spec.rb new file mode 100644 index 00000000000..3ac050c1649 --- /dev/null +++ b/qa/qa/specs/features/browser_ui/1_manage/login/oauth_login_with_github_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Manage', :orchestrated, :oauth, product_group: :authentication_and_authorization do + describe 'OAuth' do + it 'connects and logs in with GitHub OAuth', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/402405' do + Runtime::Browser.visit(:gitlab, Page::Main::Login) + + Page::Main::Login.perform(&:sign_in_with_github) + + Vendor::Github::Page::Login.perform(&:login) + + expect(page).to have_content('Welcome to GitLab') + 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 e2fd0ec9cef..821f885c4c8 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 @@ -26,7 +26,7 @@ module QA ) do issue = Resource::Issue.fabricate_via_browser_ui! { |issue| issue.project = project } - Page::Project::Menu.perform(&:click_issues) + Page::Project::Menu.perform(&:go_to_issues) Page::Project::Issue::Index.perform do |index| expect(index).to have_issue(issue) @@ -46,7 +46,7 @@ module QA expect(issue_page).to have_reopen_issue_button end - Page::Project::Menu.perform(&:click_issues) + Page::Project::Menu.perform(&:go_to_issues) Page::Project::Issue::Index.perform do |index| expect(index).not_to have_issue(closed_issue) 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 61fd743f920..275f3a52f17 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 @@ -19,7 +19,7 @@ module QA end project.visit! - Page::Project::Menu.perform(&:click_issues) + Page::Project::Menu.perform(&:go_to_issues) end it 'successfully exports issues list as CSV', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347968' do 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 45541939606..c85ea5e8a69 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 @@ -14,7 +14,7 @@ module QA end it 'shows issue suggestions when creating a new issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347995' do - Page::Project::Show.perform(&:go_to_new_issue) + Page::Project::Menu.perform(&:go_to_new_issue) Page::Project::Issue::New.perform do |new_page| new_page.fill_title("issue") expect(new_page).to have_content(issue_title) 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 83e178ae4c3..7377b0ff8af 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 @@ -16,7 +16,7 @@ module QA it 'focuses on issue board', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347996' do project.visit! - Page::Project::Menu.perform(&:go_to_boards) + Page::Project::Menu.perform(&:go_to_issue_boards) Page::Component::IssueBoard::Show.perform do |show| show.click_focus_mode_button 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 d27ec32fdda..56e1f3d4a9a 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 @@ -17,11 +17,7 @@ module QA merge_request.fork.remove_via_api! end - it 'can merge feature branch fork to mainline', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347818', quarantine: { - only: :production, - type: :investigating, - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/372258' - } do + it 'can merge source branch from fork into upstream repository', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347818' do merge_request.visit! Page::MergeRequest::Show.perform do |merge_request| diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb index 1b82543a5d4..38831f6f158 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb @@ -50,7 +50,10 @@ module QA runner&.remove_via_api! end - it 'merges after pipeline succeeds' do + it 'merges after pipeline succeeds', quarantine: { + type: :flaky, + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/403017' + } do transient_test = repeat > 1 repeat.times do |i| 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 a969b48f0fc..748b989deb8 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 @@ -15,7 +15,7 @@ module QA merge_request.visit! end - it 'views the merge request email patches', :can_use_large_setup, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347742' do + it 'views the merge request patches', :can_use_large_setup, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347742' do Page::MergeRequest::Show.perform(&:view_email_patches) expect(page.text).to start_with('From') diff --git a/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb b/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb index a214af19fca..7dc9e95bcd2 100644 --- a/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb @@ -2,15 +2,14 @@ module QA RSpec.describe 'Create', - :gitlab_pages, - :orchestrated, - except: { job: 'review-qa-*' }, - quarantine: { - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/383215', - type: :test_environment, - only: { subdomain: 'staging-ref' } - }, - feature_flag: { name: 'show_pages_in_deployments_menu' } do + :gitlab_pages, + :orchestrated, + except: { job: 'review-qa-*' }, + quarantine: { + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/383215', + type: :flaky + }, + feature_flag: { name: 'show_pages_in_deployments_menu' } do # TODO: Convert back to :smoke once proved to be stable. Related issue: https://gitlab.com/gitlab-org/gitlab/-/issues/300906 describe 'Pages', product_group: :editor do let!(:project) do @@ -23,9 +22,10 @@ module QA let(:pipeline) do Resource::Pipeline.fabricate_via_api! do |pipeline| pipeline.project = project - pipeline.variables = + pipeline.variables = [ { key: :CI_PAGES_DOMAIN, value: 'nip.io', variable_type: :env_var }, { key: :CI_PAGES_URL, value: 'http://127.0.0.1.nip.io', variable_type: :env_var } + ] end end @@ -46,7 +46,7 @@ module QA end it 'creates a Pages website', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347669' do + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347669' do Page::Project::Pipeline::Show.perform do |show| expect(show).to have_job(:pages) show.click_job(:pages) @@ -56,14 +56,18 @@ module QA expect(show).to have_passed(timeout: 300) end - Page::Project::Show.perform(&:go_to_pages_settings) - QA::Page::Project::Settings::Pages.perform do |pages| - pages.go_to_access_page - Support::Waiter.wait_until(sleep_interval: 2, max_duration: 60, reload_page: page, - retry_on_exception: true) do - expect(page).to have_content( - 'This is a simple plain-HTML website on GitLab Pages, without any fancy static site generator.') - end + Page::Project::Menu.perform(&:go_to_pages_settings) + Page::Project::Settings::Pages.perform(&:go_to_access_page) + + Support::Waiter.wait_until( + sleep_interval: 2, + max_duration: 60, + reload_page: page, + retry_on_exception: true + ) do + expect(page).to have_content( + 'This is a simple plain-HTML website on GitLab Pages, without any fancy static site generator.' + ) end end end diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb new file mode 100644 index 00000000000..3d68de30d57 --- /dev/null +++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Create' do + describe 'Branch Rules Overview', product_group: :source_code, + feature_flag: { + name: 'branch_rules', + scope: :project + }, + quarantine: { + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/403583', + type: :flaky + } do + let(:branch_name) { 'new-branch' } + let(:allowed_to_push_role) { Resource::ProtectedBranch::Roles::NO_ONE } + let(:allowed_to_merge_role) { Resource::ProtectedBranch::Roles::MAINTAINERS } + let(:project) do + Resource::Project.fabricate_via_api! do |project| + project.name = 'branch-rule-project' + project.initialize_with_readme = true + end + end + + before do + Runtime::Feature.enable(:branch_rules, project: project) + + Flow::Login.sign_in + + Resource::Repository::Commit.fabricate_via_api! do |commit| + commit.project = project + commit.branch = branch_name + commit.start_branch = project.default_branch + commit.commit_message = 'First commit' + commit.add_files([{ file_path: 'new_file.rb', content: '# new content' }]) + end + end + + after do + Runtime::Feature.disable(:branch_rules, project: project) + end + + it 'adds a new branch rule', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/397587' do + project.visit! + + Page::Project::Menu.perform(&:go_to_repository_settings) + + Page::Project::Settings::Repository.perform(&:expand_branch_rules) + + Page::Project::Settings::BranchRules.perform(&:click_add_branch_rule) + + Page::Project::Settings::ProtectedBranches.perform do |settings| + settings.select_branch(branch_name) + settings.select_allowed_to_push(roles: allowed_to_push_role) + settings.select_allowed_to_merge(roles: allowed_to_merge_role) + settings.protect_branch + end + + Page::Project::Settings::Repository.perform(&:expand_branch_rules) + + Page::Project::Settings::BranchRules.perform do |rules| + expect(rules).to have_content(branch_name) + rules.navigate_to_branch_rules_details(branch_name) + end + + Page::Project::Settings::BranchRulesDetails.perform do |details| + aggregate_failures 'branch rules details' do + expect(details).to have_allowed_to_push(allowed_to_push_role[:description]) + expect(details).to have_allowed_to_merge(allowed_to_merge_role[:description]) + end + end + end + end + end +end diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb index b98bb8592d3..afa9be034eb 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb @@ -2,10 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Branch with unusual name', product_group: :source_code, quarantine: { - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/364565', - type: :bug - } do + describe 'Branch with unusual name', product_group: :source_code do let(:branch_name) { 'unUsually/named#br--anch' } let(:project) do Resource::Project.fabricate_via_api! do |resource| @@ -33,14 +30,8 @@ module QA Page::Project::Show.perform do |show| show.switch_to_branch(branch_name) - # It takes a few seconds for console errors to appear - sleep 3 - - errors = page.driver.browser.logs.get(:browser) - .select { |e| e.level == "SEVERE" } - .to_a - - raise("Console error(s):\n#{errors.join("\n\n")}") if errors.present? + # To prevent false positives: https://gitlab.com/gitlab-org/gitlab/-/issues/383863 + expect(show).to have_no_content('An error occurred') show.click_file('test-folder') diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb index f4ca7955a0f..479c5816938 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb @@ -20,13 +20,12 @@ module QA 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, testcase| it "can be created by #{user}", testcase: testcase do Flow::Login.sign_in(as: send(user)) - create_tag_for_project(project, tag_name, tag_message, tag_release_notes) + create_tag_for_project(project, tag_name, tag_message) Page::Project::Tag::Show.perform do |show| expect(show).to have_tag_name(tag_name) @@ -40,7 +39,7 @@ module QA it "cannot be created by an unauthorized #{user}", testcase: testcase do Flow::Login.sign_in(as: send(user)) - create_tag_for_project(project, tag_name, tag_message, tag_release_notes) + create_tag_for_project(project, tag_name, tag_message) 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.') @@ -73,7 +72,7 @@ module QA it_behaves_like 'successful tag creation', :maintainer_user, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347928' end - def create_tag_for_project(project, name, message, release_notes) + def create_tag_for_project(project, name, message) project.visit! Page::Project::Menu.perform(&:go_to_repository_tags) diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb index 1a614e538ea..01ff6133e70 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb @@ -1,11 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :reliable, product_group: :editor, quarantine: { - only: { subdomain: 'pre' }, - type: :investigating, - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378697' - } do + RSpec.describe 'Create', :reliable, product_group: :editor do describe 'Multiple file snippet' do let(:first_file_content) { 'First file content' } let(:second_file_content) { 'Second file content' } diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb index e5e3941e0cd..59b008d01e7 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb @@ -1,8 +1,7 @@ # frozen_string_literal: true -# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled module QA - RSpec.describe 'Create', :skip_live_env, product_group: :editor do + RSpec.describe 'Create', product_group: :editor do describe 'Add a directory in Web IDE' do let(:project) do Resource::Project.fabricate_via_api! do |project| @@ -30,23 +29,18 @@ module QA } ]) end - project.visit! - - Page::Project::Show.perform(&:open_web_ide!) end - it 'throws an error', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347733' do - Page::Project::WebIDE::Edit.perform do |ide| - # Support::Waiter.wait_until(sleep_interval: 2, max_duration: 60, reload_page: page, - # retry_on_exception: true) do - # expect(ide).to have_element(:commit_mode_tab) - # end - ide.wait_until_ide_loads - ide.add_directory(directory_name) + it 'throws an error', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386760' do + Page::Project::Show.perform(&:open_web_ide!) + Page::Project::WebIDE::VSCode.perform do |ide| + ide.wait_for_ide_to_load + ide.create_new_folder(directory_name) + ide.within_vscode_editor do + expect(page).to have_content('A file or folder first_directory already exists at this location.') + end end - - expect(page).to have_content('The name "first_directory" is already taken in this directory.') end end @@ -57,18 +51,15 @@ module QA Page::Project::Show.perform(&:open_web_ide!) end - it 'shows in the tree view but cannot be committed', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347732' do - Page::Project::WebIDE::Edit.perform do |ide| - ide.wait_until_ide_loads - ide.add_directory(directory_name) - - expect(ide).to have_file(directory_name) - expect(ide).to have_folder_icon(directory_name) - expect(ide).not_to have_file_addition_icon(directory_name) - - ide.switch_to_commit_tab - - expect(ide).not_to have_file_to_commit(directory_name) + it 'shows successfully but not able to be committed', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386761' do + Page::Project::WebIDE::VSCode.perform do |ide| + ide.wait_for_ide_to_load + ide.create_new_folder(directory_name) + ide.commit_and_push(directory_name) + ide.within_vscode_editor do + expect(page).to have_content('No changes found. Not able to commit.') + end end end end diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide_new/add_new_directory_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_new/add_new_directory_in_web_ide_spec.rb deleted file mode 100644 index 7b40c8a62c1..00000000000 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide_new/add_new_directory_in_web_ide_spec.rb +++ /dev/null @@ -1,73 +0,0 @@ -# frozen_string_literal: true - -module QA - RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor do - describe 'Add a directory in Web IDE' do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'add-directory-project' - project.initialize_with_readme = true - end - end - - before do - Runtime::Feature.enable(:vscode_web_ide) - Flow::Login.sign_in - project.visit! - end - - after do - Runtime::Feature.disable(:vscode_web_ide) - end - - context 'when a directory with the same name already exists' do - let(:directory_name) { 'first_directory' } - - before do - Resource::Repository::Commit.fabricate_via_api! do |commit| - commit.project = project - commit.add_files( - [ - { - file_path: 'first_directory/test_file.txt', - content: "Test file content" - } - ]) - end - project.visit! - end - - it 'throws an error', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386760' do - Page::Project::Show.perform(&:open_web_ide!) - Page::Project::WebIDE::VSCode.perform do |ide| - ide.wait_for_ide_to_load - ide.create_new_folder(directory_name) - ide.within_vscode_editor do - expect(page).to have_content('A file or folder first_directory already exists at this location.') - end - end - end - end - - context 'when user adds a new empty directory' do - let(:directory_name) { 'new_empty_directory' } - - before do - Page::Project::Show.perform(&:open_web_ide!) - end - - it 'shows successfully but not able to be committed', -testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386761' do - Page::Project::WebIDE::VSCode.perform do |ide| - ide.wait_for_ide_to_load - ide.create_new_folder(directory_name) - ide.commit_and_push(directory_name) - ide.within_vscode_editor do - expect(page).to have_content('No changes found. Not able to commit.') - end - end - end - end - end - end -end 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_old/add_file_template_spec.rb index cf1e4700863..d046a6fb0c5 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_old/add_file_template_spec.rb @@ -1,8 +1,12 @@ # frozen_string_literal: true -# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled +# TODO: remove this test when coverage is replaced or deemed irrelevant module QA RSpec.describe 'Create', :skip_live_env, product_group: :editor do + before do + skip("Skipped but kept as reference. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115741#note_1330720944") + end + describe 'Web IDE file templates' do include Runtime::Fixtures 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_old/create_first_file_in_web_ide_spec.rb index 58afdfe7cd1..047490bd31e 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_old/create_first_file_in_web_ide_spec.rb @@ -1,8 +1,12 @@ # frozen_string_literal: true -# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled +# TODO: remove this test when coverage is replaced or deemed irrelevant module QA RSpec.describe 'Create', :skip_live_env, product_group: :editor do + before do + skip("Skipped but kept as reference. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115741#note_1330720944") + end + 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/link_to_line_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/link_to_line_in_web_ide_spec.rb index 9c40a3abe52..aeb7a20a15b 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/link_to_line_in_web_ide_spec.rb @@ -1,8 +1,12 @@ # frozen_string_literal: true -# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled +# TODO: remove this test when coverage is replaced or deemed irrelevant module QA RSpec.describe 'Create', :skip_live_env, product_group: :editor do + before do + skip("Skipped but kept as reference. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115741#note_1330720944") + end + describe 'Link to line in Web IDE' do let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) } let(:project) do diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/open_web_ide_from_diff_tab_spec.rb index bbfc3ba8ccd..92e4ed11ea7 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/open_web_ide_from_diff_tab_spec.rb @@ -1,8 +1,12 @@ # frozen_string_literal: true -# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled +# TODO: remove this test when coverage is replaced or deemed irrelevant module QA RSpec.describe 'Create', :skip_live_env, product_group: :editor do + before do + skip("Skipped but kept as reference. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115741#note_1330720944") + end + describe 'Open Web IDE from Diff Tab' do files = [ { 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_old/review_merge_request_spec.rb index 05c58b66b09..34e445d6c1c 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_old/review_merge_request_spec.rb @@ -1,8 +1,12 @@ # frozen_string_literal: true -# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled +# TODO: remove this test when coverage is replaced or deemed irrelevant module QA RSpec.describe 'Create', :skip_live_env, product_group: :editor do + before do + skip("Skipped but kept as reference. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115741#note_1330720944") + end + 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/web_ide/server_hooks_custom_error_message_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb index 8082c54a6ee..e3ffeba6902 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb @@ -1,8 +1,12 @@ # frozen_string_literal: true -# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled +# TODO: remove this test when coverage is replaced or deemed irrelevant module QA RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' }, product_group: :editor do + before do + skip("Skipped but kept as reference. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115741#note_1330720944") + end + describe 'Git Server Hooks' do let(:file_path) { File.join(Runtime::Path.fixtures_path, 'web_ide', 'README.md') } diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/upload_new_file_in_web_ide_spec.rb index abc7c37a1d4..d83e2517cff 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/upload_new_file_in_web_ide_spec.rb @@ -1,8 +1,12 @@ # frozen_string_literal: true -# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled +# TODO: remove this test when coverage is replaced or deemed irrelevant module QA RSpec.describe 'Create', :skip_live_env, product_group: :editor do + before do + skip("Skipped but kept as reference. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115741#note_1330720944") + end + describe 'Upload a file in Web IDE' do let(:file_path) { File.join(Runtime::Path.fixtures_path, 'web_ide', file_name) } diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb index 072c957f4dc..b08a36b0d43 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb @@ -1,10 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner, product_group: :pipeline_security, quarantine: { - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/396855', - type: :flaky - } do + RSpec.describe 'Verify', :runner, product_group: :pipeline_security do describe "Unlocking job artifacts across parent-child pipelines" do let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } @@ -22,15 +19,6 @@ module QA end end - let(:parent_test_job_name) { 'test-job-parent' } - let(:child_test_job_name) { 'test-job-child' } - - let(:previous_successful_pipeline) do - Resource::Pipeline.fabricate_via_api! do |pipeline| - pipeline.project = project - end - end - before do Flow::Login.sign_in project.visit! @@ -40,47 +28,40 @@ module QA let(:strategy) { nil } before do - add_parent_child_ci_files - Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') - previous_successful_pipeline + add_parent_child_ci_files( + parent_job_name: 'parent_1', parent_script: 'echo parent', + child_job_name: 'child_1', child_script: 'echo child' + ) Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') end context 'when latest pipeline family is successful' do before do - update_parent_child_ci_files + update_parent_child_ci_files( + parent_job_name: 'parent_2', parent_script: 'echo parent', + child_job_name: 'child_2', child_script: 'echo child' + ) + Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') end it 'unlocks job artifacts from previous successful pipeline family', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/395516' do - project.visit! - - Flow::Pipeline.visit_latest_pipeline(status: 'passed') - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_2').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - Flow::Pipeline.visit_latest_pipeline(status: 'passed') - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_2').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - previous_successful_pipeline.visit! - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_unlocked_artifact end - previous_successful_pipeline.visit! - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_unlocked_artifact end @@ -89,43 +70,31 @@ module QA context 'when latest parent pipeline failed' do before do - update_failed_parent_ci_file + update_parent_child_ci_files( + parent_job_name: 'parent_2', parent_script: 'exit 1', + child_job_name: 'child_2', child_script: 'echo child' + ) + Flow::Pipeline.wait_for_latest_pipeline(status: 'failed') end it 'does not unlock job artifacts from previous successful pipeline family', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396243' do - project.visit! - - Flow::Pipeline.visit_latest_pipeline(status: 'failed') - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_2').visit! Page::Project::Job::Show.perform do |job| - expect(job).to be_failed - # FIXME: this should be unlocked, - # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575 expect(job).to have_locked_artifact end - Flow::Pipeline.visit_latest_pipeline(status: 'failed') - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_2').visit! Page::Project::Job::Show.perform do |job| - expect(job).to be_successful expect(job).to have_locked_artifact end - previous_successful_pipeline.visit! - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - previous_successful_pipeline.visit! - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end @@ -134,41 +103,31 @@ module QA context 'when latest child pipeline failed' do before do - update_failed_child_ci_file + update_parent_child_ci_files( + parent_job_name: 'parent_2', parent_script: 'echo parent', + child_job_name: 'child_2', child_script: 'exit 1' + ) + Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') end it 'unlocks job artifacts from previous successful pipeline family because the latest parent is successful', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396244' do - project.visit! - - Flow::Pipeline.visit_latest_pipeline(status: 'passed') - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_2').visit! Page::Project::Job::Show.perform do |job| - expect(job).to be_successful expect(job).to have_locked_artifact end - Flow::Pipeline.visit_latest_pipeline(status: 'passed') - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_2').visit! Page::Project::Job::Show.perform do |job| - expect(job).to be_failed expect(job).to have_locked_artifact end - previous_successful_pipeline.visit! - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_unlocked_artifact end - previous_successful_pipeline.visit! - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_unlocked_artifact end @@ -180,47 +139,40 @@ module QA let(:strategy) { 'depend' } before do - add_parent_child_ci_files - Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') - previous_successful_pipeline + add_parent_child_ci_files( + parent_job_name: 'parent_1', parent_script: 'echo parent', + child_job_name: 'child_1', child_script: 'echo child' + ) Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') end context 'when latest pipeline family is successful' do before do - update_parent_child_ci_files + update_parent_child_ci_files( + parent_job_name: 'parent_2', parent_script: 'echo parent', + child_job_name: 'child_2', child_script: 'echo child' + ) + Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') end it 'unlocks job artifacts from previous successful pipeline family', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396245' do - project.visit! - - Flow::Pipeline.visit_latest_pipeline(status: 'passed') - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_2').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - Flow::Pipeline.visit_latest_pipeline(status: 'passed') - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_2').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - previous_successful_pipeline.visit! - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_unlocked_artifact end - previous_successful_pipeline.visit! - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_unlocked_artifact end @@ -229,43 +181,31 @@ module QA context 'when latest parent pipeline failed' do before do - update_failed_parent_ci_file + update_parent_child_ci_files( + parent_job_name: 'parent_2', parent_script: 'exit 1', + child_job_name: 'child_2', child_script: 'echo child' + ) + Flow::Pipeline.wait_for_latest_pipeline(status: 'failed') end it 'does not unlock job artifacts from previous successful pipeline family', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396246' do - project.visit! - - Flow::Pipeline.visit_latest_pipeline(status: 'failed') - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_2').visit! Page::Project::Job::Show.perform do |job| - # FIXME: this should be unlocked, - # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575 - expect(job).to be_failed expect(job).to have_locked_artifact end - Flow::Pipeline.visit_latest_pipeline(status: 'failed') - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_2').visit! Page::Project::Job::Show.perform do |job| - expect(job).to be_successful expect(job).to have_locked_artifact end - previous_successful_pipeline.visit! - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - previous_successful_pipeline.visit! - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end @@ -274,45 +214,31 @@ module QA context 'when latest child pipeline failed' do before do - update_failed_child_ci_file + update_parent_child_ci_files( + parent_job_name: 'parent_2', parent_script: 'echo parent', + child_job_name: 'child_2', child_script: 'exit 1' + ) + Flow::Pipeline.wait_for_latest_pipeline(status: 'failed') end it 'does not unlock job artifacts from previous successful pipeline family', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396248' do - project.visit! - - Flow::Pipeline.visit_latest_pipeline(status: 'failed') - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_2').visit! Page::Project::Job::Show.perform do |job| - expect(job).to be_successful - # FIXME: this should be unlocked, - # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575 expect(job).to have_locked_artifact end - Flow::Pipeline.visit_latest_pipeline(status: 'failed') - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_2').visit! Page::Project::Job::Show.perform do |job| - expect(job).to be_failed - # FIXME: this should be unlocked, - # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575 expect(job).to have_locked_artifact end - previous_successful_pipeline.visit! - Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name) + find_job('parent_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - previous_successful_pipeline.visit! - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.expand_child_pipeline - pipeline.click_job(child_test_job_name) - end + find_job('child_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end @@ -322,78 +248,33 @@ module QA private - def update_parent_child_ci_files + def update_parent_child_ci_files(parent_job_name:, parent_script:, child_job_name:, child_script:) Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project commit.commit_message = 'Update parent and child pipelines CI files.' commit.update_files( [ - parent_ci_file, - child_ci_file - ] - ) - end - end - - def update_failed_parent_ci_file - Resource::Repository::Commit.fabricate_via_api! do |commit| - commit.project = project - commit.commit_message = 'Fail parent pipeline.' - commit.update_files( - [ - parent_failed_ci_file + parent_ci_file(parent_job_name, parent_script), + child_ci_file(child_job_name, child_script) ] ) end end - def update_failed_child_ci_file - Resource::Repository::Commit.fabricate_via_api! do |commit| - commit.project = project - commit.commit_message = 'Fail child pipeline.' - commit.update_files( - [ - child_failed_ci_file - ] - ) - end - end - - def add_parent_child_ci_files + def add_parent_child_ci_files(parent_job_name:, parent_script:, child_job_name:, child_script:) Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project commit.commit_message = 'Add parent and child pipelines CI files.' commit.add_files( [ - parent_ci_file, - child_ci_file + parent_ci_file(parent_job_name, parent_script), + child_ci_file(child_job_name, child_script) ] ) end end - def parent_ci_file - { - file_path: '.gitlab-ci.yml', - content: <<~YAML - trigger-child: - stage: test - trigger: - include: ".child-ci.yml" - strategy: #{strategy} - - #{parent_test_job_name}: - stage: test - tags: ["#{executor}"] - script: echo "parent test" - artifacts: - paths: ['.gitlab-ci.yml'] - when: always - YAML - } - end - - def parent_failed_ci_file + def parent_ci_file(job_name, script) { file_path: '.gitlab-ci.yml', content: <<~YAML @@ -403,10 +284,10 @@ module QA include: ".child-ci.yml" strategy: #{strategy} - #{parent_test_job_name}: + #{job_name}: stage: test tags: ["#{executor}"] - script: echo "parent test" && exit 1 + script: #{script} artifacts: paths: ['.gitlab-ci.yml'] when: always @@ -414,14 +295,14 @@ module QA } end - def child_ci_file + def child_ci_file(job_name, script) { file_path: '.child-ci.yml', content: <<~YAML - #{child_test_job_name}: + #{job_name}: stage: test tags: ["#{executor}"] - script: echo "child test" + script: #{script} artifacts: paths: ['.child-ci.yml'] when: always @@ -429,19 +310,11 @@ module QA } end - def child_failed_ci_file - { - file_path: '.child-ci.yml', - content: <<~YAML - #{child_test_job_name}: - stage: test - tags: ["#{executor}"] - script: echo "child test" && exit 1 - artifacts: - paths: ['.child-ci.yml'] - when: always - YAML - } + def find_job(job_name) + Resource::Job.fabricate_via_api! do |job| + job.project = project + job.id = project.job_by_name(job_name)[:id] + end end end end diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb index a954bd16386..f1a433984d8 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb @@ -19,41 +19,34 @@ module QA end end - let(:test_job_name) { 'test-job' } - before do Flow::Login.sign_in + project.visit! end context 'when latest pipeline is successful' do + before do + add_ci_file(job_name: 'job_1', script: 'echo test') + Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') + end + it 'unlocks job artifacts from previous successful pipeline', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/394807' do - add_ci_file - project.visit! - - previous_successful_pipeline = Resource::Pipeline.fabricate! do |pipeline| - pipeline.project = project - end - - Flow::Pipeline.visit_latest_pipeline(status: 'passed') - Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name) - + find_job('job_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - update_ci_script('echo bye') - project.visit! + update_ci_file(job_name: 'job_2', script: 'echo test') - Flow::Pipeline.visit_latest_pipeline(status: 'passed') - Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name) + Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') + find_job('job_2').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - Flow::Pipeline.visit_pipeline_job_page(pipeline: previous_successful_pipeline, job_name: test_job_name) - + find_job('job_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_unlocked_artifact end @@ -61,57 +54,69 @@ module QA end context 'when latest pipeline failed' do - it 'unlocks job artifacts from failed pipelines, keeps job artifacts from latest successful pipeline', + before do + add_ci_file(job_name: 'successful_job_1', script: 'echo test') + Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') + end + + it 'keeps job artifacts from latest failed pipelines and from latest successful pipeline', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/394808', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/266958', type: :bug } do - add_ci_file - project.visit! + update_ci_file(job_name: 'failed_job_1', script: 'exit 1') + Flow::Pipeline.wait_for_latest_pipeline(status: 'failed') - successful_pipeline = Resource::Pipeline.fabricate! do |pipeline| - pipeline.project = project - end - - Flow::Pipeline.visit_latest_pipeline(status: 'passed') - Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name) + update_ci_file(job_name: 'failed_job_2', script: 'exit 2') + Flow::Pipeline.wait_for_latest_pipeline(status: 'failed') + find_job('failed_job_2').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end - update_ci_script('echo test && exit 1') - - failed_pipeline_1 = Resource::Pipeline.fabricate! do |pipeline| - pipeline.project = project + find_job('failed_job_1').visit! + Page::Project::Job::Show.perform do |job| + expect(job).to have_unlocked_artifact end - Flow::Pipeline.visit_latest_pipeline(status: 'failed') - Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name) - + find_job('successful_job_1').visit! Page::Project::Job::Show.perform do |job| - expect(job).to have_unlocked_artifact + expect(job).to have_locked_artifact end + end + end - update_ci_script('echo bye && exit 1') - project.visit! + context 'when latest pipeline is blocked' do + before do + add_ci_file(job_name: 'successful_job_1', script: 'echo test') + Flow::Pipeline.wait_for_latest_pipeline(status: 'passed') + end + + it 'keeps job artifacts from the latest blocked pipeline and from latest successful pipeline', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/395511', + quarantine: { + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387087', + type: :bug + } do + update_ci_with_manual_job(job_name: 'successful_job_with_manual_1', script: 'echo test') + Flow::Pipeline.wait_for_latest_pipeline(status: 'blocked') - Flow::Pipeline.visit_latest_pipeline(status: 'failed') - Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name) + update_ci_with_manual_job(job_name: 'successful_job_with_manual_2', script: 'echo test') + Flow::Pipeline.wait_for_latest_pipeline(status: 'blocked') + find_job('successful_job_with_manual_2').visit! Page::Project::Job::Show.perform do |job| - expect(job).to have_unlocked_artifact + expect(job).to have_locked_artifact end - Flow::Pipeline.visit_pipeline_job_page(pipeline: failed_pipeline_1, job_name: test_job_name) - + find_job('successful_job_with_manual_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_unlocked_artifact end - Flow::Pipeline.visit_pipeline_job_page(pipeline: successful_pipeline, job_name: test_job_name) - + find_job('successful_job_1').visit! Page::Project::Job::Show.perform do |job| expect(job).to have_locked_artifact end @@ -120,42 +125,41 @@ module QA private - def add_ci_file - script = 'echo test' - ci_file = ci_file_with_job_artifact(script) + def add_ci_file(job_name:, script:) + ci_file = ci_file_with_job_artifact(job_name, script) Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project - commit.commit_message = "Set script #{script}" + commit.commit_message = "Set job #{job_name} script #{script}" commit.add_files([ci_file]) end end - def update_ci_script(script) - ci_file = ci_file_with_job_artifact(script) + def update_ci_file(job_name:, script:) + ci_file = ci_file_with_job_artifact(job_name, script) Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project - commit.commit_message = "Set script #{script}" + commit.commit_message = "Set job #{job_name} script #{script}" commit.update_files([ci_file]) end end - def add_failing_ci_file - ci_file = ci_file_with_job_artifact('echo test && exit 1') + def update_ci_with_manual_job(job_name:, script:) + ci_file = ci_file_with_manual_job(job_name, script) Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project - commit.commit_message = 'Add failing CI file.' - commit.add_files([ci_file]) + commit.commit_message = "Set job #{job_name} script #{script}" + commit.update_files([ci_file]) end end - def ci_file_with_job_artifact(script) + def ci_file_with_job_artifact(job_name, script) { file_path: '.gitlab-ci.yml', content: <<~YAML - #{test_job_name}: + #{job_name}: stage: test tags: ["#{executor}"] script: #{script} @@ -165,6 +169,36 @@ module QA YAML } end + + def ci_file_with_manual_job(job_name, script) + { + file_path: '.gitlab-ci.yml', + content: <<~YAML + #{job_name}: + stage: test + tags: ["#{executor}"] + script: #{script} + artifacts: + paths: ['.gitlab-ci.yml'] + + manual-job: + stage: test + tags: ["#{executor}"] + rules: + - when: manual + script: "echo 'this job is manual'" + artifacts: + paths: ['.gitlab-ci.yml'] + YAML + } + end + + def find_job(job_name) + Resource::Job.fabricate_via_api! do |job| + job.project = project + job.id = project.job_by_name(job_name)[:id] + 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 deleted file mode 100644 index 8474e5c1b37..00000000000 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -module QA - RSpec.describe 'Verify' do - describe 'Add or Remove CI variable via UI', :smoke, product_group: :pipeline_security do - let(:project) do - Resource::Project.fabricate_via_api_unless_fips! do |project| - project.name = 'project-with-ci-variables' - project.description = 'project with CI variables' - end - end - - before do - Flow::Login.sign_in - project.visit! - add_ci_variable - end - - it 'user adds a CI variable', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348027' do - Page::Project::Settings::CiVariables.perform do |ci_variable| - expect(ci_variable).to have_text('VARIABLE_KEY') - expect(ci_variable).not_to have_text('some_CI_variable') - - ci_variable.click_reveal_ci_variable_value_button - - expect(ci_variable).to have_text('some_CI_variable') - end - end - - it 'user removes a CI variable', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348026' do - Page::Project::Settings::CiVariables.perform do |ci_variable| - ci_variable.click_edit_ci_variable - ci_variable.click_ci_variable_delete_button - - expect(ci_variable).to have_text('There are no variables yet', wait: 60) - end - end - - private - - def add_ci_variable - Resource::CiVariable.fabricate_via_browser_ui! do |ci_variable| - ci_variable.project = project - ci_variable.key = 'VARIABLE_KEY' - ci_variable.value = 'some_CI_variable' - ci_variable.masked = false - end - end - end - end -end diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb index 4c1319da0cb..4515353dfc5 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb @@ -49,7 +49,7 @@ module QA Flow::Login.sign_in project.visit! - Page::Project::Menu.perform(&:click_ci_cd_pipelines) + Page::Project::Menu.perform(&:go_to_pipelines) Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button) end diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb index b79f8b5f1f4..b62ae85436f 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb @@ -52,7 +52,7 @@ module QA project.visit! # Navigate to Run Pipeline page - Page::Project::Menu.perform(&:click_ci_cd_pipelines) + Page::Project::Menu.perform(&:go_to_pipelines) Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button) end 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 deleted file mode 100644 index 0aedbd307bf..00000000000 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb +++ /dev/null @@ -1,100 +0,0 @@ -# frozen_string_literal: true - -module QA - RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do - describe 'Pipeline creation and processing' do - let(:executor) { "qa-runner-#{Time.now.to_i}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-pipeline' - end - end - - let!(:runner) do - Resource::ProjectRunner.fabricate! do |runner| - runner.project = project - runner.name = executor - runner.tags = [executor] - end - end - - after do - [runner, project].each(&:remove_via_api!) - end - - it 'users creates a pipeline which gets processed', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348024' do - Flow::Login.sign_in - - 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 - test-success: - tags: - - #{executor} - script: echo 'OK' - - test-failure: - tags: - - #{executor} - script: - - echo 'FAILURE' - - exit 1 - - test-tags-mismatch: - tags: - - invalid - script: echo 'NOOP' - - test-artifacts: - tags: - - #{executor} - script: mkdir my-artifacts; echo "CONTENTS" > my-artifacts/artifact.txt - artifacts: - paths: - - my-artifacts/ - - test-coverage-report: - tags: - - #{executor} - script: mkdir coverage; echo "CONTENTS" > coverage/cobertura.xml - artifacts: - reports: - coverage_report: - coverage_format: cobertura - path: coverage/cobertura.xml - YAML - } - ] - ) - end.project.visit! - - Flow::Pipeline.visit_latest_pipeline - - aggregate_failures do - { - 'test-success': 'passed', - 'test-failure': 'failed', - 'test-tags-mismatch': 'pending', - 'test-artifacts': 'passed', - 'test-coverage-report': 'passed' - }.each do |job, status| - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.click_job(job) - end - - Page::Project::Job::Show.perform do |show| - expect(show).to have_status(status), "Expected job status to be #{status} but got #{show.status_badge} instead." - show.click_element(:pipeline_path, Page::Project::Pipeline::Show) - end - end - end - end - end - end -end diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb deleted file mode 100644 index 5543e39e38c..00000000000 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -# frozen_string_literal: true - -module QA - RSpec.describe 'Verify', :runner, product_group: :pipeline_security do - describe 'Artifacts' do - context 'when locked' do - let(:file_name) { 'artifact.txt' } - let(:directory_name) { 'my_artifacts' } - let(:executor) { "qa-runner-#{Time.now.to_i}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-locked-artifacts' - end - end - - let!(:runner) do - Resource::ProjectRunner.fabricate! do |runner| - runner.project = project - runner.name = executor - runner.tags = [executor] - end - end - - before do - Flow::Login.sign_in - end - - after do - runner.remove_via_api! - end - - it 'can be browsed', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348003' 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 - test-artifacts: - tags: - - '#{executor}' - artifacts: - paths: - - '#{directory_name}' - expire_in: 1 sec - script: - - | - mkdir #{directory_name} - echo "CONTENTS" > #{directory_name}/#{file_name} - YAML - } - ] - ) - end.project.visit! - - Flow::Pipeline.visit_latest_pipeline - - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.click_job('test-artifacts') - end - - Page::Project::Job::Show.perform do |show| - expect(show).to have_browse_button - show.click_browse_button - end - - Page::Project::Artifact::Show.perform do |show| - show.go_to_directory(directory_name) - expect(show).to have_content(file_name) - end - end - end - end - end -end diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb index e8ec01577b1..9f43471035f 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb @@ -37,7 +37,7 @@ module QA before do Flow::Login.sign_in project.visit! - Page::Project::Menu.perform(&:click_ci_cd_pipelines) + Page::Project::Menu.perform(&:go_to_pipelines) end it 'can trigger pipeline', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348011' do diff --git a/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb index e7ab515c672..e2bb6c33513 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb @@ -40,8 +40,7 @@ module QA testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/360837' ) do # create a CI variable via UI - Page::Project::Show.perform(&:go_to_ci_cd_settings) - + Page::Project::Menu.perform(&:go_to_ci_cd_settings) Page::Project::Settings::CiCd.perform do |ci_cd| ci_cd.expand_ci_variables do |vars| vars.click_add_variable diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb index ec07116550f..d79befc6837 100644 --- a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb @@ -2,8 +2,8 @@ module QA RSpec.describe 'Package', :orchestrated, :skip_live_env, product_group: :container_registry, quarantine: { - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/390090', - type: :investigating + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/399556', + type: :flaky } do describe 'Self-managed Container Registry' do include Support::Helpers::MaskToken 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 1e7d0eab365..0a9f30f0529 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 @@ -2,7 +2,7 @@ module QA RSpec.describe 'Configure', - only: { subdomain: %i[staging staging-canary] }, product_group: :configure do + only: { pipeline: %i[staging staging-canary canary production] }, product_group: :configure do describe 'Auto DevOps with a Kubernetes Agent' do let!(:app_project) do Resource::Project.fabricate_via_api! do |project| @@ -45,7 +45,7 @@ module QA app_project.visit! - Page::Project::Menu.perform(&:click_ci_cd_pipelines) + Page::Project::Menu.perform(&:go_to_pipelines) Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button) Page::Project::Pipeline::New.perform(&:click_run_pipeline_button) diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb index 70874e46f27..008d8f808b3 100644 --- a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb +++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb @@ -3,8 +3,8 @@ module QA RSpec.describe 'Monitor', :orchestrated, :smtp, :requires_admin, product_group: :respond do describe 'Alert' do - shared_examples 'notification on new alert', :aggregate_failures do - it 'sends email to user' do + shared_examples 'notification on new alert' do + it 'sends email to user', :aggregate_failures do expect { email_subjects }.to eventually_include(alert_email_subject).within(max_duration: 60) expect(recipient_email_addresses).to include(user.email) end diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb index 433d286686b..af088d2978a 100644 --- a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb +++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb @@ -26,7 +26,12 @@ module QA context( 'when using HTTP endpoint integration', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393589' + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393589', + quarantine: { + only: { pipeline: :nightly }, + type: :bug, + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/395512' + } ) do include_context 'sends and resolves test alerts' diff --git a/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb b/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident_spec.rb index fe3cd5a432b..aadca29de0c 100644 --- a/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb +++ b/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident_spec.rb @@ -27,7 +27,12 @@ module QA context( 'when using HTTP endpoint integration', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393842' + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393842', + quarantine: { + only: { pipeline: :nightly }, + type: :bug, + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/403596' + } ) do include_context 'sends and resolves test alerts' diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/group_member_access_request_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb index 3a84646977f..1206898431a 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/group/group_member_access_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :requires_admin, product_group: :organization do + RSpec.describe 'Data Stores', :requires_admin, product_group: :tenant_scale do describe 'Group member access request' do let!(:admin_api_client) { Runtime::API::Client.as_admin } @@ -40,7 +40,7 @@ module QA end it 'generates a todo item for the group owner', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370132' do + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370132' do Page::Dashboard::Todos.perform do |todos| expect(todos).to have_latest_todo_with_author( author: user.name, @@ -64,7 +64,7 @@ module QA end it 'adds user to the group', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386792' do + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386792' do found_member = group.reload!.find_member(user.username) expect(found_member).not_to be_nil @@ -81,7 +81,7 @@ module QA end it 'does not add user to the group', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386793' do + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386793' do found_member = group.reload!.find_member(user.username) expect(found_member).to be_nil diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_group_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb index b2ccacfd142..2f14e2c10da 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_group_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'Subgroup transfer', product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'Subgroup transfer', product_group: :tenant_scale do let(:source_group) do Resource::Group.fabricate_via_api! do |group| group.path = "source-group-for-transfer_#{SecureRandom.hex(8)}" @@ -28,7 +28,7 @@ module QA end it 'transfers a subgroup to another group', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347692' do + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347692' do Page::Group::Menu.perform(&:click_group_general_settings_item) Page::Group::Settings::General.perform do |general| general.transfer_group(sub_group_for_transfer, target_group) diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_project_spec.rb index ef05f4cfecf..02e1598d6e7 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_project_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'Project transfer between groups', :reliable, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'Project transfer between groups', :reliable, product_group: :tenant_scale do let(:source_group) do Resource::Group.fabricate_via_api! do |group| group.path = "source-group-#{SecureRandom.hex(8)}" @@ -36,8 +36,8 @@ module QA end it 'user transfers a project between groups', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347878' do - Page::File::Show.perform(&:go_to_general_settings) + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347878' do + Page::Project::Menu.perform(&:go_to_general_settings) Page::Project::Settings::Main.perform(&:expand_advanced_settings) @@ -45,7 +45,7 @@ module QA advanced.transfer_project!(project.name, target_group.full_path) end - Page::Project::Settings::Main.perform(&:click_project) + Page::Project::Menu.perform(&:click_project) Page::Project::Show.perform do |project| expect(project).to have_breadcrumb(target_group.path) diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb index 50e86b4d555..0beb297ffdb 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :reliable, product_group: :organization do + RSpec.describe 'Data Stores', :reliable, product_group: :tenant_scale do describe 'Add project member' do it 'user adds project member', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347887' do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/create_project_badge_spec.rb index 0a643d1e33b..87492af089e 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/create_project_badge_spec.rb @@ -1,11 +1,14 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'Create project badge', :reliable, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'Create project badge', :reliable, product_group: :tenant_scale do let(:badge_name) { "project-badge-#{SecureRandom.hex(8)}" } let(:expected_badge_link_url) { "#{Runtime::Scenario.gitlab_address}/#{project.path_with_namespace}" } - let(:expected_badge_image_url) { "#{Runtime::Scenario.gitlab_address}/#{project.path_with_namespace}/badges/main/pipeline.svg" } + let(:expected_badge_image_url) do + "#{Runtime::Scenario.gitlab_address}/#{project.path_with_namespace}/badges/main/pipeline.svg" + end + let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'badge-test-project' @@ -18,7 +21,8 @@ module QA project.visit! end - it 'creates project badge successfully', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/350065' do + it 'creates project badge successfully', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/350065' do Resource::ProjectBadge.fabricate! do |badge| badge.name = badge_name end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/create_project_spec.rb index c9e90cce84c..2d288ced0ca 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/create_project_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :smoke, product_group: :organization do + RSpec.describe 'Data Stores', :smoke, product_group: :tenant_scale do describe 'Project' do shared_examples 'successful project creation' do it 'creates a new project' do diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb index e609dfb9197..f2136773f59 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', product_group: :organization do + RSpec.describe 'Data Stores', product_group: :tenant_scale do shared_examples 'loads all images' do |admin| let(:api_client) { Runtime::API::Client.as_admin } @@ -21,7 +21,7 @@ module QA Page::Dashboard::Welcome.perform do |welcome| Support::Waiter.wait_until(sleep_interval: 2, max_duration: 60, reload_page: page, - retry_on_exception: true) do + retry_on_exception: true) do expect(welcome).to have_welcome_title("Welcome to GitLab") end # This would be better if it were a visual validation test diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/invite_group_to_project_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb index 4479f2ebfab..c7501d437eb 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/invite_group_to_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'Invite group', :reliable, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'Invite group', :reliable, product_group: :tenant_scale do shared_examples 'invites group to project' do it 'verifies group is added and members can access project with correct access level' do Page::Project::Menu.perform(&:click_members) @@ -28,7 +28,9 @@ module QA end end - let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) } + let(:user) do + Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) + end before do Flow::Login.sign_in @@ -36,7 +38,8 @@ module QA project.visit! end - context 'to personal namespace project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349223' do + context 'with a personal namespace project', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349223' do let(:group) do Resource::Group.fabricate_via_api! do |group| group.path = "group-for-personal-project-#{SecureRandom.hex(8)}" @@ -52,10 +55,15 @@ module QA end end + after do + project.remove_via_api! + group.remove_via_api! + end + it_behaves_like 'invites group to project' end - context 'to group project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349340' do + context 'with a group project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349340' do let(:group) do Resource::Group.fabricate_via_api! do |group| group.path = "group-for-group-project-#{SecureRandom.hex(8)}" @@ -70,6 +78,11 @@ module QA end end + after do + project.remove_via_api! + group.remove_via_api! + end + it_behaves_like 'invites group to project' end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/project_owner_permissions_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb index 59774ed7c49..2793b0440a4 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/project_owner_permissions_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'Project owner permissions', :reliable, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'Project owner permissions', :reliable, product_group: :tenant_scale do let!(:owner) do Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) 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/9_data_stores/project/view_project_activity_spec.rb index 95305b7a4aa..4945ef533a4 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'Project activity', :reliable, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'Project activity', :reliable, product_group: :tenant_scale do it 'user creates an event in the activity page upon Git push', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347879' do + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347879' do Flow::Login.sign_in project = Resource::Repository::ProjectPush.fabricate! do |push| diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb index ac08ecec786..c78151b94b7 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'User', :requires_admin, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'User', :requires_admin, product_group: :tenant_scale do let(:admin_api_client) { Runtime::API::Client.as_admin } let(:followed_user_api_client) { Runtime::API::Client.new(:gitlab, user: followed_user) } @@ -68,7 +68,15 @@ module QA followed_user_api_client.personal_access_token end - it 'can be followed and their activity seen', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347678' do + after do + project&.api_client = admin_api_client + project&.remove_via_api! + followed_user&.remove_via_api! + following_user&.remove_via_api! + end + + it 'can be followed and their activity seen', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347678' do Flow::Login.sign_in(as: following_user) page.visit Runtime::Scenario.gitlab_address + "/#{followed_user.username}" Page::User::Show.perform(&:click_follow_user_link) @@ -93,13 +101,6 @@ module QA end end end - - after do - project&.api_client = admin_api_client - project&.remove_via_api! - followed_user&.remove_via_api! - following_user&.remove_via_api! - end end end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb index 7caa6677787..7e88f3a9ac3 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'User', :requires_admin, :reliable, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'User', :requires_admin, :reliable, product_group: :tenant_scale do let(:admin_api_client) { Runtime::API::Client.as_admin } let!(:user) do @@ -41,7 +41,7 @@ module QA end it 'is not allowed to edit the project files', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347866' do + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347866' do Flow::Login.sign_in(as: user) project.visit! diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/user_inherited_access_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb index c57900efe35..78baba403fd 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/user/user_inherited_access_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do - describe 'User', :requires_admin, product_group: :organization do + RSpec.describe 'Data Stores' do + describe 'User', :requires_admin, product_group: :tenant_scale do let(:admin_api_client) { Runtime::API::Client.as_admin } let!(:parent_group) do @@ -41,6 +41,10 @@ module QA parent_group.add_member(parent_group_user) end + after do + parent_group_user.remove_via_api! + end + it( 'is allowed to edit the sub-group project files', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363467' @@ -58,10 +62,6 @@ module QA expect(file_form).to have_element(:commit_button) end end - - after do - parent_group_user.remove_via_api! - end end context 'when added to sub-group' do @@ -87,6 +87,10 @@ module QA sub_group.add_member(sub_group_user) end + after do + sub_group_user.remove_via_api! + end + it( 'is not allowed to edit the parent group project files', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363466' @@ -102,10 +106,6 @@ module QA expect(page).to have_text("You can’t edit files directly in this project.") end - - after do - sub_group_user.remove_via_api! - end end end end diff --git a/qa/qa/specs/features/shared_contexts/import/gitlab_group_migration_common.rb b/qa/qa/specs/features/shared_contexts/import/gitlab_group_migration_common.rb index 4bd81ccdf36..bfd0825cf91 100644 --- a/qa/qa/specs/features/shared_contexts/import/gitlab_group_migration_common.rb +++ b/qa/qa/specs/features/shared_contexts/import/gitlab_group_migration_common.rb @@ -77,7 +77,7 @@ module QA imported_group.import_details.sum([]) { |details| details[:failures] } end - let(:cleanup!) {} + let(:cleanup!) {} # rubocop:disable Lint/EmptyBlock def expect_group_import_finished_successfully imported_group # trigger import diff --git a/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb b/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb index a72140f41e0..9623bcbb7b5 100644 --- a/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb +++ b/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb @@ -35,6 +35,8 @@ module QA private def mark_as_resolved(payload, http) + sleep 3 # To ensure create and end time are different + if http payload[:end_time] = Time.now else diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb index 1bf189ed6ac..aa274a4e101 100644 --- a/qa/qa/specs/spec_helper.rb +++ b/qa/qa/specs/spec_helper.rb @@ -33,7 +33,7 @@ RSpec.configure do |config| QA::Runtime::Logger.info("Starting test: #{Rainbow(example.full_description).bright}") QA::Runtime::Example.current = example - visit(QA::Runtime::Scenario.gitlab_address) if QA::Runtime::Env.remote_mobile_device_name + visit(QA::Runtime::Scenario.gitlab_address) if QA::Runtime::Env.mobile_layout? # Reset fabrication counters tracked in resource base Thread.current[:api_fabrication] = 0 diff --git a/qa/qa/support/matchers/have_matcher.rb b/qa/qa/support/matchers/have_matcher.rb index d843949e6b2..a9b365f7e81 100644 --- a/qa/qa/support/matchers/have_matcher.rb +++ b/qa/qa/support/matchers/have_matcher.rb @@ -28,6 +28,7 @@ module QA system_note alert_with_title incident + framework ].each do |predicate| RSpec::Matchers.define "have_#{predicate}" do |*args, **kwargs| match do |page_object| diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb index 2e97325aff0..ad8d63ec856 100644 --- a/qa/qa/support/page/logging.rb +++ b/qa/qa/support/page/logging.rb @@ -92,8 +92,8 @@ module QA super end - def click_via_capybara(method, locator) - log("clicking via capybara using '#{method}(#{locator})'", :info) + def act_via_capybara(method, locator, **kwargs) + log("acting via capybara using '#{method}(#{locator})' with args #{kwargs}", :info) super end diff --git a/qa/qa/support/wait_for_requests.rb b/qa/qa/support/wait_for_requests.rb index d863ed0491d..2856602629a 100644 --- a/qa/qa/support/wait_for_requests.rb +++ b/qa/qa/support/wait_for_requests.rb @@ -16,7 +16,7 @@ module QA end def finished_all_ajax_requests? - requests = %w[window.pendingRequests window.pendingRailsUJSRequests 0] + requests = %w[window.pendingRequests window.pendingApolloRequests window.pendingRailsUJSRequests 0] if Runtime::Env.can_intercept? requests.unshift('(window.Interceptor && window.Interceptor.activeFetchRequests)') @@ -26,6 +26,10 @@ module QA Capybara.page.evaluate_script(script).zero? # rubocop:disable Style/NumericPredicate end + def spinner_exists? + Capybara.page.has_css?('.gl-spinner', wait: 2) + end + def finished_loading?(wait: DEFAULT_MAX_WAIT_TIME) # The number of selectors should be able to be reduced after # migration to the new spinner is complete. diff --git a/qa/qa/tools/test_resources_handler.rb b/qa/qa/tools/test_resources_handler.rb index 2aa8845605e..7f4b8f78618 100644 --- a/qa/qa/tools/test_resources_handler.rb +++ b/qa/qa/tools/test_resources_handler.rb @@ -31,6 +31,8 @@ module QA QA::Resource::CiVariable QA::Resource::Repository::Commit QA::Resource::Design + QA::Resource::InstanceOauthApplication + QA::EE::Resource::ComplianceFramework QA::EE::Resource::GroupIteration QA::EE::Resource::Settings::Elasticsearch QA::EE::Resource::VulnerabilityItem diff --git a/qa/qa/vendor/github/page/base.rb b/qa/qa/vendor/github/page/base.rb new file mode 100644 index 00000000000..3b96180afe9 --- /dev/null +++ b/qa/qa/vendor/github/page/base.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module QA + module Vendor + module Github + module Page + class Base + include Capybara::DSL + include Scenario::Actable + end + end + end + end +end diff --git a/qa/qa/vendor/github/page/login.rb b/qa/qa/vendor/github/page/login.rb new file mode 100644 index 00000000000..17a7471e251 --- /dev/null +++ b/qa/qa/vendor/github/page/login.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'capybara/dsl' +require 'benchmark' + +module QA + module Vendor + module Github + module Page + class Login < Page::Base + def login + fill_in 'login', with: QA::Runtime::Env.github_username + fill_in 'password', with: QA::Runtime::Env.github_password + click_on 'Sign in' + + current_otp = OnePassword::CLI.instance.current_otp + + fill_in 'app_otp', with: current_otp + + if has_text?('Two-factor authentication failed', wait: 2) + new_otp = OnePassword::CLI.instance.new_otp(otp) + + fill_in 'app_otp', with: new_otp + end + + authorize_app + end + + def authorize_app + click_on 'Authorize' if has_button?('Authorize') + end + end + end + end + end +end diff --git a/qa/qa/vendor/one_password/cli.rb b/qa/qa/vendor/one_password/cli.rb new file mode 100644 index 00000000000..f443ba05492 --- /dev/null +++ b/qa/qa/vendor/one_password/cli.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'benchmark' + +module QA + module Vendor + module OnePassword + class CLI + include Singleton + + def initialize + @email = QA::Runtime::Env.one_p_email + @password = QA::Runtime::Env.one_p_password + @secret = QA::Runtime::Env.one_p_secret + @github_uuid = QA::Runtime::Env.one_p_github_uuid + @address = 'gitlab.1password.com' + end + + def new_otp(old_otp = "") + # Fetches a new OTP that is not equal to the old OTP + new_otp = "" + time = Benchmark.realtime do + # An otp is valid for 30 seconds so 64 attempts with 0.5 interval are enough to ensure a new OTP is obtained + Support::Retrier.retry_until(max_attempts: 64, sleep_interval: 0.5) do + new_otp = current_otp + new_otp != old_otp + end + end + + QA::Runtime::Logger.info("Fetched new OTP in: #{time} seconds") + + new_otp + end + + def current_otp + result = nil + + time = Benchmark.realtime do + result = `op item get #{@github_uuid} --otp --session #{session_token}`.chop + end + + QA::Runtime::Logger.info("Fetched current OTP in: #{time} seconds") + + result + end + + private + + # OP session tokens are valid for 30 minutes. We are caching the session token here and this is fine currently + # as we just have one test that is not expected to go over 30 minutes. + # But note that if we add more tests that use this class, we might need to add a mechanism to invalidate + # the cache after 30 minutes or if the session_token is rejected by op CLI. + def session_token + @session_token ||= `echo '#{@password}' | op account add --address #{@address} --email #{@email} --secret-key #{@secret} --signin --raw` # rubocop:disable Layout/LineLength + end + end + end + end +end diff --git a/qa/tasks/ci.rake b/qa/tasks/ci.rake index aaf691de1b5..e5f4acb158b 100644 --- a/qa/tasks/ci.rake +++ b/qa/tasks/ci.rake @@ -32,7 +32,7 @@ namespace :ci do if run_all_label_present logger.info(" merge request has pipeline:run-all-e2e label, full test suite will be executed") - append_to_file(env_file, "QA_RUN_ALL_TESTS=true\n") + append_to_file(env_file, "QA_RUN_ALL_E2E_LABEL=true\n") elsif qa_changes.framework_changes? # run all tests when framework changes detected logger.info(" merge request contains qa framework changes, full test suite will be executed") append_to_file(env_file, "QA_FRAMEWORK_CHANGES=true\n") diff --git a/qa/tasks/webdrivers.rake b/qa/tasks/webdrivers.rake index f4fa3fab555..cd2a36ddf6b 100644 --- a/qa/tasks/webdrivers.rake +++ b/qa/tasks/webdrivers.rake @@ -1,4 +1,3 @@ # frozen_string_literal: true -require 'webdrivers' load 'webdrivers/Rakefile' |