Commit 66ce6a78 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 1c23b3f1
...@@ -40,12 +40,12 @@ If this feature requires changing permissions, this document https://docs.gitlab ...@@ -40,12 +40,12 @@ If this feature requires changing permissions, this document https://docs.gitlab
<!-- What risks does this change pose to our availability? How might it affect the quality of the product? What additional test coverage or changes to tests will be needed? Will it require cross-browser testing? <!-- What risks does this change pose to our availability? How might it affect the quality of the product? What additional test coverage or changes to tests will be needed? Will it require cross-browser testing?
Please list the test areas (unit, integration and end-to-end) that needs to be added or updated to ensure that this feature will work as intended. Plese use the list below as guidance. Please list the test areas (unit, integration and end-to-end) that needs to be added or updated to ensure that this feature will work as intended. Please use the list below as guidance.
* Unit test changes * Unit test changes
* Integration test changes * Integration test changes
* End-to-end test change * End-to-end test change
See the test engineering planning process and reach out to your counterpart Software Engineer in Test for assistance : https://about.gitlab.com/handbook/engineering/quality/test-engineering/#test-planning --> See the test engineering planning process and reach out to your counterpart Software Engineer in Test for assistance: https://about.gitlab.com/handbook/engineering/quality/test-engineering/#test-planning -->
### What does success look like, and how can we measure that? ### What does success look like, and how can we measure that?
......
...@@ -4,7 +4,6 @@ entry. ...@@ -4,7 +4,6 @@ entry.
## 12.7.0 ## 12.7.0
- No changes.
### Security (6 changes, 2 of them are from the community) ### Security (6 changes, 2 of them are from the community)
- Ensure content matches extension on image uploads. !20697 - Ensure content matches extension on image uploads. !20697
......
12.8.0-pre 12.7.0-pre
...@@ -311,7 +311,10 @@ export default { ...@@ -311,7 +311,10 @@ export default {
<gl-tooltip :target="() => $refs.graphTitle" :disabled="!showTitleTooltip"> <gl-tooltip :target="() => $refs.graphTitle" :disabled="!showTitleTooltip">
{{ graphData.title }} {{ graphData.title }}
</gl-tooltip> </gl-tooltip>
<div class="prometheus-graph-widgets js-graph-widgets flex-fill"> <div
class="prometheus-graph-widgets js-graph-widgets flex-fill"
data-qa-selector="prometheus_graph_widgets"
>
<slot></slot> <slot></slot>
</div> </div>
</div> </div>
......
...@@ -342,7 +342,7 @@ export default { ...@@ -342,7 +342,7 @@ export default {
</script> </script>
<template> <template>
<div class="prometheus-graphs"> <div class="prometheus-graphs" data-qa-selector="prometheus_graphs">
<div class="prometheus-graphs-header gl-p-3 pb-0 border-bottom bg-gray-light"> <div class="prometheus-graphs-header gl-p-3 pb-0 border-bottom bg-gray-light">
<div class="row"> <div class="row">
<template v-if="environmentsEndpoint"> <template v-if="environmentsEndpoint">
......
...@@ -138,6 +138,7 @@ export default { ...@@ -138,6 +138,7 @@ export default {
v-gl-tooltip v-gl-tooltip
class="ml-auto mx-3" class="ml-auto mx-3"
toggle-class="btn btn-transparent border-0" toggle-class="btn btn-transparent border-0"
data-qa-selector="prometheus_widgets_dropdown"
:right="true" :right="true"
:no-caret="true" :no-caret="true"
:title="__('More actions')" :title="__('More actions')"
...@@ -161,7 +162,11 @@ export default { ...@@ -161,7 +162,11 @@ export default {
> >
{{ __('Generate link to chart') }} {{ __('Generate link to chart') }}
</gl-dropdown-item> </gl-dropdown-item>
<gl-dropdown-item v-if="alertWidgetAvailable" v-gl-modal="`alert-modal-${index}`"> <gl-dropdown-item
v-if="alertWidgetAvailable"
v-gl-modal="`alert-modal-${index}`"
data-qa-selector="alert_widget_menu_item"
>
{{ __('Alerts') }} {{ __('Alerts') }}
</gl-dropdown-item> </gl-dropdown-item>
</gl-dropdown> </gl-dropdown>
......
...@@ -11,7 +11,7 @@ old_notes_spec.js is the spec for the legacy, jQuery notes application. It has n ...@@ -11,7 +11,7 @@ old_notes_spec.js is the spec for the legacy, jQuery notes application. It has n
*/ */
import $ from 'jquery'; import $ from 'jquery';
import _ from 'underscore'; import { escape, uniqueId } from 'lodash';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import Autosize from 'autosize'; import Autosize from 'autosize';
import 'jquery.caret'; // required by at.js import 'jquery.caret'; // required by at.js
...@@ -1449,7 +1449,7 @@ export default class Notes { ...@@ -1449,7 +1449,7 @@ export default class Notes {
return { return {
// eslint-disable-next-line no-jquery/no-serialize // eslint-disable-next-line no-jquery/no-serialize
formData: $form.serialize(), formData: $form.serialize(),
formContent: _.escape(content), formContent: escape(content),
formAction: $form.attr('action'), formAction: $form.attr('action'),
formContentOriginal: content, formContentOriginal: content,
}; };
...@@ -1516,18 +1516,16 @@ export default class Notes { ...@@ -1516,18 +1516,16 @@ export default class Notes {
`<li id="${uniqueId}" class="note being-posted fade-in-half timeline-entry"> `<li id="${uniqueId}" class="note being-posted fade-in-half timeline-entry">
<div class="timeline-entry-inner"> <div class="timeline-entry-inner">
<div class="timeline-icon"> <div class="timeline-icon">
<a href="/${_.escape(currentUsername)}"> <a href="/${escape(currentUsername)}">
<img class="avatar s40" src="${currentUserAvatar}" /> <img class="avatar s40" src="${currentUserAvatar}" />
</a> </a>
</div> </div>
<div class="timeline-content ${discussionClass}"> <div class="timeline-content ${discussionClass}">
<div class="note-header"> <div class="note-header">
<div class="note-header-info"> <div class="note-header-info">
<a href="/${_.escape(currentUsername)}"> <a href="/${escape(currentUsername)}">
<span class="d-none d-sm-inline-block bold">${_.escape( <span class="d-none d-sm-inline-block bold">${escape(currentUsername)}</span>
currentUsername, <span class="note-headline-light">${escape(currentUsername)}</span>
)}</span>
<span class="note-headline-light">${_.escape(currentUsername)}</span>
</a> </a>
</div> </div>
</div> </div>
...@@ -1541,8 +1539,8 @@ export default class Notes { ...@@ -1541,8 +1539,8 @@ export default class Notes {
</li>`, </li>`,
); );
$tempNote.find('.d-none.d-sm-inline-block').text(_.escape(currentUserFullname)); $tempNote.find('.d-none.d-sm-inline-block').text(escape(currentUserFullname));
$tempNote.find('.note-headline-light').text(`@${_.escape(currentUsername)}`); $tempNote.find('.note-headline-light').text(`@${escape(currentUsername)}`);
return $tempNote; return $tempNote;
} }
...@@ -1627,7 +1625,7 @@ export default class Notes { ...@@ -1627,7 +1625,7 @@ export default class Notes {
// Show placeholder note // Show placeholder note
if (tempFormContent) { if (tempFormContent) {
noteUniqueId = _.uniqueId('tempNote_'); noteUniqueId = uniqueId('tempNote_');
$notesContainer.append( $notesContainer.append(
this.createPlaceholderNote({ this.createPlaceholderNote({
formContent: tempFormContent, formContent: tempFormContent,
...@@ -1642,7 +1640,7 @@ export default class Notes { ...@@ -1642,7 +1640,7 @@ export default class Notes {
// Show placeholder system note // Show placeholder system note
if (hasQuickActions) { if (hasQuickActions) {
systemNoteUniqueId = _.uniqueId('tempSystemNote_'); systemNoteUniqueId = uniqueId('tempSystemNote_');
$notesContainer.append( $notesContainer.append(
this.createPlaceholderSystemNote({ this.createPlaceholderSystemNote({
formContent: this.getQuickActionDescription( formContent: this.getQuickActionDescription(
...@@ -1825,7 +1823,7 @@ export default class Notes { ...@@ -1825,7 +1823,7 @@ export default class Notes {
}) })
.catch(() => { .catch(() => {
// Submission failed, revert back to original note // Submission failed, revert back to original note
$noteBodyText.html(_.escape(cachedNoteBodyText)); $noteBodyText.html(escape(cachedNoteBodyText));
$editingNote.removeClass('being-posted fade-in'); $editingNote.removeClass('being-posted fade-in');
$editingNote.find('.fa.fa-spinner').remove(); $editingNote.find('.fa.fa-spinner').remove();
......
...@@ -331,6 +331,7 @@ export default { ...@@ -331,6 +331,7 @@ export default {
:loading="isRetrying" :loading="isRetrying"
:disabled="isRetrying" :disabled="isRetrying"
container-class="js-pipelines-retry-button btn btn-default btn-retry" container-class="js-pipelines-retry-button btn btn-default btn-retry"
data-qa-selector="pipeline_retry_button"
@click="handleRetryClick" @click="handleRetryClick"
> >
<icon name="repeat" /> <icon name="repeat" />
......
...@@ -232,7 +232,7 @@ ...@@ -232,7 +232,7 @@
- if project_nav_tab? :environments - if project_nav_tab? :environments
= nav_link(controller: :environments, action: [:metrics, :metrics_redirect]) do = nav_link(controller: :environments, action: [:metrics, :metrics_redirect]) do
= link_to metrics_project_environments_path(@project), title: _('Metrics'), class: 'shortcuts-metrics' do = link_to metrics_project_environments_path(@project), title: _('Metrics'), class: 'shortcuts-metrics', data: { qa_selector: 'operations_metrics_link' } do
%span %span
= _('Metrics') = _('Metrics')
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
.form-group.row .form-group.row
= form.label :active, "Active", class: "col-form-label col-sm-2" = form.label :active, "Active", class: "col-form-label col-sm-2"
.col-sm-10 .col-sm-10
= form.check_box :active, disabled: disable_fields_service?(@service), data: { qa_selector: 'active_checkbox' } = form.check_box :active, checked: @service.active || @service.new_record?, disabled: disable_fields_service?(@service)
- if @service.configurable_events.present? - if @service.configurable_events.present?
.form-group.row .form-group.row
......
...@@ -22,6 +22,7 @@ const plugins = [ ...@@ -22,6 +22,7 @@ const plugins = [
'@babel/plugin-proposal-json-strings', '@babel/plugin-proposal-json-strings',
'@babel/plugin-proposal-private-methods', '@babel/plugin-proposal-private-methods',
'@babel/plugin-proposal-optional-chaining', '@babel/plugin-proposal-optional-chaining',
'lodash',
]; ];
// add code coverage tooling if necessary // add code coverage tooling if necessary
......
---
title: Activate new project integrations by default
merge_request: 23009
author:
type: changed
...@@ -92,6 +92,7 @@ const alias = { ...@@ -92,6 +92,7 @@ const alias = {
vendor: path.join(ROOT_PATH, 'vendor/assets/javascripts'), vendor: path.join(ROOT_PATH, 'vendor/assets/javascripts'),
vue$: 'vue/dist/vue.esm.js', vue$: 'vue/dist/vue.esm.js',
spec: path.join(ROOT_PATH, 'spec/javascripts'), spec: path.join(ROOT_PATH, 'spec/javascripts'),
jest: path.join(ROOT_PATH, 'spec/frontend'),
// the following resolves files which are different between CE and EE // the following resolves files which are different between CE and EE
ee_else_ce: path.join(ROOT_PATH, 'app/assets/javascripts'), ee_else_ce: path.join(ROOT_PATH, 'app/assets/javascripts'),
...@@ -111,6 +112,7 @@ if (IS_EE) { ...@@ -111,6 +112,7 @@ if (IS_EE) {
ee_icons: path.join(ROOT_PATH, 'ee/app/views/shared/icons'), ee_icons: path.join(ROOT_PATH, 'ee/app/views/shared/icons'),
ee_images: path.join(ROOT_PATH, 'ee/app/assets/images'), ee_images: path.join(ROOT_PATH, 'ee/app/assets/images'),
ee_spec: path.join(ROOT_PATH, 'ee/spec/javascripts'), ee_spec: path.join(ROOT_PATH, 'ee/spec/javascripts'),
ee_jest: path.join(ROOT_PATH, 'ee/spec/frontend'),
ee_else_ce: path.join(ROOT_PATH, 'ee/app/assets/javascripts'), ee_else_ce: path.join(ROOT_PATH, 'ee/app/assets/javascripts'),
}); });
} }
......
...@@ -6,23 +6,24 @@ description: "Learn how long your open merge requests have spent in code review, ...@@ -6,23 +6,24 @@ description: "Learn how long your open merge requests have spent in code review,
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/38062) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.7. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/38062) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.7.
Code Review Analytics can be used to answer questions like: Code Review Analytics makes it easy to view the longest-running reviews among open merge requests,
enabling you to take action on individual MRs and reduce overall cycle time.
- How long do open merge requests spend in code review?
- What distinguishes your longest-running code reviews?
NOTE: **Note:** NOTE: **Note:**
Initially no data will appear. Data is populated as users comment on open merge requests. Initially, no data will appear. Data is populated as users comment on open merge requests.
## Overview ## Overview
Code Review Analytics displays a table of open merge requests, which are considered to be in code review. Code Review Analytics displays a table of open merge requests which are currently considered to be in code review.
Code review starts when a merge request receives its first comment from someone other than the author. The code review period for an MR is automatically identified as the time since the first non-author comment.
To access Code Review Analytics, from your project's menu, go to **Project Analytics > Code Review**.
The Code Review Analytics table: - The table is sorted by review duration, helping you quickly find the longest-running reviews which may need intervention or to be broken down into smaller parts.
- You can filter the list of MRs by milestone and label.
- Columns to display the author, approvers, comment count, and line change (-/+) counts.
- Is sorted by review time, so the longest reviews appear at the top. ## Use cases
- Has columns to display the author, approvers, comment count, and line -/+ counts.
This feature is designed for [development team leaders](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#delaney-development-team-lead) This feature is designed for [development team leaders](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#delaney-development-team-lead)
and others who want to understand broad code review dynamics, and identify patterns to help explain them. and others who want to understand broad code review dynamics, and identify patterns to help explain them.
...@@ -30,14 +31,12 @@ and others who want to understand broad code review dynamics, and identify patte ...@@ -30,14 +31,12 @@ and others who want to understand broad code review dynamics, and identify patte
You can use Code Review Analytics to expose your team's unique challenges with code review, and You can use Code Review Analytics to expose your team's unique challenges with code review, and
identify improvements that might substantially accelerate your development cycle. identify improvements that might substantially accelerate your development cycle.
## Use cases
Code Review Analytics can be used when: Code Review Analytics can be used when:
- Your team agrees that code review is moving too slow. - Your team agrees that code review is moving too slow.
- The [Cycle Analytics feature](cycle_analytics.md) shows that reviews are your team's most time-consuming step. - The [Cycle Analytics feature](cycle_analytics.md) shows that reviews are your team's most time-consuming step.
You can use Code Review Analytics to see what is currently moving slowest, and analyze the patterns You can use Code Review Analytics to see the types of work that are currently moving the slowest, and analyze the patterns
and trends between them. For example: and trends between them. For example:
- Lots of comments or commits? Maybe the code is too complex. - Lots of comments or commits? Maybe the code is too complex.
......
...@@ -38,6 +38,7 @@ const moduleNameMapper = { ...@@ -38,6 +38,7 @@ const moduleNameMapper = {
'\\.(jpg|jpeg|png|svg)$': '<rootDir>/spec/frontend/__mocks__/file_mock.js', '\\.(jpg|jpeg|png|svg)$': '<rootDir>/spec/frontend/__mocks__/file_mock.js',
'emojis(/.*).json': '<rootDir>/fixtures/emojis$1.json', 'emojis(/.*).json': '<rootDir>/fixtures/emojis$1.json',
'^spec/test_constants$': '<rootDir>/spec/frontend/helpers/test_constants', '^spec/test_constants$': '<rootDir>/spec/frontend/helpers/test_constants',
'^jest/(.*)$': '<rootDir>/spec/frontend/$1',
}; };
const collectCoverageFrom = ['<rootDir>/app/assets/javascripts/**/*.{js,vue}']; const collectCoverageFrom = ['<rootDir>/app/assets/javascripts/**/*.{js,vue}'];
...@@ -48,6 +49,7 @@ if (IS_EE) { ...@@ -48,6 +49,7 @@ if (IS_EE) {
'^ee(/.*)$': rootDirEE, '^ee(/.*)$': rootDirEE,
'^ee_component(/.*)$': rootDirEE, '^ee_component(/.*)$': rootDirEE,
'^ee_else_ce(/.*)$': rootDirEE, '^ee_else_ce(/.*)$': rootDirEE,
'^ee_jest/(.*)$': '<rootDir>/ee/spec/frontend/$1',
}); });
collectCoverageFrom.push(rootDirEE.replace('$1', '/**/*.{js,vue}')); collectCoverageFrom.push(rootDirEE.replace('$1', '/**/*.{js,vue}'));
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
"aws-sdk": "^2.526.0", "aws-sdk": "^2.526.0",
"axios": "^0.19.0", "axios": "^0.19.0",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"babel-plugin-lodash": "^3.3.4",
"bootstrap": "4.3.1", "bootstrap": "4.3.1",
"brace-expansion": "^1.1.8", "brace-expansion": "^1.1.8",
"cache-loader": "^4.1.0", "cache-loader": "^4.1.0",
...@@ -94,6 +95,7 @@ ...@@ -94,6 +95,7 @@
"jszip": "^3.1.3", "jszip": "^3.1.3",
"jszip-utils": "^0.0.2", "jszip-utils": "^0.0.2",
"katex": "^0.10.0", "katex": "^0.10.0",
"lodash": "^4.17.15",
"marked": "^0.3.12", "marked": "^0.3.12",
"mermaid": "^8.4.5", "mermaid": "^8.4.5",
"monaco-editor": "^0.18.1", "monaco-editor": "^0.18.1",
......
...@@ -289,6 +289,8 @@ module QA ...@@ -289,6 +289,8 @@ module QA
autoload :AddExisting, 'qa/page/project/operations/kubernetes/add_existing' autoload :AddExisting, 'qa/page/project/operations/kubernetes/add_existing'
autoload :Show, 'qa/page/project/operations/kubernetes/show' autoload :Show, 'qa/page/project/operations/kubernetes/show'
end end
autoload :Metrics, 'qa/page/project/operations/metrics'
end end
module Wiki module Wiki
......
This diff is collapsed.
...@@ -21,9 +21,9 @@ module QA ...@@ -21,9 +21,9 @@ module QA
has_element?(:performance_bar) has_element?(:performance_bar)
end end
def has_detailed_metrics?(count) def has_detailed_metrics?(minimum_count)
retry_until(sleep_interval: 1) do retry_until(sleep_interval: 1) do
all_elements(:detailed_metric_content, count: count).all? do |metric| all_elements(:detailed_metric_content, minimum: minimum_count).all? do |metric|
metric.has_text?(%r{\d+}) metric.has_text?(%r{\d+})
end end
end end
......
# frozen_string_literal: true
module QA
module Page
module Project
module Operations
class Metrics < Page::Base
EXPECTED_TITLE = 'Memory Usage (Total)'
EXPECTED_LABEL = 'Total (GB)'
LOADING_MESSAGE = 'Waiting for performance data'
view 'app/assets/javascripts/monitoring/components/dashboard.vue' do
element :prometheus_graphs
end
view 'app/assets/javascripts/monitoring/components/charts/time_series.vue' do
element :prometheus_graph_widgets
end
view 'app/assets/javascripts/monitoring/components/panel_type.vue' do
element :prometheus_widgets_dropdown
element :alert_widget_menu_item
end
view 'ee/app/assets/javascripts/monitoring/components/alert_widget_form.vue' do
element :alert_query_dropdown
element :alert_query_option
element :alert_threshold_field
end
def wait_for_metrics
wait_for_data
return if has_metrics?
wait_until(max_duration: 180) do
wait_for_data
has_metrics?
end
end
def wait_for_data
wait_until(reload: false) { !has_text?(LOADING_MESSAGE) } if has_text?(LOADING_MESSAGE)
end
def has_metrics?
within_element :prometheus_graphs do
has_text?(EXPECTED_TITLE)
end
end
def wait_for_alert(operator = '>', threshold = 0)
wait_until(reload: false) { has_alert?(operator, threshold) }
end
def has_alert?(operator = '>', threshold = 0)
within_element :prometheus_graphs do
has_text?([EXPECTED_LABEL, operator, threshold].join(' '))
end
end
def write_first_alert(operator = '>', threshold = 0)
open_first_alert_modal
click_on operator
fill_element :alert_threshold_field, threshold
within('.modal-content') { click_button(class: 'btn-success') }
end
def delete_first_alert
open_first_alert_modal
within('.modal-content') { click_button(class: 'btn-danger') }
wait_for_requests
end
def open_first_alert_modal
all_elements(:prometheus_widgets_dropdown, minimum: 1).first.click
click_element :alert_widget_menu_item
click_element :alert_query_dropdown unless has_element?(:alert_query_option, wait: 3)
all_elements(:alert_query_option, minimum: 1).first.click
end
end
end
end
end
end
...@@ -9,6 +9,7 @@ module QA::Page ...@@ -9,6 +9,7 @@ module QA::Page
view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do
element :pipeline_commit_status element :pipeline_commit_status
element :pipeline_retry_button
end end
def click_on_latest_pipeline def click_on_latest_pipeline
...@@ -18,11 +19,26 @@ module QA::Page ...@@ -18,11 +19,26 @@ module QA::Page
end end
def wait_for_latest_pipeline_success def wait_for_latest_pipeline_success
wait_for_latest_pipeline_status { has_text?('passed') }
end
def wait_for_latest_pipeline_completion
wait_for_latest_pipeline_status { has_text?('passed') || has_text?('failed') }
end
def wait_for_latest_pipeline_status
wait_until(reload: false, max_duration: 300) do wait_until(reload: false, max_duration: 300) do
within_element_by_index(:pipeline_commit_status, 0) do within_element_by_index(:pipeline_commit_status, 0) { yield }
has_text?('passed')
end end
end end
def wait_for_latest_pipeline_success_or_retry
wait_for_latest_pipeline_completion
if has_text?('failed')
click_element :pipeline_retry_button
wait_for_latest_pipeline_success
end
end end
end end
end end
......
...@@ -12,6 +12,7 @@ module QA ...@@ -12,6 +12,7 @@ module QA
view 'app/views/layouts/nav/sidebar/_project.html.haml' do view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :link_operations element :link_operations
element :operations_environments_link element :operations_environments_link
element :operations_metrics_link
end end
end end
end end
...@@ -24,6 +25,14 @@ module QA ...@@ -24,6 +25,14 @@ module QA
end end
end end
def go_to_operations_metrics
hover_operations do
within_submenu do
click_element(:operations_metrics_link)
end
end
end
def go_to_operations_kubernetes def go_to_operations_kubernetes
hover_operations do hover_operations do
within_submenu do within_submenu do
......
...@@ -4,8 +4,8 @@ module QA ...@@ -4,8 +4,8 @@ module QA
context 'Non-devops' do context 'Non-devops' do
describe 'Performance bar display', :requires_admin do describe 'Performance bar display', :requires_admin do
context 'when logged in as an admin user' do context 'when logged in as an admin user' do
# 4 metrics: pg, gitaly, redis, total # performance metrics: pg, gitaly, redis, rugged (feature flagged), total (not always provided)
let(:metrics_count) { 4 } let(:minimum_metrics_count) { 3 }
before do before do
Flow::Login.sign_in_as_admin Flow::Login.sign_in_as_admin
...@@ -28,7 +28,7 @@ module QA ...@@ -28,7 +28,7 @@ module QA
Page::Layout::PerformanceBar.perform do |bar_component| Page::Layout::PerformanceBar.perform do |bar_component|
expect(bar_component).to have_performance_bar expect(bar_component).to have_performance_bar
expect(bar_component).to have_detailed_metrics(metrics_count) expect(bar_component).to have_detailed_metrics(minimum_metrics_count)
expect(bar_component).to have_request_for('realtime_changes') # Always requested on issue pages expect(bar_component).to have_request_for('realtime_changes') # Always requested on issue pages
end end
end end
......
...@@ -8,16 +8,15 @@ describe 'User activates issue tracker', :js do ...@@ -8,16 +8,15 @@ describe 'User activates issue tracker', :js do
let(:url) { 'http://tracker.example.com' } let(:url) { 'http://tracker.example.com' }
def fill_short_form(active = true) def fill_short_form(disabled: false)
check 'Active' if active uncheck 'Active' if disabled
fill_in 'service_project_url', with: url fill_in 'service_project_url', with: url
fill_in 'service_issues_url', with: "#{url}/:id" fill_in 'service_issues_url', with: "#{url}/:id"
end end
def fill_full_form(active = true) def fill_full_form(disabled: false)
fill_short_form(active) fill_short_form(disabled: disabled)
check 'Active' if active
fill_in 'service_new_issue_url', with: url fill_in 'service_new_issue_url', with: url
end end
...@@ -86,14 +85,14 @@ describe 'User activates issue tracker', :js do ...@@ -86,14 +85,14 @@ describe 'User activates issue tracker', :js do
end end
end end
describe 'user sets the service but keeps it disabled' do describe 'user disables the service' do
before do before do
click_link(tracker) click_link(tracker)
if skip_new_issue_url if skip_new_issue_url
fill_short_form(false) fill_short_form(disabled: true)
else else
fill_full_form(false) fill_full_form(disabled: true)
end end
click_button('Save changes') click_button('Save changes')
......
...@@ -9,8 +9,8 @@ describe 'User activates Jira', :js do ...@@ -9,8 +9,8 @@ describe 'User activates Jira', :js do
let(:url) { 'http://jira.example.com' } let(:url) { 'http://jira.example.com' }
let(:test_url) { 'http://jira.example.com/rest/api/2/serverInfo' } let(:test_url) { 'http://jira.example.com/rest/api/2/serverInfo' }
def fill_form(active = true) def fill_form(disabled: false)
check 'Active' if active uncheck 'Active' if disabled
fill_in 'service_url', with: url fill_in 'service_url', with: url
fill_in 'service_username', with: 'username' fill_in 'service_username', with: 'username'
...@@ -83,10 +83,10 @@ describe 'User activates Jira', :js do ...@@ -83,10 +83,10 @@ describe 'User activates Jira', :js do
end end
end end
describe 'user sets Jira Service but keeps it disabled' do describe 'user disables the Jira Service' do
before do before do
click_link('Jira') click_link('Jira')
fill_form(false) fill_form(disabled: true)
click_button('Save changes') click_button('Save changes')
end end
......
...@@ -8,8 +8,8 @@ describe 'User activates issue tracker', :js do ...@@ -8,8 +8,8 @@ describe 'User activates issue tracker', :js do
let(:url) { 'http://tracker.example.com' } let(:url) { 'http://tracker.example.com' }
def fill_form(active = true) def fill_form(disabled: false)
check 'Active' if active uncheck 'Active' if disabled
fill_in 'service_project_url', with: url fill_in 'service_project_url', with: url
fill_in 'service_issues_url', with: "#{url}/:id" fill_in 'service_issues_url', with: "#{url}/:id"
...@@ -67,10 +67,10 @@ describe 'User activates issue tracker', :js do ...@@ -67,10 +67,10 @@ describe 'User activates issue tracker', :js do
end end
end end
describe 'user sets the service but keeps it disabled' do describe 'user disables the service' do
before do before do
click_link(tracker) click_link(tracker)
fill_form(false) fill_form(disabled: true)
click_button('Save changes') click_button('Save changes')
end end
......
...@@ -46,6 +46,13 @@ describe 'Multi-file editor new directory', :js do ...@@ -46,6 +46,13 @@ describe 'Multi-file editor new directory', :js do
find('.js-ide-commit-mode').click find('.js-ide-commit-mode').click
# Compact mode depends on the size of window. If it is shorter than MAX_WINDOW_HEIGHT_COMPACT,
# (as it is with CHROME_HEADLESS=0), this initial commit button will exist. Otherwise, if it is
# taller (as it is by default with chrome headless) then the button will not exist.
if page.has_css?('.qa-begin-commit-button')
find('.qa-begin-commit-button').click
end
fill_in('commit-message', with: 'commit message ide') fill_in('commit-message', with: 'commit message ide')
find(:css, ".js-ide-commit-new-mr input").set(false) find(:css, ".js-ide-commit-new-mr input").set(false)
......
...@@ -36,6 +36,13 @@ describe 'Multi-file editor new file', :js do ...@@ -36,6 +36,13 @@ describe 'Multi-file editor new file', :js do
find('.js-ide-commit-mode').click find('.js-ide-commit-mode').click
# Compact mode depends on the size of window. If it is shorter than MAX_WINDOW_HEIGHT_COMPACT,
# (as it is with CHROME_HEADLESS=0), this initial commit button will exist. Otherwise, if it is
# taller (as it is by default with chrome headless) then the button will not exist.
if page.has_css?('.qa-begin-commit-button')
find('.qa-begin-commit-button').click
end
fill_in('commit-message', with: 'commit message ide') fill_in('commit-message', with: 'commit message ide')
find(:css, ".js-ide-commit-new-mr input").set(false) find(:css, ".js-ide-commit-new-mr input").set(false)
......
/* global ListAssignee, ListLabel, ListIssue */ /* global ListAssignee, ListLabel, ListIssue */
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import _ from 'underscore'; import { range } from 'lodash';
import '~/boards/models/label'; import '~/boards/models/label';
import '~/boards/models/assignee'; import '~/boards/models/assignee';
import '~/boards/models/issue'; import '~/boards/models/issue';
...@@ -222,7 +222,7 @@ describe('Issue card component', () => { ...@@ -222,7 +222,7 @@ describe('Issue card component', () => {
it('renders 99+ avatar counter', done => { it('renders 99+ avatar counter', done => {
const assignees = [ const assignees = [
...wrapper.props('issue').assignees, ...wrapper.props('issue').assignees,
..._.range(5, 103).map( ...range(5, 103).map(
i => i =>
new ListAssignee({ new ListAssignee({
id: i, id: i,
......
import _ from 'underscore'; import { pick, clone } from 'lodash';
import Vuex from 'vuex'; import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
...@@ -15,7 +15,7 @@ describe('error tracking settings project dropdown', () => { ...@@ -15,7 +15,7 @@ describe('error tracking settings project dropdown', () => {
wrapper = shallowMount(ProjectDropdown, { wrapper = shallowMount(ProjectDropdown, {
localVue, localVue,
propsData: { propsData: {
..._.pick( ...pick(
defaultProps, defaultProps,
'dropdownLabel', 'dropdownLabel',
'invalidProjectLabel', 'invalidProjectLabel',
...@@ -65,7 +65,7 @@ describe('error tracking settings project dropdown', () => { ...@@ -65,7 +65,7 @@ describe('error tracking settings project dropdown', () => {
describe('populated project list', () => { describe('populated project list', () => {
beforeEach(() => { beforeEach(() => {
wrapper.setProps({ projects: _.clone(projectList), hasProjects: true }); wrapper.setProps({ projects: clone(projectList), hasProjects: true });
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -82,10 +82,10 @@ describe('error tracking settings project dropdown', () => { ...@@ -82,10 +82,10 @@ describe('error tracking settings project dropdown', () => {
}); });
describe('selected project', () => { describe('selected project', () => {
const selectedProject = _.clone(projectList[0]); const selectedProject = clone(projectList[0]);
beforeEach(() => { beforeEach(() => {
wrapper.setProps({ projects: _.clone(projectList), selectedProject, hasProjects: true }); wrapper.setProps({ projects: clone(projectList), selectedProject, hasProjects: true });
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -98,7 +98,7 @@ describe('error tracking settings project dropdown', () => { ...@@ -98,7 +98,7 @@ describe('error tracking settings project dropdown', () => {
describe('invalid project selected', () => { describe('invalid project selected', () => {
beforeEach(() => { beforeEach(() => {
wrapper.setProps({ wrapper.setProps({
projects: _.clone(projectList), projects: clone(projectList),
selectedProject: staleProject, selectedProject: staleProject,
isProjectInvalid: true, isProjectInvalid: true,
}); });
......
/* eslint-disable import/no-commonjs, no-new */ /* eslint-disable import/no-commonjs, no-new */
import $ from 'jquery'; import $ from 'jquery';
import _ from 'underscore';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import '~/behaviors/markdown/render_gfm'; import '~/behaviors/markdown/render_gfm';
import { createSpyObj } from 'helpers/jest_helpers'; import { createSpyObj } from 'helpers/jest_helpers';
...@@ -792,14 +791,11 @@ describe('Old Notes (~/notes.js)', () => { ...@@ -792,14 +791,11 @@ describe('Old Notes (~/notes.js)', () => {
}); });
it('should return form metadata with sanitized formContent from form reference', () => { it('should return form metadata with sanitized formContent from form reference', () => {
jest.spyOn(_, 'escape');
sampleComment = '<script>alert("Boom!");</script>'; sampleComment = '<script>alert("Boom!");</script>';
$form.find('textarea.js-note-text').val(sampleComment); $form.find('textarea.js-note-text').val(sampleComment);
const { formContent } = notes.getFormData($form); const { formContent } = notes.getFormData($form);
expect(_.escape).toHaveBeenCalledWith(sampleComment);
expect(formContent).toEqual('&lt;script&gt;alert(&quot;Boom!&quot;);&lt;/script&gt;'); expect(formContent).toEqual('&lt;script&gt;alert(&quot;Boom!&quot;);&lt;/script&gt;');
}); });
}); });
...@@ -990,7 +986,6 @@ describe('Old Notes (~/notes.js)', () => { ...@@ -990,7 +986,6 @@ describe('Old Notes (~/notes.js)', () => {
beforeEach(() => { beforeEach(() => {
notes = new Notes('', []); notes = new Notes('', []);
jest.spyOn(_, 'escape');
}); });
it('should return constructed placeholder element for system note based on form contents', () => { it('should return constructed placeholder element for system note based on form contents', () => {
......
import _ from 'underscore'; import { each } from 'lodash';
import { trimText } from 'helpers/text_helper'; import { trimText } from 'helpers/text_helper';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
...@@ -58,7 +58,7 @@ describe('User Avatar Link Component', () => { ...@@ -58,7 +58,7 @@ describe('User Avatar Link Component', () => {
}); });
it('should return necessary props as defined', () => { it('should return necessary props as defined', () => {
_.each(defaultProps, (val, key) => { each(defaultProps, (val, key) => {
expect(wrapper.vm[key]).toBeDefined(); expect(wrapper.vm[key]).toBeDefined();
}); });
}); });
......
...@@ -122,12 +122,12 @@ ...@@ -122,12 +122,12 @@
dependencies: dependencies:
"@babel/types" "^7.5.5" "@babel/types" "^7.5.5"
"@babel/helper-module-imports@^7.0.0": "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.0.0-beta.49":
version "7.0.0" version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498"
integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==
dependencies: dependencies:
"@babel/types" "^7.0.0" "@babel/types" "^7.8.3"
"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": "@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4":
version "7.5.5" version "7.5.5"
...@@ -683,10 +683,10 @@ ...@@ -683,10 +683,10 @@
globals "^11.1.0" globals "^11.1.0"
lodash "^4.17.13" lodash "^4.17.13"
"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0": "@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0", "@babel/types@^7.8.3":
version "7.6.1" version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.6.1.tgz#53abf3308add3ac2a2884d539151c57c4b3ac648" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c"
integrity sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g== integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==
dependencies: dependencies:
esutils "^2.0.2" esutils "^2.0.2"
lodash "^4.17.13" lodash "^4.17.13"
...@@ -1890,6 +1890,17 @@ babel-plugin-jest-hoist@^24.6.0: ...@@ -1890,6 +1890,17 @@ babel-plugin-jest-hoist@^24.6.0:
dependencies: dependencies:
"@types/babel__traverse" "^7.0.6" "@types/babel__traverse" "^7.0.6"
babel-plugin-lodash@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.4.tgz#4f6844358a1340baed182adbeffa8df9967bc196"
integrity sha512-yDZLjK7TCkWl1gpBeBGmuaDIFhZKmkoL+Cu2MUUjv5VxUZx/z7tBGBCBcQs5RI1Bkz5LLmNdjx7paOyQtMovyg==
dependencies:
"@babel/helper-module-imports" "^7.0.0-beta.49"
"@babel/types" "^7.0.0-beta.49"
glob "^7.1.1"
lodash "^4.17.10"
require-package-name "^2.0.1"
babel-plugin-rewire@^1.2.0: babel-plugin-rewire@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/babel-plugin-rewire/-/babel-plugin-rewire-1.2.0.tgz#822562d72ed2c84e47c0f95ee232c920853e9d89" resolved "https://registry.yarnpkg.com/babel-plugin-rewire/-/babel-plugin-rewire-1.2.0.tgz#822562d72ed2c84e47c0f95ee232c920853e9d89"
...@@ -9725,6 +9736,11 @@ require-main-filename@^2.0.0: ...@@ -9725,6 +9736,11 @@ require-main-filename@^2.0.0:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
require-package-name@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9"
integrity sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk=
require-uncached@^1.0.3: require-uncached@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
......
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