Commit b8e3a3de authored by Stan Hu's avatar Stan Hu

Merge branch 'qa-add-a-cop-to-forbit-element-with-pattern' into 'master'

Add a new QA::ElementWithPattern cop

Closes #52516

See merge request gitlab-org/gitlab-ce!22298
parents 3c15a20b 1db52c79
......@@ -70,15 +70,15 @@ module Page
module Main
class Login < Page::Base
view 'app/views/devise/passwords/edit.html.haml' do
element :password_field, 'password_field :password'
element :password_confirmation, 'password_field :password_confirmation'
element :change_password_button, 'submit "Change your password"'
element :password_field
element :password_confirmation
element :change_password_button
end
view 'app/views/devise/sessions/_new_base.html.haml' do
element :login_field, 'text_field :login'
element :password_field, 'password_field :password'
element :sign_in_button, 'submit "Sign in"'
element :login_field
element :password_field
element :sign_in_button
end
# ...
......@@ -87,23 +87,31 @@ end
```
The `view` DSL method declares the filename of the view where an
`element` is implmented.
`element` is implemented.
The `element` DSL method in turn declares an element and defines a value
to match to the actual view code. It is possible to use `element` with value,
with a String value or with a Regexp.
The `element` DSL method in turn declares an element for which a corresponding
`qa-element-name-dasherized` CSS class need to be added to the view file.
You can also define a value (String or Regexp) to match to the actual view
code but **this is deprecated** in favor of the above method for two reasons:
- Consistency: there is only one way to define an element
- Separation of concerns: QA uses dedicated CSS classes instead of reusing code
or classes used by other components (e.g. `js-*` classes etc.)
```ruby
view 'app/views/my/view.html.haml' do
# Implicitly require `.qa-logout-button` CSS class to be present in the view
element :logout_button
## This is deprecated and forbidden by the `QA/ElementWithPattern` RuboCop cop.
# Require `f.submit "Sign in"` to be present in `my/view.html.haml
element :my_button, 'f.submit "Sign in"'
element :my_button, 'f.submit "Sign in"' # rubocop:disable QA/ElementWithPattern
## This is deprecated and forbidden by the `QA/ElementWithPattern` RuboCop cop.
# Match every line in `my/view.html.haml` against
# `/link_to .* "My Profile"/` regexp.
element :profile_link, /link_to .* "My Profile"/
# Implicitly require `.qa-logout-button` CSS class to be present in the view
element :logout_button
element :profile_link, /link_to .* "My Profile"/ # rubocop:disable QA/ElementWithPattern
end
```
......
......@@ -7,8 +7,8 @@ module QA
def self.included(base)
base.view 'app/views/shared/_clone_panel.html.haml' do
element :clone_dropdown
element :clone_options_dropdown, '.clone-options-dropdown'
element :project_repository_location, 'text_field_tag :project_clone'
element :clone_options_dropdown, '.clone-options-dropdown' # rubocop:disable QA/ElementWithPattern
element :project_repository_location, 'text_field_tag :project_clone' # rubocop:disable QA/ElementWithPattern
end
end
......
......@@ -7,12 +7,12 @@ module QA
include Page::Component::GroupsFilter
view 'app/views/shared/groups/_search_form.html.haml' do
element :groups_filter, 'search_field_tag :filter'
element :groups_filter_placeholder, 'Search by name'
element :groups_filter, 'search_field_tag :filter' # rubocop:disable QA/ElementWithPattern
element :groups_filter_placeholder, 'Search by name' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/dashboard/_groups_head.html.haml' do
element :new_group_button, 'link_to _("New group")'
element :new_group_button, 'link_to _("New group")' # rubocop:disable QA/ElementWithPattern
end
def has_group?(name)
......
......@@ -5,7 +5,7 @@ module QA
view 'app/views/dashboard/projects/index.html.haml'
view 'app/views/shared/projects/_search_form.html.haml' do
element :form_filter_by_name, /form_tag.+id: 'project-filter-form'/
element :form_filter_by_name, /form_tag.+id: 'project-filter-form'/ # rubocop:disable QA/ElementWithPattern
end
def go_to_project(name)
......
......@@ -6,12 +6,12 @@ module QA
include Page::Component::DropdownFilter
view 'app/views/projects/blob/_editor.html.haml' do
element :file_name, "text_field_tag 'file_name'"
element :editor, '#editor'
element :file_name, "text_field_tag 'file_name'" # rubocop:disable QA/ElementWithPattern
element :editor, '#editor' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/_commit_button.html.haml' do
element :commit_changes, "button_tag 'Commit changes'"
element :commit_changes, "button_tag 'Commit changes'" # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/blob/_template_selectors.html.haml' do
......
......@@ -5,7 +5,7 @@ module QA
module CommitMessage
def self.included(base)
base.view 'app/views/shared/_commit_message_container.html.haml' do
element :commit_message, "text_area_tag 'commit_message'"
element :commit_message, "text_area_tag 'commit_message'" # rubocop:disable QA/ElementWithPattern
end
end
......
......@@ -5,12 +5,12 @@ module QA
include Shared::CommitMessage
view 'app/helpers/blob_helper.rb' do
element :edit_button, "_('Edit')"
element :delete_button, /label:\s+"Delete"/
element :edit_button, "_('Edit')" # rubocop:disable QA/ElementWithPattern
element :delete_button, /label:\s+"Delete"/ # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/blob/_remove.html.haml' do
element :delete_file_button, "button_tag 'Delete file'"
element :delete_file_button, "button_tag 'Delete file'" # rubocop:disable QA/ElementWithPattern
end
def click_edit
......
......@@ -3,14 +3,14 @@ module QA
module Group
class New < Page::Base
view 'app/views/shared/_group_form.html.haml' do
element :group_path_field, 'text_field :path'
element :group_name_field, 'text_field :name'
element :group_description_field, 'text_area :description'
element :group_path_field, 'text_field :path' # rubocop:disable QA/ElementWithPattern
element :group_name_field, 'text_field :name' # rubocop:disable QA/ElementWithPattern
element :group_description_field, 'text_area :description' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/groups/new.html.haml' do
element :create_group_button, "submit 'Create group'"
element :visibility_radios, 'visibility_level:'
element :create_group_button, "submit 'Create group'" # rubocop:disable QA/ElementWithPattern
element :visibility_radios, 'visibility_level:' # rubocop:disable QA/ElementWithPattern
end
def set_path(path)
......
......@@ -15,7 +15,7 @@ module QA
end
view 'app/assets/javascripts/groups/constants.js' do
element :no_result_text, 'No groups or projects matched your search'
element :no_result_text, 'No groups or projects matched your search' # rubocop:disable QA/ElementWithPattern
end
def go_to_subgroup(name)
......
......@@ -3,8 +3,8 @@ module QA
module Issuable
class Sidebar < Page::Base
view 'app/views/shared/issuable/_sidebar.html.haml' do
element :labels_block, ".issuable-show-labels"
element :milestones_block, '.block.milestone'
element :labels_block, ".issuable-show-labels" # rubocop:disable QA/ElementWithPattern
element :milestones_block, '.block.milestone' # rubocop:disable QA/ElementWithPattern
end
def has_label?(label)
......
......@@ -3,7 +3,7 @@ module QA
module Layout
class Banner < Page::Base
view 'app/views/layouts/header/_read_only_banner.html.haml' do
element :flash_notice, ".flash-notice"
element :flash_notice, ".flash-notice" # rubocop:disable QA/ElementWithPattern
end
def has_notice?(message)
......
......@@ -5,14 +5,14 @@ module QA
module Main
class Menu < Page::Base
view 'app/views/layouts/header/_current_user_dropdown.html.haml' do
element :user_sign_out_link, 'link_to _("Sign out")'
element :settings_link, 'link_to s_("CurrentUser|Settings")'
element :user_sign_out_link, 'link_to _("Sign out")' # rubocop:disable QA/ElementWithPattern
element :settings_link, 'link_to s_("CurrentUser|Settings")' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/layouts/header/_default.html.haml' do
element :navbar
element :user_avatar
element :user_menu, '.dropdown-menu'
element :user_menu, '.dropdown-menu' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/layouts/nav/_dashboard.html.haml' do
......
......@@ -3,7 +3,7 @@ module QA
module Main
class OAuth < Page::Base
view 'app/views/doorkeeper/authorizations/new.html.haml' do
element :authorization_button, 'submit_tag _("Authorize")'
element :authorization_button, 'submit_tag _("Authorize")' # rubocop:disable QA/ElementWithPattern
end
def needs_authorization?
......
......@@ -4,19 +4,19 @@ module QA
class Show < Page::Base
view 'app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue' do
element :merge_button
element :fast_forward_message, 'Fast-forward merge without a merge commit'
element :fast_forward_message, 'Fast-forward merge without a merge commit' # rubocop:disable QA/ElementWithPattern
element :merge_moment_dropdown
element :merge_when_pipeline_succeeds_option
element :merge_immediately_option
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue' do
element :merged_status, 'The changes were merged into'
element :merged_status, 'The changes were merged into' # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue' do
element :mr_rebase_button
element :no_fast_forward_message, 'Fast-forward merge is not possible'
element :no_fast_forward_message, 'Fast-forward merge is not possible' # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue' do
......
......@@ -5,10 +5,10 @@ module QA
module Profile
class Menu < Page::Base
view 'app/views/layouts/nav/sidebar/_profile.html.haml' do
element :access_token_link, 'link_to profile_personal_access_tokens_path'
element :access_token_title, 'Access Tokens'
element :top_level_items, '.sidebar-top-level-items'
element :ssh_keys, 'SSH Keys'
element :access_token_link, 'link_to profile_personal_access_tokens_path' # rubocop:disable QA/ElementWithPattern
element :access_token_title, 'Access Tokens' # rubocop:disable QA/ElementWithPattern
element :top_level_items, '.sidebar-top-level-items' # rubocop:disable QA/ElementWithPattern
element :ssh_keys, 'SSH Keys' # rubocop:disable QA/ElementWithPattern
end
def click_access_tokens
......
......@@ -3,13 +3,13 @@ module QA
module Profile
class PersonalAccessTokens < Page::Base
view 'app/views/shared/_personal_access_tokens_form.html.haml' do
element :personal_access_token_name_field, 'text_field :name'
element :create_token_button, 'submit "Create #{type} token"' # rubocop:disable Lint/InterpolationCheck
element :scopes_api_radios, "label :scopes"
element :personal_access_token_name_field, 'text_field :name' # rubocop:disable QA/ElementWithPattern
element :create_token_button, 'submit "Create #{type} token"' # rubocop:disable QA/ElementWithPattern, Lint/InterpolationCheck
element :scopes_api_radios, "label :scopes" # rubocop:disable QA/ElementWithPattern
end
view 'app/views/profiles/personal_access_tokens/index.html.haml' do
element :create_token_field, "text_field_tag 'created-personal-access-token'"
element :create_token_field, "text_field_tag 'created-personal-access-token'" # rubocop:disable QA/ElementWithPattern
end
def fill_token_name(name)
......
......@@ -3,7 +3,7 @@ module QA
module Project
class Activity < Page::Base
view 'app/views/shared/_event_filter.html.haml' do
element :push_events, "event_filter_link EventFilter::PUSH, _('Push events')"
element :push_events, "event_filter_link EventFilter::PUSH, _('Push events')" # rubocop:disable QA/ElementWithPattern
end
def go_to_push_events
......
......@@ -4,7 +4,7 @@ module QA
module Fork
class New < Page::Base
view 'app/views/projects/forks/_fork_button.html.haml' do
element :namespace, 'link_to project_forks_path'
element :namespace, 'link_to project_forks_path' # rubocop:disable QA/ElementWithPattern
end
def choose_namespace(namespace = Runtime::Namespace.path)
......
......@@ -6,16 +6,16 @@ module QA
include Page::Component::Select2
view 'app/views/import/github/new.html.haml' do
element :personal_access_token_field, 'text_field_tag :personal_access_token'
element :list_repos_button, "submit_tag _('List your GitHub repositories')"
element :personal_access_token_field, 'text_field_tag :personal_access_token' # rubocop:disable QA/ElementWithPattern
element :list_repos_button, "submit_tag _('List your GitHub repositories')" # rubocop:disable QA/ElementWithPattern
end
view 'app/views/import/_githubish_status.html.haml' do
element :project_import_row, 'data: { qa: { repo_path: repo.full_name } }'
element :project_import_row, 'data: { qa: { repo_path: repo.full_name } }' # rubocop:disable QA/ElementWithPattern
element :project_namespace_select
element :project_namespace_field, 'select_tag :namespace_id'
element :project_path_field, 'text_field_tag :path, sanitize_project_name(repo.name)'
element :import_button, "_('Import')"
element :project_namespace_field, 'select_tag :namespace_id' # rubocop:disable QA/ElementWithPattern
element :project_path_field, 'text_field_tag :path, sanitize_project_name(repo.name)' # rubocop:disable QA/ElementWithPattern
element :import_button, "_('Import')" # rubocop:disable QA/ElementWithPattern
end
def add_personal_access_token(personal_access_token)
......
......@@ -4,7 +4,7 @@ module QA
module Issue
class Index < Page::Base
view 'app/views/projects/issues/_issue.html.haml' do
element :issue_link, 'link_to issue.title'
element :issue_link, 'link_to issue.title' # rubocop:disable QA/ElementWithPattern
end
def go_to_issue(title)
......
......@@ -4,15 +4,15 @@ module QA
module Issue
class New < Page::Base
view 'app/views/shared/issuable/_form.html.haml' do
element :submit_issue_button, 'form.submit "Submit'
element :submit_issue_button, 'form.submit "Submit' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/shared/issuable/form/_title.html.haml' do
element :issue_title_textbox, 'form.text_field :title'
element :issue_title_textbox, 'form.text_field :title' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/shared/form_elements/_description.html.haml' do
element :issue_description_textarea, "render 'projects/zen', f: form, attr: :description"
element :issue_description_textarea, "render 'projects/zen', f: form, attr: :description" # rubocop:disable QA/ElementWithPattern
end
def add_title(title)
......
......@@ -8,17 +8,17 @@ module QA
include Page::Component::Issuable::Common
view 'app/views/projects/issues/show.html.haml' do
element :issue_details, '.issue-details'
element :title, '.title'
element :issue_details, '.issue-details' # rubocop:disable QA/ElementWithPattern
element :title, '.title' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/shared/notes/_form.html.haml' do
element :new_note_form, 'new-note'
element :new_note_form, 'attr: :note'
element :new_note_form, 'new-note' # rubocop:disable QA/ElementWithPattern
element :new_note_form, 'attr: :note' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/shared/notes/_comment_button.html.haml' do
element :comment_button, '%strong Comment'
element :comment_button, '%strong Comment' # rubocop:disable QA/ElementWithPattern
end
def issue_title
......
......@@ -5,12 +5,12 @@ module QA::Page
PASSED_STATUS = 'passed'.freeze
view 'app/views/shared/builds/_build_output.html.haml' do
element :build_output, '.js-build-output'
element :loading_animation, '.js-build-refresh'
element :build_output, '.js-build-output' # rubocop:disable QA/ElementWithPattern
element :loading_animation, '.js-build-refresh' # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do
element :status_badge, 'ci-status'
element :status_badge, 'ci-status' # rubocop:disable QA/ElementWithPattern
end
def completed?
......
......@@ -6,26 +6,26 @@ module QA
class Menu < Page::Base
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :settings_item
element :settings_link, 'link_to edit_project_path'
element :repository_link, "title: _('Repository')"
element :settings_link, 'link_to edit_project_path' # rubocop:disable QA/ElementWithPattern
element :repository_link, "title: _('Repository')" # rubocop:disable QA/ElementWithPattern
element :link_pipelines
element :link_members_settings
element :pipelines_settings_link, "title: _('CI / CD')"
element :operations_kubernetes_link, "title: _('Kubernetes')"
element :pipelines_settings_link, "title: _('CI / CD')" # rubocop:disable QA/ElementWithPattern
element :operations_kubernetes_link, "title: _('Kubernetes')" # rubocop:disable QA/ElementWithPattern
element :operations_environments_link
element :issues_link, /link_to.*shortcuts-issues/
element :issues_link_text, "Issues"
element :merge_requests_link, /link_to.*shortcuts-merge_requests/
element :merge_requests_link_text, "Merge Requests"
element :top_level_items, '.sidebar-top-level-items'
element :operations_section, "class: 'shortcuts-operations'"
element :activity_link, "title: _('Activity')"
element :wiki_link_text, "Wiki"
element :issues_link, /link_to.*shortcuts-issues/ # rubocop:disable QA/ElementWithPattern
element :issues_link_text, "Issues" # rubocop:disable QA/ElementWithPattern
element :merge_requests_link, /link_to.*shortcuts-merge_requests/ # rubocop:disable QA/ElementWithPattern
element :merge_requests_link_text, "Merge Requests" # rubocop:disable QA/ElementWithPattern
element :top_level_items, '.sidebar-top-level-items' # rubocop:disable QA/ElementWithPattern
element :operations_section, "class: 'shortcuts-operations'" # rubocop:disable QA/ElementWithPattern
element :activity_link, "title: _('Activity')" # rubocop:disable QA/ElementWithPattern
element :wiki_link_text, "Wiki" # rubocop:disable QA/ElementWithPattern
element :milestones_link
end
view 'app/assets/javascripts/fly_out_nav.js' do
element :fly_out, "classList.add('fly-out-list')"
element :fly_out, "classList.add('fly-out-list')" # rubocop:disable QA/ElementWithPattern
end
def click_repository_settings
......
......@@ -5,21 +5,21 @@ module QA
include Page::Component::Select2
view 'app/views/projects/new.html.haml' do
element :import_project_tab, "Import project"
element :import_project_tab, "Import project" # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/_new_project_fields.html.haml' do
element :project_namespace_select
element :project_namespace_field, 'namespaces_options'
element :project_name, 'text_field :name'
element :project_path, 'text_field :path'
element :project_description, 'text_area :description'
element :project_create_button, "submit 'Create project'"
element :visibility_radios, 'visibility_level:'
element :project_namespace_field, 'namespaces_options' # rubocop:disable QA/ElementWithPattern
element :project_name, 'text_field :name' # rubocop:disable QA/ElementWithPattern
element :project_path, 'text_field :path' # rubocop:disable QA/ElementWithPattern
element :project_description, 'text_area :description' # rubocop:disable QA/ElementWithPattern
element :project_create_button, "submit 'Create project'" # rubocop:disable QA/ElementWithPattern
element :visibility_radios, 'visibility_level:' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/_import_project_pane.html.haml' do
element :import_github, "icon('github', text: 'GitHub')"
element :import_github, "icon('github', text: 'GitHub')" # rubocop:disable QA/ElementWithPattern
end
def choose_test_namespace
......
......@@ -5,7 +5,7 @@ module QA
module Kubernetes
class Add < Page::Base
view 'app/views/projects/clusters/new.html.haml' do
element :add_existing_cluster_button, "Add existing cluster"
element :add_existing_cluster_button, "Add existing cluster" # rubocop:disable QA/ElementWithPattern
end
def add_existing_cluster
......
......@@ -5,11 +5,11 @@ module QA
module Kubernetes
class AddExisting < Page::Base
view 'app/views/projects/clusters/user/_form.html.haml' do
element :cluster_name, 'text_field :name'
element :api_url, 'text_field :api_url'
element :ca_certificate, 'text_area :ca_cert'
element :token, 'text_field :token'
element :add_cluster_button, "submit s_('ClusterIntegration|Add Kubernetes cluster')"
element :cluster_name, 'text_field :name' # rubocop:disable QA/ElementWithPattern
element :api_url, 'text_field :api_url' # rubocop:disable QA/ElementWithPattern
element :ca_certificate, 'text_area :ca_cert' # rubocop:disable QA/ElementWithPattern
element :token, 'text_field :token' # rubocop:disable QA/ElementWithPattern
element :add_cluster_button, "submit s_('ClusterIntegration|Add Kubernetes cluster')" # rubocop:disable QA/ElementWithPattern
element :rbac_checkbox
end
......
......@@ -5,7 +5,7 @@ module QA
module Kubernetes
class Index < Page::Base
view 'app/views/projects/clusters/_empty_state.html.haml' do
element :add_kubernetes_cluster_button, "link_to s_('ClusterIntegration|Add Kubernetes cluster')"
element :add_kubernetes_cluster_button, "link_to s_('ClusterIntegration|Add Kubernetes cluster')" # rubocop:disable QA/ElementWithPattern
end
def add_kubernetes_cluster
......
......@@ -5,13 +5,13 @@ module QA
module Kubernetes
class Show < Page::Base
view 'app/assets/javascripts/clusters/components/application_row.vue' do
element :application_row, 'js-cluster-application-row-${this.id}'
element :install_button, "s__('ClusterIntegration|Install')"
element :installed_button, "s__('ClusterIntegration|Installed')"
element :application_row, 'js-cluster-application-row-${this.id}' # rubocop:disable QA/ElementWithPattern
element :install_button, "s__('ClusterIntegration|Install')" # rubocop:disable QA/ElementWithPattern
element :installed_button, "s__('ClusterIntegration|Installed')" # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/clusters/components/applications.vue' do
element :ingress_ip_address, 'id="ingress-ip-address"'
element :ingress_ip_address, 'id="ingress-ip-address"' # rubocop:disable QA/ElementWithPattern
end
def install!(application_name)
......
......@@ -2,7 +2,7 @@ module QA::Page
module Project::Pipeline
class Index < QA::Page::Base
view 'app/assets/javascripts/pipelines/components/pipeline_url.vue' do
element :pipeline_link, 'class="js-pipeline-url-link"'
element :pipeline_link, 'class="js-pipeline-url-link"' # rubocop:disable QA/ElementWithPattern
end
def go_to_latest_pipeline
......
......@@ -2,20 +2,20 @@ module QA::Page
module Project::Pipeline
class Show < QA::Page::Base
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
element :pipeline_header, /header class.*ci-header-container.*/
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.*/
element :pipeline_graph, /class.*pipeline-graph.*/ # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/pipelines/components/graph/job_component.vue' do
element :job_component, /class.*ci-job-component.*/
element :job_link, /class.*js-pipeline-graph-job-link.*/
element :job_component, /class.*ci-job-component.*/ # rubocop:disable QA/ElementWithPattern
element :job_link, /class.*js-pipeline-graph-job-link.*/ # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
element :status_icon, 'ci-status-icon-${status}'
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
end
def running?
......
......@@ -4,9 +4,9 @@ module QA
module Settings
class Advanced < Page::Base
view 'app/views/projects/edit.html.haml' do
element :project_path_field, 'text_field :path'
element :project_name_field, 'text_field :name'
element :rename_project_button, "submit 'Rename project'"
element :project_path_field, 'text_field :path' # rubocop:disable QA/ElementWithPattern
element :project_name_field, 'text_field :name' # rubocop:disable QA/ElementWithPattern
element :rename_project_button, "submit 'Rename project'" # rubocop:disable QA/ElementWithPattern
end
def rename_to(path)
......
......@@ -12,11 +12,11 @@ module QA # rubocop:disable Naming/FileName
end
view 'app/views/projects/settings/ci_cd/_autodevops_form.html.haml' do
element :enable_auto_devops_field, 'check_box :enabled'
element :domain_field, 'text_field :domain'
element :enable_auto_devops_button, "%strong= s_('CICD|Default to Auto DevOps pipeline')"
element :domain_input, "%strong= _('Domain')"
element :save_changes_button, "submit _('Save changes')"
element :enable_auto_devops_field, 'check_box :enabled' # rubocop:disable QA/ElementWithPattern
element :domain_field, 'text_field :domain' # rubocop:disable QA/ElementWithPattern
element :enable_auto_devops_button, "%strong= s_('CICD|Default to Auto DevOps pipeline')" # rubocop:disable QA/ElementWithPattern
element :domain_input, "%strong= _('Domain')" # rubocop:disable QA/ElementWithPattern
element :save_changes_button, "submit _('Save changes')" # rubocop:disable QA/ElementWithPattern
end
def expand_runners_settings(&block)
......
......@@ -8,7 +8,7 @@ module QA
def self.included(base)
base.class_eval do
view 'app/views/projects/edit.html.haml' do
element :advanced_settings_expand, "= expanded ? 'Collapse' : 'Expand'"
element :advanced_settings_expand, "= expanded ? 'Collapse' : 'Expand'" # rubocop:disable QA/ElementWithPattern
end
end
end
......
......@@ -4,18 +4,18 @@ module QA
module Settings
class DeployKeys < Page::Base
view 'app/views/projects/deploy_keys/_form.html.haml' do
element :deploy_key_title, 'text_field :title'
element :deploy_key_key, 'text_area :key'
element :deploy_key_title, 'text_field :title' # rubocop:disable QA/ElementWithPattern
element :deploy_key_key, 'text_area :key' # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/deploy_keys/components/app.vue' do
element :deploy_keys_section, /class=".*deploy\-keys.*"/
element :project_deploy_keys, 'class="qa-project-deploy-keys"'
element :deploy_keys_section, /class=".*deploy\-keys.*"/ # rubocop:disable QA/ElementWithPattern
element :project_deploy_keys, 'class="qa-project-deploy-keys"' # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/deploy_keys/components/key.vue' do
element :key_title, /class=".*qa-key-title.*"/
element :key_fingerprint, /class=".*qa-key-fingerprint.*"/
element :key_title, /class=".*qa-key-title.*"/ # rubocop:disable QA/ElementWithPattern
element :key_fingerprint, /class=".*qa-key-fingerprint.*"/ # rubocop:disable QA/ElementWithPattern
end
def fill_key_title(title)
......
......@@ -4,8 +4,8 @@ module QA
module Settings
class Runners < Page::Base
view 'app/views/ci/runner/_how_to_setup_runner.html.haml' do
element :registration_token, '%code#registration_token'
element :coordinator_address, '%code#coordinator_address'
element :registration_token, '%code#registration_token' # rubocop:disable QA/ElementWithPattern
element :coordinator_address, '%code#coordinator_address' # rubocop:disable QA/ElementWithPattern
end
##
......@@ -13,7 +13,7 @@ module QA
#
view 'app/helpers/runners_helper.rb' do
# rubocop:disable Lint/InterpolationCheck
element :runner_status, 'runner-status-#{status}'
element :runner_status, 'runner-status-#{status}' # rubocop:disable QA/ElementWithPattern
# rubocop:enable Lint/InterpolationCheck
end
......
......@@ -6,14 +6,14 @@ module QA
include Common
view 'app/views/ci/variables/_variable_row.html.haml' do
element :variable_row, '.ci-variable-row-body'
element :variable_key, '.qa-ci-variable-input-key'
element :variable_value, '.qa-ci-variable-input-value'
element :variable_row, '.ci-variable-row-body' # rubocop:disable QA/ElementWithPattern
element :variable_key, '.qa-ci-variable-input-key' # rubocop:disable QA/ElementWithPattern
element :variable_value, '.qa-ci-variable-input-value' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/ci/variables/_index.html.haml' do
element :save_variables, '.js-secret-variables-save-button'
element :reveal_values, '.js-secret-value-reveal-button'
element :save_variables, '.js-secret-variables-save-button' # rubocop:disable QA/ElementWithPattern
element :reveal_values, '.js-secret-value-reveal-button' # rubocop:disable QA/ElementWithPattern
end
def fill_variable(key, value)
......
......@@ -16,7 +16,7 @@ module QA
view 'app/views/layouts/header/_new_dropdown.haml' do
element :new_menu_toggle
element :new_issue_link, "link_to _('New issue'), new_project_issue_path(@project)"
element :new_issue_link, "link_to _('New issue'), new_project_issue_path(@project)" # rubocop:disable QA/ElementWithPattern
end
view 'app/views/shared/_ref_switcher.html.haml' do
......@@ -25,12 +25,12 @@ module QA
end
view 'app/views/projects/buttons/_fork.html.haml' do
element :fork_label, "%span= s_('ProjectOverview|Fork')"
element :fork_link, "link_to new_project_fork_path(@project)"
element :fork_label, "%span= s_('ProjectOverview|Fork')" # rubocop:disable QA/ElementWithPattern
element :fork_link, "link_to new_project_fork_path(@project)" # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/_files.html.haml' do
element :tree_holder, '.tree-holder'
element :tree_holder, '.tree-holder' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/buttons/_dropdown.html.haml' do
......
......@@ -4,9 +4,9 @@ module QA
module Wiki
class Edit < Page::Base
view 'app/views/projects/wikis/_main_links.html.haml' do
element :new_page_link, 'New page'
element :page_history_link, 'Page history'
element :edit_page_link, 'Edit'
element :new_page_link, 'New page' # rubocop:disable QA/ElementWithPattern
element :page_history_link, 'Page history' # rubocop:disable QA/ElementWithPattern
element :edit_page_link, 'Edit' # rubocop:disable QA/ElementWithPattern
end
def go_to_new_page
......
......@@ -4,15 +4,15 @@ module QA
module Wiki
class New < Page::Base
view 'app/views/projects/wikis/_form.html.haml' do
element :wiki_title_textbox, 'text_field :title'
element :wiki_content_textarea, "render 'projects/zen', f: f, attr: :content"
element :wiki_message_textbox, 'text_field :message'
element :save_changes_button, 'submit _("Save changes")'
element :create_page_button, 'submit s_("Wiki|Create page")'
element :wiki_title_textbox, 'text_field :title' # rubocop:disable QA/ElementWithPattern
element :wiki_content_textarea, "render 'projects/zen', f: f, attr: :content" # rubocop:disable QA/ElementWithPattern
element :wiki_message_textbox, 'text_field :message' # rubocop:disable QA/ElementWithPattern
element :save_changes_button, 'submit _("Save changes")' # rubocop:disable QA/ElementWithPattern
element :create_page_button, 'submit s_("Wiki|Create page")' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/shared/empty_states/_wikis.html.haml' do
element :create_link, 'Create your first page'
element :create_link, 'Create your first page' # rubocop:disable QA/ElementWithPattern
end
def go_to_create_first_page
......
......@@ -8,7 +8,7 @@ module QA
include Page::Component::ClonePanel
view 'app/views/projects/wikis/pages.html.haml' do
element :clone_repository_link, 'Clone repository'
element :clone_repository_link, 'Clone repository' # rubocop:disable QA/ElementWithPattern
end
def go_to_clone_repository
......
......@@ -9,12 +9,12 @@ describe QA::Page::Base do
subject do
Class.new(described_class) do
view 'path/to/some/view.html.haml' do
element :something, 'string pattern'
element :something_else, /regexp pattern/
element :something, 'string pattern' # rubocop:disable QA/ElementWithPattern
element :something_else, /regexp pattern/ # rubocop:disable QA/ElementWithPattern
end
view 'path/to/some/_partial.html.haml' do
element :another_element, 'string pattern'
element :another_element, 'string pattern' # rubocop:disable QA/ElementWithPattern
end
end
end
......
......@@ -8,8 +8,8 @@ describe QA::Page::View do
describe '.evaluate' do
it 'evaluates a block and returns a DSL object' do
results = described_class.evaluate do
element :something, 'my pattern'
element :something_else, /another pattern/
element :something
element :something_else
end
expect(results.elements.size).to eq 2
......
require_relative '../../qa_helpers'
module RuboCop
module Cop
module QA
# This cop checks for the usage of factories in migration specs
#
# @example
#
# # bad
# let(:user) { create(:user) }
#
# # good
# let(:users) { table(:users) }
# let(:user) { users.create!(name: 'User 1', username: 'user1') }
class ElementWithPattern < RuboCop::Cop::Cop
include QAHelpers
MESSAGE = "Don't use a pattern for element, create a corresponding `%s` instead.".freeze
def on_send(node)
return unless in_qa_file?(node)
return unless method_name(node).to_s == 'element'
element_name, pattern = node.arguments
return unless pattern
add_offense(node, location: pattern.source_range, message: MESSAGE % "qa-#{element_name.value.to_s.tr('_', '-')}")
end
private
def method_name(node)
node.children[1]
end
end
end
end
end
module RuboCop
# Module containing helper methods for writing QA cops.
module QAHelpers
# Returns true if the given node originated from the qa/ directory.
def in_qa_file?(node)
path = node.location.expression.source_buffer.name
path.start_with?(File.join(Dir.pwd, 'qa'))
end
end
end
......@@ -29,6 +29,7 @@ require_relative 'cop/migration/update_large_table'
require_relative 'cop/project_path_helper'
require_relative 'cop/rspec/env_assignment'
require_relative 'cop/rspec/factories_in_migration_specs'
require_relative 'cop/qa/element_with_pattern'
require_relative 'cop/sidekiq_options_queue'
require_relative 'cop/destroy_all'
require_relative 'cop/ruby_interpolation_in_translation'
......
require 'spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
require_relative '../../../../rubocop/cop/qa/element_with_pattern'
describe RuboCop::Cop::QA::ElementWithPattern do
include CopHelper
let(:source_file) { 'qa/page.rb' }
subject(:cop) { described_class.new }
context 'in a QA file' do
before do
allow(cop).to receive(:in_qa_file?).and_return(true)
end
it "registers an offense for elements with a pattern" do
expect_offense(<<-RUBY)
view 'app/views/shared/groups/_search_form.html.haml' do
element :groups_filter, 'search_field_tag :filter'
^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use a pattern for element, create a corresponding `qa-groups-filter` instead.
element :groups_filter_placeholder, /Search by name/
^^^^^^^^^^^^^^^^ Don't use a pattern for element, create a corresponding `qa-groups-filter-placeholder` instead.
end
RUBY
end
it "does not register an offense for element without a pattern" do
expect_no_offenses(<<-RUBY)
view 'app/views/shared/groups/_search_form.html.haml' do
element :groups_filter
element :groups_filter_placeholder
end
RUBY
end
end
context 'outside of a migration spec file' do
it "does not register an offense" do
expect_no_offenses(<<-RUBY)
describe 'foo' do
let(:user) { create(:user) }
end
RUBY
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require 'rubocop'
require_relative '../../rubocop/qa_helpers'
describe RuboCop::QAHelpers do
def parse_source(source, path = 'foo.rb')
buffer = Parser::Source::Buffer.new(path)
buffer.source = source
builder = RuboCop::AST::Builder.new
parser = Parser::CurrentRuby.new(builder)
parser.parse(buffer)
end
let(:cop) do
Class.new do
include RuboCop::QAHelpers
end.new
end
describe '#in_qa_file?' do
it 'returns true for a node in the qa/ directory' do
node = parse_source('10', Rails.root.join('qa', 'qa', 'page', 'dashboard', 'groups.rb'))
expect(cop.in_qa_file?(node)).to eq(true)
end
it 'returns false for a node outside the qa/ directory' do
node = parse_source('10', Rails.root.join('app', 'foo', 'foo.rb'))
expect(cop.in_qa_file?(node)).to eq(false)
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