diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb
index 8d1999604a9..cbf0c756e1e 100644
--- a/app/controllers/projects/incidents_controller.rb
+++ b/app/controllers/projects/incidents_controller.rb
@@ -11,7 +11,7 @@ class Projects::IncidentsController < Projects::ApplicationController
push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_mvc_2, @project&.work_items_mvc_2_feature_flag_enabled?)
push_frontend_feature_flag(:work_items_hierarchy, @project)
- push_frontend_feature_flag(:remove_user_attributes, @group)
+ push_frontend_feature_flag(:remove_user_attributes_projects, @project)
end
feature_category :incident_management
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index ad3ed7160ce..800a7df2566 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -42,7 +42,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:incident_timeline, project)
- push_frontend_feature_flag(:remove_user_attributes, @group)
+ push_frontend_feature_flag(:remove_user_attributes_projects, project)
end
before_action only: [:index, :show] do
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index a01aea503de..7474485a09b 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -45,7 +45,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:paginated_mr_discussions, project)
push_frontend_feature_flag(:mr_review_submit_comment, project)
push_frontend_feature_flag(:mr_experience_survey, project)
- push_frontend_feature_flag(:remove_user_attributes, @group)
+ push_frontend_feature_flag(:remove_user_attributes_projects, @project)
end
before_action do
diff --git a/app/graphql/mutations/incident_management/timeline_event/promote_from_note.rb b/app/graphql/mutations/incident_management/timeline_event/promote_from_note.rb
index 31ae29d896b..bb1da9278ff 100644
--- a/app/graphql/mutations/incident_management/timeline_event/promote_from_note.rb
+++ b/app/graphql/mutations/incident_management/timeline_event/promote_from_note.rb
@@ -6,6 +6,8 @@ module Mutations
class PromoteFromNote < Base
graphql_name 'TimelineEventPromoteFromNote'
+ include NotesHelper
+
argument :note_id, Types::GlobalIDType[::Note],
required: true,
description: 'Note ID from which the timeline event promoted.'
@@ -20,7 +22,7 @@ module Mutations
incident,
current_user,
promoted_from_note: note,
- note: note.note,
+ note: build_note_string(note),
occurred_at: note.created_at,
editable: true
).execute
@@ -38,6 +40,11 @@ module Mutations
super
end
+ def build_note_string(note)
+ commented = _('commented')
+ "@#{note.author.username} [#{commented}](#{noteable_note_url(note)}): '#{note.note}'"
+ end
+
def raise_noteable_not_incident!
raise_resource_not_available_error! 'Note does not belong to an incident'
end
diff --git a/app/graphql/types/branch_protections/base_access_level_type.rb b/app/graphql/types/branch_protections/base_access_level_type.rb
new file mode 100644
index 00000000000..2fd9e394296
--- /dev/null
+++ b/app/graphql/types/branch_protections/base_access_level_type.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Types
+ module BranchProtections
+ class BaseAccessLevelType < Types::BaseObject
+ authorize :read_protected_branch
+
+ field :access_level,
+ type: GraphQL::Types::Int,
+ null: false,
+ description: 'GitLab::Access level.'
+
+ field :access_level_description,
+ type: GraphQL::Types::String,
+ null: false,
+ description: 'Human readable representation for this access level.',
+ hash_key: 'humanize'
+ end
+ end
+end
diff --git a/app/graphql/types/branch_protections/merge_access_level_type.rb b/app/graphql/types/branch_protections/merge_access_level_type.rb
new file mode 100644
index 00000000000..85295e1ba25
--- /dev/null
+++ b/app/graphql/types/branch_protections/merge_access_level_type.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Types
+ module BranchProtections
+ class MergeAccessLevelType < BaseAccessLevelType # rubocop:disable Graphql/AuthorizeTypes
+ graphql_name 'MergeAccessLevel'
+ description 'Represents the merge access level of a branch protection.'
+ accepts ::ProtectedBranch::MergeAccessLevel
+ end
+ end
+end
diff --git a/app/graphql/types/branch_rules/branch_protection_type.rb b/app/graphql/types/branch_rules/branch_protection_type.rb
index b391eba58be..02379dcf558 100644
--- a/app/graphql/types/branch_rules/branch_protection_type.rb
+++ b/app/graphql/types/branch_rules/branch_protection_type.rb
@@ -8,6 +8,11 @@ module Types
accepts ::ProtectedBranch
authorize :read_protected_branch
+ field :merge_access_levels,
+ type: Types::BranchProtections::MergeAccessLevelType.connection_type,
+ null: true,
+ description: 'Details about who can merge when this branch is the source branch.'
+
field :allow_force_push,
type: GraphQL::Types::Boolean,
null: false,
diff --git a/app/policies/protected_branch_access_policy.rb b/app/policies/protected_branch_access_policy.rb
new file mode 100644
index 00000000000..4f33af89d2a
--- /dev/null
+++ b/app/policies/protected_branch_access_policy.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class ProtectedBranchAccessPolicy < BasePolicy
+ delegate { @subject.protected_branch }
+end
diff --git a/config/feature_flags/development/group_level_protected_environment_settings_permission.yml b/config/feature_flags/development/ci_project_pipeline_config_refactoring.yml
similarity index 50%
rename from config/feature_flags/development/group_level_protected_environment_settings_permission.yml
rename to config/feature_flags/development/ci_project_pipeline_config_refactoring.yml
index bbcfe24ba72..0338b81caf7 100644
--- a/config/feature_flags/development/group_level_protected_environment_settings_permission.yml
+++ b/config/feature_flags/development/ci_project_pipeline_config_refactoring.yml
@@ -1,8 +1,8 @@
---
-name: group_level_protected_environment_settings_permission
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92801
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369873
-milestone: '15.3'
+name: ci_project_pipeline_config_refactoring
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97240
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372867
+milestone: '15.4'
type: development
-group: group::release
-default_enabled: true
+group: group::pipeline authoring
+default_enabled: false
diff --git a/config/feature_flags/development/remove_user_attributes.yml b/config/feature_flags/development/remove_user_attributes_groups.yml
similarity index 81%
rename from config/feature_flags/development/remove_user_attributes.yml
rename to config/feature_flags/development/remove_user_attributes_groups.yml
index 53a2902e590..069d83455f9 100644
--- a/config/feature_flags/development/remove_user_attributes.yml
+++ b/config/feature_flags/development/remove_user_attributes_groups.yml
@@ -1,6 +1,6 @@
---
-name: remove_user_attributes
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96447
+name: remove_user_attributes_groups
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97520
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372047
milestone: '15.4'
type: development
diff --git a/config/feature_flags/development/remove_user_attributes_projects.yml b/config/feature_flags/development/remove_user_attributes_projects.yml
new file mode 100644
index 00000000000..fc1beb42a73
--- /dev/null
+++ b/config/feature_flags/development/remove_user_attributes_projects.yml
@@ -0,0 +1,8 @@
+---
+name: remove_user_attributes_projects
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97520
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372047
+milestone: '15.4'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/ops/ci_partitioning_analyze_queries.yml b/config/feature_flags/ops/ci_partitioning_analyze_queries.yml
new file mode 100644
index 00000000000..59ca52278e9
--- /dev/null
+++ b/config/feature_flags/ops/ci_partitioning_analyze_queries.yml
@@ -0,0 +1,8 @@
+---
+name: ci_partitioning_analyze_queries
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97113
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372840
+milestone: '15.4'
+type: ops
+group: group::pipeline execution
+default_enabled: false
diff --git a/config/webpack.config.js b/config/webpack.config.js
index bad49763f4a..7eb9a7e06e4 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -55,8 +55,17 @@ const INCREMENTAL_COMPILER_RECORD_HISTORY = IS_DEV_SERVER && !process.env.CI;
const WEBPACK_REPORT = process.env.WEBPACK_REPORT && process.env.WEBPACK_REPORT !== 'false';
const WEBPACK_MEMORY_TEST =
process.env.WEBPACK_MEMORY_TEST && process.env.WEBPACK_MEMORY_TEST !== 'false';
-const NO_COMPRESSION = process.env.NO_COMPRESSION && process.env.NO_COMPRESSION !== 'false';
-const NO_SOURCEMAPS = process.env.NO_SOURCEMAPS && process.env.NO_SOURCEMAPS !== 'false';
+let NO_COMPRESSION = process.env.NO_COMPRESSION && process.env.NO_COMPRESSION !== 'false';
+let NO_SOURCEMAPS = process.env.NO_SOURCEMAPS && process.env.NO_SOURCEMAPS !== 'false';
+let NO_HASHED_CHUNKS = process.env.NO_HASHED_CHUNKS && process.env.NO_HASHED_CHUNKS !== 'false';
+
+if (WEBPACK_REPORT) {
+ console.log('Webpack report enabled. Running a "slim" production build.');
+ // For our webpack report we need no source maps, compression _or_ hashed file names.
+ NO_SOURCEMAPS = true;
+ NO_COMPRESSION = true;
+ NO_HASHED_CHUNKS = true;
+}
const WEBPACK_OUTPUT_PATH = path.join(ROOT_PATH, 'public/assets/webpack');
const WEBPACK_PUBLIC_PATH = '/assets/webpack/';
@@ -251,8 +260,10 @@ module.exports = {
output: {
path: WEBPACK_OUTPUT_PATH,
publicPath: WEBPACK_PUBLIC_PATH,
- filename: IS_PRODUCTION ? '[name].[contenthash:8].bundle.js' : '[name].bundle.js',
- chunkFilename: IS_PRODUCTION ? '[name].[contenthash:8].chunk.js' : '[name].chunk.js',
+ filename:
+ IS_PRODUCTION && !NO_HASHED_CHUNKS ? '[name].[contenthash:8].bundle.js' : '[name].bundle.js',
+ chunkFilename:
+ IS_PRODUCTION && !NO_HASHED_CHUNKS ? '[name].[contenthash:8].chunk.js' : '[name].chunk.js',
globalObject: 'this', // allow HMR and web workers to play nice
},
@@ -687,6 +698,8 @@ module.exports = {
statsFilename: path.join(ROOT_PATH, 'webpack-report/stats.json'),
statsOptions: {
source: false,
+ errors: false,
+ warnings: false,
},
}),
diff --git a/danger/Dangerfile-bundle_size b/danger/Dangerfile-bundle_size
index 23ab726096e..122002c1a7b 100644
--- a/danger/Dangerfile-bundle_size
+++ b/danger/Dangerfile-bundle_size
@@ -1,38 +1,7 @@
# frozen_string_literal: true
# This file isn't named "Dangerfile" so that it's not imported by default since it's only meant to be run in the `bundle-size-review` job.
-analysis_result = "./bundle-size-review/analysis.json"
-markdown_result = "./bundle-size-review/comparison.md"
-
-# Executing the webpack-entry-point-analyser
-# We would like to do that in the CI file directly,
-# but unfortunately the head_commit SHA is not available
-# as a CI variable due to our merge into master simulation
-analyze_cmd = [
- "webpack-entry-point-analyser",
- "--from-file ./webpack-report/stats.json",
- "--json #{analysis_result}",
- " --sha #{gitlab&.head_commit}"
-].join(" ")
-
-# execute analysis
-`#{analyze_cmd}`
-
-# We are executing the comparison by comparing the start_sha
-# to the current pipeline result. The start_sha is the commit
-# from master that was merged into for the merged pipeline.
-comparison_cmd = [
- "webpack-compare-reports",
- "--job #{ENV["CI_JOB_ID"]}",
- "--to-file #{analysis_result}",
- "--html ./bundle-size-review/comparison.html",
- "--markdown #{markdown_result}"
-].join(" ")
-
-# execute comparison
-`#{comparison_cmd}`
-
-comment = `cat #{markdown_result}`
+comment = `cat ./bundle-size-review/comparison.md`
unless comment.strip.empty?
markdown(<<~MARKDOWN)
diff --git a/danger/database/Dangerfile b/danger/database/Dangerfile
index 7b3a32358fe..df6ffab7c94 100644
--- a/danger/database/Dangerfile
+++ b/danger/database/Dangerfile
@@ -31,9 +31,8 @@ by removing the ~database label and re-running the [`danger-review` job](#{ENV['
MSG
DB_MIGRATION_TESTING_REQUIRED_MESSAGE = <<~MSG
-1. If this is not a ~"Community contribution" or from a Fork, kick off the
- `db:gitlabcom-database-testing` manual job.
-
+1. Kick off the `db:gitlabcom-database-testing` manual job. This job can also be used before
+ requesting review to test your migrations against production data.
MSG
DATABASE_APPROVED_LABEL = 'database::approved'
diff --git a/doc/api/dora/metrics.md b/doc/api/dora/metrics.md
index 99473ca7b4c..543b6583fde 100644
--- a/doc/api/dora/metrics.md
+++ b/doc/api/dora/metrics.md
@@ -105,3 +105,6 @@ parameter:
| `deployment_frequency` | The number of successful deployments during the time period. |
| `lead_time_for_changes` | The median number of seconds between the merge of the merge request (MR) and the deployment of the MR's commits for all MRs deployed during the time period. |
| `time_to_restore_service` | The median number of seconds an incident was open during the time period. Available only for production environment. |
+
+NOTE:
+The API returns the `monthly` and `all` intervals by calculating the median of the daily median values. This can introduce a slight inaccuracy in the returned data.
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 25fd23ffddb..ebe922239c9 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -7837,6 +7837,29 @@ The edge type for [`MemberInterface`](#memberinterface).
|
`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
`node` | [`MemberInterface`](#memberinterface) | The item at the end of the edge. |
+#### `MergeAccessLevelConnection`
+
+The connection type for [`MergeAccessLevel`](#mergeaccesslevel).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+|
`edges` | [`[MergeAccessLevelEdge]`](#mergeaccessleveledge) | A list of edges. |
+|
`nodes` | [`[MergeAccessLevel]`](#mergeaccesslevel) | A list of nodes. |
+|
`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `MergeAccessLevelEdge`
+
+The edge type for [`MergeAccessLevel`](#mergeaccesslevel).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+|
`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+|
`node` | [`MergeAccessLevel`](#mergeaccesslevel) | The item at the end of the edge. |
+
#### `MergeRequestAssigneeConnection`
The connection type for [`MergeRequestAssignee`](#mergerequestassignee).
@@ -10083,6 +10106,7 @@ Branch protection details for a branch rule.
| Name | Type | Description |
| ---- | ---- | ----------- |
|
`allowForcePush` | [`Boolean!`](#boolean) | Toggle force push to the branch for users with write access. |
+|
`mergeAccessLevels` | [`MergeAccessLevelConnection`](#mergeaccesslevelconnection) | Details about who can merge when this branch is the source branch. (see [Connections](#connections)) |
### `BranchRule`
@@ -13783,6 +13807,17 @@ Maven metadata.
|
`path` | [`String!`](#string) | Path of the Maven package. |
|
`updatedAt` | [`Time!`](#time) | Date of most recent update. |
+### `MergeAccessLevel`
+
+Represents the merge access level of a branch protection.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+|
`accessLevel` | [`Int!`](#int) | GitLab::Access level. |
+|
`accessLevelDescription` | [`String!`](#string) | Human readable representation for this access level. |
+
### `MergeRequest`
#### Fields
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index 65955b3e4e0..2a05471fcf1 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -156,6 +156,12 @@ the time limit to resolve all files is 30 seconds.
- You can override included configuration by having the same job name or global keyword
in the `.gitlab-ci.yml` file. The two configurations are merged together, and the
configuration in the `.gitlab-ci.yml` file takes precedence over the included configuration.
+- If you rerun a:
+ - Job, the `include` files are not fetched again. All jobs in a pipeline use the configuration
+ fetched when the pipeline was created. Any changes to the source `include` files
+ do not affect job reruns.
+ - Pipeline, the `include` files are fetched again. If they changed after the last
+ pipeline run, the new pipeline uses the changed configuration.
**Related topics**:
diff --git a/doc/user/analytics/value_stream_analytics.md b/doc/user/analytics/value_stream_analytics.md
index a71136628cf..3d2d9b2bdf5 100644
--- a/doc/user/analytics/value_stream_analytics.md
+++ b/doc/user/analytics/value_stream_analytics.md
@@ -113,16 +113,23 @@ To view the lead time for changes for merge requests in your project:
The **Lead Time for Changes** metrics display below the **Filter results** text box.
-## View number of successful deployments **(PREMIUM)**
+## View number of successful deployments **(FREE)**
-To view deployment metrics, you must have a
+Prerequisites:
+
+- To view deployment metrics, you must have a
[production environment configured](../../ci/environments/index.md#deployment-tier-of-environments).
-Value stream analytics shows the following deployment metrics for your project:
+Value stream analytics shows the following deployment metrics for your project within the specified date range:
- Deploys: The number of successful deployments in the date range.
- Deployment Frequency: The average number of successful deployments per day in the date range.
+If you have a GitLab Premium or Ultimate subscription:
+
+- The number of successful deployments is calculated with DORA data.
+- The data is filtered based on environment and environment tier.
+
To view deployment metrics for your project:
1. On the top bar, select **Menu > Projects** and find your project.
diff --git a/lib/gitlab/ci/pipeline/chain/config/content.rb b/lib/gitlab/ci/pipeline/chain/config/content.rb
index 3c150ca26bb..a14dec48619 100644
--- a/lib/gitlab/ci/pipeline/chain/config/content.rb
+++ b/lib/gitlab/ci/pipeline/chain/config/content.rb
@@ -7,6 +7,7 @@ module Gitlab
module Config
class Content < Chain::Base
include Chain::Helpers
+ include ::Gitlab::Utils::StrongMemoize
SOURCES = [
Gitlab::Ci::Pipeline::Chain::Config::Content::Parameter,
@@ -18,10 +19,10 @@ module Gitlab
].freeze
def perform!
- if config = find_config
- @pipeline.build_pipeline_config(content: config.content)
- @command.config_content = config.content
- @pipeline.config_source = config.source
+ if pipeline_config&.exists?
+ @pipeline.build_pipeline_config(content: pipeline_config.content)
+ @command.config_content = pipeline_config.content
+ @pipeline.config_source = pipeline_config.source
else
error('Missing CI config file')
end
@@ -33,7 +34,19 @@ module Gitlab
private
- def find_config
+ def pipeline_config
+ strong_memoize(:pipeline_config) do
+ next legacy_find_config if ::Feature.disabled?(:ci_project_pipeline_config_refactoring, project)
+
+ ::Gitlab::Ci::ProjectConfig.new(
+ project: project, sha: @pipeline.sha,
+ custom_content: @command.content,
+ pipeline_source: @command.source, pipeline_source_bridge: @command.bridge
+ )
+ end
+ end
+
+ def legacy_find_config
sources.each do |source|
config = source.new(@pipeline, @command)
return config if config.exists?
diff --git a/lib/gitlab/ci/pipeline/chain/config/content/source.rb b/lib/gitlab/ci/pipeline/chain/config/content/source.rb
index 8bc172f93d3..69dca1568b6 100644
--- a/lib/gitlab/ci/pipeline/chain/config/content/source.rb
+++ b/lib/gitlab/ci/pipeline/chain/config/content/source.rb
@@ -6,6 +6,7 @@ module Gitlab
module Chain
module Config
class Content
+ # When removing ci_project_pipeline_config_refactoring, this and its subclasses will be removed.
class Source
include Gitlab::Utils::StrongMemoize
diff --git a/lib/gitlab/ci/project_config.rb b/lib/gitlab/ci/project_config.rb
new file mode 100644
index 00000000000..ded6877ef29
--- /dev/null
+++ b/lib/gitlab/ci/project_config.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ # Locates project CI config
+ class ProjectConfig
+ # The order of sources is important:
+ # - EE uses Compliance first since it must be used first if compliance templates are enabled.
+ # (see ee/lib/ee/gitlab/ci/project_config.rb)
+ # - Parameter is used by on-demand security scanning which passes the actual CI YAML to use as argument.
+ # - Bridge is used for downstream pipelines since the config is defined in the bridge job. If lower in priority,
+ # it would evaluate the project's YAML file instead.
+ # - Repository / ExternalProject / Remote: their order is not important between each other.
+ # - AutoDevops is used as default option if nothing else is found and if AutoDevops is enabled.
+ SOURCES = [
+ ProjectConfig::Parameter,
+ ProjectConfig::Bridge,
+ ProjectConfig::Repository,
+ ProjectConfig::ExternalProject,
+ ProjectConfig::Remote,
+ ProjectConfig::AutoDevops
+ ].freeze
+
+ def initialize(project:, sha:, custom_content: nil, pipeline_source: nil, pipeline_source_bridge: nil)
+ @config = find_config(project, sha, custom_content, pipeline_source, pipeline_source_bridge)
+ end
+
+ delegate :content, :source, to: :@config, allow_nil: true
+
+ def exists?
+ !!@config&.exists?
+ end
+
+ private
+
+ def find_config(project, sha, custom_content, pipeline_source, pipeline_source_bridge)
+ sources.each do |source|
+ config = source.new(project, sha, custom_content, pipeline_source, pipeline_source_bridge)
+ return config if config.exists?
+ end
+
+ nil
+ end
+
+ def sources
+ SOURCES
+ end
+ end
+ end
+end
+
+Gitlab::Ci::ProjectConfig.prepend_mod_with('Gitlab::Ci::ProjectConfig')
diff --git a/lib/gitlab/ci/project_config/auto_devops.rb b/lib/gitlab/ci/project_config/auto_devops.rb
new file mode 100644
index 00000000000..c6905f480a2
--- /dev/null
+++ b/lib/gitlab/ci/project_config/auto_devops.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class ProjectConfig
+ class AutoDevops < Source
+ def content
+ strong_memoize(:content) do
+ next unless project&.auto_devops_enabled?
+
+ template = Gitlab::Template::GitlabCiYmlTemplate.find(template_name)
+ YAML.dump('include' => [{ 'template' => template.full_name }])
+ end
+ end
+
+ def source
+ :auto_devops_source
+ end
+
+ private
+
+ def template_name
+ 'Auto-DevOps'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/project_config/bridge.rb b/lib/gitlab/ci/project_config/bridge.rb
new file mode 100644
index 00000000000..c342ab2c215
--- /dev/null
+++ b/lib/gitlab/ci/project_config/bridge.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class ProjectConfig
+ class Bridge < Source
+ def content
+ return unless pipeline_source_bridge
+
+ pipeline_source_bridge.yaml_for_downstream
+ end
+
+ def source
+ :bridge_source
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/project_config/external_project.rb b/lib/gitlab/ci/project_config/external_project.rb
new file mode 100644
index 00000000000..0ed5d6fa226
--- /dev/null
+++ b/lib/gitlab/ci/project_config/external_project.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class ProjectConfig
+ class ExternalProject < Source
+ def content
+ strong_memoize(:content) do
+ next unless external_project_path?
+
+ path_file, path_project, ref = extract_location_tokens
+
+ config_location = { 'project' => path_project, 'file' => path_file }
+ config_location['ref'] = ref if ref.present?
+
+ YAML.dump('include' => [config_location])
+ end
+ end
+
+ def source
+ :external_project_source
+ end
+
+ private
+
+ # Example: path/to/.gitlab-ci.yml@another-group/another-project
+ def external_project_path?
+ ci_config_path =~ /\A.+(yml|yaml)@.+\z/
+ end
+
+ # Example: path/to/.gitlab-ci.yml@another-group/another-project:refname
+ def extract_location_tokens
+ path_file, path_project = ci_config_path.split('@', 2)
+
+ if path_project.include? ":"
+ project, ref = path_project.split(':', 2)
+ [path_file, project, ref]
+ else
+ [path_file, path_project]
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/project_config/parameter.rb b/lib/gitlab/ci/project_config/parameter.rb
new file mode 100644
index 00000000000..69e699c27f1
--- /dev/null
+++ b/lib/gitlab/ci/project_config/parameter.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class ProjectConfig
+ class Parameter < Source
+ def content
+ strong_memoize(:content) do
+ next unless custom_content.present?
+
+ custom_content
+ end
+ end
+
+ def source
+ :parameter_source
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/project_config/remote.rb b/lib/gitlab/ci/project_config/remote.rb
new file mode 100644
index 00000000000..cf1292706d2
--- /dev/null
+++ b/lib/gitlab/ci/project_config/remote.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class ProjectConfig
+ class Remote < Source
+ def content
+ strong_memoize(:content) do
+ next unless ci_config_path =~ URI::DEFAULT_PARSER.make_regexp(%w[http https])
+
+ YAML.dump('include' => [{ 'remote' => ci_config_path }])
+ end
+ end
+
+ def source
+ :remote_source
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/project_config/repository.rb b/lib/gitlab/ci/project_config/repository.rb
new file mode 100644
index 00000000000..435ad4d42fe
--- /dev/null
+++ b/lib/gitlab/ci/project_config/repository.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class ProjectConfig
+ class Repository < Source
+ def content
+ strong_memoize(:content) do
+ next unless file_in_repository?
+
+ YAML.dump('include' => [{ 'local' => ci_config_path }])
+ end
+ end
+
+ def source
+ :repository_source
+ end
+
+ private
+
+ def file_in_repository?
+ return unless project
+ return unless sha
+
+ project.repository.gitlab_ci_yml_for(sha, ci_config_path).present?
+ rescue GRPC::NotFound, GRPC::Internal
+ nil
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/project_config/source.rb b/lib/gitlab/ci/project_config/source.rb
new file mode 100644
index 00000000000..ebe5728163b
--- /dev/null
+++ b/lib/gitlab/ci/project_config/source.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class ProjectConfig
+ class Source
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(project, sha, custom_content, pipeline_source, pipeline_source_bridge)
+ @project = project
+ @sha = sha
+ @custom_content = custom_content
+ @pipeline_source = pipeline_source
+ @pipeline_source_bridge = pipeline_source_bridge
+ end
+
+ def exists?
+ strong_memoize(:exists) do
+ content.present?
+ end
+ end
+
+ def content
+ raise NotImplementedError
+ end
+
+ def source
+ raise NotImplementedError
+ end
+
+ private
+
+ attr_reader :project, :sha, :custom_content, :pipeline_source, :pipeline_source_bridge
+
+ def ci_config_path
+ @ci_config_path ||= project.ci_config_path_or_default
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb b/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb
new file mode 100644
index 00000000000..c2d5dfc1a15
--- /dev/null
+++ b/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module QueryAnalyzers
+ module Ci
+ # The purpose of this analyzer is to detect queries not going through a partitioning routing table
+ class PartitioningAnalyzer < Database::QueryAnalyzers::Base
+ RoutingTableNotUsedError = Class.new(QueryAnalyzerError)
+
+ ENABLED_TABLES = %w[
+ ci_builds_metadata
+ ].freeze
+
+ class << self
+ def enabled?
+ ::Feature::FlipperFeature.table_exists? &&
+ ::Feature.enabled?(:ci_partitioning_analyze_queries, type: :ops)
+ end
+
+ def analyze(parsed)
+ analyze_legacy_tables_usage(parsed)
+ end
+
+ private
+
+ def analyze_legacy_tables_usage(parsed)
+ detected = ENABLED_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables)
+
+ return if detected.none?
+
+ ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
+ RoutingTableNotUsedError.new("Detected non-partitioned table use #{detected.inspect}: #{parsed.sql}")
+ )
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb
index 30465ff5f74..5b9216c0914 100644
--- a/lib/gitlab/i18n.rb
+++ b/lib/gitlab/i18n.rb
@@ -44,30 +44,30 @@ module Gitlab
TRANSLATION_LEVELS = {
'bg' => 0,
'cs_CZ' => 0,
- 'da_DK' => 39,
+ 'da_DK' => 38,
'de' => 17,
'en' => 100,
'eo' => 0,
- 'es' => 38,
+ 'es' => 37,
'fil_PH' => 0,
'fr' => 11,
'gl_ES' => 0,
'id_ID' => 0,
'it' => 1,
- 'ja' => 32,
- 'ko' => 12,
+ 'ja' => 31,
+ 'ko' => 17,
'nb_NO' => 26,
'nl_NL' => 0,
'pl_PL' => 4,
- 'pt_BR' => 55,
- 'ro_RO' => 100,
+ 'pt_BR' => 56,
+ 'ro_RO' => 99,
'ru' => 27,
'si_LK' => 10,
- 'tr_TR' => 12,
+ 'tr_TR' => 11,
'uk' => 50,
- 'zh_CN' => 99,
+ 'zh_CN' => 97,
'zh_HK' => 1,
- 'zh_TW' => 100
+ 'zh_TW' => 99
}.freeze
private_constant :TRANSLATION_LEVELS
diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake
index 0b70dba5c05..76ee5379213 100644
--- a/lib/tasks/gitlab/assets.rake
+++ b/lib/tasks/gitlab/assets.rake
@@ -40,6 +40,7 @@ module Tasks
asset_files
end
+
private_class_method :assets_impacting_webpack_compilation
end
end
@@ -84,9 +85,17 @@ namespace :gitlab do
if head_assets_sha256 != master_assets_sha256 || !public_assets_webpack_dir_exists
FileUtils.rm_r(Tasks::Gitlab::Assets::PUBLIC_ASSETS_WEBPACK_DIR) if public_assets_webpack_dir_exists
- unless system('yarn webpack')
+ log_path = ENV['WEBPACK_COMPILE_LOG_PATH']
+
+ cmd = 'yarn webpack'
+ cmd += " > #{log_path}" if log_path
+
+ unless system(cmd)
abort 'Error: Unable to compile webpack production bundle.'.color(:red)
end
+
+ puts "Written webpack stdout log to #{log_path}" if log_path
+ puts "You can inspect the webpack log here: #{ENV['CI_JOB_URL']}/artifacts/file/#{log_path}" if log_path && ENV['CI_JOB_URL']
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index ad5d4eb0942..73243661969 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -46564,6 +46564,9 @@ msgstr ""
msgid "comment"
msgstr ""
+msgid "commented"
+msgstr ""
+
msgid "commented on %{link_to_project}"
msgstr ""
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/content_editor_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/content_editor_spec.rb
index 4b8edf8b792..2e8cacd8e19 100644
--- a/qa/qa/specs/features/browser_ui/3_create/wiki/content_editor_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/content_editor_spec.rb
@@ -1,7 +1,10 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, quarantine: {
+ type: :investigating,
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/373093'
+ } do
context 'Content Editor' do
let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
let(:page_title) { 'Content Editor Page' }
diff --git a/scripts/bundle_size_review b/scripts/bundle_size_review
new file mode 100755
index 00000000000..5067c3c3f2c
--- /dev/null
+++ b/scripts/bundle_size_review
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+set -euo pipefail
+IFS=$'\n\t'
+
+#
+# # How does this work in general?
+#
+# 1. We run webpack in a production like mode and enable the BundleAnalyzerPlugin
+# 2. The Plugin builds a index.html for human consumption _and_ a stats.json
+# 3. This script creates a smaller analysis.json from the gargantuan stats.json
+# 4. In Merge Requests:
+# - compare that smaller to analysis.json to the one from the base commit on master
+# - report the comparison results via danger
+
+source scripts/utils.sh
+
+# For now we only want bundle-size-review to run in CI
+# Maybe we could create a "local mode"
+if [[ -z "${CI:-}" ]]; then
+ echo 'Not running in a CI context, skipping bundle analysis'
+ exit "0"
+fi
+
+# Get the _current_ commit sha
+if [[ -z "${CI_MERGE_REQUEST_IID:-}" ]]; then
+ echo 'Not in a merge request, setting COMMIT_SHA to $CI_COMMIT_SHA'
+ COMMIT_SHA="${CI_COMMIT_SHA}"
+else
+ echo 'In a merge request, setting COMMIT_SHA to $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA'
+ COMMIT_SHA="${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA}"
+fi
+
+# Create output directory
+mkdir -p bundle-size-review
+
+# Running webpack
+export WEBPACK_REPORT="true"
+run_timed_command "yarn run webpack-prod > bundle-size-review/webpack-output.log"
+
+# Copy results from stats plugin
+cp webpack-report/index.html bundle-size-review/bundle-report.html
+
+# Run comparison in danger
+if [[ -z "${DANGER_GITLAB_API_TOKEN:-}" ]]; then
+ echo 'No Danger token available, skipping bundle analysis'
+ exit "0"
+fi
+
+# TODO: Make this a dependency of GitLab itself after a proper release
+yarn global add https://gitlab.com/gitlab-org/frontend/playground/webpack-memory-metrics.git
+
+# Create smaller analysis.json
+run_timed_command "webpack-entry-point-analyser --from-file ./webpack-report/stats.json --json ./bundle-size-review/analysis.json --sha ${COMMIT_SHA}"
+rm -rf webpack-report
+
+if [[ -z "${CI_MERGE_REQUEST_IID:-}" ]]; then
+ echo 'Not in a merge request, skipping comparison'
+ exit "0"
+fi
+
+# Run comparison
+run_timed_command "webpack-compare-reports --job ${CI_JOB_ID} --to-file ./bundle-size-review/analysis.json --html ./bundle-size-review/comparison.html --markdown ./bundle-size-review/comparison.md"
+
+# Execute danger
+danger_id=$(echo -n "${DANGER_GITLAB_API_TOKEN}" | md5sum | awk '{print $1}' | cut -c5-10)
+run_timed_command "danger --dangerfile=danger/Dangerfile-bundle_size --fail-on-errors=true --verbose --danger_id=bundle-size-review-${danger_id}"
+
+exit "0"
diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb
index cee7b577236..142ddb2b2c7 100644
--- a/spec/factories/protected_branches.rb
+++ b/spec/factories/protected_branches.rb
@@ -17,6 +17,16 @@ FactoryBot.define do
ProtectedBranches::CacheService.new(protected_branch.project).refresh
end
+ after(:build) do |protected_branch, evaluator|
+ if evaluator.default_access_level && evaluator.default_push_level
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
+ end
+
+ if evaluator.default_access_level && evaluator.default_merge_level
+ protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
+ end
+ end
+
trait :create_branch_on_repository do
association :project, factory: [:project, :repository]
@@ -31,6 +41,26 @@ FactoryBot.define do
end
end
+ trait :maintainers_can_push do
+ transient do
+ default_push_level { false }
+ end
+
+ after(:build) do |protected_branch|
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
+ end
+ end
+
+ trait :maintainers_can_merge do
+ transient do
+ default_push_level { false }
+ end
+
+ after(:build) do |protected_branch|
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
+ end
+ end
+
trait :developers_can_push do
transient do
default_push_level { false }
@@ -61,29 +91,13 @@ FactoryBot.define do
end
end
- trait :maintainers_can_push do
+ trait :no_one_can_merge do
transient do
- default_push_level { false }
+ default_merge_level { false }
end
after(:build) do |protected_branch|
- protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
- end
- end
-
- after(:build) do |protected_branch, evaluator|
- if evaluator.default_access_level && evaluator.default_push_level
- protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
- end
-
- if evaluator.default_access_level && evaluator.default_merge_level
- protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
- end
- end
-
- trait :no_one_can_merge do
- after(:create) do |protected_branch|
- protected_branch.merge_access_levels.first.update!(access_level: Gitlab::Access::NO_ACCESS)
+ protected_branch.merge_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
end
end
end
diff --git a/spec/features/discussion_comments/issue_spec.rb b/spec/features/discussion_comments/issue_spec.rb
index a8438b46803..0bb43343ecd 100644
--- a/spec/features/discussion_comments/issue_spec.rb
+++ b/spec/features/discussion_comments/issue_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'Thread Comments Issue', :js do
let(:issue) { create(:issue, project: project) }
before do
- stub_feature_flags(remove_user_attributes: false)
+ stub_feature_flags(remove_user_attributes_projects: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb
index 71777679966..4fa82de3b4b 100644
--- a/spec/features/discussion_comments/merge_request_spec.rb
+++ b/spec/features/discussion_comments/merge_request_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'Thread Comments Merge Request', :js do
let(:merge_request) { create(:merge_request, source_project: project) }
before do
- stub_feature_flags(remove_user_attributes: false)
+ stub_feature_flags(remove_user_attributes_projects: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/issuables/markdown_references/jira_spec.rb b/spec/features/issuables/markdown_references/jira_spec.rb
index 3cb88bd9191..9d46b3a274e 100644
--- a/spec/features/issuables/markdown_references/jira_spec.rb
+++ b/spec/features/issuables/markdown_references/jira_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe "Jira", :js do
before do
remotelink = double(:remotelink, all: [], build: double(save!: true))
- stub_feature_flags(remove_user_attributes: false)
+ stub_feature_flags(remove_user_attributes_projects: false)
stub_request(:get, "https://jira.example.com/rest/api/2/issue/JIRA-5")
stub_request(:post, "https://jira.example.com/rest/api/2/issue/JIRA-5/comment")
diff --git a/spec/features/issues/resource_label_events_spec.rb b/spec/features/issues/resource_label_events_spec.rb
index b47f9596344..e4da2f67516 100644
--- a/spec/features/issues/resource_label_events_spec.rb
+++ b/spec/features/issues/resource_label_events_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe 'List issue resource label events', :js do
let!(:event) { create(:resource_label_event, user: user, issue: issue, label: label) }
before do
- stub_feature_flags(remove_user_attributes: false)
+ stub_feature_flags(remove_user_attributes_projects: false)
visit project_issue_path(project, issue)
wait_for_requests
end
diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb
index 01b4cfc1779..fd33731cb7b 100644
--- a/spec/features/merge_request/user_comments_on_diff_spec.rb
+++ b/spec/features/merge_request/user_comments_on_diff_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe 'User comments on a diff', :js do
let(:user) { create(:user) }
before do
- stub_feature_flags(remove_user_attributes: false)
+ stub_feature_flags(remove_user_attributes_projects: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/merge_request/user_comments_on_merge_request_spec.rb b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
index 1c45c314e85..ec1e2fea851 100644
--- a/spec/features/merge_request/user_comments_on_merge_request_spec.rb
+++ b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'User comments on a merge request', :js do
let(:user) { create(:user) }
before do
- stub_feature_flags(remove_user_attributes: false)
+ stub_feature_flags(remove_user_attributes_projects: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/merge_request/user_views_user_status_on_merge_request_spec.rb b/spec/features/merge_request/user_views_user_status_on_merge_request_spec.rb
index 900924f86c1..d3ea8b955f2 100644
--- a/spec/features/merge_request/user_views_user_status_on_merge_request_spec.rb
+++ b/spec/features/merge_request/user_views_user_status_on_merge_request_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'Project > Merge request > View user status' do
end
before do
- stub_feature_flags(remove_user_attributes: false)
+ stub_feature_flags(remove_user_attributes_projects: false)
end
subject { visit merge_request_path(merge_request) }
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index 8b2b33dccf6..067abb46602 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'User edit profile' do
let(:user) { create(:user) }
before do
- stub_feature_flags(remove_user_attributes: false)
+ stub_feature_flags(remove_user_attributes_projects: false)
sign_in(user)
visit(profile_path)
end
diff --git a/spec/frontend/notes/components/note_header_spec.js b/spec/frontend/notes/components/note_header_spec.js
index 8b4fab48b7e..8befcc496d6 100644
--- a/spec/frontend/notes/components/note_header_spec.js
+++ b/spec/frontend/notes/components/note_header_spec.js
@@ -49,7 +49,8 @@ describe('NoteHeader component', () => {
stubs: { GlSprintf, UserNameWithStatus },
provide: {
glFeatures: {
- removeUserAttributes: userAttributes,
+ removeUserAttributesProjects: userAttributes,
+ removeUserAttributesGroups: userAttributes,
},
},
});
@@ -60,7 +61,7 @@ describe('NoteHeader component', () => {
wrapper = null;
});
- describe('when removeUserAttributes feature flag is enabled', () => {
+ describe('when removeUserAttributesProjects feature flag is enabled', () => {
it('does not render busy status', () => {
createComponent({ author: { ...author, availability: AVAILABILITY_STATUS.BUSY } }, true);
diff --git a/spec/frontend/pages/import/history/components/import_history_app_spec.js b/spec/frontend/pages/import/history/components/import_history_app_spec.js
index 0d821b114cf..5030adae2fa 100644
--- a/spec/frontend/pages/import/history/components/import_history_app_spec.js
+++ b/spec/frontend/pages/import/history/components/import_history_app_spec.js
@@ -79,7 +79,7 @@ describe('ImportHistoryApp', () => {
describe('general behavior', () => {
it('renders loading state when loading', () => {
createComponent();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
it('renders empty state when no data is available', async () => {
@@ -87,8 +87,8 @@ describe('ImportHistoryApp', () => {
createComponent();
await axios.waitForAll();
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
- expect(wrapper.find(GlEmptyState).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
+ expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true);
});
it('renders table with data when history is available', async () => {
@@ -96,7 +96,7 @@ describe('ImportHistoryApp', () => {
createComponent();
await axios.waitForAll();
- const table = wrapper.find(GlTable);
+ const table = wrapper.findComponent(GlTable);
expect(table.exists()).toBe(true);
expect(table.props().items).toStrictEqual(DUMMY_RESPONSE);
});
@@ -127,7 +127,7 @@ describe('ImportHistoryApp', () => {
expect(mock.history.get.length).toBe(1);
expect(mock.history.get[0].params).toStrictEqual(expect.objectContaining({ page: NEW_PAGE }));
- expect(wrapper.find(GlTable).props().items).toStrictEqual(FAKE_NEXT_PAGE_REPLY);
+ expect(wrapper.findComponent(GlTable).props().items).toStrictEqual(FAKE_NEXT_PAGE_REPLY);
});
});
diff --git a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
index f676f2db08e..ebb254b49c1 100644
--- a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
@@ -362,7 +362,7 @@ describe('ForkForm component', () => {
const submitForm = async () => {
fillForm();
await nextTick();
- const form = wrapper.find(GlForm);
+ const form = wrapper.findComponent(GlForm);
await form.trigger('submit');
await nextTick();
diff --git a/spec/frontend/pages/projects/graphs/code_coverage_spec.js b/spec/frontend/pages/projects/graphs/code_coverage_spec.js
index f272891919d..c9c0e406c46 100644
--- a/spec/frontend/pages/projects/graphs/code_coverage_spec.js
+++ b/spec/frontend/pages/projects/graphs/code_coverage_spec.js
@@ -20,8 +20,8 @@ describe('Code Coverage', () => {
const graphRef = 'master';
const graphCsvPath = 'url/';
- const findAlert = () => wrapper.find(GlAlert);
- const findAreaChart = () => wrapper.find(GlAreaChart);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findAreaChart = () => wrapper.findComponent(GlAreaChart);
const findAllDropdownItems = () => wrapper.findAll(GlDropdownItem);
const findFirstDropdownItem = () => findAllDropdownItems().at(0);
const findSecondDropdownItem = () => findAllDropdownItems().at(1);
@@ -142,7 +142,7 @@ describe('Code Coverage', () => {
});
it('renders the dropdown with all custom names as options', () => {
- expect(wrapper.find(GlDropdown).exists()).toBeDefined();
+ expect(wrapper.findComponent(GlDropdown).exists()).toBeDefined();
expect(findAllDropdownItems()).toHaveLength(codeCoverageMockData.length);
expect(findFirstDropdownItem().text()).toBe(codeCoverageMockData[0].group_name);
});
diff --git a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
index ca7f70f4434..a633332ab65 100644
--- a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
+++ b/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
@@ -21,7 +21,7 @@ describe('Pipeline Schedule Callout', () => {
};
const findInnerContentOfCallout = () => wrapper.find('[data-testid="innerContent"]');
- const findDismissCalloutBtn = () => wrapper.find(GlButton);
+ const findDismissCalloutBtn = () => wrapper.findComponent(GlButton);
describe(`when ${cookieKey} cookie is set`, () => {
beforeEach(async () => {
diff --git a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
index b65f2c8020d..e551e2797e5 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
@@ -81,15 +81,17 @@ describe('Settings Panel', () => {
});
};
- const findLFSSettingsRow = () => wrapper.find({ ref: 'git-lfs-settings' });
+ const findLFSSettingsRow = () => wrapper.findComponent({ ref: 'git-lfs-settings' });
const findLFSSettingsMessage = () => findLFSSettingsRow().find('p');
- const findLFSFeatureToggle = () => findLFSSettingsRow().find(GlToggle);
- const findRepositoryFeatureProjectRow = () => wrapper.find({ ref: 'repository-settings' });
+ const findLFSFeatureToggle = () => findLFSSettingsRow().findComponent(GlToggle);
+ const findRepositoryFeatureProjectRow = () =>
+ wrapper.findComponent({ ref: 'repository-settings' });
const findRepositoryFeatureSetting = () =>
- findRepositoryFeatureProjectRow().find(ProjectFeatureSetting);
- const findProjectVisibilitySettings = () => wrapper.find({ ref: 'project-visibility-settings' });
- const findIssuesSettingsRow = () => wrapper.find({ ref: 'issues-settings' });
- const findAnalyticsRow = () => wrapper.find({ ref: 'analytics-settings' });
+ findRepositoryFeatureProjectRow().findComponent(ProjectFeatureSetting);
+ const findProjectVisibilitySettings = () =>
+ wrapper.findComponent({ ref: 'project-visibility-settings' });
+ const findIssuesSettingsRow = () => wrapper.findComponent({ ref: 'issues-settings' });
+ const findAnalyticsRow = () => wrapper.findComponent({ ref: 'analytics-settings' });
const findProjectVisibilityLevelInput = () => wrapper.find('[name="project[visibility_level]"]');
const findRequestAccessEnabledInput = () =>
wrapper.find('[name="project[request_access_enabled]"]');
@@ -99,31 +101,33 @@ describe('Settings Panel', () => {
wrapper.find('[name="project[project_feature_attributes][forking_access_level]"]');
const findBuildsAccessLevelInput = () =>
wrapper.find('[name="project[project_feature_attributes][builds_access_level]"]');
- const findContainerRegistrySettings = () => wrapper.find({ ref: 'container-registry-settings' });
+ const findContainerRegistrySettings = () =>
+ wrapper.findComponent({ ref: 'container-registry-settings' });
const findContainerRegistryPublicNoteGlSprintfComponent = () =>
findContainerRegistrySettings().findComponent(GlSprintf);
const findContainerRegistryAccessLevelInput = () =>
wrapper.find('[name="project[project_feature_attributes][container_registry_access_level]"]');
- const findPackageSettings = () => wrapper.find({ ref: 'package-settings' });
+ const findPackageSettings = () => wrapper.findComponent({ ref: 'package-settings' });
const findPackageAccessLevel = () =>
wrapper.find('[data-testid="package-registry-access-level"]');
const findPackageAccessLevels = () =>
wrapper.find('[name="project[project_feature_attributes][package_registry_access_level]"]');
const findPackagesEnabledInput = () => wrapper.find('[name="project[packages_enabled]"]');
- const findPagesSettings = () => wrapper.find({ ref: 'pages-settings' });
+ const findPagesSettings = () => wrapper.findComponent({ ref: 'pages-settings' });
const findPagesAccessLevels = () =>
wrapper.find('[name="project[project_feature_attributes][pages_access_level]"]');
- const findEmailSettings = () => wrapper.find({ ref: 'email-settings' });
+ const findEmailSettings = () => wrapper.findComponent({ ref: 'email-settings' });
const findShowDefaultAwardEmojis = () =>
wrapper.find('input[name="project[project_setting_attributes][show_default_award_emojis]"]');
const findWarnAboutPuc = () =>
wrapper.find(
'input[name="project[project_setting_attributes][warn_about_potentially_unwanted_characters]"]',
);
- const findMetricsVisibilitySettings = () => wrapper.find({ ref: 'metrics-visibility-settings' });
+ const findMetricsVisibilitySettings = () =>
+ wrapper.findComponent({ ref: 'metrics-visibility-settings' });
const findMetricsVisibilityInput = () =>
findMetricsVisibilitySettings().findComponent(ProjectFeatureSetting);
- const findOperationsSettings = () => wrapper.find({ ref: 'operations-settings' });
+ const findOperationsSettings = () => wrapper.findComponent({ ref: 'operations-settings' });
const findOperationsVisibilityInput = () =>
findOperationsSettings().findComponent(ProjectFeatureSetting);
const findConfirmDangerButton = () => wrapper.findComponent(ConfirmDanger);
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
index 36a926990f2..b37d2f06191 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
@@ -39,7 +39,7 @@ describe('WikiForm', () => {
const findMarkdownHelpLink = () => wrapper.findByTestId('wiki-markdown-help-link');
const findContentEditor = () => wrapper.findComponent(ContentEditor);
const findClassicEditor = () => wrapper.findComponent(MarkdownField);
- const findLocalStorageSync = () => wrapper.find(LocalStorageSync);
+ const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
const setFormat = (value) => {
const format = findFormat();
diff --git a/spec/frontend/performance_bar/components/detailed_metric_spec.js b/spec/frontend/performance_bar/components/detailed_metric_spec.js
index 2ae36740dfb..437d51e02ba 100644
--- a/spec/frontend/performance_bar/components/detailed_metric_spec.js
+++ b/spec/frontend/performance_bar/components/detailed_metric_spec.js
@@ -257,7 +257,7 @@ describe('detailedMetric', () => {
});
it('displays request warnings', () => {
- expect(wrapper.find(RequestWarning).exists()).toBe(true);
+ expect(wrapper.findComponent(RequestWarning).exists()).toBe(true);
});
it('can open and close traces', async () => {
diff --git a/spec/frontend/pipeline_editor/components/lint/ci_lint_results_spec.js b/spec/frontend/pipeline_editor/components/lint/ci_lint_results_spec.js
index 82ac390971d..7f89eda4dff 100644
--- a/spec/frontend/pipeline_editor/components/lint/ci_lint_results_spec.js
+++ b/spec/frontend/pipeline_editor/components/lint/ci_lint_results_spec.js
@@ -24,11 +24,11 @@ describe('CI Lint Results', () => {
});
};
- const findTable = () => wrapper.find(GlTableLite);
+ const findTable = () => wrapper.findComponent(GlTableLite);
const findByTestId = (selector) => () => wrapper.find(`[data-testid="ci-lint-${selector}"]`);
const findAllByTestId = (selector) => () =>
wrapper.findAll(`[data-testid="ci-lint-${selector}"]`);
- const findLinkToDoc = () => wrapper.find(GlLink);
+ const findLinkToDoc = () => wrapper.findComponent(GlLink);
const findErrors = findByTestId('errors');
const findWarnings = findByTestId('warnings');
const findStatus = findByTestId('status');
diff --git a/spec/frontend/pipeline_editor/components/lint/ci_lint_warnings_spec.js b/spec/frontend/pipeline_editor/components/lint/ci_lint_warnings_spec.js
index 4b576508ee9..36052a2e16a 100644
--- a/spec/frontend/pipeline_editor/components/lint/ci_lint_warnings_spec.js
+++ b/spec/frontend/pipeline_editor/components/lint/ci_lint_warnings_spec.js
@@ -17,9 +17,9 @@ describe('CI lint warnings', () => {
});
};
- const findWarningAlert = () => wrapper.find(GlAlert);
+ const findWarningAlert = () => wrapper.findComponent(GlAlert);
const findWarnings = () => wrapper.findAll('[data-testid="ci-lint-warning"]');
- const findWarningMessage = () => trimText(wrapper.find(GlSprintf).text());
+ const findWarningMessage = () => trimText(wrapper.findComponent(GlSprintf).text());
afterEach(() => {
wrapper.destroy();
diff --git a/spec/frontend/pipeline_editor/pipeline_editor_home_spec.js b/spec/frontend/pipeline_editor/pipeline_editor_home_spec.js
index 0cb7155c8c0..e317d1ddcc2 100644
--- a/spec/frontend/pipeline_editor/pipeline_editor_home_spec.js
+++ b/spec/frontend/pipeline_editor/pipeline_editor_home_spec.js
@@ -254,7 +254,7 @@ describe('Pipeline editor home wrapper', () => {
expect(findPipelineEditorDrawer().props('isVisible')).toBe(true);
- findPipelineEditorDrawer().find(GlDrawer).vm.$emit('close');
+ findPipelineEditorDrawer().findComponent(GlDrawer).vm.$emit('close');
await nextTick();
expect(findPipelineEditorDrawer().props('isVisible')).toBe(false);
diff --git a/spec/frontend/pipeline_new/components/legacy_pipeline_new_form_spec.js b/spec/frontend/pipeline_new/components/legacy_pipeline_new_form_spec.js
index f2d2575c5fb..512b152f106 100644
--- a/spec/frontend/pipeline_new/components/legacy_pipeline_new_form_spec.js
+++ b/spec/frontend/pipeline_new/components/legacy_pipeline_new_form_spec.js
@@ -34,7 +34,7 @@ describe('Pipeline New Form', () => {
let mock;
let dummySubmitEvent;
- const findForm = () => wrapper.find(GlForm);
+ const findForm = () => wrapper.findComponent(GlForm);
const findRefsDropdown = () => wrapper.findComponent(RefsDropdown);
const findSubmitButton = () => wrapper.find('[data-testid="run_pipeline_button"]');
const findVariableRows = () => wrapper.findAll('[data-testid="ci-variable-row"]');
@@ -44,9 +44,9 @@ describe('Pipeline New Form', () => {
const findValueInputs = () => wrapper.findAll('[data-testid="pipeline-form-ci-variable-value"]');
const findErrorAlert = () => wrapper.find('[data-testid="run-pipeline-error-alert"]');
const findWarningAlert = () => wrapper.find('[data-testid="run-pipeline-warning-alert"]');
- const findWarningAlertSummary = () => findWarningAlert().find(GlSprintf);
+ const findWarningAlertSummary = () => findWarningAlert().findComponent(GlSprintf);
const findWarnings = () => wrapper.findAll('[data-testid="run-pipeline-warning"]');
- const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findCCAlert = () => wrapper.findComponent(CreditCardValidationRequiredAlert);
const getFormPostParams = () => JSON.parse(mock.history.post[0].data);
diff --git a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js b/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
index e6bf253b66d..5ce29bd6c5d 100644
--- a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
+++ b/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
@@ -34,7 +34,7 @@ describe('Pipeline New Form', () => {
let mock;
let dummySubmitEvent;
- const findForm = () => wrapper.find(GlForm);
+ const findForm = () => wrapper.findComponent(GlForm);
const findRefsDropdown = () => wrapper.findComponent(RefsDropdown);
const findSubmitButton = () => wrapper.find('[data-testid="run_pipeline_button"]');
const findVariableRows = () => wrapper.findAll('[data-testid="ci-variable-row"]');
@@ -44,9 +44,9 @@ describe('Pipeline New Form', () => {
const findValueInputs = () => wrapper.findAll('[data-testid="pipeline-form-ci-variable-value"]');
const findErrorAlert = () => wrapper.find('[data-testid="run-pipeline-error-alert"]');
const findWarningAlert = () => wrapper.find('[data-testid="run-pipeline-warning-alert"]');
- const findWarningAlertSummary = () => findWarningAlert().find(GlSprintf);
+ const findWarningAlertSummary = () => findWarningAlert().findComponent(GlSprintf);
const findWarnings = () => wrapper.findAll('[data-testid="run-pipeline-warning"]');
- const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findCCAlert = () => wrapper.findComponent(CreditCardValidationRequiredAlert);
const getFormPostParams = () => JSON.parse(mock.history.post[0].data);
diff --git a/spec/frontend/pipeline_new/components/refs_dropdown_spec.js b/spec/frontend/pipeline_new/components/refs_dropdown_spec.js
index 826f2826d3c..01d4bd7786f 100644
--- a/spec/frontend/pipeline_new/components/refs_dropdown_spec.js
+++ b/spec/frontend/pipeline_new/components/refs_dropdown_spec.js
@@ -19,7 +19,7 @@ describe('Pipeline New Form', () => {
let wrapper;
let mock;
- const findDropdown = () => wrapper.find(GlDropdown);
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
const findRefsDropdownItems = () => wrapper.findAll(GlDropdownItem);
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
diff --git a/spec/frontend/pipeline_wizard/components/input_wrapper_spec.js b/spec/frontend/pipeline_wizard/components/input_wrapper_spec.js
index ea2448b1362..f288264a11e 100644
--- a/spec/frontend/pipeline_wizard/components/input_wrapper_spec.js
+++ b/spec/frontend/pipeline_wizard/components/input_wrapper_spec.js
@@ -30,7 +30,7 @@ describe('Pipeline Wizard -- Input Wrapper', () => {
beforeEach(() => {
createComponent({});
- inputChild = wrapper.find(TextWidget);
+ inputChild = wrapper.findComponent(TextWidget);
});
afterEach(() => {
diff --git a/spec/frontend/pipelines/components/dag/dag_annotations_spec.js b/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
index 212f8e19a6d..28a08b6da0f 100644
--- a/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
@@ -11,7 +11,7 @@ describe('The DAG annotations', () => {
const getAllColorBlocks = () => wrapper.findAll('[data-testid="dag-color-block"]');
const getTextBlock = () => wrapper.find('[data-testid="dag-note-text"]');
const getAllTextBlocks = () => wrapper.findAll('[data-testid="dag-note-text"]');
- const getToggleButton = () => wrapper.find(GlButton);
+ const getToggleButton = () => wrapper.findComponent(GlButton);
const createComponent = (propsData = {}, method = shallowMount) => {
if (wrapper?.destroy) {
diff --git a/spec/frontend/pipelines/components/dag/dag_spec.js b/spec/frontend/pipelines/components/dag/dag_spec.js
index d78df3eb35e..5cc6537e964 100644
--- a/spec/frontend/pipelines/components/dag/dag_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_spec.js
@@ -18,12 +18,12 @@ import {
describe('Pipeline DAG graph wrapper', () => {
let wrapper;
- const getAlert = () => wrapper.find(GlAlert);
+ const getAlert = () => wrapper.findComponent(GlAlert);
const getAllAlerts = () => wrapper.findAll(GlAlert);
- const getGraph = () => wrapper.find(DagGraph);
- const getNotes = () => wrapper.find(DagAnnotations);
+ const getGraph = () => wrapper.findComponent(DagGraph);
+ const getNotes = () => wrapper.findComponent(DagAnnotations);
const getErrorText = (type) => wrapper.vm.$options.errorTexts[type];
- const getEmptyState = () => wrapper.find(GlEmptyState);
+ const getEmptyState = () => wrapper.findComponent(GlEmptyState);
const createComponent = ({
graphData = mockParsedGraphQLNodes,
diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
index 3b6ebedd724..ee3eaaf5ef3 100644
--- a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
+++ b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
@@ -14,7 +14,7 @@ describe('Pipelines filtered search', () => {
let wrapper;
let mock;
- const findFilteredSearch = () => wrapper.find(GlFilteredSearch);
+ const findFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
const getSearchToken = (type) =>
findFilteredSearch()
.props('availableTokens')
@@ -191,7 +191,7 @@ describe('Pipelines filtered search', () => {
findFilteredSearch().vm.$emit('submit', mockSearch);
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_filtered_search', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.search,
});
});
});
diff --git a/spec/frontend/pipelines/graph/action_component_spec.js b/spec/frontend/pipelines/graph/action_component_spec.js
index 6e5aa572ec0..a823e029281 100644
--- a/spec/frontend/pipelines/graph/action_component_spec.js
+++ b/spec/frontend/pipelines/graph/action_component_spec.js
@@ -9,7 +9,7 @@ import ActionComponent from '~/pipelines/components/jobs_shared/action_component
describe('pipeline graph action component', () => {
let wrapper;
let mock;
- const findButton = () => wrapper.find(GlButton);
+ const findButton = () => wrapper.findComponent(GlButton);
const findTooltipWrapper = () => wrapper.find('[data-testid="ci-action-icon-tooltip-wrapper"]');
beforeEach(() => {
diff --git a/spec/frontend/pipelines/graph/graph_component_spec.js b/spec/frontend/pipelines/graph/graph_component_spec.js
index 4b2b61c8edd..3ab58882786 100644
--- a/spec/frontend/pipelines/graph/graph_component_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_spec.js
@@ -16,7 +16,7 @@ describe('graph component', () => {
let wrapper;
const findLinkedColumns = () => wrapper.findAll(LinkedPipelinesColumn);
- const findLinksLayer = () => wrapper.find(LinksLayer);
+ const findLinksLayer = () => wrapper.findComponent(LinksLayer);
const findStageColumns = () => wrapper.findAll(StageColumnComponent);
const findStageNameInJob = () => wrapper.find('[data-testid="stage-name-in-job"]');
@@ -107,7 +107,7 @@ describe('graph component', () => {
});
it('dims unrelated jobs', () => {
- const unrelatedJob = wrapper.find(JobItem);
+ const unrelatedJob = wrapper.findComponent(JobItem);
expect(findLinksLayer().emitted().highlightedJobsChange).toHaveLength(1);
expect(unrelatedJob.classes('gl-opacity-3')).toBe(true);
});
diff --git a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
index 454b3814d8c..a2097dda860 100644
--- a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
@@ -51,11 +51,11 @@ describe('Pipeline graph wrapper', () => {
const getDependenciesToggle = () => wrapper.find('[data-testid="show-links-toggle"]');
const getLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const getLinksLayer = () => wrapper.findComponent(LinksLayer);
- const getGraph = () => wrapper.find(PipelineGraph);
+ const getGraph = () => wrapper.findComponent(PipelineGraph);
const getStageColumnTitle = () => wrapper.find('[data-testid="stage-column-title"]');
const getAllStageColumnGroupsInColumn = () =>
- wrapper.find(StageColumnComponent).findAll('[data-testid="stage-column-group"]');
- const getViewSelector = () => wrapper.find(GraphViewSelector);
+ wrapper.findComponent(StageColumnComponent).findAll('[data-testid="stage-column-group"]');
+ const getViewSelector = () => wrapper.findComponent(GraphViewSelector);
const getViewSelectorTrip = () => getViewSelector().findComponent(GlAlert);
const getLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
@@ -408,7 +408,7 @@ describe('Pipeline graph wrapper', () => {
it('reads the view type from localStorage when available', () => {
const viewSelectorNeedsSegment = wrapper
- .find(GlButtonGroup)
+ .findComponent(GlButtonGroup)
.findAllComponents(GlButton)
.at(1);
expect(viewSelectorNeedsSegment.classes()).toContain('selected');
diff --git a/spec/frontend/pipelines/graph/graph_view_selector_spec.js b/spec/frontend/pipelines/graph/graph_view_selector_spec.js
index 4e79c7e73cc..43587bebedf 100644
--- a/spec/frontend/pipelines/graph/graph_view_selector_spec.js
+++ b/spec/frontend/pipelines/graph/graph_view_selector_spec.js
@@ -11,7 +11,7 @@ describe('the graph view selector component', () => {
const findStageViewButton = () => findViewTypeSelector().findAllComponents(GlButton).at(0);
const findLayerViewButton = () => findViewTypeSelector().findAllComponents(GlButton).at(1);
const findSwitcherLoader = () => wrapper.find('[data-testid="switcher-loading-state"]');
- const findToggleLoader = () => findDependenciesToggle().find(GlLoadingIcon);
+ const findToggleLoader = () => findDependenciesToggle().findComponent(GlLoadingIcon);
const findHoverTip = () => wrapper.findComponent(GlAlert);
const defaultProps = {
diff --git a/spec/frontend/pipelines/graph/job_name_component_spec.js b/spec/frontend/pipelines/graph/job_name_component_spec.js
index d3008c046e8..ec432e98fdf 100644
--- a/spec/frontend/pipelines/graph/job_name_component_spec.js
+++ b/spec/frontend/pipelines/graph/job_name_component_spec.js
@@ -24,7 +24,7 @@ describe('job name component', () => {
});
it('should render an icon with the provided status', () => {
- expect(wrapper.find(ciIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(ciIcon).exists()).toBe(true);
expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
});
});
diff --git a/spec/frontend/pipelines/graph/linked_pipeline_spec.js b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
index 7d1e4774a24..b9244ca0547 100644
--- a/spec/frontend/pipelines/graph/linked_pipeline_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
@@ -36,13 +36,13 @@ describe('Linked pipeline', () => {
type: UPSTREAM,
};
- const findButton = () => wrapper.find(GlButton);
+ const findButton = () => wrapper.findComponent(GlButton);
const findCancelButton = () => wrapper.findByLabelText('Cancel downstream pipeline');
const findCardTooltip = () => wrapper.findComponent(GlTooltip);
const findDownstreamPipelineTitle = () => wrapper.findByTestId('downstream-title');
const findExpandButton = () => wrapper.findByTestId('expand-pipeline-button');
- const findLinkedPipeline = () => wrapper.find({ ref: 'linkedPipeline' });
- const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findLinkedPipeline = () => wrapper.findComponent({ ref: 'linkedPipeline' });
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findPipelineLabel = () => wrapper.findByTestId('downstream-pipeline-label');
const findPipelineLink = () => wrapper.findByTestId('pipelineLink');
const findRetryButton = () => wrapper.findByLabelText('Retry downstream pipeline');
@@ -80,7 +80,7 @@ describe('Linked pipeline', () => {
});
it('should render an svg within the status container', () => {
- const pipelineStatusElement = wrapper.find(CiStatus);
+ const pipelineStatusElement = wrapper.findComponent(CiStatus);
expect(pipelineStatusElement.find('svg').exists()).toBe(true);
});
@@ -90,7 +90,7 @@ describe('Linked pipeline', () => {
});
it('should have a ci-status child component', () => {
- expect(wrapper.find(CiStatus).exists()).toBe(true);
+ expect(wrapper.findComponent(CiStatus).exists()).toBe(true);
});
it('should render the pipeline id', () => {
diff --git a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
index 46000711110..50fae3ee495 100644
--- a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
@@ -39,7 +39,7 @@ describe('Linked Pipelines Column', () => {
let wrapper;
const findLinkedColumnTitle = () => wrapper.find('[data-testid="linked-column-title"]');
const findLinkedPipelineElements = () => wrapper.findAll(LinkedPipeline);
- const findPipelineGraph = () => wrapper.find(PipelineGraph);
+ const findPipelineGraph = () => wrapper.findComponent(PipelineGraph);
const findExpandButton = () => wrapper.find('[data-testid="expand-pipeline-button"]');
Vue.use(VueApollo);
diff --git a/spec/frontend/pipelines/graph/stage_column_component_spec.js b/spec/frontend/pipelines/graph/stage_column_component_spec.js
index b081258edc0..19f597a7267 100644
--- a/spec/frontend/pipelines/graph/stage_column_component_spec.js
+++ b/spec/frontend/pipelines/graph/stage_column_component_spec.js
@@ -42,8 +42,8 @@ describe('stage column component', () => {
const findStageColumnTitle = () => wrapper.find('[data-testid="stage-column-title"]');
const findStageColumnGroup = () => wrapper.find('[data-testid="stage-column-group"]');
const findAllStageColumnGroups = () => wrapper.findAll('[data-testid="stage-column-group"]');
- const findJobItem = () => wrapper.find(JobItem);
- const findActionComponent = () => wrapper.find(ActionComponent);
+ const findJobItem = () => wrapper.findComponent(JobItem);
+ const findActionComponent = () => wrapper.findComponent(ActionComponent);
const createComponent = ({ method = shallowMount, props = {} } = {}) => {
wrapper = method(StageColumnComponent, {
diff --git a/spec/frontend/pipelines/graph_shared/links_layer_spec.js b/spec/frontend/pipelines/graph_shared/links_layer_spec.js
index 44ab60cbee7..e2699d6ff2e 100644
--- a/spec/frontend/pipelines/graph_shared/links_layer_spec.js
+++ b/spec/frontend/pipelines/graph_shared/links_layer_spec.js
@@ -6,7 +6,7 @@ import { generateResponse, mockPipelineResponse } from '../graph/mock_data';
describe('links layer component', () => {
let wrapper;
- const findLinksInner = () => wrapper.find(LinksInner);
+ const findLinksInner = () => wrapper.findComponent(LinksInner);
const pipeline = generateResponse(mockPipelineResponse, 'root/fungi-xoxo');
const containerId = `pipeline-links-container-${pipeline.id}`;
diff --git a/spec/frontend/pipelines/header_component_spec.js b/spec/frontend/pipelines/header_component_spec.js
index 859be8d342c..e583c0798f5 100644
--- a/spec/frontend/pipelines/header_component_spec.js
+++ b/spec/frontend/pipelines/header_component_spec.js
@@ -21,12 +21,12 @@ describe('Pipeline details header', () => {
let glModalDirective;
let mutate = jest.fn();
- const findAlert = () => wrapper.find(GlAlert);
- const findDeleteModal = () => wrapper.find(GlModal);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findDeleteModal = () => wrapper.findComponent(GlModal);
const findRetryButton = () => wrapper.find('[data-testid="retryPipeline"]');
const findCancelButton = () => wrapper.find('[data-testid="cancelPipeline"]');
const findDeleteButton = () => wrapper.find('[data-testid="deletePipeline"]');
- const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const defaultProvideOptions = {
pipelineId: '14',
diff --git a/spec/frontend/pipelines/pipeline_multi_actions_spec.js b/spec/frontend/pipelines/pipeline_multi_actions_spec.js
index 8b800cf34f3..149b40330e2 100644
--- a/spec/frontend/pipelines/pipeline_multi_actions_spec.js
+++ b/spec/frontend/pipelines/pipeline_multi_actions_spec.js
@@ -152,7 +152,7 @@ describe('Pipeline Multi Actions Dropdown', () => {
findDropdown().vm.$emit('show');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_artifacts_dropdown', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
});
diff --git a/spec/frontend/pipelines/pipeline_url_spec.js b/spec/frontend/pipelines/pipeline_url_spec.js
index bba4ed6e5e4..1d66607e72b 100644
--- a/spec/frontend/pipelines/pipeline_url_spec.js
+++ b/spec/frontend/pipelines/pipeline_url_spec.js
@@ -117,7 +117,7 @@ describe('Pipeline Url Component', () => {
findPipelineUrlLink().vm.$emit('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_pipeline_id', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
@@ -127,7 +127,7 @@ describe('Pipeline Url Component', () => {
findRefName().vm.$emit('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_mr_ref', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
@@ -137,7 +137,7 @@ describe('Pipeline Url Component', () => {
findCommitRefName().vm.$emit('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_commit_name', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
@@ -147,7 +147,7 @@ describe('Pipeline Url Component', () => {
findCommitTitle(findCommitTitleContainer()).vm.$emit('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_commit_title', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
@@ -157,7 +157,7 @@ describe('Pipeline Url Component', () => {
findCommitShortSha().vm.$emit('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_commit_sha', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
});
diff --git a/spec/frontend/pipelines/pipelines_actions_spec.js b/spec/frontend/pipelines/pipelines_actions_spec.js
index 9a2126be1c5..ac4be04fc41 100644
--- a/spec/frontend/pipelines/pipelines_actions_spec.js
+++ b/spec/frontend/pipelines/pipelines_actions_spec.js
@@ -31,7 +31,7 @@ describe('Pipelines Actions dropdown', () => {
});
};
- const findDropdown = () => wrapper.find(GlDropdown);
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
const findAllDropdownItems = () => wrapper.findAll(GlDropdownItem);
const findAllCountdowns = () => wrapper.findAll(GlCountdown);
@@ -110,7 +110,7 @@ describe('Pipelines Actions dropdown', () => {
findDropdown().vm.$emit('shown');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_manual_actions', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
});
diff --git a/spec/frontend/pipelines/pipelines_artifacts_spec.js b/spec/frontend/pipelines/pipelines_artifacts_spec.js
index 2d876841e06..481d98fcba7 100644
--- a/spec/frontend/pipelines/pipelines_artifacts_spec.js
+++ b/spec/frontend/pipelines/pipelines_artifacts_spec.js
@@ -30,8 +30,8 @@ describe('Pipelines Artifacts dropdown', () => {
};
const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findFirstGlDropdownItem = () => wrapper.find(GlDropdownItem);
- const findAllGlDropdownItems = () => wrapper.find(GlDropdown).findAll(GlDropdownItem);
+ const findFirstGlDropdownItem = () => wrapper.findComponent(GlDropdownItem);
+ const findAllGlDropdownItems = () => wrapper.findComponent(GlDropdown).findAll(GlDropdownItem);
afterEach(() => {
wrapper.destroy();
diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js
index 0bed24e588e..cc2ff90de57 100644
--- a/spec/frontend/pipelines/pipelines_spec.js
+++ b/spec/frontend/pipelines/pipelines_spec.js
@@ -7,6 +7,7 @@ import { nextTick } from 'vue';
import mockPipelinesResponse from 'test_fixtures/pipelines/pipelines.json';
import setWindowLocation from 'helpers/set_window_location_helper';
import { TEST_HOST } from 'helpers/test_constants';
+import { mockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import Api from '~/api';
@@ -16,7 +17,7 @@ import NavigationControls from '~/pipelines/components/pipelines_list/nav_contro
import PipelinesComponent from '~/pipelines/components/pipelines_list/pipelines.vue';
import PipelinesCiTemplates from '~/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue';
import PipelinesTableComponent from '~/pipelines/components/pipelines_list/pipelines_table.vue';
-import { RAW_TEXT_WARNING } from '~/pipelines/constants';
+import { RAW_TEXT_WARNING, TRACKING_CATEGORIES } from '~/pipelines/constants';
import Store from '~/pipelines/stores/pipelines_store';
import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
@@ -37,6 +38,7 @@ const mockPipelineWithStages = mockPipelinesResponse.pipelines.find(
describe('Pipelines', () => {
let wrapper;
let mock;
+ let trackingSpy;
const paths = {
emptyStateSvgPath: '/assets/illustrations/pipelines_empty.svg',
@@ -123,7 +125,7 @@ describe('Pipelines', () => {
});
it('shows loading state when the app is loading', () => {
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
it('does not display tabs when the first request has not yet been made', () => {
@@ -236,6 +238,8 @@ describe('Pipelines', () => {
count: mockPipelinesResponse.count,
});
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+
goToTab('finished');
await waitForPromises();
@@ -256,6 +260,12 @@ describe('Pipelines', () => {
`${window.location.pathname}?scope=finished&page=1`,
);
});
+
+ it('tracks tab change click', () => {
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_filter_tabs', {
+ label: TRACKING_CATEGORIES.tabs,
+ });
+ });
});
describe('when the scope in the tab is empty', () => {
@@ -375,7 +385,7 @@ describe('Pipelines', () => {
const [firstPage, secondPage] = chunk(mockPipelinesResponse.pipelines, mockPageSize);
const goToPage = (page) => {
- findTablePagination().find(GlPagination).vm.$emit('input', page);
+ findTablePagination().findComponent(GlPagination).vm.$emit('input', page);
};
beforeEach(async () => {
@@ -583,7 +593,7 @@ describe('Pipelines', () => {
'This project is not currently set up to run pipelines.',
);
- expect(findEmptyState().find(GlButton).exists()).toBe(false);
+ expect(findEmptyState().findComponent(GlButton).exists()).toBe(false);
});
it('does not render tabs or buttons', () => {
diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js
index 53496c75123..12ee06d81a3 100644
--- a/spec/frontend/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_spec.js
@@ -181,7 +181,7 @@ describe('Pipelines Table', () => {
findStatusBadge().vm.$emit('ciStatusBadgeClick');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_ci_status_badge', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
@@ -189,7 +189,7 @@ describe('Pipelines Table', () => {
findRetryBtn().vm.$emit('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_retry_button', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
@@ -197,7 +197,7 @@ describe('Pipelines Table', () => {
findCancelBtn().vm.$emit('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_cancel_button', {
- label: TRACKING_CATEGORIES.index,
+ label: TRACKING_CATEGORIES.table,
});
});
});
diff --git a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
index c372ac06c35..da13df833e7 100644
--- a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
@@ -26,10 +26,10 @@ describe('Test reports suite table', () => {
const noCasesMessage = () => wrapper.findByTestId('no-test-cases');
const artifactsExpiredMessage = () => wrapper.findByTestId('artifacts-expired');
- const artifactsExpiredEmptyState = () => wrapper.find(GlEmptyState);
+ const artifactsExpiredEmptyState = () => wrapper.findComponent(GlEmptyState);
const allCaseRows = () => wrapper.findAllByTestId('test-case-row');
const findCaseRowAtIndex = (index) => wrapper.findAllByTestId('test-case-row').at(index);
- const findLinkForRow = (row) => row.find(GlLink);
+ const findLinkForRow = (row) => row.findComponent(GlLink);
const findIconForRow = (row, status) => row.find(`.ci-status-icon-${status}`);
const createComponent = ({ suite = testSuite, perPage = 20, errorMessage } = {}) => {
@@ -113,7 +113,7 @@ describe('Test reports suite table', () => {
const filePath = `${blobPath}/${relativeFile}`;
const row = findCaseRowAtIndex(0);
const fileLink = findLinkForRow(row);
- const button = row.find(GlButton);
+ const button = row.findComponent(GlButton);
expect(fileLink.attributes('href')).toBe(filePath);
expect(row.text()).toContain(file);
@@ -134,7 +134,7 @@ describe('Test reports suite table', () => {
});
it('renders a pagination component', () => {
- expect(wrapper.find(GlPagination).exists()).toBe(true);
+ expect(wrapper.findComponent(GlPagination).exists()).toBe(true);
});
});
diff --git a/spec/frontend/pipelines/test_reports/test_summary_table_spec.js b/spec/frontend/pipelines/test_reports/test_summary_table_spec.js
index 0e1229f7067..cfe9ff564dc 100644
--- a/spec/frontend/pipelines/test_reports/test_summary_table_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_summary_table_spec.js
@@ -44,7 +44,7 @@ describe('Test reports summary table', () => {
describe('when test reports are supplied', () => {
beforeEach(() => createComponent());
- const findErrorIcon = () => wrapper.find({ ref: 'suiteErrorIcon' });
+ const findErrorIcon = () => wrapper.findComponent({ ref: 'suiteErrorIcon' });
it('renders the correct number of rows', () => {
expect(noSuitesToShow().exists()).toBe(false);
diff --git a/spec/frontend/pipelines/time_ago_spec.js b/spec/frontend/pipelines/time_ago_spec.js
index 3de7995b476..f0da0df2ba6 100644
--- a/spec/frontend/pipelines/time_ago_spec.js
+++ b/spec/frontend/pipelines/time_ago_spec.js
@@ -48,7 +48,7 @@ describe('Timeago component', () => {
});
it('should render duration and timer svg', () => {
- const icon = duration().find(GlIcon);
+ const icon = duration().findComponent(GlIcon);
expect(duration().exists()).toBe(true);
expect(icon.props('name')).toBe('timer');
@@ -71,7 +71,7 @@ describe('Timeago component', () => {
});
it('should render time and calendar icon', () => {
- const icon = finishedAt().find(GlIcon);
+ const icon = finishedAt().findComponent(GlIcon);
const time = finishedAt().find('time');
expect(finishedAt().exists()).toBe(true);
diff --git a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
index ba478363d04..497d03bff51 100644
--- a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
@@ -9,9 +9,9 @@ import { branches, mockBranchesAfterMap } from '../mock_data';
describe('Pipeline Branch Name Token', () => {
let wrapper;
- const findFilteredSearchToken = () => wrapper.find(GlFilteredSearchToken);
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
const findAllFilteredSearchSuggestions = () => wrapper.findAll(GlFilteredSearchSuggestion);
- const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const getBranchSuggestions = () =>
findAllFilteredSearchSuggestions().wrappers.map((w) => w.text());
diff --git a/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js
index b8abf2c1727..7d60a961621 100644
--- a/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js
@@ -7,7 +7,7 @@ import PipelineSourceToken from '~/pipelines/components/pipelines_list/tokens/pi
describe('Pipeline Source Token', () => {
let wrapper;
- const findFilteredSearchToken = () => wrapper.find(GlFilteredSearchToken);
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
const findAllFilteredSearchSuggestions = () => wrapper.findAll(GlFilteredSearchSuggestion);
const defaultProps = {
diff --git a/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js
index 2c5fa8b00e2..1a51d8b251d 100644
--- a/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js
@@ -6,7 +6,7 @@ import PipelineStatusToken from '~/pipelines/components/pipelines_list/tokens/pi
describe('Pipeline Status Token', () => {
let wrapper;
- const findFilteredSearchToken = () => wrapper.find(GlFilteredSearchToken);
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
const findAllFilteredSearchSuggestions = () => wrapper.findAll(GlFilteredSearchSuggestion);
const findAllGlIcons = () => wrapper.findAll(GlIcon);
diff --git a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
index 596a9218c39..8dd79bcfb88 100644
--- a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
@@ -7,9 +7,9 @@ import { tags, mockTagsAfterMap } from '../mock_data';
describe('Pipeline Branch Name Token', () => {
let wrapper;
- const findFilteredSearchToken = () => wrapper.find(GlFilteredSearchToken);
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
const findAllFilteredSearchSuggestions = () => wrapper.findAll(GlFilteredSearchSuggestion);
- const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const stubs = {
GlFilteredSearchToken: {
diff --git a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
index 397dbdf95a9..39986ca7904 100644
--- a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
@@ -8,9 +8,9 @@ import { users } from '../mock_data';
describe('Pipeline Trigger Author Token', () => {
let wrapper;
- const findFilteredSearchToken = () => wrapper.find(GlFilteredSearchToken);
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
const findAllFilteredSearchSuggestions = () => wrapper.findAll(GlFilteredSearchSuggestion);
- const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const defaultProps = {
config: {
diff --git a/spec/frontend/popovers/components/popovers_spec.js b/spec/frontend/popovers/components/popovers_spec.js
index 6fdcd34ae83..0d00cb043d5 100644
--- a/spec/frontend/popovers/components/popovers_spec.js
+++ b/spec/frontend/popovers/components/popovers_spec.js
@@ -42,7 +42,7 @@ describe('popovers/components/popovers.vue', () => {
it('attaches popovers to the targets specified', async () => {
const target = createPopoverTarget();
await buildWrapper(target);
- expect(wrapper.find(GlPopover).props('target')).toBe(target);
+ expect(wrapper.findComponent(GlPopover).props('target')).toBe(target);
});
it('does not attach a popover twice to the same element', async () => {
@@ -66,7 +66,7 @@ describe('popovers/components/popovers.vue', () => {
`('$description', async ({ content, render }) => {
await buildWrapper(createPopoverTarget({ content, html: true }));
- const html = wrapper.find(GlPopover).html();
+ const html = wrapper.findComponent(GlPopover).html();
expect(html).toContain(render);
});
});
@@ -78,7 +78,7 @@ describe('popovers/components/popovers.vue', () => {
`('sets $option to $value when data-$option is set in target', async ({ option, value }) => {
await buildWrapper(createPopoverTarget({ [option]: value }));
- expect(wrapper.find(GlPopover).props(option)).toBe(value);
+ expect(wrapper.findComponent(GlPopover).props(option)).toBe(value);
});
});
diff --git a/spec/frontend/profile/account/components/delete_account_modal_spec.js b/spec/frontend/profile/account/components/delete_account_modal_spec.js
index ad62d84c43c..e4a316e1ee7 100644
--- a/spec/frontend/profile/account/components/delete_account_modal_spec.js
+++ b/spec/frontend/profile/account/components/delete_account_modal_spec.js
@@ -53,7 +53,7 @@ describe('DeleteAccountModal component', () => {
input: vm.$el.querySelector(`[name="${confirmation}"]`),
};
};
- const findModal = () => wrapper.find(GlModalStub);
+ const findModal = () => wrapper.findComponent(GlModalStub);
describe('with password confirmation', () => {
beforeEach(async () => {
diff --git a/spec/frontend/profile/account/components/update_username_spec.js b/spec/frontend/profile/account/components/update_username_spec.js
index 0e56bccf27e..cdeeea12582 100644
--- a/spec/frontend/profile/account/components/update_username_spec.js
+++ b/spec/frontend/profile/account/components/update_username_spec.js
@@ -44,7 +44,7 @@ describe('UpdateUsername component', () => {
});
const findElements = () => {
- const modal = wrapper.find(GlModal);
+ const modal = wrapper.findComponent(GlModal);
return {
modal,
diff --git a/spec/frontend/profile/preferences/components/integration_view_spec.js b/spec/frontend/profile/preferences/components/integration_view_spec.js
index 92c53b8c91b..f650bee7fda 100644
--- a/spec/frontend/profile/preferences/components/integration_view_spec.js
+++ b/spec/frontend/profile/preferences/components/integration_view_spec.js
@@ -98,6 +98,6 @@ describe('IntegrationView component', () => {
it('should render the help text', () => {
wrapper = createComponent();
- expect(wrapper.find(IntegrationHelpText).exists()).toBe(true);
+ expect(wrapper.findComponent(IntegrationHelpText).exists()).toBe(true);
});
});
diff --git a/spec/frontend/projects/commit/components/form_modal_spec.js b/spec/frontend/projects/commit/components/form_modal_spec.js
index 79e9dab935d..20c312ec771 100644
--- a/spec/frontend/projects/commit/components/form_modal_spec.js
+++ b/spec/frontend/projects/commit/components/form_modal_spec.js
@@ -99,7 +99,9 @@ describe('CommitFormModal', () => {
createComponent(shallowMount, {}, { prependedText: '_prepended_text_' });
expect(findPrependedText().exists()).toBe(true);
- expect(findPrependedText().find(GlSprintf).attributes('message')).toBe('_prepended_text_');
+ expect(findPrependedText().findComponent(GlSprintf).attributes('message')).toBe(
+ '_prepended_text_',
+ );
});
it('Does not show prepended text', () => {
@@ -124,7 +126,7 @@ describe('CommitFormModal', () => {
createComponent(shallowMount, { pushCode: false });
expect(findAppendedText().exists()).toBe(true);
- expect(findAppendedText().find(GlSprintf).attributes('message')).toContain(
+ expect(findAppendedText().findComponent(GlSprintf).attributes('message')).toContain(
mockData.modalPropsData.i18n.branchInFork,
);
});
@@ -133,7 +135,7 @@ describe('CommitFormModal', () => {
createComponent(shallowMount, { pushCode: false, branchCollaboration: true });
expect(findAppendedText().exists()).toBe(true);
- expect(findAppendedText().find(GlSprintf).attributes('message')).toContain(
+ expect(findAppendedText().findComponent(GlSprintf).attributes('message')).toContain(
mockData.modalPropsData.i18n.existingBranch,
);
});
diff --git a/spec/frontend/projects/commits/components/author_select_spec.js b/spec/frontend/projects/commits/components/author_select_spec.js
index 57e5ef0ed1d..287bfe1c14d 100644
--- a/spec/frontend/projects/commits/components/author_select_spec.js
+++ b/spec/frontend/projects/commits/components/author_select_spec.js
@@ -58,10 +58,10 @@ describe('Author Select', () => {
resetHTMLFixture();
});
- const findDropdownContainer = () => wrapper.find({ ref: 'dropdownContainer' });
- const findDropdown = () => wrapper.find(GlDropdown);
- const findDropdownHeader = () => wrapper.find(GlDropdownSectionHeader);
- const findSearchBox = () => wrapper.find(GlSearchBoxByType);
+ const findDropdownContainer = () => wrapper.findComponent({ ref: 'dropdownContainer' });
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownHeader = () => wrapper.findComponent(GlDropdownSectionHeader);
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
const findDropdownItems = () => wrapper.findAll(GlDropdownItem);
describe('user is searching via "filter by commit message"', () => {
diff --git a/spec/frontend/projects/compare/components/app_spec.js b/spec/frontend/projects/compare/components/app_spec.js
index c9ffdf20c32..a24e40b842c 100644
--- a/spec/frontend/projects/compare/components/app_spec.js
+++ b/spec/frontend/projects/compare/components/app_spec.js
@@ -66,7 +66,7 @@ describe('CompareApp component', () => {
});
describe('compare button', () => {
- const findCompareButton = () => wrapper.find(GlButton);
+ const findCompareButton = () => wrapper.findComponent(GlButton);
it('renders button', () => {
expect(findCompareButton().exists()).toBe(true);
diff --git a/spec/frontend/projects/compare/components/repo_dropdown_spec.js b/spec/frontend/projects/compare/components/repo_dropdown_spec.js
index 98aec347e4b..8e720b40e6f 100644
--- a/spec/frontend/projects/compare/components/repo_dropdown_spec.js
+++ b/spec/frontend/projects/compare/components/repo_dropdown_spec.js
@@ -21,7 +21,7 @@ describe('RepoDropdown component', () => {
wrapper = null;
});
- const findGlDropdown = () => wrapper.find(GlDropdown);
+ const findGlDropdown = () => wrapper.findComponent(GlDropdown);
const findHiddenInput = () => wrapper.find('input[type="hidden"]');
describe('Source Revision', () => {
diff --git a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
index 102f95f65da..8d4711a79ed 100644
--- a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
+++ b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
@@ -38,7 +38,7 @@ describe('RevisionDropdown component', () => {
axiosMock.restore();
});
- const findGlDropdown = () => wrapper.find(GlDropdown);
+ const findGlDropdown = () => wrapper.findComponent(GlDropdown);
it('sets hidden input', () => {
expect(wrapper.find('input[type="hidden"]').attributes('value')).toBe(
diff --git a/spec/frontend/projects/compare/components/revision_dropdown_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_spec.js
index c8a90848492..bd8c0d2784f 100644
--- a/spec/frontend/projects/compare/components/revision_dropdown_spec.js
+++ b/spec/frontend/projects/compare/components/revision_dropdown_spec.js
@@ -35,8 +35,8 @@ describe('RevisionDropdown component', () => {
axiosMock.restore();
});
- const findGlDropdown = () => wrapper.find(GlDropdown);
- const findSearchBox = () => wrapper.find(GlSearchBoxByType);
+ const findGlDropdown = () => wrapper.findComponent(GlDropdown);
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
it('sets hidden input', () => {
createComponent();
diff --git a/spec/frontend/projects/components/project_delete_button_spec.js b/spec/frontend/projects/components/project_delete_button_spec.js
index a3bc4931eb3..49e3218e5bc 100644
--- a/spec/frontend/projects/components/project_delete_button_spec.js
+++ b/spec/frontend/projects/components/project_delete_button_spec.js
@@ -8,7 +8,7 @@ jest.mock('lodash/uniqueId', () => () => 'fakeUniqueId');
describe('Project remove modal', () => {
let wrapper;
- const findSharedDeleteButton = () => wrapper.find(SharedDeleteButton);
+ const findSharedDeleteButton = () => wrapper.findComponent(SharedDeleteButton);
const defaultProps = {
confirmPhrase: 'foo',
diff --git a/spec/frontend/projects/components/shared/delete_button_spec.js b/spec/frontend/projects/components/shared/delete_button_spec.js
index 45c39ee91d8..097b18025a3 100644
--- a/spec/frontend/projects/components/shared/delete_button_spec.js
+++ b/spec/frontend/projects/components/shared/delete_button_spec.js
@@ -11,7 +11,7 @@ describe('Project remove modal', () => {
const findFormElement = () => wrapper.find('form');
const findConfirmButton = () => wrapper.find('.js-modal-action-primary');
const findAuthenticityTokenInput = () => findFormElement().find('input[name=authenticity_token]');
- const findModal = () => wrapper.find(GlModal);
+ const findModal = () => wrapper.findComponent(GlModal);
const findTitle = () => wrapper.find('[data-testid="delete-alert-title"]');
const findAlertBody = () => wrapper.find('[data-testid="delete-alert-body"]');
diff --git a/spec/frontend/projects/details/upload_button_spec.js b/spec/frontend/projects/details/upload_button_spec.js
index d7308963088..50638755260 100644
--- a/spec/frontend/projects/details/upload_button_spec.js
+++ b/spec/frontend/projects/details/upload_button_spec.js
@@ -32,11 +32,11 @@ describe('UploadButton', () => {
});
it('displays an upload button', () => {
- expect(wrapper.find(GlButton).exists()).toBe(true);
+ expect(wrapper.findComponent(GlButton).exists()).toBe(true);
});
it('contains a modal', () => {
- const modal = wrapper.find(UploadBlobModal);
+ const modal = wrapper.findComponent(UploadBlobModal);
expect(modal.exists()).toBe(true);
expect(modal.props('modalId')).toBe(MODAL_ID);
@@ -44,7 +44,7 @@ describe('UploadButton', () => {
describe('when clickinig the upload file button', () => {
beforeEach(() => {
- wrapper.find(GlButton).vm.$emit('click');
+ wrapper.findComponent(GlButton).vm.$emit('click');
});
it('opens the modal', () => {
diff --git a/spec/frontend/projects/pipelines/charts/components/app_spec.js b/spec/frontend/projects/pipelines/charts/components/app_spec.js
index 7b9011fa3d9..db9d7eb9a8a 100644
--- a/spec/frontend/projects/pipelines/charts/components/app_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/app_spec.js
@@ -47,15 +47,16 @@ describe('ProjectsPipelinesChartsApp', () => {
wrapper.destroy();
});
- const findGlTabs = () => wrapper.find(GlTabs);
+ const findGlTabs = () => wrapper.findComponent(GlTabs);
const findAllGlTabs = () => wrapper.findAll(GlTab);
const findGlTabAtIndex = (index) => findAllGlTabs().at(index);
- const findLeadTimeCharts = () => wrapper.find(LeadTimeChartsStub);
- const findTimeToRestoreServiceCharts = () => wrapper.find(TimeToRestoreServiceChartsStub);
- const findChangeFailureRateCharts = () => wrapper.find(ChangeFailureRateChartsStub);
- const findDeploymentFrequencyCharts = () => wrapper.find(DeploymentFrequencyChartsStub);
- const findPipelineCharts = () => wrapper.find(PipelineCharts);
- const findProjectQualitySummary = () => wrapper.find(ProjectQualitySummaryStub);
+ const findLeadTimeCharts = () => wrapper.findComponent(LeadTimeChartsStub);
+ const findTimeToRestoreServiceCharts = () =>
+ wrapper.findComponent(TimeToRestoreServiceChartsStub);
+ const findChangeFailureRateCharts = () => wrapper.findComponent(ChangeFailureRateChartsStub);
+ const findDeploymentFrequencyCharts = () => wrapper.findComponent(DeploymentFrequencyChartsStub);
+ const findPipelineCharts = () => wrapper.findComponent(PipelineCharts);
+ const findProjectQualitySummary = () => wrapper.findComponent(ProjectQualitySummaryStub);
describe('when all charts are available', () => {
beforeEach(() => {
diff --git a/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js b/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js
index 7bb289408b8..8c18d2992ea 100644
--- a/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js
@@ -81,7 +81,7 @@ describe('~/vue_shared/components/ci_cd_analytics/ci_cd_analytics_charts.vue', (
it('should select a different chart on change', async () => {
findSegmentedControl().vm.$emit('input', 1);
- const chart = wrapper.find(CiCdAnalyticsAreaChart);
+ const chart = wrapper.findComponent(CiCdAnalyticsAreaChart);
await nextTick();
@@ -92,7 +92,7 @@ describe('~/vue_shared/components/ci_cd_analytics/ci_cd_analytics_charts.vue', (
it('should not display charts if there are no charts', () => {
wrapper = createWrapper({ charts: [] });
- expect(wrapper.find(CiCdAnalyticsAreaChart).exists()).toBe(false);
+ expect(wrapper.findComponent(CiCdAnalyticsAreaChart).exists()).toBe(false);
});
describe('slots', () => {
diff --git a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js
index 3c91b913e67..2f452f909ff 100644
--- a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js
@@ -44,7 +44,7 @@ describe('~/projects/pipelines/charts/components/pipeline_charts.vue', () => {
describe('overall statistics', () => {
it('displays the statistics list', () => {
- const list = wrapper.find(StatisticsList);
+ const list = wrapper.findComponent(StatisticsList);
expect(list.exists()).toBe(true);
expect(list.props('counts')).toEqual({
@@ -56,7 +56,7 @@ describe('~/projects/pipelines/charts/components/pipeline_charts.vue', () => {
});
it('displays the commit duration chart', () => {
- const chart = wrapper.find(GlColumnChart);
+ const chart = wrapper.findComponent(GlColumnChart);
expect(chart.exists()).toBeTruthy();
expect(chart.props('yAxisTitle')).toBe('Minutes');
@@ -68,12 +68,12 @@ describe('~/projects/pipelines/charts/components/pipeline_charts.vue', () => {
describe('pipelines charts', () => {
it('displays the charts components', () => {
- expect(wrapper.find(CiCdAnalyticsCharts).exists()).toBe(true);
+ expect(wrapper.findComponent(CiCdAnalyticsCharts).exists()).toBe(true);
});
describe('displays individual correctly', () => {
it('renders with the correct data', () => {
- const charts = wrapper.find(CiCdAnalyticsCharts);
+ const charts = wrapper.findComponent(CiCdAnalyticsCharts);
expect(charts.props()).toEqual({
charts: wrapper.vm.areaCharts,
chartOptions: wrapper.vm.$options.areaChartOptions,
diff --git a/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js b/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js
index 0a05832ceb6..329060b9d10 100644
--- a/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js
+++ b/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js
@@ -27,9 +27,9 @@ describe('projects/settings/components/shared_runners', () => {
});
};
- const findErrorAlert = () => wrapper.find(GlAlert);
- const findSharedRunnersToggle = () => wrapper.find(GlToggle);
- const findToggleTooltip = () => wrapper.find(GlTooltip);
+ const findErrorAlert = () => wrapper.findComponent(GlAlert);
+ const findSharedRunnersToggle = () => wrapper.findComponent(GlToggle);
+ const findToggleTooltip = () => wrapper.findComponent(GlTooltip);
const getToggleValue = () => findSharedRunnersToggle().props('value');
const isToggleLoading = () => findSharedRunnersToggle().props('isLoading');
const isToggleDisabled = () => findSharedRunnersToggle().props('disabled');
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
index 763d54be753..13f3eea277a 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
@@ -26,7 +26,7 @@ describe('ServiceDeskRoot', () => {
publicProject: false,
};
- const getAlertText = () => wrapper.find(GlAlert).text();
+ const getAlertText = () => wrapper.findComponent(GlAlert).text();
const createComponent = (customInject = {}) =>
shallowMount(ServiceDeskRoot, {
@@ -51,7 +51,7 @@ describe('ServiceDeskRoot', () => {
it('is rendered', () => {
wrapper = createComponent();
- expect(wrapper.find(ServiceDeskSetting).props()).toEqual({
+ expect(wrapper.findComponent(ServiceDeskSetting).props()).toEqual({
customEmail: provideData.customEmail,
customEmailEnabled: provideData.customEmailEnabled,
incomingEmail: provideData.initialIncomingEmail,
@@ -89,7 +89,7 @@ describe('ServiceDeskRoot', () => {
beforeEach(async () => {
wrapper = createComponent();
- wrapper.find(ServiceDeskSetting).vm.$emit('toggle', true);
+ wrapper.findComponent(ServiceDeskSetting).vm.$emit('toggle', true);
await waitForPromises();
});
@@ -111,7 +111,7 @@ describe('ServiceDeskRoot', () => {
beforeEach(async () => {
wrapper = createComponent();
- wrapper.find(ServiceDeskSetting).vm.$emit('toggle', false);
+ wrapper.findComponent(ServiceDeskSetting).vm.$emit('toggle', false);
await waitForPromises();
});
@@ -143,7 +143,7 @@ describe('ServiceDeskRoot', () => {
projectKey: 'key',
};
- wrapper.find(ServiceDeskSetting).vm.$emit('save', payload);
+ wrapper.findComponent(ServiceDeskSetting).vm.$emit('save', payload);
await waitForPromises();
});
@@ -174,7 +174,7 @@ describe('ServiceDeskRoot', () => {
projectKey: 'key',
};
- wrapper.find(ServiceDeskSetting).vm.$emit('save', payload);
+ wrapper.findComponent(ServiceDeskSetting).vm.$emit('save', payload);
await waitForPromises();
});
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
index aac1a418142..f9f520cb2ab 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
@@ -8,13 +8,13 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
describe('ServiceDeskSetting', () => {
let wrapper;
- const findButton = () => wrapper.find(GlButton);
- const findClipboardButton = () => wrapper.find(ClipboardButton);
+ const findButton = () => wrapper.findComponent(GlButton);
+ const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
const findIncomingEmail = () => wrapper.findByTestId('incoming-email');
const findIncomingEmailLabel = () => wrapper.findByTestId('incoming-email-label');
- const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
- const findTemplateDropdown = () => wrapper.find(GlDropdown);
- const findToggle = () => wrapper.find(GlToggle);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findTemplateDropdown = () => wrapper.findComponent(GlDropdown);
+ const findToggle = () => wrapper.findComponent(GlToggle);
const createComponent = ({ props = {} } = {}) =>
extendedWrapper(
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_template_dropdown_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_template_dropdown_spec.js
index cdb355f5a9b..dde06d40a4d 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_template_dropdown_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_template_dropdown_spec.js
@@ -7,7 +7,7 @@ import { TEMPLATES } from './mock_data';
describe('ServiceDeskTemplateDropdown', () => {
let wrapper;
- const findTemplateDropdown = () => wrapper.find(GlDropdown);
+ const findTemplateDropdown = () => wrapper.findComponent(GlDropdown);
const createComponent = ({ props = {} } = {}) =>
extendedWrapper(
diff --git a/spec/frontend/ref/components/ref_selector_spec.js b/spec/frontend/ref/components/ref_selector_spec.js
index 882cb2c1199..851a3fcaf33 100644
--- a/spec/frontend/ref/components/ref_selector_spec.js
+++ b/spec/frontend/ref/components/ref_selector_spec.js
@@ -93,9 +93,9 @@ describe('Ref selector component', () => {
const findNoResults = () => wrapper.find('[data-testid="no-results"]');
- const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findSearchBox = () => wrapper.find(GlSearchBoxByType);
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
const findBranchesSection = () => wrapper.find('[data-testid="branches-section"]');
const findBranchDropdownItems = () => findBranchesSection().findAll(GlDropdownItem);
@@ -530,13 +530,13 @@ describe('Ref selector component', () => {
});
it('renders a checkmark by the selected item', async () => {
- expect(findFirstBranchDropdownItem().find(GlIcon).element).toHaveClass(
+ expect(findFirstBranchDropdownItem().findComponent(GlIcon).element).toHaveClass(
'gl-visibility-hidden',
);
await selectFirstBranch();
- expect(findFirstBranchDropdownItem().find(GlIcon).element).not.toHaveClass(
+ expect(findFirstBranchDropdownItem().findComponent(GlIcon).element).not.toHaveClass(
'gl-visibility-hidden',
);
});
@@ -684,7 +684,8 @@ describe('Ref selector component', () => {
describe('validation state', () => {
const invalidClass = 'gl-inset-border-1-red-500!';
- const isInvalidClassApplied = () => wrapper.find(GlDropdown).props('toggleClass')[invalidClass];
+ const isInvalidClassApplied = () =>
+ wrapper.findComponent(GlDropdown).props('toggleClass')[invalidClass];
describe('valid state', () => {
describe('when the state prop is not provided', () => {
diff --git a/spec/frontend/related_issues/components/related_issuable_input_spec.js b/spec/frontend/related_issues/components/related_issuable_input_spec.js
index 7d11e3cffb0..f6a13856042 100644
--- a/spec/frontend/related_issues/components/related_issuable_input_spec.js
+++ b/spec/frontend/related_issues/components/related_issuable_input_spec.js
@@ -33,7 +33,7 @@ describe('RelatedIssuableInput', () => {
it('shows placeholder text', () => {
const wrapper = shallowMount(RelatedIssuableInput, { propsData });
- expect(wrapper.find({ ref: 'input' }).element.placeholder).toBe(
+ expect(wrapper.findComponent({ ref: 'input' }).element.placeholder).toBe(
'Paste issue link or <#issue id>',
);
});
@@ -54,7 +54,7 @@ describe('RelatedIssuableInput', () => {
},
});
- expect(wrapper.find({ ref: 'input' }).element.value).toBe('');
+ expect(wrapper.findComponent({ ref: 'input' }).element.value).toBe('');
});
it('does not have GfmAutoComplete', () => {
@@ -85,7 +85,7 @@ describe('RelatedIssuableInput', () => {
await nextTick();
- expect(document.activeElement).toBe(wrapper.find({ ref: 'input' }).element);
+ expect(document.activeElement).toBe(wrapper.findComponent({ ref: 'input' }).element);
});
});
@@ -100,7 +100,7 @@ describe('RelatedIssuableInput', () => {
const newInputValue = 'filling in things';
const untouchedRawReferences = newInputValue.trim().split(/\s/);
const touchedReference = untouchedRawReferences.pop();
- const input = wrapper.find({ ref: 'input' });
+ const input = wrapper.findComponent({ ref: 'input' });
input.element.value = newInputValue;
input.element.selectionStart = newInputValue.length;
diff --git a/spec/frontend/releases/components/app_edit_new_spec.js b/spec/frontend/releases/components/app_edit_new_spec.js
index cb044b9e891..649d8eef6ec 100644
--- a/spec/frontend/releases/components/app_edit_new_spec.js
+++ b/spec/frontend/releases/components/app_edit_new_spec.js
@@ -220,7 +220,7 @@ describe('Release edit/new component', () => {
});
it('renders a checkbox to include release notes', () => {
- expect(wrapper.find(GlFormCheckbox).exists()).toBe(true);
+ expect(wrapper.findComponent(GlFormCheckbox).exists()).toBe(true);
});
});
@@ -238,7 +238,7 @@ describe('Release edit/new component', () => {
beforeEach(factory);
it('renders the asset links portion of the form', () => {
- expect(wrapper.find(AssetLinksForm).exists()).toBe(true);
+ expect(wrapper.findComponent(AssetLinksForm).exists()).toBe(true);
});
});
diff --git a/spec/frontend/releases/components/app_show_spec.js b/spec/frontend/releases/components/app_show_spec.js
index c2ea6900d6e..9ca25b3b69a 100644
--- a/spec/frontend/releases/components/app_show_spec.js
+++ b/spec/frontend/releases/components/app_show_spec.js
@@ -36,8 +36,8 @@ describe('Release show component', () => {
wrapper = null;
});
- const findLoadingSkeleton = () => wrapper.find(ReleaseSkeletonLoader);
- const findReleaseBlock = () => wrapper.find(ReleaseBlock);
+ const findLoadingSkeleton = () => wrapper.findComponent(ReleaseSkeletonLoader);
+ const findReleaseBlock = () => wrapper.findComponent(ReleaseBlock);
const expectLoadingIndicator = () => {
it('renders a loading indicator', () => {
diff --git a/spec/frontend/releases/components/asset_links_form_spec.js b/spec/frontend/releases/components/asset_links_form_spec.js
index 17f079ba5a6..1ff5766b074 100644
--- a/spec/frontend/releases/components/asset_links_form_spec.js
+++ b/spec/frontend/releases/components/asset_links_form_spec.js
@@ -73,7 +73,7 @@ describe('Release edit component', () => {
it('calls the "addEmptyAssetLink" store method when the "Add another link" button is clicked', () => {
expect(actions.addEmptyAssetLink).not.toHaveBeenCalled();
- wrapper.find({ ref: 'addAnotherLinkButton' }).vm.$emit('click');
+ wrapper.findComponent({ ref: 'addAnotherLinkButton' }).vm.$emit('click');
expect(actions.addEmptyAssetLink).toHaveBeenCalledTimes(1);
});
@@ -92,7 +92,7 @@ describe('Release edit component', () => {
let newUrl;
beforeEach(() => {
- input = wrapper.find({ ref: 'urlInput' }).element;
+ input = wrapper.findComponent({ ref: 'urlInput' }).element;
linkIdToUpdate = release.assets.links[0].id;
newUrl = 'updated url';
});
@@ -118,7 +118,7 @@ describe('Release edit component', () => {
it('calls the "updateAssetLinkUrl" store method when text is entered into the "URL" input field', () => {
expectStoreMethodNotToBeCalled();
- wrapper.find({ ref: 'urlInput' }).vm.$emit('change', newUrl);
+ wrapper.findComponent({ ref: 'urlInput' }).vm.$emit('change', newUrl);
expectStoreMethodToBeCalled();
});
@@ -150,7 +150,7 @@ describe('Release edit component', () => {
let newName;
beforeEach(() => {
- input = wrapper.find({ ref: 'nameInput' }).element;
+ input = wrapper.findComponent({ ref: 'nameInput' }).element;
linkIdToUpdate = release.assets.links[0].id;
newName = 'updated name';
});
@@ -176,7 +176,7 @@ describe('Release edit component', () => {
it('calls the "updateAssetLinkName" store method when text is entered into the "Link title" input field', () => {
expectStoreMethodNotToBeCalled();
- wrapper.find({ ref: 'nameInput' }).vm.$emit('change', newName);
+ wrapper.findComponent({ ref: 'nameInput' }).vm.$emit('change', newName);
expectStoreMethodToBeCalled();
});
@@ -208,7 +208,7 @@ describe('Release edit component', () => {
expect(actions.updateAssetLinkType).not.toHaveBeenCalled();
- wrapper.find({ ref: 'typeSelect' }).vm.$emit('change', newType);
+ wrapper.findComponent({ ref: 'typeSelect' }).vm.$emit('change', newType);
expect(actions.updateAssetLinkType).toHaveBeenCalledTimes(1);
expect(actions.updateAssetLinkType).toHaveBeenCalledWith(expect.anything(), {
@@ -225,7 +225,7 @@ describe('Release edit component', () => {
});
it('selects the default asset type', () => {
- const selected = wrapper.find({ ref: 'typeSelect' }).element.value;
+ const selected = wrapper.findComponent({ ref: 'typeSelect' }).element.value;
expect(selected).toBe(DEFAULT_ASSET_LINK_TYPE);
});
diff --git a/spec/frontend/releases/components/evidence_block_spec.js b/spec/frontend/releases/components/evidence_block_spec.js
index f0d02884305..2db1e9e38a2 100644
--- a/spec/frontend/releases/components/evidence_block_spec.js
+++ b/spec/frontend/releases/components/evidence_block_spec.js
@@ -32,19 +32,19 @@ describe('Evidence Block', () => {
});
it('renders the evidence icon', () => {
- expect(wrapper.find(GlIcon).props('name')).toBe('review-list');
+ expect(wrapper.findComponent(GlIcon).props('name')).toBe('review-list');
});
it('renders the title for the dowload link', () => {
- expect(wrapper.find(GlLink).text()).toBe(`v1.1-evidences-1.json`);
+ expect(wrapper.findComponent(GlLink).text()).toBe(`v1.1-evidences-1.json`);
});
it('renders the correct hover text for the download', () => {
- expect(wrapper.find(GlLink).attributes('title')).toBe('Download evidence JSON');
+ expect(wrapper.findComponent(GlLink).attributes('title')).toBe('Download evidence JSON');
});
it('renders the correct file link for download', () => {
- expect(wrapper.find(GlLink).attributes().download).toBe(`v1.1-evidences-1.json`);
+ expect(wrapper.findComponent(GlLink).attributes().download).toBe(`v1.1-evidences-1.json`);
});
describe('sha text', () => {
@@ -62,15 +62,15 @@ describe('Evidence Block', () => {
describe('copy to clipboard button', () => {
it('renders button', () => {
- expect(wrapper.find(ClipboardButton).exists()).toBe(true);
+ expect(wrapper.findComponent(ClipboardButton).exists()).toBe(true);
});
it('renders the correct hover text', () => {
- expect(wrapper.find(ClipboardButton).attributes('title')).toBe('Copy evidence SHA');
+ expect(wrapper.findComponent(ClipboardButton).attributes('title')).toBe('Copy evidence SHA');
});
it('copies the sha', () => {
- expect(wrapper.find(ClipboardButton).attributes('data-clipboard-text')).toBe(
+ expect(wrapper.findComponent(ClipboardButton).attributes('data-clipboard-text')).toBe(
release.evidences[0].sha,
);
});
diff --git a/spec/frontend/releases/components/issuable_stats_spec.js b/spec/frontend/releases/components/issuable_stats_spec.js
index 8fc0779da14..3ac75e138ee 100644
--- a/spec/frontend/releases/components/issuable_stats_spec.js
+++ b/spec/frontend/releases/components/issuable_stats_spec.js
@@ -16,9 +16,11 @@ describe('~/releases/components/issuable_stats.vue', () => {
});
};
- const findOpenStatLink = () => wrapper.find('[data-testid="open-stat"]').find(GlLink);
- const findMergedStatLink = () => wrapper.find('[data-testid="merged-stat"]').find(GlLink);
- const findClosedStatLink = () => wrapper.find('[data-testid="closed-stat"]').find(GlLink);
+ const findOpenStatLink = () => wrapper.find('[data-testid="open-stat"]').findComponent(GlLink);
+ const findMergedStatLink = () =>
+ wrapper.find('[data-testid="merged-stat"]').findComponent(GlLink);
+ const findClosedStatLink = () =>
+ wrapper.find('[data-testid="closed-stat"]').findComponent(GlLink);
beforeEach(() => {
defaultProps = {
diff --git a/spec/frontend/releases/components/release_block_assets_spec.js b/spec/frontend/releases/components/release_block_assets_spec.js
index c63689e11ac..4f94e4dfd55 100644
--- a/spec/frontend/releases/components/release_block_assets_spec.js
+++ b/spec/frontend/releases/components/release_block_assets_spec.js
@@ -44,7 +44,7 @@ describe('Release block assets', () => {
});
it('renders the accordion as expanded by default', () => {
- const accordion = wrapper.find(GlCollapse);
+ const accordion = wrapper.findComponent(GlCollapse);
expect(accordion.exists()).toBe(true);
expect(accordion.isVisible()).toBe(true);
diff --git a/spec/frontend/releases/components/release_block_footer_spec.js b/spec/frontend/releases/components/release_block_footer_spec.js
index 848e802df4b..8f4efad197f 100644
--- a/spec/frontend/releases/components/release_block_footer_spec.js
+++ b/spec/frontend/releases/components/release_block_footer_spec.js
@@ -38,16 +38,16 @@ describe('Release block footer', () => {
});
const commitInfoSection = () => wrapper.find('.js-commit-info');
- const commitInfoSectionLink = () => commitInfoSection().find(GlLink);
+ const commitInfoSectionLink = () => commitInfoSection().findComponent(GlLink);
const tagInfoSection = () => wrapper.find('.js-tag-info');
- const tagInfoSectionLink = () => tagInfoSection().find(GlLink);
+ const tagInfoSectionLink = () => tagInfoSection().findComponent(GlLink);
const authorDateInfoSection = () => wrapper.find('.js-author-date-info');
describe('with all props provided', () => {
beforeEach(() => factory());
it('renders the commit icon', () => {
- const commitIcon = commitInfoSection().find(GlIcon);
+ const commitIcon = commitInfoSection().findComponent(GlIcon);
expect(commitIcon.exists()).toBe(true);
expect(commitIcon.props('name')).toBe('commit');
@@ -62,14 +62,14 @@ describe('Release block footer', () => {
});
it('renders the tag icon', () => {
- const commitIcon = tagInfoSection().find(GlIcon);
+ const commitIcon = tagInfoSection().findComponent(GlIcon);
expect(commitIcon.exists()).toBe(true);
expect(commitIcon.props('name')).toBe('tag');
});
it('renders the tag name with a link', () => {
- const commitLink = tagInfoSection().find(GlLink);
+ const commitLink = tagInfoSection().findComponent(GlLink);
expect(commitLink.exists()).toBe(true);
expect(commitLink.text()).toBe(release.tagName);
@@ -120,7 +120,7 @@ describe('Release block footer', () => {
});
it("renders a link to the author's profile", () => {
- const authorLink = authorDateInfoSection().find(GlLink);
+ const authorLink = authorDateInfoSection().findComponent(GlLink);
expect(authorLink.exists()).toBe(true);
expect(authorLink.attributes('href')).toBe(release.author.webUrl);
diff --git a/spec/frontend/releases/components/release_block_header_spec.js b/spec/frontend/releases/components/release_block_header_spec.js
index c9921185bad..fc421776d60 100644
--- a/spec/frontend/releases/components/release_block_header_spec.js
+++ b/spec/frontend/releases/components/release_block_header_spec.js
@@ -30,7 +30,7 @@ describe('Release block header', () => {
});
const findHeader = () => wrapper.find('h2');
- const findHeaderLink = () => findHeader().find(GlLink);
+ const findHeaderLink = () => findHeader().findComponent(GlLink);
const findEditButton = () => wrapper.find('.js-edit-button');
const findBadge = () => wrapper.findComponent(GlBadge);
diff --git a/spec/frontend/releases/components/release_block_milestone_info_spec.js b/spec/frontend/releases/components/release_block_milestone_info_spec.js
index 84a0080965b..89ae556f906 100644
--- a/spec/frontend/releases/components/release_block_milestone_info_spec.js
+++ b/spec/frontend/releases/components/release_block_milestone_info_spec.js
@@ -43,7 +43,7 @@ describe('Release block milestone info', () => {
});
it('renders a progress bar that displays the correct percentage', () => {
- const progressBar = milestoneProgressBarContainer().find(GlProgressBar);
+ const progressBar = milestoneProgressBarContainer().findComponent(GlProgressBar);
expect(progressBar.exists()).toBe(true);
expect(progressBar.attributes()).toEqual(
@@ -72,7 +72,7 @@ describe('Release block milestone info', () => {
expect(issuesContainerText).toContain(`Issues ${totalIssueCount}`);
- const badge = issuesContainer().find(GlBadge);
+ const badge = issuesContainer().findComponent(GlBadge);
expect(badge.text()).toBe(totalIssueCount.toString());
expect(issuesContainerText).toContain('Open: 5 • Closed: 4');
@@ -107,7 +107,7 @@ describe('Release block milestone info', () => {
});
const clickShowMoreFewerButton = async () => {
- milestoneListContainer().find(GlButton).trigger('click');
+ milestoneListContainer().findComponent(GlButton).trigger('click');
await nextTick();
};
diff --git a/spec/frontend/releases/components/release_block_spec.js b/spec/frontend/releases/components/release_block_spec.js
index 17e2af687a6..096c3db8902 100644
--- a/spec/frontend/releases/components/release_block_spec.js
+++ b/spec/frontend/releases/components/release_block_spec.js
@@ -74,7 +74,7 @@ describe('Release block', () => {
});
it('renders the footer', () => {
- expect(wrapper.find(ReleaseBlockFooter).exists()).toBe(true);
+ expect(wrapper.findComponent(ReleaseBlockFooter).exists()).toBe(true);
});
});
@@ -133,7 +133,7 @@ describe('Release block', () => {
describe('evidence block', () => {
it('renders the evidence block when the evidence is available', () => {
return factory(release).then(() => {
- expect(wrapper.find(EvidenceBlock).exists()).toBe(true);
+ expect(wrapper.findComponent(EvidenceBlock).exists()).toBe(true);
});
});
@@ -141,7 +141,7 @@ describe('Release block', () => {
release.evidences = [];
return factory(release).then(() => {
- expect(wrapper.find(EvidenceBlock).exists()).toBe(false);
+ expect(wrapper.findComponent(EvidenceBlock).exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/releases/components/release_skeleton_loader_spec.js b/spec/frontend/releases/components/release_skeleton_loader_spec.js
index 7f81081ff6c..76dfe0d9777 100644
--- a/spec/frontend/releases/components/release_skeleton_loader_spec.js
+++ b/spec/frontend/releases/components/release_skeleton_loader_spec.js
@@ -10,6 +10,6 @@ describe('release_skeleton_loader.vue', () => {
});
it('renders a GlSkeletonLoader', () => {
- expect(wrapper.find(GlSkeletonLoader).exists()).toBe(true);
+ expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true);
});
});
diff --git a/spec/frontend/releases/components/tag_field_exsting_spec.js b/spec/frontend/releases/components/tag_field_exsting_spec.js
index f45a28392b7..8105aa4f6f2 100644
--- a/spec/frontend/releases/components/tag_field_exsting_spec.js
+++ b/spec/frontend/releases/components/tag_field_exsting_spec.js
@@ -20,7 +20,7 @@ describe('releases/components/tag_field_existing', () => {
});
};
- const findInput = () => wrapper.find(GlFormInput);
+ const findInput = () => wrapper.findComponent(GlFormInput);
const findHelp = () => wrapper.find('[data-testid="tag-name-help"]');
beforeEach(() => {
diff --git a/spec/frontend/releases/components/tag_field_new_spec.js b/spec/frontend/releases/components/tag_field_new_spec.js
index 9f500c318ea..b8047cae8c2 100644
--- a/spec/frontend/releases/components/tag_field_new_spec.js
+++ b/spec/frontend/releases/components/tag_field_new_spec.js
@@ -79,12 +79,12 @@ describe('releases/components/tag_field_new', () => {
});
const findTagNameFormGroup = () => wrapper.find('[data-testid="tag-name-field"]');
- const findTagNameDropdown = () => findTagNameFormGroup().find(RefSelectorStub);
+ const findTagNameDropdown = () => findTagNameFormGroup().findComponent(RefSelectorStub);
const findCreateFromFormGroup = () => wrapper.find('[data-testid="create-from-field"]');
- const findCreateFromDropdown = () => findCreateFromFormGroup().find(RefSelectorStub);
+ const findCreateFromDropdown = () => findCreateFromFormGroup().findComponent(RefSelectorStub);
- const findCreateNewTagOption = () => wrapper.find(GlDropdownItem);
+ const findCreateNewTagOption = () => wrapper.findComponent(GlDropdownItem);
describe('"Tag name" field', () => {
describe('rendering and behavior', () => {
diff --git a/spec/frontend/releases/components/tag_field_spec.js b/spec/frontend/releases/components/tag_field_spec.js
index e7b9aa4abbb..85a40f02c53 100644
--- a/spec/frontend/releases/components/tag_field_spec.js
+++ b/spec/frontend/releases/components/tag_field_spec.js
@@ -21,8 +21,8 @@ describe('releases/components/tag_field', () => {
wrapper = shallowMount(TagField, { store });
};
- const findTagFieldNew = () => wrapper.find(TagFieldNew);
- const findTagFieldExisting = () => wrapper.find(TagFieldExisting);
+ const findTagFieldNew = () => wrapper.findComponent(TagFieldNew);
+ const findTagFieldExisting = () => wrapper.findComponent(TagFieldExisting);
afterEach(() => {
wrapper.destroy();
diff --git a/spec/frontend/reports/accessibility_report/components/accessibility_issue_body_spec.js b/spec/frontend/reports/accessibility_report/components/accessibility_issue_body_spec.js
index ddabb7194cb..d835ca4c733 100644
--- a/spec/frontend/reports/accessibility_report/components/accessibility_issue_body_spec.js
+++ b/spec/frontend/reports/accessibility_report/components/accessibility_issue_body_spec.js
@@ -41,7 +41,7 @@ describe('CustomMetricsForm', () => {
});
it('Displays the issue message', () => {
- const description = wrapper.find({ ref: 'accessibility-issue-description' }).text();
+ const description = wrapper.findComponent({ ref: 'accessibility-issue-description' }).text();
expect(description).toContain(`Message: ${issue.message}`);
});
@@ -49,7 +49,7 @@ describe('CustomMetricsForm', () => {
describe('When an issue code is present', () => {
it('Creates the correct URL for learning more about the issue code', () => {
const learnMoreUrl = wrapper
- .find({ ref: 'accessibility-issue-learn-more' })
+ .findComponent({ ref: 'accessibility-issue-learn-more' })
.attributes('href');
expect(learnMoreUrl).toBe(issue.learnMoreUrl);
@@ -66,7 +66,7 @@ describe('CustomMetricsForm', () => {
it('Creates a URL leading to the overview documentation page', () => {
const learnMoreUrl = wrapper
- .find({ ref: 'accessibility-issue-learn-more' })
+ .findComponent({ ref: 'accessibility-issue-learn-more' })
.attributes('href');
expect(learnMoreUrl).toBe('https://www.w3.org/TR/WCAG20-TECHS/Overview.html');
@@ -83,7 +83,7 @@ describe('CustomMetricsForm', () => {
it('Creates a URL leading to the overview documentation page', () => {
const learnMoreUrl = wrapper
- .find({ ref: 'accessibility-issue-learn-more' })
+ .findComponent({ ref: 'accessibility-issue-learn-more' })
.attributes('href');
expect(learnMoreUrl).toBe('https://www.w3.org/TR/WCAG20-TECHS/Overview.html');
diff --git a/spec/frontend/reports/accessibility_report/grouped_accessibility_reports_app_spec.js b/spec/frontend/reports/accessibility_report/grouped_accessibility_reports_app_spec.js
index 34b1cdd92bc..9d3535291eb 100644
--- a/spec/frontend/reports/accessibility_report/grouped_accessibility_reports_app_spec.js
+++ b/spec/frontend/reports/accessibility_report/grouped_accessibility_reports_app_spec.js
@@ -114,7 +114,7 @@ describe('Grouped accessibility reports app', () => {
});
it('renders custom accessibility issue body', () => {
- const issueBody = wrapper.find(AccessibilityIssueBody);
+ const issueBody = wrapper.findComponent(AccessibilityIssueBody);
expect(issueBody.props('issue').code).toBe(mockReport.new_errors[0].code);
expect(issueBody.props('issue').message).toBe(mockReport.new_errors[0].message);
diff --git a/spec/frontend/reports/codequality_report/components/codequality_issue_body_spec.js b/spec/frontend/reports/codequality_report/components/codequality_issue_body_spec.js
index 17f07ac2b8f..c32b52d9e77 100644
--- a/spec/frontend/reports/codequality_report/components/codequality_issue_body_spec.js
+++ b/spec/frontend/reports/codequality_report/components/codequality_issue_body_spec.js
@@ -8,7 +8,7 @@ describe('code quality issue body issue body', () => {
let wrapper;
const findSeverityIcon = () => wrapper.findByTestId('codequality-severity-icon');
- const findGlIcon = () => wrapper.find(GlIcon);
+ const findGlIcon = () => wrapper.findComponent(GlIcon);
const codequalityIssue = {
name:
diff --git a/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js b/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js
index b61b65c2713..962ff068b92 100644
--- a/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js
+++ b/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js
@@ -30,7 +30,7 @@ describe('Grouped code quality reports app', () => {
};
const findWidget = () => wrapper.find('.js-codequality-widget');
- const findIssueBody = () => wrapper.find(CodequalityIssueBody);
+ const findIssueBody = () => wrapper.findComponent(CodequalityIssueBody);
beforeEach(() => {
const { state, ...storeConfig } = getStoreConfig();
diff --git a/spec/frontend/reports/components/grouped_issues_list_spec.js b/spec/frontend/reports/components/grouped_issues_list_spec.js
index 95ef0bcbcc7..74c17b0b8fc 100644
--- a/spec/frontend/reports/components/grouped_issues_list_spec.js
+++ b/spec/frontend/reports/components/grouped_issues_list_spec.js
@@ -30,7 +30,7 @@ describe('Grouped Issues List', () => {
},
});
- expect(wrapper.find(SmartVirtualList).props()).toMatchSnapshot();
+ expect(wrapper.findComponent(SmartVirtualList).props()).toMatchSnapshot();
});
describe('without data', () => {
@@ -43,7 +43,7 @@ describe('Grouped Issues List', () => {
});
it.each(['resolved', 'unresolved'])('does not render report items for %s issues', () => {
- expect(wrapper.find(ReportItem).exists()).toBe(false);
+ expect(wrapper.findComponent(ReportItem).exists()).toBe(false);
});
});
@@ -81,7 +81,7 @@ describe('Grouped Issues List', () => {
},
});
- expect(wrapper.find(ReportItem).props()).toMatchSnapshot();
+ expect(wrapper.findComponent(ReportItem).props()).toMatchSnapshot();
});
});
});
diff --git a/spec/frontend/reports/components/report_item_spec.js b/spec/frontend/reports/components/report_item_spec.js
index a7243c5377b..b52c163eb26 100644
--- a/spec/frontend/reports/components/report_item_spec.js
+++ b/spec/frontend/reports/components/report_item_spec.js
@@ -16,7 +16,7 @@ describe('ReportItem', () => {
},
});
- expect(wrapper.find(IssueStatusIcon).exists()).toBe(false);
+ expect(wrapper.findComponent(IssueStatusIcon).exists()).toBe(false);
});
it('shows status icon when unspecified', () => {
@@ -28,7 +28,7 @@ describe('ReportItem', () => {
},
});
- expect(wrapper.find(IssueStatusIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(IssueStatusIcon).exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/reports/grouped_test_report/components/modal_spec.js b/spec/frontend/reports/grouped_test_report/components/modal_spec.js
index 3de81f754fd..e8564d2428d 100644
--- a/spec/frontend/reports/grouped_test_report/components/modal_spec.js
+++ b/spec/frontend/reports/grouped_test_report/components/modal_spec.js
@@ -40,7 +40,9 @@ describe('Grouped Test Reports Modal', () => {
});
it('renders code block', () => {
- expect(wrapper.find(CodeBlock).props().code).toEqual(modalDataStructure.system_output.value);
+ expect(wrapper.findComponent(CodeBlock).props().code).toEqual(
+ modalDataStructure.system_output.value,
+ );
});
it('renders link', () => {
diff --git a/spec/frontend/repository/components/breadcrumbs_spec.js b/spec/frontend/repository/components/breadcrumbs_spec.js
index 40b32904589..a1a292e9678 100644
--- a/spec/frontend/repository/components/breadcrumbs_spec.js
+++ b/spec/frontend/repository/components/breadcrumbs_spec.js
@@ -39,8 +39,8 @@ describe('Repository breadcrumbs component', () => {
});
};
- const findUploadBlobModal = () => wrapper.find(UploadBlobModal);
- const findNewDirectoryModal = () => wrapper.find(NewDirectoryModal);
+ const findUploadBlobModal = () => wrapper.findComponent(UploadBlobModal);
+ const findNewDirectoryModal = () => wrapper.findComponent(NewDirectoryModal);
afterEach(() => {
wrapper.destroy();
@@ -95,7 +95,7 @@ describe('Repository breadcrumbs component', () => {
await nextTick();
- expect(wrapper.find(GlDropdown).exists()).toBe(false);
+ expect(wrapper.findComponent(GlDropdown).exists()).toBe(false);
});
it.each`
@@ -109,7 +109,7 @@ describe('Repository breadcrumbs component', () => {
'does render add to tree dropdown $isRendered when route is $routeName',
({ routeName, isRendered }) => {
factory('app/assets/javascripts.js', { canCollaborate: true }, { name: routeName });
- expect(wrapper.find(GlDropdown).exists()).toBe(isRendered);
+ expect(wrapper.findComponent(GlDropdown).exists()).toBe(isRendered);
},
);
@@ -122,7 +122,7 @@ describe('Repository breadcrumbs component', () => {
await nextTick();
- expect(wrapper.find(GlDropdown).exists()).toBe(true);
+ expect(wrapper.findComponent(GlDropdown).exists()).toBe(true);
});
describe('renders the upload blob modal', () => {
diff --git a/spec/frontend/repository/components/preview/index_spec.js b/spec/frontend/repository/components/preview/index_spec.js
index 0d9bfc62ed5..e4eba65795e 100644
--- a/spec/frontend/repository/components/preview/index_spec.js
+++ b/spec/frontend/repository/components/preview/index_spec.js
@@ -68,6 +68,6 @@ describe('Repository file preview component', () => {
vm.setData({ loading: 1 });
await nextTick();
- expect(vm.find(GlLoadingIcon).exists()).toBe(true);
+ expect(vm.findComponent(GlLoadingIcon).exists()).toBe(true);
});
});
diff --git a/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
index 4541f8af7d3..56514c985ff 100644
--- a/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
+++ b/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote do
+ include NotesHelper
+
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:incident) { create(:incident, project: project) }
@@ -23,7 +25,7 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote do
let(:expected_timeline_event) do
instance_double(
'IncidentManagement::TimelineEvent',
- note: comment.note,
+ note: "@#{comment.author.username} [commented](#{noteable_note_url(comment)}): '#{comment.note}'",
occurred_at: comment.created_at.to_s,
incident: incident,
author: current_user,
diff --git a/spec/graphql/types/branch_protection_type_spec.rb b/spec/graphql/types/branch_protection_type_spec.rb
index 6efa457227f..5891df666c5 100644
--- a/spec/graphql/types/branch_protection_type_spec.rb
+++ b/spec/graphql/types/branch_protection_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['BranchProtection'] do
subject { described_class }
- let(:fields) { %i[allow_force_push] }
+ let(:fields) { %i[merge_access_levels allow_force_push] }
specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
diff --git a/spec/graphql/types/branch_protections/merge_access_level_type_spec.rb b/spec/graphql/types/branch_protections/merge_access_level_type_spec.rb
new file mode 100644
index 00000000000..0c9c8553b6f
--- /dev/null
+++ b/spec/graphql/types/branch_protections/merge_access_level_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['MergeAccessLevel'] do
+ subject { described_class }
+
+ let(:fields) { %i[access_level access_level_description] }
+
+ specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
+
+ specify { is_expected.to have_graphql_fields(fields) }
+end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
index e0d656f456e..f451bd6bfef 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
@@ -11,7 +11,9 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
subject { described_class.new(pipeline, command) }
- describe '#perform!' do
+ # TODO: change this to `describe` and remove rubocop-disable
+ # when removing the FF ci_project_pipeline_config_refactoring
+ shared_context '#perform!' do # rubocop:disable RSpec/ContextWording
context 'when bridge job is passed in as parameter' do
let(:ci_config_path) { nil }
let(:bridge) { create(:ci_bridge) }
@@ -201,4 +203,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
end
end
end
+
+ it_behaves_like '#perform!'
+
+ context 'when the FF ci_project_pipeline_config_refactoring is disabled' do
+ before do
+ stub_feature_flags(ci_project_pipeline_config_refactoring: false)
+ end
+
+ it_behaves_like '#perform!'
+ end
end
diff --git a/spec/lib/gitlab/ci/project_config/repository_spec.rb b/spec/lib/gitlab/ci/project_config/repository_spec.rb
new file mode 100644
index 00000000000..2105b691d9e
--- /dev/null
+++ b/spec/lib/gitlab/ci/project_config/repository_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::ProjectConfig::Repository do
+ let(:project) { create(:project, :custom_repo, files: files) }
+ let(:sha) { project.repository.head_commit.sha }
+ let(:files) { { 'README.md' => 'hello' } }
+
+ subject(:config) { described_class.new(project, sha, nil, nil, nil) }
+
+ describe '#content' do
+ subject(:content) { config.content }
+
+ context 'when file is in repository' do
+ let(:config_content_result) do
+ <<~CICONFIG
+ ---
+ include:
+ - local: ".gitlab-ci.yml"
+ CICONFIG
+ end
+
+ let(:files) { { '.gitlab-ci.yml' => 'content' } }
+
+ it { is_expected.to eq(config_content_result) }
+ end
+
+ context 'when file is not in repository' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'when Gitaly raises error' do
+ before do
+ allow(project.repository).to receive(:gitlab_ci_yml_for).and_raise(GRPC::Internal)
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '#source' do
+ subject { config.source }
+
+ it { is_expected.to eq(:repository_source) }
+ end
+end
diff --git a/spec/lib/gitlab/ci/project_config/source_spec.rb b/spec/lib/gitlab/ci/project_config/source_spec.rb
new file mode 100644
index 00000000000..dda5c7cdce8
--- /dev/null
+++ b/spec/lib/gitlab/ci/project_config/source_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::ProjectConfig::Source do
+ let_it_be(:custom_config_class) { Class.new(described_class) }
+ let_it_be(:project) { build_stubbed(:project) }
+ let_it_be(:sha) { '123456' }
+
+ subject(:custom_config) { custom_config_class.new(project, sha, nil, nil, nil) }
+
+ describe '#content' do
+ subject(:content) { custom_config.content }
+
+ it { expect { content }.to raise_error(NotImplementedError) }
+ end
+
+ describe '#source' do
+ subject(:source) { custom_config.source }
+
+ it { expect { source }.to raise_error(NotImplementedError) }
+ end
+end
diff --git a/spec/lib/gitlab/ci/project_config_spec.rb b/spec/lib/gitlab/ci/project_config_spec.rb
new file mode 100644
index 00000000000..c4b179c9ef5
--- /dev/null
+++ b/spec/lib/gitlab/ci/project_config_spec.rb
@@ -0,0 +1,177 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::ProjectConfig do
+ let(:project) { create(:project, :empty_repo, ci_config_path: ci_config_path) }
+ let(:sha) { '123456' }
+ let(:content) { nil }
+ let(:source) { :push }
+ let(:bridge) { nil }
+
+ subject(:config) do
+ described_class.new(project: project, sha: sha,
+ custom_content: content, pipeline_source: source, pipeline_source_bridge: bridge)
+ end
+
+ context 'when bridge job is passed in as parameter' do
+ let(:ci_config_path) { nil }
+ let(:bridge) { create(:ci_bridge) }
+
+ before do
+ allow(bridge).to receive(:yaml_for_downstream).and_return('the-yaml')
+ end
+
+ it 'returns the content already available in command' do
+ expect(config.source).to eq(:bridge_source)
+ expect(config.content).to eq('the-yaml')
+ end
+ end
+
+ context 'when config is defined in a custom path in the repository' do
+ let(:ci_config_path) { 'path/to/config.yml' }
+ let(:config_content_result) do
+ <<~CICONFIG
+ ---
+ include:
+ - local: #{ci_config_path}
+ CICONFIG
+ end
+
+ before do
+ allow(project.repository)
+ .to receive(:gitlab_ci_yml_for)
+ .with(sha, ci_config_path)
+ .and_return('the-content')
+ end
+
+ it 'returns root config including the local custom file' do
+ expect(config.source).to eq(:repository_source)
+ expect(config.content).to eq(config_content_result)
+ end
+ end
+
+ context 'when config is defined remotely' do
+ let(:ci_config_path) { 'http://example.com/path/to/ci/config.yml' }
+ let(:config_content_result) do
+ <<~CICONFIG
+ ---
+ include:
+ - remote: #{ci_config_path}
+ CICONFIG
+ end
+
+ it 'returns root config including the remote config' do
+ expect(config.source).to eq(:remote_source)
+ expect(config.content).to eq(config_content_result)
+ end
+ end
+
+ context 'when config is defined in a separate repository' do
+ let(:ci_config_path) { 'path/to/.gitlab-ci.yml@another-group/another-repo' }
+ let(:config_content_result) do
+ <<~CICONFIG
+ ---
+ include:
+ - project: another-group/another-repo
+ file: path/to/.gitlab-ci.yml
+ CICONFIG
+ end
+
+ it 'returns root config including the path to another repository' do
+ expect(config.source).to eq(:external_project_source)
+ expect(config.content).to eq(config_content_result)
+ end
+
+ context 'when path specifies a refname' do
+ let(:ci_config_path) { 'path/to/.gitlab-ci.yml@another-group/another-repo:refname' }
+ let(:config_content_result) do
+ <<~CICONFIG
+ ---
+ include:
+ - project: another-group/another-repo
+ file: path/to/.gitlab-ci.yml
+ ref: refname
+ CICONFIG
+ end
+
+ it 'returns root config including the path and refname to another repository' do
+ expect(config.source).to eq(:external_project_source)
+ expect(config.content).to eq(config_content_result)
+ end
+ end
+ end
+
+ context 'when config is defined in the default .gitlab-ci.yml' do
+ let(:ci_config_path) { nil }
+ let(:config_content_result) do
+ <<~CICONFIG
+ ---
+ include:
+ - local: ".gitlab-ci.yml"
+ CICONFIG
+ end
+
+ before do
+ allow(project.repository)
+ .to receive(:gitlab_ci_yml_for)
+ .with(sha, '.gitlab-ci.yml')
+ .and_return('the-content')
+ end
+
+ it 'returns root config including the canonical CI config file' do
+ expect(config.source).to eq(:repository_source)
+ expect(config.content).to eq(config_content_result)
+ end
+ end
+
+ context 'when config is the Auto-Devops template' do
+ let(:ci_config_path) { nil }
+ let(:config_content_result) do
+ <<~CICONFIG
+ ---
+ include:
+ - template: Auto-DevOps.gitlab-ci.yml
+ CICONFIG
+ end
+
+ before do
+ allow(project).to receive(:auto_devops_enabled?).and_return(true)
+ end
+
+ it 'returns root config including the auto-devops template' do
+ expect(config.source).to eq(:auto_devops_source)
+ expect(config.content).to eq(config_content_result)
+ end
+ end
+
+ context 'when config is passed as a parameter' do
+ let(:source) { :ondemand_dast_scan }
+ let(:ci_config_path) { nil }
+ let(:content) do
+ <<~CICONFIG
+ ---
+ stages:
+ - dast
+ CICONFIG
+ end
+
+ it 'returns the parameter content' do
+ expect(config.source).to eq(:parameter_source)
+ expect(config.content).to eq(content)
+ end
+ end
+
+ context 'when config is not defined anywhere' do
+ let(:ci_config_path) { nil }
+
+ before do
+ allow(project).to receive(:auto_devops_enabled?).and_return(false)
+ end
+
+ it 'returns nil' do
+ expect(config.source).to be_nil
+ expect(config.content).to be_nil
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb
new file mode 100644
index 00000000000..ef7c7965c09
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningAnalyzer, query_analyzers: false do
+ let(:analyzer) { described_class }
+
+ before do
+ allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer])
+ end
+
+ context 'when ci_partitioning_analyze_queries is disabled' do
+ before do
+ stub_feature_flags(ci_partitioning_analyze_queries: false)
+ end
+
+ it 'does not analyze the query' do
+ expect(analyzer).not_to receive(:analyze)
+
+ process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata")
+ end
+ end
+
+ context 'when ci_partitioning_analyze_queries is enabled' do
+ context 'when analyzing targeted tables' do
+ described_class::ENABLED_TABLES.each do |enabled_table|
+ context 'when querying a non routing table' do
+ it 'tracks exception' do
+ expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}")
+ end
+
+ it 'raises RoutingTableNotUsedError' do
+ expect { process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}") }
+ .to raise_error(described_class::RoutingTableNotUsedError)
+ end
+ end
+ end
+
+ context 'when updating a record' do
+ it 'raises RoutingTableNotUsedError' do
+ expect { process_sql(Ci::BuildMetadata, "UPDATE ci_builds_metadata SET id = 1") }
+ .to raise_error(described_class::RoutingTableNotUsedError)
+ end
+ end
+
+ context 'when inserting a record' do
+ it 'raises RoutingTableNotUsedError' do
+ expect { process_sql(Ci::BuildMetadata, "INSERT INTO ci_builds_metadata (id) VALUES(1)") }
+ .to raise_error(described_class::RoutingTableNotUsedError)
+ end
+ end
+ end
+
+ context 'when analyzing non targeted table' do
+ it 'does not raise error' do
+ expect { process_sql(Ci::BuildMetadata, "SELECT 1 FROM projects") }
+ .not_to raise_error
+ end
+ end
+
+ context 'when querying a routing table' do
+ it 'does not raise error' do
+ expect { process_sql(Ci::BuildMetadata, "SELECT 1 FROM p_ci_builds_metadata") }
+ .not_to raise_error
+ end
+ end
+ end
+
+ private
+
+ def process_sql(model, sql)
+ Gitlab::Database::QueryAnalyzer.instance.within do
+ # Skip load balancer and retrieve connection assigned to model
+ Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
index b6def9f3e3d..5b5516f100b 100644
--- a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
+++ b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
@@ -136,7 +136,7 @@ RSpec.describe Gitlab::Instrumentation::RedisInterceptor, :clean_gitlab_redis_sh
end
context 'with pipelined commands' do
- it 'skips requests that have blocking commands' do
+ it 'skips requests that have blocking commands', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/373026' do
expect(instrumentation_class).not_to receive(:instance_observe_duration)
Gitlab::Redis::SharedState.with do |redis|
diff --git a/spec/policies/protected_branch_access_policy_spec.rb b/spec/policies/protected_branch_access_policy_spec.rb
new file mode 100644
index 00000000000..68a130d666a
--- /dev/null
+++ b/spec/policies/protected_branch_access_policy_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ProtectedBranchAccessPolicy do
+ let(:user) { create(:user) }
+ let(:protected_branch_access) { create(:protected_branch_merge_access_level) }
+ let(:project) { protected_branch_access.protected_branch.project }
+
+ subject { described_class.new(user, protected_branch_access) }
+
+ context 'as maintainers' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'can be read' do
+ is_expected.to be_allowed(:read_protected_branch)
+ end
+ end
+
+ context 'as guests' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'can not be read' do
+ is_expected.to be_disallowed(:read_protected_branch)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
index 9272e218172..85eaec90f47 100644
--- a/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Promote an incident timeline event from a comment' do
include GraphqlHelpers
+ include NotesHelper
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
@@ -53,7 +54,7 @@ RSpec.describe 'Promote an incident timeline event from a comment' do
'promotedFromNote' => {
'id' => comment.to_global_id.to_s
},
- 'note' => comment.note,
+ 'note' => "@#{comment.author.username} [commented](#{noteable_note_url(comment)}): '#{comment.note}'",
'action' => 'comment',
'editable' => true,
'occurredAt' => comment.created_at.iso8601
diff --git a/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb b/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
new file mode 100644
index 00000000000..cb5006ec8e4
--- /dev/null
+++ b/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting merge access levels for a branch protection' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+
+ let(:merge_access_level_data) { merge_access_levels_data[0] }
+
+ let(:merge_access_levels_data) do
+ graphql_data_at('project',
+ 'branchRules',
+ 'nodes',
+ 0,
+ 'branchProtection',
+ 'mergeAccessLevels',
+ 'nodes')
+ end
+
+ let(:project) { protected_branch.project }
+
+ let(:merge_access_levels_count) { protected_branch.merge_access_levels.size }
+
+ let(:variables) { { path: project.full_path } }
+
+ let(:fields) { all_graphql_fields_for('MergeAccessLevel') }
+
+ let(:query) do
+ <<~GQL
+ query($path: ID!) {
+ project(fullPath: $path) {
+ branchRules(first: 1) {
+ nodes {
+ branchProtection {
+ mergeAccessLevels {
+ nodes {
+ #{fields}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ context 'when the user does not have read_protected_branch abilities' do
+ let_it_be(:protected_branch) { create(:protected_branch) }
+
+ before do
+ project.add_guest(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it { expect(merge_access_levels_data).not_to be_present }
+ end
+
+ shared_examples 'merge access request' do
+ let(:merge_access) { protected_branch.merge_access_levels.first }
+
+ before do
+ project.add_maintainer(current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns all merge access levels' do
+ expect(merge_access_levels_data.size).to eq(merge_access_levels_count)
+ end
+
+ it 'includes access_level' do
+ expect(merge_access_level_data['accessLevel'])
+ .to eq(merge_access.access_level)
+ end
+
+ it 'includes access_level_description' do
+ expect(merge_access_level_data['accessLevelDescription'])
+ .to eq(merge_access.humanize)
+ end
+ end
+
+ context 'when the user does have read_protected_branch abilities' do
+ let(:merge_access) { protected_branch.merge_access_levels.first }
+
+ context 'when no one has access' do
+ let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_merge) }
+
+ it_behaves_like 'merge access request'
+ end
+
+ context 'when developers have access' do
+ let_it_be(:protected_branch) { create(:protected_branch, :developers_can_merge) }
+
+ it_behaves_like 'merge access request'
+ end
+
+ context 'when maintainers have access' do
+ let_it_be(:protected_branch) { create(:protected_branch, :maintainers_can_merge) }
+
+ it_behaves_like 'merge access request'
+ end
+ end
+end
diff --git a/spec/serializers/ci/dag_pipeline_entity_spec.rb b/spec/serializers/ci/dag_pipeline_entity_spec.rb
index 548fd247743..a8ac76d800f 100644
--- a/spec/serializers/ci/dag_pipeline_entity_spec.rb
+++ b/spec/serializers/ci/dag_pipeline_entity_spec.rb
@@ -5,7 +5,8 @@ require 'spec_helper'
RSpec.describe Ci::DagPipelineEntity do
let_it_be(:request) { double(:request) }
- let(:pipeline) { create(:ci_pipeline) }
+ let_it_be(:pipeline) { create(:ci_pipeline) }
+
let(:entity) { described_class.new(pipeline, request: request) }
describe '#as_json' do
@@ -28,9 +29,13 @@ RSpec.describe Ci::DagPipelineEntity do
end
context 'when pipeline has jobs' do
- let!(:build_job) { create(:ci_build, stage: 'build', pipeline: pipeline) }
- let!(:test_job) { create(:ci_build, stage: 'test', pipeline: pipeline) }
- let!(:deploy_job) { create(:ci_build, stage: 'deploy', pipeline: pipeline) }
+ let_it_be(:build_stage) { create(:ci_stage, name: 'build', pipeline: pipeline) }
+ let_it_be(:test_stage) { create(:ci_stage, name: 'test', pipeline: pipeline) }
+ let_it_be(:deploy_stage) { create(:ci_stage, name: 'deploy', pipeline: pipeline) }
+
+ let!(:build_job) { create(:ci_build, ci_stage: build_stage, pipeline: pipeline) }
+ let!(:test_job) { create(:ci_build, ci_stage: test_stage, pipeline: pipeline) }
+ let!(:deploy_job) { create(:ci_build, ci_stage: deploy_stage, pipeline: pipeline) }
it 'contains 3 stages' do
stages = subject[:stages]
@@ -47,28 +52,31 @@ RSpec.describe Ci::DagPipelineEntity do
let!(:stage_test) { create(:ci_stage, name: 'test', position: 2, pipeline: pipeline) }
let!(:stage_deploy) { create(:ci_stage, name: 'deploy', position: 3, pipeline: pipeline) }
- let!(:job_build_1) { create(:ci_build, name: 'build 1', stage: 'build', pipeline: pipeline) }
- let!(:job_build_2) { create(:ci_build, name: 'build 2', stage: 'build', pipeline: pipeline) }
- let!(:commit_status) { create(:generic_commit_status, stage: 'build', pipeline: pipeline) }
+ let!(:job_build_1) { create(:ci_build, name: 'build 1', ci_stage: stage_build, pipeline: pipeline) }
+ let!(:job_build_2) { create(:ci_build, name: 'build 2', ci_stage: stage_build, pipeline: pipeline) }
+ let!(:commit_status) { create(:generic_commit_status, ci_stage: stage_build, pipeline: pipeline) }
- let!(:job_rspec_1) { create(:ci_build, name: 'rspec 1/2', stage: 'test', pipeline: pipeline) }
- let!(:job_rspec_2) { create(:ci_build, name: 'rspec 2/2', stage: 'test', pipeline: pipeline) }
+ let!(:job_rspec_1) { create(:ci_build, name: 'rspec 1/2', ci_stage: stage_test, pipeline: pipeline) }
+ let!(:job_rspec_2) { create(:ci_build, name: 'rspec 2/2', ci_stage: stage_test, pipeline: pipeline) }
let!(:job_jest) do
- create(:ci_build, name: 'jest', stage: 'test', scheduling_type: 'dag', pipeline: pipeline).tap do |job|
+ create(:ci_build, name: 'jest', ci_stage: stage_test, scheduling_type: 'dag', pipeline: pipeline)
+ .tap do |job|
create(:ci_build_need, name: 'build 1', build: job)
end
end
let!(:job_deploy_ruby) do
- create(:ci_build, name: 'deploy_ruby', stage: 'deploy', scheduling_type: 'dag', pipeline: pipeline).tap do |job|
+ create(:ci_build, name: 'deploy_ruby', ci_stage: stage_deploy, scheduling_type: 'dag', pipeline: pipeline)
+ .tap do |job|
create(:ci_build_need, name: 'rspec 1/2', build: job)
create(:ci_build_need, name: 'rspec 2/2', build: job)
end
end
let!(:job_deploy_js) do
- create(:ci_build, name: 'deploy_js', stage: 'deploy', scheduling_type: 'dag', pipeline: pipeline).tap do |job|
+ create(:ci_build, name: 'deploy_js', ci_stage: stage_deploy, scheduling_type: 'dag', pipeline: pipeline)
+ .tap do |job|
create(:ci_build_need, name: 'jest', build: job)
end
end
diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb
index 289e004fcce..7578afa7c50 100644
--- a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb
+++ b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb
@@ -6,11 +6,28 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection
using RSpec::Parameterized::TableSyntax
let_it_be(:pipeline) { create(:ci_pipeline) }
- let_it_be(:build_a) { create(:ci_build, :success, name: 'build-a', stage: 'build', stage_idx: 0, pipeline: pipeline) }
- let_it_be(:build_b) { create(:ci_build, :failed, name: 'build-b', stage: 'build', stage_idx: 0, pipeline: pipeline) }
- let_it_be(:test_a) { create(:ci_build, :running, name: 'test-a', stage: 'test', stage_idx: 1, pipeline: pipeline) }
- let_it_be(:test_b) { create(:ci_build, :pending, name: 'test-b', stage: 'test', stage_idx: 1, pipeline: pipeline) }
- let_it_be(:deploy) { create(:ci_build, :created, name: 'deploy', stage: 'deploy', stage_idx: 2, pipeline: pipeline) }
+ let_it_be(:build_stage) { create(:ci_stage, name: 'build', pipeline: pipeline) }
+ let_it_be(:test_stage) { create(:ci_stage, name: 'test', pipeline: pipeline) }
+ let_it_be(:deploy_stage) { create(:ci_stage, name: 'deploy', pipeline: pipeline) }
+ let_it_be(:build_a) do
+ create(:ci_build, :success, name: 'build-a', ci_stage: build_stage, stage_idx: 0, pipeline: pipeline)
+ end
+
+ let_it_be(:build_b) do
+ create(:ci_build, :failed, name: 'build-b', ci_stage: build_stage, stage_idx: 0, pipeline: pipeline)
+ end
+
+ let_it_be(:test_a) do
+ create(:ci_build, :running, name: 'test-a', ci_stage: test_stage, stage_idx: 1, pipeline: pipeline)
+ end
+
+ let_it_be(:test_b) do
+ create(:ci_build, :pending, name: 'test-b', ci_stage: test_stage, stage_idx: 1, pipeline: pipeline)
+ end
+
+ let_it_be(:deploy) do
+ create(:ci_build, :created, name: 'deploy', ci_stage: deploy_stage, stage_idx: 2, pipeline: pipeline)
+ end
let(:collection) { described_class.new(pipeline) }
diff --git a/spec/services/ci/play_manual_stage_service_spec.rb b/spec/services/ci/play_manual_stage_service_spec.rb
index b3ae92aa787..24f0a21f3dd 100644
--- a/spec/services/ci/play_manual_stage_service_spec.rb
+++ b/spec/services/ci/play_manual_stage_service_spec.rb
@@ -75,7 +75,6 @@ RSpec.describe Ci::PlayManualStageService, '#execute' do
options.merge!({
when: 'manual',
pipeline: pipeline,
- stage: stage.name,
stage_id: stage.id,
user: pipeline.user
})
@@ -87,7 +86,6 @@ RSpec.describe Ci::PlayManualStageService, '#execute' do
options.merge!({
when: 'manual',
pipeline: pipeline,
- stage: stage.name,
stage_id: stage.id,
user: pipeline.user,
downstream: downstream_project
diff --git a/spec/services/ci/retry_job_service_spec.rb b/spec/services/ci/retry_job_service_spec.rb
index 5914e0fc4c1..69f19c5acf2 100644
--- a/spec/services/ci/retry_job_service_spec.rb
+++ b/spec/services/ci/retry_job_service_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe Ci::RetryJobService do
let_it_be_with_refind(:job) do
create(:ci_bridge, :success,
- pipeline: pipeline, downstream: downstream_project, description: 'a trigger job', stage_id: stage.id
+ pipeline: pipeline, downstream: downstream_project, description: 'a trigger job', ci_stage: stage
)
end
@@ -43,13 +43,13 @@ RSpec.describe Ci::RetryJobService do
end
shared_context 'retryable build' do
- let_it_be_with_refind(:job) { create(:ci_build, :success, pipeline: pipeline, stage_id: stage.id) }
+ let_it_be_with_refind(:job) { create(:ci_build, :success, pipeline: pipeline, ci_stage: stage) }
let_it_be(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
let_it_be(:job_to_clone) do
create(:ci_build, :failed, :picked, :expired, :erased, :queued, :coverage, :tags,
:allowed_to_fail, :on_tag, :triggered, :teardown_environment, :resource_group,
- description: 'my-job', stage: 'test', stage_id: stage.id,
+ description: 'my-job', ci_stage: stage,
pipeline: pipeline, auto_canceled_by: another_pipeline,
scheduled_at: 10.seconds.since)
end
@@ -64,8 +64,7 @@ RSpec.describe Ci::RetryJobService do
let(:job) { job_to_clone }
before_all do
- # Make sure that job has both `stage_id` and `stage`
- job_to_clone.update!(stage: 'test', stage_id: stage.id)
+ job_to_clone.update!(ci_stage: stage)
create(:ci_build_need, build: job_to_clone)
end
@@ -124,14 +123,16 @@ RSpec.describe Ci::RetryJobService do
end
context 'when there are subsequent processables that are skipped' do
+ let_it_be(:stage) { create(:ci_stage, pipeline: pipeline, name: 'deploy') }
+
let!(:subsequent_build) do
create(:ci_build, :skipped, stage_idx: 2,
pipeline: pipeline,
- stage: 'deploy')
+ ci_stage: stage)
end
let!(:subsequent_bridge) do
- create(:ci_bridge, :skipped, stage_idx: 2, pipeline: pipeline, stage: 'deploy')
+ create(:ci_bridge, :skipped, stage_idx: 2, pipeline: pipeline, ci_stage: stage)
end
it 'resumes pipeline processing in the subsequent stage' do
@@ -152,8 +153,8 @@ RSpec.describe Ci::RetryJobService do
context 'when the pipeline has other jobs' do
let!(:stage2) { create(:ci_stage, project: project, pipeline: pipeline, name: 'deploy') }
- let!(:build2) { create(:ci_build, pipeline: pipeline, stage_id: stage.id ) }
- let!(:deploy) { create(:ci_build, pipeline: pipeline, stage_id: stage2.id) }
+ let!(:build2) { create(:ci_build, pipeline: pipeline, ci_stage: stage ) }
+ let!(:deploy) { create(:ci_build, pipeline: pipeline, ci_stage: stage2) }
let!(:deploy_needs_build2) { create(:ci_build_need, build: deploy, name: build2.name) }
context 'when job has a nil scheduling_type' do
@@ -223,7 +224,7 @@ RSpec.describe Ci::RetryJobService do
context 'when a build with a deployment is retried' do
let!(:job) do
create(:ci_build, :with_deployment, :deploy_to_production,
- pipeline: pipeline, stage_id: stage.id, project: project)
+ pipeline: pipeline, ci_stage: stage, project: project)
end
it 'creates a new deployment' do
@@ -245,7 +246,7 @@ RSpec.describe Ci::RetryJobService do
environment: environment_name,
options: { environment: { name: environment_name } },
pipeline: pipeline,
- stage_id: stage.id,
+ ci_stage: stage,
project: project,
user: other_developer)
end
@@ -306,22 +307,24 @@ RSpec.describe Ci::RetryJobService do
it_behaves_like 'retries the job'
context 'when there are subsequent jobs that are skipped' do
+ let_it_be(:stage) { create(:ci_stage, pipeline: pipeline, name: 'deploy') }
+
let!(:subsequent_build) do
create(:ci_build, :skipped, stage_idx: 2,
pipeline: pipeline,
- stage: 'deploy')
+ stage_id: stage.id)
end
let!(:subsequent_bridge) do
create(:ci_bridge, :skipped, stage_idx: 2,
pipeline: pipeline,
- stage: 'deploy')
+ stage_id: stage.id)
end
it 'does not cause an N+1 when updating the job ownership' do
control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { service.execute(job) }.count
- create_list(:ci_build, 2, :skipped, stage_idx: job.stage_idx + 1, pipeline: pipeline, stage: 'deploy')
+ create_list(:ci_build, 2, :skipped, stage_idx: job.stage_idx + 1, pipeline: pipeline, stage_id: stage.id)
expect { service.execute(job) }.not_to exceed_all_query_limit(control_count)
end
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index 24272801480..0a1e767539d 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -9,6 +9,9 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:service) { described_class.new(project, user) }
+ let(:build_stage) { create(:ci_stage, name: 'build', position: 0, pipeline: pipeline) }
+ let(:test_stage) { create(:ci_stage, name: 'test', position: 1, pipeline: pipeline) }
+ let(:deploy_stage) { create(:ci_stage, name: 'deploy', position: 2, pipeline: pipeline) }
context 'when user has full ability to modify pipeline' do
before do
@@ -20,8 +23,8 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there are already retried jobs present' do
before do
- create_build('rspec', :canceled, 0, retried: true)
- create_build('rspec', :failed, 0)
+ create_build('rspec', :canceled, build_stage, retried: true)
+ create_build('rspec', :failed, build_stage)
end
it 'does not retry jobs that has already been retried' do
@@ -33,9 +36,9 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there are failed builds in the last stage' do
before do
- create_build('rspec 1', :success, 0)
- create_build('rspec 2', :failed, 1)
- create_build('rspec 3', :canceled, 1)
+ create_build('rspec 1', :success, build_stage)
+ create_build('rspec 2', :failed, test_stage)
+ create_build('rspec 3', :canceled, test_stage)
end
it 'enqueues all builds in the last stage' do
@@ -49,10 +52,10 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there are failed or canceled builds in the first stage' do
before do
- create_build('rspec 1', :failed, 0)
- create_build('rspec 2', :canceled, 0)
- create_build('rspec 3', :canceled, 1)
- create_build('spinach 1', :canceled, 2)
+ create_build('rspec 1', :failed, build_stage)
+ create_build('rspec 2', :canceled, build_stage)
+ create_build('rspec 3', :canceled, test_stage)
+ create_build('spinach 1', :canceled, deploy_stage)
end
it 'retries builds failed builds and marks subsequent for processing' do
@@ -80,10 +83,10 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there is failed build present which was run on failure' do
before do
- create_build('rspec 1', :failed, 0)
- create_build('rspec 2', :canceled, 0)
- create_build('rspec 3', :canceled, 1)
- create_build('report 1', :failed, 2)
+ create_build('rspec 1', :failed, build_stage)
+ create_build('rspec 2', :canceled, build_stage)
+ create_build('rspec 3', :canceled, test_stage)
+ create_build('report 1', :failed, deploy_stage)
end
it 'retries builds only in the first stage' do
@@ -105,9 +108,9 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there is a failed test in a DAG' do
before do
- create_build('build', :success, 0)
- create_build('build2', :success, 0)
- test_build = create_build('test', :failed, 1, scheduling_type: :dag)
+ create_build('build', :success, build_stage)
+ create_build('build2', :success, build_stage)
+ test_build = create_build('test', :failed, test_stage, scheduling_type: :dag)
create(:ci_build_need, build: test_build, name: 'build')
create(:ci_build_need, build: test_build, name: 'build2')
end
@@ -123,7 +126,7 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there is a failed DAG test without needs' do
before do
- create_build('deploy', :failed, 2, scheduling_type: :dag)
+ create_build('deploy', :failed, deploy_stage, scheduling_type: :dag)
end
it 'retries the test' do
@@ -139,10 +142,10 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when the last stage was skipped' do
before do
- create_build('build 1', :success, 0)
- create_build('test 2', :failed, 1)
- create_build('report 3', :skipped, 2)
- create_build('report 4', :skipped, 2)
+ create_build('build 1', :success, build_stage)
+ create_build('test 2', :failed, test_stage)
+ create_build('report 3', :skipped, deploy_stage)
+ create_build('report 4', :skipped, deploy_stage)
end
it 'retries builds only in the first stage' do
@@ -160,9 +163,9 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there are optional manual actions only' do
context 'when there is a canceled manual action in first stage' do
before do
- create_build('rspec 1', :failed, 0)
- create_build('staging', :canceled, 0, when: :manual, allow_failure: true)
- create_build('rspec 2', :canceled, 1)
+ create_build('rspec 1', :failed, build_stage)
+ create_build('staging', :canceled, build_stage, when: :manual, allow_failure: true)
+ create_build('rspec 2', :canceled, test_stage)
end
it 'retries failed builds and marks subsequent for processing' do
@@ -189,9 +192,9 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when pipeline has blocking manual actions defined' do
context 'when pipeline retry should enqueue builds' do
before do
- create_build('test', :failed, 0)
- create_build('deploy', :canceled, 0, when: :manual, allow_failure: false)
- create_build('verify', :canceled, 1)
+ create_build('test', :failed, build_stage)
+ create_build('deploy', :canceled, build_stage, when: :manual, allow_failure: false)
+ create_build('verify', :canceled, test_stage)
end
it 'retries failed builds' do
@@ -206,10 +209,10 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when pipeline retry should block pipeline immediately' do
before do
- create_build('test', :success, 0)
- create_build('deploy:1', :success, 1, when: :manual, allow_failure: false)
- create_build('deploy:2', :failed, 1, when: :manual, allow_failure: false)
- create_build('verify', :canceled, 2)
+ create_build('test', :success, build_stage)
+ create_build('deploy:1', :success, test_stage, when: :manual, allow_failure: false)
+ create_build('deploy:2', :failed, test_stage, when: :manual, allow_failure: false)
+ create_build('verify', :canceled, deploy_stage)
end
it 'reprocesses blocking manual action and blocks pipeline' do
@@ -225,9 +228,9 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there is a skipped manual action in last stage' do
before do
- create_build('rspec 1', :canceled, 0)
- create_build('rspec 2', :skipped, 0, when: :manual, allow_failure: true)
- create_build('staging', :skipped, 1, when: :manual, allow_failure: true)
+ create_build('rspec 1', :canceled, build_stage)
+ create_build('rspec 2', :skipped, build_stage, when: :manual, allow_failure: true)
+ create_build('staging', :skipped, test_stage, when: :manual, allow_failure: true)
end
it 'retries canceled job and reprocesses manual actions' do
@@ -242,8 +245,8 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there is a created manual action in the last stage' do
before do
- create_build('rspec 1', :canceled, 0)
- create_build('staging', :created, 1, when: :manual, allow_failure: true)
+ create_build('rspec 1', :canceled, build_stage)
+ create_build('staging', :created, test_stage, when: :manual, allow_failure: true)
end
it 'retries canceled job and does not update the manual action' do
@@ -257,8 +260,8 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there is a created manual action in the first stage' do
before do
- create_build('rspec 1', :canceled, 0)
- create_build('staging', :created, 0, when: :manual, allow_failure: true)
+ create_build('rspec 1', :canceled, build_stage)
+ create_build('staging', :created, build_stage, when: :manual, allow_failure: true)
end
it 'retries canceled job and processes the manual action' do
@@ -285,9 +288,9 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
end
context 'when pipeline has processables with nil scheduling_type' do
- let!(:build1) { create_build('build1', :success, 0) }
- let!(:build2) { create_build('build2', :failed, 0) }
- let!(:build3) { create_build('build3', :failed, 1) }
+ let!(:build1) { create_build('build1', :success, build_stage) }
+ let!(:build2) { create_build('build2', :failed, build_stage) }
+ let!(:build3) { create_build('build3', :failed, test_stage) }
let!(:build3_needs_build1) { create(:ci_build_need, build: build3, name: build1.name) }
before do
@@ -319,10 +322,10 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there are skipped jobs in later stages' do
before do
- create_build('build 1', :success, 0)
- create_build('test 2', :failed, 1)
- create_build('report 3', :skipped, 2)
- create_bridge('deploy 4', :skipped, 2)
+ create_build('build 1', :success, build_stage)
+ create_build('test 2', :failed, test_stage)
+ create_build('report 3', :skipped, deploy_stage)
+ create_bridge('deploy 4', :skipped, deploy_stage)
end
it 'retries failed jobs and processes skipped jobs' do
@@ -374,9 +377,9 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there is a failed manual action present' do
before do
- create_build('test', :failed, 0)
- create_build('deploy', :failed, 0, when: :manual)
- create_build('verify', :canceled, 1)
+ create_build('test', :failed, build_stage)
+ create_build('deploy', :failed, build_stage, when: :manual)
+ create_build('verify', :canceled, test_stage)
end
it 'returns an error' do
@@ -390,9 +393,9 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context 'when there is a failed manual action in later stage' do
before do
- create_build('test', :failed, 0)
- create_build('deploy', :failed, 1, when: :manual)
- create_build('verify', :canceled, 2)
+ create_build('test', :failed, build_stage)
+ create_build('deploy', :failed, test_stage, when: :manual)
+ create_build('verify', :canceled, deploy_stage)
end
it 'returns an error' do
@@ -418,7 +421,7 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
target_project: project,
source_branch: 'fixes',
allow_collaboration: true)
- create_build('rspec 1', :failed, 1)
+ create_build('rspec 1', :failed, test_stage)
end
it 'allows to retry failed pipeline' do
@@ -441,19 +444,19 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
statuses.latest.find_by(name: name)
end
- def create_build(name, status, stage_num, **opts)
- create_processable(:ci_build, name, status, stage_num, **opts)
+ def create_build(name, status, stage, **opts)
+ create_processable(:ci_build, name, status, stage, **opts)
end
- def create_bridge(name, status, stage_num, **opts)
- create_processable(:ci_bridge, name, status, stage_num, **opts)
+ def create_bridge(name, status, stage, **opts)
+ create_processable(:ci_bridge, name, status, stage, **opts)
end
- def create_processable(type, name, status, stage_num, **opts)
+ def create_processable(type, name, status, stage, **opts)
create(type, name: name,
status: status,
- stage: "stage_#{stage_num}",
- stage_idx: stage_num,
+ ci_stage: stage,
+ stage_idx: stage.position,
pipeline: pipeline, **opts) do |_job|
::Ci::ProcessPipelineService.new(pipeline).execute
end
diff --git a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
index 231204c714d..f7cdc4c61ec 100644
--- a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
+++ b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
@@ -2,7 +2,7 @@
RSpec.shared_examples 'comment on merge request file' do
before do
- stub_feature_flags(remove_user_attributes: false)
+ stub_feature_flags(remove_user_attributes_projects: false)
end
it 'adds a comment' do
diff --git a/spec/support/shared_examples/features/discussion_comments_shared_example.rb b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
index b9cc39c4b9a..f209070d82a 100644
--- a/spec/support/shared_examples/features/discussion_comments_shared_example.rb
+++ b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
@@ -10,10 +10,6 @@ RSpec.shared_examples 'thread comments for commit and snippet' do |resource_name
let(:comments_selector) { '.timeline > .note.timeline-entry:not(.being-posted)' }
let(:comment) { 'My comment' }
- before do
- stub_feature_flags(remove_user_attributes: false)
- end
-
it 'clicking "Comment" will post a comment' do
wait_for_all_requests