Commit dfce9333 authored by Dan Davison's avatar Dan Davison

Merge branch 'qa-mobile-nav-updates' into 'master'

Update page objects to handle mobile layout

See merge request gitlab-org/gitlab!66295
parents ee21fe72 e2b9b1fe
......@@ -192,9 +192,14 @@ export default {
class="gl-sm-display-none! w-100"
block
:text="dropdownText"
data-qa-selector="issue_actions_dropdown"
:loading="isToggleStateButtonLoading"
>
<gl-dropdown-item v-if="showToggleIssueStateButton" @click="toggleIssueState">
<gl-dropdown-item
v-if="showToggleIssueStateButton"
:data-qa-selector="`mobile_${qaSelector}`"
@click="toggleIssueState"
>
{{ buttonText }}
</gl-dropdown-item>
<gl-dropdown-item v-if="canCreateIssue" :href="newIssuePath">
......
......@@ -55,6 +55,7 @@ export default {
v-gl-tooltip="{ title: newDropdownViewModel.title }"
:view-model="newDropdownViewModel"
class="gl-ml-3"
data-qa-selector="mobile_new_dropdown"
/>
</header>
<top-nav-menu-sections class="gl-h-full" :sections="menuSections" v-on="$listeners" />
......
......@@ -46,6 +46,7 @@ export default {
link-class="top-nav-menu-item"
:href="menuItem.href"
data-testid="item"
:data-qa-selector="`${menuItem.title.toLowerCase().replace(' ', '_')}_mobile_button`"
>
{{ menuItem.title }}
</gl-dropdown-item>
......
......@@ -120,7 +120,7 @@
- sign_in_text = allow_signup? ? _('Sign in / Register') : _('Sign in')
= link_to sign_in_text, new_session_path(:user, redirect_to_referer: 'yes'), class: 'gl-button btn btn-default btn-sign-in'
%button.navbar-toggler.d-block.d-sm-none{ type: 'button', class: 'gl-border-none!', data: { testid: 'top-nav-responsive-toggle' } }
%button.navbar-toggler.d-block.d-sm-none{ type: 'button', class: 'gl-border-none!', data: { testid: 'top-nav-responsive-toggle', qa_selector: 'mobile_navbar_button' } }
%span.sr-only= _('Toggle navigation')
%span.more-icon.gl-px-3.gl-font-sm.gl-font-weight-bold
%span.gl-pr-2= _('Menu')
......
......@@ -6,7 +6,7 @@
%nav.breadcrumbs{ class: [container, @content_class], 'aria-label': _('Breadcrumbs') }
.breadcrumbs-container{ class: ("border-bottom-0" if @no_breadcrumb_border) }
- if defined?(@left_sidebar)
= button_tag class: 'toggle-mobile-nav', type: 'button' do
= button_tag class: 'toggle-mobile-nav', data: { qa_selector: 'toggle_mobile_nav_button' }, type: 'button' do
%span.sr-only= _("Open sidebar")
= sprite_icon('hamburger', size: 18)
.breadcrumbs-links{ data: { testid: 'breadcrumb-links', qa_selector: 'breadcrumb_links_content' } }
......
......@@ -485,3 +485,109 @@ To run the LDAP tests on your local with TLS disabled, follow these steps:
```shell
GITLAB_LDAP_USERNAME="tanuki" GITLAB_LDAP_PASSWORD="password" QA_DEBUG=true WEBDRIVER_HEADLESS=false bin/qa Test::Instance::All http://localhost qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb
```
## Guide to the mobile suite
### What are mobile tests
Tests that are tagged with `:mobile` can be run against specified mobile devices using cloud emulator/simulator services.
### How to run mobile tests with Sauce Labs
Running directly against an environment like staging is not recommended because Sauce Labs test logs expose credentials. Therefore, it is best practice and the default to use a tunnel.
Tunnel installation instructions are here [https://docs.saucelabs.com/secure-connections/sauce-connect/installation]. To start the tunnel, after following the installation above, copy the run command in Sauce Labs > Tunnels (must be logged in to Sauce Labs with the credentials found in 1Password) and run in terminal.
NOTE:
It is highly recommended to use `GITLAB_QA_ACCESS_TOKEN` to speed up tests and reduce flakiness.
`QA_REMOTE_MOBILE_DEVICE_NAME` can be any device name listed in [https://saucelabs.com/platform/supported-browsers-devices] under Emulators/simulators and the latest versions of Android or iOS. `QA_BROWSER` must be set to `safari` for iOS devices and `chrome` for Android devices.
1. To test against a local instance with a tunnel running, in `gitlab/qa` run:
```shell
$ QA_BROWSER="safari" \
QA_REMOTE_MOBILE_DEVICE_NAME="iPhone 12 Simulator" \
QA_REMOTE_GRID="ondemand.saucelabs.com:80" \
QA_REMOTE_GRID_USERNAME="gitlab-sl" \
QA_REMOTE_GRID_ACCESS_KEY="<found in Sauce Lab account>" \
GITLAB_QA_ACCESS_TOKEN="<token>" \
bundle exec bin/qa Test::Instance::All http://<local_ip>:3000 -- <relative_spec_path>
```
Results can be watched in real time while logged into Sauce Labs under AUTOMATED > Test Results.
### How to add an existing test to the mobile suite
The main reason a test might fail when adding the `:mobile` tag is navigation differences in desktop vs mobile layouts, therefore the test needs to be updated to use mobile navigation when running mobile tests.
If an existing method needs to be changed or a new one created, a new mobile page object should be created in `qa/qa/mobile/page/` and it should be prepended in the original page object by adding:
```ruby
prepend Mobile::Page::NewPageObject if Runtime::Env.mobile_layout?
```
For example to change an existing method when running mobile tests:
New mobile page object:
```ruby
module QA
module Mobile
module Page
module Project
module Show
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
prepend QA::Mobile::Page::Main::Menu
view 'app/assets/javascripts/nav/components/top_nav_new_dropdown.vue' do
element :new_issue_mobile_button
end
end
end
def go_to_new_issue
open_mobile_new_dropdown
click_element(:new_issue_mobile_button)
end
end
end
end
end
end
```
Original page object prepending the new mobile if there's a mobile layout:
```ruby
module QA
module Page
module Project
class Show < Page::Base
prepend Mobile::Page::Project::Show if Runtime::Env.mobile_layout?
view 'app/views/layouts/header/_new_dropdown.html.haml' do
element :new_menu_toggle
end
view 'app/helpers/nav/new_dropdown_helper.rb' do
element :new_issue_link
end
def go_to_new_issue
click_element(:new_menu_toggle)
click_element(:new_issue_link)
end
end
end
end
end
```
When running mobile tests for phone layouts, both `remote_mobile_device_name` and `mobile_layout` are `true` but when using a tablet layout, only `remote_mobile_device_name` is true. This is because phone layouts have more menus closed by default such as how both tablets and phones have the left nav closed but unlike phone layouts, tablets have the regular top navigation bar, not the mobile one. So in the case where the navigation being edited needs to be used in tablet layouts as well, use `remote_mobile_device_name` instead of `mobile_layout?` when prepending so it will use it if it's a tablet layout as well.
......@@ -23,8 +23,11 @@ module QA
end
def sign_in(as: nil, address: :gitlab, skip_page_validation: false, admin: false)
Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform(&:signed_in?)
Runtime::Browser.visit(address, Page::Main::Login)
unless Page::Main::Login.perform(&:on_login_page?)
Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform(&:signed_in?)
Runtime::Browser.visit(address, Page::Main::Login)
end
Page::Main::Login.perform do |login|
if admin
login.sign_in_using_admin_credentials
......
# frozen_string_literal: true
module QA
module Mobile
module Page
module Main
module Menu
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'app/views/layouts/header/_default.html.haml' do
element :mobile_navbar_button, required: true
end
view 'app/assets/javascripts/nav/components/responsive_home.vue' do
element :mobile_new_dropdown
end
end
end
def open_mobile_menu
if has_no_element?(:user_avatar)
Support::Retrier.retry_until do
click_element(:mobile_navbar_button)
has_element?(:user_avatar)
end
end
end
def open_mobile_new_dropdown
open_mobile_menu
Support::Retrier.retry_until do
find('[data-qa-selector="mobile_new_dropdown"] > button').click
has_css?('.dropdown-menu-right.show')
end
end
def has_personal_area?(wait: Capybara.default_max_wait_time)
open_mobile_menu
super
end
def has_no_personal_area?(wait: Capybara.default_max_wait_time)
open_mobile_menu
super
end
def within_user_menu
open_mobile_menu
super
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Mobile
module Page
module Profile
module Menu
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
prepend QA::Mobile::Page::Main::Menu
end
end
def within_sidebar
open_mobile_nav_sidebar
super
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Mobile
module Page
module Project
module Issue
module Show
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'app/assets/javascripts/issue_show/components/header_actions.vue' do
element :issue_actions_dropdown
element :mobile_close_issue_button
element :mobile_reopen_issue_button
end
end
end
def click_close_issue_button
find('[data-qa-selector="issue_actions_dropdown"] > button').click
find_element(:mobile_close_issue_button, visible: false).click
end
def has_reopen_issue_button?
find('[data-qa-selector="issue_actions_dropdown"] > button').click
has_element?(:mobile_reopen_issue_button)
end
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Mobile
module Page
module Project
module Show
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
prepend QA::Mobile::Page::Main::Menu
view 'app/assets/javascripts/nav/components/top_nav_new_dropdown.vue' do
element :new_issue_mobile_button
end
end
end
def go_to_new_issue
open_mobile_new_dropdown
click_element(:new_issue_mobile_button)
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Mobile
module Page
module SubMenus
module Common
def open_mobile_nav_sidebar
if has_element?(:project_sidebar, visible: false)
Support::Retrier.retry_until do
click_element(:toggle_mobile_nav_button)
has_element?(:project_sidebar, visible: true)
end
end
end
def within_sidebar
wait_for_requests
open_mobile_nav_sidebar
super
end
end
end
end
end
end
......@@ -45,6 +45,10 @@ module QA
has_element?(:sign_in_button)
end
def on_login_page?
has_element?(:login_page, wait: 0)
end
def sign_in_using_credentials(user: nil, skip_page_validation: false)
# Don't try to log-in if we're already logged-in
return if Page::Main::Menu.perform(&:signed_in?)
......@@ -164,6 +168,8 @@ module QA
fill_element :password_field, user.password
click_element :sign_in_button
Support::WaitForRequests.wait_for_requests
Page::Main::Terms.perform do |terms|
terms.accept_terms if terms.visible?
end
......
......@@ -4,6 +4,8 @@ module QA
module Page
module Main
class Menu < Page::Base
prepend Mobile::Page::Main::Menu if Runtime::Env.mobile_layout?
view 'app/views/layouts/header/_current_user_dropdown.html.haml' do
element :sign_out_link
element :edit_profile_link
......@@ -12,12 +14,12 @@ module QA
view 'app/views/layouts/header/_default.html.haml' do
element :navbar, required: true
element :canary_badge_link
element :user_avatar, required: true
element :user_menu, required: true
element :user_avatar, required: !QA::Runtime::Env.mobile_layout?
element :user_menu, required: !QA::Runtime::Env.mobile_layout?
element :stop_impersonation_link
element :issues_shortcut_button, required: true
element :merge_requests_shortcut_button, required: true
element :todos_shortcut_button, required: true
element :issues_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
element :merge_requests_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
element :todos_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
end
view 'app/assets/javascripts/nav/components/top_nav_app.vue' do
......@@ -98,10 +100,14 @@ module QA
end
def signed_in?
return false if Page::Main::Login.perform(&:on_login_page?)
has_personal_area?(wait: 0)
end
def not_signed_in?
return true if Page::Main::Login.perform(&:on_login_page?)
has_no_personal_area?
end
......@@ -115,7 +121,7 @@ module QA
click_element :sign_out_link
end
has_no_element?(:user_avatar)
not_signed_in?
end
end
......
......@@ -4,6 +4,10 @@ module QA
module Page
module Profile
class Menu < Page::Base
# We need to check remote_mobile_device_name instead of mobile_layout? here
# since tablets have the regular top navigation bar but still close the left nav
prepend QA::Mobile::Page::Profile::Menu if QA::Runtime::Env.remote_mobile_device_name
view 'app/views/layouts/nav/sidebar/_profile.html.haml' do
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
......
......@@ -9,6 +9,7 @@ module QA
include Page::Component::Note
include Page::Component::DesignManagement
include Page::Component::Issuable::Sidebar
prepend Mobile::Page::Project::Issue::Show if Runtime::Env.mobile_layout?
view 'app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue' do
element :remove_related_issue_button
......@@ -64,6 +65,10 @@ module QA
def has_metrics_unfurled?
has_element?(:prometheus_graph_widgets, wait: 30)
end
def has_reopen_issue_button?
has_element?(:reopen_issue_button)
end
end
end
end
......
......@@ -9,6 +9,7 @@ module QA
include Page::Component::Breadcrumbs
include Page::Project::SubMenus::Settings
include Page::File::Shared::CommitMessage
prepend Mobile::Page::Project::Show if Runtime::Env.mobile_layout?
view 'app/assets/javascripts/repository/components/preview/index.vue' do
element :blob_viewer_content
......@@ -117,7 +118,7 @@ module QA
end
def go_to_new_issue
click_element :new_menu_toggle
click_element(:new_menu_toggle)
click_element(:new_issue_link)
end
......
......@@ -19,6 +19,10 @@ module QA
view 'app/views/shared/nav/_sidebar_menu.html.haml' do
element :sidebar_menu_link
end
view 'app/views/layouts/nav/_breadcrumbs.html.haml' do
element :toggle_mobile_nav_button
end
end
end
......
......@@ -4,6 +4,10 @@ module QA
module Page
module SubMenus
module Common
# We need to check remote_mobile_device_name instead of mobile_layout? here
# since tablets have the regular top navigation bar but still close the left nav
prepend Mobile::Page::SubMenus::Common if QA::Runtime::Env.remote_mobile_device_name
def hover_element(element)
within_sidebar do
find_element(element).hover
......
......@@ -205,6 +205,9 @@ module QA
simulate_slow_connection if Runtime::Env.simulate_slow_connection?
# Wait until the new page is ready for us to interact with it
Support::WaitForRequests.wait_for_requests
page_class.validate_elements_present! if page_class.respond_to?(:validate_elements_present!)
if QA::Runtime::Env.qa_cookies
......
......@@ -153,6 +153,12 @@ module QA
ENV['QA_REMOTE_MOBILE_DEVICE_NAME']
end
def mobile_layout?
return false if ENV['QA_REMOTE_MOBILE_DEVICE_NAME'].blank?
!(ENV['QA_REMOTE_MOBILE_DEVICE_NAME'].downcase.include?('ipad') || ENV['QA_REMOTE_MOBILE_DEVICE_NAME'].downcase.include?('tablet'))
end
def user_username
ENV['GITLAB_USERNAME']
end
......
# frozen_string_literal: true
module QA
RSpec.describe 'Manage', :smoke do
RSpec.describe 'Manage', :smoke, :mobile do
describe 'basic user login' do
it 'user logs in using basic credentials and logs out', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1578' do
Flow::Login.sign_in
......
......@@ -9,7 +9,7 @@ module QA
Flow::Login.sign_in
end
it 'creates an issue', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1185' do
it 'creates an issue', :mobile, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1185' do
issue = Resource::Issue.fabricate_via_browser_ui!
Page::Project::Menu.perform(&:click_issues)
......@@ -19,13 +19,13 @@ module QA
end
end
it 'closes an issue', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1222' do
it 'closes an issue', :mobile, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1222' do
closed_issue.visit!
Page::Project::Issue::Show.perform do |issue_page|
issue_page.click_close_issue_button
expect(issue_page).to have_element(:reopen_issue_button)
expect(issue_page).to have_reopen_issue_button
end
Page::Project::Menu.perform(&:click_issues)
......
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