Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-10-26 15:09:27 +00:00
parent 0594381ba7
commit 5169b4a63b
47 changed files with 486 additions and 92 deletions

View File

@ -2,7 +2,7 @@
<!--
Please describe the engineering productivity problem that needs to be solved backed by charts from
https://about.gitlab.com/handbook/engineering/quality/engineering-productivity-team/#engineering-productivity-team-metrics.
https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/#engineering-productivity-metrics.
-->
### Problem identification checklist

View File

@ -33,6 +33,6 @@ This will help keep track of expected cost increases to the [GitLab project aver
### Post-merge
- [ ] Consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity-team/#pipeline-changes)
- [ ] Consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/#pipeline-changes)
/label ~tooling ~"tooling::pipelines" ~"Engineering Productivity"

View File

@ -1 +1 @@
ee4b20cc318876c4b237e277fefd9d75186a085c
156e65d1de93e779091a0915cf77b2aefa85fadf

View File

@ -65,7 +65,7 @@ export default {
};
</script>
<template>
<div class="blob-viewer" :data-type="activeViewer.type">
<div class="blob-viewer" :data-type="activeViewer.type" :data-loaded="!loading">
<gl-loading-icon v-if="loading" size="md" color="dark" class="my-4 mx-auto" />
<template v-else>

View File

@ -3,12 +3,14 @@ import DefaultActions from './blob_header_default_actions.vue';
import BlobFilepath from './blob_header_filepath.vue';
import ViewerSwitcher from './blob_header_viewer_switcher.vue';
import { SIMPLE_BLOB_VIEWER } from './constants';
import TableOfContents from './table_contents.vue';
export default {
components: {
ViewerSwitcher,
DefaultActions,
BlobFilepath,
TableOfContents,
},
props: {
blob: {
@ -70,11 +72,14 @@ export default {
</script>
<template>
<div class="js-file-title file-title-flex-parent">
<blob-filepath :blob="blob">
<template #filepath-prepend>
<slot name="prepend"></slot>
</template>
</blob-filepath>
<div class="gl-display-flex">
<table-of-contents class="gl-pr-2" />
<blob-filepath :blob="blob">
<template #filepath-prepend>
<slot name="prepend"></slot>
</template>
</blob-filepath>
</div>
<div class="gl-display-none gl-sm-display-flex">
<viewer-switcher v-if="showViewerSwitcher" v-model="viewer" />

View File

@ -18,11 +18,12 @@ export default {
},
mounted() {
this.blobViewer = document.querySelector('.blob-viewer[data-type="rich"]');
const blobViewerAttr = (attr) => this.blobViewer.getAttribute(attr);
this.observer = new MutationObserver(() => {
if (this.blobViewer.classList.contains('hidden')) {
if (this.blobViewer.classList.contains('hidden') || blobViewerAttr('data-type') !== 'rich') {
this.isHidden = true;
} else if (this.blobViewer.getAttribute('data-loaded') === 'true') {
} else if (blobViewerAttr('data-loaded') === 'true') {
this.isHidden = false;
this.generateHeaders();
}

View File

@ -22,6 +22,6 @@ export default {
<template>
<span class="folder-caret gl-mr-2">
<gl-icon :size="10" :name="iconClass" use-deprecated-sizes />
<gl-icon :size="12" :name="iconClass" />
</span>
</template>

View File

@ -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">

View File

@ -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" />

View File

@ -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>

View File

@ -197,7 +197,7 @@ export default {
class="gl-display-flex gl-align-items-center gl-py-3 gl-pl-7"
data-testid="extension-list-item"
>
<status-icon v-if="data.icon" :icon-name="data.icon.name" :size="12" />
<status-icon v-if="data.icon" :icon-name="data.icon.name" :size="12" class="gl-pl-0" />
<gl-intersection-observer
:options="{ rootMargin: '100px', thresholds: 0.1 }"
class="gl-flex-wrap gl-align-self-center gl-display-flex"

View File

@ -86,7 +86,7 @@ export default {
<template>
<span>
<gl-loading-icon v-if="loading" size="sm" :inline="true" />
<gl-icon v-else-if="isSymlink" name="symlink" :size="size" use-deprecated-sizes />
<gl-icon v-else-if="isSymlink" name="symlink" :size="size" />
<svg v-else-if="!folder" :key="spriteHref" :class="[iconSizeClass, cssClasses]">
<use v-bind="{ 'xlink:href': spriteHref }" />
</svg>

View File

@ -3,13 +3,14 @@
module Mutations
module Issues
class Create < BaseMutation
include Mutations::SpamProtection
include FindsProject
include CommonMutationArguments
graphql_name 'CreateIssue'
authorize :create_issue
include CommonMutationArguments
argument :project_path, GraphQL::Types::ID,
required: true,
description: 'Project full path the issue is associated with.'
@ -76,9 +77,7 @@ module Mutations
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
issue = ::Issues::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute
if issue.spam?
issue.errors.add(:base, 'Spam detected.')
end
check_spam_action_response!(issue)
{
issue: issue.valid? ? issue : nil,

View File

@ -684,7 +684,9 @@ module Ci
end
def freeze_period?
Ci::FreezePeriodStatus.new(project: project).execute
strong_memoize(:freeze_period) do
Ci::FreezePeriodStatus.new(project: project).execute
end
end
def has_warnings?
@ -800,20 +802,7 @@ module Ci
variables.append(key: 'CI_PIPELINE_CREATED_AT', value: created_at&.iso8601)
variables.concat(predefined_commit_variables)
if merge_request?
variables.append(key: 'CI_MERGE_REQUEST_EVENT_TYPE', value: merge_request_event_type.to_s)
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', value: source_sha.to_s)
variables.append(key: 'CI_MERGE_REQUEST_TARGET_BRANCH_SHA', value: target_sha.to_s)
diff = self.merge_request_diff
if diff.present?
variables.append(key: 'CI_MERGE_REQUEST_DIFF_ID', value: diff.id.to_s)
variables.append(key: 'CI_MERGE_REQUEST_DIFF_BASE_SHA', value: diff.base_commit_sha)
end
variables.concat(merge_request.predefined_variables)
end
variables.concat(predefined_merge_request_variables)
if open_merge_requests_refs.any?
variables.append(key: 'CI_OPEN_MERGE_REQUESTS', value: open_merge_requests_refs.join(','))
@ -829,27 +818,49 @@ module Ci
end
def predefined_commit_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'CI_COMMIT_SHA', value: sha)
variables.append(key: 'CI_COMMIT_SHORT_SHA', value: short_sha)
variables.append(key: 'CI_COMMIT_BEFORE_SHA', value: before_sha)
variables.append(key: 'CI_COMMIT_REF_NAME', value: source_ref)
variables.append(key: 'CI_COMMIT_REF_SLUG', value: source_ref_slug)
variables.append(key: 'CI_COMMIT_BRANCH', value: ref) if branch?
variables.append(key: 'CI_COMMIT_TAG', value: ref) if tag?
variables.append(key: 'CI_COMMIT_MESSAGE', value: git_commit_message.to_s)
variables.append(key: 'CI_COMMIT_TITLE', value: git_commit_full_title.to_s)
variables.append(key: 'CI_COMMIT_DESCRIPTION', value: git_commit_description.to_s)
variables.append(key: 'CI_COMMIT_REF_PROTECTED', value: (!!protected_ref?).to_s)
variables.append(key: 'CI_COMMIT_TIMESTAMP', value: git_commit_timestamp.to_s)
variables.append(key: 'CI_COMMIT_AUTHOR', value: git_author_full_text.to_s)
strong_memoize(:predefined_commit_variables) do
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'CI_COMMIT_SHA', value: sha)
variables.append(key: 'CI_COMMIT_SHORT_SHA', value: short_sha)
variables.append(key: 'CI_COMMIT_BEFORE_SHA', value: before_sha)
variables.append(key: 'CI_COMMIT_REF_NAME', value: source_ref)
variables.append(key: 'CI_COMMIT_REF_SLUG', value: source_ref_slug)
variables.append(key: 'CI_COMMIT_BRANCH', value: ref) if branch?
variables.append(key: 'CI_COMMIT_TAG', value: ref) if tag?
variables.append(key: 'CI_COMMIT_MESSAGE', value: git_commit_message.to_s)
variables.append(key: 'CI_COMMIT_TITLE', value: git_commit_full_title.to_s)
variables.append(key: 'CI_COMMIT_DESCRIPTION', value: git_commit_description.to_s)
variables.append(key: 'CI_COMMIT_REF_PROTECTED', value: (!!protected_ref?).to_s)
variables.append(key: 'CI_COMMIT_TIMESTAMP', value: git_commit_timestamp.to_s)
variables.append(key: 'CI_COMMIT_AUTHOR', value: git_author_full_text.to_s)
# legacy variables
variables.append(key: 'CI_BUILD_REF', value: sha)
variables.append(key: 'CI_BUILD_BEFORE_SHA', value: before_sha)
variables.append(key: 'CI_BUILD_REF_NAME', value: source_ref)
variables.append(key: 'CI_BUILD_REF_SLUG', value: source_ref_slug)
variables.append(key: 'CI_BUILD_TAG', value: ref) if tag?
# legacy variables
variables.append(key: 'CI_BUILD_REF', value: sha)
variables.append(key: 'CI_BUILD_BEFORE_SHA', value: before_sha)
variables.append(key: 'CI_BUILD_REF_NAME', value: source_ref)
variables.append(key: 'CI_BUILD_REF_SLUG', value: source_ref_slug)
variables.append(key: 'CI_BUILD_TAG', value: ref) if tag?
end
end
end
def predefined_merge_request_variables
strong_memoize(:predefined_merge_request_variables) do
Gitlab::Ci::Variables::Collection.new.tap do |variables|
next variables unless merge_request?
variables.append(key: 'CI_MERGE_REQUEST_EVENT_TYPE', value: merge_request_event_type.to_s)
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', value: source_sha.to_s)
variables.append(key: 'CI_MERGE_REQUEST_TARGET_BRANCH_SHA', value: target_sha.to_s)
diff = self.merge_request_diff
if diff.present?
variables.append(key: 'CI_MERGE_REQUEST_DIFF_ID', value: diff.id.to_s)
variables.append(key: 'CI_MERGE_REQUEST_DIFF_BASE_SHA', value: diff.base_commit_sha)
end
variables.concat(merge_request.predefined_variables)
end
end
end

View File

@ -2056,14 +2056,16 @@ class Project < ApplicationRecord
end
def predefined_variables
Gitlab::Ci::Variables::Collection.new
.concat(predefined_ci_server_variables)
.concat(predefined_project_variables)
.concat(pages_variables)
.concat(container_registry_variables)
.concat(dependency_proxy_variables)
.concat(auto_devops_variables)
.concat(api_variables)
strong_memoize(:predefined_variables) do
Gitlab::Ci::Variables::Collection.new
.concat(predefined_ci_server_variables)
.concat(predefined_project_variables)
.concat(pages_variables)
.concat(container_registry_variables)
.concat(dependency_proxy_variables)
.concat(auto_devops_variables)
.concat(api_variables)
end
end
def predefined_project_variables

View File

@ -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')

View File

@ -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' } }

View File

@ -10,7 +10,7 @@
= edit_blob_button(@project, @ref, @path, blob: blob)
= ide_edit_button(@project, @ref, @path, blob: blob)
- if can_view_pipeline_editor?(@project) && @path == @project.ci_config_path_or_default
= link_to "Pipeline Editor", project_ci_pipeline_editor_path(@project), class: "btn gl-button btn-confirm-secondary gl-ml-3"
= link_to "Pipeline Editor", project_ci_pipeline_editor_path(@project, branch_name: @ref), class: "btn gl-button btn-confirm-secondary gl-ml-3"
.btn-group{ role: "group", class: ("gl-ml-3" if current_user) }>
= render_if_exists 'projects/blob/header_file_locks_link'
- if current_user

View File

@ -14,7 +14,7 @@ Please consider the effect of the changes in this merge request on the following
- personal forks
- Effects on [pipeline performance](https://about.gitlab.com/handbook/engineering/quality/performance-indicators/#average-merge-request-pipeline-duration-for-gitlab)
Please consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity-team/#pipeline-changes)
Please consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/#pipeline-changes)
MESSAGE
if helper.has_ci_changes?

View File

@ -122,7 +122,7 @@ In these cases, use the following workflow:
- [User Experience (UX)](https://about.gitlab.com/handbook/engineering/ux/)
- [Security](https://about.gitlab.com/handbook/engineering/security/)
- [Quality](https://about.gitlab.com/handbook/engineering/quality/)
- [Engineering Productivity](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity-team/)
- [Engineering Productivity](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/)
- [Infrastructure](https://about.gitlab.com/handbook/engineering/infrastructure/)
- [Technical Writing](https://about.gitlab.com/handbook/engineering/ux/technical-writing/)

View File

@ -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.

View File

@ -360,8 +360,8 @@ always take the latest dependency scanning artifact available.
### Enable Dependency Scanning via an automatic merge request
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4908) in GitLab 14.1.
> - [Enabled with `sec_dependency_scanning_ui_enable` flag](https://gitlab.com/gitlab-org/gitlab/-/issues/282533) for self-managed GitLab in GitLab 14.1 and is ready for production use.
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4908) in GitLab 14.1 [with a flag](../../../administration/feature_flags.md) named `sec_dependency_scanning_ui_enable`. Enabled by default.
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/282533) in GitLab 14.1.
> - [Feature flag sec_dependency_scanning_ui_enable removed](https://gitlab.com/gitlab-org/gitlab/-/issues/326005) in GitLab 14.2.
To enable Dependency Scanning in a project, you can create a merge request

View File

@ -203,7 +203,7 @@ specified the `kas-address` correctly.
```
This error occurs if the `kas-address` doesn't include a trailing slash. To fix it, make sure that the
`wss` or `ws` URL ends with a training slash, such as `wss://GitLab.host.tld:443/-/kubernetes-agent/`
`wss` or `ws` URL ends with a trailing slash, such as `wss://GitLab.host.tld:443/-/kubernetes-agent/`
or `ws://GitLab.host.tld:80/-/kubernetes-agent/`.
#### ValidationError(Deployment.metadata)

View File

@ -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

View File

@ -0,0 +1,60 @@
# 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

View File

@ -0,0 +1,26 @@
# 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

View File

@ -0,0 +1,37 @@
# 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

View File

@ -0,0 +1,31 @@
# 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

View File

@ -0,0 +1,28 @@
# 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,7 +1,7 @@
# 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

View File

@ -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)

View File

@ -196,8 +196,8 @@ function rspec_rerun_previous_failed_tests() {
local test_file_count=$(wc -w "${matching_tests_file}" | awk {'print $1'})
if [[ "${test_file_count}" -gt "${test_file_count_threshold}" ]]; then
echo "This job is intentionally failed because there are more than ${test_file_count_threshold} test files to rerun."
exit 1
echo "This job is intentionally exited because there are more than ${test_file_count_threshold} test files to rerun."
exit 0
fi
if [[ -n $test_files ]]; then

View File

@ -4,9 +4,17 @@ exports[`Blob Header Default Actions rendering matches the snapshot 1`] = `
<div
class="js-file-title file-title-flex-parent"
>
<blob-filepath-stub
blob="[object Object]"
/>
<div
class="gl-display-flex"
>
<table-of-contents-stub
class="gl-pr-2"
/>
<blob-filepath-stub
blob="[object Object]"
/>
</div>
<div
class="gl-display-none gl-sm-display-flex"

View File

@ -3,6 +3,7 @@ import BlobHeader from '~/blob/components/blob_header.vue';
import DefaultActions from '~/blob/components/blob_header_default_actions.vue';
import BlobFilepath from '~/blob/components/blob_header_filepath.vue';
import ViewerSwitcher from '~/blob/components/blob_header_viewer_switcher.vue';
import TableContents from '~/blob/components/table_contents.vue';
import { Blob } from './mock_data';
@ -43,6 +44,7 @@ describe('Blob Header Default Actions', () => {
it('renders all components', () => {
createComponent();
expect(wrapper.find(TableContents).exists()).toBe(true);
expect(wrapper.find(ViewerSwitcher).exists()).toBe(true);
expect(findDefaultActions().exists()).toBe(true);
expect(wrapper.find(BlobFilepath).exists()).toBe(true);

View File

@ -32,10 +32,30 @@ describe('Markdown table of contents component', () => {
});
describe('not loaded', () => {
const findDropdownItem = () => wrapper.findComponent(GlDropdownItem);
it('does not populate dropdown', () => {
createComponent();
expect(wrapper.findComponent(GlDropdownItem).exists()).toBe(false);
expect(findDropdownItem().exists()).toBe(false);
});
it('does not show dropdown when loading blob content', async () => {
createComponent();
await setLoaded(false);
expect(findDropdownItem().exists()).toBe(false);
});
it('does not show dropdown when viewing non-rich content', async () => {
createComponent();
document.querySelector('.blob-viewer').setAttribute('data-type', 'simple');
await setLoaded(true);
expect(findDropdownItem().exists()).toBe(false);
});
});

View File

@ -48,5 +48,9 @@ RSpec.describe 'Create an issue' do
expect(mutation_response['issue']).to include('discussionLocked' => true)
expect(Issue.last.work_item_type.base_type).to eq('issue')
end
it_behaves_like 'has spam protection' do
let(:mutation_class) { ::Mutations::Issues::Create }
end
end
end

View File

@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe Ci::CreatePipelineService do
include ProjectForksHelper
let_it_be(:project, reload: true) { create(:project, :repository) }
let_it_be(:user, reload: true) { project.owner }
let_it_be_with_refind(:project) { create(:project, :repository) }
let_it_be_with_reload(:user) { project.owner }
let(:ref_name) { 'refs/heads/master' }

View File

@ -38,6 +38,11 @@ RSpec.shared_context 'stubbed service ping metrics definitions' do
)
end
after do |example|
Gitlab::Usage::Metric.instance_variable_set(:@all, nil)
Gitlab::Usage::MetricDefinition.instance_variable_set(:@all, nil)
end
def metric_attributes(key_path, category, value_type = 'string')
{
'key_path' => key_path,