提交 fe289cff 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 40cdcdd4
......@@ -404,7 +404,6 @@ RSpec/LeakyConstantDeclaration:
- 'spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb'
- 'spec/support_specs/helpers/active_record/query_recorder_spec.rb'
- 'spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb'
- 'spec/uploaders/content_type_whitelist_spec.rb'
- 'spec/uploaders/records_uploads_spec.rb'
RSpec/EmptyLineAfterHook:
......
......@@ -13,7 +13,7 @@ import {
} from '@gitlab/ui';
import createFlash from '~/flash';
import { s__ } from '~/locale';
import { joinPaths } from '~/lib/utils/url_utility';
import { joinPaths, visitUrl } from '~/lib/utils/url_utility';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import getAlerts from '../graphql/queries/getAlerts.query.graphql';
import { ALERTS_STATUS, ALERTS_STATUS_TABS, ALERTS_SEVERITY_LABELS } from '../constants';
......@@ -165,6 +165,9 @@ export default {
projectPath: this.projectPath,
},
})
.then(() => {
this.$apollo.queries.alerts.refetch();
})
.catch(() => {
createFlash(
s__(
......@@ -173,13 +176,12 @@ export default {
);
});
},
handleRowClick({ iid }) {
window.location.assign(joinPaths(window.location.pathname, iid, 'details'));
navigateToAlertDetails({ iid }) {
return visitUrl(joinPaths(window.location.pathname, iid, 'details'));
},
},
};
</script>
<template>
<div>
<div v-if="alertManagementEnabled" class="alert-management-list">
......@@ -209,7 +211,7 @@ export default {
:busy="loading"
stacked="md"
:tbody-tr-class="$options.bodyTrClass"
@row-clicked="handleRowClick"
@row-clicked="navigateToAlertDetails"
>
<template #cell(severity)="{ item }">
<div
......
......@@ -60,7 +60,7 @@ export default {
footer-primary-button-variant="danger"
@submit="onSubmit"
>
<template slot="header">
<template #header>
<h4 class="modal-title d-flex mw-100">
Stopping
<span v-gl-tooltip :title="environment.name" class="text-truncate ml-1 mr-1 flex-fill">
......
......@@ -45,6 +45,6 @@
%button.btn.btn-transparent
= icon('check', class: 'icon')
.description
%strong.title = _('Report abuse')
%strong.title= _('Report abuse')
%p.text
= _('Report %{display_issuable_type} that are abusive, inappropriate or spam.') % { display_issuable_type: display_issuable_type.pluralize }
---
title: Use visitUrl in Alert management
merge_request: 32414
author:
type: other
---
title: Add class stubs and fix leaky constant alert in content whitelist spec
merge_request: 31946
author: Rajendra Kadam
type: fixed
---
title: Update deprecated slot syntax in ./app/assets/javascripts/environments/components/stop_environment_modal.vue
merge_request: 32012
author: Gilang Gumilar
type: other
# frozen_string_literal: true
class AddSectionToApprovalMergeRequestRule < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
unless column_exists?(:approval_merge_request_rules, :section)
add_column :approval_merge_request_rules, :section, :text
end
add_text_limit :approval_merge_request_rules, :section, 255
end
def down
remove_column :approval_merge_request_rules, :section
end
end
......@@ -479,7 +479,9 @@ CREATE TABLE public.approval_merge_request_rules (
code_owner boolean DEFAULT false NOT NULL,
name character varying NOT NULL,
rule_type smallint DEFAULT 1 NOT NULL,
report_type smallint
report_type smallint,
section text,
CONSTRAINT check_6fca5928b2 CHECK ((char_length(section) <= 255))
);
CREATE TABLE public.approval_merge_request_rules_approved_approvers (
......@@ -13832,6 +13834,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200512164334
20200513160930
20200513171959
20200513224143
20200513234502
20200513235347
20200513235532
......
......@@ -110,7 +110,6 @@ The `dotenv` report collects a set of environment variables as artifacts.
The collected variables are registered as runtime-created variables of the job,
which is useful to [set dynamic environment URLs after a job finishes](../environments/index.md#set-dynamic-environment-urls-after-a-job-finishes).
It's not available for download through the web interface.
There are a couple of limitations on top of the [original dotenv rules](https://github.com/motdotla/dotenv#rules).
......@@ -151,7 +150,7 @@ The `codequality` report collects [CodeQuality issues](../../user/project/merge_
as artifacts.
The collected Code Quality report will be uploaded to GitLab as an artifact and will
be summarized in merge requests. It's not available for download through the web interface.
be summarized in merge requests.
#### `artifacts:reports:sast` **(ULTIMATE)**
......@@ -163,7 +162,7 @@ as artifacts.
The collected SAST report will be uploaded to GitLab as an artifact and will be summarized
in the merge requests and pipeline view. It's also used to provide data for security
dashboards. It's not available for download through the web interface.
dashboards.
#### `artifacts:reports:dependency_scanning` **(ULTIMATE)**
......@@ -175,7 +174,7 @@ as artifacts.
The collected Dependency Scanning report will be uploaded to GitLab as an artifact and will
be summarized in the merge requests and pipeline view. It's also used to provide data for security
dashboards. It's not available for download through the web interface.
dashboards.
#### `artifacts:reports:container_scanning` **(ULTIMATE)**
......@@ -187,7 +186,7 @@ as artifacts.
The collected Container Scanning report will be uploaded to GitLab as an artifact and will
be summarized in the merge requests and pipeline view. It's also used to provide data for security
dashboards. It's not available for download through the web interface.
dashboards.
#### `artifacts:reports:dast` **(ULTIMATE)**
......@@ -199,7 +198,7 @@ as artifacts.
The collected DAST report will be uploaded to GitLab as an artifact and will
be summarized in the merge requests and pipeline view. It's also used to provide data for security
dashboards. It's not available for download through the web interface.
dashboards.
#### `artifacts:reports:license_management` **(ULTIMATE)**
......@@ -216,7 +215,7 @@ as artifacts.
The collected License Compliance report will be uploaded to GitLab as an artifact and will
be summarized in the merge requests and pipeline view. It's also used to provide data for security
dashboards. It's not available for download through the web interface.
dashboards.
#### `artifacts:reports:license_scanning` **(ULTIMATE)**
......@@ -239,7 +238,7 @@ The `performance` report collects [Performance metrics](../../user/project/merge
as artifacts.
The collected Performance report will be uploaded to GitLab as an artifact and will
be automatically shown in merge requests. It's not available for download through the web interface.
be automatically shown in merge requests.
#### `artifacts:reports:metrics` **(PREMIUM)**
......@@ -249,7 +248,7 @@ The `metrics` report collects [Metrics](../metrics_reports.md)
as artifacts.
The collected Metrics report will be uploaded to GitLab as an artifact and will
be automatically shown in merge requests. It's not available for download through the web interface.
be automatically shown in merge requests.
## Browsing artifacts
......@@ -277,16 +276,16 @@ one HTML file that you can view directly online when
## Downloading artifacts
If you need to download the whole archive, there are buttons in various places
If you need to download an artifact or the whole archive, there are buttons in various places
in the GitLab UI to do this:
1. While on the pipelines page, you can see the download icon for each job's
artifacts archive in the right corner:
artifacts and archive in the right corner:
![Job artifacts in Pipelines page](img/job_artifacts_pipelines_page.png)
1. While on the **Jobs** page, you can see the download icon for each job's
artifacts archive in the right corner:
artifacts and archive in the right corner:
![Job artifacts in Builds page](img/job_artifacts_builds_page.png)
......
......@@ -550,6 +550,24 @@ You can also
[configure the text editor of your choice](https://errata-ai.github.io/vale/#local-use-by-a-single-writer)
to display the results.
Vale's test results are not currently displayed in CI, but may be displayed in the future.
##### Disable a Vale test
You can disable a specific Vale linting rule or all Vale linting rules for any portion of a document:
- To disable a specific rule, add a `<!-- vale gitlab.rulename = NO -->` tag
before the text, and a `<!-- vale gitlab.rulename = YES -->` tag after the text,
replacing `rulename` with the filename of a test in the [GitLab styles](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc/.linting/vale/styles/gitlab) directory.
- To disable all Vale linting rules, add a `<!-- vale off -->` tag before the text,
and a `<!-- vale on -->` tag after the text.
Whenever possible, exclude only the problematic rule and line(s).
In some cases, such as list items, you may need to disable linting for the entire
list until ["Ignore comments are not honored in a Markdown file"](https://github.com/errata-ai/vale/issues/175) is resolved.
For more information, see [Vale's documentation](https://errata-ai.gitbook.io/vale/getting-started/markup#markup-based-configuration).
## Danger Bot
GitLab uses [Danger](https://github.com/danger/danger) for some elements in
......
......@@ -308,12 +308,14 @@ tenses, words, and phrases:
appropriate way.
- Exceptions to this rule include commonly accepted technical terms, such as
CI/CD and TCP/IP.
- We discourage use of Latin abbreviations, such as "e.g.," "i.e.," or "etc.,"
- <!-- vale gitlab.LatinTerms = NO -->
We discourage use of Latin abbreviations, such as "e.g.," "i.e.," or "etc.,"
as even native users of English might misunderstand them.
- Instead of "i.e.," use "that is."
- Instead of "e.g.," use "for example," "such as," "for instance," or "like."
- Instead of "etc.," either use "and so on" or consider editing it out, since
it can be vague.
<!-- vale gitlab.rulename = NO -->
- Avoid using the word *currently* when talking about the product or its
features. The documentation describes the product as it is, and not as it
will be at some indeterminate point in the future.
......@@ -379,6 +381,8 @@ tenses, words, and phrases:
| Requests to localhost are not allowed | Requests to localhost aren't allowed |
| Specified URL cannot be used | Specified URL can't be used |
<!-- vale on -->
## Text
- [Write in Markdown](#markdown).
......@@ -1308,7 +1312,7 @@ a helpful link back to how the feature was developed.
```
NOTE: **Note:**
Version text must be on its own line and surounded by blank lines to render correctly.
Version text must be on its own line and surrounded by blank lines to render correctly.
### Versions in the past or future
......
......@@ -238,6 +238,53 @@ the view for code in a library.
In such rare cases it's reasonable to use CSS selectors in page object methods,
with a comment explaining why an `element` can't be added.
### Define Page concerns
Some pages share common behaviors, and/or are prepended with EE-specific modules that adds EE-specific methods.
These modules must:
1. Extend from the `QA::Page::PageConcern` module, with `extend QA::Page::PageConcern`.
1. Override the `self.prepended` method if they need to `include`/`prepend` other modules themselves, and/or define
`view` or `elements`.
1. Call `super` as the first thing in `self.prepended`.
1. Include/prepend other modules and define their `view`/`elements` in a `base.class_eval` block to ensure they're
defined in the class that prepends the module.
These steps ensure the sanity selectors check will detect problems properly.
For example, `qa/qa/ee/page/merge_request/show.rb` adds EE-specific methods to `qa/qa/page/merge_request/show.rb` (with
`QA::Page::MergeRequest::Show.prepend_if_ee('QA::EE::Page::MergeRequest::Show')`) and following is how it's implemented
(only showing the relevant part and refering to the 4 steps described above with inline comments):
```ruby
module QA
module EE
module Page
module MergeRequest
module Show
extend QA::Page::PageConcern # 1.
def self.prepended(base) # 2.
super # 3.
base.class_eval do # 4.
prepend Page::Component::LicenseManagement
view 'app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue' do
element :head_mismatch, "The source branch HEAD has recently changed."
end
[...]
end
end
end
end
end
end
end
```
## Running the test locally
During development, you can run the `qa:selectors` test by running
......
......@@ -469,7 +469,12 @@ vulnerabilities in your groups, projects and pipelines. Read more about the
Once a vulnerability is found, you can interact with it. Read more on how to
[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
## Vulnerabilities database update
## Vulnerabilities database
Vulnerabilities contained within the vulnerability database can be searched
and viewed at the [GitLab vulnerability advisory database](https://advisories.gitlab.com).
### Vulnerabilities database update
For more information about the vulnerabilities database update, check the
[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
......
---
description: "GitLab - Incident Management. GitLab offers solutions for handling incidents in your applications and services"
stage: Monitor
group: Health
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
......@@ -8,141 +7,106 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Incident Management
GitLab offers solutions for handling incidents in your applications and services,
from setting up an alert with Prometheus, to receiving a notification via a
monitoring tool like Slack, and automatically setting up Zoom calls with your
support team.
from setting up an alert with Prometheus, to receiving a notification through a
monitoring tool like Slack, and [setting up Zoom calls](#zoom-integration-in-issues) with your
support team. Incidents can display [metrics](#embed-metrics-in-incidents-and-issues)
and [logs](#view-logs-from-metrics-panel).
## Configuring incidents **(ULTIMATE)**
## Configure incidents **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/4925) in GitLab Ultimate 11.11.
The Incident Management features can be enabled and disabled via your project's
**Settings > Operations > Incidents**.
You can enable or disable Incident Management features in your project's
**{settings}** **Settings > Operations > Incidents**. Issues can be created for
each alert triggered, and separate email notifications can be sent to users with
[Developer permissions](../permissions.md). Appropriately configured alerts include an
[embedded chart](../project/integrations/prometheus.md#embedding-metrics-based-on-alerts-in-incident-issues)
for the query corresponding to the alert. You can also configure GitLab to
[close issues](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate)
when you receive notification that the alert is resolved.
![Incident Management Settings](img/incident_management_settings.png)
### Automatically create issues from alerts
### Create issues from alerts
GitLab issues can automatically be created as a result of an alert notification.
An issue created this way will contain the error information to help you further
debug it.
You can create GitLab issues from an alert notification. These issues contain
information about the alerts to help you diagnose the source of the alerts.
### Issue templates
You can create your own [issue templates](../project/description_templates.md#creating-issue-templates)
that can be [used within Incident Management](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate).
To select your issue template for use within Incident Management:
1. Visit your project's **Settings > Operations > Incidents**.
1. Visit your project's **{settings}** **Settings > Operations > Incidents**.
1. Select the **Create an issue** checkbox for GitLab to create an issue from
the incident.
1. Select the template from the **Issue Template** dropdown.
You can create your own [issue templates](../project/description_templates.md#creating-issue-templates)
to [use within Incident Management](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate).
1. Click **Save changes**.
## Alerting
## Notify developers of alerts
GitLab can react to the alerts that your applications and services may be
triggering by automatically creating issues, and alerting developers via email.
GitLab can react to the alerts triggered from your applications and services
by creating issues and alerting developers through email. GitLab sends these emails
to [owners and maintainers](../permissions.md) of the project. They contain details
of the alert, and a link for more information.
The emails will be sent to [owners and maintainers](../permissions.md) of the project and will contain details on the alert as well as a link to see more information.
### Configure Prometheus alerts
### Prometheus alerts
You can set up Prometheus alerts in:
Prometheus alerts can be set up in both:
- [GitLab-managed Prometheus](../project/integrations/prometheus.md#setting-up-alerts-for-prometheus-metrics) and
- [GitLab-managed Prometheus](../project/integrations/prometheus.md#setting-up-alerts-for-prometheus-metrics) installations.
- [Self-managed Prometheus](../project/integrations/prometheus.md#external-prometheus-instances) installations.
#### Alert Bot user
Behind the scenes, Prometheus alerts are created by the special Alert Bot user creating issues. This user cannot be removed but does not count toward the license limit count.
### Alert endpoint
Prometheus alerts are created by the special Alert Bot user. You can't remove this
user, but it does not count toward your license limit.
GitLab can accept alerts from any source via a generic webhook receiver. When
you set up the generic alerts integration, a unique endpoint will
be created which can receive a payload in JSON format.
### Configure external generic alerts
[Read more on setting this up, including how to customize the payload](../project/integrations/generic_alerts.md).
GitLab can accept alerts from any source through a generic webhook receiver. When
[configuring the generic alerts integration](../project/integrations/generic_alerts.md),
GitLab creates a unique endpoint which receives a JSON-formatted, customizable payload.
### Recovery alerts
## Embed metrics in incidents and issues
GitLab can [automatically close issues](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate)
that have been automatically created when you receive notification that the
alert is resolved.
## Embedded metrics
Metrics can be embedded anywhere where GitLab Markdown is used, for example,
descriptions and comments on issues and merge requests.
This can be useful for when you're sharing metrics, such as for discussing
an incident or performance issues, so you can output the dashboard directly
You can embed metrics anywhere GitLab Markdown is used, such as descriptions,
comments on issues, and merge requests. Embedding metrics helps you share them
when discussing incidents or performance issues. You can output the dashboard directly
into any issue, merge request, epic, or any other Markdown text field in GitLab
by simply [copying and pasting the link to the metrics dashboard](../project/integrations/prometheus.md#embedding-gitlab-managed-kubernetes-metrics).
by [copying and pasting the link to the metrics dashboard](../project/integrations/prometheus.md#embedding-gitlab-managed-kubernetes-metrics).
TIP: **Tip:**
Both GitLab-hosted and Grafana metrics can also be
[embedded in issue templates](../project/integrations/prometheus.md#embedding-metrics-in-issue-templates).
You can embed both
[GitLab-hosted metrics](../project/integrations/prometheus.md#embedding-metric-charts-within-gitlab-flavored-markdown) and
[Grafana metrics](../project/integrations/prometheus.md#embedding-grafana-charts)
in incidents and issue templates.
### GitLab-hosted metrics
Learn how to embed [GitLab hosted metric charts](../project/integrations/prometheus.md#embedding-metric-charts-within-gitlab-flavored-markdown).
#### Context menu
### Context menu
From each of the embedded metrics panels, you can access more details
about the data you are viewing from a context menu.
You can access the context menu by clicking the **{ellipsis_v}** **More actions**
dropdown box above the upper right corner of the panel:
about the data you're viewing from a context menu. You can access the context menu
by clicking the **{ellipsis_v}** **More actions** dropdown box above the
upper right corner of the panel. The options are:
The options are:
- [View logs](#view-logs-from-metrics-panel).
- **Download CSV** - Data from embedded charts can be
[downloaded as CSV](../project/integrations/prometheus.md#downloading-data-as-csv).
- [View logs](#view-logs)
- [Download CSV](#download-csv)
##### View logs
#### View logs from metrics panel
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/201846) in GitLab Ultimate 12.8.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25455) to [GitLab Core](https://about.gitlab.com/pricing/) 12.9.
This can be useful if you are triaging an application incident and need to
[explore logs](../project/integrations/prometheus.md#view-logs-ultimate)
from across your application. It also helps you to understand
what is affecting your application's performance and quickly resolve any problems.
##### Download CSV
Data from embedded charts can be [downloaded as CSV](../project/integrations/prometheus.md#downloading-data-as-csv).
### Grafana metrics
Learn how to embed [Grafana hosted metric charts](../project/integrations/prometheus.md#embedding-grafana-charts).
Viewing logs from a metrics panel can be useful if you're triaging an application
incident and need to [explore logs](../project/integrations/prometheus.md#view-logs-ultimate)
from across your application. These logs help you understand what is affecting
your application's performance and resolve any problems.
## Slack integration
Slack slash commands allow you to control GitLab and view content right inside
Slack, without having to leave it.
Slack slash commands allow you to control GitLab and view GitLab content without leaving Slack.
Learn how to [set up Slack slash commands](../project/integrations/slack_slash_commands.md)
and how to [use them](../../integration/slash_commands.md).
### Slash commands
Please refer to a list of [available slash commands](../../integration/slash_commands.md) and associated descriptions.
## Zoom in issues
In order to communicate synchronously for incidents management, GitLab allows you to
associate a Zoom meeting with an issue. Once you start a Zoom call for a fire-fight,
you need a way to associate the conference call with an issue, so that your team
members can join swiftly without requesting a link.
Read more how to [add or remove a zoom meeting](../project/issues/associate_zoom_meeting.md).
### Configuring Incidents
Incident Management features can be easily enabled & disabled via the Project settings page. Head to Project -> Settings -> Operations -> Incidents.
and how to [use the available slash commands](../../integration/slash_commands.md).
#### Auto-creation
## Zoom integration in issues
You can automatically create GitLab issues from an Alert notification. Issues created this way contain error information to help you debug the error. Appropriately configured alerts include an [embedded chart](../project/integrations/prometheus.md#embedding-metrics-based-on-alerts-in-incident-issues) for the query corresponding to the alert.
GitLab enables you to [associate a Zoom meeting with an issue](../project/issues/associate_zoom_meeting.md)
for synchronous communication during incident management. After starting a Zoom
call for an incident, you can associate the conference call with an issue, so your
team members can join without requesting a link.
......@@ -1725,6 +1725,15 @@ msgstr ""
msgid "After a successful password update, you will be redirected to the login page where you can log in with your new password."
msgstr ""
msgid "After that, you will not to be able to use merge approvals or code quality as well as many other features."
msgstr ""
msgid "After that, you will not to be able to use merge approvals or epics as well as many other features."
msgstr ""
msgid "After that, you will not to be able to use merge approvals or epics as well as many security features."
msgstr ""
msgid "Alert"
msgid_plural "Alerts"
msgstr[0] ""
......@@ -25014,7 +25023,7 @@ msgstr ""
msgid "YouTube"
msgstr ""
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}. After that, you will not to be able to create issues or merge requests as well as many other features."
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
msgstr ""
msgid "Your %{strong}%{plan_name}%{strong_close} subscription will expire on %{strong}%{expires_on}%{strong_close}. After that, you will not to be able to create issues or merge requests as well as many other features."
......
......@@ -162,6 +162,7 @@ module QA
autoload :Base, 'qa/page/base'
autoload :View, 'qa/page/view'
autoload :Element, 'qa/page/element'
autoload :PageConcern, 'qa/page/page_concern'
autoload :Validator, 'qa/page/validator'
autoload :Validatable, 'qa/page/validatable'
......@@ -248,7 +249,6 @@ module QA
end
module Settings
autoload :Common, 'qa/page/project/settings/common'
autoload :Advanced, 'qa/page/project/settings/advanced'
autoload :Main, 'qa/page/project/settings/main'
autoload :Repository, 'qa/page/project/settings/repository'
......@@ -409,6 +409,7 @@ module QA
autoload :Breadcrumbs, 'qa/page/component/breadcrumbs'
autoload :CiBadgeLink, 'qa/page/component/ci_badge_link'
autoload :ClonePanel, 'qa/page/component/clone_panel'
autoload :DesignManagement, 'qa/page/component/design_management'
autoload :LazyLoader, 'qa/page/component/lazy_loader'
autoload :LegacyClonePanel, 'qa/page/component/legacy_clone_panel'
autoload :Dropzone, 'qa/page/component/dropzone'
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module Breadcrumbs
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/layouts/nav/_breadcrumbs.html.haml' do
element :breadcrumb_links_content
end
......
......@@ -4,6 +4,8 @@ module QA
module Page
module Component
module CiBadgeLink
extend QA::Page::PageConcern
COMPLETED_STATUSES = %w[passed failed canceled blocked skipped manual].freeze # excludes created, pending, running
INCOMPLETE_STATUSES = %w[pending created running].freeze
......@@ -27,6 +29,8 @@ module QA
end
def self.included(base)
super
base.view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do
element :status_badge
end
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module ClonePanel
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/projects/buttons/_clone.html.haml' do
element :clone_dropdown
element :clone_options
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module ConfirmModal
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/shared/_confirm_modal.html.haml' do
element :confirm_modal
element :confirm_input
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module CustomMetric
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/custom_metrics/components/custom_metrics_form_fields.vue' do
element :custom_metric_prometheus_title_field
element :custom_metric_prometheus_query_field
......
......@@ -4,8 +4,12 @@ module QA
module Page
module Component
module DesignManagement
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
view 'app/assets/javascripts/design_management/components/design_notes/design_discussion.vue' do
element :design_discussion_content
end
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module GroupsFilter
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/shared/groups/_search_form.html.haml' do
element :groups_filter
end
......
......@@ -5,7 +5,11 @@ module QA
module Component
module Issuable
module Common
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/issue_show/components/title.vue' do
element :edit_button
element :title, required: true
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module LazyLoader
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/lazy_loader.js' do
element :js_lazy_loaded
end
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module LegacyClonePanel
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/shared/_clone_panel.html.haml' do
element :clone_dropdown
element :clone_options_dropdown, '.clone-options-dropdown' # rubocop:disable QA/ElementWithPattern
......
......@@ -4,7 +4,11 @@ module QA
module Page
module Component
module Note
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/notes/components/comment_form.vue' do
element :note_dropdown
element :discussion_option
......
......@@ -5,8 +5,12 @@ module QA
module Component
module WebIDE
module Alert
def self.prepended(page)
page.module_eval do
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'app/assets/javascripts/ide/components/error_message.vue' do
element :flash_alert
end
......
......@@ -5,7 +5,11 @@ module QA
module File
module Shared
module CommitButton
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/projects/_commit_button.html.haml' do
element :commit_button
end
......
......@@ -5,7 +5,11 @@ module QA
module File
module Shared
module CommitMessage
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/shared/_commit_message_container.html.haml' do
element :commit_message, "text_area_tag 'commit_message'" # rubocop:disable QA/ElementWithPattern
end
......
......@@ -5,7 +5,11 @@ module QA
module File
module Shared
module Editor
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/views/projects/blob/_editor.html.haml' do
element :editor
end
......
......@@ -5,9 +5,12 @@ module QA
module Group
module SubMenus
module Common
extend QA::Page::PageConcern
include QA::Page::SubMenus::Common
def self.included(base)
super
base.class_eval do
view 'app/views/layouts/nav/sidebar/_group.html.haml' do
element :group_sidebar
......
# frozen_string_literal: true
module QA
module Page::Main
class Terms < Page::Base
view 'app/views/layouts/terms.html.haml' do
element :user_avatar, required: true
end
module Page
module Main
class Terms < Page::Base
view 'app/views/layouts/terms.html.haml' do
element :user_avatar, required: true
end
view 'app/views/users/terms/index.html.haml' do
element :terms_content, required: true
view 'app/views/users/terms/index.html.haml' do
element :terms_content, required: true
element :accept_terms_button
end
element :accept_terms_button
end
def accept_terms
click_element :accept_terms_button, Page::Main::Menu
def accept_terms
click_element :accept_terms_button, Page::Main::Menu
end
end
end
end
......
module QA
module Page
module PageConcern
def included(base)
unless base.is_a?(Class)
raise "Expected #{self} to be prepended to a class, but #{base} is a module!"
end
unless base.ancestors.include?(::QA::Page::Base)
raise "Expected #{self} to be prepended to a class that inherits from ::QA::Page::Base, but #{base} doesn't!"
end
end
alias_method :prepended, :included
end
end
end
# frozen_string_literal: true
module QA::Page
module Project::Job
class Show < QA::Page::Base
include Component::CiBadgeLink
module QA
module Page
module Project
module Job
class Show < QA::Page::Base
include Component::CiBadgeLink
view 'app/assets/javascripts/jobs/components/log/log.vue' do
element :job_log_content
end
view 'app/assets/javascripts/jobs/components/log/log.vue' do
element :job_log_content
end
view 'app/assets/javascripts/jobs/components/stages_dropdown.vue' do
element :pipeline_path
end
view 'app/assets/javascripts/jobs/components/stages_dropdown.vue' do
element :pipeline_path
end
view 'app/assets/javascripts/jobs/components/sidebar.vue' do
element :retry_button
end
view 'app/assets/javascripts/jobs/components/sidebar.vue' do
element :retry_button
end
def successful?(timeout: 60)
raise "Timed out waiting for the build trace to load" unless loaded?
raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout)
def successful?(timeout: 60)
raise "Timed out waiting for the build trace to load" unless loaded?
raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout)
passed?
end
passed?
end
# Reminder: You may wish to wait for a particular job status before checking output
def output(wait: 5)
result = ''
# Reminder: You may wish to wait for a particular job status before checking output
def output(wait: 5)
result = ''
wait_until(reload: false, max_duration: wait, sleep_interval: 1) do
result = find_element(:job_log_content).text
wait_until(reload: false, max_duration: wait, sleep_interval: 1) do
result = find_element(:job_log_content).text
result.include?('Job')
end
result.include?('Job')
end
result
end
result
end
def retry!
click_element :retry_button
end
def retry!
click_element :retry_button
end
private
private
def loaded?(wait: 60)
wait_until(reload: true, max_duration: wait, sleep_interval: 1) do
has_element?(:job_log_content, wait: 1)
def loaded?(wait: 60)
wait_until(reload: true, max_duration: wait, sleep_interval: 1) do
has_element?(:job_log_content, wait: 1)
end
end
end
end
end
......
# frozen_string_literal: true
module QA::Page
module Project::Pipeline
class Index < QA::Page::Base
view 'app/assets/javascripts/pipelines/components/pipeline_url.vue' do
element :pipeline_url_link
end
view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do
element :pipeline_commit_status
element :pipeline_retry_button
end
def click_on_latest_pipeline
all_elements(:pipeline_url_link, minimum: 1, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).first.click
end
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: 360) do
within_element_by_index(:pipeline_commit_status, 0) { yield }
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
module QA
module Page
module Project
module Pipeline
class Index < QA::Page::Base
view 'app/assets/javascripts/pipelines/components/pipeline_url.vue' do
element :pipeline_url_link
end
view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do
element :pipeline_commit_status
element :pipeline_retry_button
end
def click_on_latest_pipeline
all_elements(:pipeline_url_link, minimum: 1, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).first.click
end
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: 360) do
within_element_by_index(:pipeline_commit_status, 0) { yield }
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
......
# frozen_string_literal: true
module QA::Page
module Project::Pipeline
class Show < QA::Page::Base
include Component::CiBadgeLink
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
element :pipeline_header, /header class.*ci-header-container.*/ # rubocop:disable QA/ElementWithPattern
end
module QA
module Page
module Project
module Pipeline
class Show < QA::Page::Base
include Component::CiBadgeLink
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
element :pipeline_header, /header class.*ci-header-container.*/ # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/pipelines/components/graph/graph_component.vue' do
element :pipeline_graph, /class.*pipeline-graph.*/ # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/pipelines/components/graph/graph_component.vue' do
element :pipeline_graph, /class.*pipeline-graph.*/ # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/pipelines/components/graph/job_item.vue' do
element :job_component, /class.*ci-job-component.*/ # rubocop:disable QA/ElementWithPattern
element :job_link
end
view 'app/assets/javascripts/pipelines/components/graph/job_item.vue' do
element :job_component, /class.*ci-job-component.*/ # rubocop:disable QA/ElementWithPattern
element :job_link
end
view 'app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
element :linked_pipeline_button
end
view 'app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
element :linked_pipeline_button
end
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/pipelines/_info.html.haml' do
element :pipeline_badges
end
view 'app/views/projects/pipelines/_info.html.haml' do
element :pipeline_badges
end
def running?(wait: 0)
within('.ci-header-container') do
page.has_content?('running', wait: wait)
end
end
def running?(wait: 0)
within('.ci-header-container') do
page.has_content?('running', wait: wait)
end
end
def has_build?(name, status: :success, wait: nil)
within('.pipeline-graph') do
within('.ci-job-component', text: name) do
has_selector?(".ci-status-icon-#{status}", { wait: wait }.compact)
def has_build?(name, status: :success, wait: nil)
within('.pipeline-graph') do
within('.ci-job-component', text: name) do
has_selector?(".ci-status-icon-#{status}", { wait: wait }.compact)
end
end
end
end
end
def has_job?(job_name)
has_element?(:job_link, text: job_name)
end
def has_job?(job_name)
has_element?(:job_link, text: job_name)
end
def has_no_job?(job_name)
has_no_element?(:job_link, text: job_name)
end
def has_no_job?(job_name)
has_no_element?(:job_link, text: job_name)
end
def has_tag?(tag_name)
within_element(:pipeline_badges) do
has_selector?('.badge', text: tag_name)
end
end
def has_tag?(tag_name)
within_element(:pipeline_badges) do
has_selector?('.badge', text: tag_name)
end
end
def click_job(job_name)
click_element(:job_link, text: job_name)
end
def click_job(job_name)
click_element(:job_link, text: job_name)
end
def click_linked_job(project_name)
click_element(:linked_pipeline_button, text: /#{project_name}/)
end
def click_linked_job(project_name)
click_element(:linked_pipeline_button, text: /#{project_name}/)
end
def click_on_first_job
first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click
def click_on_first_job
first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click
end
end
end
end
end
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class CICD < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/settings/ci_cd/show.html.haml' do
element :autodevops_settings_content
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class CiVariables < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue' do
element :ci_variable_key_field
......
# frozen_string_literal: true
module QA
module Page
module Project
module Settings
module Common
include QA::Page::Settings::Common
end
end
end
end
end
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class GeneralPipelines < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/settings/ci_cd/_form.html.haml' do
element :build_coverage_regex_field
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class Main < Page::Base
include Common
include QA::Page::Settings::Common
include Component::Select2
include SubMenus::Project
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class MergeRequest < QA::Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/edit.html.haml' do
element :save_merge_request_changes
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class Operations < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/settings/operations/_incidents.html.haml' do
element :incidents_settings_content
......
......@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class Repository < Page::Base
include Common
include QA::Page::Settings::Common
view 'app/views/projects/protected_branches/shared/_index.html.haml' do
element :protected_branches_settings
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module CiCd
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :link_pipelines
end
......
......@@ -5,6 +5,7 @@ module QA
module Project
module SubMenus
module Common
extend QA::Page::PageConcern
include QA::Page::SubMenus::Common
private
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Issues
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :issue_boards_link
element :issues_item
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Operations
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :operations_link
element :operations_environments_link
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Project
include Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :project_link
end
......
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Repository
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :project_menu_repo
element :branches_link
......@@ -44,5 +48,3 @@ module QA
end
end
end
QA::Page::Project::SubMenus::Repository.prepend_if_ee('QA::EE::Page::Project::SubMenus::Repository')
......@@ -5,10 +5,14 @@ module QA
module Project
module SubMenus
module Settings
include Page::Project::SubMenus::Common
extend QA::Page::PageConcern
def self.included(base)
super
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :settings_item
element :link_members_settings
......
# frozen_string_literal: true
module QA::Page
module Search
class Results < QA::Page::Base
view 'app/views/search/_category.html.haml' do
element :code_tab
element :projects_tab
end
module QA
module Page
module Search
class Results < QA::Page::Base
view 'app/views/search/_category.html.haml' do
element :code_tab
element :projects_tab
end
view 'app/views/search/results/_blob_data.html.haml' do
element :result_item_content
element :file_title_content
element :file_text_content
end
view 'app/views/search/results/_blob_data.html.haml' do
element :result_item_content
element :file_title_content
element :file_text_content
end
view 'app/views/shared/projects/_project.html.haml' do
element :project
end
view 'app/views/shared/projects/_project.html.haml' do
element :project
end
def switch_to_code
switch_to_tab(:code_tab)
end
def switch_to_code
switch_to_tab(:code_tab)
end
def switch_to_projects
switch_to_tab(:projects_tab)
end
def switch_to_projects
switch_to_tab(:projects_tab)
end
def has_file_in_project?(file_name, project_name)
has_element?(:result_item_content, text: "#{project_name}: #{file_name}")
end
def has_file_in_project?(file_name, project_name)
has_element?(:result_item_content, text: "#{project_name}: #{file_name}")
end
def has_file_with_content?(file_name, file_text)
within_element_by_index(:result_item_content, 0) do
break false unless has_element?(:file_title_content, text: file_name)
def has_file_with_content?(file_name, file_text)
within_element_by_index(:result_item_content, 0) do
break false unless has_element?(:file_title_content, text: file_name)
has_element?(:file_text_content, text: file_text)
has_element?(:file_text_content, text: file_text)
end
end
end
def has_project?(project_name)
has_element?(:project, project_name: project_name)
end
def has_project?(project_name)
has_element?(:project, project_name: project_name)
end
private
private
def switch_to_tab(tab)
retry_until do
click_element(tab)
has_active_element?(tab)
def switch_to_tab(tab)
retry_until do
click_element(tab)
has_active_element?(tab)
end
end
end
end
......
......@@ -2,83 +2,87 @@
require 'rspec/core'
module QA::Specs::Helpers
module Quarantine
include RSpec::Core::Pending
module QA
module Specs
module Helpers
module Quarantine
include RSpec::Core::Pending
extend self
extend self
def configure_rspec
RSpec.configure do |config|
config.before(:context, :quarantine) do
Quarantine.skip_or_run_quarantined_contexts(config.inclusion_filter.rules, self.class)
end
def configure_rspec
RSpec.configure do |config|
config.before(:context, :quarantine) do
Quarantine.skip_or_run_quarantined_contexts(config.inclusion_filter.rules, self.class)
end
config.before do |example|
Quarantine.skip_or_run_quarantined_tests_or_contexts(config.inclusion_filter.rules, example)
config.before do |example|
Quarantine.skip_or_run_quarantined_tests_or_contexts(config.inclusion_filter.rules, example)
end
end
end
end
end
# Skip the entire context if a context is quarantined. This avoids running
# before blocks unnecessarily.
def skip_or_run_quarantined_contexts(filters, example)
return unless example.metadata.key?(:quarantine)
# Skip the entire context if a context is quarantined. This avoids running
# before blocks unnecessarily.
def skip_or_run_quarantined_contexts(filters, example)
return unless example.metadata.key?(:quarantine)
skip_or_run_quarantined_tests_or_contexts(filters, example)
end
skip_or_run_quarantined_tests_or_contexts(filters, example)
end
# Skip tests in quarantine unless we explicitly focus on them.
def skip_or_run_quarantined_tests_or_contexts(filters, example)
if filters.key?(:quarantine)
included_filters = filters_other_than_quarantine(filters)
# Skip tests in quarantine unless we explicitly focus on them.
def skip_or_run_quarantined_tests_or_contexts(filters, example)
if filters.key?(:quarantine)
included_filters = filters_other_than_quarantine(filters)
# If :quarantine is focused, skip the test/context unless its metadata
# includes quarantine and any other filters
# E.g., Suppose a test is tagged :smoke and :quarantine, and another is tagged
# :ldap and :quarantine. If we wanted to run just quarantined smoke tests
# using `--tag quarantine --tag smoke`, without this check we'd end up
# running that ldap test as well because of the :quarantine metadata.
# We could use an exclusion filter, but this way the test report will list
# the quarantined tests when they're not run so that we're aware of them
skip("Only running tests tagged with :quarantine and any of #{included_filters.keys}") if should_skip_when_focused?(example.metadata, included_filters)
else
if example.metadata.key?(:quarantine)
quarantine_message = %w(In quarantine)
quarantine_tag = example.metadata[:quarantine]
# If :quarantine is focused, skip the test/context unless its metadata
# includes quarantine and any other filters
# E.g., Suppose a test is tagged :smoke and :quarantine, and another is tagged
# :ldap and :quarantine. If we wanted to run just quarantined smoke tests
# using `--tag quarantine --tag smoke`, without this check we'd end up
# running that ldap test as well because of the :quarantine metadata.
# We could use an exclusion filter, but this way the test report will list
# the quarantined tests when they're not run so that we're aware of them
skip("Only running tests tagged with :quarantine and any of #{included_filters.keys}") if should_skip_when_focused?(example.metadata, included_filters)
else
if example.metadata.key?(:quarantine)
quarantine_message = %w(In quarantine)
quarantine_tag = example.metadata[:quarantine]
if !!quarantine_tag
quarantine_message << case quarantine_tag
when String
": #{quarantine_tag}"
when Hash
": #{quarantine_tag[:issue]}"
else
''
end
end
if !!quarantine_tag
quarantine_message << case quarantine_tag
when String
": #{quarantine_tag}"
when Hash
": #{quarantine_tag[:issue]}"
else
''
end
end
skip(quarantine_message.join(' ').strip)
skip(quarantine_message.join(' ').strip)
end
end
end
end
end
def filters_other_than_quarantine(filter)
filter.reject { |key, _| key == :quarantine }
end
def filters_other_than_quarantine(filter)
filter.reject { |key, _| key == :quarantine }
end
# Checks if a test or context should be skipped.
#
# Returns true if
# - the metadata does not includes the :quarantine tag
# or if
# - the metadata includes the :quarantine tag
# - and the filter includes other tags that aren't in the metadata
def should_skip_when_focused?(metadata, included_filters)
return true unless metadata.key?(:quarantine)
return false if included_filters.empty?
# Checks if a test or context should be skipped.
#
# Returns true if
# - the metadata does not includes the :quarantine tag
# or if
# - the metadata includes the :quarantine tag
# - and the filter includes other tags that aren't in the metadata
def should_skip_when_focused?(metadata, included_filters)
return true unless metadata.key?(:quarantine)
return false if included_filters.empty?
(metadata.keys & included_filters.keys).empty?
(metadata.keys & included_filters.keys).empty?
end
end
end
end
end
......@@ -9,6 +9,7 @@ import {
GlIcon,
GlTab,
} from '@gitlab/ui';
import { visitUrl } from '~/lib/utils/url_utility';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import createFlash from '~/flash';
import AlertManagementList from '~/alert_management/components/alert_management_list.vue';
......@@ -18,6 +19,11 @@ import mockAlerts from '../mocks/alerts.json';
jest.mock('~/flash');
jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn().mockName('visitUrlMock'),
joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths,
}));
describe('AlertManagementList', () => {
let wrapper;
......@@ -220,12 +226,10 @@ describe('AlertManagementList', () => {
loading: false,
});
window.location.assign = jest.fn();
findAlerts()
.at(0)
.trigger('click');
expect(window.location.assign).toHaveBeenCalledWith('/1527542/details');
expect(visitUrl).toHaveBeenCalledWith('/1527542/details');
});
describe('handle date fields', () => {
......
......@@ -3,16 +3,20 @@
require 'spec_helper'
describe ContentTypeWhitelist do
class DummyUploader < CarrierWave::Uploader::Base
include ContentTypeWhitelist::Concern
let_it_be(:model) { build_stubbed(:user) }
let!(:uploader) do
stub_const('DummyUploader', Class.new(CarrierWave::Uploader::Base))
DummyUploader.class_eval do
include ContentTypeWhitelist::Concern
def content_type_whitelist
%w[image/png image/jpeg]
def content_type_whitelist
%w[image/png image/jpeg]
end
end
end
let_it_be(:model) { build_stubbed(:user) }
let_it_be(:uploader) { DummyUploader.new(model, :dummy) }
DummyUploader.new(model, :dummy)
end
context 'upload whitelisted file content type' do
let(:path) { File.join('spec', 'fixtures', 'rails_sample.jpg') }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册