diff --git a/.rubocop_todo/migration/prevent_index_creation.yml b/.rubocop_todo/migration/prevent_index_creation.yml new file mode 100644 index 00000000000..f86e164dbfb --- /dev/null +++ b/.rubocop_todo/migration/prevent_index_creation.yml @@ -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' diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 561cead8f24..d331c13f43b 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -a02ff0c8d8ae8c137651b6aa326bc2481c02b19b +5ea4031481151c6c9d055d7f7097ddeea2948594 diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 89d096f6921..b6d1bafc6c7 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -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 diff --git a/app/models/namespaces/traversal/linear.rb b/app/models/namespaces/traversal/linear.rb index c1a19a19a3f..491a2cc9f8b 100644 --- a/app/models/namespaces/traversal/linear.rb +++ b/app/models/namespaces/traversal/linear.rb @@ -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. diff --git a/app/models/namespaces/traversal/linear_scopes.rb b/app/models/namespaces/traversal/linear_scopes.rb index c63639e721a..4db3a2efdee 100644 --- a/app/models/namespaces/traversal/linear_scopes.rb +++ b/app/models/namespaces/traversal/linear_scopes.rb @@ -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 diff --git a/app/models/namespaces/traversal/recursive_scopes.rb b/app/models/namespaces/traversal/recursive_scopes.rb index c6f09a4d134..59ca7d4e136 100644 --- a/app/models/namespaces/traversal/recursive_scopes.rb +++ b/app/models/namespaces/traversal/recursive_scopes.rb @@ -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 diff --git a/app/models/organizations/organization.rb b/app/models/organizations/organization.rb index 8625fde8d64..5bc602accf8 100644 --- a/app/models/organizations/organization.rb +++ b/app/models/organizations/organization.rb @@ -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 }) } diff --git a/app/models/organizations/organization_user.rb b/app/models/organizations/organization_user.rb index d503c267c46..9c8eab93331 100644 --- a/app/models/organizations/organization_user.rb +++ b/app/models/organizations/organization_user.rb @@ -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 diff --git a/app/models/pages_deployment.rb b/app/models/pages_deployment.rb index d44609a94e3..71ccbcb1e09 100644 --- a/app/models/pages_deployment.rb +++ b/app/models/pages_deployment.rb @@ -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 diff --git a/app/models/pool_repository.rb b/app/models/pool_repository.rb index ecbd22c51b7..bbede07c33e 100644 --- a/app/models/pool_repository.rb +++ b/app/models/pool_repository.rb @@ -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 diff --git a/app/models/preloaders/user_max_access_level_in_projects_preloader.rb b/app/models/preloaders/user_max_access_level_in_projects_preloader.rb index 09854ec5ff1..ac9e497f779 100644 --- a/app/models/preloaders/user_max_access_level_in_projects_preloader.rb +++ b/app/models/preloaders/user_max_access_level_in_projects_preloader.rb @@ -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 diff --git a/app/models/wiki_page/meta.rb b/app/models/wiki_page/meta.rb index a72fa7260f1..012cf4478d1 100644 --- a/app/models/wiki_page/meta.rb +++ b/app/models/wiki_page/meta.rb @@ -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? diff --git a/app/services/labels/promote_service.rb b/app/services/labels/promote_service.rb index 5970dfbf51c..e3cd498c118 100644 --- a/app/services/labels/promote_service.rb +++ b/app/services/labels/promote_service.rb @@ -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) diff --git a/config/feature_flags/development/check_path_traversal_middleware.yml b/config/feature_flags/beta/check_path_traversal_middleware.yml similarity index 54% rename from config/feature_flags/development/check_path_traversal_middleware.yml rename to config/feature_flags/beta/check_path_traversal_middleware.yml index e8a4a39f0ea..c253b1b1e43 100644 --- a/config/feature_flags/development/check_path_traversal_middleware.yml +++ b/config/feature_flags/beta/check_path_traversal_middleware.yml @@ -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 diff --git a/doc/administration/logs/_index.md b/doc/administration/logs/_index.md index 379401f74ec..cbe46d5303c 100644 --- a/doc/administration/logs/_index.md +++ b/doc/administration/logs/_index.md @@ -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: diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md index 1581d9bfc8d..61b9ab8cb81 100644 --- a/doc/development/migration_style_guide.md +++ b/doc/development/migration_style_guide.md @@ -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. diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 37815f1d3b2..13bee5d4a78 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -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, diff --git a/lib/api/users.rb b/lib/api/users.rb index d3c38bcf557..ddd5610222b 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -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' diff --git a/lib/backup/targets/repositories.rb b/lib/backup/targets/repositories.rb index ac1f82022de..99e81109dd0 100644 --- a/lib/backup/targets/repositories.rb +++ b/lib/backup/targets/repositories.rb @@ -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 diff --git a/lib/gitlab/object_hierarchy.rb b/lib/gitlab/object_hierarchy.rb index 17a163db17d..0d0b053ded6 100644 --- a/lib/gitlab/object_hierarchy.rb +++ b/lib/gitlab/object_hierarchy.rb @@ -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). diff --git a/lib/gitlab/quick_actions/issue_actions.rb b/lib/gitlab/quick_actions/issue_actions.rb index 88c4e1ea5ab..183bd665a11 100644 --- a/lib/gitlab/quick_actions/issue_actions.rb +++ b/lib/gitlab/quick_actions/issue_actions.rb @@ -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 } diff --git a/rubocop/cop/migration/prevent_index_creation.rb b/rubocop/cop/migration/prevent_index_creation.rb index ab40814feb1..39f53b93b3e 100644 --- a/rubocop/cop/migration/prevent_index_creation.rb +++ b/rubocop/cop/migration/prevent_index_creation.rb @@ -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) diff --git a/spec/frontend/__helpers__/pinia_helpers.js b/spec/frontend/__helpers__/pinia_helpers.js index 12c7ba1fbd4..c960445a287 100644 --- a/spec/frontend/__helpers__/pinia_helpers.js +++ b/spec/frontend/__helpers__/pinia_helpers.js @@ -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; diff --git a/spec/frontend/__helpers__/vue_test_utils_helper_spec.js b/spec/frontend/__helpers__/vue_test_utils_helper_spec.js index 493e5f90c9c..287bb069778 100644 --- a/spec/frontend/__helpers__/vue_test_utils_helper_spec.js +++ b/spec/frontend/__helpers__/vue_test_utils_helper_spec.js @@ -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); }); }); }); diff --git a/spec/frontend/achievements/achievements_app_spec.js b/spec/frontend/achievements/achievements_app_spec.js index fb4cb97efd9..56c9d42739f 100644 --- a/spec/frontend/achievements/achievements_app_spec.js +++ b/spec/frontend/achievements/achievements_app_spec.js @@ -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 () => { diff --git a/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js b/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js index 975f115c4bb..4f55739c377 100644 --- a/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js +++ b/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js @@ -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); }); }); diff --git a/spec/frontend/admin/abuse_reports/components/app_spec.js b/spec/frontend/admin/abuse_reports/components/app_spec.js index 64886cedf35..fad264044fa 100644 --- a/spec/frontend/admin/abuse_reports/components/app_spec.js +++ b/spec/frontend/admin/abuse_reports/components/app_spec.js @@ -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', () => { diff --git a/spec/frontend/alert_management/components/alert_management_table_spec.js b/spec/frontend/alert_management/components/alert_management_table_spec.js index c96efbb1f5f..edb771405fd 100644 --- a/spec/frontend/alert_management/components/alert_management_table_spec.js +++ b/spec/frontend/alert_management/components/alert_management_table_spec.js @@ -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', () => { diff --git a/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js b/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js index 0453bf0b0f8..b235525b125 100644 --- a/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js +++ b/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js @@ -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', () => { diff --git a/spec/frontend/analytics/cycle_analytics/components/path_navigation_spec.js b/spec/frontend/analytics/cycle_analytics/components/path_navigation_spec.js index 83d1eff52a5..5999bd2e76e 100644 --- a/spec/frontend/analytics/cycle_analytics/components/path_navigation_spec.js +++ b/spec/frontend/analytics/cycle_analytics/components/path_navigation_spec.js @@ -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', () => { diff --git a/spec/frontend/analytics/cycle_analytics/utils_spec.js b/spec/frontend/analytics/cycle_analytics/utils_spec.js index ec7f17cb8bb..d832934df25 100644 --- a/spec/frontend/analytics/cycle_analytics/utils_spec.js +++ b/spec/frontend/analytics/cycle_analytics/utils_spec.js @@ -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', () => { diff --git a/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js b/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js index 706571bc3e5..3cfea4cffea 100644 --- a/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js +++ b/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js @@ -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); }); }); diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js index 17d24ddeafa..bc95a81ce8b 100644 --- a/spec/frontend/api_spec.js +++ b/spec/frontend/api_spec.js @@ -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'); }); }); diff --git a/spec/frontend/awards_handler_spec.js b/spec/frontend/awards_handler_spec.js index c9f920a8510..51271770436 100644 --- a/spec/frontend/awards_handler_spec.js +++ b/spec/frontend/awards_handler_spec.js @@ -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); }); }); diff --git a/spec/frontend/badges/store/actions_spec.js b/spec/frontend/badges/store/actions_spec.js index 24f0759ca83..10f9593fd4e 100644 --- a/spec/frontend/badges/store/actions_spec.js +++ b/spec/frontend/badges/store/actions_spec.js @@ -315,7 +315,7 @@ describe('Badges store actions', () => { badgeInForm.linkUrl = "https://example.com?param="; 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( diff --git a/spec/frontend/badges/store/mutations_spec.js b/spec/frontend/badges/store/mutations_spec.js index dc02e3f6dcf..88a4e6b08f6 100644 --- a/spec/frontend/badges/store/mutations_spec.js +++ b/spec/frontend/badges/store/mutations_spec.js @@ -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); diff --git a/spec/frontend/batch_comments/components/diff_file_drafts_spec.js b/spec/frontend/batch_comments/components/diff_file_drafts_spec.js index c62cc9f24ff..5a227aca034 100644 --- a/spec/frontend/batch_comments/components/diff_file_drafts_spec.js +++ b/spec/frontend/batch_comments/components/diff_file_drafts_spec.js @@ -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); diff --git a/spec/frontend/behaviors/bind_in_out_spec.js b/spec/frontend/behaviors/bind_in_out_spec.js index 7b40b1d3cd7..9d585668ee9 100644 --- a/spec/frontend/behaviors/bind_in_out_spec.js +++ b/spec/frontend/behaviors/bind_in_out_spec.js @@ -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', () => { diff --git a/spec/frontend/behaviors/components/global_alerts_spec.js b/spec/frontend/behaviors/components/global_alerts_spec.js index e3d77566dc2..3f52c97b967 100644 --- a/spec/frontend/behaviors/components/global_alerts_spec.js +++ b/spec/frontend/behaviors/components/global_alerts_spec.js @@ -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); }); }); diff --git a/spec/frontend/behaviors/date_picker_spec.js b/spec/frontend/behaviors/date_picker_spec.js index aa1a91b7f66..3cf4e68b41d 100644 --- a/spec/frontend/behaviors/date_picker_spec.js +++ b/spec/frontend/behaviors/date_picker_spec.js @@ -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'], ['']]); }); }); diff --git a/spec/frontend/behaviors/markdown/highlight_current_user_spec.js b/spec/frontend/behaviors/markdown/highlight_current_user_spec.js index ad70efdf7c3..6140b304702 100644 --- a/spec/frontend/behaviors/markdown/highlight_current_user_spec.js +++ b/spec/frontend/behaviors/markdown/highlight_current_user_spec.js @@ -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'); }); diff --git a/spec/frontend/blob/components/blob_header_default_actions_spec.js b/spec/frontend/blob/components/blob_header_default_actions_spec.js index 9565ca2450c..fdfdd2d0b6b 100644 --- a/spec/frontend/blob/components/blob_header_default_actions_spec.js +++ b/spec/frontend/blob/components/blob_header_default_actions_spec.js @@ -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); }); diff --git a/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js b/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js index 6e5af019c78..3f19c9cccbb 100644 --- a/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js +++ b/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js @@ -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); }); diff --git a/spec/frontend/blob/components/table_contents_spec.js b/spec/frontend/blob/components/table_contents_spec.js index acfcef9704c..09f806e3eaa 100644 --- a/spec/frontend/blob/components/table_contents_spec.js +++ b/spec/frontend/blob/components/table_contents_spec.js @@ -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 () => { diff --git a/spec/frontend/blob/line_highlighter_spec.js b/spec/frontend/blob/line_highlighter_spec.js index 4250a0610ad..ac0525c1621 100644 --- a/spec/frontend/blob/line_highlighter_spec.js +++ b/spec/frontend/blob/line_highlighter_spec.js @@ -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); } diff --git a/spec/frontend/boards/board_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js index 38b3ac5d239..43328d8d999 100644 --- a/spec/frontend/boards/board_card_inner_spec.js +++ b/spec/frontend/boards/board_card_inner_spec.js @@ -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); }); }); diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js index 8947be283ae..683e614b1ef 100644 --- a/spec/frontend/boards/board_list_spec.js +++ b/spec/frontend/boards/board_list_spec.js @@ -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', () => { diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js index 140b60b9fe5..79af90f0139 100644 --- a/spec/frontend/boards/components/board_form_spec.js +++ b/spec/frontend/boards/components/board_form_spec.js @@ -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([ [ { diff --git a/spec/frontend/boards/components/sidebar/board_editable_item_spec.js b/spec/frontend/boards/components/sidebar/board_editable_item_spec.js index 6dbeac3864f..0d2f9a0f5c8 100644 --- a/spec/frontend/boards/components/sidebar/board_editable_item_spec.js +++ b/spec/frontend/boards/components/sidebar/board_editable_item_spec.js @@ -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 () => { diff --git a/spec/frontend/boards/project_select_spec.js b/spec/frontend/boards/project_select_spec.js index 67f7c13929f..5c3428122b7 100644 --- a/spec/frontend/boards/project_select_spec.js +++ b/spec/frontend/boards/project_select_spec.js @@ -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); }); }); diff --git a/spec/frontend/branches/components/divergence_graph_spec.js b/spec/frontend/branches/components/divergence_graph_spec.js index 66193c2ebf0..8aba1c487aa 100644 --- a/spec/frontend/branches/components/divergence_graph_spec.js +++ b/spec/frontend/branches/components/divergence_graph_spec.js @@ -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(); }); diff --git a/spec/frontend/captcha/init_recaptcha_script_spec.js b/spec/frontend/captcha/init_recaptcha_script_spec.js index 3e2d7ba00ee..f5f2a1ef6d1 100644 --- a/spec/frontend/captcha/init_recaptcha_script_spec.js +++ b/spec/frontend/captcha/init_recaptcha_script_spec.js @@ -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', () => { diff --git a/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js b/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js index 0c44c6cbba9..5b9e36cff8f 100644 --- a/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js +++ b/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js @@ -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); }); diff --git a/spec/frontend/ci/catalog/components/list/ci_resources_list_item_spec.js b/spec/frontend/ci/catalog/components/list/ci_resources_list_item_spec.js index 58906cfa467..0e69165eaed 100644 --- a/spec/frontend/ci/catalog/components/list/ci_resources_list_item_spec.js +++ b/spec/frontend/ci/catalog/components/list/ci_resources_list_item_spec.js @@ -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', () => { diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js index 5b9d72110c0..ac67d6daa9f 100644 --- a/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js +++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js @@ -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); diff --git a/spec/frontend/ci/common/pipeline_inputs/pipeline_inputs_table/inputs_table_skeleton_loader_spec.js b/spec/frontend/ci/common/pipeline_inputs/pipeline_inputs_table/inputs_table_skeleton_loader_spec.js index 8d3844c3c3c..6be6f58fa75 100644 --- a/spec/frontend/ci/common/pipeline_inputs/pipeline_inputs_table/inputs_table_skeleton_loader_spec.js +++ b/spec/frontend/ci/common/pipeline_inputs/pipeline_inputs_table/inputs_table_skeleton_loader_spec.js @@ -21,6 +21,6 @@ describe('InputsTableSkeletonLoader', () => { }); it('renders 8 rects (2 rows x 4 columns)', () => { - expect(findSkeletonRects().length).toBe(8); + expect(findSkeletonRects()).toHaveLength(8); }); }); diff --git a/spec/frontend/ci/job_details/components/log/line_header_spec.js b/spec/frontend/ci/job_details/components/log/line_header_spec.js index 998b95b2b45..b1dba1eb353 100644 --- a/spec/frontend/ci/job_details/components/log/line_header_spec.js +++ b/spec/frontend/ci/job_details/components/log/line_header_spec.js @@ -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); }); }); diff --git a/spec/frontend/ci/pipeline_details/graph/components/stage_column_component_spec.js b/spec/frontend/ci/pipeline_details/graph/components/stage_column_component_spec.js index 96f419991f7..f15694bd555 100644 --- a/spec/frontend/ci/pipeline_details/graph/components/stage_column_component_spec.js +++ b/spec/frontend/ci/pipeline_details/graph/components/stage_column_component_spec.js @@ -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); }); }); diff --git a/spec/frontend/ci/pipeline_details/test_reports/test_suite_table_spec.js b/spec/frontend/ci/pipeline_details/test_reports/test_suite_table_spec.js index 181b8df31f4..c6de99ec6ec 100644 --- a/spec/frontend/ci/pipeline_details/test_reports/test_suite_table_spec.js +++ b/spec/frontend/ci/pipeline_details/test_reports/test_suite_table_spec.js @@ -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', () => { diff --git a/spec/frontend/ci/pipeline_details/test_reports/test_summary_table_spec.js b/spec/frontend/ci/pipeline_details/test_reports/test_summary_table_spec.js index bb62fbcb32c..20a79fbade5 100644 --- a/spec/frontend/ci/pipeline_details/test_reports/test_summary_table_spec.js +++ b/spec/frontend/ci/pipeline_details/test_reports/test_summary_table_spec.js @@ -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', () => { diff --git a/spec/frontend/ci/pipeline_mini_graph/pipeline_stage_dropdown_spec.js b/spec/frontend/ci/pipeline_mini_graph/pipeline_stage_dropdown_spec.js index 1c8cb843cbf..d0ff7e2c365 100644 --- a/spec/frontend/ci/pipeline_mini_graph/pipeline_stage_dropdown_spec.js +++ b/spec/frontend/ci/pipeline_mini_graph/pipeline_stage_dropdown_spec.js @@ -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); }); }); diff --git a/spec/frontend/ci/pipeline_new/components/variable_values_listbox_spec.js b/spec/frontend/ci/pipeline_new/components/variable_values_listbox_spec.js index 5226d962f61..3af30bd117e 100644 --- a/spec/frontend/ci/pipeline_new/components/variable_values_listbox_spec.js +++ b/spec/frontend/ci/pipeline_new/components/variable_values_listbox_spec.js @@ -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'); }); }); diff --git a/spec/frontend/ci/pipelines_page/components/empty_state/ci_templates_spec.js b/spec/frontend/ci/pipelines_page/components/empty_state/ci_templates_spec.js index 980a8be24ea..e0bb334f0c2 100644 --- a/spec/frontend/ci/pipelines_page/components/empty_state/ci_templates_spec.js +++ b/spec/frontend/ci/pipelines_page/components/empty_state/ci_templates_spec.js @@ -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++'); }); diff --git a/spec/frontend/ci/runner/components/runner_projects_spec.js b/spec/frontend/ci/runner/components/runner_projects_spec.js index fea138f58c7..8259dd71981 100644 --- a/spec/frontend/ci/runner/components/runner_projects_spec.js +++ b/spec/frontend/ci/runner/components/runner_projects_spec.js @@ -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); }); diff --git a/spec/frontend/ci/runner/components/runner_tags_spec.js b/spec/frontend/ci/runner/components/runner_tags_spec.js index 17f1de734c5..da31867db2c 100644 --- a/spec/frontend/ci/runner/components/runner_tags_spec.js +++ b/spec/frontend/ci/runner/components/runner_tags_spec.js @@ -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'); diff --git a/spec/frontend/clusters/agents/components/integration_status_spec.js b/spec/frontend/clusters/agents/components/integration_status_spec.js index 0f3da3e02be..36b3ff40a31 100644 --- a/spec/frontend/clusters/agents/components/integration_status_spec.js +++ b/spec/frontend/clusters/agents/components/integration_status_spec.js @@ -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({ diff --git a/spec/frontend/clusters_list/components/clusters_view_all_spec.js b/spec/frontend/clusters_list/components/clusters_view_all_spec.js index 79777d58391..aa13d8ac98d 100644 --- a/spec/frontend/clusters_list/components/clusters_view_all_spec.js +++ b/spec/frontend/clusters_list/components/clusters_view_all_spec.js @@ -89,7 +89,7 @@ describe('ClustersViewAllComponent', () => { }); it('should render 2 cards', () => { - expect(findCards().length).toBe(2); + expect(findCards()).toHaveLength(2); }); }); diff --git a/spec/frontend/code_navigation/components/popover_spec.js b/spec/frontend/code_navigation/components/popover_spec.js index 9698dc3e091..33efe345cba 100644 --- a/spec/frontend/code_navigation/components/popover_spec.js +++ b/spec/frontend/code_navigation/components/popover_spec.js @@ -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', () => { diff --git a/spec/frontend/code_navigation/store/actions_spec.js b/spec/frontend/code_navigation/store/actions_spec.js index 7d411726f07..0f61f68ee9c 100644 --- a/spec/frontend/code_navigation/store/actions_spec.js +++ b/spec/frontend/code_navigation/store/actions_spec.js @@ -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 }, ]); diff --git a/spec/frontend/code_navigation/utils/index_spec.js b/spec/frontend/code_navigation/utils/index_spec.js index c3c7d40fa86..a8752e6b11b 100644 --- a/spec/frontend/code_navigation/utils/index_spec.js +++ b/spec/frontend/code_navigation/utils/index_spec.js @@ -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(' '); diff --git a/spec/frontend/comment_templates/pages/index_spec.js b/spec/frontend/comment_templates/pages/index_spec.js index b432a84e92e..0f8b9a03fd5 100644 --- a/spec/frontend/comment_templates/pages/index_spec.js +++ b/spec/frontend/comment_templates/pages/index_spec.js @@ -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]), ); diff --git a/spec/frontend/commits_spec.js b/spec/frontend/commits_spec.js index 327e8d3cfca..80f6ef3f010 100644 --- a/spec/frontend/commits_spec.js +++ b/spec/frontend/commits_spec.js @@ -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); }); }); diff --git a/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js b/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js index 0d1e432c22f..42a48333172 100644 --- a/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js +++ b/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js @@ -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', () => { diff --git a/spec/frontend/contributors/component/contributors_spec.js b/spec/frontend/contributors/component/contributors_spec.js index ac06111155f..ecd17af5155 100644 --- a/spec/frontend/contributors/component/contributors_spec.js +++ b/spec/frontend/contributors/component/contributors_spec.js @@ -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', diff --git a/spec/frontend/create_item_dropdown_spec.js b/spec/frontend/create_item_dropdown_spec.js index df4bfdb4ad0..dc03178e1ca 100644 --- a/spec/frontend/create_item_dropdown_spec.js +++ b/spec/frontend/create_item_dropdown_spec.js @@ -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'); }); diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js index 87d6b6ec62f..4ad44092a04 100644 --- a/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js +++ b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js @@ -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'); }); diff --git a/spec/frontend/deploy_keys/components/app_spec.js b/spec/frontend/deploy_keys/components/app_spec.js index 949f0146d5f..58129d3a69a 100644 --- a/spec/frontend/deploy_keys/components/app_spec.js +++ b/spec/frontend/deploy_keys/components/app_spec.js @@ -102,7 +102,7 @@ describe('Deploy keys app component', () => { }, }); await mountComponent(); - expect(findKeyPanels().length).toBe(3); + expect(findKeyPanels()).toHaveLength(3); }); describe.each` diff --git a/spec/frontend/deploy_keys/components/key_spec.js b/spec/frontend/deploy_keys/components/key_spec.js index 246e551d183..ae6fd19cd68 100644 --- a/spec/frontend/deploy_keys/components/key_spec.js +++ b/spec/frontend/deploy_keys/components/key_spec.js @@ -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); }); }); diff --git a/spec/frontend/deprecated_jquery_dropdown_spec.js b/spec/frontend/deprecated_jquery_dropdown_spec.js index a814d2fe293..c63e43fbcc7 100644 --- a/spec/frontend/deprecated_jquery_dropdown_spec.js +++ b/spec/frontend/deprecated_jquery_dropdown_spec.js @@ -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); }); diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js index 9d0bd732eb2..2e7a7082fbf 100644 --- a/spec/frontend/design_management/pages/index_spec.js +++ b/spec/frontend/design_management/pages/index_spec.js @@ -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); }); diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js index 51d73bddb63..395947c6ccf 100644 --- a/spec/frontend/diffs/components/app_spec.js +++ b/spec/frontend/diffs/components/app_spec.js @@ -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', () => { diff --git a/spec/frontend/diffs/components/diff_discussions_spec.js b/spec/frontend/diffs/components/diff_discussions_spec.js index a741251d010..1f00c2f5922 100644 --- a/spec/frontend/diffs/components/diff_discussions_spec.js +++ b/spec/frontend/diffs/components/diff_discussions_spec.js @@ -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); }); }); diff --git a/spec/frontend/diffs/components/diff_file_spec.js b/spec/frontend/diffs/components/diff_file_spec.js index 4142dcf7228..b8df50c2fb0 100644 --- a/spec/frontend/diffs/components/diff_file_spec.js +++ b/spec/frontend/diffs/components/diff_file_spec.js @@ -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', () => { diff --git a/spec/frontend/diffs/components/diff_gutter_avatars_spec.js b/spec/frontend/diffs/components/diff_gutter_avatars_spec.js index f272e6b7c7a..0ce2aad1058 100644 --- a/spec/frontend/diffs/components/diff_gutter_avatars_spec.js +++ b/spec/frontend/diffs/components/diff_gutter_avatars_spec.js @@ -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 diff --git a/spec/frontend/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js index 99fe973a697..9ef6aa070e9 100644 --- a/spec/frontend/diffs/components/diff_stats_spec.js +++ b/spec/frontend/diffs/components/diff_stats_spec.js @@ -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); }); }); diff --git a/spec/frontend/diffs/components/diff_view_spec.js b/spec/frontend/diffs/components/diff_view_spec.js index cfe5d5fe21c..03c432fc960 100644 --- a/spec/frontend/diffs/components/diff_view_spec.js +++ b/spec/frontend/diffs/components/diff_view_spec.js @@ -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); }, ); diff --git a/spec/frontend/diffs/store/getters_spec.js b/spec/frontend/diffs/store/getters_spec.js index b8491975c7e..50e073fbd88 100644 --- a/spec/frontend/diffs/store/getters_spec.js +++ b/spec/frontend/diffs/store/getters_spec.js @@ -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); }); }); diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js index a5ad95c2791..c4f853e318b 100644 --- a/spec/frontend/diffs/store/mutations_spec.js +++ b/spec/frontend/diffs/store/mutations_spec.js @@ -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'); }); }); diff --git a/spec/frontend/diffs/store/utils_spec.js b/spec/frontend/diffs/store/utils_spec.js index c5469c1443d..5d60fd4d5b2 100644 --- a/spec/frontend/diffs/store/utils_spec.js +++ b/spec/frontend/diffs/store/utils_spec.js @@ -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); }); diff --git a/spec/frontend/diffs/stores/legacy_diffs/getters_spec.js b/spec/frontend/diffs/stores/legacy_diffs/getters_spec.js index 6edaf5d3665..5576d0a4f2b 100644 --- a/spec/frontend/diffs/stores/legacy_diffs/getters_spec.js +++ b/spec/frontend/diffs/stores/legacy_diffs/getters_spec.js @@ -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); }); }); diff --git a/spec/frontend/diffs/stores/legacy_diffs/mutations_spec.js b/spec/frontend/diffs/stores/legacy_diffs/mutations_spec.js index 7eef0b4b6de..a74b674bcc5 100644 --- a/spec/frontend/diffs/stores/legacy_diffs/mutations_spec.js +++ b/spec/frontend/diffs/stores/legacy_diffs/mutations_spec.js @@ -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'); }); }); diff --git a/spec/frontend/editor/utils_spec.js b/spec/frontend/editor/utils_spec.js index b9ed44f268c..f1291ce18dd 100644 --- a/spec/frontend/editor/utils_spec.js +++ b/spec/frontend/editor/utils_spec.js @@ -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); }); }); diff --git a/spec/frontend/emoji/components/category_spec.js b/spec/frontend/emoji/components/category_spec.js index ad06feab4ec..e8c54b98028 100644 --- a/spec/frontend/emoji/components/category_spec.js +++ b/spec/frontend/emoji/components/category_spec.js @@ -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 () => { diff --git a/spec/frontend/emoji/components/emoji_group_spec.js b/spec/frontend/emoji/components/emoji_group_spec.js index 8adb2f2c7eb..46a25ba5422 100644 --- a/spec/frontend/emoji/components/emoji_group_spec.js +++ b/spec/frontend/emoji/components/emoji_group_spec.js @@ -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', () => { diff --git a/spec/frontend/emoji/index_spec.js b/spec/frontend/emoji/index_spec.js index da4cf3a6bbf..75d2131df64 100644 --- a/spec/frontend/emoji/index_spec.js +++ b/spec/frontend/emoji/index_spec.js @@ -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); }); }); }); diff --git a/spec/frontend/emoji/support/unicode_support_map_spec.js b/spec/frontend/emoji/support/unicode_support_map_spec.js index 7b0fa297168..209dc4d785f 100644 --- a/spec/frontend/emoji/support/unicode_support_map_spec.js +++ b/spec/frontend/emoji/support/unicode_support_map_spec.js @@ -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(); }); }); diff --git a/spec/frontend/environments/enable_review_app_modal_spec.js b/spec/frontend/environments/enable_review_app_modal_spec.js index f5571609931..47caedd9d20 100644 --- a/spec/frontend/environments/enable_review_app_modal_spec.js +++ b/spec/frontend/environments/enable_review_app_modal_spec.js @@ -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); }); diff --git a/spec/frontend/environments/environment_actions_spec.js b/spec/frontend/environments/environment_actions_spec.js index f13c54ee707..4bd67d9ee2a 100644 --- a/spec/frontend/environments/environment_actions_spec.js +++ b/spec/frontend/environments/environment_actions_spec.js @@ -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', () => { diff --git a/spec/frontend/environments/folder/environments_folder_app_spec.js b/spec/frontend/environments/folder/environments_folder_app_spec.js index 83554af52bb..5cb81facc1e 100644 --- a/spec/frontend/environments/folder/environments_folder_app_spec.js +++ b/spec/frontend/environments/folder/environments_folder_app_spec.js @@ -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); }); [ diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js index 7d8f444e575..1f78e438456 100644 --- a/spec/frontend/error_tracking/components/error_details_spec.js +++ b/spec/frontend/error_tracking/components/error_details_spec.js @@ -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))( diff --git a/spec/frontend/error_tracking/components/error_tracking_list_spec.js b/spec/frontend/error_tracking/components/error_tracking_list_spec.js index 87823c79b3f..f4327d1cabb 100644 --- a/spec/frontend/error_tracking/components/error_tracking_list_spec.js +++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js @@ -142,7 +142,7 @@ describe('ErrorTrackingList', () => { }); it('shows list of errors in a table', () => { - expect(findErrorListRows().length).toEqual(store.state.list.errors.length); + expect(findErrorListRows()).toHaveLength(store.state.list.errors.length); }); it('shows user count', () => { @@ -250,7 +250,7 @@ describe('ErrorTrackingList', () => { it('shows empty table', () => { expect(findLoadingIcon().exists()).toBe(false); - expect(findErrorListRows().length).toEqual(1); + expect(findErrorListRows()).toHaveLength(1); expect(findSortDropdown().exists()).toBe(true); }); @@ -273,7 +273,7 @@ describe('ErrorTrackingList', () => { expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true); expect(findLoadingIcon().exists()).toBe(false); expect(findErrorListTable().exists()).toBe(false); - expect(dropdownsArray().length).toBe(0); + expect(dropdownsArray()).toHaveLength(0); }); }); @@ -444,7 +444,7 @@ describe('ErrorTrackingList', () => { await nextTick(); const dropdownItems = wrapper.findAll('[data-testid="recent-searches-dropdown"] li'); - expect(dropdownItems.length).toBe(3); + expect(dropdownItems).toHaveLength(3); expect(dropdownItems.at(0).text()).toBe('great'); expect(dropdownItems.at(1).text()).toBe('search'); }); diff --git a/spec/frontend/error_tracking/components/stacktrace_entry_spec.js b/spec/frontend/error_tracking/components/stacktrace_entry_spec.js index 2db32bf360c..ac20265c359 100644 --- a/spec/frontend/error_tracking/components/stacktrace_entry_spec.js +++ b/spec/frontend/error_tracking/components/stacktrace_entry_spec.js @@ -49,15 +49,15 @@ describe('Stacktrace Entry', () => { it('should render stacktrace entry table expanded', () => { mountComponent({ expanded: true, lines }); expect(wrapper.find('table').exists()).toBe(true); - expect(wrapper.findAll('tr.line_holder').length).toBe(4); - expect(findAllContentLines().length).toBe(1); + expect(wrapper.findAll('tr.line_holder')).toHaveLength(4); + expect(findAllContentLines()).toHaveLength(1); }); it('should render stacktrace entry table expanded with GraphQL API data format', () => { mountComponent({ expanded: true, lines: graphqlLines }); expect(wrapper.find('table').exists()).toBe(true); - expect(wrapper.findAll('tr.line_holder').length).toBe(4); - expect(findAllContentLines().length).toBe(1); + expect(wrapper.findAll('tr.line_holder')).toHaveLength(4); + expect(findAllContentLines()).toHaveLength(1); }); it('should render file information if filePath exists', () => { diff --git a/spec/frontend/error_tracking/components/stacktrace_spec.js b/spec/frontend/error_tracking/components/stacktrace_spec.js index f9e2d824455..4c5160ba41a 100644 --- a/spec/frontend/error_tracking/components/stacktrace_spec.js +++ b/spec/frontend/error_tracking/components/stacktrace_spec.js @@ -43,7 +43,7 @@ describe('ErrorDetails', () => { it('should render single Stacktrace entry', () => { mountComponent([stackTraceEntry]); const allEntries = wrapper.findAllComponents(StackTraceEntry); - expect(allEntries.length).toBe(1); + expect(allEntries).toHaveLength(1); const entry = allEntries.at(0); expect(entry.props()).toEqual({ lines: stackTraceEntry.context, @@ -58,7 +58,7 @@ describe('ErrorDetails', () => { it('should render single Stacktrace entry with GraphQL API data format', () => { mountComponent([graphqlStackTraceEntry]); const allEntries = wrapper.findAllComponents(StackTraceEntry); - expect(allEntries.length).toBe(1); + expect(allEntries).toHaveLength(1); const entry = allEntries.at(0); expect(entry.props()).toEqual({ lines: graphqlStackTraceEntry.context, @@ -74,7 +74,7 @@ describe('ErrorDetails', () => { const entriesNum = 3; mountComponent(new Array(entriesNum).fill(stackTraceEntry)); const entries = wrapper.findAllComponents(StackTraceEntry); - expect(entries.length).toBe(entriesNum); + expect(entries).toHaveLength(entriesNum); expect(entries.at(0).props('expanded')).toBe(true); expect(entries.at(1).props('expanded')).toBe(false); expect(entries.at(2).props('expanded')).toBe(false); diff --git a/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js b/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js index 57c06eae2aa..57a0efba1fe 100644 --- a/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js +++ b/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js @@ -27,7 +27,7 @@ describe('error tracking settings form', () => { describe('an empty form', () => { it('is rendered', () => { - expect(wrapper.findAllComponents(GlFormInput).length).toBe(2); + expect(wrapper.findAllComponents(GlFormInput)).toHaveLength(2); expect(wrapper.findComponent(GlFormInput).attributes('id')).toBe('error-tracking-api-host'); expect(wrapper.findAllComponents(GlFormInput).at(1).attributes('id')).toBe( 'error-tracking-token', diff --git a/spec/frontend/error_tracking_settings/components/project_dropdown_spec.js b/spec/frontend/error_tracking_settings/components/project_dropdown_spec.js index e720e77e4af..c5e751c67fe 100644 --- a/spec/frontend/error_tracking_settings/components/project_dropdown_spec.js +++ b/spec/frontend/error_tracking_settings/components/project_dropdown_spec.js @@ -72,7 +72,7 @@ describe('error tracking settings project dropdown', () => { it('contains a number of dropdown items', () => { expect(wrapper.findComponent(GlCollapsibleListbox).exists()).toBe(true); - expect(wrapper.findComponent(GlCollapsibleListbox).props('items').length).toBe(2); + expect(wrapper.findComponent(GlCollapsibleListbox).props('items')).toHaveLength(2); }); }); diff --git a/spec/frontend/error_tracking_settings/store/actions_spec.js b/spec/frontend/error_tracking_settings/store/actions_spec.js index d8f61be6df7..feffe11bd23 100644 --- a/spec/frontend/error_tracking_settings/store/actions_spec.js +++ b/spec/frontend/error_tracking_settings/store/actions_spec.js @@ -43,7 +43,7 @@ describe('error tracking settings actions', () => { }, ], ); - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); }); it('should handle a server error', async () => { @@ -60,7 +60,7 @@ describe('error tracking settings actions', () => { }, ], ); - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); }); it('should request projects correctly', () => { @@ -121,7 +121,7 @@ describe('error tracking settings actions', () => { it('should save the page', async () => { mock.onPatch(TEST_HOST).reply(HTTP_STATUS_OK); await testAction(actions.updateSettings, null, state, [], [{ type: 'requestSettings' }]); - expect(mock.history.patch.length).toBe(1); + expect(mock.history.patch).toHaveLength(1); expect(refreshCurrentPage).toHaveBeenCalled(); }); @@ -140,7 +140,7 @@ describe('error tracking settings actions', () => { }, ], ); - expect(mock.history.patch.length).toBe(1); + expect(mock.history.patch).toHaveLength(1); }); it('should request to save the page', () => { diff --git a/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js b/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js index b75e2f653e9..366218c9dff 100644 --- a/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js +++ b/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js @@ -89,7 +89,7 @@ describe('Configure Feature Flags Modal', () => { it('should display one and only one danger alert', () => { const dangerGlAlert = findDangerGlAlert(); - expect(dangerGlAlert.length).toBe(1); + expect(dangerGlAlert).toHaveLength(1); expect(dangerGlAlert.at(0).text()).toMatch(/Regenerating the instance ID/); }); diff --git a/spec/frontend/filtered_search/dropdown_utils_spec.js b/spec/frontend/filtered_search/dropdown_utils_spec.js index 776601ab04e..dd29e725754 100644 --- a/spec/frontend/filtered_search/dropdown_utils_spec.js +++ b/spec/frontend/filtered_search/dropdown_utils_spec.js @@ -227,7 +227,7 @@ describe('Dropdown Utils', () => { DropdownUtils.setDataValueIfSelected(null, '=', selected); - expect(FilteredSearchDropdownManager.addWordToInput.mock.calls.length).toEqual(1); + expect(FilteredSearchDropdownManager.addWordToInput.mock.calls).toHaveLength(1); }); it('returns true when dataValue exists', () => { diff --git a/spec/frontend/filtered_search/droplab/drop_down_spec.js b/spec/frontend/filtered_search/droplab/drop_down_spec.js index 6fbb4394944..536220afa72 100644 --- a/spec/frontend/filtered_search/droplab/drop_down_spec.js +++ b/spec/frontend/filtered_search/droplab/drop_down_spec.js @@ -226,7 +226,7 @@ describe('DropLab DropDown', () => { it('does not select element', () => { DropDown.prototype.clickEvent.call(testContext.dropdown, testContext.event); - expect(testContext.ignoredButton.closest.mock.calls.length).toBe(1); + expect(testContext.ignoredButton.closest.mock.calls).toHaveLength(1); expect(testContext.ignoredButton.closest).toHaveBeenCalledWith('.droplab-item-ignore'); expect(testContext.dropdown.addSelectedClass).not.toHaveBeenCalled(); }); @@ -427,7 +427,7 @@ describe('DropLab DropDown', () => { }); it('should call .renderChildren for each data item', () => { - expect(testContext.dropdown.renderChildren.mock.calls.length).toBe(testContext.data.length); + expect(testContext.dropdown.renderChildren.mock.calls).toHaveLength(testContext.data.length); }); it('sets the renderableList .innerHTML', () => { diff --git a/spec/frontend/filtered_search/droplab/plugins/ajax_filter_spec.js b/spec/frontend/filtered_search/droplab/plugins/ajax_filter_spec.js index c958f669f9a..34bd048115f 100644 --- a/spec/frontend/filtered_search/droplab/plugins/ajax_filter_spec.js +++ b/spec/frontend/filtered_search/droplab/plugins/ajax_filter_spec.js @@ -48,7 +48,7 @@ describe('AjaxFilter', () => { }; await AjaxFilter.trigger(); - expect(dummyConfig.onLoadingFinished.mock.calls.length).toBe(1); + expect(dummyConfig.onLoadingFinished.mock.calls).toHaveLength(1); }); it('does not call onLoadingFinished if Ajax call fails', async () => { @@ -59,7 +59,7 @@ describe('AjaxFilter', () => { }; await expect(AjaxFilter.trigger()).rejects.toEqual(dummyError); - expect(dummyConfig.onLoadingFinished.mock.calls.length).toBe(0); + expect(dummyConfig.onLoadingFinished.mock.calls).toHaveLength(0); }); }); }); diff --git a/spec/frontend/filtered_search/droplab/plugins/ajax_spec.js b/spec/frontend/filtered_search/droplab/plugins/ajax_spec.js index c968b982091..b32e5368330 100644 --- a/spec/frontend/filtered_search/droplab/plugins/ajax_spec.js +++ b/spec/frontend/filtered_search/droplab/plugins/ajax_spec.js @@ -24,7 +24,7 @@ describe('Ajax', () => { it('calls preprocessing', () => { Ajax.preprocessing(config, []); - expect(config.preprocessing.mock.calls.length).toBe(1); + expect(config.preprocessing.mock.calls).toHaveLength(1); }); it('overrides AjaxCache', () => { @@ -34,7 +34,7 @@ describe('Ajax', () => { Ajax.preprocessing(config, []); - expect(AjaxCache.override.mock.calls.length).toBe(1); + expect(AjaxCache.override.mock.calls).toHaveLength(1); }); }); }); diff --git a/spec/frontend/filtered_search/droplab/plugins/input_setter_spec.js b/spec/frontend/filtered_search/droplab/plugins/input_setter_spec.js index 811b5ca4573..39c62778e31 100644 --- a/spec/frontend/filtered_search/droplab/plugins/input_setter_spec.js +++ b/spec/frontend/filtered_search/droplab/plugins/input_setter_spec.js @@ -117,7 +117,7 @@ describe('InputSetter', () => { it('should call .setInput for each config element', () => { const allArgs = testContext.inputSetter.setInput.mock.calls; - expect(allArgs.length).toEqual(2); + expect(allArgs).toHaveLength(2); allArgs.forEach((args, i) => { expect(args[0]).toBe(testContext.config[i]); diff --git a/spec/frontend/filtered_search/filtered_search_manager_spec.js b/spec/frontend/filtered_search/filtered_search_manager_spec.js index 69f938b72da..0826b63f7e5 100644 --- a/spec/frontend/filtered_search/filtered_search_manager_spec.js +++ b/spec/frontend/filtered_search/filtered_search_manager_spec.js @@ -478,31 +478,31 @@ describe('Filtered Search Manager', () => { }); it('removes selected token when the backspace key is pressed', () => { - expect(getVisualTokens().length).toEqual(1); + expect(getVisualTokens()).toHaveLength(1); dispatchBackspaceEvent(document, 'keydown'); - expect(getVisualTokens().length).toEqual(0); + expect(getVisualTokens()).toHaveLength(0); }); it('removes selected token when the delete key is pressed', () => { - expect(getVisualTokens().length).toEqual(1); + expect(getVisualTokens()).toHaveLength(1); dispatchDeleteEvent(document, 'keydown'); - expect(getVisualTokens().length).toEqual(0); + expect(getVisualTokens()).toHaveLength(0); }); it('updates the input placeholder after removal', () => { manager.handleInputPlaceholder(); expect(input.placeholder).toEqual(''); - expect(getVisualTokens().length).toEqual(1); + expect(getVisualTokens()).toHaveLength(1); dispatchBackspaceEvent(document, 'keydown'); expect(input.placeholder).not.toEqual(''); - expect(getVisualTokens().length).toEqual(0); + expect(getVisualTokens()).toHaveLength(0); }); it('updates the clear button after removal', () => { @@ -511,12 +511,12 @@ describe('Filtered Search Manager', () => { const clearButton = document.querySelector('.clear-search'); expect(clearButton.classList.contains('hidden')).toEqual(false); - expect(getVisualTokens().length).toEqual(1); + expect(getVisualTokens()).toHaveLength(1); dispatchBackspaceEvent(document, 'keydown'); expect(clearButton.classList.contains('hidden')).toEqual(true); - expect(getVisualTokens().length).toEqual(0); + expect(getVisualTokens()).toHaveLength(0); }); }); diff --git a/spec/frontend/filtered_search/filtered_search_tokenizer_spec.js b/spec/frontend/filtered_search/filtered_search_tokenizer_spec.js index b6a95eb55c7..f0b9cab7385 100644 --- a/spec/frontend/filtered_search/filtered_search_tokenizer_spec.js +++ b/spec/frontend/filtered_search/filtered_search_tokenizer_spec.js @@ -9,7 +9,7 @@ describe('Filtered Search Tokenizer', () => { const results = FilteredSearchTokenizer.processTokens('searchTerm', allowedKeys); expect(results.searchToken).toBe('searchTerm'); - expect(results.tokens.length).toBe(0); + expect(results.tokens).toHaveLength(0); expect(results.lastToken).toBe(results.searchToken); }); @@ -20,7 +20,7 @@ describe('Filtered Search Tokenizer', () => { ); expect(results.searchToken).toBe(''); - expect(results.tokens.length).toBe(4); + expect(results.tokens).toHaveLength(4); expect(results.tokens[3]).toBe(results.lastToken); expect(results.tokens[0].key).toBe('author'); @@ -47,7 +47,7 @@ describe('Filtered Search Tokenizer', () => { ); expect(results.searchToken).toBe('searchTerm anotherSearchTerm'); - expect(results.tokens.length).toBe(1); + expect(results.tokens).toHaveLength(1); expect(results.tokens[0]).toBe(results.lastToken); expect(results.tokens[0].key).toBe('milestone'); expect(results.tokens[0].value).toBe('none'); @@ -61,7 +61,7 @@ describe('Filtered Search Tokenizer', () => { ); expect(results.searchToken).toBe('searchTerm'); - expect(results.tokens.length).toBe(1); + expect(results.tokens).toHaveLength(1); expect(results.tokens[0].key).toBe('assignee'); expect(results.tokens[0].value).toBe('user'); expect(results.tokens[0].symbol).toBe('@'); @@ -75,7 +75,7 @@ describe('Filtered Search Tokenizer', () => { ); expect(results.searchToken).toBe('searchTerm anotherSearchTerm'); - expect(results.tokens.length).toBe(3); + expect(results.tokens).toHaveLength(3); expect(results.tokens[2]).toBe(results.lastToken); expect(results.tokens[0].key).toBe('author'); @@ -98,7 +98,7 @@ describe('Filtered Search Tokenizer', () => { ); expect(results.searchToken).toBe('searchTerm anotherSearchTerm'); - expect(results.tokens.length).toBe(3); + expect(results.tokens).toHaveLength(3); expect(results.tokens[2]).toBe(results.lastToken); expect(results.tokens[0].key).toBe('author'); @@ -119,13 +119,13 @@ describe('Filtered Search Tokenizer', () => { expect(results.lastToken).toBe('fake:token'); expect(results.searchToken).toBe('fake:token'); - expect(results.tokens.length).toEqual(0); + expect(results.tokens).toHaveLength(0); }); it('returns search value and token for mix of valid and invalid tokens', () => { const results = FilteredSearchTokenizer.processTokens('label:real fake:token', allowedKeys); - expect(results.tokens.length).toEqual(1); + expect(results.tokens).toHaveLength(1); expect(results.tokens[0].key).toBe('label'); expect(results.tokens[0].value).toBe('real'); expect(results.tokens[0].symbol).toBe(''); @@ -143,7 +143,7 @@ describe('Filtered Search Tokenizer', () => { it('removes duplicated values', () => { const results = FilteredSearchTokenizer.processTokens('label:~foo label:~foo', allowedKeys); - expect(results.tokens.length).toBe(1); + expect(results.tokens).toHaveLength(1); expect(results.tokens[0].key).toBe('label'); expect(results.tokens[0].value).toBe('foo'); expect(results.tokens[0].symbol).toBe('~'); diff --git a/spec/frontend/filtered_search/visual_token_value_spec.js b/spec/frontend/filtered_search/visual_token_value_spec.js index 85cfd8c67cc..5f41b227019 100644 --- a/spec/frontend/filtered_search/visual_token_value_spec.js +++ b/spec/frontend/filtered_search/visual_token_value_spec.js @@ -254,11 +254,11 @@ describe('Filtered Search Visual Tokens', () => { const { updateLabelTokenColorSpy, updateUserTokenAppearanceSpy } = setupSpies(subject); subject.render(tokenValueContainer, tokenValueElement); - expect(updateUserTokenAppearanceSpy.mock.calls.length).toBe(1); + expect(updateUserTokenAppearanceSpy.mock.calls).toHaveLength(1); const expectedArgs = [tokenValueContainer, tokenValueElement]; expect(updateUserTokenAppearanceSpy.mock.calls[0]).toEqual(expectedArgs); - expect(updateLabelTokenColorSpy.mock.calls.length).toBe(0); + expect(updateLabelTokenColorSpy.mock.calls).toHaveLength(0); }); it('renders a label token value element', () => { @@ -267,11 +267,11 @@ describe('Filtered Search Visual Tokens', () => { const { updateLabelTokenColorSpy, updateUserTokenAppearanceSpy } = setupSpies(subject); subject.render(tokenValueContainer, tokenValueElement); - expect(updateLabelTokenColorSpy.mock.calls.length).toBe(1); + expect(updateLabelTokenColorSpy.mock.calls).toHaveLength(1); const expectedArgs = [tokenValueContainer]; expect(updateLabelTokenColorSpy.mock.calls[0]).toEqual(expectedArgs); - expect(updateUserTokenAppearanceSpy.mock.calls.length).toBe(0); + expect(updateUserTokenAppearanceSpy.mock.calls).toHaveLength(0); }); it('renders a milestone token value element', () => { @@ -280,8 +280,8 @@ describe('Filtered Search Visual Tokens', () => { const { updateLabelTokenColorSpy, updateUserTokenAppearanceSpy } = setupSpies(subject); subject.render(tokenValueContainer, tokenValueElement); - expect(updateLabelTokenColorSpy.mock.calls.length).toBe(0); - expect(updateUserTokenAppearanceSpy.mock.calls.length).toBe(0); + expect(updateLabelTokenColorSpy.mock.calls).toHaveLength(0); + expect(updateUserTokenAppearanceSpy.mock.calls).toHaveLength(0); }); it('does not update user token appearance for `none` filter', () => { @@ -292,7 +292,7 @@ describe('Filtered Search Visual Tokens', () => { const { updateUserTokenAppearanceSpy } = setupSpies(subject); subject.render(tokenValueContainer, tokenValueElement); - expect(updateUserTokenAppearanceSpy.mock.calls.length).toBe(0); + expect(updateUserTokenAppearanceSpy.mock.calls).toHaveLength(0); }); it('does not update user token appearance for `None` filter', () => { @@ -303,7 +303,7 @@ describe('Filtered Search Visual Tokens', () => { const { updateUserTokenAppearanceSpy } = setupSpies(subject); subject.render(tokenValueContainer, tokenValueElement); - expect(updateUserTokenAppearanceSpy.mock.calls.length).toBe(0); + expect(updateUserTokenAppearanceSpy.mock.calls).toHaveLength(0); }); it('does not update user token appearance for `any` filter', () => { @@ -314,7 +314,7 @@ describe('Filtered Search Visual Tokens', () => { const { updateUserTokenAppearanceSpy } = setupSpies(subject); subject.render(tokenValueContainer, tokenValueElement); - expect(updateUserTokenAppearanceSpy.mock.calls.length).toBe(0); + expect(updateUserTokenAppearanceSpy.mock.calls).toHaveLength(0); }); it('does not update label token color for `None` filter', () => { @@ -325,7 +325,7 @@ describe('Filtered Search Visual Tokens', () => { const { updateLabelTokenColorSpy } = setupSpies(subject); subject.render(tokenValueContainer, tokenValueElement); - expect(updateLabelTokenColorSpy.mock.calls.length).toBe(0); + expect(updateLabelTokenColorSpy.mock.calls).toHaveLength(0); }); it('does not update label token color for `none` filter', () => { @@ -336,7 +336,7 @@ describe('Filtered Search Visual Tokens', () => { const { updateLabelTokenColorSpy } = setupSpies(subject); subject.render(tokenValueContainer, tokenValueElement); - expect(updateLabelTokenColorSpy.mock.calls.length).toBe(0); + expect(updateLabelTokenColorSpy.mock.calls).toHaveLength(0); }); it('does not update label token color for `any` filter', () => { @@ -347,7 +347,7 @@ describe('Filtered Search Visual Tokens', () => { const { updateLabelTokenColorSpy } = setupSpies(subject); subject.render(tokenValueContainer, tokenValueElement); - expect(updateLabelTokenColorSpy.mock.calls.length).toBe(0); + expect(updateLabelTokenColorSpy.mock.calls).toHaveLength(0); }); }); }); diff --git a/spec/frontend/gitlab_pages/components/deployments_spec.js b/spec/frontend/gitlab_pages/components/deployments_spec.js index 45fa20badef..7a5e40a9b31 100644 --- a/spec/frontend/gitlab_pages/components/deployments_spec.js +++ b/spec/frontend/gitlab_pages/components/deployments_spec.js @@ -110,11 +110,11 @@ describe('PagesDeployments', () => { }); it('renders a list for all primary deployments', () => { - expect(findAllPrimaryDeployments().length).toBe(10); + expect(findAllPrimaryDeployments()).toHaveLength(10); }); it('renders a list for all parallel deployments', () => { - expect(findAllParallelDeployments().length).toBe(10); + expect(findAllParallelDeployments()).toHaveLength(10); }); }); diff --git a/spec/frontend/gl_field_errors_spec.js b/spec/frontend/gl_field_errors_spec.js index 7233d6f4b6e..2df4f4ccec4 100644 --- a/spec/frontend/gl_field_errors_spec.js +++ b/spec/frontend/gl_field_errors_spec.js @@ -24,24 +24,24 @@ describe('GL Style Field Errors', () => { it('should select the correct input elements', () => { expect(testContext.$form).toBeDefined(); - expect(testContext.$form.length).toBe(1); + expect(testContext.$form).toHaveLength(1); expect(testContext.fieldErrors).toBeDefined(); const { inputs } = testContext.fieldErrors.state; - expect(inputs.length).toBe(7); + expect(inputs).toHaveLength(7); }); it('should ignore elements with custom error handling', () => { const customErrorFlag = 'gl-field-error-ignore'; const customErrorElem = $(`.${customErrorFlag}`); - expect(customErrorElem.length).toBe(1); + expect(customErrorElem).toHaveLength(1); const customErrors = testContext.fieldErrors.state.inputs.filter((input) => { return input.inputElement.hasClass(customErrorFlag); }); - expect(customErrors.length).toBe(0); + expect(customErrors).toHaveLength(0); }); it('should not show any errors before submit attempt', () => { @@ -51,7 +51,7 @@ describe('GL Style Field Errors', () => { const errorsShown = testContext.$form.find('.gl-field-error-outline'); - expect(errorsShown.length).toBe(0); + expect(errorsShown).toHaveLength(0); }); it('should show errors when input valid is submitted', () => { @@ -63,7 +63,7 @@ describe('GL Style Field Errors', () => { const errorsShown = testContext.$form.find('.gl-field-error-outline'); - expect(errorsShown.length).toBe(5); + expect(errorsShown).toHaveLength(5); }); it('should properly track validity state on input after invalid submission attempt', () => { diff --git a/spec/frontend/google_cloud/components/incubation_banner_spec.js b/spec/frontend/google_cloud/components/incubation_banner_spec.js index 92bc39bdff9..c6f0550a66c 100644 --- a/spec/frontend/google_cloud/components/incubation_banner_spec.js +++ b/spec/frontend/google_cloud/components/incubation_banner_spec.js @@ -27,7 +27,7 @@ describe('google_cloud/components/incubation_banner', () => { describe('has relevant gl-links', () => { it('three in total', () => { - expect(findLinks().length).toBe(3); + expect(findLinks()).toHaveLength(3); }); it('contains feature request link', () => { diff --git a/spec/frontend/google_cloud/service_accounts/list_spec.js b/spec/frontend/google_cloud/service_accounts/list_spec.js index ae5776081d7..c638808985a 100644 --- a/spec/frontend/google_cloud/service_accounts/list_spec.js +++ b/spec/frontend/google_cloud/service_accounts/list_spec.js @@ -80,7 +80,7 @@ describe('google_cloud/service_accounts/list', () => { }); it('table must have three rows + header row', () => { - expect(findRows().length).toBe(4); + expect(findRows()).toHaveLength(4); }); it('table row must contain link to the google cloud console', () => { diff --git a/spec/frontend/gpg_badges_spec.js b/spec/frontend/gpg_badges_spec.js index 2d961e6872e..fe0dc671e3f 100644 --- a/spec/frontend/gpg_badges_spec.js +++ b/spec/frontend/gpg_badges_spec.js @@ -108,7 +108,7 @@ describe('GpgBadges', () => { expect(document.querySelector('.js-loading-signature-badge:empty')).toBe(null); const spinners = document.querySelectorAll('.js-loading-signature-badge span.gl-spinner'); - expect(spinners.length).toBe(1); + expect(spinners).toHaveLength(1); }); it('replaces the loading spinner', async () => { diff --git a/spec/frontend/groups/components/group_item_spec.js b/spec/frontend/groups/components/group_item_spec.js index 02bac5104d2..3c4527c4e05 100644 --- a/spec/frontend/groups/components/group_item_spec.js +++ b/spec/frontend/groups/components/group_item_spec.js @@ -55,7 +55,7 @@ describe('GroupItemComponent', () => { const classes = ['is-open', 'has-children', 'has-description', 'being-removed']; const { rowClass } = wrapper.vm; - expect(Object.keys(rowClass).length).toBe(classes.length); + expect(Object.keys(rowClass)).toHaveLength(classes.length); Object.keys(rowClass).forEach((className) => { expect(classes.indexOf(className)).toBeGreaterThan(-1); }); diff --git a/spec/frontend/groups/store/groups_store_spec.js b/spec/frontend/groups/store/groups_store_spec.js index 8bd950456ea..6693e55baa9 100644 --- a/spec/frontend/groups/store/groups_store_spec.js +++ b/spec/frontend/groups/store/groups_store_spec.js @@ -15,9 +15,9 @@ describe('ProjectsStore', () => { store = new GroupsStore(); - expect(Object.keys(store.state).length).toBe(2); + expect(Object.keys(store.state)).toHaveLength(2); expect(Array.isArray(store.state.groups)).toBe(true); - expect(Object.keys(store.state.pageInfo).length).toBe(0); + expect(Object.keys(store.state.pageInfo)).toHaveLength(0); expect(store.hideProjects).toBe(false); store = new GroupsStore({ hideProjects: true }); @@ -33,7 +33,7 @@ describe('ProjectsStore', () => { store.setGroups(mockGroups); - expect(store.state.groups.length).toBe(mockGroups.length); + expect(store.state.groups).toHaveLength(mockGroups.length); expect(store.formatGroupItem).toHaveBeenCalledWith(expect.any(Object)); expect(Object.keys(store.state.groups[0]).indexOf('fullName')).toBeGreaterThan(-1); }); @@ -46,7 +46,7 @@ describe('ProjectsStore', () => { store.setSearchedGroups(mockSearchedGroups); - expect(store.state.groups.length).toBe(mockSearchedGroups.length); + expect(store.state.groups).toHaveLength(mockSearchedGroups.length); expect(store.formatGroupItem).toHaveBeenCalledWith(expect.any(Object)); expect(Object.keys(store.state.groups[0]).indexOf('fullName')).toBeGreaterThan(-1); expect(Object.keys(store.state.groups[0].children[0]).indexOf('fullName')).toBeGreaterThan( @@ -63,7 +63,7 @@ describe('ProjectsStore', () => { store.setGroupChildren(mockParentGroupItem, mockRawChildren); expect(store.formatGroupItem).toHaveBeenCalledWith(expect.any(Object)); - expect(mockParentGroupItem.children.length).toBe(1); + expect(mockParentGroupItem.children).toHaveLength(1); expect(Object.keys(mockParentGroupItem.children[0]).indexOf('fullName')).toBeGreaterThan(-1); expect(mockParentGroupItem.isOpen).toBe(true); expect(mockParentGroupItem.isChildrenLoading).toBe(false); @@ -152,7 +152,7 @@ describe('ProjectsStore', () => { store.removeGroup(childItem, store.state.groups[0]); - expect(store.state.groups[0].children.length).toBe(0); + expect(store.state.groups[0].children).toHaveLength(0); }); }); }); diff --git a/spec/frontend/highlight_js/plugins/index_spec.js b/spec/frontend/highlight_js/plugins/index_spec.js index 78c33406f31..c37f5ac270a 100644 --- a/spec/frontend/highlight_js/plugins/index_spec.js +++ b/spec/frontend/highlight_js/plugins/index_spec.js @@ -23,7 +23,7 @@ describe('index.js', () => { expect(withoutWrapLines).not.toContain('wrapLines'); expect(withWrapLines).toContain('wrapLines'); - expect(withWrapLines.length).toBe(withoutWrapLines.length + 1); + expect(withWrapLines).toHaveLength(withoutWrapLines.length + 1); }); }); diff --git a/spec/frontend/ide/components/reset_application_settings_modal_spec.js b/spec/frontend/ide/components/reset_application_settings_modal_spec.js index ca818e541f4..b9253695974 100644 --- a/spec/frontend/ide/components/reset_application_settings_modal_spec.js +++ b/spec/frontend/ide/components/reset_application_settings_modal_spec.js @@ -68,7 +68,7 @@ describe('ResetApplicationSettingsModal', () => { await waitForPromises(); await nextTick(); - expect(mockAxios.history.post.length).toBe(1); + expect(mockAxios.history.post).toHaveLength(1); expect(mockAxios.history.post[0].url).toBe(MOCK_RESET_APPLICATION_SETTINGS_PATH); }); diff --git a/spec/frontend/image_diff/image_diff_spec.js b/spec/frontend/image_diff/image_diff_spec.js index f8faa8d78c2..c024fd116b1 100644 --- a/spec/frontend/image_diff/image_diff_spec.js +++ b/spec/frontend/image_diff/image_diff_spec.js @@ -245,7 +245,7 @@ describe('ImageDiff', () => { it('should call renderBadge for each discussionEl', () => { const discussionEls = element.querySelectorAll('.note-container .discussion-notes .notes'); - expect(imageDiff.renderBadge.mock.calls.length).toEqual(discussionEls.length); + expect(imageDiff.renderBadge.mock.calls).toHaveLength(discussionEls.length); }); }); @@ -265,7 +265,7 @@ describe('ImageDiff', () => { }); it('should populate imageBadges', () => { - expect(imageDiff.imageBadges.length).toEqual(1); + expect(imageDiff.imageBadges).toHaveLength(1); }); describe('renderCommentBadge', () => { @@ -306,7 +306,7 @@ describe('ImageDiff', () => { }); it('should add imageBadge to imageBadges', () => { - expect(imageDiff.imageBadges.length).toEqual(1); + expect(imageDiff.imageBadges).toHaveLength(1); }); it('should call addImageBadge', () => { @@ -344,7 +344,7 @@ describe('ImageDiff', () => { expect(imageBadgeEls[0].textContent).toEqual('1'); expect(imageBadgeEls[1].textContent).toEqual('2'); - expect(imageBadgeEls.length).toEqual(2); + expect(imageBadgeEls).toHaveLength(2); }); it('should call updateDiscussionBadgeNumber', () => { @@ -357,7 +357,7 @@ describe('ImageDiff', () => { }); it('should remove badge from imageBadges', () => { - expect(imageDiff.imageBadges.length).toEqual(2); + expect(imageDiff.imageBadges).toHaveLength(2); }); it('should remove imageBadgeEl', () => { diff --git a/spec/frontend/image_diff/init_discussion_tab_spec.js b/spec/frontend/image_diff/init_discussion_tab_spec.js index 3b427f0d54d..4dcba6fd1cd 100644 --- a/spec/frontend/image_diff/init_discussion_tab_spec.js +++ b/spec/frontend/image_diff/init_discussion_tab_spec.js @@ -40,6 +40,6 @@ describe('initDiscussionTab', () => { jest.spyOn(initImageDiffHelper, 'initImageDiff').mockImplementation(() => {}); initDiscussionTab(); - expect(initImageDiffHelper.initImageDiff.mock.calls.length).toEqual(2); + expect(initImageDiffHelper.initImageDiff.mock.calls).toHaveLength(2); }); }); diff --git a/spec/frontend/image_diff/replaced_image_diff_spec.js b/spec/frontend/image_diff/replaced_image_diff_spec.js index cb062bbb3ec..33beab4b6b2 100644 --- a/spec/frontend/image_diff/replaced_image_diff_spec.js +++ b/spec/frontend/image_diff/replaced_image_diff_spec.js @@ -287,7 +287,7 @@ describe('ReplacedImageDiff', () => { }); it('should clear imageBadges', () => { - expect(replacedImageDiff.imageBadges.length).toEqual(0); + expect(replacedImageDiff.imageBadges).toHaveLength(0); }); it('should call renderNewView', () => { diff --git a/spec/frontend/import/details/components/import_details_table_spec.js b/spec/frontend/import/details/components/import_details_table_spec.js index 702d2f4e1e5..c71dd558bac 100644 --- a/spec/frontend/import/details/components/import_details_table_spec.js +++ b/spec/frontend/import/details/components/import_details_table_spec.js @@ -95,7 +95,7 @@ describe('Import details table', () => { it('sets items and pagination info', async () => { await waitForPromises(); - expect(findGlTableRows().length).toBe(mockImportFailures.length); + expect(findGlTableRows()).toHaveLength(mockImportFailures.length); expect(findPaginationBar().props('pageInfo')).toMatchObject({ page: mockHeaders['x-page'], perPage: mockHeaders['x-per-page'], @@ -159,7 +159,7 @@ describe('Import details table', () => { it('sets items and pagination info', async () => { await waitForPromises(); - expect(findGlTableRows().length).toBe(mockImportFailures.length); + expect(findGlTableRows()).toHaveLength(mockImportFailures.length); expect(findPaginationBar().props('pageInfo')).toMatchObject({ page: mockHeaders['x-page'], perPage: mockHeaders['x-per-page'], diff --git a/spec/frontend/import_entities/import_projects/store/mutations_spec.js b/spec/frontend/import_entities/import_projects/store/mutations_spec.js index 90053f79bdf..5501214d47c 100644 --- a/spec/frontend/import_entities/import_projects/store/mutations_spec.js +++ b/spec/frontend/import_entities/import_projects/store/mutations_spec.js @@ -38,7 +38,7 @@ describe('import_projects store mutations', () => { }); it('removes current repositories list', () => { - expect(state.repositories.length).toBe(0); + expect(state.repositories).toHaveLength(0); }); it('resets pagintation', () => { diff --git a/spec/frontend/incidents/components/incidents_list_spec.js b/spec/frontend/incidents/components/incidents_list_spec.js index 7c8e0b720f8..e07c1ce1d00 100644 --- a/spec/frontend/incidents/components/incidents_list_spec.js +++ b/spec/frontend/incidents/components/incidents_list_spec.js @@ -153,11 +153,11 @@ describe('Incidents List', () => { }); it('renders rows based on provided data', () => { - expect(findTableRows().length).toBe(mockIncidents.length); + expect(findTableRows()).toHaveLength(mockIncidents.length); }); it('renders a createdAt with timeAgo component per row', () => { - expect(findTimeAgo().length).toBe(mockIncidents.length); + expect(findTimeAgo()).toHaveLength(mockIncidents.length); }); it('renders a link to the incident as the incident title', () => { @@ -185,14 +185,14 @@ describe('Incidents List', () => { }); it('renders a closed icon for closed incidents', () => { - expect(findClosedIcon().length).toBe( + expect(findClosedIcon()).toHaveLength( mockIncidents.filter(({ state }) => state === 'closed').length, ); }); }); it('renders severity per row', () => { - expect(findSeverity().length).toBe(mockIncidents.length); + expect(findSeverity()).toHaveLength(mockIncidents.length); }); describe('Escalation status', () => { @@ -200,7 +200,7 @@ describe('Incidents List', () => { const statuses = findEscalationStatus().wrappers; const expectedStatuses = ['Triggered', 'Acknowledged', 'Resolved', I18N.noEscalationStatus]; - expect(statuses.length).toBe(mockIncidents.length); + expect(statuses).toHaveLength(mockIncidents.length); statuses.forEach((status, index) => { expect(status.text()).toEqual(expectedStatuses[index]); expect(status.classes('gl-truncate')).toBe(true); diff --git a/spec/frontend/integrations/beyond_identity/components/add_exclusions_drawer_spec.js b/spec/frontend/integrations/beyond_identity/components/add_exclusions_drawer_spec.js index 6618536a2de..5757833b715 100644 --- a/spec/frontend/integrations/beyond_identity/components/add_exclusions_drawer_spec.js +++ b/spec/frontend/integrations/beyond_identity/components/add_exclusions_drawer_spec.js @@ -100,6 +100,6 @@ describe('AddExclusionsDrawer component', () => { await nextTick(); expect(wrapper.emitted('add')).toEqual([[mockData]]); - expect(findSelector().props('selectedItems').length).toBe(0); + expect(findSelector().props('selectedItems')).toHaveLength(0); }); }); diff --git a/spec/frontend/integrations/edit/components/sections/trigger_spec.js b/spec/frontend/integrations/edit/components/sections/trigger_spec.js index b9c1efbb0a2..ca2e73bfd65 100644 --- a/spec/frontend/integrations/edit/components/sections/trigger_spec.js +++ b/spec/frontend/integrations/edit/components/sections/trigger_spec.js @@ -25,7 +25,7 @@ describe('IntegrationSectionTrigger', () => { createComponent(); const fields = findAllTriggerFields(); - expect(fields.length).toBe(mockIntegrationProps.triggerEvents.length); + expect(fields).toHaveLength(mockIntegrationProps.triggerEvents.length); fields.wrappers.forEach((field, index) => { expect(field.props('event')).toBe(mockIntegrationProps.triggerEvents[index]); }); diff --git a/spec/frontend/issuable/components/issue_assignees_spec.js b/spec/frontend/issuable/components/issue_assignees_spec.js index fe7f73b4418..5adb33dc25c 100644 --- a/spec/frontend/issuable/components/issue_assignees_spec.js +++ b/spec/frontend/issuable/components/issue_assignees_spec.js @@ -50,11 +50,11 @@ describe('IssueAssigneesComponent', () => { if (expectedShown) { it('shows assignee avatars', () => { - expect(findAvatars().length).toEqual(expectedShown); + expect(findAvatars()).toHaveLength(expectedShown); }); } else { it('does not show assignee avatars', () => { - expect(findAvatars().length).toEqual(0); + expect(findAvatars()).toHaveLength(0); }); } diff --git a/spec/frontend/issuable/components/merge_request_reviewers_spec.js b/spec/frontend/issuable/components/merge_request_reviewers_spec.js index dd6db6aa8a7..ffbfe6895c1 100644 --- a/spec/frontend/issuable/components/merge_request_reviewers_spec.js +++ b/spec/frontend/issuable/components/merge_request_reviewers_spec.js @@ -61,11 +61,11 @@ describe('MergeRequestReviewersComponent', () => { if (expectedShown) { it('shows reviewer avatars', () => { - expect(findAvatars().length).toEqual(expectedShown); + expect(findAvatars()).toHaveLength(expectedShown); }); } else { it('does not show reviewer avatars', () => { - expect(findAvatars().length).toEqual(0); + expect(findAvatars()).toHaveLength(0); }); } diff --git a/spec/frontend/issues/new/components/title_suggestions_spec.js b/spec/frontend/issues/new/components/title_suggestions_spec.js index d5323347b34..4c7a3c3f96b 100644 --- a/spec/frontend/issues/new/components/title_suggestions_spec.js +++ b/spec/frontend/issues/new/components/title_suggestions_spec.js @@ -91,11 +91,11 @@ describe('Issue title suggestions component', () => { }); it('renders component', () => { - expect(wrapper.findAll('li').length).toBe(MOCK_ISSUES_COUNT); + expect(wrapper.findAll('li')).toHaveLength(MOCK_ISSUES_COUNT); }); it('renders list of issues', () => { - expect(wrapper.findAllComponents(TitleSuggestionsItem).length).toBe(MOCK_ISSUES_COUNT); + expect(wrapper.findAllComponents(TitleSuggestionsItem)).toHaveLength(MOCK_ISSUES_COUNT); }); it('adds margin class to first item', () => { diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js index 2500c808073..4206dab6537 100644 --- a/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js +++ b/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js @@ -79,7 +79,7 @@ describe('IncidentTimelineEventList', () => { mountComponent({ propsData: { eventTags } }); expect(findEventTags().exists()).toBe(Boolean(expected)); - expect(findEventTags().length).toBe(eventTags.length); + expect(findEventTags()).toHaveLength(eventTags.length); }); }); diff --git a/spec/frontend/issues/show/components/incidents/utils_spec.js b/spec/frontend/issues/show/components/incidents/utils_spec.js index 8ee0d906dd4..705f86a5db4 100644 --- a/spec/frontend/issues/show/components/incidents/utils_spec.js +++ b/spec/frontend/issues/show/components/incidents/utils_spec.js @@ -59,12 +59,12 @@ describe('incident utils', () => { const nodes = []; const previousTags = getPreviousEventTags(nodes); - expect(previousTags.length).toBe(0); + expect(previousTags).toHaveLength(0); }); it('should return an array of strings, when passed object containing tags', () => { const previousTags = getPreviousEventTags(mockTimelineEventTags.nodes); - expect(previousTags.length).toBe(2); + expect(previousTags).toHaveLength(2); expect(previousTags).toContain(mockTimelineEventTags.nodes[0].name); expect(previousTags).toContain(mockTimelineEventTags.nodes[1].name); }); diff --git a/spec/frontend/lib/utils/axios_startup_calls_spec.js b/spec/frontend/lib/utils/axios_startup_calls_spec.js index f54391f5660..cdd32a15357 100644 --- a/spec/frontend/lib/utils/axios_startup_calls_spec.js +++ b/spec/frontend/lib/utils/axios_startup_calls_spec.js @@ -51,7 +51,7 @@ describe('setupAxiosStartupCalls', () => { it('if no startupCalls are registered: does not register a request interceptor', () => { setupAxiosStartupCalls(axios); - expect(axios.interceptors.request.handlers.length).toBe(0); + expect(axios.interceptors.request.handlers).toHaveLength(0); }); describe('if startupCalls are registered', () => { @@ -68,7 +68,7 @@ describe('setupAxiosStartupCalls', () => { }); it('registers a request interceptor', () => { - expect(axios.interceptors.request.handlers.length).toBe(1); + expect(axios.interceptors.request.handlers).toHaveLength(1); }); it('detaches the request interceptor if every startup call has been made', async () => { diff --git a/spec/frontend/lib/utils/csrf_token_spec.js b/spec/frontend/lib/utils/csrf_token_spec.js index 55dd29571c0..1ddb432e8b7 100644 --- a/spec/frontend/lib/utils/csrf_token_spec.js +++ b/spec/frontend/lib/utils/csrf_token_spec.js @@ -51,7 +51,7 @@ describe('csrf', () => { it('returns empty object for headers', () => { expect(typeof csrf.headers).toBe('object'); - expect(Object.keys(csrf.headers).length).toBe(0); + expect(Object.keys(csrf.headers)).toHaveLength(0); }); }); }); diff --git a/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js b/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js index 6d0f0576b1f..eb7d07cce82 100644 --- a/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js +++ b/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js @@ -273,7 +273,7 @@ describe('getSundays', () => { const dateOfSundays = [3, 10, 17, 24, 31]; const sundays = getSundays(new Date(2017, 11, 1)); - expect(sundays.length).toBe(5); + expect(sundays).toHaveLength(5); sundays.forEach((sunday, index) => { expect(sunday.getDate()).toBe(dateOfSundays[index]); }); @@ -292,7 +292,7 @@ describe('getTimeframeWindowFrom', () => { ]; const timeframe = getTimeframeWindowFrom(startDate, 5); - expect(timeframe.length).toBe(5); + expect(timeframe).toHaveLength(5); timeframe.forEach((timeframeItem, index) => { expect(timeframeItem.getFullYear()).toBe(mockTimeframe[index].getFullYear()); expect(timeframeItem.getMonth()).toBe(mockTimeframe[index].getMonth()); @@ -311,7 +311,7 @@ describe('getTimeframeWindowFrom', () => { ]; const timeframe = getTimeframeWindowFrom(startDate, -5); - expect(timeframe.length).toBe(5); + expect(timeframe).toHaveLength(5); timeframe.forEach((timeframeItem, index) => { expect(timeframeItem.getFullYear()).toBe(mockTimeframe[index].getFullYear()); expect(timeframeItem.getMonth()).toBe(mockTimeframe[index].getMonth()); @@ -423,7 +423,7 @@ describe('getDatesInRange', () => { const range = getDatesInRange(d1, d2); - expect(range.length).toEqual(31); + expect(range).toHaveLength(31); }); it('applies mapper function if provided fro each item in range', () => { diff --git a/spec/frontend/lib/utils/uuids_spec.js b/spec/frontend/lib/utils/uuids_spec.js index a7770d37566..e6c9256bf79 100644 --- a/spec/frontend/lib/utils/uuids_spec.js +++ b/spec/frontend/lib/utils/uuids_spec.js @@ -31,7 +31,7 @@ describe('UUIDs Util', () => { it('outputs an array of UUIDs', () => { const ids = uuids({ count: 11 }); - expect(ids.length).toEqual(11); + expect(ids).toHaveLength(11); expect(ids.every((id) => UUIDV4.test(id))).toEqual(true); }); diff --git a/spec/frontend/merge_requests/components/compare_dropdown_spec.js b/spec/frontend/merge_requests/components/compare_dropdown_spec.js index bd8b16c8089..77008d24a56 100644 --- a/spec/frontend/merge_requests/components/compare_dropdown_spec.js +++ b/spec/frontend/merge_requests/components/compare_dropdown_spec.js @@ -63,7 +63,7 @@ describe('Merge requests compare dropdown component', () => { await waitForPromises(); const items = wrapper.findAll('[role="option"]'); - expect(items.length).toBe(2); + expect(items).toHaveLength(2); expect(items.at(0).text()).toBe('root/gitlab-test'); expect(items.at(1).text()).toBe('gitlab-org/gitlab-test'); }); @@ -98,6 +98,6 @@ describe('Merge requests compare dropdown component', () => { await waitForPromises(); - expect(wrapper.findAll('[role="option"]').length).toBe(1); + expect(wrapper.findAll('[role="option"]')).toHaveLength(1); }); }); diff --git a/spec/frontend/merge_requests/list/components/merge_requests_list_app_spec.js b/spec/frontend/merge_requests/list/components/merge_requests_list_app_spec.js index 58b1661306d..a49f8ac98eb 100644 --- a/spec/frontend/merge_requests/list/components/merge_requests_list_app_spec.js +++ b/spec/frontend/merge_requests/list/components/merge_requests_list_app_spec.js @@ -270,19 +270,20 @@ describe('Merge requests list app', () => { it('only requests fresh data if the cache has become stale', async () => { // Prime the target cache await wrapper.vm.fetchBranches('target'); - expect(axiosMock.history.get.length).toBe(1); + + expect(axiosMock.history.get).toHaveLength(1); jest.advanceTimersByTime(1000); // Only load from the cache since it has not expired yet await wrapper.vm.fetchBranches('target'); - expect(axiosMock.history.get.length).toBe(1); + expect(axiosMock.history.get).toHaveLength(1); jest.advanceTimersByTime(BRANCH_LIST_REFRESH_INTERVAL); // Refresh the cache since the expiration date has passed await wrapper.vm.fetchBranches('target'); - expect(axiosMock.history.get.length).toBe(2); + expect(axiosMock.history.get).toHaveLength(2); }); }); diff --git a/spec/frontend/merge_requests/utils/autocomplete_cache_spec.js b/spec/frontend/merge_requests/utils/autocomplete_cache_spec.js index 1eae23c4cc9..66931ac59b7 100644 --- a/spec/frontend/merge_requests/utils/autocomplete_cache_spec.js +++ b/spec/frontend/merge_requests/utils/autocomplete_cache_spec.js @@ -112,11 +112,11 @@ describe('AutocompleteCache', () => { it('overwrites the cache with the new data from the endpoint', async () => { // Initially confirm the cache was hydrated - expect(autocompleteCache.cache.get(url).length).toBe(data.length); + expect(autocompleteCache.cache.get(url)).toHaveLength(data.length); await autocompleteCache.updateLocalCache(url); - expect(autocompleteCache.cache.get(url).length).toBe(updatedData.length); + expect(autocompleteCache.cache.get(url)).toHaveLength(updatedData.length); }); }); diff --git a/spec/frontend/ml/experiment_tracking/components/performance_graph_spec.js b/spec/frontend/ml/experiment_tracking/components/performance_graph_spec.js index ad4c45ed9cd..0ec2c8f0426 100644 --- a/spec/frontend/ml/experiment_tracking/components/performance_graph_spec.js +++ b/spec/frontend/ml/experiment_tracking/components/performance_graph_spec.js @@ -33,13 +33,13 @@ describe('PerformanceGraph', () => { it('renders the correct data', () => { createWrapper(); - expect(findLineChart().props('data').length).toBe(MOCK_METRICS.length); + expect(findLineChart().props('data')).toHaveLength(MOCK_METRICS.length); expect(findLineChart().props('data')[0].name).toBe('auc'); expect(findLineChart().props('data')[1].name).toBe('l1_ratio'); expect(findLineChart().props('data')[2].name).toBe('rmse'); - expect(findLineChart().props('data')[0].data.length).toBe(4); - expect(findLineChart().props('data')[1].data.length).toBe(5); - expect(findLineChart().props('data')[2].data.length).toBe(1); + expect(findLineChart().props('data')[0].data).toHaveLength(4); + expect(findLineChart().props('data')[1].data).toHaveLength(5); + expect(findLineChart().props('data')[2].data).toHaveLength(1); }); it('sorts the data by created_at in ascending order', () => { diff --git a/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js index c44fdc5ba38..2a03a4cfa87 100644 --- a/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js +++ b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js @@ -181,7 +181,7 @@ describe('MlExperimentsShow', () => { }); it('renders the correct tabs', () => { - expect(findTabs().findAllComponents(GlTab).length).toBe(3); + expect(findTabs().findAllComponents(GlTab)).toHaveLength(3); }); it('renders metadata tab', () => { diff --git a/spec/frontend/ml/model_registry/components/candidates_table_spec.js b/spec/frontend/ml/model_registry/components/candidates_table_spec.js index b1684bdd605..1edf66db9c9 100644 --- a/spec/frontend/ml/model_registry/components/candidates_table_spec.js +++ b/spec/frontend/ml/model_registry/components/candidates_table_spec.js @@ -43,7 +43,7 @@ describe('CandidatesTable', () => { }); it('renders the correct number of rows', () => { - expect(findTableRows().length).toBe(2); + expect(findTableRows()).toHaveLength(2); }); it('renders the correct information in the id column', () => { diff --git a/spec/frontend/ml/model_registry/components/delete_model_disclosure_dropdown_item_spec.js b/spec/frontend/ml/model_registry/components/delete_model_disclosure_dropdown_item_spec.js index d74806c1126..6c41eef4b10 100644 --- a/spec/frontend/ml/model_registry/components/delete_model_disclosure_dropdown_item_spec.js +++ b/spec/frontend/ml/model_registry/components/delete_model_disclosure_dropdown_item_spec.js @@ -53,7 +53,7 @@ describe('DeleteButton', () => { it('submits the form when primary action is clicked', () => { findModal().vm.$emit('primary'); - expect(wrapper.emitted('confirm-deletion').length).toEqual(1); + expect(wrapper.emitted('confirm-deletion')).toHaveLength(1); }); }); }); diff --git a/spec/frontend/ml/model_registry/components/delete_model_version_disclosure_dropdown_item_spec.js b/spec/frontend/ml/model_registry/components/delete_model_version_disclosure_dropdown_item_spec.js index 24c00186275..50c02a00048 100644 --- a/spec/frontend/ml/model_registry/components/delete_model_version_disclosure_dropdown_item_spec.js +++ b/spec/frontend/ml/model_registry/components/delete_model_version_disclosure_dropdown_item_spec.js @@ -72,7 +72,7 @@ describe('DeleteModelVersionDisclosureDropdownItem', () => { it('emits delete-model-version event when primary action is clicked', () => { findModal().vm.$emit('primary'); - expect(wrapper.emitted('delete-model-version').length).toEqual(1); + expect(wrapper.emitted('delete-model-version')).toHaveLength(1); }); }); }); diff --git a/spec/frontend/ml/model_registry/components/models_table_spec.js b/spec/frontend/ml/model_registry/components/models_table_spec.js index 56820e6fb95..446d5405ad0 100644 --- a/spec/frontend/ml/model_registry/components/models_table_spec.js +++ b/spec/frontend/ml/model_registry/components/models_table_spec.js @@ -61,7 +61,7 @@ describe('ModelsTable', () => { }); it('renders the correct number of rows', () => { - expect(findTableRows().length).toBe(1); + expect(findTableRows()).toHaveLength(1); }); it('renders the model name link correctly', () => { diff --git a/spec/frontend/notebook/cells/markdown_spec.js b/spec/frontend/notebook/cells/markdown_spec.js index f7211b2343b..bfac530d99f 100644 --- a/spec/frontend/notebook/cells/markdown_spec.js +++ b/spec/frontend/notebook/cells/markdown_spec.js @@ -135,10 +135,10 @@ describe('Markdown component', () => { await nextTick(); const images = wrapper.vm.$el.querySelectorAll('img'); - expect(images.length).toBe(5); + expect(images).toHaveLength(5); const columns = wrapper.vm.$el.querySelectorAll('td'); - expect(columns.length).toBe(6); + expect(columns).toHaveLength(6); expect(columns[0].textContent).toEqual('Hello '); expect(columns[1].textContent).toEqual('Test '); diff --git a/spec/frontend/notebook/index_spec.js b/spec/frontend/notebook/index_spec.js index 8811a8517a1..0e34fe2a69e 100644 --- a/spec/frontend/notebook/index_spec.js +++ b/spec/frontend/notebook/index_spec.js @@ -35,7 +35,7 @@ describe('Notebook component', () => { }); it('renders cells', () => { - expect(vm.$el.querySelectorAll('.cell').length).toBe(json.cells.length); + expect(vm.$el.querySelectorAll('.cell')).toHaveLength(json.cells.length); }); it('renders markdown cell', () => { @@ -57,7 +57,7 @@ describe('Notebook component', () => { }); it('renders cells', () => { - expect(vm.$el.querySelectorAll('.cell').length).toBe(jsonWithRawCell.cells.length); + expect(vm.$el.querySelectorAll('.cell')).toHaveLength(jsonWithRawCell.cells.length); }); }); @@ -69,7 +69,7 @@ describe('Notebook component', () => { }); it('renders cells', () => { - expect(vm.$el.querySelectorAll('.cell').length).toBe( + expect(vm.$el.querySelectorAll('.cell')).toHaveLength( jsonWithWorksheet.worksheets[0].cells.length, ); }); diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js index 9f45b0c9ffc..1b92e0bd1b7 100644 --- a/spec/frontend/notes/components/comment_form_spec.js +++ b/spec/frontend/notes/components/comment_form_spec.js @@ -163,7 +163,7 @@ describe('issue_comment_form component', () => { // not necessarily that there aren't any at all. // We want to check here that there are none found, so we use the // raw wrapper array length instead. - expect(findErrorAlerts().length).toBe(0); + expect(findErrorAlerts()).toHaveLength(0); }); it.each` @@ -188,7 +188,7 @@ describe('issue_comment_form component', () => { await findCommentButton().trigger('click'); await waitForPromises(); const errorAlerts = findErrorAlerts(); - expect(errorAlerts.length).toBe(errors.length); + expect(errorAlerts).toHaveLength(errors.length); errors.forEach((msg, index) => { const alert = errorAlerts[index]; @@ -217,7 +217,7 @@ describe('issue_comment_form component', () => { it('renders an error message', () => { const errorAlerts = findErrorAlerts(); - expect(errorAlerts.length).toBe(1); + expect(errorAlerts).toHaveLength(1); expect(errorAlerts[0].text()).toBe( sprintf(COMMENT_FORM.error, { reason: 'error 1 and error 2' }), @@ -242,7 +242,7 @@ describe('issue_comment_form component', () => { let errorAlerts = findErrorAlerts(); - expect(errorAlerts.length).toBe(commandErrors.length); + expect(errorAlerts).toHaveLength(commandErrors.length); // dismiss the second error extendedWrapper(errorAlerts[1]).findByTestId('close-icon').trigger('click'); @@ -251,7 +251,7 @@ describe('issue_comment_form component', () => { // Refresh the list of alerts errorAlerts = findErrorAlerts(); - expect(errorAlerts.length).toBe(commandErrors.length - 1); + expect(errorAlerts).toHaveLength(commandErrors.length - 1); // We want to know that the *correct* error was dismissed, not just that any one is gone expect(errorAlerts[0].text()).toBe(commandErrors[0]); expect(errorAlerts[1].text()).toBe(commandErrors[2]); diff --git a/spec/frontend/notes/components/comment_type_dropdown_spec.js b/spec/frontend/notes/components/comment_type_dropdown_spec.js index e1cb1c9a8bc..3e841f8bfa8 100644 --- a/spec/frontend/notes/components/comment_type_dropdown_spec.js +++ b/spec/frontend/notes/components/comment_type_dropdown_spec.js @@ -87,7 +87,7 @@ describe('CommentTypeDropdown component', () => { findDiscussionListboxOption().trigger('click'); expect(wrapper.emitted('change')[0]).toEqual([constants.COMMENT]); - expect(wrapper.emitted('change').length).toEqual(1); + expect(wrapper.emitted('change')).toHaveLength(1); }); it('Should emit `click` event when clicking on the action button', () => { diff --git a/spec/frontend/notes/components/diff_with_note_spec.js b/spec/frontend/notes/components/diff_with_note_spec.js index 0b898765f6f..7c8773b5a9d 100644 --- a/spec/frontend/notes/components/diff_with_note_spec.js +++ b/spec/frontend/notes/components/diff_with_note_spec.js @@ -72,7 +72,7 @@ describe('diff_with_note', () => { }); it('shows diff lines', () => { - expect(selectors.diffRows.length).toBe(12); + expect(selectors.diffRows).toHaveLength(12); }); it('shows notes row', () => { diff --git a/spec/frontend/notes/components/discussion_filter_spec.js b/spec/frontend/notes/components/discussion_filter_spec.js index f6dfba638b0..4f1102951a9 100644 --- a/spec/frontend/notes/components/discussion_filter_spec.js +++ b/spec/frontend/notes/components/discussion_filter_spec.js @@ -145,7 +145,7 @@ describe('DiscussionFilter component', () => { }); it('renders the all filters', () => { - expect(wrapper.findAll('.discussion-filter-container .gl-new-dropdown-item').length).toBe( + expect(wrapper.findAll('.discussion-filter-container .gl-new-dropdown-item')).toHaveLength( discussionFiltersMock.length, ); }); diff --git a/spec/frontend/notes/components/discussion_notes_spec.js b/spec/frontend/notes/components/discussion_notes_spec.js index 29203bfd0eb..d9a5961d169 100644 --- a/spec/frontend/notes/components/discussion_notes_spec.js +++ b/spec/frontend/notes/components/discussion_notes_spec.js @@ -66,12 +66,12 @@ describe('DiscussionNotes', () => { it('renders an element for each note in the discussion', () => { createComponent(); const notesCount = discussionMock.notes.length; - expect(findNoteableNotes().length).toBe(notesCount); + expect(findNoteableNotes()).toHaveLength(notesCount); }); it('renders one element if replies groupping is enabled', () => { createComponent({ shouldGroupReplies: true }); - expect(findNoteableNotes().length).toBe(1); + expect(findNoteableNotes()).toHaveLength(1); }); it.each([ diff --git a/spec/frontend/notes/deprecated_notes_spec.js b/spec/frontend/notes/deprecated_notes_spec.js index 667449ebafd..c33a2060566 100644 --- a/spec/frontend/notes/deprecated_notes_spec.js +++ b/spec/frontend/notes/deprecated_notes_spec.js @@ -598,7 +598,7 @@ describe.skip('Old Notes (~/deprecated_notes.js)', () => { await waitForPromises(); - expect($notesContainer.find('.note.being-posted').length).toEqual(0); + expect($notesContainer.find('.note.being-posted')).toHaveLength(0); }); describe('postComment', () => { @@ -694,11 +694,11 @@ describe.skip('Old Notes (~/deprecated_notes.js)', () => { jest.spyOn(gl.awardsHandler, 'addAwardToEmojiBar'); $('.js-comment-button').click(); - expect($notesContainer.find('.note.being-posted').length).toEqual(1); // Placeholder shown + expect($notesContainer.find('.note.being-posted')).toHaveLength(1); // Placeholder shown await waitForPromises(); - expect($notesContainer.find('.note.being-posted').length).toEqual(0); // Placeholder removed + expect($notesContainer.find('.note.being-posted')).toHaveLength(0); // Placeholder removed }); }); @@ -727,12 +727,12 @@ describe.skip('Old Notes (~/deprecated_notes.js)', () => { it('should show message placeholder including lines starting with slash', async () => { $('.js-comment-button').click(); - expect($notesContainer.find('.note.being-posted').length).toEqual(1); // Placeholder shown + expect($notesContainer.find('.note.being-posted')).toHaveLength(1); // Placeholder shown expect($notesContainer.find('.note-body p').text()).toEqual(sampleComment); // No quick action processing await waitForPromises(); - expect($notesContainer.find('.note.being-posted').length).toEqual(0); // Placeholder removed + expect($notesContainer.find('.note.being-posted')).toHaveLength(0); // Placeholder removed }); }); diff --git a/spec/frontend/notes/store/legacy_notes/getters_spec.js b/spec/frontend/notes/store/legacy_notes/getters_spec.js index 741eb905ca1..cb96e596977 100644 --- a/spec/frontend/notes/store/legacy_notes/getters_spec.js +++ b/spec/frontend/notes/store/legacy_notes/getters_spec.js @@ -138,7 +138,7 @@ describe('Getters Notes Store', () => { const discussions = getDiscussions(); - expect(discussions.length).toEqual(discussionMock.notes.length); + expect(discussions).toHaveLength(discussionMock.notes.length); discussions.forEach((discussion) => { expect(discussion.individual_note).toBe(true); expect(discussion.id).toBe(discussion.notes[0].id); @@ -205,7 +205,7 @@ describe('Getters Notes Store', () => { it('should return a single system note when a description was updated multiple times', () => { store.$patch(stateCollapsedNotes); - expect(store.filteredDiscussions.length).toEqual(1); + expect(store.filteredDiscussions).toHaveLength(1); }); }); diff --git a/spec/frontend/notes/store/legacy_notes/mutation_spec.js b/spec/frontend/notes/store/legacy_notes/mutation_spec.js index 943b62dff88..7ab31be7ea2 100644 --- a/spec/frontend/notes/store/legacy_notes/mutation_spec.js +++ b/spec/frontend/notes/store/legacy_notes/mutation_spec.js @@ -42,14 +42,14 @@ describe('Notes Store mutations', () => { it('should add a new note to an array of notes', () => { store[types.ADD_NEW_NOTE](note); expect(store.discussions).toStrictEqual([noteData]); - expect(store.discussions.length).toBe(1); + expect(store.discussions).toHaveLength(1); }); it('should not add the same note to the notes array', () => { store[types.ADD_NEW_NOTE](note); store[types.ADD_NEW_NOTE](note); - expect(store.discussions.length).toBe(1); + expect(store.discussions).toHaveLength(1); }); it('trims first character from truncated_diff_lines', () => { @@ -74,14 +74,14 @@ describe('Notes Store mutations', () => { it('should add a reply to a specific discussion', () => { store[types.ADD_NEW_REPLY_TO_DISCUSSION](newReply); - expect(store.discussions[0].notes.length).toEqual(4); + expect(store.discussions[0].notes).toHaveLength(4); }); it('should not add the note if it already exists in the discussion', () => { store[types.ADD_NEW_REPLY_TO_DISCUSSION](newReply); store[types.ADD_NEW_REPLY_TO_DISCUSSION](newReply); - expect(store.discussions[0].notes.length).toEqual(4); + expect(store.discussions[0].notes).toHaveLength(4); }); }); @@ -93,7 +93,7 @@ describe('Notes Store mutations', () => { store[types.DELETE_NOTE](toDelete); - expect(store.discussions[0].notes.length).toEqual(lengthBefore - 1); + expect(store.discussions[0].notes).toHaveLength(lengthBefore - 1); }); }); @@ -151,7 +151,7 @@ describe('Notes Store mutations', () => { store[types.REMOVE_PLACEHOLDER_NOTES](); - expect(store.discussions[0].notes.length).toEqual(lengthBefore); + expect(store.discussions[0].notes).toHaveLength(lengthBefore); }); }); @@ -228,7 +228,7 @@ describe('Notes Store mutations', () => { expect(store.discussions[0].id).toEqual(note.id); expect(store.discussions[1].notes[0].note).toBe(legacyNote.notes[0].note); expect(store.discussions[2].notes[0].note).toBe(legacyNote.notes[1].note); - expect(store.discussions.length).toEqual(3); + expect(store.discussions).toHaveLength(3); }); it('adds truncated_diff_lines if discussion is a diffFile', () => { @@ -339,7 +339,7 @@ describe('Notes Store mutations', () => { }; store[types.TOGGLE_AWARD](data); - expect(store.discussions[0].award_emoji.length).toEqual(2); + expect(store.discussions[0].award_emoji).toHaveLength(2); }); }); @@ -854,7 +854,7 @@ describe('Notes Store mutations', () => { it('removes info for all suggestions from a batch', () => { store[types.CLEAR_SUGGESTION_BATCH](); - expect(store.batchSuggestionsInfo.length).toEqual(0); + expect(store.batchSuggestionsInfo).toHaveLength(0); }); }); diff --git a/spec/frontend/notes/stores/getters_spec.js b/spec/frontend/notes/stores/getters_spec.js index d04d646cb43..cdc4adb0e67 100644 --- a/spec/frontend/notes/stores/getters_spec.js +++ b/spec/frontend/notes/stores/getters_spec.js @@ -120,7 +120,7 @@ describe('Getters Notes Store', () => { const discussions = getDiscussions(); - expect(discussions.length).toEqual(discussionMock.notes.length); + expect(discussions).toHaveLength(discussionMock.notes.length); discussions.forEach((discussion) => { expect(discussion.individual_note).toBe(true); expect(discussion.id).toBe(discussion.notes[0].id); @@ -185,7 +185,7 @@ describe('Getters Notes Store', () => { }; it('should return a single system note when a description was updated multiple times', () => { - expect(getters.discussions(stateCollapsedNotes, {}, {}).length).toEqual(1); + expect(getters.discussions(stateCollapsedNotes, {}, {})).toHaveLength(1); }); }); diff --git a/spec/frontend/notes/stores/mutation_spec.js b/spec/frontend/notes/stores/mutation_spec.js index b3f2804a4a0..4a36d30322d 100644 --- a/spec/frontend/notes/stores/mutation_spec.js +++ b/spec/frontend/notes/stores/mutation_spec.js @@ -39,14 +39,14 @@ describe('Notes Store mutations', () => { mutations.ADD_NEW_NOTE(state, note); expect(state).toEqual(expect.objectContaining({ discussions: [noteData] })); - expect(state.discussions.length).toBe(1); + expect(state.discussions).toHaveLength(1); }); it('should not add the same note to the notes array', () => { mutations.ADD_NEW_NOTE(state, note); mutations.ADD_NEW_NOTE(state, note); - expect(state.discussions.length).toBe(1); + expect(state.discussions).toHaveLength(1); }); it('trims first character from truncated_diff_lines', () => { @@ -73,14 +73,14 @@ describe('Notes Store mutations', () => { it('should add a reply to a specific discussion', () => { mutations.ADD_NEW_REPLY_TO_DISCUSSION(state, newReply); - expect(state.discussions[0].notes.length).toEqual(4); + expect(state.discussions[0].notes).toHaveLength(4); }); it('should not add the note if it already exists in the discussion', () => { mutations.ADD_NEW_REPLY_TO_DISCUSSION(state, newReply); mutations.ADD_NEW_REPLY_TO_DISCUSSION(state, newReply); - expect(state.discussions[0].notes.length).toEqual(4); + expect(state.discussions[0].notes).toHaveLength(4); }); }); @@ -92,7 +92,7 @@ describe('Notes Store mutations', () => { mutations.DELETE_NOTE(state, toDelete); - expect(state.discussions[0].notes.length).toEqual(lengthBefore - 1); + expect(state.discussions[0].notes).toHaveLength(lengthBefore - 1); }); }); @@ -150,7 +150,7 @@ describe('Notes Store mutations', () => { mutations.REMOVE_PLACEHOLDER_NOTES(state); - expect(state.discussions[0].notes.length).toEqual(lengthBefore); + expect(state.discussions[0].notes).toHaveLength(lengthBefore); }); }); @@ -227,7 +227,7 @@ describe('Notes Store mutations', () => { expect(state.discussions[0].id).toEqual(note.id); expect(state.discussions[1].notes[0].note).toBe(legacyNote.notes[0].note); expect(state.discussions[2].notes[0].note).toBe(legacyNote.notes[1].note); - expect(state.discussions.length).toEqual(3); + expect(state.discussions).toHaveLength(3); }); it('adds truncated_diff_lines if discussion is a diffFile', () => { @@ -338,7 +338,7 @@ describe('Notes Store mutations', () => { }; mutations.TOGGLE_AWARD(state, data); - expect(state.discussions[0].award_emoji.length).toEqual(2); + expect(state.discussions[0].award_emoji).toHaveLength(2); }); }); @@ -882,7 +882,7 @@ describe('Notes Store mutations', () => { it('removes info for all suggestions from a batch', () => { mutations.CLEAR_SUGGESTION_BATCH(state); - expect(state.batchSuggestionsInfo.length).toEqual(0); + expect(state.batchSuggestionsInfo).toHaveLength(0); }); }); diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js index bffe2db98b9..2ac20a89165 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js @@ -401,14 +401,14 @@ describe('tags list row', () => { mountComponent(); await nextTick(); - expect(findDetailsRows().length).toBe(3); + expect(findDetailsRows()).toHaveLength(3); }); it('has 2 details rows when revision is empty', async () => { mountComponent({ tag: { ...tag, revision: '' } }); await nextTick(); - expect(findDetailsRows().length).toBe(2); + expect(findDetailsRows()).toHaveLength(2); }); describe.each` @@ -470,7 +470,7 @@ describe('tags list row', () => { mountComponent({ tag: { ...tag, digest: null } }); await nextTick(); - expect(findDetailsRows().length).toBe(0); + expect(findDetailsRows()).toHaveLength(0); }); }); }); diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js index 8896185ce67..f5acf118bb4 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js @@ -22,7 +22,7 @@ describe('TagsLoader component', () => { it('produces the correct amount of loaders', () => { mountComponent(); - expect(findGlSkeletonLoaders().length).toBe(1); + expect(findGlSkeletonLoaders()).toHaveLength(1); }); it('has the correct props', () => { diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js index bc0102055ff..1a4153c1c92 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js @@ -22,7 +22,7 @@ describe('Image List', () => { it('contains one list element for each image', () => { mountComponent(); - expect(findRow().length).toBe(imagesListResponse.length); + expect(findRow()).toHaveLength(imagesListResponse.length); }); it('when delete event is emitted on the row it emits up a delete event', () => { diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js index a1803ecf7fb..ff185fea23b 100644 --- a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js +++ b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js @@ -24,7 +24,7 @@ describe('Harbor List', () => { it('contains one list element for each image', () => { mountComponent(); - expect(findHarborListRow().length).toBe(harborImagesList.length); + expect(findHarborListRow()).toHaveLength(harborImagesList.length); }); it('passes down the metadataLoading prop', () => { diff --git a/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js index 8bad49acd50..a43e49f054b 100644 --- a/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js +++ b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js @@ -141,7 +141,7 @@ describe('BulkImportsHistoryApp', () => { findPaginationBar().vm.$emit('set-page', NEW_PAGE); await waitForPromises(); - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); expect(mock.history.get[0].params).toStrictEqual(expect.objectContaining({ page: NEW_PAGE })); }); }); @@ -159,7 +159,7 @@ describe('BulkImportsHistoryApp', () => { }); it('makes a request to bulk_import_history endpoint', () => { - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); expect(mock.history.get[0].url).toBe(`/api/v4/bulk_imports/${mockId}/entities`); expect(mock.history.get[0].params).toStrictEqual({ page: 1, @@ -178,7 +178,7 @@ describe('BulkImportsHistoryApp', () => { findPaginationBar().vm.$emit('set-page-size', NEW_PAGE_SIZE); await waitForPromises(); - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); expect(mock.history.get[0].params).toStrictEqual( expect.objectContaining({ per_page: NEW_PAGE_SIZE }), ); @@ -196,7 +196,7 @@ describe('BulkImportsHistoryApp', () => { findPaginationBar().vm.$emit('set-page-size', NEW_PAGE_SIZE); await waitForPromises(); - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); expect(mock.history.get[0].params).toStrictEqual( expect.objectContaining({ per_page: NEW_PAGE_SIZE, page: 1 }), ); diff --git a/spec/frontend/pages/import/history/components/import_history_app_spec.js b/spec/frontend/pages/import/history/components/import_history_app_spec.js index 8e14b5a24f8..d9eb3d3e8af 100644 --- a/spec/frontend/pages/import/history/components/import_history_app_spec.js +++ b/spec/frontend/pages/import/history/components/import_history_app_spec.js @@ -117,7 +117,7 @@ describe('ImportHistoryApp', () => { wrapper.findComponent(PaginationBar).vm.$emit('set-page', NEW_PAGE); await axios.waitForAll(); - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); expect(mock.history.get[0].params).toStrictEqual(expect.objectContaining({ page: NEW_PAGE })); expect(wrapper.findComponent(GlTable).props().items).toStrictEqual(FAKE_NEXT_PAGE_REPLY); }); @@ -134,7 +134,7 @@ describe('ImportHistoryApp', () => { wrapper.findComponent(PaginationBar).vm.$emit('set-page-size', NEW_PAGE_SIZE); await axios.waitForAll(); - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); expect(mock.history.get[0].params).toStrictEqual( expect.objectContaining({ per_page: NEW_PAGE_SIZE }), ); @@ -153,7 +153,7 @@ describe('ImportHistoryApp', () => { wrapper.findComponent(PaginationBar).vm.$emit('set-page-size', NEW_PAGE_SIZE); await axios.waitForAll(); - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); expect(mock.history.get[0].params).toStrictEqual( expect.objectContaining({ per_page: NEW_PAGE_SIZE, page: 1 }), ); diff --git a/spec/frontend/pipeline_wizard/components/commit_spec.js b/spec/frontend/pipeline_wizard/components/commit_spec.js index 09ff7fd1e5e..101fe9116d3 100644 --- a/spec/frontend/pipeline_wizard/components/commit_spec.js +++ b/spec/frontend/pipeline_wizard/components/commit_spec.js @@ -137,7 +137,7 @@ describe('Pipeline Wizard - Commit Page', () => { }); it('emits a done event', () => { - expect(wrapper.emitted().done.length).toBe(1); + expect(wrapper.emitted().done).toHaveLength(1); }); }); diff --git a/spec/frontend/pipeline_wizard/components/step_nav_spec.js b/spec/frontend/pipeline_wizard/components/step_nav_spec.js index 8a94f58523a..4ce4d8c6ca8 100644 --- a/spec/frontend/pipeline_wizard/components/step_nav_spec.js +++ b/spec/frontend/pipeline_wizard/components/step_nav_spec.js @@ -43,14 +43,14 @@ describe('Pipeline Wizard - Step Navigation Component', () => { createComponent(); await prevButton.trigger('click'); - expect(wrapper.emitted().back.length).toBe(1); + expect(wrapper.emitted().back).toHaveLength(1); }); it('emits "next" events when clicking next button', async () => { createComponent(); await nextButton.trigger('click'); - expect(wrapper.emitted().next.length).toBe(1); + expect(wrapper.emitted().next).toHaveLength(1); }); it('enables the next button if nextButtonEnabled ist set to true', () => { diff --git a/spec/frontend/pipeline_wizard/components/widgets/list_spec.js b/spec/frontend/pipeline_wizard/components/widgets/list_spec.js index 2d94c2cfe18..fa924dcd063 100644 --- a/spec/frontend/pipeline_wizard/components/widgets/list_spec.js +++ b/spec/frontend/pipeline_wizard/components/widgets/list_spec.js @@ -76,7 +76,7 @@ describe('Pipeline Wizard - List Widget', () => { await addStep(); const inputGroups = findAllGlFormInputGroups().wrappers; - expect(inputGroups.length).toBe(3); + expect(inputGroups).toHaveLength(3); inputGroups.forEach((inputGroup) => { const button = inputGroup.find('[data-testid="remove-step-button"]'); expect(button.find('[data-testid="remove-icon"]').exists()).toBe(true); @@ -97,7 +97,7 @@ describe('Pipeline Wizard - List Widget', () => { const inputGroups = findAllGlFormInputGroups().wrappers; - expect(inputGroups.length).toBe(1); + expect(inputGroups).toHaveLength(1); expect(wrapper.findByTestId('remove-step-button').exists()).toBe(false); }); @@ -129,9 +129,9 @@ describe('Pipeline Wizard - List Widget', () => { it('the "add step" button increases the number of input fields', async () => { createComponent(); - expect(findAllGlFormInputGroups().wrappers.length).toBe(1); + expect(findAllGlFormInputGroups().wrappers).toHaveLength(1); await addStep(); - expect(findAllGlFormInputGroups().wrappers.length).toBe(2); + expect(findAllGlFormInputGroups().wrappers).toHaveLength(2); }); it('does not pass the placeholder on subsequent input fields', async () => { @@ -164,7 +164,7 @@ describe('Pipeline Wizard - List Widget', () => { const events = wrapper.emitted('input'); - expect(events.length).toBe(1); + expect(events).toHaveLength(1); expect(events[0]).toEqual([['abc']]); }); }); diff --git a/spec/frontend/pipeline_wizard/pipeline_wizard_spec.js b/spec/frontend/pipeline_wizard/pipeline_wizard_spec.js index e7bd7f686b6..039e5006cfa 100644 --- a/spec/frontend/pipeline_wizard/pipeline_wizard_spec.js +++ b/spec/frontend/pipeline_wizard/pipeline_wizard_spec.js @@ -102,6 +102,6 @@ describe('PipelineWizard', () => { wrapper.findComponent(PipelineWizardWrapper).vm.$emit('done'); - expect(wrapper.emitted().done.length).toBe(1); + expect(wrapper.emitted().done).toHaveLength(1); }); }); diff --git a/spec/frontend/profile/components/snippets/snippets_tab_spec.js b/spec/frontend/profile/components/snippets/snippets_tab_spec.js index 5992bb03e4d..38f4a3b6248 100644 --- a/spec/frontend/profile/components/snippets/snippets_tab_spec.js +++ b/spec/frontend/profile/components/snippets/snippets_tab_spec.js @@ -123,7 +123,9 @@ describe('UserProfileSnippetsTab', () => { it('renders a snippet row for each snippet', () => { expect(findSnippetRows().exists()).toBe(true); - expect(findSnippetRows().length).toBe(MOCK_USER_SNIPPETS_RES.data.user.snippets.nodes.length); + expect(findSnippetRows()).toHaveLength( + MOCK_USER_SNIPPETS_RES.data.user.snippets.nodes.length, + ); }); it('does not render empty state', () => { diff --git a/spec/frontend/profile/components/user_achievements_spec.js b/spec/frontend/profile/components/user_achievements_spec.js index 518b0b1506e..6c159893dcf 100644 --- a/spec/frontend/profile/components/user_achievements_spec.js +++ b/spec/frontend/profile/components/user_achievements_spec.js @@ -44,7 +44,7 @@ describe('UserAchievements', () => { await waitForPromises(); - expect(wrapper.findAllByTestId('user-achievement').length).toBe(0); + expect(wrapper.findAllByTestId('user-achievement')).toHaveLength(0); }); it('renders no achievements when none are present', async () => { @@ -54,7 +54,7 @@ describe('UserAchievements', () => { await waitForPromises(); - expect(wrapper.findAllByTestId('user-achievement').length).toBe(0); + expect(wrapper.findAllByTestId('user-achievement')).toHaveLength(0); }); it('renders count for achievements awarded more than once', async () => { @@ -117,6 +117,6 @@ describe('UserAchievements', () => { await waitForPromises(); - expect(wrapper.findAllByTestId('achievement-description').length).toBe(0); + expect(wrapper.findAllByTestId('achievement-description')).toHaveLength(0); }); }); diff --git a/spec/frontend/profile/preferences/components/diffs_colors_spec.js b/spec/frontend/profile/preferences/components/diffs_colors_spec.js index 22caef5c7b9..ccfad308c06 100644 --- a/spec/frontend/profile/preferences/components/diffs_colors_spec.js +++ b/spec/frontend/profile/preferences/components/diffs_colors_spec.js @@ -78,7 +78,7 @@ describe('DiffsColors component', () => { const colorPickers = findColorPickers(); - expect(colorPickers.length).toBe(2); + expect(colorPickers).toHaveLength(2); expect(colorPickers.at(0).props()).toMatchObject({ label: 'Color for removed lines', value: '#ff0000', diff --git a/spec/frontend/projects/commit/store/getters_spec.js b/spec/frontend/projects/commit/store/getters_spec.js index f45f3114550..31bcd14a9cf 100644 --- a/spec/frontend/projects/commit/store/getters_spec.js +++ b/spec/frontend/projects/commit/store/getters_spec.js @@ -36,8 +36,8 @@ describe('Commit form modal getters', () => { ]; const state = { projects }; - expect(state.projects.length).toBe(3); - expect(getters.sortedProjects(state).length).toBe(2); + expect(state.projects).toHaveLength(3); + expect(getters.sortedProjects(state)).toHaveLength(2); expect(getters.sortedProjects(state)).toEqual(projects.slice(1)); }); }); diff --git a/spec/frontend/projects/compare/components/app_spec.js b/spec/frontend/projects/compare/components/app_spec.js index c86bff45ab4..b093b243ea2 100644 --- a/spec/frontend/projects/compare/components/app_spec.js +++ b/spec/frontend/projects/compare/components/app_spec.js @@ -82,7 +82,7 @@ describe('CompareApp component', () => { it('render Source and Target BranchDropdown components', () => { const revisionCards = wrapper.findAllComponents(RevisionCard); - expect(revisionCards.length).toBe(2); + expect(revisionCards).toHaveLength(2); expect(revisionCards.at(0).props('revisionText')).toBe(I18N.source); expect(revisionCards.at(1).props('revisionText')).toBe(I18N.target); }); diff --git a/spec/frontend/projects/new_v2/components/import_project_form_spec.js b/spec/frontend/projects/new_v2/components/import_project_form_spec.js index 3970477faf4..9ed2335a4af 100644 --- a/spec/frontend/projects/new_v2/components/import_project_form_spec.js +++ b/spec/frontend/projects/new_v2/components/import_project_form_spec.js @@ -129,7 +129,7 @@ describe('Import Project Form', () => { it('renders a selectable item for all available options', () => { createComponent(); - expect(findImportOptionItems().length).toBe(2); + expect(findImportOptionItems()).toHaveLength(2); expect(findImportOptionItem(0).attributes('value')).toEqual('gitlab'); expect(findImportOptionItem(1).attributes('value')).toEqual('github'); }); @@ -144,7 +144,7 @@ describe('Import Project Form', () => { }, }); - expect(findImportOptionItems().length).toBe(1); + expect(findImportOptionItems()).toHaveLength(1); expect(findImportOptionItem(0).attributes('value')).toEqual('manifest'); }); @@ -158,7 +158,7 @@ describe('Import Project Form', () => { }, }); - expect(findImportOptionItems().length).toBe(0); + expect(findImportOptionItems()).toHaveLength(0); }); }); }); diff --git a/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js index 6d3317a5f78..fac5d03d4ff 100644 --- a/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js +++ b/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js @@ -51,7 +51,7 @@ describe('Branch dropdown', () => { }); it('renders GlDropdownItem components for each branch', () => { - expect(findAllBranches().length).toBe(mockBranchNames.length); + expect(findAllBranches()).toHaveLength(mockBranchNames.length); mockBranchNames.forEach((branchName, index) => expect(findAllBranches().at(index).text()).toBe(branchName), diff --git a/spec/frontend/projects/settings/branch_rules/components/view/access_levels_drawer_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/access_levels_drawer_spec.js index 65845fb538d..0adf775e0f6 100644 --- a/spec/frontend/projects/settings/branch_rules/components/view/access_levels_drawer_spec.js +++ b/spec/frontend/projects/settings/branch_rules/components/view/access_levels_drawer_spec.js @@ -72,7 +72,7 @@ describe('Edit Access Levels Drawer', () => { }); it('renders checkboxes with expected text', () => { - expect(findCheckboxes().length).toBe(4); + expect(findCheckboxes()).toHaveLength(4); expect(findAdministratorsCheckbox().text()).toBe('Administrators'); expect(findMaintainersCheckbox().text()).toBe('Maintainers'); expect(findDevelopersAndMaintainersCheckbox().text()).toBe('Developers and Maintainers'); @@ -138,7 +138,7 @@ describe('Edit Access Levels Drawer', () => { }); it('does not render a checkbox for Administrators', () => { - expect(findCheckboxes().length).toBe(3); + expect(findCheckboxes()).toHaveLength(3); expect(findAdministratorsCheckbox().exists()).toBe(false); }); }); diff --git a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js index 5467d3ba6ea..c8e6da0da85 100644 --- a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js +++ b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js @@ -97,7 +97,7 @@ describe('Branch rules app', () => { const { nodes } = branchRulesMockResponse.data.project.branchRules; - expect(findAllBranchRules().length).toBe(nodes.length); + expect(findAllBranchRules()).toHaveLength(nodes.length); expect(findAllBranchRules().at(0).props()).toEqual( expect.objectContaining({ @@ -232,7 +232,7 @@ describe('Branch rules app', () => { await findAddBranchRuleDropdown().vm.$emit('shown'); await nextTick(); - expect(findAddBranchRuleDropdown().props('items').length).toEqual( + expect(findAddBranchRuleDropdown().props('items')).toHaveLength( addBranchRulesItems.length - nodes.length, ); }); diff --git a/spec/frontend/rapid_diffs/diff_file_spec.js b/spec/frontend/rapid_diffs/diff_file_spec.js index 2b033ee06c5..ef3aee4bc42 100644 --- a/spec/frontend/rapid_diffs/diff_file_spec.js +++ b/spec/frontend/rapid_diffs/diff_file_spec.js @@ -171,7 +171,7 @@ describe('DiffFile Web Component', () => {
`; const instances = DiffFile.getAll(); - expect(instances.length).toBe(2); + expect(instances).toHaveLength(2); instances.forEach((instance) => expect(instance).toBeInstanceOf(DiffFile)); // properly run destruction callbacks instances.forEach((instance) => instance.mount(app)); diff --git a/spec/frontend/rapid_diffs/options_menu/adapter_spec.js b/spec/frontend/rapid_diffs/options_menu/adapter_spec.js index 958ce2db38b..be53245f470 100644 --- a/spec/frontend/rapid_diffs/options_menu/adapter_spec.js +++ b/spec/frontend/rapid_diffs/options_menu/adapter_spec.js @@ -91,7 +91,7 @@ describe('Diff File Options Menu', () => { const items = Array.from(get('menuItems')); - expect(items.length).toBe(1); + expect(items).toHaveLength(1); expect(items[0].textContent.trim()).toBe(item1.text); expect(items[0].querySelector('a').getAttribute('href')).toBe(item1.path); }); diff --git a/spec/frontend/read_more_spec.js b/spec/frontend/read_more_spec.js index a4104c39e04..c21de63696e 100644 --- a/spec/frontend/read_more_spec.js +++ b/spec/frontend/read_more_spec.js @@ -105,7 +105,7 @@ describe('data-read-more-height defines when to show the read-more button', () = initReadMore(); - expect(findTrigger().length).toBe(1); + expect(findTrigger()).toHaveLength(1); }); it('if set hides button as threshold is met', () => { @@ -120,6 +120,6 @@ describe('data-read-more-height defines when to show the read-more button', () = initReadMore(); - expect(findTrigger().length).toBe(0); + expect(findTrigger()).toHaveLength(0); }); }); diff --git a/spec/frontend/ref/components/ref_selector_spec.js b/spec/frontend/ref/components/ref_selector_spec.js index eb3a7a120d7..5e965792828 100644 --- a/spec/frontend/ref/components/ref_selector_spec.js +++ b/spec/frontend/ref/components/ref_selector_spec.js @@ -832,7 +832,7 @@ describe('Ref selector component', () => { selectFirstBranch(); await nextTick(); - expect(findCountBadges().length).toBe(2); + expect(findCountBadges()).toHaveLength(2); expect(findCountBadges().at(0).text()).toBe('2'); expect(findCountBadges().at(1).text()).toBe('3'); }); @@ -902,7 +902,7 @@ describe('Ref selector component', () => { (item) => item.text().includes(defaultBranchName) && item.text().includes('default'), ); - expect(defaultBranchItem.length).toBe(1); + expect(defaultBranchItem).toHaveLength(1); }); }); }); diff --git a/spec/frontend/repository/commits_service_spec.js b/spec/frontend/repository/commits_service_spec.js index 09a3e53c7f7..dca172841df 100644 --- a/spec/frontend/repository/commits_service_spec.js +++ b/spec/frontend/repository/commits_service_spec.js @@ -59,7 +59,7 @@ describe('commits service', () => { it('calls axios get once per batch', async () => { await Promise.all([requestCommits(0), requestCommits(1), requestCommits(23)]); - expect(axios.get.mock.calls.length).toEqual(1); + expect(axios.get.mock.calls).toHaveLength(1); }); it('updates the list of requested offsets', async () => { diff --git a/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js b/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js index 3fd9284e29b..9837357cd36 100644 --- a/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js +++ b/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js @@ -29,7 +29,7 @@ describe('ConflictsModal', () => { }); it('renders a selection of markdown fields', () => { - expect(findInstructions().length).toBe(3); + expect(findInstructions()).toHaveLength(3); }); it('renders a source url in a first intruction', () => { diff --git a/spec/frontend/repository/components/header_area/breadcrumbs_spec.js b/spec/frontend/repository/components/header_area/breadcrumbs_spec.js index 010b21e7c42..bc2e2be8408 100644 --- a/spec/frontend/repository/components/header_area/breadcrumbs_spec.js +++ b/spec/frontend/repository/components/header_area/breadcrumbs_spec.js @@ -179,7 +179,7 @@ describe('Repository breadcrumbs component', () => { directoryCodeDropdownUpdates: true, }, }); - expect(findGLBreadcrumb().props('items').length).toEqual(linkCount); + expect(findGLBreadcrumb().props('items')).toHaveLength(linkCount); }); it.each` @@ -237,7 +237,7 @@ describe('Repository breadcrumbs component', () => { `('renders $linkCount links for path $path', ({ path, linkCount }) => { factory({ currentPath: path }); - expect(findRouterLinks().length).toEqual(linkCount); + expect(findRouterLinks()).toHaveLength(linkCount); }); it.each` diff --git a/spec/frontend/repository/components/header_area/open_mr_badge_spec.js b/spec/frontend/repository/components/header_area/open_mr_badge_spec.js index ca4f4fa7f3a..0c01dcd58cc 100644 --- a/spec/frontend/repository/components/header_area/open_mr_badge_spec.js +++ b/spec/frontend/repository/components/header_area/open_mr_badge_spec.js @@ -141,7 +141,7 @@ describe('OpenMrBadge', () => { targetBranch: ['main'], }); - expect(findAllMergeRequestItems().length).toEqual(2); + expect(findAllMergeRequestItems()).toHaveLength(2); expect(findLoader().exists()).toBe(false); }); diff --git a/spec/frontend/repository/components/table/index_spec.js b/spec/frontend/repository/components/table/index_spec.js index ce22d49a5f2..368d8498375 100644 --- a/spec/frontend/repository/components/table/index_spec.js +++ b/spec/frontend/repository/components/table/index_spec.js @@ -142,7 +142,7 @@ describe('Repository table component', () => { const rows = findTableRows(); - expect(rows.length).toEqual(3); + expect(rows).toHaveLength(3); expect(rows.at(2).attributes().mode).toEqual('120000'); expect(rows.at(2).props().rowNumber).toBe(2); expect(rows.at(2).props().commitInfo).toEqual(MOCK_COMMITS[2]); diff --git a/spec/frontend/repository/log_tree_spec.js b/spec/frontend/repository/log_tree_spec.js index a2e86c86add..6a169878a71 100644 --- a/spec/frontend/repository/log_tree_spec.js +++ b/spec/frontend/repository/log_tree_spec.js @@ -96,7 +96,7 @@ describe('fetchLogsTree', () => { fetchLogsTree(client, '', '0', resolver), fetchLogsTree(client, '', '0', resolver), ]).then(() => { - expect(axios.get.mock.calls.length).toEqual(1); + expect(axios.get.mock.calls).toHaveLength(1); })); it('calls axios for each path', () => @@ -104,7 +104,7 @@ describe('fetchLogsTree', () => { fetchLogsTree(client, '', '0', resolver), fetchLogsTree(client, '/test', '0', resolver), ]).then(() => { - expect(axios.get.mock.calls.length).toEqual(2); + expect(axios.get.mock.calls).toHaveLength(2); })); it('calls entry resolver', () => diff --git a/spec/frontend/repository/mixins/highlight_mixin_spec.js b/spec/frontend/repository/mixins/highlight_mixin_spec.js index 990c17dce72..5a7e0bc4cf6 100644 --- a/spec/frontend/repository/mixins/highlight_mixin_spec.js +++ b/spec/frontend/repository/mixins/highlight_mixin_spec.js @@ -76,7 +76,7 @@ describe('HighlightMixin', () => { }); it('calls postMessage on the worker', () => { - expect(workerMock.postMessage.mock.calls.length).toBe(2); + expect(workerMock.postMessage.mock.calls).toHaveLength(2); // first call instructs worker to highlight the first 70 lines expect(workerMock.postMessage.mock.calls[0][0]).toMatchObject({ diff --git a/spec/frontend/search/highlight_blob_search_result_spec.js b/spec/frontend/search/highlight_blob_search_result_spec.js index 91fc97c15ae..5d7a29d5f35 100644 --- a/spec/frontend/search/highlight_blob_search_result_spec.js +++ b/spec/frontend/search/highlight_blob_search_result_spec.js @@ -14,6 +14,6 @@ describe('search/highlight_blob_search_result', () => { it('highlights lines with search term occurrence', () => { setHighlightClass(searchKeyword); - expect(document.querySelectorAll('.js-blob-result .hll').length).toBe(4); + expect(document.querySelectorAll('.js-blob-result .hll')).toHaveLength(4); }); }); diff --git a/spec/frontend/search/results/utils_spec.js b/spec/frontend/search/results/utils_spec.js index 82eccf40af9..39ba616d6aa 100644 --- a/spec/frontend/search/results/utils_spec.js +++ b/spec/frontend/search/results/utils_spec.js @@ -253,7 +253,7 @@ describe('Global Search Results Utils', () => { expect(result.length).toBeLessThan(html.length); expect(result).toContain('HIGHLIGHTED-'); - expect(result.length).toBe(3045); + expect(result).toHaveLength(3045); expect(result).toMatch(/…/); }); @@ -274,7 +274,7 @@ describe('Global Search Results Utils', () => { expect(result).toContain('FIRST'); expect(result).toContain('SECOND'); expect(result).not.toContain('THIRD'); - expect(result.length).toBe(3014); + expect(result).toHaveLength(3014); }); it('properly handles string with many highlights with no apparent clusters', () => { @@ -348,7 +348,7 @@ describe('Global Search Results Utils', () => { // to measure the trim correctly we have // to strip away the html tags const cleanText = result.replace(/<[^>]*>/g, ''); - expect(cleanText.length).toBe(3001); + expect(cleanText).toHaveLength(3001); }); it('properly handles string with NO highlights', () => { diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js index a215c4ab98a..41d8e5689c9 100644 --- a/spec/frontend/search/store/actions_spec.js +++ b/spec/frontend/search/store/actions_spec.js @@ -565,7 +565,7 @@ describe('Global Search Store Actions', () => { it('should not request anything', async () => { await testAction({ action: actions.fetchSidebarCount, state, expectedMutations: [] }); - expect(mock.history.get.length).toBe(0); + expect(mock.history.get).toHaveLength(0); }); }); diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js index 39005555d72..4b5e13aa719 100644 --- a/spec/frontend/security_configuration/components/app_spec.js +++ b/spec/frontend/security_configuration/components/app_spec.js @@ -300,7 +300,7 @@ describe('~/security_configuration/components/app', () => { }); it('does not render feature card component', () => { - expect(findFeatureCards().length).toBe(0); + expect(findFeatureCards()).toHaveLength(0); }); it('renders component with correct props', () => { expect(findSecretPushProtection().exists()).toBe(true); @@ -316,7 +316,7 @@ describe('~/security_configuration/components/app', () => { }); it('does not render regular feature card component', () => { - expect(findFeatureCards().length).toBe(0); + expect(findFeatureCards()).toHaveLength(0); }); it('renders PipelineSecretDetectionFeatureCard with correct props', () => { diff --git a/spec/frontend/sidebar/components/assignees/assignees_spec.js b/spec/frontend/sidebar/components/assignees/assignees_spec.js index 099f03eae90..2b48ed815fe 100644 --- a/spec/frontend/sidebar/components/assignees/assignees_spec.js +++ b/spec/frontend/sidebar/components/assignees/assignees_spec.js @@ -31,7 +31,7 @@ describe('Assignee component', () => { const collapsedChildren = findCollapsedChildren(); const userIcon = collapsedChildren.at(0).findComponent(GlIcon); - expect(collapsedChildren.length).toBe(1); + expect(collapsedChildren).toHaveLength(1); expect(collapsedChildren.at(0).attributes('aria-label')).toBe('None'); expect(userIcon.exists()).toBe(true); expect(userIcon.props('name')).toBe('user'); @@ -78,7 +78,7 @@ describe('Assignee component', () => { const collapsedChildren = findCollapsedChildren(); const assignee = collapsedChildren.at(0); - expect(collapsedChildren.length).toBe(1); + expect(collapsedChildren).toHaveLength(1); expect(assignee.findComponent(GlAvatar).props('src')).toBe(UsersMock.user.avatar); expect(assignee.findComponent(GlAvatar).props('alt')).toBe(`${UsersMock.user.name}'s avatar`); @@ -96,7 +96,7 @@ describe('Assignee component', () => { const collapsedChildren = findCollapsedChildren(); - expect(collapsedChildren.length).toBe(2); + expect(collapsedChildren).toHaveLength(2); const first = collapsedChildren.at(0); @@ -122,7 +122,7 @@ describe('Assignee component', () => { const collapsedChildren = findCollapsedChildren(); - expect(collapsedChildren.length).toBe(2); + expect(collapsedChildren).toHaveLength(2); const first = collapsedChildren.at(0); diff --git a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js index 52d68d7047e..7f4f4e1e6c6 100644 --- a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js +++ b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js @@ -87,7 +87,7 @@ describe('CollapsedAssigneeList component', () => { }); it('returns just two collapsed users', () => { - expect(findAssignees().length).toBe(2); + expect(findAssignees()).toHaveLength(2); }); }); @@ -111,7 +111,7 @@ describe('CollapsedAssigneeList component', () => { }); it('returns one collapsed users', () => { - expect(findAssignees().length).toBe(1); + expect(findAssignees()).toHaveLength(1); }); }); diff --git a/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js index 27c31ac56c9..b3ab7a70385 100644 --- a/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js +++ b/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js @@ -117,7 +117,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 () => { diff --git a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js index 9e7a198d32c..ec794d4b7b3 100644 --- a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js +++ b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js @@ -38,7 +38,7 @@ describe('UncollapsedAssigneeList component', () => { }); it('only has one user', () => { - expect(wrapper.findAllComponents(AssigneeAvatarLink).length).toBe(1); + expect(wrapper.findAllComponents(AssigneeAvatarLink)).toHaveLength(1); }); it('calls the AssigneeAvatarLink with the proper props', () => { @@ -75,7 +75,7 @@ describe('UncollapsedAssigneeList component', () => { }); it('shows truncated users', () => { - expect(wrapper.findAllComponents(AssigneeAvatarLink).length).toBe(DEFAULT_RENDER_COUNT); + expect(wrapper.findAllComponents(AssigneeAvatarLink)).toHaveLength(DEFAULT_RENDER_COUNT); }); describe('when more button is clicked', () => { @@ -90,7 +90,7 @@ describe('UncollapsedAssigneeList component', () => { }); it('shows all users', () => { - expect(wrapper.findAllComponents(AssigneeAvatarLink).length).toBe( + expect(wrapper.findAllComponents(AssigneeAvatarLink)).toHaveLength( DEFAULT_RENDER_COUNT + 1, ); }); @@ -112,7 +112,7 @@ describe('UncollapsedAssigneeList component', () => { { mrAttentionRequests: true }, ); - expect(wrapper.findAll('[data-testid="username"]').length).toBe(numberOfUsers); + expect(wrapper.findAll('[data-testid="username"]')).toHaveLength(numberOfUsers); }); }); }); diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_value_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_value_spec.js index 21068c2858d..db0ee6f442b 100644 --- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_value_spec.js +++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_value_spec.js @@ -53,7 +53,7 @@ describe('DropdownValue', () => { }); it('does not render any labels', () => { - expect(findAllLabels().length).toBe(0); + expect(findAllLabels()).toHaveLength(0); }); }); @@ -71,7 +71,7 @@ describe('DropdownValue', () => { }); it('renders a list of three labels', () => { - expect(findAllLabels().length).toBe(3); + expect(findAllLabels()).toHaveLength(3); }); it('passes correct props to the regular label', () => { diff --git a/spec/frontend/sidebar/components/reviewers/reviewers_spec.js b/spec/frontend/sidebar/components/reviewers/reviewers_spec.js index 3afbb81fbae..91353b472b4 100644 --- a/spec/frontend/sidebar/components/reviewers/reviewers_spec.js +++ b/spec/frontend/sidebar/components/reviewers/reviewers_spec.js @@ -41,7 +41,7 @@ describe('Reviewer component', () => { editable: true, }); - expect(wrapper.findAll('[data-testid="reviewer"]').length).toBe(users.length); + expect(wrapper.findAll('[data-testid="reviewer"]')).toHaveLength(users.length); }); it('shows sorted reviewer where "can merge" users are sorted first', () => { @@ -72,7 +72,7 @@ describe('Reviewer component', () => { const userItems = wrapper.findAll('[data-testid="reviewer"]'); - expect(userItems.length).toBe(3); + expect(userItems).toHaveLength(3); }); }); }); diff --git a/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js index 277ef6d9561..6ede64b22d5 100644 --- a/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js +++ b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js @@ -31,6 +31,6 @@ describe('Sidebar reviewers inputs component', () => { factory(); - expect(wrapper.findAll('input[type="hidden"]').length).toBe(2); + expect(wrapper.findAll('input[type="hidden"]')).toHaveLength(2); }); }); diff --git a/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_spec.js b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_spec.js index 795bfba1301..57556d8e2bb 100644 --- a/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_spec.js +++ b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_spec.js @@ -149,12 +149,12 @@ describe('sidebar reviewers', () => { createComponent(); expect(mediator.addSelfReview).not.toHaveBeenCalled(); - expect(mediator.store.reviewers.length).toBe(0); + expect(mediator.store.reviewers).toHaveLength(0); wrapper.vm.reviewBySelf(); expect(mediator.addSelfReview).toHaveBeenCalled(); - expect(mediator.store.reviewers.length).toBe(1); + expect(mediator.store.reviewers).toHaveLength(1); }); }); }); diff --git a/spec/frontend/sidebar/stores/sidebar_store_spec.js b/spec/frontend/sidebar/stores/sidebar_store_spec.js index 3f4b80409c2..b80a9f855fc 100644 --- a/spec/frontend/sidebar/stores/sidebar_store_spec.js +++ b/spec/frontend/sidebar/stores/sidebar_store_spec.js @@ -98,7 +98,7 @@ describe('Sidebar store', () => { it('removes all assignees', () => { testContext.store.removeAllAssignees(); - expect(testContext.store.assignees.length).toEqual(0); + expect(testContext.store.assignees).toHaveLength(0); expect(testContext.store.changing).toBe(true); }); @@ -110,7 +110,7 @@ describe('Sidebar store', () => { testContext.store.setAssigneeData(users); expect(testContext.store.isFetching.assignees).toBe(false); - expect(testContext.store.assignees.length).toEqual(3); + expect(testContext.store.assignees).toHaveLength(3); }); it('sets fetching state', () => { diff --git a/spec/frontend/single_file_diff_spec.js b/spec/frontend/single_file_diff_spec.js index 572fd3810ab..7f8ea51dc7b 100644 --- a/spec/frontend/single_file_diff_spec.js +++ b/spec/frontend/single_file_diff_spec.js @@ -64,7 +64,7 @@ describe('SingleFileDiff', () => { expect(diff.isOpen).toBe(true); expect(diff.content).not.toBeNull(); - expect(mock.history.get.length).toBe(1); + expect(mock.history.get).toHaveLength(1); }); it('ignores user-defined diff path attributes', () => { @@ -110,6 +110,6 @@ describe('SingleFileDiff', () => { await diff.toggleDiff($(document.querySelector('.js-file-title'))); expect(diff.isOpen).toBe(true); - expect(mock.history.get.length).toBe(0); + expect(mock.history.get).toHaveLength(0); }); }); diff --git a/spec/frontend/snippets/components/show_spec.js b/spec/frontend/snippets/components/show_spec.js index 2c2e8e74d7f..b1ba7b28044 100644 --- a/spec/frontend/snippets/components/show_spec.js +++ b/spec/frontend/snippets/components/show_spec.js @@ -59,7 +59,7 @@ describe('Snippet view app', () => { }, }); const blobs = wrapper.findAllComponents(SnippetBlob); - expect(blobs.length).toBe(2); + expect(blobs).toHaveLength(2); expect(blobs.at(0).props('blob')).toEqual(Blob); expect(blobs.at(1).props('blob')).toEqual(BinaryBlob); }); diff --git a/spec/frontend/streaming/rate_limit_stream_requests_spec.js b/spec/frontend/streaming/rate_limit_stream_requests_spec.js index 02e3cf93014..55b4795ab97 100644 --- a/spec/frontend/streaming/rate_limit_stream_requests_spec.js +++ b/spec/frontend/streaming/rate_limit_stream_requests_spec.js @@ -24,7 +24,7 @@ describe('rateLimitStreamRequests', () => { total: 0, }); expect(factory).toHaveBeenCalledTimes(0); - expect(requests.length).toBe(0); + expect(requests).toHaveLength(0); }); it('does not exceed total requests', () => { @@ -36,7 +36,7 @@ describe('rateLimitStreamRequests', () => { total: 2, }); expect(factory).toHaveBeenCalledTimes(2); - expect(requests.length).toBe(2); + expect(requests).toHaveLength(2); }); it('creates immediate requests', () => { @@ -47,7 +47,7 @@ describe('rateLimitStreamRequests', () => { total: 2, }); expect(factory).toHaveBeenCalledTimes(2); - expect(requests.length).toBe(2); + expect(requests).toHaveLength(2); }); it('returns correct values', async () => { @@ -83,7 +83,7 @@ describe('rateLimitStreamRequests', () => { total: 3, }); expect(factory).toHaveBeenCalledTimes(2); - expect(requests.length).toBe(3); + expect(requests).toHaveLength(3); await waitForPromises(); @@ -107,7 +107,7 @@ describe('rateLimitStreamRequests', () => { total: 2, }); expect(factory).toHaveBeenCalledTimes(1); - expect(requests.length).toBe(2); + expect(requests).toHaveLength(2); await waitForPromises(); @@ -139,7 +139,7 @@ describe('rateLimitStreamRequests', () => { timeout: 9999, }); expect(factory).toHaveBeenCalledTimes(1); - expect(requests.length).toBe(2); + expect(requests).toHaveLength(2); await waitForPromises(); diff --git a/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js b/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js index 95ee2eca449..b69bad0c51c 100644 --- a/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js +++ b/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js @@ -400,8 +400,8 @@ describe('Global Search Store Getters', () => { const expectUniqueAutocompleteResults = (result) => { expect(result).toStrictEqual(MOCK_GROUPED_AUTOCOMPLETE_OPTIONS); - expect(findGroupItems(result, 'Users').length).toBe(totalResults); - expect(findGroupItems(result, 'Projects').length).toBe(totalProjects); + expect(findGroupItems(result, 'Users')).toHaveLength(totalResults); + expect(findGroupItems(result, 'Projects')).toHaveLength(totalProjects); }; describe('without duplicates', () => { diff --git a/spec/frontend/super_sidebar/components/menu_section_spec.js b/spec/frontend/super_sidebar/components/menu_section_spec.js index 5129819c0df..953a199c509 100644 --- a/spec/frontend/super_sidebar/components/menu_section_spec.js +++ b/spec/frontend/super_sidebar/components/menu_section_spec.js @@ -40,7 +40,7 @@ describe('MenuSection component', () => { { title: 'Item2', href: '/item2' }, ], }); - expect(findNavItems().length).toBe(2); + expect(findNavItems()).toHaveLength(2); }); it('associates button with list with aria-controls', () => { diff --git a/spec/frontend/super_sidebar/components/user_menu_spec.js b/spec/frontend/super_sidebar/components/user_menu_spec.js index 2015ca8be3e..16ee089bbaf 100644 --- a/spec/frontend/super_sidebar/components/user_menu_spec.js +++ b/spec/frontend/super_sidebar/components/user_menu_spec.js @@ -400,7 +400,7 @@ describe('UserMenu component', () => { }); it('does not call the callout dismiss endpoint', () => { - expect(mockAxios.history.post.length).toBe(0); + expect(mockAxios.history.post).toHaveLength(0); }); it('does not manually proceed to the URL', () => { diff --git a/spec/frontend/super_sidebar/utils_spec.js b/spec/frontend/super_sidebar/utils_spec.js index 855cc14095a..f214b2520ec 100644 --- a/spec/frontend/super_sidebar/utils_spec.js +++ b/spec/frontend/super_sidebar/utils_spec.js @@ -25,13 +25,13 @@ describe('Super sidebar utils spec', () => { it.each([undefined, null, []])('returns empty array if `items` is %s', (items) => { const result = getTopFrequentItems(items); - expect(result.length).toBe(0); + expect(result).toHaveLength(0); }); it('returns the requested amount of items', () => { const result = getTopFrequentItems(unsortedFrequentItems, maxItems); - expect(result.length).toBe(maxItems); + expect(result).toHaveLength(maxItems); }); it('sorts frequent items in order of frequency and lastAccessedOn', () => { diff --git a/spec/frontend/syntax_highlight_spec.js b/spec/frontend/syntax_highlight_spec.js index 75e540e7e07..640c18d991e 100644 --- a/spec/frontend/syntax_highlight_spec.js +++ b/spec/frontend/syntax_highlight_spec.js @@ -43,7 +43,7 @@ describe('Syntax Highlighter', () => { expect(fn('.parent')).not.toHaveClass('code-syntax-highlight-theme'); expect(fn('.foo')).not.toHaveClass('code-syntax-highlight-theme'); - expect(document.querySelectorAll('.code-syntax-highlight-theme').length).toBe(2); + expect(document.querySelectorAll('.code-syntax-highlight-theme')).toHaveLength(2); }); it('prevents an infinite loop when no matches exist', () => { diff --git a/spec/frontend/task_list_spec.js b/spec/frontend/task_list_spec.js index 605ae028049..43a308442b9 100644 --- a/spec/frontend/task_list_spec.js +++ b/spec/frontend/task_list_spec.js @@ -79,7 +79,7 @@ describe('TaskList', () => { it('should call taskList method with disable param', () => { taskList.disableTaskListItems(); - expect(document.querySelectorAll('.task-list-item input:disabled').length).toEqual(2); + expect(document.querySelectorAll('.task-list-item input:disabled')).toHaveLength(2); }); }); @@ -88,8 +88,8 @@ describe('TaskList', () => { taskList.disableTaskListItems(); taskList.enableTaskListItems(); - expect(document.querySelectorAll('.task-list-item input:enabled').length).toEqual(1); - expect(document.querySelectorAll('.task-list-item input:disabled').length).toEqual(1); + expect(document.querySelectorAll('.task-list-item input:enabled')).toHaveLength(1); + expect(document.querySelectorAll('.task-list-item input:disabled')).toHaveLength(1); }); }); @@ -99,8 +99,8 @@ describe('TaskList', () => { taskList.enable(); - expect(document.querySelectorAll('.task-list-item input:enabled').length).toEqual(1); - expect(document.querySelectorAll('.task-list-item input:disabled').length).toEqual(1); + expect(document.querySelectorAll('.task-list-item input:enabled')).toHaveLength(1); + expect(document.querySelectorAll('.task-list-item input:disabled')).toHaveLength(1); expect($(document).on).toHaveBeenCalledWith( 'tasklist:changed', @@ -116,7 +116,7 @@ describe('TaskList', () => { taskList.disable(); - expect(document.querySelectorAll('.task-list-item input:disabled').length).toEqual(2); + expect(document.querySelectorAll('.task-list-item input:disabled')).toHaveLength(2); expect($(document).off).toHaveBeenCalledWith( 'tasklist:changed', diff --git a/spec/frontend/terraform/components/states_table_spec.js b/spec/frontend/terraform/components/states_table_spec.js index 227cf2acc70..23453d56184 100644 --- a/spec/frontend/terraform/components/states_table_spec.js +++ b/spec/frontend/terraform/components/states_table_spec.js @@ -214,6 +214,6 @@ describe('StatesTable', () => { return createComponent(); }); - expect(findActions().length).toEqual(defaultProps.states.length); + expect(findActions()).toHaveLength(defaultProps.states.length); }); }); diff --git a/spec/frontend/todos/components/todos_app_spec.js b/spec/frontend/todos/components/todos_app_spec.js index 8c3edeef5ab..74277d8bda9 100644 --- a/spec/frontend/todos/components/todos_app_spec.js +++ b/spec/frontend/todos/components/todos_app_spec.js @@ -60,13 +60,13 @@ describe('TodosApp', () => { ignoreConsoleMessages([/\[Vue warn\]: \(deprecation TRANSITION_GROUP_ROOT\)/]); it('should have a tracking event for each tab', () => { - expect(STATUS_BY_TAB.length).toBe(INSTRUMENT_TAB_LABELS.length); + expect(STATUS_BY_TAB).toHaveLength(INSTRUMENT_TAB_LABELS.length); }); it('shows a loading state while fetching todos', () => { createComponent(); - expect(findTodoItems().length).toBe(0); + expect(findTodoItems()).toHaveLength(0); expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true); }); @@ -74,7 +74,7 @@ describe('TodosApp', () => { createComponent(); await waitForPromises(); - expect(findTodoItems().length).toBe(todosResponse.data.currentUser.todos.nodes.length); + expect(findTodoItems()).toHaveLength(todosResponse.data.currentUser.todos.nodes.length); expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false); }); diff --git a/spec/frontend/user_popovers_spec.js b/spec/frontend/user_popovers_spec.js index 7b469c3147d..45f79736d39 100644 --- a/spec/frontend/user_popovers_spec.js +++ b/spec/frontend/user_popovers_spec.js @@ -68,7 +68,7 @@ describe('User Popovers', () => { triggerEvent('mouseover', el); }); - expect(findPopovers().length).toBe(0); + expect(findPopovers()).toHaveLength(0); }); }); @@ -94,7 +94,7 @@ describe('User Popovers', () => { }); it('for initial links', () => { - expect(findPopovers().length).toBe(linksWithUsers.length); + expect(findPopovers()).toHaveLength(linksWithUsers.length); }); it('for elements added after initial load', () => { @@ -109,7 +109,7 @@ describe('User Popovers', () => { triggerEvent(eventType, link); }); - expect(findPopovers().length).toBe(linksWithUsers.length + addedLinks.length); + expect(findPopovers()).toHaveLength(linksWithUsers.length + addedLinks.length); }); it('for non-link elements', () => { @@ -120,11 +120,11 @@ describe('User Popovers', () => { jest.runOnlyPendingTimers(); - expect(findPopovers().length).toBe(linksWithUsers.length); + expect(findPopovers()).toHaveLength(linksWithUsers.length); triggerEvent(eventType, div); - expect(findPopovers().length).toBe(linksWithUsers.length + 1); + expect(findPopovers()).toHaveLength(linksWithUsers.length + 1); }); }); @@ -134,7 +134,7 @@ describe('User Popovers', () => { triggerEvent('mouseover', groupLink); jest.runOnlyPendingTimers(); - expect(findPopovers().length).toBe(0); + expect(findPopovers()).toHaveLength(0); }); // TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/18442 @@ -145,7 +145,7 @@ describe('User Popovers', () => { triggerEvent('mouseover', projectLink); jest.runOnlyPendingTimers(); - expect(findPopovers().length).toBe(0); + expect(findPopovers()).toHaveLength(0); }); it('does not initialize the user popovers twice for the same element', () => { @@ -158,7 +158,7 @@ describe('User Popovers', () => { jest.runOnlyPendingTimers(); }); - expect(findPopovers().length).toBe(1); + expect(findPopovers()).toHaveLength(1); }); describe.each(['focusin', 'mouseover'])( diff --git a/spec/frontend/vue_alerts_spec.js b/spec/frontend/vue_alerts_spec.js index be4a45639cf..18bd7499ba3 100644 --- a/spec/frontend/vue_alerts_spec.js +++ b/spec/frontend/vue_alerts_spec.js @@ -65,8 +65,8 @@ describe('VueAlerts', () => { }); it('starts with only JsHooks', () => { - expect(findJsHooks().length).toEqual(alerts.length); - expect(findAlerts().length).toEqual(0); + expect(findJsHooks()).toHaveLength(alerts.length); + expect(findAlerts()).toHaveLength(0); }); describe('when mounted', () => { @@ -75,8 +75,8 @@ describe('VueAlerts', () => { }); it('replaces JsHook with GlAlert', () => { - expect(findJsHooks().length).toEqual(0); - expect(findAlerts().length).toEqual(alerts.length); + expect(findJsHooks()).toHaveLength(0); + expect(findAlerts()).toHaveLength(alerts.length); }); it('passes along props to gl-alert', () => { @@ -90,7 +90,7 @@ describe('VueAlerts', () => { }); it('hides the alert', () => { - expect(findAlerts().length).toEqual(alerts.length - 1); + expect(findAlerts()).toHaveLength(alerts.length - 1); }); }); }); diff --git a/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js b/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js index 8058c958061..775786766b1 100644 --- a/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js @@ -100,7 +100,7 @@ describe('Merge Requests Artifacts list app', () => { findTitle().trigger('click'); await nextTick(); - expect(findTableRows().length).toEqual(2); + expect(findTableRows()).toHaveLength(2); }); }); }); diff --git a/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js b/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js index bb049a5d52f..f3ef1cedf97 100644 --- a/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js @@ -23,7 +23,7 @@ describe('Artifacts List', () => { }); it('renders list of artifacts', () => { - expect(wrapper.findAll('tbody tr').length).toEqual(data.artifacts.length); + expect(wrapper.findAll('tbody tr')).toHaveLength(data.artifacts.length); }); it('renders link for the artifact', () => { diff --git a/spec/frontend/vue_merge_request_widget/components/merge_checks_spec.js b/spec/frontend/vue_merge_request_widget/components/merge_checks_spec.js index ca6ad95bb3b..0c69ee3e2e3 100644 --- a/spec/frontend/vue_merge_request_widget/components/merge_checks_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/merge_checks_spec.js @@ -188,7 +188,7 @@ describe('Merge request merge checks component', () => { wrapper.vm.toggleCollapsed(); - expect(wrapper.vm.sortedChecks.length).toBe(2); + expect(wrapper.vm.sortedChecks).toHaveLength(2); expect(wrapper.vm.sortedChecks[0].status).toBe('FAILED'); expect(wrapper.vm.sortedChecks[1].status).toBe('SUCCESS'); }); @@ -209,7 +209,7 @@ describe('Merge request merge checks component', () => { const mergeChecks = wrapper.findAllByTestId('merge-check'); - expect(mergeChecks.length).toBe(1); + expect(mergeChecks).toHaveLength(1); }); describe('expansion', () => { @@ -228,23 +228,23 @@ describe('Merge request merge checks component', () => { }); it('shows failed checks before user expands section', () => { - expect(findMergeChecks().length).toBe(1); + expect(findMergeChecks()).toHaveLength(1); }); it('shows all checks when user expands section', async () => { await wrapper.findByTestId('widget-toggle').trigger('click'); - expect(findMergeChecks().length).toBe(2); + expect(findMergeChecks()).toHaveLength(2); }); it('shows failed checks when user collapses section', async () => { await wrapper.findByTestId('widget-toggle').trigger('click'); - expect(findMergeChecks().length).toBe(2); + expect(findMergeChecks()).toHaveLength(2); await wrapper.findByTestId('widget-toggle').trigger('click'); - expect(findMergeChecks().length).toBe(1); + expect(findMergeChecks()).toHaveLength(1); }); }); diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_memory_usage_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_memory_usage_spec.js index 8e72174eb1c..8817c9e2d3e 100644 --- a/spec/frontend/vue_merge_request_widget/components/mr_widget_memory_usage_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_memory_usage_spec.js @@ -83,7 +83,7 @@ describe('MemoryUsage', () => { const data = MemoryUsage.data(); expect(Array.isArray(data.memoryMetrics)).toBe(true); - expect(data.memoryMetrics.length).toBe(0); + expect(data.memoryMetrics).toHaveLength(0); expect(typeof data.deploymentTime).toBe('number'); expect(data.deploymentTime).toBe(0); diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_closed_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_closed_spec.js index cdd63a1ce08..708114f04c4 100644 --- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_closed_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_closed_spec.js @@ -91,7 +91,7 @@ describe('MRWidgetClosed', () => { }); it('shows the "reopen" button', () => { - expect(wrapper.findComponent(StateContainer).props().actions.length).toBe(1); + expect(wrapper.findComponent(StateContainer).props().actions).toHaveLength(1); expect(findReopenActionButton(wrapper).text()).toBe('Reopen'); }); diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commit_message_dropdown_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commit_message_dropdown_spec.js index b0f9f123950..b8d6feb8478 100644 --- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commit_message_dropdown_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commit_message_dropdown_spec.js @@ -44,7 +44,7 @@ describe('Commits message dropdown component', () => { const findFirstDropdownElement = () => findDropdownElements().at(0); it('should have 3 elements in dropdown list', () => { - expect(findDropdownElements().length).toBe(3); + expect(findDropdownElements()).toHaveLength(3); }); it('should have correct message for the first dropdown list element', () => { diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_view_button_spec.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_view_button_spec.js index 06aa656d045..96a9c947a45 100644 --- a/spec/frontend/vue_merge_request_widget/deployment/deployment_view_button_spec.js +++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_view_button_spec.js @@ -92,7 +92,7 @@ describe('Deployment View App button', () => { const links = dropdown.findAll('a'); - expect(links.length).toBe(3); + expect(links).toHaveLength(3); expect(links.at(2).attributes('href')).toBe(thirdChangeUrl); }); diff --git a/spec/frontend/vue_merge_request_widget/mr_widget_how_to_merge_modal_spec.js b/spec/frontend/vue_merge_request_widget/mr_widget_how_to_merge_modal_spec.js index 60525a96907..bec28229357 100644 --- a/spec/frontend/vue_merge_request_widget/mr_widget_how_to_merge_modal_spec.js +++ b/spec/frontend/vue_merge_request_widget/mr_widget_how_to_merge_modal_spec.js @@ -29,7 +29,7 @@ describe('MRWidgetHowToMerge', () => { }); it('renders a selection of markdown fields', () => { - expect(findInstructionsFields().length).toBe(2); + expect(findInstructionsFields()).toHaveLength(2); }); it('renders a tip including a link to docs when a valid link is present', () => { diff --git a/spec/frontend/vue_popovers_spec.js b/spec/frontend/vue_popovers_spec.js index 9b1e6d910e7..839322a4425 100644 --- a/spec/frontend/vue_popovers_spec.js +++ b/spec/frontend/vue_popovers_spec.js @@ -43,8 +43,8 @@ describe('VuePopovers', () => { }); it('starts with only JsHooks', () => { - expect(findJsHooks().length).toBe(popovers.length); - expect(findPopovers().length).toBe(0); + expect(findJsHooks()).toHaveLength(popovers.length); + expect(findPopovers()).toHaveLength(0); }); describe('when mounted', () => { @@ -53,8 +53,8 @@ describe('VuePopovers', () => { }); it('replaces JsHook with Popovers and triggers', () => { - expect(findJsHooks().length).toBe(0); - expect(findPopovers().length).toBe(popovers.length); + expect(findJsHooks()).toHaveLength(0); + expect(findPopovers()).toHaveLength(popovers.length); }); it('passes along props to gl-popover', () => { diff --git a/spec/frontend/vue_shared/alert_details/alert_status_spec.js b/spec/frontend/vue_shared/alert_details/alert_status_spec.js index 97b5d10fa47..70598df2463 100644 --- a/spec/frontend/vue_shared/alert_details/alert_status_spec.js +++ b/spec/frontend/vue_shared/alert_details/alert_status_spec.js @@ -151,7 +151,7 @@ describe('AlertManagementStatus', () => { describe('Statuses', () => { it('renders default translated statuses', () => { mountComponent({}); - expect(findAllStatusOptions().length).toBe(3); + expect(findAllStatusOptions()).toHaveLength(3); expect(findFirstStatusOption().text()).toBe('Triggered'); }); diff --git a/spec/frontend/vue_shared/components/awards_list_spec.js b/spec/frontend/vue_shared/components/awards_list_spec.js index cd0e868b974..a272a4dfd9f 100644 --- a/spec/frontend/vue_shared/components/awards_list_spec.js +++ b/spec/frontend/vue_shared/components/awards_list_spec.js @@ -227,7 +227,7 @@ describe('vue_shared/components/awards_list', () => { }); it('has no award buttons', () => { - expect(findAwardButtons().length).toBe(0); + expect(findAwardButtons()).toHaveLength(0); }); }); @@ -258,7 +258,7 @@ describe('vue_shared/components/awards_list', () => { it('disables award buttons', () => { const buttons = findAwardButtons(); - expect(buttons.length).toBe(TEST_AWARDS_LENGTH); + expect(buttons).toHaveLength(TEST_AWARDS_LENGTH); expect(buttons.wrappers.every((x) => x.classes('disabled'))).toBe(true); }); }); diff --git a/spec/frontend/vue_shared/components/customizable_dashboard/customizable_dashboard_spec.js b/spec/frontend/vue_shared/components/customizable_dashboard/customizable_dashboard_spec.js index c7f06d98db2..151c9a80475 100644 --- a/spec/frontend/vue_shared/components/customizable_dashboard/customizable_dashboard_spec.js +++ b/spec/frontend/vue_shared/components/customizable_dashboard/customizable_dashboard_spec.js @@ -155,14 +155,14 @@ describe('CustomizableDashboard', () => { }); it('body container', () => { - expect(document.querySelectorAll('.container-fluid.not-container-limited').length).toBe(1); + expect(document.querySelectorAll('.container-fluid.not-container-limited')).toHaveLength(1); }); it('body container after destroy', () => { wrapper.destroy(); - expect(document.querySelectorAll('.container-fluid.not-container-limited').length).toBe(0); - expect(document.querySelectorAll('.container-fluid.container-limited').length).toBe(1); + expect(document.querySelectorAll('.container-fluid.not-container-limited')).toHaveLength(0); + expect(document.querySelectorAll('.container-fluid.container-limited')).toHaveLength(1); }); }); diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js index c0af6f6d637..ccbcce61a72 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js @@ -257,7 +257,7 @@ describe('BaseToken', () => { wrapper = createComponent({ props, mountFn: shallowMountExtended, stubs: {} }); expect(findMockSuggestionList().exists()).toBe(true); - expect(getMockSuggestionListSuggestions().length).toEqual(maxSuggestions); + expect(getMockSuggestionListSuggestions()).toHaveLength(maxSuggestions); }); }); diff --git a/spec/frontend/vue_shared/components/groups_list/formatter_spec.js b/spec/frontend/vue_shared/components/groups_list/formatter_spec.js index 308bc1a2220..3bdb01a206c 100644 --- a/spec/frontend/vue_shared/components/groups_list/formatter_spec.js +++ b/spec/frontend/vue_shared/components/groups_list/formatter_spec.js @@ -38,7 +38,7 @@ describe('formatGraphQLGroups', () => { hasChildren: false, customProperty: firstMockGroup.fullName, }); - expect(formattedGroups.length).toBe(organizationGroups.length); + expect(formattedGroups).toHaveLength(organizationGroups.length); }); it('correctly formats the groups without edit, delete, and leave permissions', () => { @@ -57,6 +57,6 @@ describe('formatGraphQLGroups', () => { availableActions: [], }); - expect(formattedGroups.length).toBe(organizationGroups.length); + expect(formattedGroups).toHaveLength(organizationGroups.length); }); }); diff --git a/spec/frontend/vue_shared/components/import/import_history_table.spec.js b/spec/frontend/vue_shared/components/import/import_history_table.spec.js index 39f4f18cd5e..6063c3594bb 100644 --- a/spec/frontend/vue_shared/components/import/import_history_table.spec.js +++ b/spec/frontend/vue_shared/components/import/import_history_table.spec.js @@ -47,43 +47,43 @@ describe('ImportHistoryTableRowStats component', () => { createComponent(); }); it('renders a row for each item and each nested item', () => { - expect(findAllTableRows().length).toBe(totalDataRows); + expect(findAllTableRows()).toHaveLength(totalDataRows); - expect(findAllTopLevelRows().length).toBe(apiItems.length); + expect(findAllTopLevelRows()).toHaveLength(apiItems.length); const itemsWithNestedRows = countItemsAndNested(apiItems, (i) => i.nestedRow); - expect(findAllNestedRows().length).toBe(itemsWithNestedRows); + expect(findAllNestedRows()).toHaveLength(itemsWithNestedRows); }); it('renders correct number of sources', () => { - expect(findAllSources().length).toBe(totalDataRows); + expect(findAllSources()).toHaveLength(totalDataRows); }); it('renders correct number of destinations', () => { - expect(findAllDestinations().length).toBe(totalDataRows); + expect(findAllDestinations()).toHaveLength(totalDataRows); }); it('renders a GlAvatarLabeled for each item where userAvatarProps is defined', () => { const itemsWithAvatarProps = countItemsAndNested(apiItems, (i) => i.userAvatarProps); - expect(findAllGlAvatarLabeled().length).toBe(itemsWithAvatarProps); + expect(findAllGlAvatarLabeled()).toHaveLength(itemsWithAvatarProps); }); it('renders a TimeAgoTooltip for each row', () => { - expect(findAllTimeago().length).toBe(totalDataRows); + expect(findAllTimeago()).toHaveLength(totalDataRows); }); it('renders status icon for each row that has status_name defined', () => { const itemsWithStatus = countItemsAndNested(apiItems, (i) => i.status_name); - expect(findallStatusBadges().length).toBe(itemsWithStatus); + expect(findallStatusBadges()).toHaveLength(itemsWithStatus); }); it('renders stats for all items that have at least 1 stat', () => { const itemsWithStats = countItemsAndNested( apiItems, (i) => i.stats && Object.keys(i.stats).length, ); - expect(findAllStats().length).toBe(itemsWithStats); + expect(findAllStats()).toHaveLength(itemsWithStats); }); it('renders errors for all items that have at least 1 error but no stats', () => { const itemsWithErrors = countItemsAndNested( apiItems, (i) => i.has_failures && !(i.stats && Object.keys(i.stats).length), ); - expect(findAllErrors().length).toBe(itemsWithErrors); + expect(findAllErrors()).toHaveLength(itemsWithErrors); }); }); }); diff --git a/spec/frontend/vue_shared/components/import/import_history_table_row_errors.spec.js b/spec/frontend/vue_shared/components/import/import_history_table_row_errors.spec.js index fdd5b7bfc22..dc63c2f4f8c 100644 --- a/spec/frontend/vue_shared/components/import/import_history_table_row_errors.spec.js +++ b/spec/frontend/vue_shared/components/import/import_history_table_row_errors.spec.js @@ -23,12 +23,12 @@ describe('ImportHistoryTableRowStats component', () => { it('does not render any errors if there are no failures', () => { createComponent({ item: apiItems[0] }); - expect(findErrors().length).toEqual(0); + expect(findErrors()).toHaveLength(0); }); it('renders an error for each failure in the item data', () => { createComponent(); - expect(findErrors().length).toEqual(apiItems[1].failures.length); + expect(findErrors()).toHaveLength(apiItems[1].failures.length); }); describe('alert', () => { @@ -36,10 +36,10 @@ describe('ImportHistoryTableRowStats component', () => { createComponent(); }); it('renders GlAlert', () => { - expect(findAlerts().length).toEqual(apiItems[1].failures.length); + expect(findAlerts()).toHaveLength(apiItems[1].failures.length); }); it('renders GlLink', () => { - expect(findLinks().length).toEqual(apiItems[1].failures.length); + expect(findLinks()).toHaveLength(apiItems[1].failures.length); }); it('uses custom link_text if provided', () => { createComponent({ item: apiItems[3] }); @@ -49,6 +49,6 @@ describe('ImportHistoryTableRowStats component', () => { it('renders raw if it exists', () => { createComponent({ item: apiItems[3] }); - expect(findRaws().length).toEqual(1); + expect(findRaws()).toHaveLength(1); }); }); diff --git a/spec/frontend/vue_shared/components/import/import_history_table_row_stats.spec.js b/spec/frontend/vue_shared/components/import/import_history_table_row_stats.spec.js index 769d4c235e6..844da65686e 100644 --- a/spec/frontend/vue_shared/components/import/import_history_table_row_stats.spec.js +++ b/spec/frontend/vue_shared/components/import/import_history_table_row_stats.spec.js @@ -32,13 +32,13 @@ describe('ImportHistoryTableRowStats component', () => { }); it('renders status icon for each stat', () => { - expect(findStats().length).toEqual(findIcons().length); + expect(findStats()).toHaveLength(findIcons().length); }); it('renders name of stat', () => { - expect(findStats().length).toEqual(findStatNames().length); + expect(findStats()).toHaveLength(findStatNames().length); }); it('renders count of stats remaining', () => { - expect(findStats().length).toEqual(findStatCounts().length); + expect(findStats()).toHaveLength(findStatCounts().length); }); }); describe('errors', () => { diff --git a/spec/frontend/vue_shared/components/import/import_source_list_table.spec.js b/spec/frontend/vue_shared/components/import/import_source_list_table.spec.js index 4e6d0b3ce9d..7019885f28e 100644 --- a/spec/frontend/vue_shared/components/import/import_source_list_table.spec.js +++ b/spec/frontend/vue_shared/components/import/import_source_list_table.spec.js @@ -40,32 +40,32 @@ describe('ImportHistoryTableRowStats component', () => { createComponent(); }); it('renders a row for each item and each nested item', () => { - expect(findAllTableRows().length).toBe(totalDataRows); + expect(findAllTableRows()).toHaveLength(totalDataRows); }); it('renders correct number of sources', () => { - expect(findAllSources().length).toBe(totalDataRows); + expect(findAllSources()).toHaveLength(totalDataRows); }); it('renders destination for rows that have destination_slug defined', () => { const itemsWithDestinations = countItemsAndNested(apiItems, (i) => i.destination_slug); - expect(findAllDestinations().length).toBe(itemsWithDestinations); + expect(findAllDestinations()).toHaveLength(itemsWithDestinations); }); it('renders status icon for each row that has status_name defined', () => { const itemsWithStatus = countItemsAndNested(apiItems, (i) => i.status_name); - expect(findallStatusBadges().length).toBe(itemsWithStatus); + expect(findallStatusBadges()).toHaveLength(itemsWithStatus); }); it('renders stats for all items that have at least 1 stat', () => { const itemsWithStats = countItemsAndNested( apiItems, (i) => i.stats && Object.keys(i.stats).length, ); - expect(findAllStats().length).toBe(itemsWithStats); + expect(findAllStats()).toHaveLength(itemsWithStats); }); it('renders errors for all items that have at least 1 error but no stats', () => { const itemsWithErrors = countItemsAndNested( apiItems, (i) => i.has_failures && !(i.stats && Object.keys(i.stats).length), ); - expect(findAllErrors().length).toBe(itemsWithErrors); + expect(findAllErrors()).toHaveLength(itemsWithErrors); }); }); }); diff --git a/spec/frontend/vue_shared/components/list_selector/api_spec.js b/spec/frontend/vue_shared/components/list_selector/api_spec.js index 5358c6cb5f7..7689aae4aa4 100644 --- a/spec/frontend/vue_shared/components/list_selector/api_spec.js +++ b/spec/frontend/vue_shared/components/list_selector/api_spec.js @@ -126,7 +126,7 @@ describe('List Selector Utils', () => { it('calls axios.get with correct parameters', async () => { await fetchGroupsWithProjectAccess(mockProjectId, mockGroupSearch); - expect(axiosMock.history.get.length).toBe(1); + expect(axiosMock.history.get).toHaveLength(1); expect(axiosMock.history.get[0].params).toStrictEqual({ project_id: mockProjectId, with_project_access: true, diff --git a/spec/frontend/vue_shared/components/list_selector/index_spec.js b/spec/frontend/vue_shared/components/list_selector/index_spec.js index d75aaa6b0a0..bdbb8da6f7c 100644 --- a/spec/frontend/vue_shared/components/list_selector/index_spec.js +++ b/spec/frontend/vue_shared/components/list_selector/index_spec.js @@ -128,7 +128,7 @@ describe('List Selector spec', () => { it('does not call query when search box has not received an input', () => { expect(Api.projectUsers).not.toHaveBeenCalled(); - expect(findAllUserComponents().length).toBe(0); + expect(findAllUserComponents()).toHaveLength(0); }); describe('namespace dropdown rendering', () => { @@ -150,7 +150,7 @@ describe('List Selector spec', () => { }); it('renders a user component for each selected item', () => { - expect(findAllUserComponents().length).toBe(selectedItems.length); + expect(findAllUserComponents()).toHaveLength(selectedItems.length); expect(findAllUserComponents().at(0).props()).toMatchObject({ data: selectedUser, canDelete: true, @@ -180,11 +180,11 @@ describe('List Selector spec', () => { it('does not call query when search box has not received an input', () => { expect(groupsAutocompleteQuerySuccess).not.toHaveBeenCalled(); - expect(findAllGroupComponents().length).toBe(0); + expect(findAllGroupComponents()).toHaveLength(0); }); it('renders two namespace dropdown items', () => { - expect(findNamespaceDropdown().props('items').length).toBe(2); + expect(findNamespaceDropdown().props('items')).toHaveLength(2); }); it('does not render namespace dropdown with disableNamespaceDropdown prop set to true', () => { @@ -231,7 +231,7 @@ describe('List Selector spec', () => { }); it('renders a group component for each search result', () => { - expect(findAllGroupComponents().length).toBe(searchResponse.length); + expect(findAllGroupComponents()).toHaveLength(searchResponse.length); }); it('emits an event when a search result is selected', () => { @@ -329,7 +329,7 @@ describe('List Selector spec', () => { }); it('renders a group component for each search result', () => { - expect(findAllGroupComponents().length).toBe(searchResponse.length); + expect(findAllGroupComponents()).toHaveLength(searchResponse.length); }); it('emits an event when a search result is selected', () => { @@ -353,7 +353,7 @@ describe('List Selector spec', () => { }); it('renders a group component for each selected item', () => { - expect(findAllGroupComponents().length).toBe(selectedItems.length); + expect(findAllGroupComponents()).toHaveLength(selectedItems.length); expect(findAllGroupComponents().at(0).props()).toMatchObject({ data: selectedGroup, canDelete: true, @@ -415,7 +415,7 @@ describe('List Selector spec', () => { }); it('renders a group component for each search result', () => { - expect(findAllDeployKeyComponents().length).toBe(deployKeysItems.length); + expect(findAllDeployKeyComponents()).toHaveLength(deployKeysItems.length); }); it('emits a select event when a search result is selected', () => { @@ -437,7 +437,7 @@ describe('List Selector spec', () => { }); it('renders a deploy key component for each search result', () => { - expect(findAllDeployKeyComponents().length).toBe(deployKeysItems.length); + expect(findAllDeployKeyComponents()).toHaveLength(deployKeysItems.length); }); }); @@ -458,7 +458,7 @@ describe('List Selector spec', () => { }); it('renders a deploy key component for each selected item', () => { - expect(findAllDeployKeyComponents().length).toBe(selectedItems.length); + expect(findAllDeployKeyComponents()).toHaveLength(selectedItems.length); expect(findAllDeployKeyComponents().at(0).props()).toMatchObject({ data: selectedKey, canDelete: true, @@ -510,7 +510,7 @@ describe('List Selector spec', () => { }); it('renders a project component for each search result', () => { - expect(findAllProjectComponents().length).toBe(searchResponse.length); + expect(findAllProjectComponents()).toHaveLength(searchResponse.length); }); }); @@ -525,7 +525,7 @@ describe('List Selector spec', () => { }); it('renders a group component for each selected item', () => { - expect(findAllGroupComponents().length).toBe(selectedItems.length); + expect(findAllGroupComponents()).toHaveLength(selectedItems.length); expect(findAllGroupComponents().at(0).props()).toMatchObject({ data: selectedGroup, canDelete: true, diff --git a/spec/frontend/vue_shared/components/markdown/header_spec.js b/spec/frontend/vue_shared/components/markdown/header_spec.js index 0fc31501c0a..b71a53969dd 100644 --- a/spec/frontend/vue_shared/components/markdown/header_spec.js +++ b/spec/frontend/vue_shared/components/markdown/header_spec.js @@ -147,19 +147,19 @@ describe('Markdown field header component', () => { it('hides divider in preview mode', () => { createWrapper({ props: { previewMarkdown: true } }); - expect(findDividers().length).toBe(0); + expect(findDividers()).toHaveLength(0); }); it('emits toggle markdown event when clicking preview toggle', async () => { findPreviewToggle().vm.$emit('click', true); await nextTick(); - expect(wrapper.emitted('showPreview').length).toEqual(1); + expect(wrapper.emitted('showPreview')).toHaveLength(1); findPreviewToggle().vm.$emit('click', false); await nextTick(); - expect(wrapper.emitted('showPreview').length).toEqual(2); + expect(wrapper.emitted('showPreview')).toHaveLength(2); }); it('does not emit toggle markdown event when triggered from another form', () => { @@ -259,11 +259,11 @@ describe('Markdown field header component', () => { }, }); - expect(findToolbarButtons().length).toBe(defaultCount - 1); + expect(findToolbarButtons()).toHaveLength(defaultCount - 1); }); it('shows all items by default', () => { - expect(findToolbarButtons().length).toBe(defaultCount); + expect(findToolbarButtons()).toHaveLength(defaultCount); }); it("doesn't render dividers when toolbar buttons past them are restricted", () => { @@ -286,7 +286,7 @@ describe('Markdown field header component', () => { ], }, }); - expect(findDividers().length).toBe(1); + expect(findDividers()).toHaveLength(1); }); }); @@ -494,7 +494,7 @@ describe('Markdown field header component', () => { await findFindInput().vm.$emit('keyup', { target: { value: 'lorem' } }); await nextTick(); - expect(findCloneDiv().element.querySelectorAll('.js-highlight-active').length).toBe(1); + expect(findCloneDiv().element.querySelectorAll('.js-highlight-active')).toHaveLength(1); }); it('allows navigating between matches through next and prev buttons', async () => { @@ -506,7 +506,7 @@ describe('Markdown field header component', () => { const matches = findCloneDiv().element.querySelectorAll('.js-highlight'); - expect(matches.length).toBe(2); + expect(matches).toHaveLength(2); expect(Array.from(matches[0].classList)).toEqual(['js-highlight', 'js-highlight-active']); expect(Array.from(matches[1].classList)).toEqual(['js-highlight']); @@ -545,7 +545,7 @@ describe('Markdown field header component', () => { await nextTick(); const matches = findCloneDiv().element.querySelectorAll('.js-highlight'); - expect(matches.length).toBe(2); + expect(matches).toHaveLength(2); }); it('should have a close button', async () => { diff --git a/spec/frontend/vue_shared/components/metric_images/metric_images_tab_spec.js b/spec/frontend/vue_shared/components/metric_images/metric_images_tab_spec.js index f128a5f3b80..78c89bf51ea 100644 --- a/spec/frontend/vue_shared/components/metric_images/metric_images_tab_spec.js +++ b/spec/frontend/vue_shared/components/metric_images/metric_images_tab_spec.js @@ -77,7 +77,7 @@ describe('Metric images tab', () => { await waitForPromises(); - expect(findImages().length).toBe(1); + expect(findImages()).toHaveLength(1); }); }); diff --git a/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js b/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js index f99034111c2..28b0f17ea2b 100644 --- a/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js +++ b/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js @@ -36,7 +36,7 @@ describe('ProjectSelector component', () => { }); it('renders the search results', () => { - expect(wrapper.findAll('.js-project-list-item').length).toBe(5); + expect(wrapper.findAll('.js-project-list-item')).toHaveLength(5); }); it(`triggers a search when the search input value changes`, () => { diff --git a/spec/frontend/vue_shared/components/projects_list/formatter_spec.js b/spec/frontend/vue_shared/components/projects_list/formatter_spec.js index 078435b83a2..c01158899df 100644 --- a/spec/frontend/vue_shared/components/projects_list/formatter_spec.js +++ b/spec/frontend/vue_shared/components/projects_list/formatter_spec.js @@ -40,6 +40,6 @@ describe('formatGraphQLProjects', () => { isPersonal: false, }); - expect(formattedProjects.length).toBe(projects.length); + expect(formattedProjects).toHaveLength(projects.length); }); }); diff --git a/spec/frontend/vue_shared/components/registry/persisted_radio_group_spec.js b/spec/frontend/vue_shared/components/registry/persisted_radio_group_spec.js index cf7b468d275..9fc7ce6c162 100644 --- a/spec/frontend/vue_shared/components/registry/persisted_radio_group_spec.js +++ b/spec/frontend/vue_shared/components/registry/persisted_radio_group_spec.js @@ -75,7 +75,7 @@ describe('Persisted radio group', () => { it('has one item for each option', () => { createComponent(); - expect(findGlFormRadios().length).toEqual(defaultProps.options.length); + expect(findGlFormRadios()).toHaveLength(defaultProps.options.length); }); it('on click updates the data and emits event', async () => { diff --git a/spec/frontend/vue_shared/components/resizable_chart/skeleton_loader_spec.js b/spec/frontend/vue_shared/components/resizable_chart/skeleton_loader_spec.js index 043552baf0c..3183cc00955 100644 --- a/spec/frontend/vue_shared/components/resizable_chart/skeleton_loader_spec.js +++ b/spec/frontend/vue_shared/components/resizable_chart/skeleton_loader_spec.js @@ -14,9 +14,9 @@ describe('Resizable Skeleton Loader', () => { const gridItems = wrapper.findAll('[data-testid="skeleton-chart-grid"]').wrappers; const barItems = wrapper.findAll('[data-testid="skeleton-chart-bar"]').wrappers; const labelItems = wrapper.findAll('[data-testid="skeleton-chart-label"]').wrappers; - expect(gridItems.length).toBe(3); - expect(barItems.length).toBe(8); - expect(labelItems.length).toBe(8); + expect(gridItems).toHaveLength(3); + expect(barItems).toHaveLength(8); + expect(labelItems).toHaveLength(8); }; describe('default setup', () => { diff --git a/spec/frontend/vue_shared/components/smart_virtual_list_spec.js b/spec/frontend/vue_shared/components/smart_virtual_list_spec.js index e79b89c2259..703e7e12d2d 100644 --- a/spec/frontend/vue_shared/components/smart_virtual_list_spec.js +++ b/spec/frontend/vue_shared/components/smart_virtual_list_spec.js @@ -81,7 +81,7 @@ describe('Smart Virtual List', () => { }); it('renders all children list elements', () => { - expect(wrapper.findAll('li').length).toEqual(listLength); + expect(wrapper.findAll('li')).toHaveLength(listLength); }); }); diff --git a/spec/frontend/vue_shared/components/source_viewer/components/blame_info_spec.js b/spec/frontend/vue_shared/components/source_viewer/components/blame_info_spec.js index 121bc691041..d7d80e6c017 100644 --- a/spec/frontend/vue_shared/components/source_viewer/components/blame_info_spec.js +++ b/spec/frontend/vue_shared/components/source_viewer/components/blame_info_spec.js @@ -19,7 +19,7 @@ describe('BlameInfo component', () => { const findCommitInfoComponents = () => wrapper.findAllComponents(CommitInfo); it('renders a CommitInfo component for each blame entry', () => { - expect(findCommitInfoComponents().length).toBe(BLAME_DATA_MOCK.length); + expect(findCommitInfoComponents()).toHaveLength(BLAME_DATA_MOCK.length); }); it.each(BLAME_DATA_MOCK)( diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js index 32f9df8a63c..1b21ff3038f 100644 --- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js +++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js @@ -129,7 +129,7 @@ describe('UserAvatarList', () => { const links = wrapper.findAllComponents(UserAvatarLink); - expect(links.length).toEqual(props.items.length); + expect(links).toHaveLength(props.items.length); }); it('does not show button', () => { @@ -150,7 +150,7 @@ describe('UserAvatarList', () => { const links = wrapper.findAllComponents(UserAvatarLink); - expect(links.length).toEqual(TEST_BREAKPOINT); + expect(links).toHaveLength(TEST_BREAKPOINT); }); it('does not emit any event on mount', async () => { @@ -169,7 +169,7 @@ describe('UserAvatarList', () => { it('renders all avatars', () => { const links = wrapper.findAllComponents(UserAvatarLink); - expect(links.length).toEqual(props.items.length); + expect(links).toHaveLength(props.items.length); }); it('emits the `expanded` event', () => { @@ -185,7 +185,7 @@ describe('UserAvatarList', () => { await nextTick(); const links = wrapper.findAllComponents(UserAvatarLink); - expect(links.length).toEqual(TEST_BREAKPOINT); + expect(links).toHaveLength(TEST_BREAKPOINT); }); it('emits the `collapsed` event', () => { diff --git a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js index 3a1318d30db..b2450a4a4eb 100644 --- a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js +++ b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js @@ -191,8 +191,8 @@ describe('User Popover Component', () => { createWrapper({ user }); expect( - wrapper.findAllComponents(GlIcon).filter((icon) => icon.props('name') === 'profile').length, - ).toEqual(1); + wrapper.findAllComponents(GlIcon).filter((icon) => icon.props('name') === 'profile'), + ).toHaveLength(1); }); it('shows icon for work information', () => { @@ -204,8 +204,8 @@ describe('User Popover Component', () => { createWrapper({ user }); expect( - wrapper.findAllComponents(GlIcon).filter((icon) => icon.props('name') === 'work').length, - ).toEqual(1); + wrapper.findAllComponents(GlIcon).filter((icon) => icon.props('name') === 'work'), + ).toHaveLength(1); }); }); @@ -384,7 +384,7 @@ describe('User Popover Component', () => { await axios.waitForAll(); - expect(wrapper.emitted().follow.length).toBe(1); + expect(wrapper.emitted().follow).toHaveLength(1); expect(wrapper.emitted().unfollow).toBeUndefined(); }); @@ -456,7 +456,7 @@ describe('User Popover Component', () => { await axios.waitForAll(); expect(wrapper.emitted().follow).toBe(undefined); - expect(wrapper.emitted().unfollow.length).toBe(1); + expect(wrapper.emitted().unfollow).toHaveLength(1); }); itTracksToggleFollowButtonClick('unfollow_from_user_popover'); diff --git a/spec/frontend/vue_shared/translate_spec.js b/spec/frontend/vue_shared/translate_spec.js index e2a38991b22..b6a5c06f6c5 100644 --- a/spec/frontend/vue_shared/translate_spec.js +++ b/spec/frontend/vue_shared/translate_spec.js @@ -44,7 +44,7 @@ describe('Vue translate filter', () => { const { wrappers } = wrapper.findAll('span'); // Just to ensure that the rendering actually worked; - expect(wrappers.length).toBe(10); + expect(wrappers).toHaveLength(10); for (const span of wrappers) { expect(span.text().trim()).toBe(span.attributes()['data-expected']); diff --git a/spec/frontend/wikis/notes/components/wiki_notes_app_spec.js b/spec/frontend/wikis/notes/components/wiki_notes_app_spec.js index 8a6ca447d0c..663de3c7035 100644 --- a/spec/frontend/wikis/notes/components/wiki_notes_app_spec.js +++ b/spec/frontend/wikis/notes/components/wiki_notes_app_spec.js @@ -135,7 +135,7 @@ describe('WikiNotesApp', () => { createWrapper(); const skeletonNotes = wrapper.findAllComponents(SkeletonNote); - expect(skeletonNotes.length).toBe(5); + expect(skeletonNotes).toHaveLength(5); }); it('should render Comment Form correctly', () => { @@ -180,12 +180,12 @@ describe('WikiNotesApp', () => { it('should not render any discussions', () => { const wikiDiscussions = wrapper.findAllComponents(WikiDiscussion); - expect(wikiDiscussions.length).toBe(0); + expect(wikiDiscussions).toHaveLength(0); }); it('should not render any skeleton notes', () => { const skeletonNotes = wrapper.findAllComponents(SkeletonNote); - expect(skeletonNotes.length).toBe(0); + expect(skeletonNotes).toHaveLength(0); }); it('should attempt to fetch Discussions when retry button is clicked', async () => { @@ -222,7 +222,7 @@ describe('WikiNotesApp', () => { it('should render discussions correctly', () => { const wikiDiscussions = wrapper.findAllComponents(WikiDiscussion); - expect(wikiDiscussions.length).toBe(3); + expect(wikiDiscussions).toHaveLength(3); expect(wikiDiscussions.at(0).props('noteableId')).toEqual('gid://gitlab/WikiPage/1'); expect(wikiDiscussions.at(1).props('noteableId')).toEqual('gid://gitlab/WikiPage/1'); expect(wikiDiscussions.at(2).props('noteableId')).toEqual('gid://gitlab/WikiPage/1'); diff --git a/spec/frontend/work_items/components/create_work_item_cancel_confirmation_modal_spec.js b/spec/frontend/work_items/components/create_work_item_cancel_confirmation_modal_spec.js index 511903a0b08..89f8f8b5e31 100644 --- a/spec/frontend/work_items/components/create_work_item_cancel_confirmation_modal_spec.js +++ b/spec/frontend/work_items/components/create_work_item_cancel_confirmation_modal_spec.js @@ -66,7 +66,7 @@ describe('CreateWorkItemCancelConfirmationModal', () => { findContinueEditingButton().vm.$emit('click'); - expect(wrapper.emitted('continueEditing').length).toBe(1); + expect(wrapper.emitted('continueEditing')).toHaveLength(1); }); it('emits proper event when "Discard changes" button is clicked', async () => { @@ -74,7 +74,7 @@ describe('CreateWorkItemCancelConfirmationModal', () => { await findDiscardButton().vm.$emit('click'); - expect(wrapper.emitted('discardDraft').length).toBe(1); + expect(wrapper.emitted('discardDraft')).toHaveLength(1); }); }); }); diff --git a/spec/frontend/work_items/components/design_management/design_management_widget_spec.js b/spec/frontend/work_items/components/design_management/design_management_widget_spec.js index e54a77326af..6e169a52670 100644 --- a/spec/frontend/work_items/components/design_management/design_management_widget_spec.js +++ b/spec/frontend/work_items/components/design_management/design_management_widget_spec.js @@ -290,15 +290,15 @@ describe('DesignWidget', () => { await waitForPromises(); expect(queryHandler).toHaveBeenCalled(); - expect(findAllDesignItems().length).toBe(length); - expect(findDesignCheckboxes().length).toBe(length); + expect(findAllDesignItems()).toHaveLength(length); + expect(findDesignCheckboxes()).toHaveLength(length); }); it('renders text if all designs are archived', async () => { createComponent({ designCollectionQueryHandler: allDesignsArchivedQueryHandler }); await waitForPromises(); - expect(findAllDesignItems().length).toBe(0); + expect(findAllDesignItems()).toHaveLength(0); expect(wrapper.text()).toContain(ALL_DESIGNS_ARCHIVED_TEXT); }); @@ -349,7 +349,7 @@ describe('DesignWidget', () => { }); it('does not render the design checkboxes', () => { - expect(wrapper.findAllByTestId('design-checkbox').length).toBe(0); + expect(wrapper.findAllByTestId('design-checkbox')).toHaveLength(0); }); }); @@ -540,7 +540,7 @@ describe('DesignWidget', () => { document.dispatchEvent(event); - expect(wrapper.emitted('upload').length).toBe(3); + expect(wrapper.emitted('upload')).toHaveLength(3); expect(wrapper.emitted('upload')[0][0][0].name).toBe('image_2025-05-01_18_18_19.png'); expect(wrapper.emitted('upload')[1][0][0].name).toBe('image_2025-05-01_18_18_19_1.png'); expect(wrapper.emitted('upload')[2][0][0].name).toBe('image_2025-05-01_18_18_19_2.png'); diff --git a/spec/frontend/work_items/components/work_item_ancestors/disclosure_hierarchy_spec.js b/spec/frontend/work_items/components/work_item_ancestors/disclosure_hierarchy_spec.js index f70fe16572a..95036eac1a0 100644 --- a/spec/frontend/work_items/components/work_item_ancestors/disclosure_hierarchy_spec.js +++ b/spec/frontend/work_items/components/work_item_ancestors/disclosure_hierarchy_spec.js @@ -34,7 +34,7 @@ describe('DisclosurePath', () => { describe('renders the list of items', () => { it('renders the correct number of items', () => { - expect(listItems().length).toBe(mockDisclosureHierarchyItems.length); + expect(listItems()).toHaveLength(mockDisclosureHierarchyItems.length); }); it('renders the items in the correct order', () => { @@ -81,7 +81,7 @@ describe('DisclosurePath', () => { describe('renders items and dropdown', () => { it('renders 2 items', () => { - expect(listItems().length).toBe(2); + expect(listItems()).toHaveLength(2); }); it('renders first and last items', () => { @@ -93,7 +93,7 @@ describe('DisclosurePath', () => { it('renders dropdown with the rest of the items passed down', () => { expect(findDropdown().exists()).toBe(true); - expect(findDropdown().props('items').length).toBe(mockDisclosureHierarchyItems.length - 2); + expect(findDropdown().props('items')).toHaveLength(mockDisclosureHierarchyItems.length - 2); }); it('renders tooltip with text passed as prop', () => { @@ -117,7 +117,7 @@ describe('DisclosurePath', () => { }); it('renders 1 item', () => { - expect(listItems().length).toBe(1); + expect(listItems()).toHaveLength(1); }); it('renders last item', () => { @@ -128,7 +128,7 @@ describe('DisclosurePath', () => { it('renders dropdown with the rest of the items passed down', () => { expect(findDropdown().exists()).toBe(true); - expect(findDropdown().props('items').length).toBe(mockDisclosureHierarchyItems.length - 1); + expect(findDropdown().props('items')).toHaveLength(mockDisclosureHierarchyItems.length - 1); }); describe('when there is one item', () => { @@ -147,7 +147,7 @@ describe('DisclosurePath', () => { }); it('renders 1 item', () => { - expect(listItems().length).toBe(1); + expect(listItems()).toHaveLength(1); }); it('does not render dropdown', () => { diff --git a/spec/frontend/work_items/components/work_item_development/work_item_development_relationship_list_spec.js b/spec/frontend/work_items/components/work_item_development/work_item_development_relationship_list_spec.js index 39b97149b92..99b5ec3bab7 100644 --- a/spec/frontend/work_items/components/work_item_development/work_item_development_relationship_list_spec.js +++ b/spec/frontend/work_items/components/work_item_development/work_item_development_relationship_list_spec.js @@ -64,7 +64,7 @@ describe('WorkItemDevelopmentRelationshipList', () => { }), }); - expect(findAllMergeRequests().length).toBe(3); + expect(findAllMergeRequests()).toHaveLength(3); expect(findAllMergeRequests().at(0).props('itemContent')).toEqual( expect.objectContaining({ diff --git a/spec/frontend/work_items/components/work_item_links/work_item_children_wrapper_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_children_wrapper_spec.js index c6f945ff694..4435d6b1d83 100644 --- a/spec/frontend/work_items/components/work_item_links/work_item_children_wrapper_spec.js +++ b/spec/frontend/work_items/components/work_item_links/work_item_children_wrapper_spec.js @@ -208,7 +208,7 @@ describe('WorkItemChildrenWrapper', () => { expect(document.body.classList.contains('is-dragging')).toBe(true); wrapper.findComponent(Draggable).vm.$emit('end', dragParams); - expect(wrapper.emitted('drop').length).toBe(1); + expect(wrapper.emitted('drop')).toHaveLength(1); await nextTick(); expect(document.body.classList.contains('is-dragging')).toBe(false); diff --git a/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js index 545b068e589..beb321ee85d 100644 --- a/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js +++ b/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js @@ -333,7 +333,7 @@ describe('WorkItemLinkChild', () => { expect(wrapper.emitted('drag')).toEqual([['Task']]); findTreeChildren().vm.$emit('drop'); - expect(wrapper.emitted('drop').length).toBe(1); + expect(wrapper.emitted('drop')).toHaveLength(1); }); it.each` diff --git a/spec/frontend/work_items/components/work_item_links/work_item_rolled_up_count_info_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_rolled_up_count_info_spec.js index c7166d7d4ba..2f1a689d40d 100644 --- a/spec/frontend/work_items/components/work_item_links/work_item_rolled_up_count_info_spec.js +++ b/spec/frontend/work_items/components/work_item_links/work_item_rolled_up_count_info_spec.js @@ -31,6 +31,6 @@ describe('Work item rolled up count info', () => { it('renders the correct number of counts', () => { createComponent(); - expect(findCountInfo().length).toBe(mockRolledUpCountsByType.length); + expect(findCountInfo()).toHaveLength(mockRolledUpCountsByType.length); }); }); diff --git a/spec/frontend/work_items/components/work_item_notes_spec.js b/spec/frontend/work_items/components/work_item_notes_spec.js index 8cb2c750457..89b7858fe63 100644 --- a/spec/frontend/work_items/components/work_item_notes_spec.js +++ b/spec/frontend/work_items/components/work_item_notes_spec.js @@ -234,7 +234,7 @@ describe('WorkItemNotes component', () => { // Preview note should not be rendered when modal is open const discussions = wrapper.findAllComponents(WorkItemDiscussion); - expect(discussions.length).toBe(0); + expect(discussions).toHaveLength(0); // Should still show loading state expect(findNotesLoading().exists()).toBe(true); @@ -259,7 +259,7 @@ describe('WorkItemNotes component', () => { // Preview note should not be rendered when modal is open const discussions = wrapper.findAllComponents(WorkItemDiscussion); - expect(discussions.length).toBe(0); + expect(discussions).toHaveLength(0); // Should still show loading state expect(findNotesLoading().exists()).toBe(true); diff --git a/spec/frontend/work_items/components/work_item_relationships/work_item_relationships_spec.js b/spec/frontend/work_items/components/work_item_relationships/work_item_relationships_spec.js index d0074f4932a..f2ebecedb24 100644 --- a/spec/frontend/work_items/components/work_item_relationships/work_item_relationships_spec.js +++ b/spec/frontend/work_items/components/work_item_relationships/work_item_relationships_spec.js @@ -152,7 +152,7 @@ describe('WorkItemRelationships', () => { await waitForPromises(); // renders all 3 lists: blocking, blocked by and related to - expect(findAllWorkItemRelationshipListComponents().length).toBe(3); + expect(findAllWorkItemRelationshipListComponents()).toHaveLength(3); expect(findLinkedItemsCountBadge().text()).toBe('3'); }); diff --git a/spec/frontend/work_items/components/work_item_state_toggle_spec.js b/spec/frontend/work_items/components/work_item_state_toggle_spec.js index 6d3e24c3dba..35afd44f478 100644 --- a/spec/frontend/work_items/components/work_item_state_toggle_spec.js +++ b/spec/frontend/work_items/components/work_item_state_toggle_spec.js @@ -265,7 +265,7 @@ describe('Work Item State toggle button component', () => { }); await waitForPromises(); - expect(findBlockedByModal().findAllComponents(GlLink).length).toEqual( + expect(findBlockedByModal().findAllComponents(GlLink)).toHaveLength( blockersWithClosed.length - 1, ); }); diff --git a/spec/rubocop/cop/migration/prevent_index_creation_spec.rb b/spec/rubocop/cop/migration/prevent_index_creation_spec.rb index 209b1103189..39ff28f9a5a 100644 --- a/spec/rubocop/cop/migration/prevent_index_creation_spec.rb +++ b/spec/rubocop/cop/migration/prevent_index_creation_spec.rb @@ -157,9 +157,10 @@ RSpec.describe RuboCop::Cop::Migration::PreventIndexCreation, feature_category: it "registers an offense when prepare_partitioned_async_index is used", :aggregate_failures do expect_offense(<<~RUBY) TABLE_NAME = :p_ci_builds + COLUMNS = [:project_id, :name, :ref, :id] - def change - prepare_partitioned_async_index TABLE_NAME, :protected + def up + prepare_partitioned_async_index(TABLE_NAME, COLUMNS, order: { id: :desc }) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{offense} end RUBY