Commit bf5e9d20 authored by Rémy Coutable's avatar Rémy Coutable

Fix including/prepending QA modules

This makes sure that `bundle exec bin/qa Test::Sanity::Selectors`
detects missing selectors in some cases where modules are included in
modules that are also included.
Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent 1aba995b
......@@ -162,6 +162,7 @@ module QA
autoload :Base, 'qa/page/base'
autoload :View, 'qa/page/view'
autoload :Element, 'qa/page/element'
autoload :PageConcern, 'qa/page/page_concern'
autoload :Validator, 'qa/page/validator'
autoload :Validatable, 'qa/page/validatable'
......@@ -248,7 +249,6 @@ module QA
end
module Settings
autoload :Common, 'qa/page/project/settings/common'
autoload :Advanced, 'qa/page/project/settings/advanced'
autoload :Main, 'qa/page/project/settings/main'
autoload :Repository, 'qa/page/project/settings/repository'
......
......@@ -5,8 +5,12 @@ module QA
module Page
module Admin
module Menu
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'app/views/layouts/nav/sidebar/_admin.html.haml' do
element :admin_settings_template_item
end
......
......@@ -7,8 +7,12 @@ module QA
module Overview
module Groups
module Edit
def self.included(page)
page.class_eval do
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
view 'ee/app/views/admin/_namespace_plan.html.haml' do
element :plan_dropdown
end
......
......@@ -5,8 +5,12 @@ module QA
module Page
module Component
module LicenseManagement
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'app/assets/javascripts/reports/components/report_item.vue' do
element :report_item_row
end
......
......@@ -5,8 +5,12 @@ module QA
module Page
module Component
module SecureReport
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/assets/javascripts/security_dashboard/components/filter.vue' do
element :filter_dropdown, ':data-qa-selector="qaSelector"' # rubocop:disable QA/ElementWithPattern
element :filter_dropdown_content
......
......@@ -6,8 +6,12 @@ module QA
module Component
module WebIDE
module WebTerminalPanel
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue' do
element :ide_right_sidebar, %q(:data-qa-selector="`ide_${side}_sidebar`") # rubocop:disable QA/ElementWithPattern
element :terminal_tab_button, %q(:data-qa-selector="`${tab.title.toLowerCase()}_tab_button`") # rubocop:disable QA/ElementWithPattern
......
......@@ -5,8 +5,12 @@ module QA
module Page
module Dashboard
module Projects
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'app/views/shared/projects/_list.html.haml' do
element :projects_list
end
......
......@@ -5,8 +5,12 @@ module QA
module Page
module File
module Show
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/views/projects/blob/_owners.html.haml' do
element :file_owner_content
element :link_file_owner
......
......@@ -5,10 +5,14 @@ module QA
module Page
module Group
module Menu
prepend QA::Page::Group::SubMenus::Common
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
prepend QA::Page::Group::SubMenus::Common
view 'ee/app/views/groups/ee/_settings_nav.html.haml' do
element :ldap_synchronization_link
element :audit_events_settings_link
......
......@@ -3,18 +3,20 @@
module QA
module EE
module Page
module Group::Secure
class Show < QA::Page::Base
include Page::Component::SecureReport
module Group
module Secure
class Show < QA::Page::Base
include Page::Component::SecureReport
view 'ee/app/assets/javascripts/security_dashboard/components/security_dashboard_table.vue' do
element :security_report_content, required: true
end
view 'ee/app/assets/javascripts/security_dashboard/components/security_dashboard_table.vue' do
element :security_report_content, required: true
end
def filter_project(project)
click_element(:filter_project_dropdown)
within_element(:filter_dropdown_content) do
click_on project
def filter_project(project)
click_element(:filter_project_dropdown)
within_element(:filter_dropdown_content) do
click_on project
end
end
end
end
......
......@@ -6,11 +6,15 @@ module QA
module Group
module Settings
module General
prepend ::QA::Page::Component::Select2
prepend ::QA::Page::Settings::Common
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
prepend ::QA::Page::Component::Select2
prepend ::QA::Page::Settings::Common
view 'ee/app/views/groups/_custom_project_templates_setting.html.haml' do
element :custom_project_template_select
element :custom_project_templates
......
......@@ -8,6 +8,7 @@ module QA
view 'ee/app/assets/javascripts/insights/components/insights.vue' do
element :insights_dashboard_dropdown
end
view 'ee/app/assets/javascripts/insights/components/insights_page.vue' do
element :insights_charts
element :insights_page
......
......@@ -5,10 +5,14 @@ module QA
module Page
module MergeRequest
module New
include QA::Page::Component::Select2
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
prepend ::QA::Page::Component::Select2
def self.prepended(page)
page.module_eval do
view 'ee/app/assets/javascripts/approvals/components/app.vue' do
element :add_approvers_button
end
......
......@@ -5,10 +5,14 @@ module QA
module Page
module MergeRequest
module Show
include Page::Component::LicenseManagement
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
prepend Page::Component::LicenseManagement
def self.prepended(page)
page.module_eval do
view 'app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue' do
element :head_mismatch, "The source branch HEAD has recently changed." # rubocop:disable QA/ElementWithPattern
end
......
......@@ -5,6 +5,8 @@ module QA
module Page
module Profile
module Menu
extend QA::Page::PageConcern
def wait_for_key_to_replicate(text, max_wait: Runtime::Geo.max_file_replication_time)
wait_until(max_duration: max_wait) { page.has_text?(text) }
end
......
......@@ -6,8 +6,12 @@ module QA
module Project
module Issue
module Index
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'app/views/shared/issuable/_search_bar.html.haml' do
element :issue_filter_form, /form_tag.+class: 'filter-form / # rubocop:disable QA/ElementWithPattern
element :issue_filter_input, /%input.form-control.filtered-search/ # rubocop:disable QA/ElementWithPattern
......
......@@ -6,8 +6,12 @@ module QA
module Project
module Issue
module Show
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/assets/javascripts/related_issues/components/add_issuable_form.vue' do
element :add_issue_button
end
......
......@@ -5,11 +5,20 @@ module QA
module Page
module Project
module Menu
prepend QA::Page::Project::SubMenus::Common
prepend SubMenus::SecurityCompliance
prepend SubMenus::Packages
prepend SubMenus::Project
prepend SubMenus::Settings
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
prepend QA::Page::Project::SubMenus::Common
prepend SubMenus::SecurityCompliance
prepend SubMenus::Packages
prepend SubMenus::Project
prepend SubMenus::Repository
prepend SubMenus::Settings
end
end
end
end
end
......
......@@ -5,8 +5,12 @@ module QA
module Page
module Project
module New
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/views/projects/_project_templates.html.haml' do
element :group_templates_tab
element :group_template_tab_badge
......
......@@ -7,8 +7,12 @@ module QA
module Operations
module Kubernetes
module Show
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/views/clusters/clusters/_health.html.haml' do
element :cluster_health_section
end
......
......@@ -7,10 +7,14 @@ module QA
module Operations
module Metrics
module Show
extend QA::Page::PageConcern
EXPECTED_LABEL = 'Total (GB)'
def self.prepended(page)
page.module_eval do
def self.prepended(base)
super
base.class_eval do
view 'app/assets/javascripts/monitoring/components/alert_widget_form.vue' do
element :alert_query_dropdown
element :alert_query_option
......
# frozen_string_literal: true
module QA::EE
module Page::Project
module Pipeline
module Show
include Page::Component::LicenseManagement
include Page::Component::SecureReport
module QA
module EE
module Page
module Project
module Pipeline
module Show
extend QA::Page::PageConcern
def self.prepended(page)
page.module_eval do
view 'ee/app/views/projects/pipelines/_tabs_holder.html.haml' do
element :security_tab
element :licenses_tab
element :licenses_counter
def self.prepended(base)
super
base.class_eval do
include Page::Component::LicenseManagement
include Page::Component::SecureReport
view 'ee/app/views/projects/pipelines/_tabs_holder.html.haml' do
element :security_tab
element :licenses_tab
element :licenses_counter
end
end
end
end
end
def click_on_security
click_element(:security_tab)
end
def click_on_security
click_element(:security_tab)
end
def click_on_licenses
click_element(:licenses_tab)
end
def click_on_licenses
click_element(:licenses_tab)
end
def has_license_count_of?(count)
find_element(:licenses_counter).has_content?(count)
def has_license_count_of?(count)
find_element(:licenses_counter).has_content?(count)
end
end
end
end
end
......
......@@ -3,14 +3,16 @@
module QA
module EE
module Page
module Project::Secure
class DependencyList < QA::Page::Base
view 'ee/app/assets/javascripts/dependencies/components/app.vue' do
element :dependency_list_all_count, "dependency_list_${label.toLowerCase().replace(' ', '_')" # rubocop:disable QA/ElementWithPattern
end
module Project
module Secure
class DependencyList < QA::Page::Base
view 'ee/app/assets/javascripts/dependencies/components/app.vue' do
element :dependency_list_all_count, "dependency_list_${label.toLowerCase().replace(' ', '_')" # rubocop:disable QA/ElementWithPattern
end
def has_dependency_count_of?(expected)
find_element(:dependency_list_all_count).has_content?(expected)
def has_dependency_count_of?(expected)
find_element(:dependency_list_all_count).has_content?(expected)
end
end
end
end
......
......@@ -3,12 +3,14 @@
module QA
module EE
module Page
module Project::Secure
class Show < QA::Page::Base
include Page::Component::SecureReport
module Project
module Secure
class Show < QA::Page::Base
include Page::Component::SecureReport
view 'ee/app/assets/javascripts/security_dashboard/components/security_dashboard_table.vue' do
element :security_report_content, required: true
view 'ee/app/assets/javascripts/security_dashboard/components/security_dashboard_table.vue' do
element :security_report_content, required: true
end
end
end
end
......
# frozen_string_literal: true
module QA::EE
module Page
module Project
module Settings
module CICD
def self.prepended(page)
page.module_eval do
view 'ee/app/views/projects/settings/ci_cd/_managed_licenses.html.haml' do
element :license_compliance_settings_content
module QA
module EE
module Page
module Project
module Settings
module CICD
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/views/projects/settings/ci_cd/_managed_licenses.html.haml' do
element :license_compliance_settings_content
end
end
end
end
def expand_license_compliance(&block)
expand_section(:license_compliance_settings_content) do
Settings::LicenseCompliance.perform(&block)
def expand_license_compliance(&block)
expand_section(:license_compliance_settings_content) do
Settings::LicenseCompliance.perform(&block)
end
end
end
end
......
# frozen_string_literal: true
module QA::EE
module Page
module Project
module Settings
class LicenseCompliance < QA::Page::Base
include QA::Page::Component::Select2 # Select2 is an external library, so we can't add our own selectors
module QA
module EE
module Page
module Project
module Settings
class LicenseCompliance < QA::Page::Base
include QA::Page::Component::Select2 # Select2 is an external library, so we can't add our own selectors
view 'ee/app/assets/javascripts/vue_shared/license_compliance/license_management.vue' do
element :license_add_button
end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/license_management.vue' do
element :license_add_button
end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/components/add_license_form.vue' do
element :license_radio, 'data-qa-selector="`${option.value}_license_radio`"' # rubocop:disable QA/ElementWithPattern
element :add_license_submit_button
end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/components/add_license_form.vue' do
element :license_radio, 'data-qa-selector="`${option.value}_license_radio`"' # rubocop:disable QA/ElementWithPattern
element :add_license_submit_button
end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/license_management.vue' do
element :license_compliance_list
end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/license_management.vue' do
element :license_compliance_list
end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/components/admin_license_management_row.vue' do
element :admin_license_compliance_row
element :license_name_content
end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/components/admin_license_management_row.vue' do
element :admin_license_compliance_row
element :license_name_content
end
view 'app/assets/javascripts/reports/components/issue_status_icon.vue' do
element :icon_status, ':data-qa-selector="`status_${status}_icon`" ' # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/reports/components/issue_status_icon.vue' do
element :icon_status, ':data-qa-selector="`status_${status}_icon`" ' # rubocop:disable QA/ElementWithPattern
end
def has_approved_license?(name)
within_element(:admin_license_compliance_row, text: name) do
has_element?(:status_success_icon)
def has_approved_license?(name)
within_element(:admin_license_compliance_row, text: name) do
has_element?(:status_success_icon)
end
end
end
def has_denied_license?(name)
within_element(:admin_license_compliance_row, text: name) do
has_element?(:status_failed_icon)
def has_denied_license?(name)
within_element(:admin_license_compliance_row, text: name) do
has_element?(:status_failed_icon)
end
end
end
def approve_license(license)
click_element :license_add_button
expand_select_list
search_and_select license
click_element :approved_license_radio
click_element :add_license_submit_button
def approve_license(license)
click_element :license_add_button
expand_select_list
search_and_select license
click_element :approved_license_radio
click_element :add_license_submit_button
has_approved_license? license
end
has_approved_license? license
end
def deny_license(license)
click_element :license_add_button
expand_select_list
search_and_select license
click_element :blacklisted_license_radio
click_element :add_license_submit_button
def deny_license(license)
click_element :license_add_button
expand_select_list
search_and_select license
click_element :blacklisted_license_radio
click_element :add_license_submit_button
has_denied_license? license
has_denied_license? license
end
end
end
end
......
......@@ -6,10 +6,14 @@ module QA
module Project
module Settings
module MergeRequest
include Page::Component::SecureReport
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
include Page::Component::SecureReport
def self.prepended(page)
page.module_eval do
view 'ee/app/views/projects/_merge_pipelines_settings.html.haml' do
element :merged_results_pipeline_checkbox
end
......
......@@ -6,8 +6,12 @@ module QA
module Project
module Settings
module MirroringRepositories
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/views/projects/mirrors/_mirror_repos_form.html.haml' do
element :mirror_direction
end
......
......@@ -6,8 +6,12 @@ module QA
module Project
module Settings
module ProtectedBranches
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/views/projects/protected_branches/ee/_create_protected_branch.html.haml' do
element :allowed_to_push_select
element :allowed_to_push_dropdown
......
......@@ -6,8 +6,12 @@ module QA
module Project
module Settings
module Repository
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/views/projects/push_rules/_index.html.haml' do
element :push_rules_content
end
......
......@@ -5,6 +5,8 @@ module QA
module Page
module Project
module Show
extend QA::Page::PageConcern
def wait_for_repository_replication(max_wait: Runtime::Geo.max_file_replication_time)
QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait_for_repository_replication])
wait_until_geo_max_replication_time(max_wait: max_wait) do
......
......@@ -6,8 +6,10 @@ module QA
module Project
module SubMenus
module Packages
def self.included(page)
page.class_eval do
extend QA::Page::PageConcern
def self.prepended(base)
base.class_eval do
view 'ee/app/views/layouts/nav/sidebar/_project_packages_link.html.haml' do
element :packages_link
end
......
......@@ -6,8 +6,10 @@ module QA
module Project
module SubMenus
module Repository
def self.included(page)
page.class_eval do
extend QA::Page::PageConcern
def self.prepended(base)
base.class_eval do
view 'ee/app/views/projects/sidebar/_repository_locked_files.html.haml' do
element :path_locks_link
end
......
......@@ -6,8 +6,10 @@ module QA
module Project
module SubMenus
module SecurityCompliance
def self.included(page)
page.class_eval do
extend QA::Page::PageConcern
def self.prepended(base)
base.class_eval do
view 'ee/app/views/layouts/nav/sidebar/_project_security_link.html.haml' do
element :security_dashboard_link
element :dependency_list_link
......
......@@ -6,10 +6,12 @@ module QA
module Project
module SubMenus
module Settings
include QA::Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
def self.prepended(base)
base.class_eval do
prepend QA::Page::Project::SubMenus::Common
view 'ee/app/views/projects/sidebar/_settings_audit_events.html.haml' do
element :audit_events_settings_link
end
......
......@@ -6,6 +6,8 @@ module QA
module Project
module Wiki
module Show
extend QA::Page::PageConcern
def wait_for_repository_replication(max_wait: Runtime::Geo.max_file_replication_time)
QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait_for_repository_replication])
wait_until_geo_max_replication_time(max_wait: max_wait) do
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module Breadcrumbs
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/layouts/nav/_breadcrumbs.html.haml' do
element :breadcrumb_links_content
end
......
......@@ -4,6 +4,8 @@ module QA
module Page
module Component
module CiBadgeLink
extend QA::Page::PageConcern
COMPLETED_STATUSES = %w[passed failed canceled blocked skipped manual].freeze # excludes created, pending, running
INCOMPLETE_STATUSES = %w[pending created running].freeze
......@@ -27,6 +29,8 @@ module QA
end
def self.included(base)
super
base.view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do
element :status_badge
end
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module ClonePanel
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/projects/buttons/_clone.html.haml' do
element :clone_dropdown
element :clone_options
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module ConfirmModal
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/shared/_confirm_modal.html.haml' do
element :confirm_modal
element :confirm_input
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module CustomMetric
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/custom_metrics/components/custom_metrics_form_fields.vue' do
element :custom_metric_prometheus_title_field
element :custom_metric_prometheus_query_field
......
......@@ -4,8 +4,10 @@ module QA
module Page
module Component
module DesignManagement
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
base.class_eval do
view 'app/assets/javascripts/design_management/components/design_notes/design_discussion.vue' do
element :design_discussion_content
end
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module GroupsFilter
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/shared/groups/_search_form.html.haml' do
element :groups_filter
end
......
......@@ -5,7 +5,11 @@ module QA
module Component
module Issuable
module Common
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/issue_show/components/title.vue' do
element :edit_button
element :title, required: true
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module LazyLoader
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/lazy_loader.js' do
element :js_lazy_loaded
end
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module LegacyClonePanel
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/shared/_clone_panel.html.haml' do
element :clone_dropdown
element :clone_options_dropdown, '.clone-options-dropdown' # rubocop:disable QA/ElementWithPattern
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module Note
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/notes/components/comment_form.vue' do
element :note_dropdown
element :discussion_option
......
......@@ -5,8 +5,12 @@ module QA
module Component
module WebIDE
module Alert
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'app/assets/javascripts/ide/components/error_message.vue' do
element :flash_alert
end
......
......@@ -5,7 +5,11 @@ module QA
module File
module Shared
module CommitButton
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/projects/_commit_button.html.haml' do
element :commit_button
end
......
......@@ -5,7 +5,11 @@ module QA
module File
module Shared
module CommitMessage
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/shared/_commit_message_container.html.haml' do
element :commit_message, "text_area_tag 'commit_message'" # rubocop:disable QA/ElementWithPattern
end
......
......@@ -5,7 +5,11 @@ module QA
module File
module Shared
module Editor
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/projects/blob/_editor.html.haml' do
element :editor
end
......
......@@ -5,9 +5,12 @@ module QA
module Group
module SubMenus
module Common
extend QA::Page::PageConcern
include QA::Page::SubMenus::Common
def self.included(base)
super
base.class_eval do
view 'app/views/layouts/nav/sidebar/_group.html.haml' do
element :group_sidebar
......
# frozen_string_literal: true
module QA
module Page::Main
class Terms < Page::Base
view 'app/views/layouts/terms.html.haml' do
element :user_avatar, required: true
end
module Page
module Main
class Terms < Page::Base
view 'app/views/layouts/terms.html.haml' do
element :user_avatar, required: true
end
view 'app/views/users/terms/index.html.haml' do
element :terms_content, required: true
view 'app/views/users/terms/index.html.haml' do
element :terms_content, required: true
element :accept_terms_button
end
element :accept_terms_button
end
def accept_terms
click_element :accept_terms_button, Page::Main::Menu
def accept_terms
click_element :accept_terms_button, Page::Main::Menu
end
end
end
end
......
module QA
module Page
module PageConcern
def included(base)
unless base.is_a?(Class)
raise "Expected #{self} to be prepended to a class, but #{base} is a module!"
end
unless base.ancestors.include?(::QA::Page::Base)
raise "Expected #{self} to be prepended to a class that inherits from ::QA::Page::Base, but #{base} doesn't!"
end
end
alias_method :prepended, :included
end
end
end
# frozen_string_literal: true
module QA::Page
module Project::Job
class Show < QA::Page::Base
include Component::CiBadgeLink
module QA
module Page
module Project
module Job
class Show < QA::Page::Base
include Component::CiBadgeLink
view 'app/assets/javascripts/jobs/components/log/log.vue' do
element :job_log_content
end
view 'app/assets/javascripts/jobs/components/log/log.vue' do
element :job_log_content
end
view 'app/assets/javascripts/jobs/components/stages_dropdown.vue' do
element :pipeline_path
end
view 'app/assets/javascripts/jobs/components/stages_dropdown.vue' do
element :pipeline_path
end
view 'app/assets/javascripts/jobs/components/sidebar.vue' do
element :retry_button
end
view 'app/assets/javascripts/jobs/components/sidebar.vue' do
element :retry_button
end
def successful?(timeout: 60)
raise "Timed out waiting for the build trace to load" unless loaded?
raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout)
def successful?(timeout: 60)
raise "Timed out waiting for the build trace to load" unless loaded?
raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout)
passed?
end
passed?
end
# Reminder: You may wish to wait for a particular job status before checking output
def output(wait: 5)
result = ''
# Reminder: You may wish to wait for a particular job status before checking output
def output(wait: 5)
result = ''
wait_until(reload: false, max_duration: wait, sleep_interval: 1) do
result = find_element(:job_log_content).text
wait_until(reload: false, max_duration: wait, sleep_interval: 1) do
result = find_element(:job_log_content).text
result.include?('Job')
end
result.include?('Job')
end
result
end
result
end
def retry!
click_element :retry_button
end
def retry!
click_element :retry_button
end
private
private
def loaded?(wait: 60)
wait_until(reload: true, max_duration: wait, sleep_interval: 1) do
has_element?(:job_log_content, wait: 1)
def loaded?(wait: 60)
wait_until(reload: true, max_duration: wait, sleep_interval: 1) do
has_element?(:job_log_content, wait: 1)
end
end
end
end
end
......
# frozen_string_literal: true
module QA::Page
module Project::Pipeline
class Index < QA::Page::Base
view 'app/assets/javascripts/pipelines/components/pipeline_url.vue' do
element :pipeline_url_link
end
view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do
element :pipeline_commit_status
element :pipeline_retry_button
end
def click_on_latest_pipeline
all_elements(:pipeline_url_link, minimum: 1, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).first.click
end
def wait_for_latest_pipeline_success
wait_for_latest_pipeline_status { has_text?('passed') }
end
def wait_for_latest_pipeline_completion
wait_for_latest_pipeline_status { has_text?('passed') || has_text?('failed') }
end
def wait_for_latest_pipeline_status
wait_until(reload: false, max_duration: 360) do
within_element_by_index(:pipeline_commit_status, 0) { yield }
end
end
def wait_for_latest_pipeline_success_or_retry
wait_for_latest_pipeline_completion
if has_text?('failed')
click_element :pipeline_retry_button
wait_for_latest_pipeline_success
module QA
module Page
module Project
module Pipeline
class Index < QA::Page::Base
view 'app/assets/javascripts/pipelines/components/pipeline_url.vue' do
element :pipeline_url_link
end
view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do
element :pipeline_commit_status
element :pipeline_retry_button
end
def click_on_latest_pipeline
all_elements(:pipeline_url_link, minimum: 1, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).first.click
end
def wait_for_latest_pipeline_success
wait_for_latest_pipeline_status { has_text?('passed') }
end
def wait_for_latest_pipeline_completion
wait_for_latest_pipeline_status { has_text?('passed') || has_text?('failed') }
end
def wait_for_latest_pipeline_status
wait_until(reload: false, max_duration: 360) do
within_element_by_index(:pipeline_commit_status, 0) { yield }
end
end
def wait_for_latest_pipeline_success_or_retry
wait_for_latest_pipeline_completion
if has_text?('failed')
click_element :pipeline_retry_button
wait_for_latest_pipeline_success
end
end
end
end
end
......
# frozen_string_literal: true
module QA::Page
module Project::Pipeline
class Show < QA::Page::Base
include Component::CiBadgeLink
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
element :pipeline_header, /header class.*ci-header-container.*/ # rubocop:disable QA/ElementWithPattern
end
module QA
module Page
module Project
module Pipeline
class Show < QA::Page::Base
include Component::CiBadgeLink
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
element :pipeline_header, /header class.*ci-header-container.*/ # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/pipelines/components/graph/graph_component.vue' do
element :pipeline_graph, /class.*pipeline-graph.*/ # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/pipelines/components/graph/graph_component.vue' do
element :pipeline_graph, /class.*pipeline-graph.*/ # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/pipelines/components/graph/job_item.vue' do
element :job_component, /class.*ci-job-component.*/ # rubocop:disable QA/ElementWithPattern
element :job_link
end
view 'app/assets/javascripts/pipelines/components/graph/job_item.vue' do
element :job_component, /class.*ci-job-component.*/ # rubocop:disable QA/ElementWithPattern
element :job_link
end
view 'app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
element :linked_pipeline_button
end
view 'app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
element :linked_pipeline_button
end
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/pipelines/_info.html.haml' do
element :pipeline_badges
end
view 'app/views/projects/pipelines/_info.html.haml' do
element :pipeline_badges
end
def running?(wait: 0)
within('.ci-header-container') do
page.has_content?('running', wait: wait)
end
end
def running?(wait: 0)
within('.ci-header-container') do
page.has_content?('running', wait: wait)
end
end
def has_build?(name, status: :success, wait: nil)
within('.pipeline-graph') do
within('.ci-job-component', text: name) do
has_selector?(".ci-status-icon-#{status}", { wait: wait }.compact)
def has_build?(name, status: :success, wait: nil)
within('.pipeline-graph') do
within('.ci-job-component', text: name) do
has_selector?(".ci-status-icon-#{status}", { wait: wait }.compact)
end
end
end
end
end
def has_job?(job_name)
has_element?(:job_link, text: job_name)
end
def has_job?(job_name)
has_element?(:job_link, text: job_name)
end
def has_no_job?(job_name)
has_no_element?(:job_link, text: job_name)
end
def has_no_job?(job_name)
has_no_element?(:job_link, text: job_name)
end
def has_tag?(tag_name)
within_element(:pipeline_badges) do
has_selector?('.badge', text: tag_name)
end
end
def has_tag?(tag_name)
within_element(:pipeline_badges) do
has_selector?('.badge', text: tag_name)
end
end
def click_job(job_name)
click_element(:job_link, text: job_name)
end
def click_job(job_name)
click_element(:job_link, text: job_name)
end
def click_linked_job(project_name)
click_element(:linked_pipeline_button, text: /#{project_name}/)
end
def click_linked_job(project_name)
click_element(:linked_pipeline_button, text: /#{project_name}/)
end
def click_on_first_job
first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click
def click_on_first_job
first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click
end
end
end
end
end
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class CICD < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/settings/ci_cd/show.html.haml' do
element :autodevops_settings_content
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class CiVariables < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue' do
element :ci_variable_key_field
......
# frozen_string_literal: true
module QA
module Page
module Project
module Settings
module Common
include QA::Page::Settings::Common
end
end
end
end
end
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class GeneralPipelines < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/settings/ci_cd/_form.html.haml' do
element :build_coverage_regex_field
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class Main < Page::Base
include Common
include QA::Page::Settings::Common
include Component::Select2
include SubMenus::Project
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class MergeRequest < QA::Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/edit.html.haml' do
element :save_merge_request_changes
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class Operations < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/settings/operations/_incidents.html.haml' do
element :incidents_settings_content
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class Repository < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/protected_branches/shared/_index.html.haml' do
element :protected_branches_settings
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module CiCd
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :link_pipelines
end
......
......@@ -5,6 +5,7 @@ module QA
module Project
module SubMenus
module Common
extend QA::Page::PageConcern
include QA::Page::SubMenus::Common
private
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Issues
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :issue_boards_link
element :issues_item
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Operations
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :operations_link
element :operations_environments_link
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Project
include Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :project_link
end
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Repository
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :project_menu_repo
element :branches_link
......@@ -44,5 +48,3 @@ module QA
end
end
end
QA::Page::Project::SubMenus::Repository.prepend_if_ee('QA::EE::Page::Project::SubMenus::Repository')
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Settings
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :settings_item
element :link_members_settings
......
# frozen_string_literal: true
module QA::Page
module Search
class Results < QA::Page::Base
view 'app/views/search/_category.html.haml' do
element :code_tab
element :projects_tab
end
module QA
module Page
module Search
class Results < QA::Page::Base
view 'app/views/search/_category.html.haml' do
element :code_tab
element :projects_tab
end
view 'app/views/search/results/_blob_data.html.haml' do
element :result_item_content
element :file_title_content
element :file_text_content
end
view 'app/views/search/results/_blob_data.html.haml' do
element :result_item_content
element :file_title_content
element :file_text_content
end
view 'app/views/shared/projects/_project.html.haml' do
element :project
end
view 'app/views/shared/projects/_project.html.haml' do
element :project
end
def switch_to_code
switch_to_tab(:code_tab)
end
def switch_to_code
switch_to_tab(:code_tab)
end
def switch_to_projects
switch_to_tab(:projects_tab)
end
def switch_to_projects
switch_to_tab(:projects_tab)
end
def has_file_in_project?(file_name, project_name)
has_element?(:result_item_content, text: "#{project_name}: #{file_name}")
end
def has_file_in_project?(file_name, project_name)
has_element?(:result_item_content, text: "#{project_name}: #{file_name}")
end
def has_file_with_content?(file_name, file_text)
within_element_by_index(:result_item_content, 0) do
break false unless has_element?(:file_title_content, text: file_name)
def has_file_with_content?(file_name, file_text)
within_element_by_index(:result_item_content, 0) do
break false unless has_element?(:file_title_content, text: file_name)
has_element?(:file_text_content, text: file_text)
has_element?(:file_text_content, text: file_text)
end
end
end
def has_project?(project_name)
has_element?(:project, project_name: project_name)
end
def has_project?(project_name)
has_element?(:project, project_name: project_name)
end
private
private
def switch_to_tab(tab)
retry_until do
click_element(tab)
has_active_element?(tab)
def switch_to_tab(tab)
retry_until do
click_element(tab)
has_active_element?(tab)
end
end
end
end
......
......@@ -2,83 +2,87 @@
require 'rspec/core'
module QA::Specs::Helpers
module Quarantine
include RSpec::Core::Pending
module QA
module Specs
module Helpers
module Quarantine
include RSpec::Core::Pending
extend self
extend self
def configure_rspec
RSpec.configure do |config|
config.before(:context, :quarantine) do
Quarantine.skip_or_run_quarantined_contexts(config.inclusion_filter.rules, self.class)
end
def configure_rspec
RSpec.configure do |config|
config.before(:context, :quarantine) do
Quarantine.skip_or_run_quarantined_contexts(config.inclusion_filter.rules, self.class)
end
config.before do |example|
Quarantine.skip_or_run_quarantined_tests_or_contexts(config.inclusion_filter.rules, example)
config.before do |example|
Quarantine.skip_or_run_quarantined_tests_or_contexts(config.inclusion_filter.rules, example)
end
end
end
end
end
# Skip the entire context if a context is quarantined. This avoids running
# before blocks unnecessarily.
def skip_or_run_quarantined_contexts(filters, example)
return unless example.metadata.key?(:quarantine)
# Skip the entire context if a context is quarantined. This avoids running
# before blocks unnecessarily.
def skip_or_run_quarantined_contexts(filters, example)
return unless example.metadata.key?(:quarantine)
skip_or_run_quarantined_tests_or_contexts(filters, example)
end
skip_or_run_quarantined_tests_or_contexts(filters, example)
end
# Skip tests in quarantine unless we explicitly focus on them.
def skip_or_run_quarantined_tests_or_contexts(filters, example)
if filters.key?(:quarantine)
included_filters = filters_other_than_quarantine(filters)
# Skip tests in quarantine unless we explicitly focus on them.
def skip_or_run_quarantined_tests_or_contexts(filters, example)
if filters.key?(:quarantine)
included_filters = filters_other_than_quarantine(filters)
# If :quarantine is focused, skip the test/context unless its metadata
# includes quarantine and any other filters
# E.g., Suppose a test is tagged :smoke and :quarantine, and another is tagged
# :ldap and :quarantine. If we wanted to run just quarantined smoke tests
# using `--tag quarantine --tag smoke`, without this check we'd end up
# running that ldap test as well because of the :quarantine metadata.
# We could use an exclusion filter, but this way the test report will list
# the quarantined tests when they're not run so that we're aware of them
skip("Only running tests tagged with :quarantine and any of #{included_filters.keys}") if should_skip_when_focused?(example.metadata, included_filters)
else
if example.metadata.key?(:quarantine)
quarantine_message = %w(In quarantine)
quarantine_tag = example.metadata[:quarantine]
# If :quarantine is focused, skip the test/context unless its metadata
# includes quarantine and any other filters
# E.g., Suppose a test is tagged :smoke and :quarantine, and another is tagged
# :ldap and :quarantine. If we wanted to run just quarantined smoke tests
# using `--tag quarantine --tag smoke`, without this check we'd end up
# running that ldap test as well because of the :quarantine metadata.
# We could use an exclusion filter, but this way the test report will list
# the quarantined tests when they're not run so that we're aware of them
skip("Only running tests tagged with :quarantine and any of #{included_filters.keys}") if should_skip_when_focused?(example.metadata, included_filters)
else
if example.metadata.key?(:quarantine)
quarantine_message = %w(In quarantine)
quarantine_tag = example.metadata[:quarantine]
if !!quarantine_tag
quarantine_message << case quarantine_tag
when String
": #{quarantine_tag}"
when Hash
": #{quarantine_tag[:issue]}"
else
''
end
end
if !!quarantine_tag
quarantine_message << case quarantine_tag
when String
": #{quarantine_tag}"
when Hash
": #{quarantine_tag[:issue]}"
else
''
end
end
skip(quarantine_message.join(' ').strip)
skip(quarantine_message.join(' ').strip)
end
end
end
end
end
def filters_other_than_quarantine(filter)
filter.reject { |key, _| key == :quarantine }
end
def filters_other_than_quarantine(filter)
filter.reject { |key, _| key == :quarantine }
end
# Checks if a test or context should be skipped.
#
# Returns true if
# - the metadata does not includes the :quarantine tag
# or if
# - the metadata includes the :quarantine tag
# - and the filter includes other tags that aren't in the metadata
def should_skip_when_focused?(metadata, included_filters)
return true unless metadata.key?(:quarantine)
return false if included_filters.empty?
# Checks if a test or context should be skipped.
#
# Returns true if
# - the metadata does not includes the :quarantine tag
# or if
# - the metadata includes the :quarantine tag
# - and the filter includes other tags that aren't in the metadata
def should_skip_when_focused?(metadata, included_filters)
return true unless metadata.key?(:quarantine)
return false if included_filters.empty?
(metadata.keys & included_filters.keys).empty?
(metadata.keys & included_filters.keys).empty?
end
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment