diff options
author | ddavison <ddavison@gitlab.com> | 2018-08-20 11:04:30 -0400 |
---|---|---|
committer | ddavison <ddavison@gitlab.com> | 2018-08-20 11:04:30 -0400 |
commit | c1c218252b2df207e564d57ce66d376906dfbe83 (patch) | |
tree | 9464a9c0b7de5e95642003dabc784e9e3bf9521f | |
parent | 1a7ecf03944050b9f0126bde9767481d7e8d3ec2 (diff) | |
download | gitlab-ce-qa-consolidate-selector-pattern.tar.gz |
wip: refactoringqa-consolidate-selector-pattern
-rw-r--r-- | app/helpers/qa_helper.rb | 25 | ||||
-rw-r--r-- | app/views/devise/sessions/_new_base.html.haml | 6 | ||||
-rw-r--r-- | app/views/devise/shared/_tabs_normal.html.haml | 4 | ||||
-rw-r--r-- | app/views/layouts/header/_current_user_dropdown.html.haml | 4 | ||||
-rw-r--r-- | app/views/layouts/header/_default.html.haml | 6 | ||||
-rw-r--r-- | app/views/layouts/nav/_dashboard.html.haml | 6 | ||||
-rw-r--r-- | app/views/layouts/nav/groups_dropdown/_show.html.haml | 4 | ||||
-rw-r--r-- | app/views/layouts/nav/projects_dropdown/_show.html.haml | 4 | ||||
-rw-r--r-- | db/schema.rb | 4 | ||||
-rw-r--r-- | qa/qa.rb | 1 | ||||
-rw-r--r-- | qa/qa/page/base.rb | 4 | ||||
-rw-r--r-- | qa/qa/page/element.rb | 19 | ||||
-rw-r--r-- | qa/qa/page/main/login.rb | 36 | ||||
-rw-r--r-- | qa/qa/page/menu/main.rb | 39 | ||||
-rw-r--r-- | qa/qa/page/validatable.rb | 19 | ||||
-rw-r--r-- | qa/qa/page/view.rb | 4 | ||||
-rw-r--r-- | qa/qa/runtime/browser.rb | 1 |
17 files changed, 125 insertions, 61 deletions
diff --git a/app/helpers/qa_helper.rb b/app/helpers/qa_helper.rb new file mode 100644 index 00000000000..57eee9c144c --- /dev/null +++ b/app/helpers/qa_helper.rb @@ -0,0 +1,25 @@ +module QaHelper + # Define a data-qa attribute on the webpage + # + # Examples: + # qa('selector', 'username') + # qa('index', 1) + # + # Params: + # +attr+:: the data-qa-* attribute where * is the attribute to match + # +value+:: the value to set for data-qa-attr="value" + def qa(attr, value) + { "qa-#{attr}": value } + end + + # Shortcut method(s) for QA + # + # Examples: + # data: qa_selector('test') + # data: qa_index(1) + [:qa_selector].each do |qa_method| + define_method qa_method do |pattern| + qa("#{qa_method.to_s.split('_')[1]}", pattern) + end + end +end diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml index 0ee563ac066..9ac89013631 100644 --- a/app/views/devise/sessions/_new_base.html.haml +++ b/app/views/devise/sessions/_new_base.html.haml @@ -1,10 +1,10 @@ = form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'new_user gl-show-field-errors', 'aria-live' => 'assertive'}) do |f| .form-group = f.label "Username or email", for: "user_login" - = f.text_field :login, class: "form-control top", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required." + = f.text_field :login, class: "form-control top", data: qa_selector('txt_username'), autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required." .form-group = f.label :password - = f.password_field :password, class: "form-control bottom", required: true, title: "This field is required." + = f.password_field :password, class: "form-control bottom", data: qa_selector('txt_password'), required: true, title: "This field is required." - if devise_mapping.rememberable? .remember-me %label{ for: "user_remember_me" } @@ -17,4 +17,4 @@ = recaptcha_tags .submit-container.move-submit-down - = f.submit "Sign in", class: "btn btn-save" + = f.submit "Sign in", class: "btn btn-save", data: qa_selector('btn_signin') diff --git a/app/views/devise/shared/_tabs_normal.html.haml b/app/views/devise/shared/_tabs_normal.html.haml index 284d4fa1b89..13382491f81 100644 --- a/app/views/devise/shared/_tabs_normal.html.haml +++ b/app/views/devise/shared/_tabs_normal.html.haml @@ -1,6 +1,6 @@ %ul.nav-links.new-session-tabs.nav-tabs.nav{ role: 'tablist' } %li.nav-item{ role: 'presentation' } - %a.nav-link.active{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab' } Sign in + %a.nav-link.active{ href: '#login-pane', data: { toggle: 'tab' }.merge(qa_selector('tab_standard')), role: 'tab' } Sign in - if allow_signup? %li.nav-item{ role: 'presentation' } - %a.nav-link{ href: '#register-pane', data: { toggle: 'tab' }, role: 'tab' } Register + %a.nav-link{ href: '#register-pane', data: { toggle: 'tab' }.merge(qa_selector('tab_register')), role: 'tab' } Register diff --git a/app/views/layouts/header/_current_user_dropdown.html.haml b/app/views/layouts/header/_current_user_dropdown.html.haml index 9ed05d6e3d0..dfa471bf761 100644 --- a/app/views/layouts/header/_current_user_dropdown.html.haml +++ b/app/views/layouts/header/_current_user_dropdown.html.haml @@ -11,7 +11,7 @@ = link_to s_("CurrentUser|Profile"), current_user, class: 'profile-link', data: { user: current_user.username } - if current_user_menu?(:settings) %li - = link_to s_("CurrentUser|Settings"), profile_path + = link_to s_("CurrentUser|Settings"), profile_path, data: qa_selector('btn_settings') - if current_user_menu?(:help) %li = link_to _("Help"), help_path @@ -20,4 +20,4 @@ = render 'shared/user_dropdown_contributing_link' - if current_user_menu?(:sign_out) %li - = link_to _("Sign out"), destroy_user_session_path, class: "sign-out-link" + = link_to _("Sign out"), destroy_user_session_path, class: "sign-out-link", data: qa_selector('btn_signout') diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index e8d31992149..a8880f4bce8 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -1,4 +1,4 @@ -%header.navbar.navbar-gitlab.qa-navbar.navbar-expand-sm +%header.navbar.navbar-gitlab.navbar-expand-sm{data: qa_selector('navbar')} %a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content .container-fluid .header-content @@ -50,9 +50,9 @@ - if header_link?(:user_dropdown) %li.nav-item.header-user.dropdown = link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do - = image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar" + = image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar", data: qa_selector('user_avatar') = sprite_icon('angle-down', css_class: 'caret-down') - .dropdown-menu.dropdown-menu-right + .dropdown-menu.dropdown-menu-right{data: qa_selector('drp_user')} = render 'layouts/header/current_user_dropdown' - if header_link?(:admin_impersonation) %li.nav-item.impersonation diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 5e467c862ab..18635f9e910 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -1,6 +1,6 @@ %ul.list-unstyled.navbar-sub-nav - if dashboard_nav_link?(:projects) - = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown" }) do + = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects", data: qa_selector('drp_projects') }) do %button{ type: 'button', data: { toggle: "dropdown" } } = _('Projects') = sprite_icon('angle-down', css_class: 'caret-down') @@ -8,7 +8,7 @@ = render "layouts/nav/projects_dropdown/show" - if dashboard_nav_link?(:groups) - = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "home dropdown header-groups qa-groups-dropdown" }) do + = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "home dropdown header-groups", data: qa_selector('drp_groups') }) do %button{ type: 'button', data: { toggle: "dropdown" } } = _('Groups') = sprite_icon('angle-down', css_class: 'caret-down') @@ -72,7 +72,7 @@ = sprite_icon('chart', size: 18) - if current_user.admin? = nav_link(controller: 'admin/dashboard') do - = link_to admin_root_path, class: 'admin-icon qa-admin-area-link', title: _('Admin area'), aria: { label: _('Admin area') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do + = link_to admin_root_path, class: 'admin-icon', title: _('Admin area'), aria: { label: _('Admin area') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'}.merge(qa_selector('lnk_adminarea')) do = sprite_icon('admin', size: 18) - if Gitlab::Sherlock.enabled? %li diff --git a/app/views/layouts/nav/groups_dropdown/_show.html.haml b/app/views/layouts/nav/groups_dropdown/_show.html.haml index 3ce1fa6bcca..a34ebdaf6fe 100644 --- a/app/views/layouts/nav/groups_dropdown/_show.html.haml +++ b/app/views/layouts/nav/groups_dropdown/_show.html.haml @@ -1,9 +1,9 @@ - group_meta = { id: @group.id, name: @group.name, namespace: @group.full_name, web_url: group_path(@group), avatar_url: @group.avatar_url } if @group&.persisted? .frequent-items-dropdown-container - .frequent-items-dropdown-sidebar.qa-groups-dropdown-sidebar + .frequent-items-dropdown-sidebar{data: qa_selector('drp_groups_sidebar')} %ul = nav_link(path: 'dashboard/groups#index') do - = link_to dashboard_groups_path, class: 'qa-your-groups-link' do + = link_to dashboard_groups_path, data: qa_selector('drp_groups_sidebar_lnk_yourgroups') do = _('Your groups') = nav_link(path: 'groups#explore') do = link_to explore_groups_path do diff --git a/app/views/layouts/nav/projects_dropdown/_show.html.haml b/app/views/layouts/nav/projects_dropdown/_show.html.haml index f2170f71532..b9e37a73bb4 100644 --- a/app/views/layouts/nav/projects_dropdown/_show.html.haml +++ b/app/views/layouts/nav/projects_dropdown/_show.html.haml @@ -1,9 +1,9 @@ - project_meta = { id: @project.id, name: @project.name, namespace: @project.full_name, web_url: project_path(@project), avatar_url: @project.avatar_url } if @project&.persisted? .frequent-items-dropdown-container - .frequent-items-dropdown-sidebar.qa-projects-dropdown-sidebar + .frequent-items-dropdown-sidebar{data: qa_selector('drp_projects_sidebar')} %ul = nav_link(path: 'dashboard/projects#index') do - = link_to dashboard_projects_path, class: 'qa-your-projects-link' do + = link_to dashboard_projects_path, data: qa_selector('drp_projects_sidebar_lnk_yourprojects') do = _('Your projects') = nav_link(path: 'projects#starred') do = link_to starred_dashboard_projects_path do diff --git a/db/schema.rb b/db/schema.rb index 1288a98745c..66d45115f7e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1204,6 +1204,7 @@ ActiveRecord::Schema.define(version: 20180808162000) do t.integer "commits_count" end + add_index "merge_request_diffs", ["id"], name: "tmp_partial_diff_id_with_files_index", where: "((state)::text <> ALL ((ARRAY['without_files'::character varying, 'empty'::character varying])::text[]))", using: :btree add_index "merge_request_diffs", ["merge_request_id", "id"], name: "index_merge_request_diffs_on_merge_request_id_and_id", using: :btree create_table "merge_request_metrics", force: :cascade do |t| @@ -1764,6 +1765,7 @@ ActiveRecord::Schema.define(version: 20180808162000) do end add_index "redirect_routes", ["path"], name: "index_redirect_routes_on_path", unique: true, using: :btree + add_index "redirect_routes", ["path"], name: "index_redirect_routes_on_path_text_pattern_ops", using: :btree, opclasses: {"path"=>"varchar_pattern_ops"} add_index "redirect_routes", ["source_type", "source_id"], name: "index_redirect_routes_on_source_type_and_source_id", using: :btree create_table "releases", force: :cascade do |t| @@ -2395,7 +2397,7 @@ ActiveRecord::Schema.define(version: 20180808162000) do add_foreign_key "term_agreements", "users", on_delete: :cascade add_foreign_key "timelogs", "issues", name: "fk_timelogs_issues_issue_id", on_delete: :cascade add_foreign_key "timelogs", "merge_requests", name: "fk_timelogs_merge_requests_merge_request_id", on_delete: :cascade - add_foreign_key "todos", "namespaces", column: "group_id", on_delete: :cascade + add_foreign_key "todos", "namespaces", column: "group_id", name: "fk_a27c483435", on_delete: :cascade add_foreign_key "todos", "notes", name: "fk_91d1f47b13", on_delete: :cascade add_foreign_key "todos", "projects", name: "fk_45054f9c45", on_delete: :cascade add_foreign_key "todos", "users", column: "author_id", name: "fk_ccf0373936", on_delete: :cascade @@ -109,6 +109,7 @@ module QA autoload :View, 'qa/page/view' autoload :Element, 'qa/page/element' autoload :Validator, 'qa/page/validator' + autoload :Validatable, 'qa/page/validatable' module Main autoload :Login, 'qa/page/main/login' diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index 30e35bf7abb..10e790ff547 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -5,6 +5,7 @@ module QA class Base include Capybara::DSL include Scenario::Actable + extend Validatable extend SingleForwardable def_delegators :evaluator, :view, :views @@ -68,8 +69,9 @@ module QA all(element_selector_css(name)) end - def click_element(name) + def click_element(name, page = self) find_element(name).click + page.validate_elements_present! end def fill_element(name, content) diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb index 9944a39ce07..cc81b8884ca 100644 --- a/qa/qa/page/element.rb +++ b/qa/qa/page/element.rb @@ -1,19 +1,28 @@ module QA module Page class Element - attr_reader :name + attr_reader :name, :required - def initialize(name, pattern = nil) + def initialize(name, required = true) @name = name - @pattern = pattern || selector + + unless !!required == required + warn "[QA] DEPRECATED TYPING: element #{name}, #{required} should be a boolean!" + end + + @required = required + end + + def required? + !!required end def selector - "qa-#{@name.to_s.tr('_', '-')}" + /['"]data-qa-selector['"]: ['"]#{@name}['"]/ end def selector_css - ".#{selector}" + %Q([data-qa-selector="#{@name}"]) end def expression diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb index 6cdfbd1c125..089bb49f5c9 100644 --- a/qa/qa/page/main/login.rb +++ b/qa/qa/page/main/login.rb @@ -3,31 +3,31 @@ module QA 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 :txt_password, false + element :txt_password, false + element :btn_change_password, false 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 :txt_username + element :txt_password + element :btn_signin end view 'app/views/devise/sessions/_new_ldap.html.haml' do - element :username_field, 'text_field_tag :username' - element :password_field, 'password_field_tag :password' - element :sign_in_button, 'submit_tag "Sign in"' + element :txt_username + element :txt_password + element :btn_signin end view 'app/views/devise/shared/_tabs_ldap.html.haml' do - element :ldap_tab, "link_to server['label']" - element :standard_tab, "link_to 'Standard'" + element :ldap_tab, false + element :standard_tab, false end view 'app/views/devise/shared/_tabs_normal.html.haml' do - element :sign_in_tab, /nav-link.*login-pane.*Sign in/ - element :register_tab, /nav-link.*register-pane.*Register/ + element :tab_standard + element :tab_register end def initialize @@ -62,11 +62,11 @@ module QA end def switch_to_sign_in_tab - click_on 'Sign in' + click_element :tab_standard end def switch_to_register_tab - click_on 'Register' + click_element :tab_register end private @@ -82,9 +82,9 @@ module QA def sign_in_using_gitlab_credentials click_link 'Standard' if page.has_content?('LDAP') - fill_in :user_login, with: Runtime::User.name - fill_in :user_password, with: Runtime::User.password - click_button 'Sign in' + fill_element :txt_username, Runtime::User.name + fill_element :txt_password, Runtime::User.password + click_element :btn_signin, Page::Menu::Main end def set_initial_password_if_present diff --git a/qa/qa/page/menu/main.rb b/qa/qa/page/menu/main.rb index 36e7285f7b7..00c6508cefa 100644 --- a/qa/qa/page/menu/main.rb +++ b/qa/qa/page/menu/main.rb @@ -3,49 +3,54 @@ module QA module Menu class Main < 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 :btn_signout + element :btn_settings end view 'app/views/layouts/header/_default.html.haml' do element :navbar element :user_avatar - element :user_menu, '.dropdown-menu' + element :drp_user end view 'app/views/layouts/nav/_dashboard.html.haml' do - element :admin_area_link - element :projects_dropdown - element :groups_dropdown + element :lnk_adminarea + element :drp_projects + element :drp_groups end view 'app/views/layouts/nav/projects_dropdown/_show.html.haml' do - element :projects_dropdown_sidebar - element :your_projects_link + element :drp_projects_sidebar + element :drp_projects_sidebar_lnk_yourprojects + end + + view 'app/views/layouts/nav/groups_dropdown/_show.html.haml' do + element :drp_groups_sidebar + element :drp_groups_sidebar_lnk_yourgroups end def go_to_groups within_top_menu do - click_element :groups_dropdown + click_element :drp_groups end - page.within('.qa-groups-dropdown-sidebar') do - click_element :your_groups_link + page.within_element(:drp_groups_sidebar) do + click_element :drp_groups_sidebar_lnk_yourgroups end end def go_to_projects within_top_menu do - click_element :projects_dropdown + click_element :drp_projects end - page.within('.qa-projects-dropdown-sidebar') do - click_element :your_projects_link + page.within_element(:drp_projects_sidebar) do + click_element :drp_projects_sidebar_lnk_yourprojects end end def go_to_admin_area - within_top_menu { click_element :admin_area_link } + within_top_menu { click_element :lnk_adminarea } end def sign_out @@ -68,7 +73,7 @@ module QA private def within_top_menu - page.within('.qa-navbar') do + page.within_element(:navbar) do yield end end @@ -77,7 +82,7 @@ module QA within_top_menu do click_element :user_avatar - page.within('.dropdown-menu') do + page.within_element(:drp_user) do yield end end diff --git a/qa/qa/page/validatable.rb b/qa/qa/page/validatable.rb new file mode 100644 index 00000000000..1d885915f74 --- /dev/null +++ b/qa/qa/page/validatable.rb @@ -0,0 +1,19 @@ +module QA + module Page + module Validatable + PageValidationError = Class.new(StandardError) + + def validate_elements_present! + # get elements from self + elements.each do |element| + if element.required? + base_page = self.new + unless base_page.using_wait_time(10) { base_page.page.has_selector?(element.selector_css) } + raise Validatable::PageValidationError, "#{element.name} expected on #{self.name} page" + end + end + end + end + end + end +end diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb index b2a2da4dbf3..9ee17d54c22 100644 --- a/qa/qa/page/view.rb +++ b/qa/qa/page/view.rb @@ -46,8 +46,8 @@ module QA @elements = [] end - def element(name, pattern = nil) - @elements.push(Page::Element.new(name, pattern)) + def element(name, required = true) + @elements.push(Page::Element.new(name, required)) end end end diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index 4c64270ce92..a1e19441123 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -29,6 +29,7 @@ module QA def self.visit(address, page = nil, &block) new.visit(address, page, &block) + page.validate_elements_present! end def self.configure! |