Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
fbdcfe539e
commit
704d7cf777
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
Migration/PreventIndexCreation:
|
||||
Details: grace period
|
||||
Exclude:
|
||||
- 'db/migrate/20250428232147_change_unique_contraints_ci_job_artifact_states.rb'
|
||||
- 'db/post_migrate/20240213125219_schedule_index_approval_merge_request_rules_on_config_id_and_id_and_updated_at.rb'
|
||||
- 'db/post_migrate/20240319005754_swap_columns_for_upstream_pipeline_id_between_ci_builds_and_ci_pipelines.rb'
|
||||
- 'db/post_migrate/20240328123442_index_vulnerability_reads_for_vulnerability_export.rb'
|
||||
- 'db/post_migrate/20240402105907_add_index_merge_requests_for_latest_diffs_with_state_merged.rb'
|
||||
- 'db/post_migrate/20240402110451_add_index_on_merge_request_diffs_head_commit_sha.rb'
|
||||
- 'db/post_migrate/20240403005214_add_concurrent_index_merge_requests_for_latest_diffs_with_state_merged.rb'
|
||||
- 'db/post_migrate/20240403005435_add_concurrent_index_on_merge_request_diffs_head_commit_sha.rb'
|
||||
- 'db/post_migrate/20240403020614_prepare_tmp_backfill_index_for_pipeline_ids_to_vulnerability_occurrences.rb'
|
||||
- 'db/post_migrate/20240403104306_add_tmp_backfill_index_for_pipeline_ids_to_vulnerability_occurrences.rb'
|
||||
- 'db/post_migrate/20240416005004_swap_columns_for_p_ci_builds_runner_id.rb'
|
||||
- 'db/post_migrate/20240423235307_swap_columns_for_p_ci_builds_project_id.rb'
|
||||
- 'db/post_migrate/20240424100929_create_indexes_for_merge_request_metrics_pipeline_id_convert_to_bigint.rb'
|
||||
- 'db/post_migrate/20240430015514_swap_columns_for_p_ci_builds_user_id.rb'
|
||||
- 'db/post_migrate/20240610106705_prepare_async_indexes_for_merge_requests_head_pipelines.rb'
|
||||
- 'db/post_migrate/20240702081839_swap_head_pipeline_columns_for_merge_requests_head_pipelines.rb'
|
||||
- 'db/post_migrate/20240714093324_add_index_on_job_artifact_state_verification_state.rb'
|
||||
- 'db/post_migrate/20240819123915_add_index_vulnerability_occurrences_to_support_sbom_services.rb'
|
||||
- 'db/post_migrate/20240821074453_index_ci_job_variables_on_project_id.rb'
|
||||
- 'db/post_migrate/20240828082456_prepare_async_index_to_project_id_in_ci_build_needs.rb'
|
||||
- 'db/post_migrate/20240923114736_prepare_index_for_has_vulnerability_resolution_on_vulnerability_reads.rb'
|
||||
- 'db/post_migrate/20241007114424_add_index_for_has_vulnerability_resolution_on_vulnerability_reads.rb'
|
||||
- 'db/post_migrate/20241014081028_add_index_ci_pipeline_messages_project_id.rb'
|
||||
- 'db/post_migrate/20241016105456_schedule_index_approval_merge_request_rules_on_config_and_approval_policy_rule.rb'
|
||||
- 'db/post_migrate/20241118121418_add_sync_index_to_sbom_occurrences_for_severity_aggregations.rb'
|
||||
- 'db/post_migrate/20241204045404_prepare_async_index_for_p_ci_pipelines_trigger_id.rb'
|
||||
- 'db/post_migrate/20241216064063_prepare_async_tmp_index_for_builds_trigger_request_id.rb'
|
||||
- 'db/post_migrate/20241218062559_index_ci_build_needs_on_project_id.rb'
|
||||
- 'db/post_migrate/20241230011511_sync_tmp_index_for_p_ci_builds_trigger_request_id.rb'
|
||||
- 'db/post_migrate/20241230105009_sync_index_for_p_ci_pipelines_trigger_id.rb'
|
||||
- 'db/post_migrate/20250113060958_sync_indexes_for_ci_pipeline_messages_project_id.rb'
|
||||
- 'db/post_migrate/20250120081541_schedule_indexes_to_web_hook_logs_daily.rb'
|
||||
- 'db/post_migrate/20250129150604_create_todos_coalesced_snoozed_until_created_at_index.rb'
|
||||
- 'db/post_migrate/20250204075753_add_indexes_to_web_hook_logs_daily.rb'
|
||||
- 'db/post_migrate/20250303230228_add_async_index_to_merge_request_diff_files.rb'
|
||||
- 'db/post_migrate/20250319005645_prepare_index_for_p_ci_pipelines_trigger_id_and_id.rb'
|
||||
- 'db/post_migrate/20250331050258_sync_index_for_p_ci_pipeline_trigger_id_and_id.rb'
|
||||
- 'db/post_migrate/20250512110339_replace_tmp_idx_on_maven_packages_with_uniq_idx.rb'
|
||||
- 'db/post_migrate/20250520214740_readd_index_users_for_auditors_for_gitlab_com.rb'
|
||||
- 'db/post_migrate/20250529231801_async_add_index_ci_build_report_results_on_build_id_partition_id.rb'
|
||||
- 'db/post_migrate/20250609181410_change_idx_ci_build_report_results_on_build_id_partition_id.rb'
|
||||
- 'db/post_migrate/20250625234115_prepare_indexes_for_merge_request_diffs_bigint_conversion.rb'
|
||||
|
|
@ -1 +1 @@
|
|||
a02ff0c8d8ae8c137651b6aa326bc2481c02b19b
|
||||
5ea4031481151c6c9d055d7f7097ddeea2948594
|
||||
|
|
|
|||
|
|
@ -326,13 +326,13 @@ module Clusters
|
|||
|
||||
duplicate_management_clusters = management_project.management_clusters
|
||||
.where(environment_scope: environment_scope)
|
||||
.where.not(id: id)
|
||||
.id_not_in(id)
|
||||
|
||||
errors.add(:environment_scope, 'cannot add duplicated environment scope') if duplicate_management_clusters.any?
|
||||
end
|
||||
|
||||
def unique_environment_scope
|
||||
if clusterable.present? && clusterable.clusters.where(environment_scope: environment_scope).where.not(id: id).exists?
|
||||
if clusterable.present? && clusterable.clusters.where(environment_scope: environment_scope).id_not_in(id).exists?
|
||||
errors.add(:environment_scope, 'cannot add duplicated environment scope')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ module Namespaces
|
|||
def descendants
|
||||
return super unless use_traversal_ids?
|
||||
|
||||
self_and_descendants.where.not(id: id)
|
||||
self_and_descendants.id_not_in(id)
|
||||
end
|
||||
|
||||
def self_and_hierarchy
|
||||
|
|
@ -253,12 +253,12 @@ module Namespaces
|
|||
].compact
|
||||
|
||||
roots = Gitlab::ObjectHierarchy
|
||||
.new(Namespace.where(id: parent_ids))
|
||||
.new(Namespace.id_in(parent_ids))
|
||||
.base_and_ancestors
|
||||
.reorder(nil)
|
||||
.top_level
|
||||
|
||||
Namespace.lock('FOR NO KEY UPDATE').select(:id).where(id: roots).order(id: :asc).load
|
||||
Namespace.lock('FOR NO KEY UPDATE').select(:id).id_in(roots).order(id: :asc).load
|
||||
end
|
||||
|
||||
# Search this namespace's lineage. Bound inclusively by top node.
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ module Namespaces
|
|||
|
||||
if upto
|
||||
upto_ancestor_ids = unscoped.where(id: upto).select(unnest_func(Arel.sql('traversal_ids')))
|
||||
records = records.where.not(id: upto_ancestor_ids)
|
||||
records = records.id_not_in(upto_ancestor_ids)
|
||||
end
|
||||
|
||||
records
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module Namespaces
|
|||
if include_self
|
||||
records
|
||||
else
|
||||
records.where.not(id: all.as_ids)
|
||||
records.id_not_in(all.as_ids)
|
||||
end
|
||||
end
|
||||
alias_method :recursive_self_and_ancestors, :self_and_ancestors
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module Organizations
|
|||
|
||||
DEFAULT_ORGANIZATION_ID = 1
|
||||
|
||||
scope :without_default, -> { where.not(id: DEFAULT_ORGANIZATION_ID) }
|
||||
scope :without_default, -> { id_not_in(DEFAULT_ORGANIZATION_ID) }
|
||||
scope :with_namespace_path, ->(path) {
|
||||
joins(namespaces: :route).where(route: { path: path.to_s })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ module Organizations
|
|||
def ensure_user_has_an_organization
|
||||
return unless user
|
||||
|
||||
return unless user.organization_users.where.not(id: id).empty?
|
||||
return unless user.organization_users.id_not_in(id).empty?
|
||||
|
||||
errors.add(:base, _('A user must associate with at least one organization'))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ class PagesDeployment < ApplicationRecord
|
|||
|
||||
# Stop existing active deployment with same path when a deleted one is restored
|
||||
def deactivate_deployments_with_same_path_prefix
|
||||
project.pages_deployments.active.where.not(id: id).with_path_prefix(path_prefix).each(&:deactivate)
|
||||
project.pages_deployments.active.id_not_in(id).with_path_prefix(path_prefix).each(&:deactivate)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ class PoolRepository < ApplicationRecord
|
|||
def unlink_repository(repository, disconnect: true)
|
||||
repository.disconnect_alternates if disconnect
|
||||
|
||||
if member_projects.where.not(id: repository.project.id).exists?
|
||||
if member_projects.id_not_in(repository.project.id).exists?
|
||||
true
|
||||
else
|
||||
mark_obsolete
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ module Preloaders
|
|||
class UserMaxAccessLevelInProjectsPreloader
|
||||
def initialize(projects, user)
|
||||
@projects = if projects.is_a?(Array)
|
||||
Project.where(id: projects)
|
||||
Project.id_in(projects)
|
||||
else
|
||||
# Push projects base query in to a sub-select to avoid
|
||||
# table name clashes. Performs better than aliasing.
|
||||
Project.where(id: projects.subquery(:id))
|
||||
Project.id_in(projects.subquery(:id))
|
||||
end
|
||||
|
||||
@user = user
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ class WikiPage
|
|||
return unless container_id.present? && canonical_slug.present?
|
||||
|
||||
offending = self.class.with_canonical_slug(canonical_slug).where(container_key => container_id)
|
||||
offending = offending.where.not(id: id) if persisted?
|
||||
offending = offending.id_not_in(id) if persisted?
|
||||
|
||||
return unless offending.exists?
|
||||
|
||||
|
|
|
|||
|
|
@ -44,15 +44,13 @@ module Labels
|
|||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def label_ids_for_merge(group_label)
|
||||
LabelsFinder
|
||||
.new(current_user, title: group_label.title, group_id: project.group.id)
|
||||
.execute(skip_authorization: true)
|
||||
.where.not(id: group_label)
|
||||
.id_not_in(group_label)
|
||||
.select(:id, :project_id, :group_id, :type) # Can't use pluck() to avoid object-creation because of the batching
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def update_issuables(group_label, label_ids)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
---
|
||||
name: check_path_traversal_middleware
|
||||
description: Enable middleware that detects and blocks path traversal attempts in HTTP requests
|
||||
feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/13437
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123477
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415460
|
||||
milestone: '16.5'
|
||||
type: development
|
||||
group: group::package registry
|
||||
default_enabled: false
|
||||
type: beta
|
||||
default_enabled: true
|
||||
|
|
@ -160,12 +160,11 @@ For more Kubernetes troubleshooting commands, see the [Kubernetes cheat sheet](h
|
|||
|
||||
## `production_json.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/production_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/production_json.log` on self-compiled installations.
|
||||
|
||||
On Helm Chart installations, the logs are available on the Webservice pods under the `subcomponent="production_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/production_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/production_json.log` file on self-compiled installations.
|
||||
- On the Webservice pods under the `subcomponent="production_json"` key on Helm chart installations.
|
||||
|
||||
It contains a structured log for Rails controller requests received from
|
||||
GitLab, thanks to [Lograge](https://github.com/roidrage/lograge/).
|
||||
|
|
@ -322,10 +321,10 @@ If an error occurs, an
|
|||
|
||||
## `production.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/production.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/production.log` on self-compiled installations.
|
||||
- In the `/var/log/gitlab/gitlab-rails/production.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/production.log` file on self-compiled installations.
|
||||
|
||||
It contains information about all performed requests. You can see the
|
||||
URL and type of request, IP address, and what parts of code were
|
||||
|
|
@ -358,12 +357,11 @@ The request was processed by `Projects::TreeController`.
|
|||
|
||||
## `api_json.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/api_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/api_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Webservice pods under the `subcomponent="api_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/api_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/api_json.log` file on self-compiled installations.
|
||||
- On the Webservice pods under the `subcomponent="api_json"` key on Helm chart installations.
|
||||
|
||||
It helps you see requests made directly to the API. For example:
|
||||
|
||||
|
|
@ -421,10 +419,10 @@ process on Redis or external HTTP, not only the serialization process.
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/application.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/application.log` on self-compiled installations.
|
||||
- In the `/var/log/gitlab/gitlab-rails/application.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/application.log` file on self-compiled installations.
|
||||
|
||||
It contains a less structured version of the logs in
|
||||
[`application_json.log`](#application_jsonlog), like this example:
|
||||
|
|
@ -439,12 +437,11 @@ October 07, 2014 11:25: Project "project133" was removed
|
|||
|
||||
## `application_json.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/application_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/application_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="application_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/application_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/application_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="application_json"` key on Helm chart installations.
|
||||
|
||||
It helps you discover events happening in your instance such as user creation
|
||||
and project deletion. For example:
|
||||
|
|
@ -466,12 +463,11 @@ and project deletion. For example:
|
|||
|
||||
## `integrations_json.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/integrations_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/integrations_json.log` on self-compiled installations.
|
||||
|
||||
On Helm Chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="integrations_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/integrations_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/integrations_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="integrations_json"` key on Helm chart installations.
|
||||
|
||||
It contains information about [integration](../../user/project/integrations/_index.md)
|
||||
activities, such as Jira, Asana, and irker services. It uses JSON format,
|
||||
|
|
@ -507,23 +503,21 @@ like this example:
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/kubernetes.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/kubernetes.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq pods under the `subcomponent="kubernetes"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/kubernetes.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/kubernetes.log` file on self-compiled installations.
|
||||
- On the Sidekiq pods under the `subcomponent="kubernetes"` key on Helm chart installations.
|
||||
|
||||
It logs information related to [certificate-based clusters](../../user/project/clusters/_index.md), such as connectivity errors. Each line contains JSON that can be ingested by services like Elasticsearch and Splunk.
|
||||
|
||||
## `git_json.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/git_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/git_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq pods under the `subcomponent="git_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/git_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/git_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq pods under the `subcomponent="git_json"` key on Helm chart installations.
|
||||
|
||||
GitLab has to interact with Git repositories, but in some rare cases
|
||||
something can go wrong. If this happens, you need to know exactly what
|
||||
|
|
@ -556,12 +550,11 @@ GitLab Premium tracks many more.
|
|||
|
||||
{{< /alert >}}
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/audit_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/audit_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="audit_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/audit_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/audit_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="audit_json"` key on Helm chart installations.
|
||||
|
||||
Changes to group or project settings and memberships (`target_details`)
|
||||
are logged to this file. For example:
|
||||
|
|
@ -596,10 +589,10 @@ and as follows.
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/sidekiq/current` on Linux package installations.
|
||||
- `/home/git/gitlab/log/sidekiq.log` on self-compiled installations.
|
||||
- In the `/var/log/gitlab/sidekiq/current` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/sidekiq.log` file on self-compiled installations.
|
||||
|
||||
GitLab uses background jobs for processing tasks which can take a long
|
||||
time. All information about processing these jobs are written to this
|
||||
|
|
@ -662,12 +655,11 @@ For self-compiled installations, edit the `gitlab.yml` and set the Sidekiq
|
|||
|
||||
### `sidekiq_client.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/sidekiq_client.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/sidekiq_client.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Webservice pods under the `subcomponent="sidekiq_client"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/sidekiq_client.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/sidekiq_client.log` file on self-compiled installations.
|
||||
- On the Webservice pods under the `subcomponent="sidekiq_client"` key on Helm chart installations.
|
||||
|
||||
This file contains logging information about jobs before Sidekiq starts
|
||||
processing them, such as before being enqueued.
|
||||
|
|
@ -757,58 +749,55 @@ failures received during processing of the responses from GitLab API.
|
|||
|
||||
### `puma_stdout.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/puma/puma_stdout.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/puma_stdout.log` on self-compiled installations.
|
||||
- In the `/var/log/gitlab/puma/puma_stdout.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/puma_stdout.log` file on self-compiled installations.
|
||||
|
||||
### `puma_stderr.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/puma/puma_stderr.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/puma_stderr.log` on self-compiled installations.
|
||||
- In the `/var/log/gitlab/puma/puma_stderr.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/puma_stderr.log` file on self-compiled installations.
|
||||
|
||||
## `repocheck.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/repocheck.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/repocheck.log` on self-compiled installations.
|
||||
- In the `/var/log/gitlab/gitlab-rails/repocheck.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/repocheck.log` file on self-compiled installations.
|
||||
|
||||
It logs information whenever a [repository check is run](../repository_checks.md)
|
||||
on a project.
|
||||
|
||||
## `importer.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/importer.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/importer.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq pods under the `subcomponent="importer"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/importer.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/importer.log` file on self-compiled installations.
|
||||
- On the Sidekiq pods under the `subcomponent="importer"` key on Helm chart installations.
|
||||
|
||||
This file logs the progress of [project imports and migrations](../../user/project/import/_index.md).
|
||||
|
||||
## `exporter.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/exporter.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/exporter.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="exporter"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/exporter.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/exporter.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="exporter"` key on Helm chart installations.
|
||||
|
||||
It logs the progress of the export process.
|
||||
|
||||
## `features_json.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/features_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/features_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="features_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/features_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/features_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="features_json"` key on Helm chart installations.
|
||||
|
||||
The modification events from Feature flags in development of GitLab
|
||||
are recorded in this file. For example:
|
||||
|
|
@ -834,12 +823,11 @@ are recorded in this file. For example:
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/ci_resource_groups_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/ci_resource_group_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="ci_resource_groups_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/ci_resource_groups_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/ci_resource_group_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="ci_resource_groups_json"` key on Helm chart installations.
|
||||
|
||||
It contains information about [resource group](../../ci/resource_groups/_index.md) acquisition. For example:
|
||||
|
||||
|
|
@ -852,10 +840,10 @@ The examples show the `resource_group_id`, `processable_id`, `message`, and `suc
|
|||
|
||||
## `auth.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/auth.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/auth.log` on self-compiled installations.
|
||||
- In the `/var/log/gitlab/gitlab-rails/auth.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/auth.log` file on self-compiled installations.
|
||||
|
||||
This log records:
|
||||
|
||||
|
|
@ -865,12 +853,11 @@ This log records:
|
|||
|
||||
## `auth_json.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/auth_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/auth_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="auth_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/auth_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/auth_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="auth_json"` key on Helm chart installations.
|
||||
|
||||
This file contains the JSON version of the logs in `auth.log`, for example:
|
||||
|
||||
|
|
@ -889,12 +876,11 @@ This file contains the JSON version of the logs in `auth.log`, for example:
|
|||
|
||||
## `graphql_json.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/graphql_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/graphql_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="graphql_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/graphql_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/graphql_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="graphql_json"` key on Helm chart installations.
|
||||
|
||||
GraphQL queries are recorded in the file. For example:
|
||||
|
||||
|
|
@ -910,31 +896,30 @@ GraphQL queries are recorded in the file. For example:
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/clickhouse.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/clickhouse.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="clickhouse"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/clickhouse.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/clickhouse.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="clickhouse"` key.
|
||||
|
||||
The `clickhouse.log` file logs information related to the
|
||||
[ClickHouse database client](../../integration/clickhouse.md) in GitLab.
|
||||
|
||||
## `migrations.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/migrations.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/migrations.log` on self-compiled installations.
|
||||
- In the `/var/log/gitlab/gitlab-rails/migrations.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/migrations.log` file on self-compiled installations.
|
||||
|
||||
This file logs the progress of [database migrations](../raketasks/maintenance.md#display-status-of-database-migrations).
|
||||
|
||||
## `mail_room_json.log` (default)
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/mailroom/current` on Linux package installations.
|
||||
- `/home/git/gitlab/log/mail_room_json.log` on self-compiled installations.
|
||||
- In the `/var/log/gitlab/mailroom/current` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/mail_room_json.log` file on self-compiled installations.
|
||||
|
||||
This structured log file records internal activity in the `mail_room` gem.
|
||||
Its name and path are configurable, so the name and path may not match this one
|
||||
|
|
@ -948,12 +933,11 @@ documented previously.
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/web_hooks.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/web_hooks.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq pods under the `subcomponent="web_hooks"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/web_hooks.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/web_hooks.log` file on self-compiled installations.
|
||||
- On the Sidekiq pods under the `subcomponent="web_hooks"` key on Helm chart installations.
|
||||
|
||||
The back-off, disablement, and re-enablement events for Webhook are recorded in this file. For example:
|
||||
|
||||
|
|
@ -1005,12 +989,11 @@ are generated in a location based on your installation method:
|
|||
|
||||
Contains details of GitLab [Database Load Balancing](../postgresql/database_load_balancing.md).
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/database_load_balancing.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/database_load_balancing.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="database_load_balancing"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/database_load_balancing.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/database_load_balancing.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="database_load_balancing"` key on Helm chart installations.
|
||||
|
||||
## `zoekt.log`
|
||||
|
||||
|
|
@ -1028,12 +1011,12 @@ On Helm chart installations, the logs are available on the Sidekiq and Webservic
|
|||
{{< /history >}}
|
||||
|
||||
This file logs information related to [exact code search](../../user/search/exact_code_search.md).
|
||||
This file is located at:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/zoekt.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/zoekt.log` on self-compiled installations.
|
||||
This log is located:
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="zoekt"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/zoekt.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/zoekt.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="zoekt"` key on Helm chart installations.
|
||||
|
||||
## `elasticsearch.log`
|
||||
|
||||
|
|
@ -1047,12 +1030,11 @@ On Helm chart installations, the logs are available on the Sidekiq and Webservic
|
|||
This file logs information related to the Elasticsearch Integration, including
|
||||
errors during indexing or searching Elasticsearch.
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/elasticsearch.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/elasticsearch.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="elasticsearch"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/elasticsearch.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/elasticsearch.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="elasticsearch"` key on Helm chart installations.
|
||||
|
||||
Each line contains JSON that can be ingested by services like Elasticsearch and Splunk.
|
||||
Line breaks have been added to the following example line for clarity:
|
||||
|
|
@ -1076,12 +1058,12 @@ Line breaks have been added to the following example line for clarity:
|
|||
This file logs the information about exceptions being tracked by
|
||||
`Gitlab::ErrorTracking`, which provides a standard and consistent way of
|
||||
processing rescued exceptions.
|
||||
This file is located at:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/exceptions_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/exceptions_json.log` on self-compiled installations.
|
||||
This log is located:
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="exceptions_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/exceptions_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/exceptions_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="exceptions_json"` key on Helm chart installations.
|
||||
|
||||
Each line contains JSON that can be ingested by Elasticsearch. For example:
|
||||
|
||||
|
|
@ -1104,12 +1086,11 @@ Each line contains JSON that can be ingested by Elasticsearch. For example:
|
|||
|
||||
## `service_measurement.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/service_measurement.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/service_measurement.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="service_measurement"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/service_measurement.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/service_measurement.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="service_measurement"` key on Helm chart installations.
|
||||
|
||||
It contains only a single structured log with measurements for each service execution.
|
||||
It contains measurements such as the number of SQL calls, `execution_time`, `gc_stats`, and `memory usage`.
|
||||
|
|
@ -1129,12 +1110,11 @@ For example:
|
|||
|
||||
{{< /details >}}
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/geo.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/geo.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="geo"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/geo.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/geo.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="geo"` key on Helm chart installations.
|
||||
|
||||
This file contains information about when Geo attempts to sync repositories
|
||||
and files. Each line in the file contains a separate JSON entry that can be
|
||||
|
|
@ -1150,12 +1130,11 @@ This message shows that Geo detected that a repository update was needed for pro
|
|||
|
||||
## `update_mirror_service_json.log`
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/update_mirror_service_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/update_mirror_service_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq pods under the `subcomponent="update_mirror_service_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/update_mirror_service_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/update_mirror_service_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq pods under the `subcomponent="update_mirror_service_json"` key on Helm chart installations.
|
||||
|
||||
This file contains information about LFS errors that occurred during project mirroring.
|
||||
While we work to move other project mirroring errors into this log, the [general log](#productionlog)
|
||||
|
|
@ -1216,10 +1195,9 @@ By default, the log does not contain LLM prompt input and response output to sup
|
|||
|
||||
The log file is located at:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/llm.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/llm.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Webservice pods under the `subcomponent="llm"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/llm.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/llm.log` file on self-compiled installations.
|
||||
- On the Webservice pods under the `subcomponent="llm"` key on Helm chart installations.
|
||||
|
||||
## `epic_work_item_sync.log`
|
||||
|
||||
|
|
@ -1238,12 +1216,11 @@ On Helm chart installations, the logs are available on the Webservice pods under
|
|||
|
||||
The `epic_work_item_sync.log` file logs information related to syncing and migrating epics as work items.
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/epic_work_item_sync.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/epic_work_item_sync.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq and Webservice pods under the `subcomponent="epic_work_item_sync"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/epic_work_item_sync.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/epic_work_item_sync.log` file on self-compiled installations.
|
||||
- On the Sidekiq and Webservice pods under the `subcomponent="epic_work_item_sync"` key on Helm chart installations.
|
||||
|
||||
## `secret_push_protection.log`
|
||||
|
||||
|
|
@ -1262,12 +1239,11 @@ On Helm chart installations, the logs are available on the Sidekiq and Webservic
|
|||
|
||||
The `secret_push_protection.log` file logs information related to [Secret Push Protection](../../user/application_security/secret_detection/secret_push_protection/_index.md) feature.
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/secret_push_protection.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/secret_push_protection.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Webservice pods under the `subcomponent="secret_push_protection"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/secret_push_protection.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/secret_push_protection.log` file on self-compiled installations.
|
||||
- On the Webservice pods under the `subcomponent="secret_push_protection"` key on Helm chart installations.
|
||||
|
||||
## Registry logs
|
||||
|
||||
|
|
@ -1335,12 +1311,11 @@ The list of events can change in each version based on new features or changes t
|
|||
|
||||
{{< /alert >}}
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/product_usage_data.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/product_usage_data.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Webservice pods under the `subcomponent="product_usage_data"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/product_usage_data.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/product_usage_data.log` file on self-compiled installations.
|
||||
- On the Webservice pods under the `subcomponent="product_usage_data"` key on Helm chart installations.
|
||||
|
||||
It contains JSON-formatted logs of product usage events tracked through Snowplow. Each line in the file contains a separate JSON entry that can be ingested by services like Elasticsearch or Splunk. Line breaks were added to examples for legibility:
|
||||
|
||||
|
|
@ -1464,12 +1439,11 @@ This log is populated when a [GitLab backup is created](../backup_restore/_index
|
|||
|
||||
## Performance bar stats
|
||||
|
||||
This file is located at:
|
||||
This log is located:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/performance_bar_json.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/performance_bar_json.log` on self-compiled installations.
|
||||
|
||||
On Helm chart installations, the logs are available on the Sidekiq pods under the `subcomponent="performance_bar_json"` key.
|
||||
- In the `/var/log/gitlab/gitlab-rails/performance_bar_json.log` file on Linux package installations.
|
||||
- In the `/home/git/gitlab/log/performance_bar_json.log` file on self-compiled installations.
|
||||
- On the Sidekiq pods under the `subcomponent="performance_bar_json"` key on Helm chart installations.
|
||||
|
||||
Performance bar statistics (currently only duration of SQL queries) are recorded
|
||||
in that file. For example:
|
||||
|
|
|
|||
|
|
@ -1340,22 +1340,42 @@ efficient:
|
|||
```ruby
|
||||
class AddSecretToSomething < Gitlab::Database::Migration[2.1]
|
||||
def change
|
||||
add_column :something, :secret, :jsonb
|
||||
add_column :something, :secret, :jsonb, null: true
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
When storing encrypted attributes in a JSONB column, it's good to add a length validation that
|
||||
[follows the Active Record Encryption recommendations](https://guides.rubyonrails.org/active_record_encryption.html#important-about-storage-and-column-size).
|
||||
For most encrypted attributes, a 510 max length should be enough.
|
||||
When storing encrypted attributes in a JSONB column, you need to:
|
||||
|
||||
1. Add JSON schema validation
|
||||
1. Add length validation following [Active Record Encryption recommendations](https://guides.rubyonrails.org/active_record_encryption.html#important-about-storage-and-column-size)
|
||||
1. Allow `nil` values if the attribute is optional
|
||||
|
||||
### Model Configuration
|
||||
|
||||
```ruby
|
||||
class Something < ApplicationRecord
|
||||
encrypts :secret
|
||||
validates :secret, length: { maximum: 510 }
|
||||
validates :secret,
|
||||
json_schema: { filename: 'something_secret' },
|
||||
allow_nil: true,
|
||||
length: { maximum: 510 }
|
||||
end
|
||||
```
|
||||
|
||||
### JSON Schema
|
||||
|
||||
Create a JSON schema file at `config/json_schemas/something_secret.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Secret Configuration",
|
||||
"type": "string",
|
||||
"description": "Encrypted secret value"
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
See the [Testing Rails migrations](testing_guide/testing_migrations_guide.md) style guide.
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ module API
|
|||
use :pagination
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def find_groups(params, parent_id = nil)
|
||||
find_params = params.slice(*allowable_find_params)
|
||||
|
||||
|
|
@ -52,11 +51,10 @@ module API
|
|||
find_params.fetch(:all_available, current_user&.can_read_all_resources?)
|
||||
|
||||
groups = GroupsFinder.new(current_user, find_params).execute
|
||||
groups = groups.where.not(id: params[:skip_groups]) if params[:skip_groups].present?
|
||||
groups = groups.id_not_in(params[:skip_groups]) if params[:skip_groups].present?
|
||||
|
||||
order_groups(groups).with_api_scopes
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def allowable_find_params
|
||||
[:all_available,
|
||||
|
|
|
|||
|
|
@ -410,20 +410,18 @@ module API
|
|||
optional :username, type: String, desc: 'The username of the user'
|
||||
use :optional_attributes
|
||||
end
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
|
||||
put ":id", feature_category: :user_profile do
|
||||
authenticated_as_admin!
|
||||
|
||||
user = User.find_by(id: params.delete(:id))
|
||||
user = User.find_by_id(params.delete(:id))
|
||||
not_found!('User') unless user
|
||||
|
||||
conflict!('Email has already been taken') if params[:email] &&
|
||||
User.by_any_email(params[:email].downcase)
|
||||
.where.not(id: user.id).exists?
|
||||
User.by_any_email(params[:email].downcase).id_not_in(user.id).exists?
|
||||
|
||||
conflict!('Username has already been taken') if params[:username] &&
|
||||
User.by_username(params[:username])
|
||||
.where.not(id: user.id).exists?
|
||||
User.by_username(params[:username]).id_not_in(user.id).exists?
|
||||
|
||||
user_params = declared_params(include_missing: false)
|
||||
|
||||
|
|
@ -451,7 +449,6 @@ module API
|
|||
render_validation_error!(user)
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
desc "Disable two factor authentication for a user. Available only for admins" do
|
||||
detail 'This feature was added in GitLab 15.2'
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ module Backup
|
|||
end
|
||||
|
||||
def skipped_path_relation
|
||||
Project.where.not(id: Project.where_full_path_in(skip_paths).or(
|
||||
Project.id_not_in(Project.where_full_path_in(skip_paths).or(
|
||||
Project.where(namespace_id: Namespace.where_full_path_in(skip_paths).self_and_descendants)
|
||||
))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,11 +25,9 @@ module Gitlab
|
|||
|
||||
# Returns the set of descendants of a given relation, but excluding the given
|
||||
# relation
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def descendants
|
||||
base_and_descendants.where.not(id: descendants_base.select(:id))
|
||||
base_and_descendants.id_not_in(descendants_base.select(:id))
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
# Returns the maximum depth starting from the base
|
||||
# A base object with no children has a maximum depth of `1`
|
||||
|
|
@ -43,11 +41,9 @@ module Gitlab
|
|||
# Passing an `upto` will stop the recursion once the specified parent_id is
|
||||
# reached. So all ancestors *lower* than the specified ancestor will be
|
||||
# included.
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def ancestors(upto: nil, hierarchy_order: nil)
|
||||
base_and_ancestors(upto: upto, hierarchy_order: hierarchy_order).where.not(id: ancestors_base.select(:id))
|
||||
base_and_ancestors(upto: upto, hierarchy_order: hierarchy_order).id_not_in(ancestors_base.select(:id))
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
# Returns a relation that includes the ancestors_base set of objects
|
||||
# and all their ancestors (recursively).
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ module Gitlab
|
|||
label_id = label_ids.first
|
||||
|
||||
@updates[:remove_label_ids] =
|
||||
quick_action_target.labels.on_project_boards(quick_action_target.project_id).where.not(id: label_id).pluck(:id) # rubocop: disable CodeReuse/ActiveRecord
|
||||
quick_action_target.labels.on_project_boards(quick_action_target.project_id).id_not_in(label_id).pluck(:id) # rubocop: disable CodeReuse/ActiveRecord
|
||||
@updates[:add_label_ids] = [label_id]
|
||||
|
||||
message = _("Moved issue to %{label} column in the board.") % { label: labels_to_reference(labels).first }
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ module RuboCop
|
|||
PATTERN
|
||||
|
||||
def on_casgn(node)
|
||||
@forbidden_tables_used = !!forbidden_constant_defined?(node)
|
||||
@forbidden_tables_used ||= !!forbidden_constant_defined?(node)
|
||||
end
|
||||
|
||||
def on_def(node)
|
||||
|
|
@ -84,10 +84,12 @@ module RuboCop
|
|||
end
|
||||
|
||||
def offense?(node)
|
||||
add_index?(node) ||
|
||||
add_concurrent_index?(node) ||
|
||||
prepare_async_index?(node) ||
|
||||
any_constant_used_with_forbidden_tables?(node)
|
||||
return true if add_index?(node)
|
||||
return true if add_concurrent_index?(node)
|
||||
return true if prepare_async_index?(node)
|
||||
return true if any_constant_used_with_forbidden_tables?(node)
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def any_constant_used_with_forbidden_tables?(node)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export const createTestPiniaAction =
|
|||
});
|
||||
} else {
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(actionCalls.length).toBe(0);
|
||||
expect(actionCalls).toHaveLength(0);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ describe('Vue test utils helpers', () => {
|
|||
resultWrapper.options === wrapper.options,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(result.length).toBe(3);
|
||||
expect(result).toHaveLength(3);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ describe('Vue test utils helpers', () => {
|
|||
const result = wrapper[findMethod](text, options);
|
||||
|
||||
expect(result).toBeInstanceOf(VTUWrapperArray);
|
||||
expect(result.length).toBe(0);
|
||||
expect(result).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -311,7 +311,7 @@ describe('Vue test utils helpers', () => {
|
|||
it('mounts component and provides extended queries', () => {
|
||||
const wrapper = mountExtended(FakeComponent);
|
||||
expect(wrapper.text()).toBe('Foo Bar');
|
||||
expect(wrapper.findAllByTestId('fake-id').length).toBe(2);
|
||||
expect(wrapper.findAllByTestId('fake-id')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -319,7 +319,7 @@ describe('Vue test utils helpers', () => {
|
|||
it('shallow mounts component and provides extended queries', () => {
|
||||
const wrapper = shallowMountExtended(FakeComponent);
|
||||
expect(wrapper.text()).toBe('Foo');
|
||||
expect(wrapper.findAllByTestId('fake-id').length).toBe(1);
|
||||
expect(wrapper.findAllByTestId('fake-id')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ describe('Achievements app', () => {
|
|||
|
||||
const achievements = wrapper.findAllComponents(CrudComponent);
|
||||
|
||||
expect(achievements.length).toBe(3);
|
||||
expect(achievements).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('should render the correct achievement name and avatar (when present)', async () => {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,6 @@ describe('ReviewTabContainer', () => {
|
|||
|
||||
it('renders all passed commits as list', () => {
|
||||
createWrapper({ commits: [commit] });
|
||||
expect(wrapper.findAllComponents(CommitItem).length).toBe(1);
|
||||
expect(wrapper.findAllComponents(CommitItem)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ describe('AbuseReportsApp', () => {
|
|||
createComponent();
|
||||
|
||||
expect(findEmptyState().exists()).toBe(false);
|
||||
expect(findAbuseReportRows().length).toBe(mockAbuseReports.length);
|
||||
expect(findAbuseReportRows()).toHaveLength(mockAbuseReports.length);
|
||||
});
|
||||
|
||||
it('renders empty state when there are no reports', () => {
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ describe('AlertManagementTable', () => {
|
|||
},
|
||||
loading: false,
|
||||
});
|
||||
expect(findDateFields().length).toBe(1);
|
||||
expect(findDateFields()).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should not display time ago dates when values not provided', () => {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ describe('AlertIntegrationsList', () => {
|
|||
});
|
||||
|
||||
it('renders an an edit and delete button for each integration', () => {
|
||||
expect(findTableComponent().findAllComponents(GlButton).length).toBe(4);
|
||||
expect(findTableComponent().findAllComponents(GlButton)).toHaveLength(4);
|
||||
});
|
||||
|
||||
describe('integration status', () => {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ describe('Project PathNavigation', () => {
|
|||
|
||||
it('renders each stage', () => {
|
||||
const result = findPathNavigationTitles();
|
||||
expect(result.length).toBe(transformedProjectStagePathData.length);
|
||||
expect(result).toHaveLength(transformedProjectStagePathData.length);
|
||||
});
|
||||
|
||||
it('renders each stage with its median', () => {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ describe('Value stream analytics utils', () => {
|
|||
describe('transforms the data as expected', () => {
|
||||
it('returns an array of stages', () => {
|
||||
expect(Array.isArray(response)).toBe(true);
|
||||
expect(response.length).toBe(stages.length);
|
||||
expect(response).toHaveLength(stages.length);
|
||||
});
|
||||
|
||||
it('selects the correct stage', () => {
|
||||
|
|
|
|||
|
|
@ -218,8 +218,8 @@ describe('ProjectsDropdownFilter component', () => {
|
|||
});
|
||||
|
||||
it('hides the unhighlighted items that do not match the string', () => {
|
||||
expect(wrapper.find(`[name="Selected"]`).findAllComponents(GlListboxItem).length).toBe(1);
|
||||
expect(wrapper.find(`[name="Unselected"]`).findAllComponents(GlListboxItem).length).toBe(0);
|
||||
expect(wrapper.find(`[name="Selected"]`).findAllComponents(GlListboxItem)).toHaveLength(1);
|
||||
expect(wrapper.find(`[name="Unselected"]`).findAllComponents(GlListboxItem)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ describe('Api', () => {
|
|||
|
||||
return new Promise((resolve) => {
|
||||
Api.groups(query, options, (response) => {
|
||||
expect(response.length).toBe(1);
|
||||
expect(response).toHaveLength(1);
|
||||
expect(response[0].name).toBe('test');
|
||||
resolve();
|
||||
});
|
||||
|
|
@ -336,7 +336,7 @@ describe('Api', () => {
|
|||
]);
|
||||
|
||||
return Api.groupLabels(expectedGroup, options).then((res) => {
|
||||
expect(res.length).toBe(1);
|
||||
expect(res).toHaveLength(1);
|
||||
expect(res[0].name).toBe('Foo Label');
|
||||
});
|
||||
});
|
||||
|
|
@ -354,7 +354,7 @@ describe('Api', () => {
|
|||
|
||||
return new Promise((resolve) => {
|
||||
Api.namespaces(query, {}, (response) => {
|
||||
expect(response.length).toBe(1);
|
||||
expect(response).toHaveLength(1);
|
||||
expect(response[0].name).toBe('test');
|
||||
resolve();
|
||||
});
|
||||
|
|
@ -376,7 +376,7 @@ describe('Api', () => {
|
|||
|
||||
return new Promise((resolve) => {
|
||||
Api.projects(query, options, (response) => {
|
||||
expect(response.length).toBe(1);
|
||||
expect(response).toHaveLength(1);
|
||||
expect(response[0].name).toBe('test');
|
||||
resolve();
|
||||
});
|
||||
|
|
@ -395,7 +395,7 @@ describe('Api', () => {
|
|||
|
||||
return new Promise((resolve) => {
|
||||
Api.projects(query, options, (response) => {
|
||||
expect(response.length).toBe(1);
|
||||
expect(response).toHaveLength(1);
|
||||
expect(response[0].name).toBe('test');
|
||||
resolve();
|
||||
});
|
||||
|
|
@ -428,7 +428,7 @@ describe('Api', () => {
|
|||
]);
|
||||
|
||||
return Api.projectUsers('gitlab-org/gitlab-ce', query, options).then((response) => {
|
||||
expect(response.length).toBe(1);
|
||||
expect(response).toHaveLength(1);
|
||||
expect(response[0].name).toBe('test');
|
||||
});
|
||||
});
|
||||
|
|
@ -442,7 +442,7 @@ describe('Api', () => {
|
|||
const mockData = [{ source_branch: 'foo' }, { source_branch: 'bar' }];
|
||||
mock.onGet(expectedUrl).reply(HTTP_STATUS_OK, mockData);
|
||||
return Api.projectMergeRequests(projectPath).then(({ data }) => {
|
||||
expect(data.length).toEqual(2);
|
||||
expect(data).toHaveLength(2);
|
||||
expect(data[0].source_branch).toBe('foo');
|
||||
expect(data[1].source_branch).toBe('bar');
|
||||
});
|
||||
|
|
@ -456,7 +456,7 @@ describe('Api', () => {
|
|||
mock.onGet(expectedUrl, { params }).reply(HTTP_STATUS_OK, mockData);
|
||||
|
||||
return Api.projectMergeRequests(projectPath, params).then(({ data }) => {
|
||||
expect(data.length).toEqual(1);
|
||||
expect(data).toHaveLength(1);
|
||||
expect(data[0].source_branch).toBe('bar');
|
||||
});
|
||||
});
|
||||
|
|
@ -504,7 +504,7 @@ describe('Api', () => {
|
|||
]);
|
||||
|
||||
return Api.projectMergeRequestVersions(projectPath, mergeRequestId).then(({ data }) => {
|
||||
expect(data.length).toBe(1);
|
||||
expect(data).toHaveLength(1);
|
||||
expect(data[0].id).toBe(123);
|
||||
});
|
||||
});
|
||||
|
|
@ -563,7 +563,7 @@ describe('Api', () => {
|
|||
]);
|
||||
|
||||
return Api.projectMilestones(projectId, options).then(({ data }) => {
|
||||
expect(data.length).toBe(1);
|
||||
expect(data).toHaveLength(1);
|
||||
expect(data[0].title).toBe('milestone1');
|
||||
});
|
||||
});
|
||||
|
|
@ -675,7 +675,7 @@ describe('Api', () => {
|
|||
]);
|
||||
|
||||
return Api.groupProjects(groupId, query, {}).then((response) => {
|
||||
expect(response.data.length).toBe(1);
|
||||
expect(response.data).toHaveLength(1);
|
||||
expect(response.data[0].name).toBe('test');
|
||||
});
|
||||
});
|
||||
|
|
@ -787,7 +787,7 @@ describe('Api', () => {
|
|||
|
||||
return new Promise((resolve) => {
|
||||
Api.issueTemplates(namespace, project, templateType, (_, response) => {
|
||||
expect(response.length).toBe(1);
|
||||
expect(response).toHaveLength(1);
|
||||
const { key, name, content } = response[0];
|
||||
expect(key).toBe('Template1');
|
||||
expect(name).toBe('Template 1');
|
||||
|
|
@ -857,7 +857,7 @@ describe('Api', () => {
|
|||
]);
|
||||
|
||||
return Api.users(query, options).then(({ data }) => {
|
||||
expect(data.length).toBe(1);
|
||||
expect(data).toHaveLength(1);
|
||||
expect(data[0].name).toBe('test');
|
||||
});
|
||||
});
|
||||
|
|
@ -918,7 +918,7 @@ describe('Api', () => {
|
|||
|
||||
return new Promise((resolve) => {
|
||||
Api.userProjects(userId, query, options, (response) => {
|
||||
expect(response.length).toBe(1);
|
||||
expect(response).toHaveLength(1);
|
||||
expect(response[0].name).toBe('test');
|
||||
resolve();
|
||||
});
|
||||
|
|
@ -938,7 +938,7 @@ describe('Api', () => {
|
|||
]);
|
||||
|
||||
return Api.commitPipelines(projectId, commitSha).then(({ data }) => {
|
||||
expect(data.length).toBe(1);
|
||||
expect(data).toHaveLength(1);
|
||||
expect(data[0].name).toBe('test');
|
||||
});
|
||||
});
|
||||
|
|
@ -1372,7 +1372,7 @@ describe('Api', () => {
|
|||
]);
|
||||
|
||||
return Api.tags(projectId, query, options).then(({ data }) => {
|
||||
expect(data.length).toBe(1);
|
||||
expect(data).toHaveLength(1);
|
||||
expect(data[0].name).toBe('test');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -120,10 +120,10 @@ describe('AwardsHandler', () => {
|
|||
|
||||
const $emojiMenu = $('.emoji-menu');
|
||||
|
||||
expect($emojiMenu.length).toBe(1);
|
||||
expect($emojiMenu).toHaveLength(1);
|
||||
expect($emojiMenu.hasClass('is-visible')).toBe(true);
|
||||
expect($emojiMenu.find('.js-emoji-menu-search').length).toBe(1);
|
||||
expect($('.js-awards-block.current').length).toBe(1);
|
||||
expect($emojiMenu.find('.js-emoji-menu-search')).toHaveLength(1);
|
||||
expect($('.js-awards-block.current')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should also show emoji menu for the smiley icon in notes', async () => {
|
||||
|
|
@ -131,7 +131,7 @@ describe('AwardsHandler', () => {
|
|||
|
||||
const $emojiMenu = $('.emoji-menu');
|
||||
|
||||
expect($emojiMenu.length).toBe(1);
|
||||
expect($emojiMenu).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should remove emoji menu when body is clicked', async () => {
|
||||
|
|
@ -140,9 +140,9 @@ describe('AwardsHandler', () => {
|
|||
const $emojiMenu = $('.emoji-menu');
|
||||
$('body').click();
|
||||
|
||||
expect($emojiMenu.length).toBe(1);
|
||||
expect($emojiMenu).toHaveLength(1);
|
||||
expect($emojiMenu.hasClass('is-visible')).toBe(false);
|
||||
expect($('.js-awards-block.current').length).toBe(0);
|
||||
expect($('.js-awards-block.current')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should not remove emoji menu when search is clicked', async () => {
|
||||
|
|
@ -151,9 +151,9 @@ describe('AwardsHandler', () => {
|
|||
const $emojiMenu = $('.emoji-menu');
|
||||
$('.emoji-search').click();
|
||||
|
||||
expect($emojiMenu.length).toBe(1);
|
||||
expect($emojiMenu).toHaveLength(1);
|
||||
expect($emojiMenu.hasClass('is-visible')).toBe(true);
|
||||
expect($('.js-awards-block.current').length).toBe(1);
|
||||
expect($('.js-awards-block.current')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ describe('AwardsHandler', () => {
|
|||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart');
|
||||
const $emojiButton = $votesBlock.find('[data-name=heart]');
|
||||
|
||||
expect($emojiButton.length).toBe(1);
|
||||
expect($emojiButton).toHaveLength(1);
|
||||
expect($emojiButton.next('.js-counter').text()).toBe('1');
|
||||
expect($votesBlock.hasClass('hidden')).toBe(false);
|
||||
});
|
||||
|
|
@ -174,7 +174,7 @@ describe('AwardsHandler', () => {
|
|||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart');
|
||||
const $emojiButton = $votesBlock.find('[data-name=heart]');
|
||||
|
||||
expect($emojiButton.length).toBe(0);
|
||||
expect($emojiButton).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should decrement the emoji counter', () => {
|
||||
|
|
@ -184,7 +184,7 @@ describe('AwardsHandler', () => {
|
|||
$emojiButton.next('.js-counter').text(5);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart');
|
||||
|
||||
expect($emojiButton.length).toBe(1);
|
||||
expect($emojiButton).toHaveLength(1);
|
||||
expect($emojiButton.next('.js-counter').text()).toBe('4');
|
||||
});
|
||||
});
|
||||
|
|
@ -222,10 +222,10 @@ describe('AwardsHandler', () => {
|
|||
const $votesBlock = $('.js-awards-block').eq(0);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, 'fire');
|
||||
|
||||
expect($votesBlock.find('[data-name=fire]').length).toBe(1);
|
||||
expect($votesBlock.find('[data-name=fire]')).toHaveLength(1);
|
||||
awardsHandler.removeEmoji($votesBlock.find('[data-name=fire]').closest('button'));
|
||||
|
||||
expect($votesBlock.find('[data-name=fire]').length).toBe(0);
|
||||
expect($votesBlock.find('[data-name=fire]')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -346,12 +346,12 @@ describe('AwardsHandler', () => {
|
|||
const $block = $('.js-awards-block');
|
||||
const $emoji = $menu.find(`.emoji-menu-list:not(.frequent-emojis) ${emojiSelector}`);
|
||||
|
||||
expect($emoji.length).toBe(1);
|
||||
expect($block.find(emojiSelector).length).toBe(0);
|
||||
expect($emoji).toHaveLength(1);
|
||||
expect($block.find(emojiSelector)).toHaveLength(0);
|
||||
$emoji.click();
|
||||
|
||||
expect($menu.hasClass('.is-visible')).toBe(false);
|
||||
expect($block.find(emojiSelector).length).toBe(1);
|
||||
expect($block.find(emojiSelector)).toHaveLength(1);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -369,7 +369,7 @@ describe('AwardsHandler', () => {
|
|||
);
|
||||
$emoji.click();
|
||||
|
||||
expect($block.find(emojiSelector).length).toBe(0);
|
||||
expect($block.find(emojiSelector)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ describe('Badges store actions', () => {
|
|||
badgeInForm.linkUrl = "https://example.com?param=<script>alert('XSS')</script>";
|
||||
|
||||
await actions.renderBadge({ state, dispatch });
|
||||
expect(axios.get.mock.calls.length).toBe(1);
|
||||
expect(axios.get.mock.calls).toHaveLength(1);
|
||||
const url = axios.get.mock.calls[0][0];
|
||||
|
||||
expect(url).toContain(
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ describe('Badges store mutations', () => {
|
|||
|
||||
store.commit(types.RECEIVE_DELETE_BADGE_ERROR, dummyBadge.id);
|
||||
|
||||
expect(store.state.badges.length).toBe(badgeCount);
|
||||
expect(store.state.badges).toHaveLength(badgeCount);
|
||||
expect(store.state.badges[0].isDeleting).toBe(false);
|
||||
expect(store.state.badges[1].isDeleting).toBe(false);
|
||||
expect(store.state.badges[2].isDeleting).toBe(true);
|
||||
|
|
@ -177,7 +177,7 @@ describe('Badges store mutations', () => {
|
|||
|
||||
store.commit(types.RECEIVE_UPDATED_BADGE, newBadge);
|
||||
|
||||
expect(store.state.badges.length).toBe(badgeCount);
|
||||
expect(store.state.badges).toHaveLength(badgeCount);
|
||||
expect(store.state.badges[badgeIndex]).toStrictEqual(newBadge);
|
||||
});
|
||||
});
|
||||
|
|
@ -216,7 +216,7 @@ describe('Badges store mutations', () => {
|
|||
|
||||
store.commit(types.REQUEST_DELETE_BADGE, dummyBadge.id);
|
||||
|
||||
expect(store.state.badges.length).toBe(badgeCount);
|
||||
expect(store.state.badges).toHaveLength(badgeCount);
|
||||
expect(store.state.badges[0].isDeleting).toBe(false);
|
||||
expect(store.state.badges[1].isDeleting).toBe(true);
|
||||
expect(store.state.badges[2].isDeleting).toBe(true);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ describe('Batch comments diff file drafts component', () => {
|
|||
it('renders list of draft notes', () => {
|
||||
factory();
|
||||
|
||||
expect(wrapper.findAllComponents(DraftNote).length).toEqual(2);
|
||||
expect(wrapper.findAllComponents(DraftNote)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('renders index of draft note', () => {
|
||||
|
|
@ -48,7 +48,7 @@ describe('Batch comments diff file drafts component', () => {
|
|||
|
||||
const elements = wrapper.findAllComponents(DesignNotePin);
|
||||
|
||||
expect(elements.length).toEqual(2);
|
||||
expect(elements).toHaveLength(2);
|
||||
|
||||
expect(elements.at(0).props('label')).toEqual(1);
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ describe('BindInOut', () => {
|
|||
});
|
||||
|
||||
it('should call .init for each element', () => {
|
||||
expect(BindInOut.init.mock.calls.length).toEqual(3);
|
||||
expect(BindInOut.init.mock.calls).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('should return an array of instances', () => {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ describe('GlobalAlerts', () => {
|
|||
wrapper.findComponent(GlAlert).vm.$emit('dismiss');
|
||||
await nextTick();
|
||||
|
||||
expect(findAllAlerts().length).toBe(1);
|
||||
expect(findAllAlerts()).toHaveLength(1);
|
||||
expect(removeGlobalAlertById).toHaveBeenCalledWith(alert1.id);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ describe('date_picker behavior', () => {
|
|||
it('Instantiates Pickaday for every instance of a .datepicker class', () => {
|
||||
initDatePickers();
|
||||
|
||||
expect(pikadayMock.mock.calls.length).toEqual(2);
|
||||
expect(pikadayMock.mock.calls).toHaveLength(2);
|
||||
expect(parseMock.mock.calls).toEqual([['2020-10-01'], ['']]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ describe('highlightCurrentUser', () => {
|
|||
it('highlights current user', () => {
|
||||
highlightCurrentUser(elements);
|
||||
|
||||
expect(elements.length).toBe(2);
|
||||
expect(elements).toHaveLength(2);
|
||||
expect(elements[0]).not.toHaveClass('current-user');
|
||||
expect(elements[1]).toHaveClass('current-user');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ describe('Blob Header Default Actions', () => {
|
|||
});
|
||||
|
||||
it('exactly 3 buttons with predefined actions', () => {
|
||||
expect(buttons.length).toBe(3);
|
||||
expect(buttons).toHaveLength(3);
|
||||
[BTN_COPY_CONTENTS_TITLE, BTN_RAW_TITLE, BTN_DOWNLOAD_TITLE].forEach((title, i) => {
|
||||
expect(buttons.at(i).attributes('title')).toBe(title);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ describe('Blob Header Viewer Switcher', () => {
|
|||
});
|
||||
|
||||
it('renders exactly 2 buttons with predefined actions', () => {
|
||||
expect(buttons.length).toBe(2);
|
||||
expect(buttons).toHaveLength(2);
|
||||
[SIMPLE_BLOB_VIEWER_TITLE, RICH_BLOB_VIEWER_TITLE].forEach((title, i) => {
|
||||
expect(buttons.at(i).attributes('title')).toBe(title);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -69,12 +69,12 @@ describe('Markdown table of contents component', () => {
|
|||
const dropdown = findDropdown();
|
||||
|
||||
expect(dropdown.exists()).toBe(true);
|
||||
expect(dropdown.props('items').length).toBe(4);
|
||||
expect(dropdown.props('items')).toHaveLength(4);
|
||||
|
||||
// make sure that this only happens once
|
||||
await setLoaded(true);
|
||||
|
||||
expect(dropdown.props('items').length).toBe(4);
|
||||
expect(dropdown.props('items')).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('generates proper anchor links', async () => {
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ describe('LineHighlighter', () => {
|
|||
});
|
||||
|
||||
expect(document.querySelector('#LC13').classList).toContain(testContext.css);
|
||||
expect(document.querySelectorAll(`.${testContext.css}`).length).toBe(1);
|
||||
expect(document.querySelectorAll(`.${testContext.css}`)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('sets the hash', () => {
|
||||
|
|
@ -180,7 +180,7 @@ describe('LineHighlighter', () => {
|
|||
shiftKey: true,
|
||||
});
|
||||
|
||||
expect(document.querySelectorAll(`.${testContext.css}`).length).toBe(6);
|
||||
expect(document.querySelectorAll(`.${testContext.css}`)).toHaveLength(6);
|
||||
for (let line = 15; line <= 20; line += 1) {
|
||||
expect(document.querySelector(`#LC${line}`).classList).toContain(testContext.css);
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ describe('LineHighlighter', () => {
|
|||
shiftKey: true,
|
||||
});
|
||||
|
||||
expect(document.querySelectorAll(`.${testContext.css}`).length).toBe(6);
|
||||
expect(document.querySelectorAll(`.${testContext.css}`)).toHaveLength(6);
|
||||
for (let line = 5; line <= 10; line += 1) {
|
||||
expect(document.querySelector(`#LC${line}`).classList).toContain(testContext.css);
|
||||
}
|
||||
|
|
@ -214,7 +214,7 @@ describe('LineHighlighter', () => {
|
|||
shiftKey: true,
|
||||
});
|
||||
|
||||
expect(document.querySelectorAll(`.${testContext.css}`).length).toBe(6);
|
||||
expect(document.querySelectorAll(`.${testContext.css}`)).toHaveLength(6);
|
||||
for (let line = 5; line <= 10; line += 1) {
|
||||
expect(document.querySelector(`#LC${line}`).classList).toContain(testContext.css);
|
||||
}
|
||||
|
|
@ -225,7 +225,7 @@ describe('LineHighlighter', () => {
|
|||
shiftKey: true,
|
||||
});
|
||||
|
||||
expect(document.querySelectorAll(`.${testContext.css}`).length).toBe(6);
|
||||
expect(document.querySelectorAll(`.${testContext.css}`)).toHaveLength(6);
|
||||
for (let line = 10; line <= 15; line += 1) {
|
||||
expect(document.querySelector(`#LC${line}`).classList).toContain(testContext.css);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ describe('Board card component', () => {
|
|||
});
|
||||
|
||||
it('renders all three assignees', () => {
|
||||
expect(wrapper.findAll('.board-card-assignee .gl-avatar').length).toEqual(3);
|
||||
expect(wrapper.findAll('.board-card-assignee .gl-avatar')).toHaveLength(3);
|
||||
});
|
||||
|
||||
describe('more than three assignees', () => {
|
||||
|
|
@ -377,7 +377,7 @@ describe('Board card component', () => {
|
|||
});
|
||||
|
||||
it('renders two assignees', () => {
|
||||
expect(wrapper.findAll('.board-card-assignee .gl-avatar').length).toEqual(2);
|
||||
expect(wrapper.findAll('.board-card-assignee .gl-avatar')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('renders 99+ avatar counter', async () => {
|
||||
|
|
@ -412,7 +412,7 @@ describe('Board card component', () => {
|
|||
});
|
||||
|
||||
it('does not render list label but renders all other labels', () => {
|
||||
expect(wrapper.findAllComponents(GlLabel).length).toBe(1);
|
||||
expect(wrapper.findAllComponents(GlLabel)).toHaveLength(1);
|
||||
const label = wrapper.findComponent(GlLabel);
|
||||
expect(label.props('title')).toEqual(label1.title);
|
||||
expect(label.props('description')).toEqual(label1.description);
|
||||
|
|
@ -424,7 +424,7 @@ describe('Board card component', () => {
|
|||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.findAllComponents(GlLabel).length).toBe(1);
|
||||
expect(wrapper.findAllComponents(GlLabel)).toHaveLength(1);
|
||||
expect(wrapper.text()).not.toContain('closed');
|
||||
});
|
||||
});
|
||||
|
|
@ -453,7 +453,7 @@ describe('Board card component', () => {
|
|||
});
|
||||
|
||||
it('emits setFilters event', () => {
|
||||
expect(wrapper.emitted('setFilters').length).toBe(1);
|
||||
expect(wrapper.emitted('setFilters')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ describe('Board list component', () => {
|
|||
});
|
||||
|
||||
it('renders issues', () => {
|
||||
expect(wrapper.findAllComponents(BoardCard).length).toBe(1);
|
||||
expect(wrapper.findAllComponents(BoardCard)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('sets data attribute with issue id', () => {
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ describe('BoardForm', () => {
|
|||
|
||||
await waitForPromises();
|
||||
expect(global.window.location.href).not.toContain('?group_by=epic');
|
||||
expect(wrapper.emitted('updateBoard').length).toBe(1);
|
||||
expect(wrapper.emitted('updateBoard')).toHaveLength(1);
|
||||
expect(wrapper.emitted('updateBoard')).toEqual([
|
||||
[
|
||||
{
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ describe('boards sidebar remove issue', () => {
|
|||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.emitted().open.length).toBe(1);
|
||||
expect(wrapper.emitted().open).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not emits events when collapsing with false `emitEvent`', async () => {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ describe('ProjectSelect component', () => {
|
|||
await waitForPromises();
|
||||
findGlCollapsibleListBox().vm.$emit('shown');
|
||||
await nextTick();
|
||||
expect(findGlCollapsibleListBox().props('items').length).toEqual(mockProjects.length - 1);
|
||||
expect(findGlCollapsibleListBox().props('items')).toHaveLength(mockProjects.length - 1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ describe('Branch divergence graph component', () => {
|
|||
maxCommits: 100,
|
||||
});
|
||||
|
||||
expect(vm.findAllComponents(GraphBar).length).toBe(2);
|
||||
expect(vm.findAllComponents(GraphBar)).toHaveLength(2);
|
||||
expect(vm.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ describe('Branch divergence graph component', () => {
|
|||
maxCommits: 100,
|
||||
});
|
||||
|
||||
expect(vm.findAllComponents(GraphBar).length).toBe(1);
|
||||
expect(vm.findAllComponents(GraphBar)).toHaveLength(1);
|
||||
expect(vm.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ describe('initRecaptchaScript', () => {
|
|||
|
||||
it('is memoized', () => {
|
||||
expect(initRecaptchaScript()).toBe(result);
|
||||
expect(document.head.querySelectorAll('script').length).toBe(1);
|
||||
expect(document.head.querySelectorAll('script')).toHaveLength(1);
|
||||
});
|
||||
|
||||
describe('when onload is triggered', () => {
|
||||
|
|
|
|||
|
|
@ -275,19 +275,19 @@ describe('JobArtifactsTable component', () => {
|
|||
|
||||
describe('row expansion', () => {
|
||||
it('toggles the visibility of the row details', async () => {
|
||||
expect(findDetailsRows().length).toBe(0);
|
||||
expect(findDetailsRows()).toHaveLength(0);
|
||||
expect(findCountIcon().props('isOn')).toBe(false);
|
||||
|
||||
findCount().trigger('click');
|
||||
await nextTick();
|
||||
|
||||
expect(findDetailsRows().length).toBe(1);
|
||||
expect(findDetailsRows()).toHaveLength(1);
|
||||
expect(findCountIcon().props('isOn')).toBe(true);
|
||||
|
||||
findCount().trigger('click');
|
||||
await nextTick();
|
||||
|
||||
expect(findDetailsRows().length).toBe(0);
|
||||
expect(findDetailsRows()).toHaveLength(0);
|
||||
expect(findCountIcon().props('isOn')).toBe(false);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ describe('CiResourcesListItem', () => {
|
|||
createComponent();
|
||||
|
||||
const markdown = findMarkdown();
|
||||
expect(markdown.props().markdown.length).toBe(260);
|
||||
expect(markdown.props().markdown).toHaveLength(260);
|
||||
});
|
||||
|
||||
it('hides the resource description on mobile devices', () => {
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ describe('Ci variable table', () => {
|
|||
});
|
||||
|
||||
it('hides alert', () => {
|
||||
expect(findLimitReachedAlerts().length).toBe(0);
|
||||
expect(findLimitReachedAlerts()).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -268,7 +268,7 @@ describe('Ci variable table', () => {
|
|||
it('hides alert when limit has not been reached', () => {
|
||||
createComponent({ provide });
|
||||
|
||||
expect(findLimitReachedAlerts().length).toBe(0);
|
||||
expect(findLimitReachedAlerts()).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('shows alert when limit has been reached', () => {
|
||||
|
|
@ -282,7 +282,7 @@ describe('Ci variable table', () => {
|
|||
props: { maxVariableLimit: mockMaxVariableLimit },
|
||||
});
|
||||
|
||||
expect(findLimitReachedAlerts().length).toBe(2);
|
||||
expect(findLimitReachedAlerts()).toHaveLength(2);
|
||||
|
||||
expect(findLimitReachedAlerts().at(0).props('dismissible')).toBe(false);
|
||||
expect(findLimitReachedAlerts().at(0).text()).toContain(exceedsVariableLimitText);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ describe('InputsTableSkeletonLoader', () => {
|
|||
});
|
||||
|
||||
it('renders 8 rects (2 rows x 4 columns)', () => {
|
||||
expect(findSkeletonRects().length).toBe(8);
|
||||
expect(findSkeletonRects()).toHaveLength(8);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ describe('Job Log Header Line', () => {
|
|||
wrapper.trigger('click');
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.emitted().toggleLine.length).toBe(1);
|
||||
expect(wrapper.emitted().toggleLine).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ describe('stage column component', () => {
|
|||
});
|
||||
|
||||
it('should render the provided groups', () => {
|
||||
expect(findAllStageColumnGroups().length).toBe(mockGroups.length);
|
||||
expect(findAllStageColumnGroups()).toHaveLength(mockGroups.length);
|
||||
});
|
||||
|
||||
it('should emit updateMeasurements event on mount', () => {
|
||||
|
|
@ -138,9 +138,9 @@ describe('stage column component', () => {
|
|||
});
|
||||
|
||||
it('shows failed jobs grouped', () => {
|
||||
expect(findAllStageColumnFailedGroups().length).toBe(1);
|
||||
expect(findAllStageColumnFailedGroups()).toHaveLength(1);
|
||||
expect(findAllStageColumnFailedTitle().text()).toEqual('Failed jobs');
|
||||
expect(findAllStageColumnGroups().length).toBe(1);
|
||||
expect(findAllStageColumnGroups()).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ describe('Test reports suite table', () => {
|
|||
});
|
||||
|
||||
it('renders one page of test cases', () => {
|
||||
expect(allCaseRows().length).toBe(perPage);
|
||||
expect(allCaseRows()).toHaveLength(perPage);
|
||||
});
|
||||
|
||||
it('renders a pagination component', () => {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ describe('Test reports summary table', () => {
|
|||
|
||||
it('renders the correct number of rows', () => {
|
||||
expect(noSuitesToShow().exists()).toBe(false);
|
||||
expect(allSuitesRows().length).toBe(testReports.test_suites.length);
|
||||
expect(allSuitesRows()).toHaveLength(testReports.test_suites.length);
|
||||
});
|
||||
|
||||
describe('when there is a suite error', () => {
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ describe('PipelineStageDropdown', () => {
|
|||
const { name } = jobs.data.ciPipelineStage.jobs.nodes[5];
|
||||
wrapper.findComponent(GlSearchBoxByType).vm.$emit('input', name);
|
||||
await nextTick();
|
||||
expect(findJobDropdownItems().length).toBe(1);
|
||||
expect(findJobDropdownItems()).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -49,14 +49,14 @@ describe('Variable values listbox', () => {
|
|||
|
||||
await nextTick();
|
||||
|
||||
expect(findListboxItems().length).toBe(1);
|
||||
expect(findListboxItems()).toHaveLength(1);
|
||||
expect(findListboxItems().at(0).text()).toContain(searchString);
|
||||
|
||||
search('');
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(findListboxItems().length).toBe(3);
|
||||
expect(findListboxItems()).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('filters options with fuzzy filtering', async () => {
|
||||
|
|
@ -66,7 +66,7 @@ describe('Variable values listbox', () => {
|
|||
|
||||
await nextTick();
|
||||
|
||||
expect(findListboxItems().length).toBe(1);
|
||||
expect(findListboxItems()).toHaveLength(1);
|
||||
expect(findListboxItems().at(0).text()).toBe('production');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ describe('CI Templates', () => {
|
|||
});
|
||||
|
||||
it('renders all suggested templates', () => {
|
||||
expect(findTemplateNames().length).toBe(3);
|
||||
expect(findTemplateNames()).toHaveLength(3);
|
||||
expect(wrapper.text()).toContain('Android', 'Bash', 'C++');
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ describe('RunnerProjects', () => {
|
|||
});
|
||||
|
||||
it('Shows projects', () => {
|
||||
expect(findRunnerAssignedItems().length).toBe(mockProjects.length);
|
||||
expect(findRunnerAssignedItems()).toHaveLength(mockProjects.length);
|
||||
});
|
||||
|
||||
it('Shows a project', () => {
|
||||
|
|
@ -218,7 +218,7 @@ describe('RunnerProjects', () => {
|
|||
createComponent();
|
||||
|
||||
expect(wrapper.findByText(I18N_NO_PROJECTS_FOUND).exists()).toBe(false);
|
||||
expect(findRunnerAssignedItems().length).toBe(0);
|
||||
expect(findRunnerAssignedItems()).toHaveLength(0);
|
||||
|
||||
expect(findGlSearchBoxByType().props('isLoading')).toBe(true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ describe('RunnerTags', () => {
|
|||
it('Displays all tags', () => {
|
||||
expect(wrapper.text()).toMatchInterpolatedText('tag1 tag2 tag3');
|
||||
|
||||
expect(findTags().length).toBe(3);
|
||||
expect(findTags()).toHaveLength(3);
|
||||
|
||||
expect(findTagAt(0).props('tag')).toBe('tag1');
|
||||
expect(findTagAt(1).props('tag')).toBe('tag2');
|
||||
|
|
@ -56,7 +56,7 @@ describe('RunnerTags', () => {
|
|||
it('Displays limited tags', () => {
|
||||
expect(wrapper.text()).toMatchInterpolatedText('tag1 +2 more');
|
||||
|
||||
expect(findTags().length).toBe(1);
|
||||
expect(findTags()).toHaveLength(1);
|
||||
expect(findTagAt(0).props('tag')).toBe('tag1');
|
||||
|
||||
expect(findButton().text()).toBe('+2 more');
|
||||
|
|
@ -68,7 +68,7 @@ describe('RunnerTags', () => {
|
|||
|
||||
expect(wrapper.text()).toMatchInterpolatedText('tag1 tag2 tag3');
|
||||
|
||||
expect(findTags().length).toBe(3);
|
||||
expect(findTags()).toHaveLength(3);
|
||||
expect(findTagAt(0).props('tag')).toBe('tag1');
|
||||
expect(findTagAt(1).props('tag')).toBe('tag2');
|
||||
expect(findTagAt(2).props('tag')).toBe('tag3');
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ describe('IntegrationStatus', () => {
|
|||
({ tokens, integrationStatuses }) => {
|
||||
createWrapper(tokens);
|
||||
|
||||
expect(findAgentIntegrationStatusRows().length).toBe(integrationStatuses.length);
|
||||
expect(findAgentIntegrationStatusRows()).toHaveLength(integrationStatuses.length);
|
||||
|
||||
integrationStatuses.forEach((integrationStatus, index) => {
|
||||
expect(findAgentIntegrationStatusRows().at(index).props()).toMatchObject({
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ describe('ClustersViewAllComponent', () => {
|
|||
});
|
||||
|
||||
it('should render 2 cards', () => {
|
||||
expect(findCards().length).toBe(2);
|
||||
expect(findCards()).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ describe('Code navigation popover component', () => {
|
|||
});
|
||||
|
||||
expect(wrapper.find('[data-testid="references-tab"]').exists()).toBe(true);
|
||||
expect(wrapper.findAll('[data-testid="reference-link"]').length).toBe(2);
|
||||
expect(wrapper.findAll('[data-testid="reference-link"]')).toHaveLength(2);
|
||||
});
|
||||
|
||||
describe('code output', () => {
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ describe('Code navigation actions', () => {
|
|||
actions.showBlobInteractionZones({ state }, 'index.js');
|
||||
|
||||
expect(addInteractionClass).toHaveBeenCalled();
|
||||
expect(addInteractionClass.mock.calls.length).toBe(2);
|
||||
expect(addInteractionClass.mock.calls).toHaveLength(2);
|
||||
expect(addInteractionClass.mock.calls[0]).toEqual([
|
||||
{ path: 'index.js', d: 'test', wrapTextNodes },
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -88,14 +88,14 @@ describe('addInteractionClass', () => {
|
|||
it('does not wrap text nodes by default', () => {
|
||||
addInteractionClass(params);
|
||||
const spans = findAllSpans();
|
||||
expect(spans.length).toBe(0);
|
||||
expect(spans).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('wraps text nodes if wrapTextNodes is true', () => {
|
||||
addInteractionClass({ ...params, wrapTextNodes: true });
|
||||
const spans = findAllSpans();
|
||||
|
||||
expect(spans.length).toBe(3);
|
||||
expect(spans).toHaveLength(3);
|
||||
expect(spans[0].textContent).toBe(' ');
|
||||
expect(spans[1].textContent).toBe('Text');
|
||||
expect(spans[2].textContent).toBe(' ');
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ describe('Comment templates index page component', () => {
|
|||
|
||||
await waitForPromises();
|
||||
|
||||
expect(wrapper.findAllComponents(ListItem).length).toBe(0);
|
||||
expect(wrapper.findAllComponents(ListItem)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('renders list of comment templates', async () => {
|
||||
|
|
@ -49,7 +49,7 @@ describe('Comment templates index page component', () => {
|
|||
|
||||
await waitForPromises();
|
||||
|
||||
expect(wrapper.findAllComponents(ListItem).length).toBe(2);
|
||||
expect(wrapper.findAllComponents(ListItem)).toHaveLength(2);
|
||||
expect(wrapper.findAllComponents(ListItem).at(0).props('template')).toEqual(
|
||||
expect.objectContaining(savedReplies[0]),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ describe('Commits List', () => {
|
|||
|
||||
// The last commit header should be removed
|
||||
// since the previous one has the same data-day value.
|
||||
expect(commitsList.processCommits(data).find('li.commit-header').length).toBe(0);
|
||||
expect(commitsList.processCommits(data).find('li.commit-header')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ describe('content_editor/components/toolbar_text_style_dropdown', () => {
|
|||
TEXT_STYLE_DROPDOWN_ITEMS.forEach((textStyle, index) => {
|
||||
expect(findListbox().props('items').at(index).text).toContain(textStyle.label);
|
||||
});
|
||||
expect(findListbox().props('items').length).toBe(TEXT_STYLE_DROPDOWN_ITEMS.length);
|
||||
expect(findListbox().props('items')).toHaveLength(TEXT_STYLE_DROPDOWN_ITEMS.length);
|
||||
});
|
||||
|
||||
describe('when there is an active item', () => {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ describe('Contributors', () => {
|
|||
});
|
||||
|
||||
it('renders the individual charts', () => {
|
||||
expect(findIndividualCharts().length).toBe(1);
|
||||
expect(findIndividualCharts()).toHaveLength(1);
|
||||
expect(findIndividualCharts().at(0).props()).toMatchObject({
|
||||
contributor: {
|
||||
name: 'John',
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ describe('CreateItemDropdown', () => {
|
|||
|
||||
const $itemEls = $wrapperEl.find('.js-dropdown-content a');
|
||||
|
||||
expect($itemEls.length).toEqual(DROPDOWN_ITEM_DATA.length);
|
||||
expect($itemEls).toHaveLength(DROPDOWN_ITEM_DATA.length);
|
||||
|
||||
DROPDOWN_ITEM_DATA.forEach((dataItem, i) => {
|
||||
expect($($itemEls[i]).text()).toEqual(dataItem.text);
|
||||
|
|
@ -116,7 +116,7 @@ describe('CreateItemDropdown', () => {
|
|||
|
||||
const $itemEls = $wrapperEl.find('.js-dropdown-content a');
|
||||
|
||||
expect($itemEls.length).toEqual(1 + DROPDOWN_ITEM_DATA.length);
|
||||
expect($itemEls).toHaveLength(1 + DROPDOWN_ITEM_DATA.length);
|
||||
expect($($itemEls.get(DROPDOWN_ITEM_DATA.length)).text()).toEqual(NEW_ITEM_TEXT);
|
||||
});
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ describe('CreateItemDropdown', () => {
|
|||
|
||||
const $itemEls = $wrapperEl.find('.js-dropdown-content a');
|
||||
|
||||
expect($itemEls.length).toEqual(DROPDOWN_ITEM_DATA.length);
|
||||
expect($itemEls).toHaveLength(DROPDOWN_ITEM_DATA.length);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -152,13 +152,13 @@ describe('CreateItemDropdown', () => {
|
|||
|
||||
const $itemElsAfterFilter = $wrapperEl.find('.js-dropdown-content a');
|
||||
|
||||
expect($itemElsAfterFilter.length).toEqual(1);
|
||||
expect($itemElsAfterFilter).toHaveLength(1);
|
||||
|
||||
createItemDropdown.clearDropdown();
|
||||
|
||||
const $itemElsAfterClear = $wrapperEl.find('.js-dropdown-content a');
|
||||
|
||||
expect($itemElsAfterClear.length).toEqual(0);
|
||||
expect($itemElsAfterClear).toHaveLength(0);
|
||||
expect(filterInput.val()).toEqual('');
|
||||
});
|
||||
});
|
||||
|
|
@ -188,7 +188,7 @@ describe('CreateItemDropdown', () => {
|
|||
|
||||
const $itemEls = $wrapperEl.find('.js-dropdown-content a');
|
||||
|
||||
expect($itemEls.length).toEqual(1 + DROPDOWN_ITEM_DATA.length);
|
||||
expect($itemEls).toHaveLength(1 + DROPDOWN_ITEM_DATA.length);
|
||||
expect($($itemEls[DROPDOWN_ITEM_DATA.length]).text()).toEqual('new-item-text');
|
||||
expect($wrapperEl.find('.dropdown-toggle-text').text()).toEqual('new-item-title');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ describe('Deploy freeze table', () => {
|
|||
|
||||
it('displays data', () => {
|
||||
const tableRows = findDeployFreezeTable().findAll('tbody tr');
|
||||
expect(tableRows.length).toBe(freezePeriodsFixture.length);
|
||||
expect(tableRows).toHaveLength(freezePeriodsFixture.length);
|
||||
expect(findEmptyFreezePeriods().exists()).toBe(false);
|
||||
expect(findEditDeployFreezeButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('displays correct count', () => {
|
||||
const tableRows = findDeployFreezeTable().findAll('tbody tr');
|
||||
expect(tableRows.length).toBe(freezePeriodsFixture.length);
|
||||
expect(tableRows).toHaveLength(freezePeriodsFixture.length);
|
||||
expect(findCount().text()).toBe('3');
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ describe('Deploy keys app component', () => {
|
|||
},
|
||||
});
|
||||
await mountComponent();
|
||||
expect(findKeyPanels().length).toBe(3);
|
||||
expect(findKeyPanels()).toHaveLength(3);
|
||||
});
|
||||
|
||||
describe.each`
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ describe('Deploy keys key', () => {
|
|||
await createComponent({ deployKey });
|
||||
const labels = wrapper.findAll('.deploy-project-label');
|
||||
|
||||
expect(labels.length).toBe(2);
|
||||
expect(labels).toHaveLength(2);
|
||||
expect(labels.at(1).text()).toContain('others');
|
||||
expect(labels.at(1).attributes('title')).toContain('Expand');
|
||||
});
|
||||
|
|
@ -167,7 +167,7 @@ describe('Deploy keys key', () => {
|
|||
|
||||
const labels = wrapper.findAll('.deploy-project-label');
|
||||
|
||||
expect(labels.length).toBe(2);
|
||||
expect(labels).toHaveLength(2);
|
||||
expect(labels.at(1).text()).toContain(deployKey.deployKeysProjects[1].project.fullName);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -123,10 +123,10 @@ describe('deprecatedJQueryDropdown', () => {
|
|||
});
|
||||
|
||||
it('should select a following item on DOWN keypress', () => {
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement).length).toBe(0);
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement)).toHaveLength(0);
|
||||
const randomIndex = Math.floor(Math.random() * (test.projectsData.length - 1)) + 0;
|
||||
navigateWithKeys('down', randomIndex, () => {
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement).length).toBe(1);
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement)).toHaveLength(1);
|
||||
expect($(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, test.$dropdownMenuElement)).toHaveClass(
|
||||
'is-focused',
|
||||
);
|
||||
|
|
@ -134,12 +134,12 @@ describe('deprecatedJQueryDropdown', () => {
|
|||
});
|
||||
|
||||
it('should select a previous item on UP keypress', () => {
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement).length).toBe(0);
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement)).toHaveLength(0);
|
||||
navigateWithKeys('down', test.projectsData.length - 1, () => {
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement).length).toBe(1);
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement)).toHaveLength(1);
|
||||
const randomIndex = Math.floor(Math.random() * (test.projectsData.length - 2)) + 0;
|
||||
navigateWithKeys('up', randomIndex, () => {
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement).length).toBe(1);
|
||||
expect($(FOCUSED_ITEM_SELECTOR, test.$dropdownMenuElement)).toHaveLength(1);
|
||||
expect(
|
||||
$(
|
||||
`${ITEM_SELECTOR}:eq(${test.projectsData.length - 2 - randomIndex}) a`,
|
||||
|
|
@ -296,7 +296,7 @@ describe('deprecatedJQueryDropdown', () => {
|
|||
const li = dropdown.renderItem(sep);
|
||||
|
||||
expect(li).toHaveClass('separator');
|
||||
expect(li.childNodes.length).toEqual(0);
|
||||
expect(li.childNodes).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should return an empty .divider li when when appropriate', () => {
|
||||
|
|
@ -305,7 +305,7 @@ describe('deprecatedJQueryDropdown', () => {
|
|||
const li = dropdown.renderItem(div);
|
||||
|
||||
expect(li).toHaveClass('divider');
|
||||
expect(li.childNodes.length).toEqual(0);
|
||||
expect(li.childNodes).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should return a .dropdown-header li with the correct content when when appropriate', () => {
|
||||
|
|
@ -315,7 +315,7 @@ describe('deprecatedJQueryDropdown', () => {
|
|||
const li = dropdown.renderItem(header);
|
||||
|
||||
expect(li).toHaveClass('dropdown-header');
|
||||
expect(li.childNodes.length).toEqual(1);
|
||||
expect(li.childNodes).toHaveLength(1);
|
||||
expect(li.textContent).toEqual(text);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ describe('Design management index page', () => {
|
|||
createComponent({ allVersions: [mockVersion] });
|
||||
|
||||
expect(findDesignsWrapper().exists()).toBe(true);
|
||||
expect(findDesigns().length).toBe(3);
|
||||
expect(findDesigns()).toHaveLength(3);
|
||||
expect(findDesignToolbarWrapper().exists()).toBe(true);
|
||||
expect(findDesignUploadButton().exists()).toBe(true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -688,7 +688,7 @@ describe('diffs/components/app', () => {
|
|||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.findAllComponents(DiffFile).length).toBe(1);
|
||||
expect(wrapper.findAllComponents(DiffFile)).toHaveLength(1);
|
||||
});
|
||||
|
||||
describe('rechecking the url hash for scrolling', () => {
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ describe('DiffDiscussions', () => {
|
|||
expect(findNoteableDiscussion().exists()).toBe(true);
|
||||
expect(wrapper.findComponent(DiscussionNotes).exists()).toBe(true);
|
||||
expect(
|
||||
wrapper.findComponent(DiscussionNotes).findAllComponents(TimelineEntryItem).length,
|
||||
).toBe(discussionsMockData.notes.length);
|
||||
wrapper.findComponent(DiscussionNotes).findAllComponents(TimelineEntryItem),
|
||||
).toHaveLength(discussionsMockData.notes.length);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ describe('DiffFile', () => {
|
|||
expect(el.id).toEqual(file_hash);
|
||||
expect(el.classList.contains('diff-file')).toEqual(true);
|
||||
|
||||
expect(el.querySelectorAll('.diff-content.hidden').length).toEqual(0);
|
||||
expect(el.querySelectorAll('.diff-content.hidden')).toHaveLength(0);
|
||||
expect(el.querySelector('.js-file-title')).toBeDefined();
|
||||
expect(wrapper.findComponent(DiffFileHeaderComponent).exists()).toBe(true);
|
||||
expect(el.querySelector('.js-syntax-highlight')).toBeDefined();
|
||||
|
|
@ -340,7 +340,7 @@ describe('DiffFile', () => {
|
|||
createComponent();
|
||||
makeFileAutomaticallyCollapsed();
|
||||
|
||||
expect(findDiffContentArea(wrapper).element.children.length).toBe(1);
|
||||
expect(findDiffContentArea(wrapper).element.children).toHaveLength(1);
|
||||
expect(wrapper.classes('has-body')).toBe(true);
|
||||
});
|
||||
|
||||
|
|
@ -348,7 +348,7 @@ describe('DiffFile', () => {
|
|||
createComponent();
|
||||
makeFileManuallyCollapsed();
|
||||
|
||||
expect(findDiffContentArea(wrapper).element.children.length).toBe(1);
|
||||
expect(findDiffContentArea(wrapper).element.children).toHaveLength(1);
|
||||
expect(wrapper.classes('has-body')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -384,7 +384,7 @@ describe('DiffFile', () => {
|
|||
createComponent();
|
||||
await nextTick();
|
||||
|
||||
expect(findDiffContentArea(wrapper).element.children.length).toBe(0);
|
||||
expect(findDiffContentArea(wrapper).element.children).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should not have the class `has-body` to present the header differently', () => {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ describe('DiffGutterAvatars', () => {
|
|||
});
|
||||
|
||||
it('renders correct amount of user avatars', () => {
|
||||
expect(findUserAvatars().length).toBe(3);
|
||||
expect(findUserAvatars()).toHaveLength(3);
|
||||
});
|
||||
|
||||
// Avoid images in file contents copy: https://gitlab.com/gitlab-org/gitlab/-/issues/337139
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ describe('diff_stats', () => {
|
|||
it('is not rendered if diffsCount is empty', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findDiffStatsGroup().length).toBe(2);
|
||||
expect(findDiffStatsGroup()).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('is not rendered if diffsCount is not a number', () => {
|
||||
|
|
@ -42,7 +42,7 @@ describe('diff_stats', () => {
|
|||
diffsCount: null,
|
||||
});
|
||||
|
||||
expect(findDiffStatsGroup().length).toBe(2);
|
||||
expect(findDiffStatsGroup()).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ describe('DiffView', () => {
|
|||
inline: type === 'inline',
|
||||
},
|
||||
});
|
||||
expect(wrapper.findAllComponents(DiffCommentCell).length).toBe(total);
|
||||
expect(wrapper.findAllComponents(DiffCommentCell)).toHaveLength(total);
|
||||
expect(wrapper.find(container).findComponent(DiffCommentCell).exists()).toBe(true);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -288,15 +288,14 @@ describe('Diffs Module Getters', () => {
|
|||
{},
|
||||
{},
|
||||
{ discussions: [discussionMock] },
|
||||
)(diffFileMock).length,
|
||||
).toEqual(1);
|
||||
)(diffFileMock),
|
||||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('returns an empty array when no discussions are found in the given diff', () => {
|
||||
expect(
|
||||
getters.getDiffFileDiscussions(localState, {}, {}, { discussions: [] })(diffFileMock)
|
||||
.length,
|
||||
).toEqual(0);
|
||||
getters.getDiffFileDiscussions(localState, {}, {}, { discussions: [] })(diffFileMock),
|
||||
).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ describe('DiffsStoreMutations', () => {
|
|||
|
||||
mutations[types.SET_DIFF_FILES](state, ['file', 'another file']);
|
||||
|
||||
expect(state.diffFiles.length).toEqual(2);
|
||||
expect(state.diffFiles).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should not set anything except diffFiles in state', () => {
|
||||
|
|
@ -309,7 +309,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
|
|
@ -356,7 +356,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0].discussions.length).toEqual(1);
|
||||
expect(state.diffFiles[0].discussions).toHaveLength(1);
|
||||
expect(state.diffFiles[0].discussions[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
|
|
@ -406,7 +406,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
|
||||
mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
|
||||
|
|
@ -414,7 +414,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
|
|
@ -464,7 +464,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
|
||||
mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
|
||||
|
|
@ -476,7 +476,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].notes.length).toBe(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].notes).toHaveLength(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].resolved).toBe(true);
|
||||
});
|
||||
|
||||
|
|
@ -542,7 +542,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toBe(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should add legacy discussions to the given line', () => {
|
||||
|
|
@ -590,7 +590,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
|
|
@ -672,7 +672,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode: null,
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0].discussions.length).toEqual(1);
|
||||
expect(state.diffFiles[0].discussions).toHaveLength(1);
|
||||
});
|
||||
|
||||
describe('expanded state', () => {
|
||||
|
|
@ -928,7 +928,7 @@ describe('DiffsStoreMutations', () => {
|
|||
lineCode: 'ABC_1',
|
||||
});
|
||||
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(0);
|
||||
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -1332,7 +1332,7 @@ describe('DiffsStoreMutations', () => {
|
|||
|
||||
mutations[types.ADD_DRAFT_TO_FILE](state, { filePath: 'path', draft: 'test' });
|
||||
|
||||
expect(state.diffFiles[0].drafts.length).toEqual(1);
|
||||
expect(state.diffFiles[0].drafts).toHaveLength(1);
|
||||
expect(state.diffFiles[0].drafts[0]).toEqual('test');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ describe('DiffsStoreUtils', () => {
|
|||
it('sets the collapsed attribute on files', () => {
|
||||
const checkLine = preparedDiff.diff_files[0][INLINE_DIFF_LINES_KEY][0];
|
||||
|
||||
expect(checkLine.discussions.length).toBe(0);
|
||||
expect(checkLine.discussions).toHaveLength(0);
|
||||
expect(checkLine).not.toHaveAttr('text');
|
||||
const firstChar = checkLine.rich_text.charAt(0);
|
||||
|
||||
|
|
@ -453,11 +453,11 @@ describe('DiffsStoreUtils', () => {
|
|||
|
||||
it('guarantees an empty array for both diff styles', () => {
|
||||
expect(splitInlineDiff.diff_files[0][INLINE_DIFF_LINES_KEY].length).toBeGreaterThan(0);
|
||||
expect(splitParallelDiff.diff_files[0][INLINE_DIFF_LINES_KEY].length).toEqual(0);
|
||||
expect(splitParallelDiff.diff_files[0][INLINE_DIFF_LINES_KEY]).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('merges existing diff files with newly loaded diff files to ensure split diffs are eventually completed', () => {
|
||||
expect(completedDiff.diff_files.length).toEqual(1);
|
||||
expect(completedDiff.diff_files).toHaveLength(1);
|
||||
expect(completedDiff.diff_files[0][INLINE_DIFF_LINES_KEY].length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
|
|
@ -544,7 +544,7 @@ describe('DiffsStoreUtils', () => {
|
|||
});
|
||||
|
||||
it('guarantees an empty array of lines for both diff styles', () => {
|
||||
expect(preparedDiffFiles[0][INLINE_DIFF_LINES_KEY].length).toEqual(0);
|
||||
expect(preparedDiffFiles[0][INLINE_DIFF_LINES_KEY]).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('leaves files in the existing state', () => {
|
||||
|
|
@ -553,7 +553,7 @@ describe('DiffsStoreUtils', () => {
|
|||
const priorFiles = [fileMock];
|
||||
const updatedFilesList = utils.prepareDiffData({ diff: metaData, priorFiles, meta: true });
|
||||
|
||||
expect(updatedFilesList.length).toEqual(2);
|
||||
expect(updatedFilesList).toHaveLength(2);
|
||||
expect(updatedFilesList[0]).toEqual(fileMock);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -305,12 +305,12 @@ describe('Diffs Module Getters', () => {
|
|||
discussionMock.diff_file.file_hash = diffFileMock.file_hash;
|
||||
useNotes().discussions = [discussionMock];
|
||||
|
||||
expect(store.getDiffFileDiscussions(diffFileMock).length).toEqual(1);
|
||||
expect(store.getDiffFileDiscussions(diffFileMock)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('returns an empty array when no discussions are found in the given diff', () => {
|
||||
useNotes().discussions = [];
|
||||
expect(store.getDiffFileDiscussions(diffFileMock).length).toEqual(0);
|
||||
expect(store.getDiffFileDiscussions(diffFileMock)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ describe('DiffsStoreMutations', () => {
|
|||
it('should set diffFiles in state', () => {
|
||||
store[types.SET_DIFF_FILES](['file', 'another file']);
|
||||
|
||||
expect(store.diffFiles.length).toEqual(2);
|
||||
expect(store.diffFiles).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -297,7 +297,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
|
|
@ -344,7 +344,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0].discussions.length).toEqual(1);
|
||||
expect(store.diffFiles[0].discussions).toHaveLength(1);
|
||||
expect(store.diffFiles[0].discussions[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
|
|
@ -394,7 +394,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
|
||||
store[types.SET_LINE_DISCUSSIONS_FOR_FILE]({
|
||||
|
|
@ -402,7 +402,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
|
|
@ -452,7 +452,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
|
||||
store[types.SET_LINE_DISCUSSIONS_FOR_FILE]({
|
||||
|
|
@ -464,7 +464,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].notes.length).toBe(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].notes).toHaveLength(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].resolved).toBe(true);
|
||||
});
|
||||
|
||||
|
|
@ -530,7 +530,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toBe(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should add legacy discussions to the given line', () => {
|
||||
|
|
@ -578,7 +578,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode,
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(1);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
|
|
@ -660,7 +660,7 @@ describe('DiffsStoreMutations', () => {
|
|||
diffPositionByLineCode: null,
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0].discussions.length).toEqual(1);
|
||||
expect(store.diffFiles[0].discussions).toHaveLength(1);
|
||||
});
|
||||
|
||||
describe('expanded state', () => {
|
||||
|
|
@ -916,7 +916,7 @@ describe('DiffsStoreMutations', () => {
|
|||
lineCode: 'ABC_1',
|
||||
});
|
||||
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions.length).toEqual(0);
|
||||
expect(store.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussions).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -1312,7 +1312,7 @@ describe('DiffsStoreMutations', () => {
|
|||
|
||||
store[types.ADD_DRAFT_TO_FILE]({ filePath: 'path', draft: 'test' });
|
||||
|
||||
expect(store.diffFiles[0].drafts.length).toEqual(1);
|
||||
expect(store.diffFiles[0].drafts).toHaveLength(1);
|
||||
expect(store.diffFiles[0].drafts[0]).toEqual('test');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ describe('Source Editor utils', () => {
|
|||
});
|
||||
|
||||
it('removes all child nodes from an element', () => {
|
||||
expect(el.children.length).toBe(1);
|
||||
expect(el.children).toHaveLength(1);
|
||||
utils.clearDomElement(el);
|
||||
expect(el.children.length).toBe(0);
|
||||
expect(el.children).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ describe('Emoji category component', () => {
|
|||
});
|
||||
|
||||
it('renders emoji groups', () => {
|
||||
expect(wrapper.findAllComponents(EmojiGroup).length).toBe(2);
|
||||
expect(wrapper.findAllComponents(EmojiGroup)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('renders group', async () => {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ describe('Emoji group component', () => {
|
|||
});
|
||||
|
||||
expect(wrapper.findAllByTestId('emoji-button').exists()).toBe(true);
|
||||
expect(wrapper.findAllByTestId('emoji-button').length).toBe(2);
|
||||
expect(wrapper.findAllByTestId('emoji-button')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('emits emoji-click', () => {
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ describe('retrieval of emojis.json', () => {
|
|||
});
|
||||
|
||||
const assertCorrectLocalStorage = () => {
|
||||
expect(localStorage.length).toBe(1);
|
||||
expect(localStorage).toHaveLength(1);
|
||||
expect(localStorage.getItem(CACHE_KEY)).toBe(
|
||||
JSON.stringify({ data: mockEmojiData, EMOJI_VERSION }),
|
||||
);
|
||||
|
|
@ -151,7 +151,7 @@ describe('retrieval of emojis.json', () => {
|
|||
await initEmojiMap();
|
||||
|
||||
assertEmojiBeingLoadedCorrectly();
|
||||
expect(mock.history.get.length).toBe(1);
|
||||
expect(mock.history.get).toHaveLength(1);
|
||||
assertCorrectLocalStorage();
|
||||
});
|
||||
});
|
||||
|
|
@ -165,7 +165,7 @@ describe('retrieval of emojis.json', () => {
|
|||
|
||||
it('should not call the API and not mutate the localStorage', () => {
|
||||
assertEmojiBeingLoadedCorrectly();
|
||||
expect(mock.history.get.length).toBe(0);
|
||||
expect(mock.history.get).toHaveLength(0);
|
||||
expect(localStorage.setItem).not.toHaveBeenCalled();
|
||||
assertCorrectLocalStorage();
|
||||
});
|
||||
|
|
@ -183,7 +183,7 @@ describe('retrieval of emojis.json', () => {
|
|||
|
||||
it('should call the API and store results in localStorage', () => {
|
||||
assertEmojiBeingLoadedCorrectly();
|
||||
expect(mock.history.get.length).toBe(1);
|
||||
expect(mock.history.get).toHaveLength(1);
|
||||
assertCorrectLocalStorage();
|
||||
});
|
||||
});
|
||||
|
|
@ -197,7 +197,7 @@ describe('retrieval of emojis.json', () => {
|
|||
|
||||
it('should call the API and store results in localStorage', () => {
|
||||
assertEmojiBeingLoadedCorrectly();
|
||||
expect(mock.history.get.length).toBe(1);
|
||||
expect(mock.history.get).toHaveLength(1);
|
||||
assertCorrectLocalStorage();
|
||||
});
|
||||
});
|
||||
|
|
@ -211,7 +211,7 @@ describe('retrieval of emojis.json', () => {
|
|||
|
||||
it('should call the API and store results in localStorage', () => {
|
||||
assertEmojiBeingLoadedCorrectly();
|
||||
expect(mock.history.get.length).toBe(1);
|
||||
expect(mock.history.get).toHaveLength(1);
|
||||
assertCorrectLocalStorage();
|
||||
});
|
||||
});
|
||||
|
|
@ -230,8 +230,8 @@ describe('retrieval of emojis.json', () => {
|
|||
|
||||
it('should call API but not store the results', () => {
|
||||
assertEmojiBeingLoadedCorrectly();
|
||||
expect(mock.history.get.length).toBe(1);
|
||||
expect(localStorage.length).toBe(0);
|
||||
expect(mock.history.get).toHaveLength(1);
|
||||
expect(localStorage).toHaveLength(0);
|
||||
expect(localStorage.setItem).toHaveBeenCalledTimes(1);
|
||||
expect(localStorage.setItem).toHaveBeenCalledWith(
|
||||
CACHE_KEY,
|
||||
|
|
@ -275,12 +275,12 @@ describe('retrieval of emojis.json', () => {
|
|||
// Load emoji the old way to pre-populate the cache
|
||||
let res = await prevImplementation();
|
||||
expect(res).toEqual(mockEmojiData);
|
||||
expect(mock.history.get.length).toBe(1);
|
||||
expect(mock.history.get).toHaveLength(1);
|
||||
localStorage.setItem.mockClear();
|
||||
|
||||
// Load emoji the new way
|
||||
await initEmojiMap();
|
||||
expect(mock.history.get.length).toBe(2);
|
||||
expect(mock.history.get).toHaveLength(2);
|
||||
assertEmojiBeingLoadedCorrectly();
|
||||
assertCorrectLocalStorage();
|
||||
localStorage.setItem.mockClear();
|
||||
|
|
@ -288,7 +288,7 @@ describe('retrieval of emojis.json', () => {
|
|||
// Load emoji the old way to pre-populate the cache
|
||||
res = await prevImplementation();
|
||||
expect(res).toEqual(mockEmojiData);
|
||||
expect(mock.history.get.length).toBe(3);
|
||||
expect(mock.history.get).toHaveLength(3);
|
||||
expect(localStorage.setItem.mock.calls).toEqual([
|
||||
[CACHE_VERSION_KEY, EMOJI_VERSION],
|
||||
[CACHE_KEY, JSON.stringify(mockEmojiData)],
|
||||
|
|
@ -297,7 +297,7 @@ describe('retrieval of emojis.json', () => {
|
|||
// Load emoji the old way should work again (and be taken from the cache)
|
||||
res = await prevImplementation();
|
||||
expect(res).toEqual(mockEmojiData);
|
||||
expect(mock.history.get.length).toBe(3);
|
||||
expect(mock.history.get).toHaveLength(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ describe('Unicode Support Map', () => {
|
|||
});
|
||||
|
||||
it('should not call .getItem or .setItem', () => {
|
||||
expect(window.localStorage.getItem.mock.calls.length).toBe(1);
|
||||
expect(window.localStorage.getItem.mock.calls).toHaveLength(1);
|
||||
expect(window.localStorage.setItem).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ describe('Enable Review Apps Modal', () => {
|
|||
});
|
||||
|
||||
it('displays instructions', () => {
|
||||
expect(findInstructions().length).toBe(7);
|
||||
expect(findInstructions()).toHaveLength(7);
|
||||
expect(findInstructionAt(0).text()).toContain(i18n.instructions.step1);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ describe('EnvironmentActions Component', () => {
|
|||
|
||||
it('should render a dropdown button with 2 icons', () => {
|
||||
createComponent();
|
||||
expect(wrapper.findComponent(GlDisclosureDropdown).findAllComponents(GlIcon).length).toBe(2);
|
||||
expect(wrapper.findComponent(GlDisclosureDropdown).findAllComponents(GlIcon)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should render a dropdown button with aria-label description', () => {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ describe('EnvironmentsFolderAppComponent', () => {
|
|||
|
||||
it('should show skeletons while loading', () => {
|
||||
createWrapper();
|
||||
expect(findSkeletonLoaders().length).toBe(3);
|
||||
expect(findSkeletonLoaders()).toHaveLength(3);
|
||||
});
|
||||
|
||||
describe('when environments are loaded', () => {
|
||||
|
|
@ -91,12 +91,12 @@ describe('EnvironmentsFolderAppComponent', () => {
|
|||
|
||||
it('should list environments in folder', () => {
|
||||
const items = findEnvironmentItems();
|
||||
expect(items.length).toBe(resolvedFolder.environments.length);
|
||||
expect(items).toHaveLength(resolvedFolder.environments.length);
|
||||
});
|
||||
|
||||
it('should render active and stopped tabs', () => {
|
||||
const tabs = findTabs();
|
||||
expect(tabs.length).toBe(2);
|
||||
expect(tabs).toHaveLength(2);
|
||||
});
|
||||
|
||||
[
|
||||
|
|
|
|||
|
|
@ -212,8 +212,8 @@ describe('ErrorDetails', () => {
|
|||
});
|
||||
|
||||
it('should not convert interpolated text to html entities', () => {
|
||||
expect(findReportedText().findAll('script').length).toEqual(0);
|
||||
expect(findReportedText().findAll('strong').length).toEqual(1);
|
||||
expect(findReportedText().findAll('script')).toHaveLength(0);
|
||||
expect(findReportedText().findAll('strong')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should render text instead of converting to html entities', () => {
|
||||
|
|
@ -225,13 +225,13 @@ describe('ErrorDetails', () => {
|
|||
it('should show language and error level badges', async () => {
|
||||
const detailedError = { tags: { level: 'error', logger: 'ruby' } };
|
||||
await createComponent({ detailedError });
|
||||
expect(wrapper.findAllComponents(GlBadge).length).toBe(2);
|
||||
expect(wrapper.findAllComponents(GlBadge)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should NOT show the badge if the tag is not present', async () => {
|
||||
const detailedError = { tags: { level: 'error', logger: null } };
|
||||
await createComponent({ detailedError });
|
||||
expect(wrapper.findAllComponents(GlBadge).length).toBe(1);
|
||||
expect(wrapper.findAllComponents(GlBadge)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it.each(Object.keys(severityLevel))(
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue