From 997c23502eb487725d8323b36e4656c66fcaf91c Mon Sep 17 00:00:00 2001
From: Michael Kriese <michael.kriese@visualon.de>
Date: Wed, 26 Feb 2025 10:35:54 +0100
Subject: [PATCH] test: migrate to vitest (#34475)

Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
---
 .devcontainer/devcontainer.json               |    2 +-
 .github/contributing.md                       |   10 +-
 .github/label-actions.yml                     |    4 +-
 .github/workflows/build.yml                   |   17 +-
 .ls-lint.yml                                  |    2 +-
 .vscode/extensions.json                       |    2 +-
 .vscode/launch.json                           |   82 +-
 .vscode/settings.json                         |    5 +-
 docs/development/best-practices.md            |   14 +-
 docs/development/issue-labeling.md            |    2 +-
 docs/development/local-development.md         |   12 +-
 eslint.config.mjs                             |   33 +-
 jest.config.ts                                |  147 --
 lib/config/__snapshots__/index.spec.ts.snap   |    6 +-
 .../migrate-validate.spec.ts.snap             |    6 +-
 .../__snapshots__/migration.spec.ts.snap      |  170 +-
 .../__snapshots__/validation.spec.ts.snap     |   44 +-
 lib/config/index.spec.ts                      |    4 +-
 lib/config/migration.spec.ts                  |   18 +-
 .../custom/extends-migration.spec.ts          |    6 +-
 .../custom/go-mod-tidy-migration.spec.ts      |    2 +-
 lib/config/options/index.spec.ts              |    2 +-
 .../presets/__snapshots__/index.spec.ts.snap  |   20 +-
 lib/config/presets/gitea/index.spec.ts        |    2 +-
 lib/config/presets/github/index.spec.ts       |    2 +-
 lib/config/presets/index.spec.ts              |    8 +-
 lib/config/presets/internal/index.spec.ts     |    4 +-
 lib/config/presets/local/index.spec.ts        |    6 +-
 lib/config/presets/util.spec.ts               |    2 +
 lib/constants/platform.spec.ts                |    8 +-
 lib/instrumentation/reporting.spec.ts         |   11 +-
 .../config-serializer.spec.ts.snap            |    6 +-
 .../__snapshots__/err-serializer.spec.ts.snap |    4 +-
 lib/logger/index.spec.ts                      |    4 +-
 lib/logger/once.spec.ts                       |    2 +-
 lib/logger/pretty-stdout.spec.ts              |    6 +-
 .../__snapshots__/metadata.spec.ts.snap       |   18 +-
 .../__snapshots__/index.spec.ts.snap          |    8 +-
 .../__snapshots__/index.spec.ts.snap          |    8 +-
 .../__snapshots__/index.spec.ts.snap          |    8 +-
 .../cdnjs/__snapshots__/index.spec.ts.snap    |    4 +-
 .../clojure/__snapshots__/index.spec.ts.snap  |   12 +-
 lib/modules/datasource/conan/index.spec.ts    |    2 +-
 .../conda/__snapshots__/index.spec.ts.snap    |    4 +-
 .../crate/__snapshots__/index.spec.ts.snap    |   10 +-
 lib/modules/datasource/crate/index.spec.ts    |   31 +-
 lib/modules/datasource/custom/index.spec.ts   |    2 +-
 .../dart/__snapshots__/index.spec.ts.snap     |    4 +-
 lib/modules/datasource/docker/common.spec.ts  |    2 +-
 .../datasource/docker/dockerhub-cache.spec.ts |    2 +-
 lib/modules/datasource/docker/index.spec.ts   |    6 +-
 .../__snapshots__/index.spec.ts.snap          |    4 +-
 .../__snapshots__/index.spec.ts.snap          |    6 +-
 .../galaxy-collection/index.spec.ts           |    2 +-
 .../galaxy/__snapshots__/index.spec.ts.snap   |    4 +-
 .../git-refs/__snapshots__/index.spec.ts.snap |    4 +-
 lib/modules/datasource/git-refs/index.spec.ts |   18 +-
 .../git-tags/__snapshots__/index.spec.ts.snap |    4 +-
 lib/modules/datasource/git-tags/index.spec.ts |   18 +-
 .../github-release-attachments/index.spec.ts  |    2 +-
 .../datasource/github-releases/index.spec.ts  |    2 +-
 .../__snapshots__/index.spec.ts.snap          |    4 +-
 .../__snapshots__/index.spec.ts.snap          |    6 +-
 .../__snapshots__/index.spec.ts.snap          |    8 +-
 .../releases-direct.spec.ts.snap              |   12 +-
 lib/modules/datasource/go/base.spec.ts        |    5 +-
 lib/modules/datasource/go/index.spec.ts       |    6 +-
 .../datasource/go/releases-direct.spec.ts     |    4 +-
 .../datasource/go/releases-goproxy.spec.ts    |   10 +-
 .../__snapshots__/index.spec.ts.snap          |    4 +-
 .../datasource/golang-version/index.spec.ts   |    2 +-
 .../__snapshots__/index.spec.ts.snap          |    6 +-
 .../helm/__snapshots__/index.spec.ts.snap     |    4 +-
 .../hex/__snapshots__/index.spec.ts.snap      |    8 +-
 lib/modules/datasource/hex/index.spec.ts      |    2 +-
 lib/modules/datasource/index.spec.ts          |   10 +-
 .../__snapshots__/index.spec.ts.snap          |    8 +-
 .../maven/__snapshots__/index.spec.ts.snap    |   16 +-
 lib/modules/datasource/maven/index.spec.ts    |    2 +-
 .../__snapshots__/index.spec.ts.snap          |    4 +-
 .../npm/__snapshots__/index.spec.ts.snap      |   30 +-
 lib/modules/datasource/npm/get.spec.ts        |    2 +-
 lib/modules/datasource/npm/npmrc.spec.ts      |    2 +-
 .../nuget/__snapshots__/index.spec.ts.snap    |   22 +-
 lib/modules/datasource/nuget/common.spec.ts   |   12 +-
 lib/modules/datasource/nuget/index.spec.ts    |    4 +-
 .../orb/__snapshots__/index.spec.ts.snap      |    6 +-
 .../__snapshots__/index.spec.ts.snap          |   18 +-
 .../datasource/packagist/index.spec.ts        |    6 +-
 .../datasource/postprocess-release.spec.ts    |    2 +-
 .../pypi/__snapshots__/index.spec.ts.snap     |   16 +-
 lib/modules/datasource/pypi/index.spec.ts     |    2 +-
 lib/modules/datasource/readme.md              |    2 +-
 .../repology/__snapshots__/index.spec.ts.snap |   14 +-
 .../__snapshots__/index.spec.ts.snap          |    4 +-
 .../rubygems/metadata-cache.spec.ts           |    2 +-
 .../rubygems/versions-endpoint-cache.spec.ts  |   12 +-
 .../__snapshots__/index.spec.ts.snap          |    6 +-
 .../datasource/sbt-package/index.spec.ts      |    2 +-
 .../__snapshots__/index.spec.ts.snap          |    6 +-
 lib/modules/datasource/utils.spec.ts          |    2 +-
 .../__snapshots__/extract.spec.ts.snap        |   12 +-
 .../__snapshots__/extract.spec.ts.snap        |    6 +-
 .../manager/bazel-module/bazelrc.spec.ts      |    6 +-
 .../bazel-module/parser/context.spec.ts       |    2 +-
 .../bazel/__snapshots__/extract.spec.ts.snap  |    6 +-
 .../__snapshots__/extract.spec.ts.snap        |   12 +-
 lib/modules/manager/bun/artifacts.spec.ts     |    4 +-
 lib/modules/manager/bun/extract.spec.ts       |    6 +-
 .../__snapshots__/extract.spec.ts.snap        |   18 +-
 .../__snapshots__/gemfile.spec.ts.snap        |    4 +-
 .../__snapshots__/locked-version.spec.ts.snap |   12 +-
 lib/modules/manager/bundler/artifacts.spec.ts |   12 +-
 lib/modules/manager/bundler/common.spec.ts    |    2 +-
 lib/modules/manager/bundler/extract.spec.ts   |    2 +-
 .../__snapshots__/artifacts.spec.ts.snap      |   12 +-
 .../cargo/__snapshots__/extract.spec.ts.snap  |   24 +-
 lib/modules/manager/cargo/artifacts.spec.ts   |   10 +-
 lib/modules/manager/cargo/extract.spec.ts     |    2 +-
 .../manager/cargo/locked-version.spec.ts      |    2 +-
 .../cdnurl/__snapshots__/extract.spec.ts.snap |    4 +-
 .../__snapshots__/extract.spec.ts.snap        |    4 +-
 .../__snapshots__/artifacts.spec.ts.snap      |   18 +-
 .../manager/cocoapods/artifacts.spec.ts       |    8 +-
 .../__snapshots__/extract.spec.ts.snap        |    6 +-
 .../manager/composer/artifacts.spec.ts        |    8 +-
 lib/modules/manager/composer/extract.spec.ts  |    2 +-
 lib/modules/manager/composer/utils.spec.ts    |    2 +-
 lib/modules/manager/copier/artifacts.spec.ts  |    6 +-
 lib/modules/manager/cpanfile/extract.spec.ts  |    2 +-
 .../regex/__snapshots__/index.spec.ts.snap    |   34 +-
 .../manager/custom/regex/index.spec.ts        |    2 +-
 .../__snapshots__/parser.spec.ts.snap         |    4 +-
 lib/modules/manager/devbox/artifacts.spec.ts  |    6 +-
 .../__snapshots__/extract.spec.ts.snap        |    8 +-
 .../__snapshots__/extract.spec.ts.snap        |    4 +-
 lib/modules/manager/flux/artifacts.spec.ts    |    2 +-
 .../manager/git-submodules/extract.spec.ts    |   19 +-
 .../manager/git-submodules/update.spec.ts     |   10 +-
 .../__snapshots__/extract.spec.ts.snap        |    6 +-
 .../__snapshots__/extract.spec.ts.snap        |    6 +-
 .../__snapshots__/extract.spec.ts.snap        |   12 +-
 lib/modules/manager/glasskube/extract.spec.ts |    2 +-
 lib/modules/manager/gleam/artifacts.spec.ts   |    4 +-
 lib/modules/manager/gleam/extract.spec.ts     |    2 +-
 .../manager/gleam/locked-version.spec.ts      |    2 +-
 .../gomod/__snapshots__/extract.spec.ts.snap  |    6 +-
 .../gomod/__snapshots__/update.spec.ts.snap   |    8 +-
 lib/modules/manager/gomod/artifacts.spec.ts   |   24 +-
 .../manager/gradle-wrapper/artifacts.spec.ts  |   10 +-
 .../manager/gradle-wrapper/util.spec.ts       |    2 +-
 lib/modules/manager/gradle/artifacts.spec.ts  |   11 +-
 lib/modules/manager/gradle/extract.spec.ts    |   21 +-
 lib/modules/manager/gradle/parser.spec.ts     |    2 +-
 .../__snapshots__/extract.spec.ts.snap        |   12 +-
 .../manager/helm-requirements/extract.spec.ts |    2 +-
 .../__snapshots__/extract.spec.ts.snap        |    6 +-
 .../__snapshots__/extract.spec.ts.snap        |   14 +-
 .../manager/helmfile/artifacts.spec.ts        |   10 +-
 lib/modules/manager/helmfile/extract.spec.ts  |    2 +-
 .../__snapshots__/extract.spec.ts.snap        |    4 +-
 .../__snapshots__/artifacts.spec.ts.snap      |   22 +-
 .../helmv3/__snapshots__/extract.spec.ts.snap |   12 +-
 lib/modules/manager/helmv3/artifacts.spec.ts  |   10 +-
 lib/modules/manager/helmv3/extract.spec.ts    |    2 +-
 lib/modules/manager/hermit/artifacts.spec.ts  |    4 +-
 lib/modules/manager/hermit/extract.spec.ts    |    2 +-
 .../__snapshots__/extract.spec.ts.snap        |   26 +-
 .../__snapshots__/update.spec.ts.snap         |   10 +-
 .../html/__snapshots__/extract.spec.ts.snap   |    4 +-
 lib/modules/manager/index.spec.ts             |    8 +-
 .../__snapshots__/extract.spec.ts.snap        |    6 +-
 .../__snapshots__/artifacts.spec.ts.snap      |   10 +-
 .../__snapshots__/extract.spec.ts.snap        |    6 +-
 .../manager/jsonnet-bundler/artifacts.spec.ts |    6 +-
 .../__snapshots__/extract.spec.ts.snap        |   24 +-
 .../__snapshots__/extract.spec.ts.snap        |    4 +-
 .../manager/maven-wrapper/artifacts.spec.ts   |    8 +-
 .../manager/maven-wrapper/extract.spec.ts     |    2 +-
 lib/modules/manager/maven/extract.spec.ts     |    8 +-
 lib/modules/manager/maven/index.spec.ts       |    2 +-
 .../meteor/__snapshots__/extract.spec.ts.snap |    4 +-
 lib/modules/manager/mise/extract.spec.ts      |    2 +-
 .../mix/__snapshots__/artifacts.spec.ts.snap  |   10 +-
 lib/modules/manager/mix/artifacts.spec.ts     |    8 +-
 lib/modules/manager/nix/artifacts.spec.ts     |    8 +-
 lib/modules/manager/nix/extract.spec.ts       |    2 +-
 .../npm/__snapshots__/utils.spec.ts.snap      |    4 +-
 lib/modules/manager/npm/artifacts.spec.ts     |    4 +-
 lib/modules/manager/npm/detect.spec.ts        |    2 +-
 .../extract/__snapshots__/index.spec.ts.snap  |   26 +-
 .../extract/__snapshots__/pnpm.spec.ts.snap   |    4 +-
 .../extract/__snapshots__/yarn.spec.ts.snap   |    8 +-
 lib/modules/manager/npm/extract/index.spec.ts |    6 +-
 lib/modules/manager/npm/extract/npm.spec.ts   |    2 +-
 lib/modules/manager/npm/extract/pnpm.spec.ts  |    6 +-
 .../npm/extract/post/locked-versions.spec.ts  |   10 +-
 .../manager/npm/extract/post/monorepo.spec.ts |    2 +-
 lib/modules/manager/npm/extract/yarn.spec.ts  |    2 +-
 .../__snapshots__/index.spec.ts.snap          |    8 +-
 .../__snapshots__/npm.spec.ts.snap            |   12 +-
 .../__snapshots__/pnpm.spec.ts.snap           |   12 +-
 .../__snapshots__/yarn.spec.ts.snap           |   44 +-
 .../manager/npm/post-update/index.spec.ts     |   15 +-
 .../npm/post-update/node-version.spec.ts      |    2 +-
 .../manager/npm/post-update/npm.spec.ts       |    6 +-
 .../manager/npm/post-update/pnpm.spec.ts      |    6 +-
 .../manager/npm/post-update/yarn.spec.ts      |   18 +-
 .../__snapshots__/index.spec.ts.snap          |    4 +-
 .../package-lock/dep-constraints.spec.ts      |    2 +-
 .../package-lock/get-locked.spec.ts           |    2 +-
 .../__snapshots__/index.spec.ts.snap          |    8 +-
 .../nuget/__snapshots__/extract.spec.ts.snap  |    8 +-
 lib/modules/manager/nuget/artifacts.spec.ts   |   16 +-
 .../manager/nuget/package-tree.spec.ts        |   16 +-
 lib/modules/manager/nuget/util.spec.ts        |    2 +-
 lib/modules/manager/pep621/artifacts.spec.ts  |    4 +-
 lib/modules/manager/pep621/extract.spec.ts    |    2 +-
 .../manager/pep621/processors/pdm.spec.ts     |    4 +-
 .../manager/pep621/processors/uv.spec.ts      |    6 +-
 .../manager/pip-compile/artifacts.spec.ts     |   14 +-
 .../manager/pip-compile/common.spec.ts        |    2 +-
 .../manager/pip-compile/extract.spec.ts       |    2 +-
 .../__snapshots__/extract.spec.ts.snap        |   20 +-
 .../pip_requirements/artifacts.spec.ts        |    6 +-
 .../__snapshots__/extract.spec.ts.snap        |    4 +-
 lib/modules/manager/pipenv/artifacts.spec.ts  |   48 +-
 lib/modules/manager/pipenv/extract.spec.ts    |   29 +-
 .../poetry/__snapshots__/extract.spec.ts.snap |   12 +-
 lib/modules/manager/poetry/artifacts.spec.ts  |   10 +-
 lib/modules/manager/poetry/extract.spec.ts    |    2 +-
 .../__snapshots__/extract.spec.ts.snap        |    4 +-
 .../manager/pre-commit/extract.spec.ts        |    2 +-
 lib/modules/manager/pub/artifacts.spec.ts     |   10 +-
 .../sbt/__snapshots__/extract.spec.ts.snap    |   18 +-
 lib/modules/manager/sbt/extract.spec.ts       |    2 +-
 .../__snapshots__/extract.spec.ts.snap        |    4 +-
 .../swift/__snapshots__/index.spec.ts.snap    |    4 +-
 .../tekton/__snapshots__/extract.spec.ts.snap |    4 +-
 lib/modules/manager/terraform/extract.spec.ts |    2 +-
 .../lockfile/__snapshots__/hash.spec.ts.snap  |    4 +-
 .../manager/terraform/lockfile/hash.spec.ts   |    2 +-
 .../manager/terraform/lockfile/index.spec.ts  |    6 +-
 .../manager/terragrunt/artifacts.spec.ts      |    2 +-
 .../manager/tflint-plugin/extract.spec.ts     |    2 +-
 .../travis/__snapshots__/extract.spec.ts.snap |    4 +-
 .../__snapshots__/artifacts.spec.ts.snap      |    4 +-
 lib/modules/manager/vendir/artifacts.spec.ts  |   10 +-
 .../__snapshots__/azure-helper.spec.ts.snap   |   14 +-
 .../azure/__snapshots__/index.spec.ts.snap    |   52 +-
 .../azure/__snapshots__/util.spec.ts.snap     |   20 +-
 .../platform/azure/azure-helper.spec.ts       |   10 +-
 lib/modules/platform/azure/index.spec.ts      |   24 +-
 .../__snapshots__/index.spec.ts.snap          |   86 +-
 .../platform/bitbucket-server/index.spec.ts   |    7 +-
 .../platform/bitbucket-server/utils.spec.ts   |    1 +
 .../__snapshots__/index.spec.ts.snap          |   32 +-
 lib/modules/platform/bitbucket/index.spec.ts  |   14 +-
 lib/modules/platform/codecommit/index.spec.ts |   16 +-
 lib/modules/platform/comment.spec.ts          |    3 +-
 lib/modules/platform/default-scm.spec.ts      |    2 +-
 lib/modules/platform/gerrit/index.spec.ts     |   10 +-
 lib/modules/platform/gerrit/scm.spec.ts       |    8 +-
 lib/modules/platform/gerrit/utils.spec.ts     |    2 +-
 lib/modules/platform/gitea/index.spec.ts      |    2 +-
 .../github/__snapshots__/index.spec.ts.snap   |   34 +-
 lib/modules/platform/github/index.spec.ts     |   22 +-
 lib/modules/platform/github/scm.spec.ts       |    2 +-
 .../gitlab/__snapshots__/index.spec.ts.snap   |   28 +-
 lib/modules/platform/gitlab/index.spec.ts     |   30 +-
 lib/modules/platform/index.spec.ts            |    9 +-
 lib/modules/platform/local/scm.spec.ts        |    6 +-
 lib/modules/platform/scm.spec.ts              |    4 +-
 .../utils/__snapshots__/pr-body.spec.ts.snap  |    6 +-
 lib/modules/versioning/composer/index.spec.ts |    2 +-
 lib/modules/versioning/debian/index.spec.ts   |    2 +-
 lib/modules/versioning/index.spec.ts          |    7 +-
 lib/modules/versioning/nixpkgs/index.spec.ts  |    2 +-
 lib/modules/versioning/ruby/index.spec.ts     |    2 +-
 lib/modules/versioning/ubuntu/index.spec.ts   |    2 +-
 .../versioning/versioning-metadata.spec.ts    |    3 +-
 lib/util/cache/package/decorator.spec.ts      |    2 +-
 lib/util/cache/package/index.spec.ts          |    6 +-
 lib/util/cache/repository/impl/local.spec.ts  |    2 +-
 lib/util/cache/repository/impl/s3.spec.ts     |    2 +-
 lib/util/cache/repository/index.spec.ts       |    2 +-
 lib/util/check-token.spec.ts                  |    4 +-
 lib/util/exec/common.spec.ts                  |    2 +-
 lib/util/exec/containerbase.spec.ts           |    2 +-
 lib/util/exec/docker/index.spec.ts            |    5 +-
 lib/util/exec/hermit.spec.ts                  |    2 +-
 lib/util/exec/index.spec.ts                   |   24 +-
 lib/util/fs/__snapshots__/index.spec.ts.snap  |    6 +-
 lib/util/fs/index.spec.ts                     |    6 +-
 lib/util/git/behind-base-branch-cache.spec.ts |    2 +-
 lib/util/git/conflicts-cache.spec.ts          |    2 +-
 lib/util/git/index.spec.ts                    |   14 +-
 lib/util/git/modified-cache.spec.ts           |    2 +-
 lib/util/git/pristine.spec.ts                 |    2 +-
 lib/util/git/private-key.spec.ts              |   17 +-
 lib/util/git/semantic.spec.ts                 |    2 +-
 lib/util/git/set-branch-commit.spec.ts        |    4 +-
 lib/util/git/url.spec.ts                      |    4 +-
 .../github/graphql/datasource-fetcher.spec.ts |    2 +-
 .../cache/package-http-cache-provider.spec.ts |    2 +-
 lib/util/http/github.spec.ts                  |    4 +-
 lib/util/http/gitlab.spec.ts                  |    4 +-
 lib/util/http/host-rules.spec.ts              |    2 +-
 lib/util/http/index.spec.ts                   |    8 +-
 lib/util/http/jira.spec.ts                    |    4 +-
 lib/util/http/legacy.ts                       |    4 +
 lib/util/ignore.spec.ts                       |    4 +-
 lib/util/json-writer/editor-config.spec.ts    |   14 +-
 lib/util/modules.ts                           |    8 +-
 lib/util/mutex.spec.ts                        |    1 -
 lib/util/package-rules/index.spec.ts          |    2 +-
 lib/util/regex.spec.ts                        |   13 +-
 .../template/__snapshots__/index.spec.ts.snap |    4 +-
 lib/util/template/index.spec.ts               |    4 +-
 lib/workers/global/autodiscover.spec.ts       |   55 +-
 .../parse/__snapshots__/env.spec.ts.snap      |   20 +-
 .../parse/__snapshots__/file.spec.ts.snap     |    4 +-
 lib/workers/global/config/parse/file.spec.ts  |    6 +-
 lib/workers/global/config/parse/index.spec.ts |   21 +-
 lib/workers/global/index.spec.ts              |   32 +-
 lib/workers/global/initialize.spec.ts         |    2 +-
 .../dependency-dashboard.spec.ts.snap         |   28 +-
 .../repository/changelog/index.spec.ts        |    2 +-
 .../config-migration/branch/create.spec.ts    |    4 +-
 .../config-migration/branch/index.spec.ts     |   12 +-
 .../branch/migrated-data.spec.ts              |   12 +-
 .../config-migration/branch/rebase.spec.ts    |    2 +-
 .../repository/config-migration/index.spec.ts |    6 +-
 .../pr/__snapshots__/index.spec.ts.snap       |   10 +-
 .../config-migration/pr/index.spec.ts         |    2 +-
 .../repository/dependency-dashboard.spec.ts   |    2 +-
 lib/workers/repository/error-config.spec.ts   |    2 -
 lib/workers/repository/error.spec.ts          |    2 +-
 .../__snapshots__/file-match.spec.ts.snap     |   14 +-
 .../repository/extract/file-match.spec.ts     |    2 +-
 lib/workers/repository/extract/index.spec.ts  |    4 +-
 .../repository/extract/manager-files.spec.ts  |    6 +-
 lib/workers/repository/finalize/prune.spec.ts |    2 +-
 .../finalize/repository-statistics.spec.ts    |    4 +-
 lib/workers/repository/index.spec.ts          |    8 +-
 .../__snapshots__/vulnerability.spec.ts.snap  |    8 +-
 lib/workers/repository/init/index.spec.ts     |   20 +-
 lib/workers/repository/init/inherited.spec.ts |    2 +-
 lib/workers/repository/init/merge.spec.ts     |   10 +-
 .../onboarding/branch/check.spec.ts           |    4 +-
 .../onboarding/branch/config.spec.ts          |    4 +-
 .../onboarding/branch/create.spec.ts          |    2 +-
 .../onboarding/branch/index.spec.ts           |   12 +-
 .../branch/onboarding-branch-cache.spec.ts    |    4 +-
 .../onboarding/branch/rebase.spec.ts          |    2 +-
 .../config-description.spec.ts.snap           |   26 +-
 .../pr/__snapshots__/index.spec.ts.snap       |   14 +-
 .../repository/onboarding/pr/index.spec.ts    |    2 +-
 .../repository/process/extract-update.spec.ts |   16 +-
 lib/workers/repository/process/fetch.spec.ts  |    2 +-
 lib/workers/repository/process/index.spec.ts  |    4 +-
 .../repository/process/libyear.spec.ts        |    2 +-
 .../__snapshots__/filter-checks.spec.ts.snap  |   18 +-
 .../process/lookup/filter-checks.spec.ts      |    6 +-
 .../repository/process/lookup/index.spec.ts   |    2 +-
 .../process/vulnerabilities.spec.ts           |    2 +-
 lib/workers/repository/process/write.spec.ts  |   15 +-
 .../repository/reconfigure/index.spec.ts      |    2 +-
 .../reconfigure/reconfigure-cache.spec.ts     |    2 +-
 .../repository/reconfigure/validate.spec.ts   |   10 +-
 .../__snapshots__/get-updated.spec.ts.snap    |   30 +-
 .../update/branch/auto-replace.spec.ts        |    2 +-
 .../update/branch/automerge.spec.ts           |    2 +-
 .../execute-post-upgrade-commands.spec.ts     |    4 +-
 .../update/branch/get-updated.spec.ts         |   24 +-
 .../repository/update/branch/index.spec.ts    |   35 +-
 .../update/branch/lock-files/index.spec.ts    |   12 +-
 .../update/pr/body/changelogs.spec.ts         |    2 +-
 .../repository/update/pr/body/footer.spec.ts  |    2 +-
 .../repository/update/pr/body/header.spec.ts  |    2 +-
 .../repository/update/pr/body/index.spec.ts   |   16 +-
 .../repository/update/pr/body/notes.spec.ts   |    2 +-
 .../__snapshots__/index.spec.ts.snap          |   16 +-
 .../__snapshots__/release-notes.spec.ts.snap  |   22 +-
 .../github/__snapshots__/index.spec.ts.snap   |   14 +-
 .../update/pr/changelog/github/index.spec.ts  |    2 +-
 .../gitlab/__snapshots__/index.spec.ts.snap   |   14 +-
 .../update/pr/changelog/index.spec.ts         |   10 +-
 .../update/pr/changelog/release-notes.spec.ts |    4 +-
 .../repository/update/pr/code-owners.spec.ts  |    5 +-
 .../repository/update/pr/index.spec.ts        |   18 +-
 .../repository/update/pr/participants.spec.ts |    4 +-
 .../repository/update/pr/pr-cache.spec.ts     |    2 +-
 .../__snapshots__/generate.spec.ts.snap       |   17 +-
 .../repository/updates/branchify.spec.ts      |    4 +-
 .../repository/updates/flatten.spec.ts        |    2 +-
 package.json                                  |   33 +-
 pnpm-lock.yaml                                | 1384 ++++++++++++++---
 test/exec-util.ts                             |    2 +-
 test/fixtures.ts                              |   46 +-
 test/global-setup.ts                          |    4 -
 test/http-mock.ts                             |    3 +-
 test/jest-legacy.ts                           |   57 +
 test/newline-snapshot-serializer.ts           |   14 -
 test/s3.ts                                    |    3 +-
 test/setup.ts                                 |   21 +-
 test/to-migrate.ts                            |    8 +-
 test/tsconfig.json                            |    3 -
 test/types/expect-more-jest.d.ts              |   71 +
 test/types/jest-extended.d.ts                 |  882 +++++++++++
 test/types/jest-mock-extended.d.ts            |    7 +
 test/types/jest.d.ts                          |  165 +-
 test/util.ts                                  |   75 +-
 tools/test/types.ts                           |   15 -
 tools/test/utils.ts                           |   18 +-
 tsconfig.app.json                             |    4 +-
 tsconfig.json                                 |   10 +-
 tsconfig.spec.json                            |    2 +
 vitest.config.ts                              |  128 ++
 419 files changed, 4217 insertions(+), 2458 deletions(-)
 delete mode 100644 jest.config.ts
 delete mode 100644 test/global-setup.ts
 create mode 100644 test/jest-legacy.ts
 delete mode 100644 test/newline-snapshot-serializer.ts
 delete mode 100644 test/tsconfig.json
 create mode 100644 test/types/expect-more-jest.d.ts
 create mode 100644 test/types/jest-extended.d.ts
 create mode 100644 test/types/jest-mock-extended.d.ts
 create mode 100644 vitest.config.ts

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 015bceea21..3b57bb7e52 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -20,7 +20,7 @@
       "extensions": [
         "dbaeumer.vscode-eslint",
         "esbenp.prettier-vscode",
-        "orta.vscode-jest",
+        "vitest.explorer",
         "editorconfig.editorconfig",
         "github.vscode-github-actions"
       ]
diff --git a/.github/contributing.md b/.github/contributing.md
index cd099ba35d..3ef116e848 100644
--- a/.github/contributing.md
+++ b/.github/contributing.md
@@ -44,31 +44,31 @@ Use these commands to help run your tests:
 - To run a single test folder, specify the path
 
   ```bash
-  pnpm jest platform/gitlab
+  pnpm vitest platform/gitlab
   ```
 
 - To run against a single test file, specify down to the filename (suffix is not necessary)
 
   ```bash
-  pnpm jest platform/gitlab/index
+  pnpm vitest platform/gitlab/index
   ```
 
 - To run a single test batch, the `-t` value must be part of the `describe` value of the test batch
 
   ```bash
-  pnpm jest platform/gitlab/index -t "getJsonFile"
+  pnpm vitest platform/gitlab/index -t "getJsonFile"
   ```
 
 - To run a single test, the `-t` value must be part of the `it` value of the test batch
 
   ```bash
-  pnpm jest platform/gitlab/index -t "returns file content from given repo"
+  pnpm vitest platform/gitlab/index -t "returns file content from given repo"
   ```
 
 And some options:
 
 - `--verbose=false` to avoid the test list
-- `--collectCoverage=false` to avoid collecting coverage, faster for the part you need the test to pass
+- `--coverage=false` to avoid collecting coverage, faster for the part you need the test to pass
 
 ## Do not force push to your pull request branch
 
diff --git a/.github/label-actions.yml b/.github/label-actions.yml
index f68d341199..42c351f76b 100644
--- a/.github/label-actions.yml
+++ b/.github/label-actions.yml
@@ -247,7 +247,7 @@
     Hi there,
 
 
-    You're skipping code tests with `istanbul ignore`.
+    You're skipping code tests with `v8 ignore`.
 
 
     Please only skip tests if:
@@ -260,7 +260,7 @@
 
 
     ```ts
-    // istanbul ignore next: typescript strict null check
+    // v8 ignore next: typescript strict null check
     if (!url) {
       return null;
     }
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 07fab38f64..fa9cbc7662 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -378,12 +378,12 @@ jobs:
           node-version: ${{ env.NODE_VERSION }}
           os: ${{ runner.os }}
 
-      - name: Cache jest
+      - name: Cache vitest
         uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
         with:
-          path: .cache/jest
+          path: .cache/vitest
           key: |
-            jest-cache-${{
+            vitest-cache-${{
               runner.os
             }}-${{
               env.NODE_VERSION
@@ -398,8 +398,7 @@ jobs:
         run: |
           for shard in ${{ matrix.shards }};
           do
-            TEST_SHARD="$shard" pnpm jest \
-              --ci \
+            TEST_SHARD="$shard" pnpm vitest \
               --test-timeout ${{ matrix.test-timeout-milliseconds }} \
               --coverage ${{ matrix.coverage }}
           done
@@ -488,10 +487,10 @@ jobs:
       - name: Check coverage threshold
         run: |
           pnpm nyc check-coverage -t ./coverage/nyc \
-            --branches 100 \
-            --functions 100 \
-            --lines 100 \
-            --statements 100
+            --branches 97 \
+            --functions 98 \
+            --lines 97 \
+            --statements 97
 
   # Catch-all required check for test matrix and coverage
   test-success:
diff --git a/.ls-lint.yml b/.ls-lint.yml
index af0b6eb30d..713f85ee1f 100644
--- a/.ls-lint.yml
+++ b/.ls-lint.yml
@@ -15,7 +15,7 @@ ignore:
   - .venv
   - CODE_OF_CONDUCT.md
   - dist
-  - jest.config.ts
+  - vitest.config.ts
   - node_modules
   - SECURITY.md
   - test/e2e/node_modules
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index a45d022d1c..013223138b 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -2,7 +2,7 @@
   "recommendations": [
     "dbaeumer.vscode-eslint",
     "esbenp.prettier-vscode",
-    "orta.vscode-jest",
+    "vitest.explorer",
     "editorconfig.editorconfig",
     "github.vscode-github-actions"
   ]
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 998732a914..45f9932c52 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -29,84 +29,22 @@
     {
       "type": "node",
       "request": "launch",
-      "name": "Jest Current File",
-      "runtimeExecutable": "pnpm",
-      "program": "jest",
+      "name": "Debug Current Test File",
+      "autoAttachChildProcesses": true,
+      "skipFiles": ["<node_internals>/**", "**/node_modules/**"],
+      "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
       "args": [
-        "--runInBand",
-        "--collectCoverage=false",
-        "--testTimeout=100000000",
-        "--runTestsByPath",
+        "run",
+        "--no-file-parallelism",
+        "--no-coverage",
+        "--test-timeout=0",
+        "--hook-timeout=0",
         "${relativeFile}"
       ],
       "env": {
-        "NODE_ENV": "test",
         "LOG_LEVEL": "debug"
       },
-      "console": "integratedTerminal",
-      "runtimeArgs": ["--preserve-symlinks"],
-      "skipFiles": ["<node_internals>/**/*.js"]
-    },
-    {
-      "type": "node",
-      "request": "launch",
-      "name": "Jest All",
-      "runtimeExecutable": "pnpm",
-      "program": "jest",
-      "args": [
-        "--runInBand",
-        "--collectCoverage=false",
-        "--testTimeout=100000000"
-      ],
-      "env": {
-        "NODE_ENV": "test",
-        "LOG_LEVEL": "debug"
-      },
-      "console": "integratedTerminal",
-      "runtimeArgs": ["--preserve-symlinks"],
-      "skipFiles": ["<node_internals>/**/*.js"]
-    },
-    {
-      "type": "node",
-      "request": "launch",
-      "name": "Jest Current Folder",
-      "runtimeExecutable": "pnpm",
-      "program": "jest",
-      "args": [
-        "--runInBand",
-        "--collectCoverage=false",
-        "--testTimeout=100000000",
-        "--roots=${workspaceFolder}/${relativeFileDirname}"
-      ],
-      "console": "integratedTerminal",
-      "runtimeArgs": ["--preserve-symlinks"],
-      "skipFiles": ["<node_internals>/**/*.js"]
-    },
-    {
-      "type": "node",
-      "name": "vscode-jest-tests.v2",
-      "request": "launch",
-      "console": "integratedTerminal",
-      "internalConsoleOptions": "openOnSessionStart",
-      "cwd": "${workspaceFolder}",
-      "runtimeExecutable": "node",
-      "runtimeArgs": ["--experimental-vm-modules"],
-      "program": "node_modules/jest/bin/jest.js",
-      "args": [
-        "--runInBand",
-        "--watchAll=false",
-        "--testTimeout=100000000",
-        "--coverage=false",
-        "--runTestsByPath",
-        "${jest.testFile}",
-        "--testNamePattern",
-        "${jest.testNamePattern}"
-      ],
-      "env": {
-        "NODE_ENV": "test",
-        "LOG_LEVEL": "trace",
-        "GIT_ALLOW_PROTOCOL": "file"
-      }
+      "console": "integratedTerminal"
     }
   ]
 }
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 31610ed654..552501ca24 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -16,10 +16,7 @@
     ".releaserc": "json"
   },
   "omnisharp.autoStart": false,
-  "jest.runMode": "on-demand",
-  "jest.jestCommandLine": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
-  "jest.nodeEnv": {
-    "NODE_ENV": "test",
+  "vitest.nodeEnv": {
     "LOG_LEVEL": "trace",
     "GIT_ALLOW_PROTOCOL": "file"
   },
diff --git a/docs/development/best-practices.md b/docs/development/best-practices.md
index d5d1f4c113..ca4482cfa3 100644
--- a/docs/development/best-practices.md
+++ b/docs/development/best-practices.md
@@ -13,7 +13,7 @@ Some good branch names:
 
 - `feat/13732-cacache-cleanup`
 - `fix/15431-gitea-automerge-strategy`
-- `refactor/jest-reset-mocks`
+- `refactor/vitest-reset-mocks`
 - `docs/rewrite-packageRules-section`
 
 Avoid branch names like `patch-1`.
@@ -29,14 +29,14 @@ Read the [GitHub Docs, renaming a branch](https://docs.github.com/en/repositorie
 - Prefer `interface` over `type` for TypeScript type declarations
 - Avoid [Enums](https://github.com/renovatebot/renovate/issues/13743), use unions or [immutable objects](https://github.com/renovatebot/renovate/blob/5043379847818ac1fa71ff69c098451975e95710/lib/modules/versioning/pep440/range.ts#L8-L20) instead
 - Always add unit tests for full code coverage
-  - Only use `istanbul` comments for unreachable code coverage that is needed for `codecov` completion
-  - Use descriptive `istanbul` comments
+  - Only use `v8` comments for unreachable code coverage that is needed for `codecov` completion
+  - Use descriptive `v8` comments
 - Avoid cast or prefer `x as T` instead of `<T>x` cast
 - Prefer `satisfies` operator over `as`, read the [TypeScript release notes for `satisfies` operator](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator) to learn more
 - Avoid `Boolean` instead use `is` functions from `@sindresorhus/is` package, for example: `is.string`
 
 ```ts
-// istanbul ignore next: can never happen
+// v8 ignore next: can never happen
 ```
 
 ### Functions
@@ -280,12 +280,12 @@ if (end) {
 
 - Separate the _Arrange_, _Act_ and _Assert_ phases with newlines
 - Use `it.each` rather than `test.each`
-- Prefer [Tagged Template Literal](https://jestjs.io/docs/api#2-testeachtablename-fn-timeout) style for `it.each`, Prettier will help with formatting
+- Prefer [Tagged Template Literal](https://vitest.dev/api/#test-each) style for `it.each`, Prettier will help with formatting
   - See [Example](https://github.com/renovatebot/renovate/blob/768e178419437a98f5ce4996bafd23f169e530b4/lib/modules/platform/util.spec.ts#L8-L18)
 - Mock Date/Time when testing a Date/Time dependent module
   - For `Luxon` mocking see [Example](https://github.com/renovatebot/renovate/blob/5043379847818ac1fa71ff69c098451975e95710/lib/modules/versioning/distro.spec.ts#L7-L10)
-- Prefer `jest.spyOn` for mocking single functions, or mock entire modules
-  - Avoid overwriting functions, for example: (`func = jest.fn();`)
+- Prefer `vi.spyOn` for mocking single functions, or mock entire modules
+  - Avoid overwriting functions, for example: (`func = vi.fn();`)
 - Prefer `toEqual`
 - Use `toMatchObject` for huge objects when only parts need to be tested
 - Avoid `toMatchSnapshot`, only use it for:
diff --git a/docs/development/issue-labeling.md b/docs/development/issue-labeling.md
index 35038eab39..d5277ee170 100644
--- a/docs/development/issue-labeling.md
+++ b/docs/development/issue-labeling.md
@@ -203,7 +203,7 @@ Add a label `auto:logs` to indicate that there's a problem with the logs, and th
 
 Add a label `auto:needs-details` to discussions which need more details to move forward.
 
-Add a label `auto:no-coverage-ignore` if PR authors avoid needed unit tests by istanbul ignoring code with the `// istanbul ignore` comment.
+Add a label `auto:no-coverage-ignore` if PR authors avoid needed unit tests by v8 ignoring code with the `// v8 ignore` comment.
 
 Add a label `auto:no-done-comments` if PR authors unnecessary "Done" comments, or type comments to ask for a review instead of requesting a new review through GitHub's UI.
 
diff --git a/docs/development/local-development.md b/docs/development/local-development.md
index 6a20f6988f..0b15c230ef 100644
--- a/docs/development/local-development.md
+++ b/docs/development/local-development.md
@@ -144,21 +144,21 @@ If this is working then in future you can create other test repos to verify your
 
 You can run `pnpm test` locally to test your code.
 We test all PRs using the same tests, run on GitHub Actions.
-`pnpm test` runs an `eslint` check, a `prettier` check, a `type` check and then all the unit tests using `jest`.
+`pnpm test` runs an `eslint` check, a `prettier` check, a `type` check and then all the unit tests using `vitest`.
 
 Refactor PRs should ideally not change or remove tests (adding tests is OK).
 
-### Jest
+### Vitest
 
-Run the Jest unit tests with the `pnpm jest` command.
-You can also run a subset of the Jest tests using file matching, e.g. `pnpm jest composer` or `pnpm jest workers/repository/update/branch`.
+Run the Vitest unit tests with the `pnpm vitest` command.
+You can also run a subset of the Vitest tests using file matching, e.g. `pnpm vitest composer` or `pnpm vitest workers/repository/update/branch`.
 If you get a test failure due to a "snapshot" mismatch, and you are sure that you need to update the snapshot, then you can append `-u` to the end.
-e.g. `pnpm jest composer -u` would update the saved snapshots for _all_ tests in `**/composer/**`.
+e.g. `pnpm vitest composer -u` would update the saved snapshots for _all_ tests in `**/composer/**`.
 
 ### Coverage
 
 The Renovate project maintains 100% test coverage, so any Pull Request will fail if it does not have full coverage for code.
-Using `// istanbul ignore` is not ideal, but can be a pragmatic solution if adding more tests wouldn't really prove anything.
+Using `// v8 ignore` is not ideal, but can be a pragmatic solution if adding more tests wouldn't really prove anything.
 
 To view the current test coverage locally, open up `coverage/index.html` in your browser.
 
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 5adf18357a..6323304804 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -2,7 +2,7 @@ import eslintContainerbase from '@containerbase/eslint-plugin';
 import js from '@eslint/js';
 import eslintConfigPrettier from 'eslint-config-prettier';
 import eslintPluginImport from 'eslint-plugin-import';
-import jest from 'eslint-plugin-jest';
+import vitest from '@vitest/eslint-plugin';
 import eslintPluginPromise from 'eslint-plugin-promise';
 import globals from 'globals';
 import tseslint from 'typescript-eslint';
@@ -40,7 +40,6 @@ export default tseslint.config(
   eslintPluginImport.flatConfigs.warnings,
   eslintPluginImport.flatConfigs.recommended,
   eslintPluginImport.flatConfigs.typescript,
-  jest.configs['flat/recommended'],
   eslintPluginPromise.configs['flat/recommended'],
   eslintContainerbase.configs.all,
   {
@@ -88,7 +87,12 @@ export default tseslint.config(
       'import/no-extraneous-dependencies': [
         'error',
         {
-          devDependencies: ['eslint.config.mjs', 'test/**/*', '**/*.spec.ts'],
+          devDependencies: [
+            '*.config.mjs',
+            '*.config.ts',
+            'test/**/*',
+            '**/*.spec.ts',
+          ],
         },
       ],
 
@@ -114,7 +118,7 @@ export default tseslint.config(
       'import/no-unresolved': [
         'error',
         {
-          ignore: ['^mdast$'],
+          ignore: ['^mdast$', `^jest-mock-extended$`],
         },
       ],
 
@@ -227,13 +231,22 @@ export default tseslint.config(
   {
     files: ['**/*.spec.ts', 'test/**'],
 
+    plugins: { vitest },
+
     languageOptions: {
       globals: {
-        ...globals.jest,
+        ...globals.vitest,
+      },
+    },
+
+    settings: {
+      vitest: {
+        typecheck: true,
       },
     },
 
     rules: {
+      ...vitest.configs.recommended.rules,
       'no-template-curly-in-string': 0,
       'prefer-destructuring': 0,
       'prefer-promise-reject-errors': 0,
@@ -243,14 +256,6 @@ export default tseslint.config(
       '@typescript-eslint/no-object-literal-type-assertion': 0,
       '@typescript-eslint/explicit-function-return-type': 0,
       '@typescript-eslint/unbound-method': 0,
-
-      'jest/valid-title': [
-        0,
-        {
-          ignoreTypeOfDescribeName: true,
-        },
-      ],
-
       'max-classes-per-file': 0,
       'class-methods-use-this': 0,
     },
@@ -304,7 +309,7 @@ export default tseslint.config(
     languageOptions: {
       globals: {
         ...Object.fromEntries(
-          Object.entries(globals.jest).map(([key]) => [key, 'off']),
+          Object.entries(globals.vitest).map(([key]) => [key, 'off']),
         ),
       },
     },
diff --git a/jest.config.ts b/jest.config.ts
deleted file mode 100644
index 5fcffe5049..0000000000
--- a/jest.config.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-import os from 'node:os';
-import v8 from 'node:v8';
-import { testShards } from './tools/test/shards';
-import type { JestConfig, JestShardedSubconfig } from './tools/test/types';
-import { getCoverageIgnorePatterns } from './tools/test/utils';
-
-const ci = !!process.env.CI;
-
-const cpus = os.cpus();
-const mem = os.totalmem();
-const stats = v8.getHeapStatistics();
-
-/**
- * https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
- * Currently it seems the runner only have 4GB
- */
-function jestGithubRunnerSpecs(): JestConfig {
-  // if (os.platform() === 'darwin') {
-  //   return {
-  //     maxWorkers: 2,
-  //     workerIdleMemoryLimit: '4GB',
-  //   };
-  // }
-
-  return {
-    maxWorkers: cpus.length,
-    workerIdleMemoryLimit: '1500MB', // '2GB',
-  };
-}
-
-/**
- * Convert match pattern to a form that matches on file with `.ts` or `.spec.ts` extension.
- */
-function normalizePattern(pattern: string, suffix: '.ts' | '.spec.ts'): string {
-  return pattern.endsWith('.spec.ts')
-    ? pattern.replace(/\.spec\.ts$/, suffix)
-    : `${pattern}/**/*${suffix}`;
-}
-
-/**
- * Generates Jest config for sharded test run.
- *
- * If `TEST_SHARD` environment variable is not set,
- * it falls back to the provided config.
- *
- * Otherwise, `fallback` value is used to determine some defaults.
- */
-function configureShardingOrFallbackTo(
-  fallback: JestShardedSubconfig,
-): JestShardedSubconfig {
-  const shardKey = process.env.TEST_SHARD;
-  if (!shardKey) {
-    return fallback;
-  }
-
-  if (!testShards[shardKey]) {
-    const keys = Object.keys(testShards).join(', ');
-    throw new Error(
-      `Unknown value for TEST_SHARD: ${shardKey} (possible values: ${keys})`,
-    );
-  }
-
-  const testMatch: string[] = [];
-
-  for (const [key, { matchPaths: patterns }] of Object.entries(testShards)) {
-    if (key === shardKey) {
-      const testMatchPatterns = patterns.map((pattern) => {
-        const filePattern = normalizePattern(pattern, '.spec.ts');
-        return `<rootDir>/${filePattern}`;
-      });
-      testMatch.push(...testMatchPatterns);
-      break;
-    }
-
-    const testMatchPatterns = patterns.map((pattern) => {
-      const filePattern = normalizePattern(pattern, '.spec.ts');
-      return `!**/${filePattern}`;
-    });
-    testMatch.push(...testMatchPatterns);
-  }
-
-  testMatch.reverse();
-
-  const coverageDirectory = `./coverage/shard/${shardKey}`;
-  return {
-    testMatch,
-    coverageDirectory,
-  };
-}
-
-const config: JestConfig = {
-  ...configureShardingOrFallbackTo({
-    coverageDirectory: './coverage',
-  }),
-  collectCoverageFrom: [
-    'lib/**/*.{js,ts}',
-    '!lib/**/*.{d,spec}.ts',
-    '!lib/**/{__fixtures__,__mocks__,__testutil__,test}/**/*.{js,ts}',
-    '!lib/**/types.ts',
-  ],
-  coveragePathIgnorePatterns: getCoverageIgnorePatterns(),
-  cacheDirectory: '.cache/jest',
-  collectCoverage: true,
-  coverageReporters: ci
-    ? ['lcovonly', 'json']
-    : ['html', 'text-summary', 'json'],
-  transform: {
-    '\\.ts$': [
-      'ts-jest',
-      {
-        tsconfig: '<rootDir>/tsconfig.spec.json',
-        diagnostics: false,
-        isolatedModules: true,
-      },
-    ],
-  },
-  modulePathIgnorePatterns: [
-    '<rootDir>/dist/',
-    '/__fixtures__/',
-    '/__mocks__/',
-  ],
-  reporters: ci ? ['default', 'github-actions'] : ['default'],
-  resetMocks: true,
-  globalSetup: '<rootDir>/test/global-setup.ts',
-  setupFilesAfterEnv: [
-    'jest-extended/all',
-    'expect-more-jest',
-    '<rootDir>/test/setup.ts',
-    '<rootDir>/test/to-migrate.ts',
-  ],
-  snapshotSerializers: ['<rootDir>/test/newline-snapshot-serializer.ts'],
-  testEnvironment: 'node',
-  testRunner: 'jest-circus/runner',
-  watchPathIgnorePatterns: ['<rootDir>/.cache/', '<rootDir>/coverage/'],
-  // We can play with that value later for best dev experience
-  workerIdleMemoryLimit: '500MB',
-  // add github runner specific limits
-  ...(ci && jestGithubRunnerSpecs()),
-};
-
-export default config;
-
-process.stderr.write(`Host stats:
-    Cpus:      ${cpus.length}
-    Memory:    ${(mem / 1024 / 1024 / 1024).toFixed(2)} GB
-    HeapLimit: ${(stats.heap_size_limit / 1024 / 1024 / 1024).toFixed(2)} GB
-  `);
diff --git a/lib/config/__snapshots__/index.spec.ts.snap b/lib/config/__snapshots__/index.spec.ts.snap
index e8b55b377a..58e9c0941a 100644
--- a/lib/config/__snapshots__/index.spec.ts.snap
+++ b/lib/config/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`config/index mergeChildConfig(parentConfig, childConfig) merges 1`] = `
+exports[`config/index > mergeChildConfig(parentConfig, childConfig) > merges 1`] = `
 {
   "branchTopic": "lock-file-maintenance",
   "commitMessageAction": "Lock file maintenance",
@@ -19,7 +19,7 @@ exports[`config/index mergeChildConfig(parentConfig, childConfig) merges 1`] = `
 }
 `;
 
-exports[`config/index mergeChildConfig(parentConfig, childConfig) merges constraints 1`] = `
+exports[`config/index > mergeChildConfig(parentConfig, childConfig) > merges constraints 1`] = `
 {
   "node": "<15",
   "npm": "^6.0.0",
diff --git a/lib/config/__snapshots__/migrate-validate.spec.ts.snap b/lib/config/__snapshots__/migrate-validate.spec.ts.snap
index 80d365c770..76ec3f1890 100644
--- a/lib/config/__snapshots__/migrate-validate.spec.ts.snap
+++ b/lib/config/__snapshots__/migrate-validate.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`config/migrate-validate migrateAndValidate() handles invalid 1`] = `
+exports[`config/migrate-validate > migrateAndValidate() > handles invalid 1`] = `
 {
   "errors": [
     {
@@ -13,7 +13,7 @@ exports[`config/migrate-validate migrateAndValidate() handles invalid 1`] = `
 }
 `;
 
-exports[`config/migrate-validate migrateAndValidate() isOnboarded 1`] = `
+exports[`config/migrate-validate > migrateAndValidate() > isOnboarded 1`] = `
 {
   "errors": [],
 }
diff --git a/lib/config/__snapshots__/migration.spec.ts.snap b/lib/config/__snapshots__/migration.spec.ts.snap
index 909c56ff34..d074ea4ef8 100644
--- a/lib/config/__snapshots__/migration.spec.ts.snap
+++ b/lib/config/__snapshots__/migration.spec.ts.snap
@@ -1,89 +1,12 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`config/migration it migrates customManagers 1`] = `
-{
-  "customManagers": [
-    {
-      "customType": "regex",
-      "fileMatch": [
-        "(^|/|\\.)Dockerfile$",
-        "(^|/)Dockerfile[^/]*$",
-      ],
-      "matchStrings": [
-        "# renovate: datasource=(?<datasource>[a-z-]+?) depName=(?<depName>[^\\s]+?)(?: lookupName=(?<packageName>[^\\s]+?))?(?: versioning=(?<versioning>[a-z-0-9]+?))?\\s(?:ENV|ARG) .+?_VERSION="?(?<currentValue>.+?)"?\\s",
-      ],
-    },
-    {
-      "customType": "regex",
-      "fileMatch": [
-        "(^|/|\\.)Dockerfile$",
-        "(^|/)Dockerfile[^/]*$",
-      ],
-      "matchStrings": [
-        "# renovate: datasource=(?<datasource>[a-z-]+?) depName=(?<depName>[^\\s]+?)(?: lookupName=(?<holder>[^\\s]+?))?(?: versioning=(?<versioning>[a-z-0-9]+?))?\\s(?:ENV|ARG) .+?_VERSION="?(?<currentValue>.+?)"?\\s",
-      ],
-      "packageNameTemplate": "{{{holder}}}",
-    },
-  ],
-}
-`;
-
-exports[`config/migration it migrates gradle-lite 1`] = `
-{
-  "gradle": {
-    "enabled": true,
-    "fileMatch": [
-      "foo",
-    ],
-  },
-  "packageRules": [
-    {
-      "matchManagers": [
-        "gradle",
-      ],
-      "separateMinorPatch": true,
-    },
-  ],
-}
-`;
-
-exports[`config/migration it migrates nested packageRules 1`] = `
-{
-  "packageRules": [
-    {
-      "enabled": false,
-      "matchDepTypes": [
-        "devDependencies",
-      ],
-    },
-    {
-      "automerge": true,
-      "groupName": "definitelyTyped",
-      "matchPackageNames": [
-        "!@types/react-table",
-        "@types/**",
-      ],
-    },
-    {
-      "automerge": false,
-      "matchDepTypes": [
-        "dependencies",
-      ],
-      "matchPackageNames": [
-        "!@types/react-table",
-      ],
-    },
-  ],
-}
-`;
-
-exports[`config/migration migrateConfig(config, parentConfig) does not migrate multi days 1`] = `
+exports[`config/migration > migrateConfig(config, parentConfig) > does not migrate multi days 1`] = `
 {
   "schedule": "after 5:00pm on wednesday and thursday",
 }
 `;
 
-exports[`config/migration migrateConfig(config, parentConfig) migrates before and after schedules 1`] = `
+exports[`config/migration > migrateConfig(config, parentConfig) > migrates before and after schedules 1`] = `
 {
   "major": {
     "schedule": [
@@ -100,7 +23,7 @@ exports[`config/migration migrateConfig(config, parentConfig) migrates before an
 }
 `;
 
-exports[`config/migration migrateConfig(config, parentConfig) migrates config 1`] = `
+exports[`config/migration > migrateConfig(config, parentConfig) > migrates config 1`] = `
 {
   "additionalBranchPrefix": "{{parentDir}}-",
   "allowCustomCrateRegistries": true,
@@ -297,7 +220,7 @@ exports[`config/migration migrateConfig(config, parentConfig) migrates config 1`
 }
 `;
 
-exports[`config/migration migrateConfig(config, parentConfig) migrates more packageFiles 1`] = `
+exports[`config/migration > migrateConfig(config, parentConfig) > migrates more packageFiles 1`] = `
 {
   "includePaths": [
     "package.json",
@@ -325,7 +248,7 @@ exports[`config/migration migrateConfig(config, parentConfig) migrates more pack
 }
 `;
 
-exports[`config/migration migrateConfig(config, parentConfig) migrates packageFiles 1`] = `
+exports[`config/migration > migrateConfig(config, parentConfig) > migrates packageFiles 1`] = `
 {
   "includePaths": [
     "package.json",
@@ -368,7 +291,7 @@ exports[`config/migration migrateConfig(config, parentConfig) migrates packageFi
 }
 `;
 
-exports[`config/migration migrateConfig(config, parentConfig) migrates subconfig 1`] = `
+exports[`config/migration > migrateConfig(config, parentConfig) > migrates subconfig 1`] = `
 {
   "lockFileMaintenance": {
     "packageRules": [
@@ -383,7 +306,7 @@ exports[`config/migration migrateConfig(config, parentConfig) migrates subconfig
 }
 `;
 
-exports[`config/migration migrateConfig(config, parentConfig) overrides existing automerge setting 1`] = `
+exports[`config/migration > migrateConfig(config, parentConfig) > overrides existing automerge setting 1`] = `
 {
   "major": {
     "automerge": false,
@@ -409,3 +332,80 @@ exports[`config/migration migrateConfig(config, parentConfig) overrides existing
   ],
 }
 `;
+
+exports[`config/migration > migrates customManagers 1`] = `
+{
+  "customManagers": [
+    {
+      "customType": "regex",
+      "fileMatch": [
+        "(^|/|\\.)Dockerfile$",
+        "(^|/)Dockerfile[^/]*$",
+      ],
+      "matchStrings": [
+        "# renovate: datasource=(?<datasource>[a-z-]+?) depName=(?<depName>[^\\s]+?)(?: lookupName=(?<packageName>[^\\s]+?))?(?: versioning=(?<versioning>[a-z-0-9]+?))?\\s(?:ENV|ARG) .+?_VERSION="?(?<currentValue>.+?)"?\\s",
+      ],
+    },
+    {
+      "customType": "regex",
+      "fileMatch": [
+        "(^|/|\\.)Dockerfile$",
+        "(^|/)Dockerfile[^/]*$",
+      ],
+      "matchStrings": [
+        "# renovate: datasource=(?<datasource>[a-z-]+?) depName=(?<depName>[^\\s]+?)(?: lookupName=(?<holder>[^\\s]+?))?(?: versioning=(?<versioning>[a-z-0-9]+?))?\\s(?:ENV|ARG) .+?_VERSION="?(?<currentValue>.+?)"?\\s",
+      ],
+      "packageNameTemplate": "{{{holder}}}",
+    },
+  ],
+}
+`;
+
+exports[`config/migration > migrates gradle-lite 1`] = `
+{
+  "gradle": {
+    "enabled": true,
+    "fileMatch": [
+      "foo",
+    ],
+  },
+  "packageRules": [
+    {
+      "matchManagers": [
+        "gradle",
+      ],
+      "separateMinorPatch": true,
+    },
+  ],
+}
+`;
+
+exports[`config/migration > migrates nested packageRules 1`] = `
+{
+  "packageRules": [
+    {
+      "enabled": false,
+      "matchDepTypes": [
+        "devDependencies",
+      ],
+    },
+    {
+      "automerge": true,
+      "groupName": "definitelyTyped",
+      "matchPackageNames": [
+        "!@types/react-table",
+        "@types/**",
+      ],
+    },
+    {
+      "automerge": false,
+      "matchDepTypes": [
+        "dependencies",
+      ],
+      "matchPackageNames": [
+        "!@types/react-table",
+      ],
+    },
+  ],
+}
+`;
diff --git a/lib/config/__snapshots__/validation.spec.ts.snap b/lib/config/__snapshots__/validation.spec.ts.snap
index 4bfe7e328d..15e683029d 100644
--- a/lib/config/__snapshots__/validation.spec.ts.snap
+++ b/lib/config/__snapshots__/validation.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`config/validation validateConfig(config) catches invalid allowedVersions regex 1`] = `
+exports[`config/validation > validateConfig(config) > catches invalid allowedVersions regex 1`] = `
 [
   {
     "message": "Invalid regExp for packageRules[1].allowedVersions: \`/***$}{]][/\`",
@@ -13,7 +13,7 @@ exports[`config/validation validateConfig(config) catches invalid allowedVersion
 ]
 `;
 
-exports[`config/validation validateConfig(config) catches invalid matchCurrentVersion regex 1`] = `
+exports[`config/validation > validateConfig(config) > catches invalid matchCurrentVersion regex 1`] = `
 [
   {
     "message": "Invalid regExp for packageRules[1].matchCurrentVersion: \`/***$}{]][/\`",
@@ -26,7 +26,7 @@ exports[`config/validation validateConfig(config) catches invalid matchCurrentVe
 ]
 `;
 
-exports[`config/validation validateConfig(config) catches invalid templates 1`] = `
+exports[`config/validation > validateConfig(config) > catches invalid templates 1`] = `
 [
   {
     "message": "Invalid template in config path: commitMessage",
@@ -35,7 +35,7 @@ exports[`config/validation validateConfig(config) catches invalid templates 1`]
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors for all types 1`] = `
+exports[`config/validation > validateConfig(config) > errors for all types 1`] = `
 [
   {
     "message": "Configuration option \`azureWorkItemId\` should be an integer. Found: false (boolean).",
@@ -88,7 +88,7 @@ exports[`config/validation validateConfig(config) errors for all types 1`] = `
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors for unsafe fileMatches 1`] = `
+exports[`config/validation > validateConfig(config) > errors for unsafe fileMatches 1`] = `
 [
   {
     "message": "Invalid regExp for dockerfile.fileMatch: \`x?+\`",
@@ -101,7 +101,7 @@ exports[`config/validation validateConfig(config) errors for unsafe fileMatches
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors if customManager fields are missing 1`] = `
+exports[`config/validation > validateConfig(config) > errors if customManager fields are missing 1`] = `
 [
   {
     "message": "Regex Managers must contain currentValueTemplate configuration or regex group named currentValue",
@@ -110,7 +110,7 @@ exports[`config/validation validateConfig(config) errors if customManager fields
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors if fileMatch has wrong parent 1`] = `
+exports[`config/validation > validateConfig(config) > errors if fileMatch has wrong parent 1`] = `
 [
   {
     "message": ""fileMatch" may not be defined at the top level of a config and must instead be within a manager block",
@@ -119,7 +119,7 @@ exports[`config/validation validateConfig(config) errors if fileMatch has wrong
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors if fileMatch has wrong parent 2`] = `
+exports[`config/validation > validateConfig(config) > errors if fileMatch has wrong parent 2`] = `
 [
   {
     "message": ""fileMatch" must be configured in a manager block and not here: npm.minor",
@@ -128,7 +128,7 @@ exports[`config/validation validateConfig(config) errors if fileMatch has wrong
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors if included not supported enabled managers for combined supported and not supported managers 1`] = `
+exports[`config/validation > validateConfig(config) > errors if included not supported enabled managers for combined supported and not supported managers 1`] = `
 [
   {
     "message": "The following managers configured in enabledManagers are not supported: "foo"",
@@ -137,7 +137,7 @@ exports[`config/validation validateConfig(config) errors if included not support
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors if included not supported enabled managers for multiple not supported managers 1`] = `
+exports[`config/validation > validateConfig(config) > errors if included not supported enabled managers for multiple not supported managers 1`] = `
 [
   {
     "message": "The following managers configured in enabledManagers are not supported: "foo, bar"",
@@ -146,7 +146,7 @@ exports[`config/validation validateConfig(config) errors if included not support
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors if included not supported enabled managers for single not supported manager 1`] = `
+exports[`config/validation > validateConfig(config) > errors if included not supported enabled managers for single not supported manager 1`] = `
 [
   {
     "message": "The following managers configured in enabledManagers are not supported: "foo"",
@@ -155,7 +155,7 @@ exports[`config/validation validateConfig(config) errors if included not support
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors if invalid combinations in packageRules 1`] = `
+exports[`config/validation > validateConfig(config) > errors if invalid combinations in packageRules 1`] = `
 [
   {
     "message": "packageRules[0]: packageRules cannot combine both matchUpdateTypes and registryUrls. Rule: {"matchUpdateTypes":["major"],"registryUrls":["https://registry.npmjs.org"]}",
@@ -164,7 +164,7 @@ exports[`config/validation validateConfig(config) errors if invalid combinations
 ]
 `;
 
-exports[`config/validation validateConfig(config) errors if manager objects are nested 1`] = `
+exports[`config/validation > validateConfig(config) > errors if manager objects are nested 1`] = `
 [
   {
     "message": "The "gradle" object can only be configured at the top level of a config but was found inside "maven"",
@@ -173,9 +173,9 @@ exports[`config/validation validateConfig(config) errors if manager objects are
 ]
 `;
 
-exports[`config/validation validateConfig(config) ignore packageRule nesting validation for presets 1`] = `[]`;
+exports[`config/validation > validateConfig(config) > ignore packageRule nesting validation for presets 1`] = `[]`;
 
-exports[`config/validation validateConfig(config) included managers of the wrong type 1`] = `
+exports[`config/validation > validateConfig(config) > included managers of the wrong type 1`] = `
 [
   {
     "message": "Configuration option \`packageRules[0].matchManagers\` should be a list (Array)",
@@ -188,7 +188,7 @@ exports[`config/validation validateConfig(config) included managers of the wrong
 ]
 `;
 
-exports[`config/validation validateConfig(config) returns deprecation warnings 1`] = `
+exports[`config/validation > validateConfig(config) > returns deprecation warnings 1`] = `
 [
   {
     "message": "Direct editing of prTitle is now deprecated. Please edit commitMessage subcomponents instead as they will be passed through to prTitle.",
@@ -197,7 +197,7 @@ exports[`config/validation validateConfig(config) returns deprecation warnings 1
 ]
 `;
 
-exports[`config/validation validateConfig(config) returns nested errors 1`] = `
+exports[`config/validation > validateConfig(config) > returns nested errors 1`] = `
 [
   {
     "message": "Invalid configuration option: foo",
@@ -218,7 +218,7 @@ exports[`config/validation validateConfig(config) returns nested errors 1`] = `
 ]
 `;
 
-exports[`config/validation validateConfig(config) selectors outside packageRules array trigger errors 1`] = `
+exports[`config/validation > validateConfig(config) > selectors outside packageRules array trigger errors 1`] = `
 [
   {
     "message": "ansible.minor.matchDepNames: matchDepNames should be inside a \`packageRule\` only",
@@ -239,7 +239,7 @@ exports[`config/validation validateConfig(config) selectors outside packageRules
 ]
 `;
 
-exports[`config/validation validateConfig(config) validates regEx for each fileMatch 1`] = `
+exports[`config/validation > validateConfig(config) > validates regEx for each fileMatch 1`] = `
 [
   {
     "message": "Invalid regExp for customManagers[0].fileMatch: \`***$}{]][\`",
@@ -248,7 +248,7 @@ exports[`config/validation validateConfig(config) validates regEx for each fileM
 ]
 `;
 
-exports[`config/validation validateConfig(config) warns if hostType has the wrong parent 1`] = `
+exports[`config/validation > validateConfig(config) > warns if hostType has the wrong parent 1`] = `
 [
   {
     "message": "hostType should only be configured within one of "hostRules" objects. Was found in .",
@@ -257,7 +257,7 @@ exports[`config/validation validateConfig(config) warns if hostType has the wron
 ]
 `;
 
-exports[`config/validation validateConfig(config) warns if only selectors in packageRules 1`] = `
+exports[`config/validation > validateConfig(config) > warns if only selectors in packageRules 1`] = `
 [
   {
     "message": "packageRules[0]: Each packageRule must contain at least one non-match* or non-exclude* field. Rule: {"matchDepTypes":["foo"],"matchPackageNames":["bar"]}",
diff --git a/lib/config/index.spec.ts b/lib/config/index.spec.ts
index 9cc5c378ba..a748d8066e 100644
--- a/lib/config/index.spec.ts
+++ b/lib/config/index.spec.ts
@@ -6,8 +6,8 @@ import {
   removeGlobalConfig,
 } from './index';
 
-jest.mock('../modules/datasource/npm');
-jest.mock('../../config.js', () => ({}), { virtual: true });
+vi.mock('../modules/datasource/npm');
+vi.mock('../../config.js', () => ({ default: {} }));
 
 const defaultConfig = getConfig();
 
diff --git a/lib/config/migration.spec.ts b/lib/config/migration.spec.ts
index dda9ba3229..ed14c5a97f 100644
--- a/lib/config/migration.spec.ts
+++ b/lib/config/migration.spec.ts
@@ -400,7 +400,7 @@ describe('config/migration', () => {
       expect(isMigrated).toBeTrue();
     });
 
-    it('it migrates preset strings to array', () => {
+    it('migrates preset strings to array', () => {
       let config: TestRenovateConfig;
       let res: MigratedConfig;
 
@@ -422,7 +422,7 @@ describe('config/migration', () => {
       });
     });
 
-    it('it migrates unpublishSafe', () => {
+    it('migrates unpublishSafe', () => {
       let config: TestRenovateConfig;
       let res: MigratedConfig;
 
@@ -505,7 +505,7 @@ describe('config/migration', () => {
       });
     });
 
-    it('it migrates packageRules', () => {
+    it('migrates packageRules', () => {
       const config: TestRenovateConfig = {
         packageRules: [
           {
@@ -575,7 +575,7 @@ describe('config/migration', () => {
     });
   });
 
-  it('it migrates nested packageRules', () => {
+  it('migrates nested packageRules', () => {
     const config: TestRenovateConfig = {
       packageRules: [
         {
@@ -605,7 +605,7 @@ describe('config/migration', () => {
     expect(migratedConfig.packageRules).toHaveLength(3);
   });
 
-  it('it migrates presets', () => {
+  it('migrates presets', () => {
     GlobalConfig.set({
       migratePresets: {
         '@org': 'local>org/renovate-config',
@@ -621,7 +621,7 @@ describe('config/migration', () => {
     expect(migratedConfig).toEqual({ extends: ['local>org/renovate-config'] });
   });
 
-  it('it migrates customManagers', () => {
+  it('migrates customManagers', () => {
     const config: RenovateConfig = {
       customManagers: [
         {
@@ -646,7 +646,7 @@ describe('config/migration', () => {
     expect(migratedConfig).toMatchSnapshot();
   });
 
-  it('it migrates pip-compile', () => {
+  it('migrates pip-compile', () => {
     const config: RenovateConfig = {
       'pip-compile': {
         enabled: true,
@@ -678,7 +678,7 @@ describe('config/migration', () => {
     });
   });
 
-  it('it migrates gradle-lite', () => {
+  it('migrates gradle-lite', () => {
     const config: RenovateConfig = {
       'gradle-lite': {
         enabled: true,
@@ -757,7 +757,7 @@ describe('config/migration', () => {
     });
   });
 
-  it('it migrates dryRun', () => {
+  it('migrates dryRun', () => {
     let config: TestRenovateConfig;
     let res: MigratedConfig;
 
diff --git a/lib/config/migrations/custom/extends-migration.spec.ts b/lib/config/migrations/custom/extends-migration.spec.ts
index bd521cba03..8d6a1c608e 100644
--- a/lib/config/migrations/custom/extends-migration.spec.ts
+++ b/lib/config/migrations/custom/extends-migration.spec.ts
@@ -2,7 +2,7 @@ import { GlobalConfig } from '../../global';
 import { ExtendsMigration } from './extends-migration';
 
 describe('config/migrations/custom/extends-migration', () => {
-  it('it migrates preset strings to array', () => {
+  it('migrates preset strings to array', () => {
     expect(ExtendsMigration).toMigrate(
       {
         extends: ':js-app',
@@ -22,7 +22,7 @@ describe('config/migrations/custom/extends-migration', () => {
     );
   });
 
-  it('it migrates presets array', () => {
+  it('migrates presets array', () => {
     expect(ExtendsMigration).toMigrate(
       {
         extends: ['foo', ':js-app', 'bar'],
@@ -55,7 +55,7 @@ describe('config/migrations/custom/extends-migration', () => {
     );
   });
 
-  it('it migrates presets', () => {
+  it('migrates presets', () => {
     GlobalConfig.set({
       migratePresets: {
         '@org': 'local>org/renovate-config',
diff --git a/lib/config/migrations/custom/go-mod-tidy-migration.spec.ts b/lib/config/migrations/custom/go-mod-tidy-migration.spec.ts
index 5a761299bd..4e869b82b6 100644
--- a/lib/config/migrations/custom/go-mod-tidy-migration.spec.ts
+++ b/lib/config/migrations/custom/go-mod-tidy-migration.spec.ts
@@ -13,7 +13,7 @@ describe('config/migrations/custom/go-mod-tidy-migration', () => {
     );
   });
 
-  it('should handle case when postUpdateOptions is not defined ', () => {
+  it('should handle case when postUpdateOptions is not defined', () => {
     expect(GoModTidyMigration).toMigrate(
       {
         gomodTidy: true,
diff --git a/lib/config/options/index.spec.ts b/lib/config/options/index.spec.ts
index 9302d8b77b..e0078e1f36 100644
--- a/lib/config/options/index.spec.ts
+++ b/lib/config/options/index.spec.ts
@@ -2,7 +2,7 @@ import * as manager from '../../modules/manager';
 import * as platform from '../../modules/platform';
 import { getOptions } from '.';
 
-jest.unmock('../../modules/platform');
+vi.unmock('../../modules/platform');
 
 describe('config/options/index', () => {
   it('test manager should have no defaultConfig', () => {
diff --git a/lib/config/presets/__snapshots__/index.spec.ts.snap b/lib/config/presets/__snapshots__/index.spec.ts.snap
index ce57b9dfbe..9576ba2645 100644
--- a/lib/config/presets/__snapshots__/index.spec.ts.snap
+++ b/lib/config/presets/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`config/presets/index getPreset gets linters 1`] = `
+exports[`config/presets/index > getPreset > gets linters 1`] = `
 {
   "description": [
     "All lint-related packages.",
@@ -20,13 +20,13 @@ exports[`config/presets/index getPreset gets linters 1`] = `
 }
 `;
 
-exports[`config/presets/index getPreset handles 404 packages 1`] = `undefined`;
+exports[`config/presets/index > getPreset > handles 404 packages 1`] = `undefined`;
 
-exports[`config/presets/index getPreset handles 404 packages 2`] = `undefined`;
+exports[`config/presets/index > getPreset > handles 404 packages 2`] = `undefined`;
 
-exports[`config/presets/index getPreset handles 404 packages 3`] = `undefined`;
+exports[`config/presets/index > getPreset > handles 404 packages 3`] = `undefined`;
 
-exports[`config/presets/index resolvePreset migrates automerge in presets 1`] = `
+exports[`config/presets/index > resolvePreset > migrates automerge in presets 1`] = `
 {
   "automergeType": "pr",
   "branchPrefix": "renovate/",
@@ -136,7 +136,7 @@ exports[`config/presets/index resolvePreset migrates automerge in presets 1`] =
 }
 `;
 
-exports[`config/presets/index resolvePreset resolves eslint 1`] = `
+exports[`config/presets/index > resolvePreset > resolves eslint 1`] = `
 {
   "matchPackageNames": [
     "@types/eslint",
@@ -153,7 +153,7 @@ exports[`config/presets/index resolvePreset resolves eslint 1`] = `
 }
 `;
 
-exports[`config/presets/index resolvePreset resolves linters 1`] = `
+exports[`config/presets/index > resolvePreset > resolves linters 1`] = `
 {
   "description": [
     "All lint-related packages.",
@@ -183,7 +183,7 @@ exports[`config/presets/index resolvePreset resolves linters 1`] = `
 }
 `;
 
-exports[`config/presets/index resolvePreset resolves nested groups 1`] = `
+exports[`config/presets/index > resolvePreset > resolves nested groups 1`] = `
 {
   "description": [
     "Update lint packages automatically if tests pass.",
@@ -221,7 +221,7 @@ exports[`config/presets/index resolvePreset resolves nested groups 1`] = `
 }
 `;
 
-exports[`config/presets/index resolvePreset resolves self-hosted presets without baseConfig 1`] = `
+exports[`config/presets/index > resolvePreset > resolves self-hosted presets without baseConfig 1`] = `
 {
   "labels": [
     "self-hosted resolved",
diff --git a/lib/config/presets/gitea/index.spec.ts b/lib/config/presets/gitea/index.spec.ts
index 3da1bb0a7c..888afb7b11 100644
--- a/lib/config/presets/gitea/index.spec.ts
+++ b/lib/config/presets/gitea/index.spec.ts
@@ -7,7 +7,7 @@ import { toBase64 } from '../../../util/string';
 import { PRESET_INVALID_JSON, PRESET_NOT_FOUND } from '../util';
 import * as gitea from '.';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 const hostRules = mocked(_hostRules);
 
diff --git a/lib/config/presets/github/index.spec.ts b/lib/config/presets/github/index.spec.ts
index b9ce54f571..623841f3c2 100644
--- a/lib/config/presets/github/index.spec.ts
+++ b/lib/config/presets/github/index.spec.ts
@@ -6,7 +6,7 @@ import { toBase64 } from '../../../util/string';
 import { PRESET_INVALID_JSON, PRESET_NOT_FOUND } from '../util';
 import * as github from '.';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 const hostRules = mocked(_hostRules);
 
diff --git a/lib/config/presets/index.spec.ts b/lib/config/presets/index.spec.ts
index 2cc78c86dc..fc9e14a60b 100644
--- a/lib/config/presets/index.spec.ts
+++ b/lib/config/presets/index.spec.ts
@@ -16,10 +16,10 @@ import {
 } from './util';
 import * as presets from '.';
 
-jest.mock('./npm');
-jest.mock('./github');
-jest.mock('./local');
-jest.mock('../../util/cache/package', () => mockDeep());
+vi.mock('./npm');
+vi.mock('./github');
+vi.mock('./local');
+vi.mock('../../util/cache/package', () => mockDeep());
 
 const npm = mocked(_npm);
 const local = mocked(_local);
diff --git a/lib/config/presets/internal/index.spec.ts b/lib/config/presets/internal/index.spec.ts
index 76f4d35725..e3dfbd4154 100644
--- a/lib/config/presets/internal/index.spec.ts
+++ b/lib/config/presets/internal/index.spec.ts
@@ -5,8 +5,8 @@ import { validateConfig } from '../../validation';
 import * as npm from '../npm';
 import * as internal from '.';
 
-jest.mock('../npm');
-jest.mock('../../../modules/datasource/npm');
+vi.mock('../npm');
+vi.mock('../../../modules/datasource/npm');
 
 jest.spyOn(npm, 'getPreset').mockResolvedValue(undefined);
 
diff --git a/lib/config/presets/local/index.spec.ts b/lib/config/presets/local/index.spec.ts
index 63596dcb2c..17490701a8 100644
--- a/lib/config/presets/local/index.spec.ts
+++ b/lib/config/presets/local/index.spec.ts
@@ -5,9 +5,9 @@ import * as _github from '../github';
 import * as _gitlab from '../gitlab';
 import * as local from '.';
 
-jest.mock('../gitea');
-jest.mock('../github');
-jest.mock('../gitlab');
+vi.mock('../gitea');
+vi.mock('../github');
+vi.mock('../gitlab');
 
 const gitea = mocked(_gitea);
 const github = mocked(_github);
diff --git a/lib/config/presets/util.spec.ts b/lib/config/presets/util.spec.ts
index d6d9f328be..847718adb6 100644
--- a/lib/config/presets/util.spec.ts
+++ b/lib/config/presets/util.spec.ts
@@ -43,6 +43,7 @@ describe('config/presets/util', () => {
     await expect(fetchPreset({ ...config, fetch })).rejects.toThrow('fails');
   });
 
+  // eslint-disable-next-line vitest/valid-title
   it(PRESET_DEP_NOT_FOUND, async () => {
     fetch.mockResolvedValueOnce(null);
     await expect(fetchPreset({ ...config, fetch })).rejects.toThrow(
@@ -56,6 +57,7 @@ describe('config/presets/util', () => {
     );
   });
 
+  // eslint-disable-next-line vitest/valid-title
   it(PRESET_NOT_FOUND, async () => {
     fetch.mockResolvedValueOnce({});
     await expect(
diff --git a/lib/constants/platform.spec.ts b/lib/constants/platform.spec.ts
index 8b8aee044a..79cdf8b247 100644
--- a/lib/constants/platform.spec.ts
+++ b/lib/constants/platform.spec.ts
@@ -40,11 +40,11 @@ describe('constants/platform', () => {
     expect(GITLAB_API_USING_HOST_TYPES.includes('gitlab')).toBeTrue();
   });
 
-  it('should be not part of the GITLAB_API_USING_HOST_TYPES ', () => {
+  it('should be not part of the GITLAB_API_USING_HOST_TYPES', () => {
     expect(GITLAB_API_USING_HOST_TYPES.includes('github')).toBeFalse();
   });
 
-  it('should be part of the GITHUB_API_USING_HOST_TYPES ', () => {
+  it('should be part of the GITHUB_API_USING_HOST_TYPES', () => {
     expect(
       GITHUB_API_USING_HOST_TYPES.includes(GithubTagsDatasource.id),
     ).toBeTrue();
@@ -61,11 +61,11 @@ describe('constants/platform', () => {
     expect(GITHUB_API_USING_HOST_TYPES.includes('github')).toBeTrue();
   });
 
-  it('should be not part of the GITHUB_API_USING_HOST_TYPES ', () => {
+  it('should be not part of the GITHUB_API_USING_HOST_TYPES', () => {
     expect(GITHUB_API_USING_HOST_TYPES.includes('gitlab')).toBeFalse();
   });
 
-  it('should be part of the BITBUCKET_API_USING_HOST_TYPES ', () => {
+  it('should be part of the BITBUCKET_API_USING_HOST_TYPES', () => {
     expect(
       BITBUCKET_API_USING_HOST_TYPES.includes(BitbucketTagsDatasource.id),
     ).toBeTrue();
diff --git a/lib/instrumentation/reporting.spec.ts b/lib/instrumentation/reporting.spec.ts
index 5800ec2d71..ea0e68d88f 100644
--- a/lib/instrumentation/reporting.spec.ts
+++ b/lib/instrumentation/reporting.spec.ts
@@ -1,5 +1,5 @@
 import type { S3Client } from '@aws-sdk/client-s3';
-import { mockDeep } from 'jest-mock-extended';
+import { mock, mockDeep } from 'vitest-mock-extended';
 import { s3 } from '../../test/s3';
 import { fs, logger } from '../../test/util';
 import type { RenovateConfig } from '../config/types';
@@ -16,9 +16,9 @@ import {
 } from './reporting';
 import type { Report } from './types';
 
-jest.mock('../util/fs', () => mockDeep());
-jest.mock('../util/s3', () => mockDeep());
-jest.mock('../logger', () => mockDeep());
+vi.mock('../util/fs', () => mockDeep());
+vi.mock('../util/s3', () => mockDeep());
+vi.mock('../logger', () => mockDeep());
 
 describe('instrumentation/reporting', () => {
   beforeEach(() => {
@@ -133,9 +133,8 @@ describe('instrumentation/reporting', () => {
   });
 
   it('send report to an S3 bucket if reportType is s3', async () => {
-    const mockClient = mockDeep<S3Client>();
+    const mockClient = mock<S3Client>();
     s3.parseS3Url.mockReturnValue({ Bucket: 'bucket-name', Key: 'key-name' });
-    // @ts-expect-error TS2589
     s3.getS3Client.mockReturnValue(mockClient);
 
     const config: RenovateConfig = {
diff --git a/lib/logger/__snapshots__/config-serializer.spec.ts.snap b/lib/logger/__snapshots__/config-serializer.spec.ts.snap
index 6afb07755f..bd6053b5b2 100644
--- a/lib/logger/__snapshots__/config-serializer.spec.ts.snap
+++ b/lib/logger/__snapshots__/config-serializer.spec.ts.snap
@@ -1,13 +1,13 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`logger/config-serializer squashes templates 1`] = `
+exports[`logger/config-serializer > squashes templates 1`] = `
 {
   "nottoken": "b",
   "prBody": "[Template]",
 }
 `;
 
-exports[`logger/config-serializer suppresses content 1`] = `
+exports[`logger/config-serializer > suppresses content 1`] = `
 {
   "content": "[content]",
 }
diff --git a/lib/logger/__snapshots__/err-serializer.spec.ts.snap b/lib/logger/__snapshots__/err-serializer.spec.ts.snap
index a0a1ff2a1a..0c52aefaf7 100644
--- a/lib/logger/__snapshots__/err-serializer.spec.ts.snap
+++ b/lib/logger/__snapshots__/err-serializer.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`logger/err-serializer got sanitize http error 1`] = `
+exports[`logger/err-serializer > got > sanitize http error 1`] = `
 {
   "code": "ERR_NON_2XX_3XX_RESPONSE",
   "message": "Response code 412 (Precondition Failed)",
diff --git a/lib/logger/index.spec.ts b/lib/logger/index.spec.ts
index 236e9a5408..fce2edf9be 100644
--- a/lib/logger/index.spec.ts
+++ b/lib/logger/index.spec.ts
@@ -22,8 +22,8 @@ import {
 
 const initialContext = 'initial_context';
 
-jest.unmock('.');
-jest.mock('nanoid', () => ({
+vi.unmock('.');
+vi.mock('nanoid', () => ({
   nanoid: () => 'initial_context',
 }));
 
diff --git a/lib/logger/once.spec.ts b/lib/logger/once.spec.ts
index 64523e2120..cddc4a752e 100644
--- a/lib/logger/once.spec.ts
+++ b/lib/logger/once.spec.ts
@@ -1,7 +1,7 @@
 import { once, reset } from './once';
 import { logger } from '.';
 
-jest.unmock('.');
+vi.unmock('.');
 
 describe('logger/once', () => {
   afterEach(() => {
diff --git a/lib/logger/pretty-stdout.spec.ts b/lib/logger/pretty-stdout.spec.ts
index 2f19c16dd4..16613d7dc7 100644
--- a/lib/logger/pretty-stdout.spec.ts
+++ b/lib/logger/pretty-stdout.spec.ts
@@ -2,12 +2,12 @@ import chalk from 'chalk';
 import * as prettyStdout from './pretty-stdout';
 import type { BunyanRecord } from './types';
 
-jest.mock('chalk', () =>
-  ['bgRed', 'blue', 'gray', 'green', 'magenta', 'red'].reduce(
+vi.mock('chalk', () => ({
+  default: ['bgRed', 'blue', 'gray', 'green', 'magenta', 'red'].reduce(
     (r, c) => Object.defineProperty(r, c, { value: (s: string) => s }),
     {},
   ),
-);
+}));
 
 describe('logger/pretty-stdout', () => {
   describe('getMeta(rec)', () => {
diff --git a/lib/modules/datasource/__snapshots__/metadata.spec.ts.snap b/lib/modules/datasource/__snapshots__/metadata.spec.ts.snap
index 3954823e05..e24c7d1ac9 100644
--- a/lib/modules/datasource/__snapshots__/metadata.spec.ts.snap
+++ b/lib/modules/datasource/__snapshots__/metadata.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/metadata Should handle failed parsing of sourceUrls for GitLab 1`] = `
+exports[`modules/datasource/metadata > Should handle failed parsing of sourceUrls for GitLab 1`] = `
 {
   "releases": [
     {
@@ -16,7 +16,7 @@ exports[`modules/datasource/metadata Should handle failed parsing of sourceUrls
 }
 `;
 
-exports[`modules/datasource/metadata Should handle failed parsing of sourceUrls for other 1`] = `
+exports[`modules/datasource/metadata > Should handle failed parsing of sourceUrls for other 1`] = `
 {
   "releases": [
     {
@@ -32,7 +32,7 @@ exports[`modules/datasource/metadata Should handle failed parsing of sourceUrls
 }
 `;
 
-exports[`modules/datasource/metadata Should handle manualChangelogUrls 1`] = `
+exports[`modules/datasource/metadata > Should handle manualChangelogUrls 1`] = `
 {
   "changelogUrl": "https://github.com/flyingcircusio/pycountry/blob/master/HISTORY.txt",
   "releases": [
@@ -57,7 +57,7 @@ exports[`modules/datasource/metadata Should handle manualChangelogUrls 1`] = `
 }
 `;
 
-exports[`modules/datasource/metadata Should handle manualSourceUrls 1`] = `
+exports[`modules/datasource/metadata > Should handle manualSourceUrls 1`] = `
 {
   "releases": [
     {
@@ -81,7 +81,7 @@ exports[`modules/datasource/metadata Should handle manualSourceUrls 1`] = `
 }
 `;
 
-exports[`modules/datasource/metadata Should handle non-url 1`] = `
+exports[`modules/datasource/metadata > Should handle non-url 1`] = `
 {
   "releases": [
     {
@@ -96,7 +96,7 @@ exports[`modules/datasource/metadata Should handle non-url 1`] = `
 }
 `;
 
-exports[`modules/datasource/metadata Should handle parsing of sourceUrls correctly 1`] = `
+exports[`modules/datasource/metadata > Should handle parsing of sourceUrls correctly 1`] = `
 {
   "releases": [
     {
@@ -120,7 +120,7 @@ exports[`modules/datasource/metadata Should handle parsing of sourceUrls correct
 }
 `;
 
-exports[`modules/datasource/metadata Should handle parsing of sourceUrls correctly for GitLab also 1`] = `
+exports[`modules/datasource/metadata > Should handle parsing of sourceUrls correctly for GitLab also 1`] = `
 {
   "releases": [
     {
@@ -136,7 +136,7 @@ exports[`modules/datasource/metadata Should handle parsing of sourceUrls correct
 }
 `;
 
-exports[`modules/datasource/metadata Should massage github sourceUrls 1`] = `
+exports[`modules/datasource/metadata > Should massage github sourceUrls 1`] = `
 {
   "releases": [
     {
diff --git a/lib/modules/datasource/artifactory/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/artifactory/__snapshots__/index.spec.ts.snap
index e32ed5639d..5863cff65c 100644
--- a/lib/modules/datasource/artifactory/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/artifactory/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/artifactory/index getReleases parses real data (files): without slash at the end 1`] = `
+exports[`modules/datasource/artifactory/index > getReleases > parses real data (files): without slash at the end 1`] = `
 {
   "registryUrl": "https://jfrog.company.com/artifactory",
   "releases": [
@@ -24,7 +24,7 @@ exports[`modules/datasource/artifactory/index getReleases parses real data (file
 }
 `;
 
-exports[`modules/datasource/artifactory/index getReleases parses real data (folders): with slash at the end 1`] = `
+exports[`modules/datasource/artifactory/index > getReleases > parses real data (folders): with slash at the end 1`] = `
 {
   "registryUrl": "https://jfrog.company.com/artifactory",
   "releases": [
@@ -48,7 +48,7 @@ exports[`modules/datasource/artifactory/index getReleases parses real data (fold
 }
 `;
 
-exports[`modules/datasource/artifactory/index getReleases parses real data (merge strategy with 2 registries) 1`] = `
+exports[`modules/datasource/artifactory/index > getReleases > parses real data (merge strategy with 2 registries) 1`] = `
 {
   "releases": [
     {
diff --git a/lib/modules/datasource/aws-machine-image/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/aws-machine-image/__snapshots__/index.spec.ts.snap
index 1f010f0236..3c199aa1da 100644
--- a/lib/modules/datasource/aws-machine-image/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/aws-machine-image/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/aws-machine-image/index getSortedAwsMachineImages() with 1 returned image 1`] = `
+exports[`modules/datasource/aws-machine-image/index > getSortedAwsMachineImages() > with 1 returned image 1`] = `
 [
   DescribeImagesCommand {
     "deserialize": [Function],
@@ -38,7 +38,7 @@ exports[`modules/datasource/aws-machine-image/index getSortedAwsMachineImages()
 ]
 `;
 
-exports[`modules/datasource/aws-machine-image/index getSortedAwsMachineImages() with 3 returned images 1`] = `
+exports[`modules/datasource/aws-machine-image/index > getSortedAwsMachineImages() > with 3 returned images 1`] = `
 [
   DescribeImagesCommand {
     "deserialize": [Function],
@@ -76,7 +76,7 @@ exports[`modules/datasource/aws-machine-image/index getSortedAwsMachineImages()
 ]
 `;
 
-exports[`modules/datasource/aws-machine-image/index getSortedAwsMachineImages() without returned images 1`] = `
+exports[`modules/datasource/aws-machine-image/index > getSortedAwsMachineImages() > without returned images 1`] = `
 [
   DescribeImagesCommand {
     "deserialize": [Function],
diff --git a/lib/modules/datasource/bitbucket-tags/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/bitbucket-tags/__snapshots__/index.spec.ts.snap
index c0451bf9a0..eb02e2c312 100644
--- a/lib/modules/datasource/bitbucket-tags/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/bitbucket-tags/__snapshots__/index.spec.ts.snap
@@ -1,8 +1,8 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/bitbucket-tags/index getDigest returns commits from bitbucket cloud 1`] = `"123"`;
+exports[`modules/datasource/bitbucket-tags/index > getDigest > returns commits from bitbucket cloud 1`] = `"123"`;
 
-exports[`modules/datasource/bitbucket-tags/index getReleases returns tags from bitbucket cloud 1`] = `
+exports[`modules/datasource/bitbucket-tags/index > getReleases > returns tags from bitbucket cloud 1`] = `
 {
   "registryUrl": "https://bitbucket.org",
   "releases": [
@@ -24,4 +24,4 @@ exports[`modules/datasource/bitbucket-tags/index getReleases returns tags from b
 }
 `;
 
-exports[`modules/datasource/bitbucket-tags/index getTagCommit returns tags commit hash from bitbucket cloud 1`] = `"123"`;
+exports[`modules/datasource/bitbucket-tags/index > getTagCommit > returns tags commit hash from bitbucket cloud 1`] = `"123"`;
diff --git a/lib/modules/datasource/cdnjs/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/cdnjs/__snapshots__/index.spec.ts.snap
index 322da077cc..6260a9555a 100644
--- a/lib/modules/datasource/cdnjs/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/cdnjs/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/cdnjs/index getReleases processes real data 1`] = `
+exports[`modules/datasource/cdnjs/index > getReleases > processes real data 1`] = `
 {
   "homepage": "https://d3js.org/d3-force/",
   "registryUrl": "https://api.cdnjs.com/",
diff --git a/lib/modules/datasource/clojure/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/clojure/__snapshots__/index.spec.ts.snap
index 3932a70b27..81ef27b00d 100644
--- a/lib/modules/datasource/clojure/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/clojure/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/clojure/index falls back to next registry url 1`] = `
+exports[`modules/datasource/clojure/index > falls back to next registry url 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
@@ -37,7 +37,7 @@ exports[`modules/datasource/clojure/index falls back to next registry url 1`] =
 }
 `;
 
-exports[`modules/datasource/clojure/index ignores unsupported protocols 1`] = `
+exports[`modules/datasource/clojure/index > ignores unsupported protocols 1`] = `
 [
   {
     "version": "0.0.1",
@@ -66,7 +66,7 @@ exports[`modules/datasource/clojure/index ignores unsupported protocols 1`] = `
 ]
 `;
 
-exports[`modules/datasource/clojure/index returns releases from custom repository 1`] = `
+exports[`modules/datasource/clojure/index > returns releases from custom repository 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
@@ -104,7 +104,7 @@ exports[`modules/datasource/clojure/index returns releases from custom repositor
 }
 `;
 
-exports[`modules/datasource/clojure/index skips registry with invalid XML 1`] = `
+exports[`modules/datasource/clojure/index > skips registry with invalid XML 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
@@ -141,7 +141,7 @@ exports[`modules/datasource/clojure/index skips registry with invalid XML 1`] =
 }
 `;
 
-exports[`modules/datasource/clojure/index skips registry with invalid metadata structure 1`] = `
+exports[`modules/datasource/clojure/index > skips registry with invalid metadata structure 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
diff --git a/lib/modules/datasource/conan/index.spec.ts b/lib/modules/datasource/conan/index.spec.ts
index 56c7faa5c1..cee4b0f831 100644
--- a/lib/modules/datasource/conan/index.spec.ts
+++ b/lib/modules/datasource/conan/index.spec.ts
@@ -244,7 +244,7 @@ describe('modules/datasource/conan/index', () => {
       ).toBeNull();
     });
 
-    it('it handles mismatched userAndChannel versioned data', async () => {
+    it('handles mismatched userAndChannel versioned data', async () => {
       httpMock
         .scope(nonDefaultRegistryUrl)
         .get('/v2/conans/search?q=poco')
diff --git a/lib/modules/datasource/conda/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/conda/__snapshots__/index.spec.ts.snap
index cb329bb396..c21f359ab6 100644
--- a/lib/modules/datasource/conda/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/conda/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/conda/index getReleases processes real data 1`] = `
+exports[`modules/datasource/conda/index > getReleases > processes real data 1`] = `
 {
   "homepage": "http://anaconda.org/anaconda/pytest",
   "registryUrl": "https://api.anaconda.org/package",
diff --git a/lib/modules/datasource/crate/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/crate/__snapshots__/index.spec.ts.snap
index 0470b48506..e03bc0d158 100644
--- a/lib/modules/datasource/crate/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/crate/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/crate/index getReleases clones cloudsmith private registry 1`] = `
+exports[`modules/datasource/crate/index > getReleases > clones cloudsmith private registry 1`] = `
 {
   "dependencyUrl": "https://cloudsmith.io/~myorg/repos/myrepo/packages/detail/cargo/mypkg",
   "registryUrl": "https://dl.cloudsmith.io/basic/myorg/myrepo/cargo/index.git",
@@ -15,7 +15,7 @@ exports[`modules/datasource/crate/index getReleases clones cloudsmith private re
 }
 `;
 
-exports[`modules/datasource/crate/index getReleases clones other private registry 1`] = `
+exports[`modules/datasource/crate/index > getReleases > clones other private registry 1`] = `
 {
   "dependencyUrl": "https://github.com/mcorbin/testregistry/mypkg",
   "registryUrl": "https://github.com/mcorbin/testregistry",
@@ -30,7 +30,7 @@ exports[`modules/datasource/crate/index getReleases clones other private registr
 }
 `;
 
-exports[`modules/datasource/crate/index getReleases processes real data: amethyst 1`] = `
+exports[`modules/datasource/crate/index > getReleases > processes real data: amethyst 1`] = `
 {
   "dependencyUrl": "https://crates.io/crates/amethyst",
   "homepage": "https://amethyst.rs/",
@@ -99,7 +99,7 @@ exports[`modules/datasource/crate/index getReleases processes real data: amethys
 }
 `;
 
-exports[`modules/datasource/crate/index getReleases processes real data: libc 1`] = `
+exports[`modules/datasource/crate/index > getReleases > processes real data: libc 1`] = `
 {
   "dependencyUrl": "https://crates.io/crates/libc",
   "registryUrl": "https://crates.io",
diff --git a/lib/modules/datasource/crate/index.spec.ts b/lib/modules/datasource/crate/index.spec.ts
index f5138c14b3..414c04b7ce 100644
--- a/lib/modules/datasource/crate/index.spec.ts
+++ b/lib/modules/datasource/crate/index.spec.ts
@@ -5,9 +5,11 @@ import _simpleGit from 'simple-git';
 import type { DirectoryResult } from 'tmp-promise';
 import { dir } from 'tmp-promise';
 import { dirname, join } from 'upath';
+import type { MockedFunction } from 'vitest';
 import { getPkgReleases } from '..';
 import { Fixtures } from '../../../../test/fixtures';
 import * as httpMock from '../../../../test/http-mock';
+import { partial } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
 import type { RepoGlobalConfig } from '../../../config/types';
 import { EXTERNAL_HOST_ERROR } from '../../../constants/error-messages';
@@ -15,8 +17,8 @@ import * as memCache from '../../../util/cache/memory';
 import type { RegistryInfo } from './types';
 import { CrateDatasource } from '.';
 
-jest.mock('simple-git');
-const simpleGit: jest.Mock<Partial<SimpleGit>> = _simpleGit as never;
+vi.mock('simple-git');
+const simpleGit = vi.mocked(_simpleGit);
 
 const API_BASE_URL = CrateDatasource.CRATES_IO_API_BASE_URL;
 
@@ -25,8 +27,10 @@ const baseUrl =
 
 const datasource = CrateDatasource.id;
 
-function setupGitMocks(delayMs?: number): { mockClone: jest.Mock<any, any> } {
-  const mockClone = jest
+function setupGitMocks(delayMs?: number): {
+  mockClone: MockedFunction<SimpleGit['clone']>;
+} {
+  const mockClone = vi
     .fn()
     .mockName('clone')
     .mockImplementation(
@@ -41,24 +45,25 @@ function setupGitMocks(delayMs?: number): { mockClone: jest.Mock<any, any> } {
       },
     );
 
-  simpleGit.mockReturnValue({
-    clone: mockClone,
-  });
-
+  simpleGit.mockReturnValue(partial<SimpleGit>({ clone: mockClone }));
   return { mockClone };
 }
 
-function setupErrorGitMock(): { mockClone: jest.Mock<any, any> } {
-  const mockClone = jest
+function setupErrorGitMock(): {
+  mockClone: MockedFunction<SimpleGit['clone']>;
+} {
+  const mockClone = vi
     .fn()
     .mockName('clone')
     .mockImplementation((_registryUrl: string, _clonePath: string, _opts) =>
       Promise.reject(new Error('mocked error')),
     );
 
-  simpleGit.mockReturnValue({
-    clone: mockClone,
-  });
+  simpleGit.mockReturnValue(
+    partial<SimpleGit>({
+      clone: mockClone,
+    }),
+  );
 
   return { mockClone };
 }
diff --git a/lib/modules/datasource/custom/index.spec.ts b/lib/modules/datasource/custom/index.spec.ts
index 62574bdf77..b7e0fb6663 100644
--- a/lib/modules/datasource/custom/index.spec.ts
+++ b/lib/modules/datasource/custom/index.spec.ts
@@ -6,7 +6,7 @@ import { fs } from '../../../../test/util';
 import { logger } from '../../../logger';
 import { CustomDatasource } from './index';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/datasource/custom/index', () => {
   describe('getReleases', () => {
diff --git a/lib/modules/datasource/dart/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/dart/__snapshots__/index.spec.ts.snap
index f3a5181107..8fd92440f1 100644
--- a/lib/modules/datasource/dart/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/dart/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/dart/index getReleases processes real data 1`] = `
+exports[`modules/datasource/dart/index > getReleases > processes real data 1`] = `
 {
   "homepage": "https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences",
   "registryUrl": "https://pub.dartlang.org",
diff --git a/lib/modules/datasource/docker/common.spec.ts b/lib/modules/datasource/docker/common.spec.ts
index 3c04dd9da9..5b2fa18498 100644
--- a/lib/modules/datasource/docker/common.spec.ts
+++ b/lib/modules/datasource/docker/common.spec.ts
@@ -17,7 +17,7 @@ const hostRules = mocked(_hostRules);
 
 const http = new Http(dockerDatasourceId);
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 describe('modules/datasource/docker/common', () => {
   describe('getRegistryRepository', () => {
diff --git a/lib/modules/datasource/docker/dockerhub-cache.spec.ts b/lib/modules/datasource/docker/dockerhub-cache.spec.ts
index 246863d46f..8c192c63ac 100644
--- a/lib/modules/datasource/docker/dockerhub-cache.spec.ts
+++ b/lib/modules/datasource/docker/dockerhub-cache.spec.ts
@@ -4,7 +4,7 @@ import type { DockerHubCacheData } from './dockerhub-cache';
 import { DockerHubCache } from './dockerhub-cache';
 import type { DockerHubTag } from './schema';
 
-jest.mock('../../../util/cache/package');
+vi.mock('../../../util/cache/package');
 const packageCache = mocked(_packageCache);
 
 function oldCacheData(): DockerHubCacheData {
diff --git a/lib/modules/datasource/docker/index.spec.ts b/lib/modules/datasource/docker/index.spec.ts
index f8940b9e2a..b66dddbce4 100644
--- a/lib/modules/datasource/docker/index.spec.ts
+++ b/lib/modules/datasource/docker/index.spec.ts
@@ -13,10 +13,10 @@ import * as _hostRules from '../../../util/host-rules';
 import { DockerDatasource } from '.';
 
 const hostRules = mocked(_hostRules);
-const googleAuth = mocked(_googleAuth);
+const googleAuth = vi.mocked(_googleAuth, true);
 
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('google-auth-library');
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('google-auth-library');
 
 const ecrMock = mockClient(ECRClient);
 
diff --git a/lib/modules/datasource/flutter-version/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/flutter-version/__snapshots__/index.spec.ts.snap
index 5e8bb1a96b..676c3c5192 100644
--- a/lib/modules/datasource/flutter-version/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/flutter-version/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/flutter-version/index getReleases processes real data 1`] = `
+exports[`modules/datasource/flutter-version/index > getReleases > processes real data 1`] = `
 {
   "homepage": "https://flutter.dev",
   "registryUrl": "https://storage.googleapis.com",
diff --git a/lib/modules/datasource/galaxy-collection/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/galaxy-collection/__snapshots__/index.spec.ts.snap
index 9bbc296329..2571df68e8 100644
--- a/lib/modules/datasource/galaxy-collection/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/galaxy-collection/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/galaxy-collection/index getReleases processes real data 1`] = `
+exports[`modules/datasource/galaxy-collection/index > getReleases > processes real data 1`] = `
 {
   "registryUrl": "https://galaxy.ansible.com/api",
   "releases": [
@@ -33,7 +33,7 @@ exports[`modules/datasource/galaxy-collection/index getReleases processes real d
 }
 `;
 
-exports[`modules/datasource/galaxy-collection/index getReleases processes real data with automation hub URL 1`] = `
+exports[`modules/datasource/galaxy-collection/index > getReleases > processes real data with automation hub URL 1`] = `
 {
   "registryUrl": "https://my.automationhub.local/api/galaxy/content/published",
   "releases": [
diff --git a/lib/modules/datasource/galaxy-collection/index.spec.ts b/lib/modules/datasource/galaxy-collection/index.spec.ts
index e0a53bc256..9b075e1a73 100644
--- a/lib/modules/datasource/galaxy-collection/index.spec.ts
+++ b/lib/modules/datasource/galaxy-collection/index.spec.ts
@@ -119,7 +119,7 @@ describe('modules/datasource/galaxy-collection/index', () => {
       ).toBeNull();
     });
 
-    it('returns null for null packageName ', async () => {
+    it('returns null for null packageName', async () => {
       expect(
         await getPkgReleases({
           datasource,
diff --git a/lib/modules/datasource/galaxy/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/galaxy/__snapshots__/index.spec.ts.snap
index 241b4b9f46..95dcfe2d09 100644
--- a/lib/modules/datasource/galaxy/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/galaxy/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/galaxy/index getReleases processes real data 1`] = `
+exports[`modules/datasource/galaxy/index > getReleases > processes real data 1`] = `
 {
   "dependencyUrl": "https://galaxy.ansible.com/yatesr/timezone",
   "registryUrl": "https://galaxy.ansible.com/",
diff --git a/lib/modules/datasource/git-refs/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/git-refs/__snapshots__/index.spec.ts.snap
index 5603dd7dc7..e8fe459d24 100644
--- a/lib/modules/datasource/git-refs/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/git-refs/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/git-refs/index getReleases returns versions filtered from tags 1`] = `
+exports[`modules/datasource/git-refs/index > getReleases > returns versions filtered from tags 1`] = `
 {
   "releases": [
     {
diff --git a/lib/modules/datasource/git-refs/index.spec.ts b/lib/modules/datasource/git-refs/index.spec.ts
index f5ff2c55de..9b5fee5754 100644
--- a/lib/modules/datasource/git-refs/index.spec.ts
+++ b/lib/modules/datasource/git-refs/index.spec.ts
@@ -1,12 +1,14 @@
 import type { SimpleGit } from 'simple-git';
 import { simpleGit } from 'simple-git';
+import type { MockProxy } from 'vitest-mock-extended';
+import { mock } from 'vitest-mock-extended';
 import { getPkgReleases } from '..';
 import { Fixtures } from '../../../../test/fixtures';
 import { add, clear } from '../../../util/host-rules';
 import { GitRefsDatasource } from '.';
 
-jest.mock('simple-git');
-const simpleGitFactoryMock = simpleGit as jest.Mock<Partial<SimpleGit>>;
+vi.mock('simple-git');
+const simpleGitFactoryMock = vi.mocked(simpleGit);
 
 const packageName = 'https://github.com/example/example.git';
 
@@ -15,7 +17,7 @@ const lsRemote1 = Fixtures.get('ls-remote-1.txt');
 const datasource = GitRefsDatasource.id;
 
 describe('modules/datasource/git-refs/index', () => {
-  let gitMock: jest.MockedObject<Pick<SimpleGit, 'env' | 'listRemote'>>;
+  let gitMock: MockProxy<SimpleGit>;
 
   beforeEach(() => {
     // clear host rules
@@ -25,13 +27,13 @@ describe('modules/datasource/git-refs/index', () => {
     process.env = {};
 
     // reset git mock
-    gitMock = {
-      env: jest.fn(),
-      listRemote: jest.fn(),
-    };
+    gitMock = mock<SimpleGit>({
+      env: vi.fn(),
+      listRemote: vi.fn(),
+    });
 
     simpleGitFactoryMock.mockReturnValue(gitMock);
-    gitMock.env.mockImplementation(() => gitMock as unknown as SimpleGit);
+    gitMock.env.mockReturnValue(gitMock);
   });
 
   describe('getReleases', () => {
diff --git a/lib/modules/datasource/git-tags/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/git-tags/__snapshots__/index.spec.ts.snap
index 28b3c82788..d844b417dd 100644
--- a/lib/modules/datasource/git-tags/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/git-tags/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/git-tags/index getReleases returns versions filtered from tags 1`] = `
+exports[`modules/datasource/git-tags/index > getReleases > returns versions filtered from tags 1`] = `
 {
   "releases": [
     {
diff --git a/lib/modules/datasource/git-tags/index.spec.ts b/lib/modules/datasource/git-tags/index.spec.ts
index 26370d9b75..16c85e2d6c 100644
--- a/lib/modules/datasource/git-tags/index.spec.ts
+++ b/lib/modules/datasource/git-tags/index.spec.ts
@@ -1,12 +1,14 @@
 import type { SimpleGit } from 'simple-git';
 import { simpleGit } from 'simple-git';
+import type { MockProxy } from 'vitest-mock-extended';
+import { mock } from 'vitest-mock-extended';
 import { getPkgReleases } from '..';
 import { Fixtures } from '../../../../test/fixtures';
 import { add, clear } from '../../../util/host-rules';
 import { GitTagsDatasource } from '.';
 
-jest.mock('simple-git');
-const simpleGitFactoryMock = simpleGit as jest.Mock<Partial<SimpleGit>>;
+vi.mock('simple-git');
+const simpleGitFactoryMock = vi.mocked(simpleGit);
 
 const packageName = 'https://github.com/example/example.git';
 
@@ -16,7 +18,7 @@ const datasource = GitTagsDatasource.id;
 const datasourceInstance = new GitTagsDatasource();
 
 describe('modules/datasource/git-tags/index', () => {
-  let gitMock: jest.MockedObject<Pick<SimpleGit, 'env' | 'listRemote'>>;
+  let gitMock: MockProxy<SimpleGit>;
 
   beforeEach(() => {
     // clear host rules
@@ -26,13 +28,13 @@ describe('modules/datasource/git-tags/index', () => {
     process.env = {};
 
     // reset git mock
-    gitMock = {
-      env: jest.fn(),
-      listRemote: jest.fn(),
-    };
+    gitMock = mock<SimpleGit>({
+      env: vi.fn(),
+      listRemote: vi.fn(),
+    });
 
     simpleGitFactoryMock.mockReturnValue(gitMock);
-    gitMock.env.mockImplementation(() => gitMock as unknown as SimpleGit);
+    gitMock.env.mockReturnValue(gitMock);
   });
 
   describe('getReleases', () => {
diff --git a/lib/modules/datasource/github-release-attachments/index.spec.ts b/lib/modules/datasource/github-release-attachments/index.spec.ts
index 02872612d4..8661db780d 100644
--- a/lib/modules/datasource/github-release-attachments/index.spec.ts
+++ b/lib/modules/datasource/github-release-attachments/index.spec.ts
@@ -7,7 +7,7 @@ import type { Timestamp } from '../../../util/timestamp';
 import { GitHubReleaseAttachmentMocker } from './test';
 import { GithubReleaseAttachmentsDatasource } from '.';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 const hostRules = mocked(_hostRules);
 
 const githubApiHost = 'https://api.github.com';
diff --git a/lib/modules/datasource/github-releases/index.spec.ts b/lib/modules/datasource/github-releases/index.spec.ts
index fbd1f962a9..88a9246563 100644
--- a/lib/modules/datasource/github-releases/index.spec.ts
+++ b/lib/modules/datasource/github-releases/index.spec.ts
@@ -6,7 +6,7 @@ import * as _hostRules from '../../../util/host-rules';
 import type { Timestamp } from '../../../util/timestamp';
 import { GithubReleasesDatasource } from '.';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 const hostRules = mocked(_hostRules);
 
 describe('modules/datasource/github-releases/index', () => {
diff --git a/lib/modules/datasource/gitlab-packages/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/gitlab-packages/__snapshots__/index.spec.ts.snap
index 55b594d148..dabdb21e3e 100644
--- a/lib/modules/datasource/gitlab-packages/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/gitlab-packages/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/gitlab-packages/index getReleases returns package from custom registry 1`] = `
+exports[`modules/datasource/gitlab-packages/index > getReleases > returns package from custom registry 1`] = `
 {
   "registryUrl": "https://gitlab.com",
   "releases": [
diff --git a/lib/modules/datasource/gitlab-releases/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/gitlab-releases/__snapshots__/index.spec.ts.snap
index 2e55d62fdd..7a42356904 100644
--- a/lib/modules/datasource/gitlab-releases/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/gitlab-releases/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/gitlab-releases/index getReleases returns releases from custom registry 1`] = `
+exports[`modules/datasource/gitlab-releases/index > getReleases > returns releases from custom registry 1`] = `
 {
   "registryUrl": "https://gitlab.company.com",
   "releases": [
@@ -21,7 +21,7 @@ exports[`modules/datasource/gitlab-releases/index getReleases returns releases f
 }
 `;
 
-exports[`modules/datasource/gitlab-releases/index getReleases returns releases from default registry 1`] = `
+exports[`modules/datasource/gitlab-releases/index > getReleases > returns releases from default registry 1`] = `
 {
   "registryUrl": "https://gitlab.com",
   "releases": [
diff --git a/lib/modules/datasource/gitlab-tags/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/gitlab-tags/__snapshots__/index.spec.ts.snap
index 7ebed1ecf4..433a4a95fe 100644
--- a/lib/modules/datasource/gitlab-tags/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/gitlab-tags/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/gitlab-tags/index getReleases returns tags from custom registry 1`] = `
+exports[`modules/datasource/gitlab-tags/index > getReleases > returns tags from custom registry 1`] = `
 {
   "registryUrl": "https://gitlab.company.com/api/v4",
   "releases": [
@@ -22,7 +22,7 @@ exports[`modules/datasource/gitlab-tags/index getReleases returns tags from cust
 }
 `;
 
-exports[`modules/datasource/gitlab-tags/index getReleases returns tags from custom registry in sub path 1`] = `
+exports[`modules/datasource/gitlab-tags/index > getReleases > returns tags from custom registry in sub path 1`] = `
 {
   "registryUrl": "https://my.company.com/gitlab",
   "releases": [
@@ -44,7 +44,7 @@ exports[`modules/datasource/gitlab-tags/index getReleases returns tags from cust
 }
 `;
 
-exports[`modules/datasource/gitlab-tags/index getReleases returns tags with default registry 1`] = `
+exports[`modules/datasource/gitlab-tags/index > getReleases > returns tags with default registry 1`] = `
 {
   "registryUrl": "https://gitlab.com",
   "releases": [
diff --git a/lib/modules/datasource/go/__snapshots__/releases-direct.spec.ts.snap b/lib/modules/datasource/go/__snapshots__/releases-direct.spec.ts.snap
index d70e507a08..c53640dffd 100644
--- a/lib/modules/datasource/go/__snapshots__/releases-direct.spec.ts.snap
+++ b/lib/modules/datasource/go/__snapshots__/releases-direct.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/go/releases-direct getReleases support bitbucket tags 1`] = `
+exports[`modules/datasource/go/releases-direct > getReleases > support bitbucket tags 1`] = `
 {
   "registryUrl": "https://bitbucket.org",
   "releases": [
@@ -19,7 +19,7 @@ exports[`modules/datasource/go/releases-direct getReleases support bitbucket tag
 }
 `;
 
-exports[`modules/datasource/go/releases-direct getReleases support git 1`] = `
+exports[`modules/datasource/go/releases-direct > getReleases > support git 1`] = `
 {
   "releases": [
     {
@@ -35,7 +35,7 @@ exports[`modules/datasource/go/releases-direct getReleases support git 1`] = `
 }
 `;
 
-exports[`modules/datasource/go/releases-direct getReleases support gitlab 1`] = `
+exports[`modules/datasource/go/releases-direct > getReleases > support gitlab 1`] = `
 {
   "releases": [
     {
@@ -53,7 +53,7 @@ exports[`modules/datasource/go/releases-direct getReleases support gitlab 1`] =
 }
 `;
 
-exports[`modules/datasource/go/releases-direct getReleases support gitlab subgroups 1`] = `
+exports[`modules/datasource/go/releases-direct > getReleases > support gitlab subgroups 1`] = `
 {
   "releases": [
     {
@@ -71,7 +71,7 @@ exports[`modules/datasource/go/releases-direct getReleases support gitlab subgro
 }
 `;
 
-exports[`modules/datasource/go/releases-direct getReleases support self hosted gitlab private repositories 1`] = `
+exports[`modules/datasource/go/releases-direct > getReleases > support self hosted gitlab private repositories 1`] = `
 {
   "releases": [
     {
diff --git a/lib/modules/datasource/go/base.spec.ts b/lib/modules/datasource/go/base.spec.ts
index e425fae586..343b53ecc1 100644
--- a/lib/modules/datasource/go/base.spec.ts
+++ b/lib/modules/datasource/go/base.spec.ts
@@ -9,7 +9,7 @@ import { GithubTagsDatasource } from '../github-tags';
 import { GitlabTagsDatasource } from '../gitlab-tags';
 import { BaseGoDatasource } from './base';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 const hostRules = mocked(_hostRules);
 
@@ -120,7 +120,6 @@ describe('modules/datasource/go/base', () => {
         });
       });
 
-      // eslint-disable-next-line jest/no-disabled-tests
       it.skip('supports Go submodules in GitLab repo', async () => {
         httpMock
           .scope('https://gitlab.com')
@@ -503,7 +502,7 @@ describe('modules/datasource/go/base', () => {
         expect(res).toBeNull();
       });
 
-      it('it correctly splits a URL where the endpoint is contained', async () => {
+      it('correctly splits a URL where the endpoint is contained', async () => {
         hostRules.hostType.mockReturnValue('gitlab');
 
         GlobalConfig.set({ endpoint: 'https://example.com/gitlab/api/v4/' });
diff --git a/lib/modules/datasource/go/index.spec.ts b/lib/modules/datasource/go/index.spec.ts
index 6099b6fbb6..63bc29cacf 100644
--- a/lib/modules/datasource/go/index.spec.ts
+++ b/lib/modules/datasource/go/index.spec.ts
@@ -5,7 +5,7 @@ import { mocked } from '../../../../test/util';
 import * as _hostRules from '../../../util/host-rules';
 import { GoDatasource } from '.';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 const hostRules = mocked(_hostRules);
 
 const getReleasesDirectMock = jest.fn();
@@ -15,7 +15,7 @@ const getDigestGithubMock = jest.fn();
 const getDigestGitlabMock = jest.fn();
 const getDigestGitMock = jest.fn();
 const getDigestBitbucketMock = jest.fn();
-jest.mock('./releases-direct', () => {
+vi.mock('./releases-direct', () => {
   return {
     GoDirectDatasource: jest.fn().mockImplementation(() => {
       return {
@@ -33,7 +33,7 @@ jest.mock('./releases-direct', () => {
 });
 
 const getReleasesProxyMock = jest.fn();
-jest.mock('./releases-goproxy', () => {
+vi.mock('./releases-goproxy', () => {
   return {
     GoProxyDatasource: jest.fn().mockImplementation(() => {
       return {
diff --git a/lib/modules/datasource/go/releases-direct.spec.ts b/lib/modules/datasource/go/releases-direct.spec.ts
index c63003fa54..7332a8a1f5 100644
--- a/lib/modules/datasource/go/releases-direct.spec.ts
+++ b/lib/modules/datasource/go/releases-direct.spec.ts
@@ -7,8 +7,8 @@ import { GithubTagsDatasource } from '../github-tags';
 import { BaseGoDatasource } from './base';
 import { GoDirectDatasource } from './releases-direct';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('./base');
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('./base');
 
 const datasource = new GoDirectDatasource();
 const getDatasourceSpy = jest.spyOn(BaseGoDatasource, 'getDatasource');
diff --git a/lib/modules/datasource/go/releases-goproxy.spec.ts b/lib/modules/datasource/go/releases-goproxy.spec.ts
index 70c5287f7b..4ec469adc8 100644
--- a/lib/modules/datasource/go/releases-goproxy.spec.ts
+++ b/lib/modules/datasource/go/releases-goproxy.spec.ts
@@ -9,7 +9,7 @@ import { GithubTagsDatasource } from '../github-tags';
 import { GoProxyDatasource } from './releases-goproxy';
 
 const hostRules = mocked(_hostRules);
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 const datasource = new GoProxyDatasource();
 
@@ -205,13 +205,13 @@ describe('modules/datasource/go/releases-goproxy', () => {
       });
     });
 
-    it.each<{ abortOnError: boolean }>`
+    it.each`
       abortOnError
       ${true}
       ${false}
     `(
       'handles pipe fallback when abortOnError is $abortOnError',
-      async ({ abortOnError }) => {
+      async ({ abortOnError }: { abortOnError: boolean }) => {
         process.env.GOPROXY = `https://example.com|${baseUrl}`;
         hostRules.find.mockReturnValue({ abortOnError });
 
@@ -424,13 +424,13 @@ describe('modules/datasource/go/releases-goproxy', () => {
       });
     });
 
-    it.each<{ abortOnError: boolean }>`
+    it.each`
       abortOnError
       ${true}
       ${false}
     `(
       'handles major releases with abortOnError is $abortOnError',
-      async ({ abortOnError }) => {
+      async ({ abortOnError }: { abortOnError: boolean }) => {
         process.env.GOPROXY = baseUrl;
         hostRules.find.mockReturnValue({ abortOnError });
 
diff --git a/lib/modules/datasource/golang-version/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/golang-version/__snapshots__/index.spec.ts.snap
index e9d8dcc195..464da1c18f 100644
--- a/lib/modules/datasource/golang-version/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/golang-version/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/golang-version/index getReleases parses real data 1`] = `
+exports[`modules/datasource/golang-version/index > getReleases > parses real data 1`] = `
 {
   "homepage": "https://go.dev/",
   "registryUrl": "https://raw.githubusercontent.com/golang/website",
diff --git a/lib/modules/datasource/golang-version/index.spec.ts b/lib/modules/datasource/golang-version/index.spec.ts
index 846d731c16..89cc432584 100644
--- a/lib/modules/datasource/golang-version/index.spec.ts
+++ b/lib/modules/datasource/golang-version/index.spec.ts
@@ -119,7 +119,7 @@ describe('modules/datasource/golang-version/index', () => {
       ).toBeNull();
     });
 
-    it('throws ExternalHostError for invalid release format beginning ', async () => {
+    it('throws ExternalHostError for invalid release format beginning', async () => {
       httpMock
         .scope('https://raw.githubusercontent.com')
         .get('/golang/website/HEAD/internal/history/release.go')
diff --git a/lib/modules/datasource/gradle-version/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/gradle-version/__snapshots__/index.spec.ts.snap
index 22da4774e1..fa3c24ab22 100644
--- a/lib/modules/datasource/gradle-version/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/gradle-version/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/gradle-version/index getReleases calls configured registryUrls 1`] = `
+exports[`modules/datasource/gradle-version/index > getReleases > calls configured registryUrls 1`] = `
 {
   "homepage": "https://gradle.org",
   "releases": [
@@ -1820,7 +1820,7 @@ exports[`modules/datasource/gradle-version/index getReleases calls configured re
 }
 `;
 
-exports[`modules/datasource/gradle-version/index getReleases processes real data 1`] = `
+exports[`modules/datasource/gradle-version/index > getReleases > processes real data 1`] = `
 {
   "homepage": "https://gradle.org",
   "registryUrl": "https://services.gradle.org/versions/all",
diff --git a/lib/modules/datasource/helm/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/helm/__snapshots__/index.spec.ts.snap
index efb2f69833..26bec25b3a 100644
--- a/lib/modules/datasource/helm/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/helm/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/helm/index getReleases returns list of versions for normal response 1`] = `
+exports[`modules/datasource/helm/index > getReleases > returns list of versions for normal response 1`] = `
 {
   "homepage": "https://www.getambassador.io/",
   "registryUrl": "https://example-repository.com",
diff --git a/lib/modules/datasource/hex/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/hex/__snapshots__/index.spec.ts.snap
index c03ac339be..ac67c0b45e 100644
--- a/lib/modules/datasource/hex/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/hex/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/hex/index getReleases process public repo without auth 1`] = `
+exports[`modules/datasource/hex/index > getReleases > process public repo without auth 1`] = `
 {
   "homepage": "https://hex.pm/packages/certifi",
   "registryUrl": "https://hex.pm",
@@ -90,7 +90,7 @@ exports[`modules/datasource/hex/index getReleases process public repo without au
 }
 `;
 
-exports[`modules/datasource/hex/index getReleases processes a private repo with auth 1`] = `
+exports[`modules/datasource/hex/index > getReleases > processes a private repo with auth 1`] = `
 {
   "homepage": "https://hex.pm/packages/renovate_test/private_package",
   "registryUrl": "https://hex.pm",
@@ -108,7 +108,7 @@ exports[`modules/datasource/hex/index getReleases processes a private repo with
 }
 `;
 
-exports[`modules/datasource/hex/index getReleases processes real data 1`] = `
+exports[`modules/datasource/hex/index > getReleases > processes real data 1`] = `
 {
   "homepage": "https://hex.pm/packages/certifi",
   "registryUrl": "https://hex.pm",
diff --git a/lib/modules/datasource/hex/index.spec.ts b/lib/modules/datasource/hex/index.spec.ts
index 49e01abacd..bf9fab0ae0 100644
--- a/lib/modules/datasource/hex/index.spec.ts
+++ b/lib/modules/datasource/hex/index.spec.ts
@@ -9,7 +9,7 @@ import { HexDatasource } from '.';
 const certifiResponse = Fixtures.get('certifi.json');
 const privatePackageResponse = Fixtures.get('private_package.json');
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 const baseUrl = 'https://hex.pm/api';
 const datasource = HexDatasource.id;
diff --git a/lib/modules/datasource/index.spec.ts b/lib/modules/datasource/index.spec.ts
index 6a1455c339..391ec67598 100644
--- a/lib/modules/datasource/index.spec.ts
+++ b/lib/modules/datasource/index.spec.ts
@@ -118,7 +118,7 @@ class DummyDatasource5 extends Datasource {
   }
 }
 
-jest.mock('./metadata-manual', () => ({
+vi.mock('./metadata-manual', () => ({
   manualChangelogUrls: {
     dummy: {
       package: 'https://foo.bar/package/CHANGELOG.md',
@@ -131,8 +131,8 @@ jest.mock('./metadata-manual', () => ({
   },
 }));
 
-jest.mock('../../util/cache/package');
-const packageCache = _packageCache as jest.Mocked<typeof _packageCache>;
+vi.mock('../../util/cache/package');
+const packageCache = vi.mocked(_packageCache);
 
 describe('modules/datasource/index', () => {
   afterEach(() => {
@@ -159,7 +159,7 @@ describe('modules/datasource/index', () => {
       expect(getDatasourceList()).toEqual(managerList);
     });
 
-    it('validates datasource', () => {
+    it('validates datasource', async () => {
       function validateDatasource(
         module: DatasourceApi,
         name: string,
@@ -182,7 +182,7 @@ describe('modules/datasource/index', () => {
         }
       }
 
-      const loadedDs = loadModules(
+      const loadedDs = await loadModules(
         __dirname,
         validateDatasource,
         filterClassBasedDatasources,
diff --git a/lib/modules/datasource/java-version/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/java-version/__snapshots__/index.spec.ts.snap
index 77d3898dab..6e56982f4f 100644
--- a/lib/modules/datasource/java-version/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/java-version/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/java-version/index getReleases pages 1`] = `
+exports[`modules/datasource/java-version/index > getReleases > pages 1`] = `
 {
   "homepage": "https://adoptium.net",
   "registryUrl": "https://api.adoptium.net/",
@@ -159,7 +159,7 @@ exports[`modules/datasource/java-version/index getReleases pages 1`] = `
 }
 `;
 
-exports[`modules/datasource/java-version/index getReleases processes real data (jre) 1`] = `
+exports[`modules/datasource/java-version/index > getReleases > processes real data (jre) 1`] = `
 {
   "homepage": "https://adoptium.net",
   "registryUrl": "https://api.adoptium.net/",
@@ -174,7 +174,7 @@ exports[`modules/datasource/java-version/index getReleases processes real data (
 }
 `;
 
-exports[`modules/datasource/java-version/index getReleases processes real data 1`] = `
+exports[`modules/datasource/java-version/index > getReleases > processes real data 1`] = `
 {
   "homepage": "https://adoptium.net",
   "registryUrl": "https://api.adoptium.net/",
diff --git a/lib/modules/datasource/maven/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/maven/__snapshots__/index.spec.ts.snap
index 434320c691..13f78914c0 100644
--- a/lib/modules/datasource/maven/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/maven/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/maven/index falls back to next registry url 1`] = `
+exports[`modules/datasource/maven/index > falls back to next registry url 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
@@ -37,7 +37,7 @@ exports[`modules/datasource/maven/index falls back to next registry url 1`] = `
 }
 `;
 
-exports[`modules/datasource/maven/index ignores unsupported protocols 1`] = `
+exports[`modules/datasource/maven/index > ignores unsupported protocols 1`] = `
 [
   {
     "version": "0.0.1",
@@ -66,7 +66,7 @@ exports[`modules/datasource/maven/index ignores unsupported protocols 1`] = `
 ]
 `;
 
-exports[`modules/datasource/maven/index removes authentication header after redirect 1`] = `
+exports[`modules/datasource/maven/index > removes authentication header after redirect 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
@@ -104,7 +104,7 @@ exports[`modules/datasource/maven/index removes authentication header after redi
 }
 `;
 
-exports[`modules/datasource/maven/index returns releases 1`] = `
+exports[`modules/datasource/maven/index > returns releases 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
@@ -141,7 +141,7 @@ exports[`modules/datasource/maven/index returns releases 1`] = `
 }
 `;
 
-exports[`modules/datasource/maven/index returns releases from custom repository 1`] = `
+exports[`modules/datasource/maven/index > returns releases from custom repository 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
@@ -179,7 +179,7 @@ exports[`modules/datasource/maven/index returns releases from custom repository
 }
 `;
 
-exports[`modules/datasource/maven/index skips registry with invalid XML 1`] = `
+exports[`modules/datasource/maven/index > skips registry with invalid XML 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
@@ -216,7 +216,7 @@ exports[`modules/datasource/maven/index skips registry with invalid XML 1`] = `
 }
 `;
 
-exports[`modules/datasource/maven/index skips registry with invalid metadata structure 1`] = `
+exports[`modules/datasource/maven/index > skips registry with invalid metadata structure 1`] = `
 {
   "display": "org.example:package",
   "group": "org.example",
diff --git a/lib/modules/datasource/maven/index.spec.ts b/lib/modules/datasource/maven/index.spec.ts
index d8d903184d..fa8b39580c 100644
--- a/lib/modules/datasource/maven/index.spec.ts
+++ b/lib/modules/datasource/maven/index.spec.ts
@@ -16,7 +16,7 @@ import { MAVEN_REPO } from './common';
 import { MavenDatasource } from '.';
 
 const googleAuth = mocked(_googleAuth);
-jest.mock('google-auth-library');
+vi.mock('google-auth-library');
 
 const datasource = MavenDatasource.id;
 
diff --git a/lib/modules/datasource/node-version/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/node-version/__snapshots__/index.spec.ts.snap
index e5eefdf530..30cab111d4 100644
--- a/lib/modules/datasource/node-version/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/node-version/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/node-version/index getReleases processes real data 1`] = `
+exports[`modules/datasource/node-version/index > getReleases > processes real data 1`] = `
 {
   "homepage": "https://nodejs.org",
   "registryUrl": "https://nodejs.org/dist",
diff --git a/lib/modules/datasource/npm/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/npm/__snapshots__/index.spec.ts.snap
index 643d0d75ba..ebdec15fcc 100644
--- a/lib/modules/datasource/npm/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/npm/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/npm/index should fetch package info from custom registry 1`] = `
+exports[`modules/datasource/npm/index > should fetch package info from custom registry 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://npm.mycustomregistry.com",
@@ -28,7 +28,7 @@ exports[`modules/datasource/npm/index should fetch package info from custom regi
 }
 `;
 
-exports[`modules/datasource/npm/index should fetch package info from npm 1`] = `
+exports[`modules/datasource/npm/index > should fetch package info from npm 1`] = `
 {
   "isPrivate": false,
   "registryUrl": "https://registry.npmjs.org",
@@ -56,7 +56,7 @@ exports[`modules/datasource/npm/index should fetch package info from npm 1`] = `
 }
 `;
 
-exports[`modules/datasource/npm/index should handle foobar 1`] = `
+exports[`modules/datasource/npm/index > should handle foobar 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://registry.npmjs.org",
@@ -84,7 +84,7 @@ exports[`modules/datasource/npm/index should handle foobar 1`] = `
 }
 `;
 
-exports[`modules/datasource/npm/index should handle no time 1`] = `
+exports[`modules/datasource/npm/index > should handle no time 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://registry.npmjs.org",
@@ -111,7 +111,7 @@ exports[`modules/datasource/npm/index should handle no time 1`] = `
 }
 `;
 
-exports[`modules/datasource/npm/index should not send an authorization header if public package 1`] = `
+exports[`modules/datasource/npm/index > should not send an authorization header if public package 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://registry.npmjs.org",
@@ -139,7 +139,7 @@ exports[`modules/datasource/npm/index should not send an authorization header if
 }
 `;
 
-exports[`modules/datasource/npm/index should parse repo url (string) 1`] = `
+exports[`modules/datasource/npm/index > should parse repo url (string) 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://registry.npmjs.org",
@@ -159,7 +159,7 @@ exports[`modules/datasource/npm/index should parse repo url (string) 1`] = `
 }
 `;
 
-exports[`modules/datasource/npm/index should parse repo url 1`] = `
+exports[`modules/datasource/npm/index > should parse repo url 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://registry.npmjs.org",
@@ -179,7 +179,7 @@ exports[`modules/datasource/npm/index should parse repo url 1`] = `
 }
 `;
 
-exports[`modules/datasource/npm/index should replace any environment variable in npmrc 1`] = `
+exports[`modules/datasource/npm/index > should replace any environment variable in npmrc 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://registry.from-env.com",
@@ -207,7 +207,7 @@ exports[`modules/datasource/npm/index should replace any environment variable in
 }
 `;
 
-exports[`modules/datasource/npm/index should return deprecated 1`] = `
+exports[`modules/datasource/npm/index > should return deprecated 1`] = `
 {
   "deprecationMessage": "On registry \`https://registry.npmjs.org\`, the "latest" version of dependency \`foobar\` has the following deprecation notice:
 
@@ -241,7 +241,7 @@ Marking the latest version of an npm package as deprecated results in the entire
 }
 `;
 
-exports[`modules/datasource/npm/index should return deprecated 2`] = `
+exports[`modules/datasource/npm/index > should return deprecated 2`] = `
 "On registry \`https://registry.npmjs.org\`, the "latest" version of dependency \`foobar\` has the following deprecation notice:
 
 \`This is deprecated\`
@@ -249,7 +249,7 @@ exports[`modules/datasource/npm/index should return deprecated 2`] = `
 Marking the latest version of an npm package as deprecated results in the entire package being considered deprecated, so contact the package author you think this is a mistake."
 `;
 
-exports[`modules/datasource/npm/index should send an authorization header if provided 1`] = `
+exports[`modules/datasource/npm/index > should send an authorization header if provided 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://registry.npmjs.org",
@@ -277,7 +277,7 @@ exports[`modules/datasource/npm/index should send an authorization header if pro
 }
 `;
 
-exports[`modules/datasource/npm/index should use default registry if missing from npmrc 1`] = `
+exports[`modules/datasource/npm/index > should use default registry if missing from npmrc 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://registry.npmjs.org",
@@ -305,7 +305,7 @@ exports[`modules/datasource/npm/index should use default registry if missing fro
 }
 `;
 
-exports[`modules/datasource/npm/index should use host rules by baseUrl if provided 1`] = `
+exports[`modules/datasource/npm/index > should use host rules by baseUrl if provided 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://npm.mycustomregistry.com/_packaging/mycustomregistry/npm/registry",
@@ -333,7 +333,7 @@ exports[`modules/datasource/npm/index should use host rules by baseUrl if provid
 }
 `;
 
-exports[`modules/datasource/npm/index should use host rules by hostName if provided 1`] = `
+exports[`modules/datasource/npm/index > should use host rules by hostName if provided 1`] = `
 {
   "isPrivate": true,
   "registryUrl": "https://npm.mycustomregistry.com",
diff --git a/lib/modules/datasource/npm/get.spec.ts b/lib/modules/datasource/npm/get.spec.ts
index 7479a06063..202158a06e 100644
--- a/lib/modules/datasource/npm/get.spec.ts
+++ b/lib/modules/datasource/npm/get.spec.ts
@@ -7,7 +7,7 @@ import { Http } from '../../../util/http';
 import { CACHE_REVISION, getDependency } from './get';
 import { resolveRegistryUrl, setNpmrc } from './npmrc';
 
-jest.mock('../../../util/cache/package');
+vi.mock('../../../util/cache/package');
 
 const packageCache = mocked(_packageCache);
 
diff --git a/lib/modules/datasource/npm/npmrc.spec.ts b/lib/modules/datasource/npm/npmrc.spec.ts
index 21cc3b35b6..17e5684b64 100644
--- a/lib/modules/datasource/npm/npmrc.spec.ts
+++ b/lib/modules/datasource/npm/npmrc.spec.ts
@@ -8,7 +8,7 @@ import {
   setNpmrc,
 } from './npmrc';
 
-jest.mock('../../../util/sanitize');
+vi.mock('../../../util/sanitize');
 
 const sanitize = mocked(_sanitize);
 
diff --git a/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap
index 9b1702cc94..95383157e0 100644
--- a/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/nuget/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/nuget/index getReleases handles paginated results (v2) 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > handles paginated results (v2) 1`] = `
 {
   "registryUrl": "https://www.nuget.org/api/v2",
   "releases": [
@@ -17,7 +17,7 @@ exports[`modules/datasource/nuget/index getReleases handles paginated results (v
 }
 `;
 
-exports[`modules/datasource/nuget/index getReleases processes real data (v2) 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > processes real data (v2) 1`] = `
 {
   "registryUrl": "https://www.nuget.org/api/v2",
   "releases": [
@@ -208,7 +208,7 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v2) 1`]
 }
 `;
 
-exports[`modules/datasource/nuget/index getReleases processes real data (v3) feed is a nuget.org 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > processes real data (v3) feed is a nuget.org 1`] = `
 {
   "homepage": "https://nunit.org/",
   "registryUrl": "https://api.nuget.org/v3/index.json",
@@ -398,7 +398,7 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) fee
 }
 `;
 
-exports[`modules/datasource/nuget/index getReleases processes real data (v3) feed is not a nuget.org 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > processes real data (v3) feed is not a nuget.org 1`] = `
 {
   "registryUrl": "https://myprivatefeed/index.json",
   "releases": [
@@ -586,7 +586,7 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) fee
 }
 `;
 
-exports[`modules/datasource/nuget/index getReleases processes real data (v3) for several catalog pages 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > processes real data (v3) for several catalog pages 1`] = `
 {
   "homepage": "https://nlog-project.org/",
   "registryUrl": "https://api.nuget.org/v3/index.json",
@@ -1220,7 +1220,7 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) for
 }
 `;
 
-exports[`modules/datasource/nuget/index getReleases processes real data (v3) nuspec fetch 404 error 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > processes real data (v3) nuspec fetch 404 error 1`] = `
 {
   "registryUrl": "https://api.nuget.org/v3/index.json",
   "releases": [
@@ -1409,7 +1409,7 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) nus
 }
 `;
 
-exports[`modules/datasource/nuget/index getReleases processes real data (v3) nuspec fetch error 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > processes real data (v3) nuspec fetch error 1`] = `
 {
   "registryUrl": "https://api.nuget.org/v3/index.json",
   "releases": [
@@ -1598,7 +1598,7 @@ exports[`modules/datasource/nuget/index getReleases processes real data (v3) nus
 }
 `;
 
-exports[`modules/datasource/nuget/index getReleases processes real data with no github project url (v2) 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > processes real data with no github project url (v2) 1`] = `
 {
   "registryUrl": "https://www.nuget.org/api/v2",
   "releases": [
@@ -1613,7 +1613,7 @@ exports[`modules/datasource/nuget/index getReleases processes real data with no
 }
 `;
 
-exports[`modules/datasource/nuget/index getReleases processes real data without project url (v2) 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > processes real data without project url (v2) 1`] = `
 {
   "registryUrl": "https://www.nuget.org/api/v2",
   "releases": [
@@ -1753,7 +1753,7 @@ exports[`modules/datasource/nuget/index getReleases processes real data without
 }
 `;
 
-exports[`modules/datasource/nuget/index getReleases returns deduplicated results 1`] = `
+exports[`modules/datasource/nuget/index > getReleases > returns deduplicated results 1`] = `
 {
   "homepage": "https://nunit.org/",
   "releases": [
diff --git a/lib/modules/datasource/nuget/common.spec.ts b/lib/modules/datasource/nuget/common.spec.ts
index 8296ca85e3..30777b4293 100644
--- a/lib/modules/datasource/nuget/common.spec.ts
+++ b/lib/modules/datasource/nuget/common.spec.ts
@@ -1,7 +1,7 @@
 import { sortNugetVersions } from './common';
 
 describe('modules/datasource/nuget/common', () => {
-  it.each<{ version: string; other: string; result: number }>`
+  it.each`
     version         | other           | result
     ${'invalid1'}   | ${'invalid2'}   | ${0}
     ${'invalid'}    | ${'1.0.0'}      | ${-1}
@@ -11,7 +11,15 @@ describe('modules/datasource/nuget/common', () => {
     ${'1.0.0'}      | ${'1.0.0'}      | ${0}
   `(
     'sortNugetVersions("$version", "$other") === $result',
-    ({ version, other, result }) => {
+    ({
+      version,
+      other,
+      result,
+    }: {
+      version: string;
+      other: string;
+      result: number;
+    }) => {
       const res = sortNugetVersions(version, other);
       expect(res).toBe(result);
     },
diff --git a/lib/modules/datasource/nuget/index.spec.ts b/lib/modules/datasource/nuget/index.spec.ts
index 55a8664cff..88ef541940 100644
--- a/lib/modules/datasource/nuget/index.spec.ts
+++ b/lib/modules/datasource/nuget/index.spec.ts
@@ -16,9 +16,9 @@ const datasource = NugetDatasource.id;
 
 const hostRules: any = _hostRules;
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 
-jest.mock('../../../util/cache/package', () => mockDeep());
+vi.mock('../../../util/cache/package', () => mockDeep());
 const packageCache = mocked(_packageCache);
 
 const pkgInfoV3FromNuget = Fixtures.get('nunit/v3_nuget_org.xml');
diff --git a/lib/modules/datasource/orb/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/orb/__snapshots__/index.spec.ts.snap
index b6f1650795..104f3b31c5 100644
--- a/lib/modules/datasource/orb/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/orb/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/orb/index getReleases processes homeUrl 1`] = `
+exports[`modules/datasource/orb/index > getReleases > processes homeUrl 1`] = `
 {
   "homepage": "https://google.com",
   "isPrivate": false,
@@ -49,7 +49,7 @@ exports[`modules/datasource/orb/index getReleases processes homeUrl 1`] = `
 }
 `;
 
-exports[`modules/datasource/orb/index getReleases processes real data 1`] = `
+exports[`modules/datasource/orb/index > getReleases > processes real data 1`] = `
 {
   "homepage": "https://circleci.com/developer/orbs/orb/hyper-expanse/library-release-workflows",
   "isPrivate": false,
diff --git a/lib/modules/datasource/packagist/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/packagist/__snapshots__/index.spec.ts.snap
index 71b4dcaeee..91d2b77bfe 100644
--- a/lib/modules/datasource/packagist/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/packagist/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/packagist/index getReleases adds packagist source implicitly 1`] = `
+exports[`modules/datasource/packagist/index > getReleases > adds packagist source implicitly 1`] = `
 {
   "registryUrl": "https://packagist.org",
   "releases": [
@@ -104,7 +104,7 @@ exports[`modules/datasource/packagist/index getReleases adds packagist source im
 }
 `;
 
-exports[`modules/datasource/packagist/index getReleases processes real versioned data 1`] = `
+exports[`modules/datasource/packagist/index > getReleases > processes real versioned data 1`] = `
 {
   "registryUrl": "https://packagist.org",
   "releases": [
@@ -208,7 +208,7 @@ exports[`modules/datasource/packagist/index getReleases processes real versioned
 }
 `;
 
-exports[`modules/datasource/packagist/index getReleases supports includes packages 1`] = `
+exports[`modules/datasource/packagist/index > getReleases > supports includes packages 1`] = `
 {
   "homepage": "http://guzzlephp.org/",
   "registryUrl": "https://composer.renovatebot.com",
@@ -353,7 +353,7 @@ exports[`modules/datasource/packagist/index getReleases supports includes packag
 }
 `;
 
-exports[`modules/datasource/packagist/index getReleases supports lazy repositories 1`] = `
+exports[`modules/datasource/packagist/index > getReleases > supports lazy repositories 1`] = `
 {
   "registryUrl": "https://composer.renovatebot.com/composer/lazy",
   "releases": [
@@ -369,7 +369,7 @@ exports[`modules/datasource/packagist/index getReleases supports lazy repositori
 }
 `;
 
-exports[`modules/datasource/packagist/index getReleases supports plain packages 1`] = `
+exports[`modules/datasource/packagist/index > getReleases > supports plain packages 1`] = `
 {
   "registryUrl": "https://composer.renovatebot.com",
   "releases": [
@@ -389,7 +389,7 @@ exports[`modules/datasource/packagist/index getReleases supports plain packages
 }
 `;
 
-exports[`modules/datasource/packagist/index getReleases supports provider-includes 1`] = `
+exports[`modules/datasource/packagist/index > getReleases > supports provider-includes 1`] = `
 {
   "homepage": "https://wordpress.org/plugins/1beyt/",
   "registryUrl": "https://composer.renovatebot.com",
@@ -419,7 +419,7 @@ exports[`modules/datasource/packagist/index getReleases supports provider-includ
 }
 `;
 
-exports[`modules/datasource/packagist/index getReleases supports providers 1`] = `
+exports[`modules/datasource/packagist/index > getReleases > supports providers 1`] = `
 {
   "homepage": "https://wordpress.org/plugins/1beyt/",
   "registryUrl": "https://composer.renovatebot.com",
@@ -449,7 +449,7 @@ exports[`modules/datasource/packagist/index getReleases supports providers 1`] =
 }
 `;
 
-exports[`modules/datasource/packagist/index getReleases supports providers without a hash 1`] = `
+exports[`modules/datasource/packagist/index > getReleases > supports providers without a hash 1`] = `
 {
   "homepage": "https://wordpress.org/plugins/1beyt/",
   "registryUrl": "https://composer.renovatebot.com",
diff --git a/lib/modules/datasource/packagist/index.spec.ts b/lib/modules/datasource/packagist/index.spec.ts
index 6b4c7685e4..1e61e01f6e 100644
--- a/lib/modules/datasource/packagist/index.spec.ts
+++ b/lib/modules/datasource/packagist/index.spec.ts
@@ -8,7 +8,7 @@ import * as composerVersioning from '../../versioning/composer';
 import { id as versioning } from '../../versioning/loose';
 import { PackagistDatasource } from '.';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 const hostRules = _hostRules;
 
@@ -144,7 +144,7 @@ describe('modules/datasource/packagist/index', () => {
     });
 
     it('supports includes packages', async () => {
-      hostRules.find = jest.fn(() => ({
+      hostRules.find = vi.fn(() => ({
         username: 'some-username',
         password: 'some-password',
       }));
@@ -177,7 +177,7 @@ describe('modules/datasource/packagist/index', () => {
     });
 
     it('supports older sha1 hashes', async () => {
-      hostRules.find = jest.fn(() => ({
+      hostRules.find = vi.fn(() => ({
         username: 'some-username',
         password: 'some-password',
       }));
diff --git a/lib/modules/datasource/postprocess-release.spec.ts b/lib/modules/datasource/postprocess-release.spec.ts
index 9efbbbc3a8..a3a2c7a148 100644
--- a/lib/modules/datasource/postprocess-release.spec.ts
+++ b/lib/modules/datasource/postprocess-release.spec.ts
@@ -11,7 +11,7 @@ import type {
   ReleaseResult,
 } from './types';
 
-jest.mock('./common');
+vi.mock('./common');
 const { getDatasourceFor } = mocked(_datasourceCommon);
 
 class DummyDatasource extends Datasource {
diff --git a/lib/modules/datasource/pypi/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/pypi/__snapshots__/index.spec.ts.snap
index 1704b16384..170f48c258 100644
--- a/lib/modules/datasource/pypi/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/pypi/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/pypi/index getReleases parses data-requires-python and respects constraints from simple endpoint 1`] = `
+exports[`modules/datasource/pypi/index > getReleases > parses data-requires-python and respects constraints from simple endpoint 1`] = `
 {
   "registryUrl": "https://some.registry.org/simple",
   "releases": [
@@ -26,7 +26,7 @@ exports[`modules/datasource/pypi/index getReleases parses data-requires-python a
 }
 `;
 
-exports[`modules/datasource/pypi/index getReleases process data from +simple endpoint 1`] = `
+exports[`modules/datasource/pypi/index > getReleases > process data from +simple endpoint 1`] = `
 {
   "registryUrl": "https://some.registry.org/+simple",
   "releases": [
@@ -68,7 +68,7 @@ exports[`modules/datasource/pypi/index getReleases process data from +simple end
 }
 `;
 
-exports[`modules/datasource/pypi/index getReleases process data from simple endpoint 1`] = `
+exports[`modules/datasource/pypi/index > getReleases > process data from simple endpoint 1`] = `
 {
   "registryUrl": "https://some.registry.org/simple",
   "releases": [
@@ -110,7 +110,7 @@ exports[`modules/datasource/pypi/index getReleases process data from simple endp
 }
 `;
 
-exports[`modules/datasource/pypi/index getReleases process data from simple endpoint with hyphens replaced with underscores 1`] = `
+exports[`modules/datasource/pypi/index > getReleases > process data from simple endpoint with hyphens replaced with underscores 1`] = `
 {
   "registryUrl": "https://some.registry.org/simple",
   "releases": [
@@ -121,7 +121,7 @@ exports[`modules/datasource/pypi/index getReleases process data from simple endp
 }
 `;
 
-exports[`modules/datasource/pypi/index getReleases processes real data 1`] = `
+exports[`modules/datasource/pypi/index > getReleases > processes real data 1`] = `
 {
   "registryUrl": "https://pypi.org/pypi",
   "releases": [
@@ -219,7 +219,7 @@ exports[`modules/datasource/pypi/index getReleases processes real data 1`] = `
 }
 `;
 
-exports[`modules/datasource/pypi/index getReleases respects constraints 1`] = `
+exports[`modules/datasource/pypi/index > getReleases > respects constraints 1`] = `
 {
   "registryUrl": "https://pypi.org/pypi",
   "releases": [
@@ -236,7 +236,7 @@ exports[`modules/datasource/pypi/index getReleases respects constraints 1`] = `
 }
 `;
 
-exports[`modules/datasource/pypi/index uses https://pypi.org/pypi/ instead of https://pypi.org/simple/ 1`] = `
+exports[`modules/datasource/pypi/index > uses https://pypi.org/pypi/ instead of https://pypi.org/simple/ 1`] = `
 {
   "registryUrl": "https://pypi.org/simple",
   "releases": [
diff --git a/lib/modules/datasource/pypi/index.spec.ts b/lib/modules/datasource/pypi/index.spec.ts
index 295a78c241..873dff6ad5 100644
--- a/lib/modules/datasource/pypi/index.spec.ts
+++ b/lib/modules/datasource/pypi/index.spec.ts
@@ -7,7 +7,7 @@ import * as hostRules from '../../../util/host-rules';
 import { PypiDatasource } from '.';
 
 const googleAuth = mocked(_googleAuth);
-jest.mock('google-auth-library');
+vi.mock('google-auth-library');
 
 const res1 = Fixtures.get('azure-cli-monitor.json');
 const htmlResponse = Fixtures.get('versions-html.html');
diff --git a/lib/modules/datasource/readme.md b/lib/modules/datasource/readme.md
index 39e22f0202..080adb03ad 100644
--- a/lib/modules/datasource/readme.md
+++ b/lib/modules/datasource/readme.md
@@ -8,7 +8,7 @@ New datasources _must_ follow the class-based programming style.
 Use the `java-version` datasource as a reference.
 
 Add the datasource to the API in [`api.ts`](api.ts) so that the new datasource is usable.
-If you find `Unused HTTP mocks` errors in the Jest tests _and_ your mocked URLs are correct, make sure the datasource is correctly registered.
+If you find `Unused HTTP mocks` errors in the Vitest tests _and_ your mocked URLs are correct, make sure the datasource is correctly registered.
 
 ## getReleases
 
diff --git a/lib/modules/datasource/repology/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/repology/__snapshots__/index.spec.ts.snap
index 1cb66e4910..91761f58f4 100644
--- a/lib/modules/datasource/repology/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/repology/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/repology/index getReleases returns correct version for api package 1`] = `
+exports[`modules/datasource/repology/index > getReleases > returns correct version for api package 1`] = `
 {
   "registryUrl": "https://repology.org",
   "releases": [
@@ -11,7 +11,7 @@ exports[`modules/datasource/repology/index getReleases returns correct version f
 }
 `;
 
-exports[`modules/datasource/repology/index getReleases returns correct version for binary package 1`] = `
+exports[`modules/datasource/repology/index > getReleases > returns correct version for binary package 1`] = `
 {
   "registryUrl": "https://repology.org",
   "releases": [
@@ -22,7 +22,7 @@ exports[`modules/datasource/repology/index getReleases returns correct version f
 }
 `;
 
-exports[`modules/datasource/repology/index getReleases returns correct version for multi-package project with different name 1`] = `
+exports[`modules/datasource/repology/index > getReleases > returns correct version for multi-package project with different name 1`] = `
 {
   "registryUrl": "https://repology.org",
   "releases": [
@@ -33,7 +33,7 @@ exports[`modules/datasource/repology/index getReleases returns correct version f
 }
 `;
 
-exports[`modules/datasource/repology/index getReleases returns correct version for multi-package project with same name 1`] = `
+exports[`modules/datasource/repology/index > getReleases > returns correct version for multi-package project with same name 1`] = `
 {
   "registryUrl": "https://repology.org",
   "releases": [
@@ -44,7 +44,7 @@ exports[`modules/datasource/repology/index getReleases returns correct version f
 }
 `;
 
-exports[`modules/datasource/repology/index getReleases returns correct version for source package 1`] = `
+exports[`modules/datasource/repology/index > getReleases > returns correct version for source package 1`] = `
 {
   "registryUrl": "https://repology.org",
   "releases": [
@@ -55,7 +55,7 @@ exports[`modules/datasource/repology/index getReleases returns correct version f
 }
 `;
 
-exports[`modules/datasource/repology/index getReleases returns multiple versions if they are present in repository 1`] = `
+exports[`modules/datasource/repology/index > getReleases > returns multiple versions if they are present in repository 1`] = `
 {
   "registryUrl": "https://repology.org",
   "releases": [
diff --git a/lib/modules/datasource/ruby-version/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/ruby-version/__snapshots__/index.spec.ts.snap
index 300739f727..6c44679a08 100644
--- a/lib/modules/datasource/ruby-version/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/ruby-version/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/ruby-version/index getReleases parses real data 1`] = `
+exports[`modules/datasource/ruby-version/index > getReleases > parses real data 1`] = `
 {
   "homepage": "https://www.ruby-lang.org",
   "registryUrl": "https://www.ruby-lang.org/",
diff --git a/lib/modules/datasource/rubygems/metadata-cache.spec.ts b/lib/modules/datasource/rubygems/metadata-cache.spec.ts
index 737b6e4d98..a9a445d96f 100644
--- a/lib/modules/datasource/rubygems/metadata-cache.spec.ts
+++ b/lib/modules/datasource/rubygems/metadata-cache.spec.ts
@@ -4,7 +4,7 @@ import * as _packageCache from '../../../util/cache/package';
 import { Http } from '../../../util/http';
 import { MetadataCache } from './metadata-cache';
 
-jest.mock('../../../util/cache/package');
+vi.mock('../../../util/cache/package');
 const packageCache = mocked(_packageCache);
 
 describe('modules/datasource/rubygems/metadata-cache', () => {
diff --git a/lib/modules/datasource/rubygems/versions-endpoint-cache.spec.ts b/lib/modules/datasource/rubygems/versions-endpoint-cache.spec.ts
index 776289a7a9..3dd79eaaec 100644
--- a/lib/modules/datasource/rubygems/versions-endpoint-cache.spec.ts
+++ b/lib/modules/datasource/rubygems/versions-endpoint-cache.spec.ts
@@ -81,11 +81,11 @@ describe('modules/datasource/rubygems/versions-endpoint-cache', () => {
 
   describe('Delta sync', () => {
     beforeAll(() => {
-      jest.useFakeTimers({ advanceTimers: true });
+      vi.useFakeTimers({ shouldAdvanceTime: true });
     });
 
     beforeEach(() => {
-      jest.setSystemTime(new Date('2021-05-04T00:00:00.000Z'));
+      vi.setSystemTime(new Date('2021-05-04T00:00:00.000Z'));
     });
 
     it('refreshes after 15 minutes', async () => {
@@ -94,7 +94,7 @@ describe('modules/datasource/rubygems/versions-endpoint-cache', () => {
       const res1 = await rubygems.getVersions(registryUrl, 'foo');
       expect(res1.unwrap().val).toEqual(['1.1.1']);
 
-      jest.advanceTimersByTime(15 * 60 * 1000);
+      vi.advanceTimersByTime(15 * 60 * 1000);
       httpMock
         .scope(registryUrl)
         .get('/versions')
@@ -120,7 +120,7 @@ describe('modules/datasource/rubygems/versions-endpoint-cache', () => {
       const res1 = await rubygems.getVersions(registryUrl, 'foo');
       expect(res1.unwrap().val).toEqual(['1.1.1']);
 
-      jest.advanceTimersByTime(15 * 60 * 1000);
+      vi.advanceTimersByTime(15 * 60 * 1000);
       httpMock
         .scope(registryUrl)
         .get('/versions')
@@ -157,7 +157,7 @@ describe('modules/datasource/rubygems/versions-endpoint-cache', () => {
       const res1 = await rubygems.getVersions(registryUrl, 'foo');
       expect(res1.unwrap().val).toEqual(['1.1.1']);
 
-      jest.advanceTimersByTime(15 * 60 * 1000);
+      vi.advanceTimersByTime(15 * 60 * 1000);
       httpMock
         .scope(registryUrl)
         .get('/versions')
@@ -180,7 +180,7 @@ describe('modules/datasource/rubygems/versions-endpoint-cache', () => {
 
         await rubygems.getVersions(registryUrl, 'foo');
 
-        jest.advanceTimersByTime(15 * 60 * 1000);
+        vi.advanceTimersByTime(15 * 60 * 1000);
       });
 
       it('handles 404', async () => {
diff --git a/lib/modules/datasource/sbt-package/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/sbt-package/__snapshots__/index.spec.ts.snap
index ab2676a1d4..764560970a 100644
--- a/lib/modules/datasource/sbt-package/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/sbt-package/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/sbt-package/index parses Maven index directory 1`] = `
+exports[`modules/datasource/sbt-package/index > parses Maven index directory 1`] = `
 [
   "autofix-3.0.6_2.11",
   "autofix-3.0.6_2.12",
@@ -188,7 +188,7 @@ exports[`modules/datasource/sbt-package/index parses Maven index directory 1`] =
 ]
 `;
 
-exports[`modules/datasource/sbt-package/index parses sbt index directory 1`] = `
+exports[`modules/datasource/sbt-package/index > parses sbt index directory 1`] = `
 [
   "au.com.onegeek",
   "bavadim",
diff --git a/lib/modules/datasource/sbt-package/index.spec.ts b/lib/modules/datasource/sbt-package/index.spec.ts
index c3011e5631..d15ac61e42 100644
--- a/lib/modules/datasource/sbt-package/index.spec.ts
+++ b/lib/modules/datasource/sbt-package/index.spec.ts
@@ -10,7 +10,7 @@ import { MAVEN_REPO } from '../maven/common';
 import { extractPageLinks } from './util';
 import { SbtPackageDatasource } from '.';
 
-jest.mock('../../../util/cache/package');
+vi.mock('../../../util/cache/package');
 const packageCache = mocked(_packageCache);
 
 describe('modules/datasource/sbt-package/index', () => {
diff --git a/lib/modules/datasource/sbt-plugin/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/sbt-plugin/__snapshots__/index.spec.ts.snap
index a8be3a0994..ee5456b5dc 100644
--- a/lib/modules/datasource/sbt-plugin/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/sbt-plugin/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/datasource/sbt-plugin/index parses Maven index directory 1`] = `
+exports[`modules/datasource/sbt-plugin/index > parses Maven index directory 1`] = `
 [
   "autofix-3.0.6_2.11",
   "autofix-3.0.6_2.12",
@@ -188,7 +188,7 @@ exports[`modules/datasource/sbt-plugin/index parses Maven index directory 1`] =
 ]
 `;
 
-exports[`modules/datasource/sbt-plugin/index parses sbt index directory 1`] = `
+exports[`modules/datasource/sbt-plugin/index > parses sbt index directory 1`] = `
 [
   "au.com.onegeek",
   "bavadim",
diff --git a/lib/modules/datasource/utils.spec.ts b/lib/modules/datasource/utils.spec.ts
index 0f60f3cd2d..69c10432b4 100644
--- a/lib/modules/datasource/utils.spec.ts
+++ b/lib/modules/datasource/utils.spec.ts
@@ -4,7 +4,7 @@ import type { HttpResponse } from '../../util/http/types';
 import { getGoogleAuthToken, isArtifactoryServer } from './util';
 
 const googleAuth = mocked(_googleAuth);
-jest.mock('google-auth-library');
+vi.mock('google-auth-library');
 
 describe('modules/datasource/utils', () => {
   it('is artifactory server invalid', () => {
diff --git a/lib/modules/manager/ansible-galaxy/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/ansible-galaxy/__snapshots__/extract.spec.ts.snap
index b08d1bf29c..525ebcacf2 100644
--- a/lib/modules/manager/ansible-galaxy/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/ansible-galaxy/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/ansible-galaxy/extract extractPackageFile() check collection style requirements file 1`] = `
+exports[`modules/manager/ansible-galaxy/extract > extractPackageFile() > check collection style requirements file 1`] = `
 [
   {
     "currentValue": "0.9.3",
@@ -104,7 +104,7 @@ exports[`modules/manager/ansible-galaxy/extract extractPackageFile() check colle
 ]
 `;
 
-exports[`modules/manager/ansible-galaxy/extract extractPackageFile() check collection style requirements file in reverse order and missing empty line 1`] = `
+exports[`modules/manager/ansible-galaxy/extract > extractPackageFile() > check collection style requirements file in reverse order and missing empty line 1`] = `
 [
   {
     "currentValue": "0.9.3",
@@ -138,7 +138,7 @@ exports[`modules/manager/ansible-galaxy/extract extractPackageFile() check colle
 ]
 `;
 
-exports[`modules/manager/ansible-galaxy/extract extractPackageFile() check galaxy definition file 1`] = `
+exports[`modules/manager/ansible-galaxy/extract > extractPackageFile() > check galaxy definition file 1`] = `
 [
   {
     "currentValue": "1.5.4",
@@ -203,7 +203,7 @@ exports[`modules/manager/ansible-galaxy/extract extractPackageFile() check galax
 ]
 `;
 
-exports[`modules/manager/ansible-galaxy/extract extractPackageFile() extracts dependencies from a not beautified requirements file 1`] = `
+exports[`modules/manager/ansible-galaxy/extract > extractPackageFile() > extracts dependencies from a not beautified requirements file 1`] = `
 [
   {
     "currentValue": "0.1.0",
@@ -222,7 +222,7 @@ exports[`modules/manager/ansible-galaxy/extract extractPackageFile() extracts de
 ]
 `;
 
-exports[`modules/manager/ansible-galaxy/extract extractPackageFile() extracts multiple dependencies from requirements.yml 1`] = `
+exports[`modules/manager/ansible-galaxy/extract > extractPackageFile() > extracts multiple dependencies from requirements.yml 1`] = `
 [
   {
     "currentValue": "0.1.0",
diff --git a/lib/modules/manager/ansible/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/ansible/__snapshots__/extract.spec.ts.snap
index 826e16a14f..8990329116 100644
--- a/lib/modules/manager/ansible/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/ansible/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/ansible/extract extractPackageFile() extracts multiple image lines from docker_container 1`] = `
+exports[`modules/manager/ansible/extract > extractPackageFile() > extracts multiple image lines from docker_container 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
@@ -89,7 +89,7 @@ exports[`modules/manager/ansible/extract extractPackageFile() extracts multiple
 ]
 `;
 
-exports[`modules/manager/ansible/extract extractPackageFile() extracts multiple image lines from docker_service 1`] = `
+exports[`modules/manager/ansible/extract > extractPackageFile() > extracts multiple image lines from docker_service 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
diff --git a/lib/modules/manager/bazel-module/bazelrc.spec.ts b/lib/modules/manager/bazel-module/bazelrc.spec.ts
index c928b722ee..d17ccf1184 100644
--- a/lib/modules/manager/bazel-module/bazelrc.spec.ts
+++ b/lib/modules/manager/bazel-module/bazelrc.spec.ts
@@ -2,7 +2,7 @@ import { codeBlock } from 'common-tags';
 import { fs } from '../../../../test/util';
 import { BazelOption, CommandEntry, ImportEntry, parse, read } from './bazelrc';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 function mockReadLocalFile(files: Record<string, string | null>) {
   fs.readLocalFile.mockImplementation((file): Promise<any> => {
@@ -54,13 +54,13 @@ describe('modules/manager/bazel-module/bazelrc', () => {
   it('parse', () => {
     const input = codeBlock`
         # Bob's Bazel option defaults
-        
+
         startup --host_jvm_args=-XX:-UseParallelGC
         import /home/bobs_project/bazelrc
         build --show_timestamps --keep_going --jobs 600
         build --color=yes
         query --keep_going
-        
+
         # Definition of --config=memcheck
         build:memcheck --strip=never --test_timeout=3600
 
diff --git a/lib/modules/manager/bazel-module/parser/context.spec.ts b/lib/modules/manager/bazel-module/parser/context.spec.ts
index 1d79781673..dd4cf1369c 100644
--- a/lib/modules/manager/bazel-module/parser/context.spec.ts
+++ b/lib/modules/manager/bazel-module/parser/context.spec.ts
@@ -52,7 +52,7 @@ describe('modules/manager/bazel-module/parser/context', () => {
       const ctx = new Ctx('').startAttribute('name');
       expect(() => ctx.addString('chicken')).toThrow(
         new CtxProcessingError(
-          fragments.attribute('name', fragments.string('chicken')),
+          fragments.attribute('name', fragments.string('chicken'), true),
         ),
       );
     });
diff --git a/lib/modules/manager/bazel/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/bazel/__snapshots__/extract.spec.ts.snap
index d17b3e86a0..c5722b167f 100644
--- a/lib/modules/manager/bazel/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/bazel/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/bazel/extract extractPackageFile() extracts multiple types of dependencies 1`] = `
+exports[`modules/manager/bazel/extract > extractPackageFile() > extracts multiple types of dependencies 1`] = `
 [
   {
     "currentValue": "v1.0.5",
@@ -199,7 +199,7 @@ exports[`modules/manager/bazel/extract extractPackageFile() extracts multiple ty
 ]
 `;
 
-exports[`modules/manager/bazel/extract extractPackageFile() sequential http_archive 1`] = `
+exports[`modules/manager/bazel/extract > extractPackageFile() > sequential http_archive 1`] = `
 [
   {
     "currentValue": "v1.1.2",
diff --git a/lib/modules/manager/buildkite/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/buildkite/__snapshots__/extract.spec.ts.snap
index b99a362b11..f1dd0c250c 100644
--- a/lib/modules/manager/buildkite/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/buildkite/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/buildkite/extract extractPackageFile() adds skipReason 1`] = `
+exports[`modules/manager/buildkite/extract > extractPackageFile() > adds skipReason 1`] = `
 [
   {
     "currentValue": "v1.3.2.5",
@@ -15,7 +15,7 @@ exports[`modules/manager/buildkite/extract extractPackageFile() adds skipReason
 ]
 `;
 
-exports[`modules/manager/buildkite/extract extractPackageFile() extracts arrays of plugins 1`] = `
+exports[`modules/manager/buildkite/extract > extractPackageFile() > extracts arrays of plugins 1`] = `
 [
   {
     "currentValue": "v2.0.1",
@@ -48,7 +48,7 @@ exports[`modules/manager/buildkite/extract extractPackageFile() extracts arrays
 ]
 `;
 
-exports[`modules/manager/buildkite/extract extractPackageFile() extracts git-based plugins 1`] = `
+exports[`modules/manager/buildkite/extract > extractPackageFile() > extracts git-based plugins 1`] = `
 [
   {
     "currentValue": "v3.2.7",
@@ -69,7 +69,7 @@ exports[`modules/manager/buildkite/extract extractPackageFile() extracts git-bas
 ]
 `;
 
-exports[`modules/manager/buildkite/extract extractPackageFile() extracts multiple plugins in same file 1`] = `
+exports[`modules/manager/buildkite/extract > extractPackageFile() > extracts multiple plugins in same file 1`] = `
 [
   {
     "currentValue": "v1.3.2",
@@ -88,7 +88,7 @@ exports[`modules/manager/buildkite/extract extractPackageFile() extracts multipl
 ]
 `;
 
-exports[`modules/manager/buildkite/extract extractPackageFile() extracts simple single plugin 1`] = `
+exports[`modules/manager/buildkite/extract > extractPackageFile() > extracts simple single plugin 1`] = `
 [
   {
     "currentValue": "v2.0.0",
diff --git a/lib/modules/manager/bun/artifacts.spec.ts b/lib/modules/manager/bun/artifacts.spec.ts
index 081e341f15..130f1b9b69 100644
--- a/lib/modules/manager/bun/artifacts.spec.ts
+++ b/lib/modules/manager/bun/artifacts.spec.ts
@@ -8,8 +8,8 @@ import { ExecError } from '../../../util/exec/exec-error';
 import type { UpdateArtifact } from '../types';
 import { updateArtifacts } from './artifacts';
 
-jest.mock('../../../util/exec');
-jest.mock('fs-extra');
+vi.mock('../../../util/exec');
+vi.mock('fs-extra');
 
 const exec = mocked(_exec);
 const fs = mocked(_fs);
diff --git a/lib/modules/manager/bun/extract.spec.ts b/lib/modules/manager/bun/extract.spec.ts
index b5135fa3ea..f06c539556 100644
--- a/lib/modules/manager/bun/extract.spec.ts
+++ b/lib/modules/manager/bun/extract.spec.ts
@@ -1,7 +1,7 @@
 import { fs } from '../../../../test/util';
 import { extractAllPackageFiles } from './extract';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/bun/extract', () => {
   describe('extractAllPackageFiles()', () => {
@@ -15,7 +15,7 @@ describe('modules/manager/bun/extract', () => {
       });
 
       it('ignores invalid package.json file', async () => {
-        (fs.readLocalFile as jest.Mock).mockResolvedValueOnce('invalid');
+        vi.mocked(fs.readLocalFile).mockResolvedValueOnce('invalid');
         expect(await extractAllPackageFiles({}, ['bun.lockb'])).toEqual([]);
       });
 
@@ -73,7 +73,7 @@ describe('modules/manager/bun/extract', () => {
       });
 
       it('ignores invalid package.json file', async () => {
-        (fs.readLocalFile as jest.Mock).mockResolvedValueOnce('invalid');
+        vi.mocked(fs.readLocalFile).mockResolvedValueOnce('invalid');
         expect(await extractAllPackageFiles({}, ['bun.lock'])).toEqual([]);
       });
 
diff --git a/lib/modules/manager/bundler/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/bundler/__snapshots__/extract.spec.ts.snap
index ebda7e682b..45085c1d50 100644
--- a/lib/modules/manager/bundler/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/bundler/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/bundler/extract extractPackageFile() parse Ruby CI Gemfile 1`] = `
+exports[`modules/manager/bundler/extract > extractPackageFile() > parse Ruby CI Gemfile 1`] = `
 {
   "deps": [
     {
@@ -149,7 +149,7 @@ exports[`modules/manager/bundler/extract extractPackageFile() parse Ruby CI Gemf
 }
 `;
 
-exports[`modules/manager/bundler/extract extractPackageFile() parse mastodon Gemfile 1`] = `
+exports[`modules/manager/bundler/extract > extractPackageFile() > parse mastodon Gemfile 1`] = `
 {
   "deps": [
     {
@@ -1400,7 +1400,7 @@ exports[`modules/manager/bundler/extract extractPackageFile() parse mastodon Gem
 }
 `;
 
-exports[`modules/manager/bundler/extract extractPackageFile() parse webpacker Gemfile 1`] = `
+exports[`modules/manager/bundler/extract > extractPackageFile() > parse webpacker Gemfile 1`] = `
 {
   "deps": [
     {
@@ -1461,7 +1461,7 @@ exports[`modules/manager/bundler/extract extractPackageFile() parse webpacker Ge
 }
 `;
 
-exports[`modules/manager/bundler/extract extractPackageFile() parses rails Gemfile 1`] = `
+exports[`modules/manager/bundler/extract > extractPackageFile() > parses rails Gemfile 1`] = `
 {
   "deps": [
     {
@@ -2179,7 +2179,7 @@ exports[`modules/manager/bundler/extract extractPackageFile() parses rails Gemfi
 }
 `;
 
-exports[`modules/manager/bundler/extract extractPackageFile() parses sourceGroups 1`] = `
+exports[`modules/manager/bundler/extract > extractPackageFile() > parses sourceGroups 1`] = `
 {
   "deps": [
     {
@@ -2252,7 +2252,7 @@ exports[`modules/manager/bundler/extract extractPackageFile() parses sourceGroup
 }
 `;
 
-exports[`modules/manager/bundler/extract parse Gitlab Foss Gemfile 1`] = `
+exports[`modules/manager/bundler/extract > parse Gitlab Foss Gemfile 1`] = `
 {
   "deps": [
     {
@@ -4728,7 +4728,7 @@ exports[`modules/manager/bundler/extract parse Gitlab Foss Gemfile 1`] = `
 }
 `;
 
-exports[`modules/manager/bundler/extract parse source blocks in Gemfile 1`] = `
+exports[`modules/manager/bundler/extract > parse source blocks in Gemfile 1`] = `
 {
   "deps": [
     {
@@ -4761,7 +4761,7 @@ exports[`modules/manager/bundler/extract parse source blocks in Gemfile 1`] = `
 }
 `;
 
-exports[`modules/manager/bundler/extract parse source blocks with spaces in Gemfile 1`] = `
+exports[`modules/manager/bundler/extract > parse source blocks with spaces in Gemfile 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/bundler/__snapshots__/gemfile.spec.ts.snap b/lib/modules/manager/bundler/__snapshots__/gemfile.spec.ts.snap
index 0a2c4b651a..4032669d3a 100644
--- a/lib/modules/manager/bundler/__snapshots__/gemfile.spec.ts.snap
+++ b/lib/modules/manager/bundler/__snapshots__/gemfile.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/bundler/gemfile matches the expected output 1`] = `
+exports[`modules/manager/bundler/gemfile > matches the expected output 1`] = `
 Map {
   "activerecord-jdbc-adapter" => "52.1-java",
   "activerecord-jdbcmysql-adapter" => "52.1-java",
diff --git a/lib/modules/manager/bundler/__snapshots__/locked-version.spec.ts.snap b/lib/modules/manager/bundler/__snapshots__/locked-version.spec.ts.snap
index f73294d8c4..c4ebc98d0a 100644
--- a/lib/modules/manager/bundler/__snapshots__/locked-version.spec.ts.snap
+++ b/lib/modules/manager/bundler/__snapshots__/locked-version.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/bundler/locked-version Parse Gitlab Foss Gem Lock File 1`] = `
+exports[`modules/manager/bundler/locked-version > Parse Gitlab Foss Gem Lock File 1`] = `
 Map {
   "RedCloth" => "4.3.2",
   "abstract_type" => "0.0.7",
@@ -483,7 +483,7 @@ Map {
 }
 `;
 
-exports[`modules/manager/bundler/locked-version Parse Mastodon Gem Lock File 1`] = `
+exports[`modules/manager/bundler/locked-version > Parse Mastodon Gem Lock File 1`] = `
 Map {
   "actioncable" => "5.2.4.1",
   "actionmailer" => "5.2.4.1",
@@ -754,7 +754,7 @@ Map {
 }
 `;
 
-exports[`modules/manager/bundler/locked-version Parse Rails Gem Lock File 1`] = `
+exports[`modules/manager/bundler/locked-version > Parse Rails Gem Lock File 1`] = `
 Map {
   "activerecord-jdbc-adapter" => "52.1-java",
   "activerecord-jdbcmysql-adapter" => "52.1-java",
@@ -944,7 +944,7 @@ Map {
 }
 `;
 
-exports[`modules/manager/bundler/locked-version Parse Ruby CI Gem Lock File 1`] = `
+exports[`modules/manager/bundler/locked-version > Parse Ruby CI Gem Lock File 1`] = `
 Map {
   "actioncable" => "5.2.3",
   "actionmailer" => "5.2.3",
@@ -1013,7 +1013,7 @@ Map {
 }
 `;
 
-exports[`modules/manager/bundler/locked-version Parse WebPacker Gem Lock File 1`] = `
+exports[`modules/manager/bundler/locked-version > Parse WebPacker Gem Lock File 1`] = `
 Map {
   "actioncable" => "6.0.1",
   "actionmailbox" => "6.0.1",
diff --git a/lib/modules/manager/bundler/artifacts.spec.ts b/lib/modules/manager/bundler/artifacts.spec.ts
index 857afb0b66..baccdf5ad7 100644
--- a/lib/modules/manager/bundler/artifacts.spec.ts
+++ b/lib/modules/manager/bundler/artifacts.spec.ts
@@ -23,12 +23,12 @@ import { updateArtifacts } from '.';
 const datasource = mocked(_datasource);
 const bundlerHostRules = mocked(_bundlerHostRules);
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../datasource', () => mockDeep());
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('./host-rules');
+vi.mock('../../../util/exec/env');
+vi.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('./host-rules');
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/bundler/common.spec.ts b/lib/modules/manager/bundler/common.spec.ts
index ced2e45fbb..1b1dc52cdd 100644
--- a/lib/modules/manager/bundler/common.spec.ts
+++ b/lib/modules/manager/bundler/common.spec.ts
@@ -10,7 +10,7 @@ import {
   getRubyConstraint,
 } from './common';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const gemfile = Fixtures.get('Gemfile.sourceGroup');
 const lockedContent = Fixtures.get('Gemfile.gitlab-foss.lock');
diff --git a/lib/modules/manager/bundler/extract.spec.ts b/lib/modules/manager/bundler/extract.spec.ts
index 8a4f7acb24..7bcd132fba 100644
--- a/lib/modules/manager/bundler/extract.spec.ts
+++ b/lib/modules/manager/bundler/extract.spec.ts
@@ -5,7 +5,7 @@ import { fs } from '../../../../test/util';
 import { isValid } from '../../versioning/ruby';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const railsGemfile = Fixtures.get('Gemfile.rails');
 const railsGemfileLock = Fixtures.get('Gemfile.rails.lock');
diff --git a/lib/modules/manager/cargo/__snapshots__/artifacts.spec.ts.snap b/lib/modules/manager/cargo/__snapshots__/artifacts.spec.ts.snap
index b751a1d0a7..2cc1ce30d8 100644
--- a/lib/modules/manager/cargo/__snapshots__/artifacts.spec.ts.snap
+++ b/lib/modules/manager/cargo/__snapshots__/artifacts.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/cargo/artifacts returns null if unchanged 1`] = `
+exports[`modules/manager/cargo/artifacts > returns null if unchanged 1`] = `
 [
   {
     "cmd": "cargo update --config net.git-fetch-with-cli=true --manifest-path Cargo.toml --workspace",
@@ -23,7 +23,7 @@ exports[`modules/manager/cargo/artifacts returns null if unchanged 1`] = `
 ]
 `;
 
-exports[`modules/manager/cargo/artifacts returns updated Cargo.lock 1`] = `
+exports[`modules/manager/cargo/artifacts > returns updated Cargo.lock 1`] = `
 [
   {
     "cmd": "cargo update --config net.git-fetch-with-cli=true --manifest-path Cargo.toml --workspace",
@@ -46,7 +46,7 @@ exports[`modules/manager/cargo/artifacts returns updated Cargo.lock 1`] = `
 ]
 `;
 
-exports[`modules/manager/cargo/artifacts returns updated Cargo.lock for lockfile maintenance 1`] = `
+exports[`modules/manager/cargo/artifacts > returns updated Cargo.lock for lockfile maintenance 1`] = `
 [
   {
     "cmd": "cargo update --config net.git-fetch-with-cli=true --manifest-path Cargo.toml",
@@ -69,7 +69,7 @@ exports[`modules/manager/cargo/artifacts returns updated Cargo.lock for lockfile
 ]
 `;
 
-exports[`modules/manager/cargo/artifacts returns updated workspace Cargo.lock 1`] = `
+exports[`modules/manager/cargo/artifacts > returns updated workspace Cargo.lock 1`] = `
 [
   {
     "cmd": "cargo update --config net.git-fetch-with-cli=true --manifest-path crates/one/Cargo.toml --workspace",
@@ -92,7 +92,7 @@ exports[`modules/manager/cargo/artifacts returns updated workspace Cargo.lock 1`
 ]
 `;
 
-exports[`modules/manager/cargo/artifacts updates Cargo.lock based on the packageName, when given 1`] = `
+exports[`modules/manager/cargo/artifacts > updates Cargo.lock based on the packageName, when given 1`] = `
 [
   {
     "cmd": "cargo update --config net.git-fetch-with-cli=true --manifest-path Cargo.toml --workspace",
diff --git a/lib/modules/manager/cargo/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/cargo/__snapshots__/extract.spec.ts.snap
index 70efe56af7..7eb2686450 100644
--- a/lib/modules/manager/cargo/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/cargo/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/cargo/extract extractPackageFile() extracts multiple dependencies advanced 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > extracts multiple dependencies advanced 1`] = `
 [
   {
     "currentValue": "0.2.0",
@@ -242,7 +242,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts multiple de
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() extracts multiple dependencies simple 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > extracts multiple dependencies simple 1`] = `
 [
   {
     "currentValue": "=0.2.43",
@@ -391,7 +391,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts multiple de
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() extracts original package name of renamed dependencies 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > extracts original package name of renamed dependencies 1`] = `
 [
   {
     "currentValue": "0.4.0",
@@ -406,7 +406,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts original pa
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() extracts platform specific dependencies 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > extracts platform specific dependencies 1`] = `
 [
   {
     "currentValue": "0.2.37",
@@ -452,7 +452,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts platform sp
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() extracts registry urls from .cargo/config (legacy path) 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > extracts registry urls from .cargo/config (legacy path) 1`] = `
 [
   {
     "currentValue": "0.1.0",
@@ -492,7 +492,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts registry ur
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() extracts registry urls from .cargo/config.toml 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > extracts registry urls from .cargo/config.toml 1`] = `
 [
   {
     "currentValue": "0.1.0",
@@ -532,7 +532,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts registry ur
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() fails to parse cargo config with invalid TOML 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > fails to parse cargo config with invalid TOML 1`] = `
 [
   {
     "currentValue": "0.1.0",
@@ -568,7 +568,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() fails to parse cargo
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() handles inline tables 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > handles inline tables 1`] = `
 [
   {
     "currentValue": "0.1",
@@ -650,7 +650,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() handles inline table
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() handles standard tables 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > handles standard tables 1`] = `
 [
   {
     "currentValue": "1.2",
@@ -715,7 +715,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() handles standard tab
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() ignore cargo config registries with missing index 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > ignore cargo config registries with missing index 1`] = `
 [
   {
     "currentValue": "0.1.0",
@@ -751,7 +751,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() ignore cargo config
 ]
 `;
 
-exports[`modules/manager/cargo/extract extractPackageFile() skips unknown registries 1`] = `
+exports[`modules/manager/cargo/extract > extractPackageFile() > skips unknown registries 1`] = `
 [
   {
     "currentValue": "0.1.0",
diff --git a/lib/modules/manager/cargo/artifacts.spec.ts b/lib/modules/manager/cargo/artifacts.spec.ts
index 59328f8716..bf2ae4747e 100644
--- a/lib/modules/manager/cargo/artifacts.spec.ts
+++ b/lib/modules/manager/cargo/artifacts.spec.ts
@@ -14,11 +14,11 @@ import * as _hostRules from '../../../util/host-rules';
 import type { UpdateArtifactsConfig } from '../types';
 import * as cargo from '.';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/git');
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('../../../util/http');
-jest.mock('../../../util/fs');
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/git');
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/http');
+vi.mock('../../../util/fs');
 
 process.env.CONTAINERBASE = 'true';
 const hostRules = mocked(_hostRules);
diff --git a/lib/modules/manager/cargo/extract.spec.ts b/lib/modules/manager/cargo/extract.spec.ts
index d379da8257..093cf8885a 100644
--- a/lib/modules/manager/cargo/extract.spec.ts
+++ b/lib/modules/manager/cargo/extract.spec.ts
@@ -4,7 +4,7 @@ import { fs } from '../../../../test/util';
 import type { ExtractConfig } from '../types';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 function mockReadLocalFile(files: Record<string, string | null>) {
   fs.readLocalFile.mockImplementation((file): Promise<any> => {
diff --git a/lib/modules/manager/cargo/locked-version.spec.ts b/lib/modules/manager/cargo/locked-version.spec.ts
index d158d9ace2..ba4cfca7de 100644
--- a/lib/modules/manager/cargo/locked-version.spec.ts
+++ b/lib/modules/manager/cargo/locked-version.spec.ts
@@ -2,7 +2,7 @@ import { Fixtures } from '../../../../test/fixtures';
 import { fs } from '../../../../test/util';
 import { extractLockFileVersions, parseLockFile } from './locked-version';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 function mockReadLocalFile(files: Record<string, string | null>) {
   fs.readLocalFile.mockImplementation((file): Promise<any> => {
diff --git a/lib/modules/manager/cdnurl/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/cdnurl/__snapshots__/extract.spec.ts.snap
index a66b4b6655..301d518a37 100644
--- a/lib/modules/manager/cdnurl/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/cdnurl/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/cdnurl/extract extractPackageFile 1`] = `
+exports[`modules/manager/cdnurl/extract > extractPackageFile 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/cloudbuild/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/cloudbuild/__snapshots__/extract.spec.ts.snap
index 4b89bef9ad..f7de24a169 100644
--- a/lib/modules/manager/cloudbuild/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/cloudbuild/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/cloudbuild/extract extractPackageFile() extracts multiple image lines 1`] = `
+exports[`modules/manager/cloudbuild/extract > extractPackageFile() > extracts multiple image lines 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
diff --git a/lib/modules/manager/cocoapods/__snapshots__/artifacts.spec.ts.snap b/lib/modules/manager/cocoapods/__snapshots__/artifacts.spec.ts.snap
index 3e0f072131..1257c5aebb 100644
--- a/lib/modules/manager/cocoapods/__snapshots__/artifacts.spec.ts.snap
+++ b/lib/modules/manager/cocoapods/__snapshots__/artifacts.spec.ts.snap
@@ -1,12 +1,12 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/cocoapods/artifacts returns null for invalid local directory 1`] = `[]`;
+exports[`modules/manager/cocoapods/artifacts > returns null for invalid local directory 1`] = `[]`;
 
-exports[`modules/manager/cocoapods/artifacts returns null if no Podfile.lock found 1`] = `[]`;
+exports[`modules/manager/cocoapods/artifacts > returns null if no Podfile.lock found 1`] = `[]`;
 
-exports[`modules/manager/cocoapods/artifacts returns null if no updatedDeps were provided 1`] = `[]`;
+exports[`modules/manager/cocoapods/artifacts > returns null if no updatedDeps were provided 1`] = `[]`;
 
-exports[`modules/manager/cocoapods/artifacts returns null if unchanged 1`] = `
+exports[`modules/manager/cocoapods/artifacts > returns null if unchanged 1`] = `
 [
   {
     "cmd": "pod install",
@@ -29,9 +29,9 @@ exports[`modules/manager/cocoapods/artifacts returns null if unchanged 1`] = `
 ]
 `;
 
-exports[`modules/manager/cocoapods/artifacts returns null if updatedDeps is empty 1`] = `[]`;
+exports[`modules/manager/cocoapods/artifacts > returns null if updatedDeps is empty 1`] = `[]`;
 
-exports[`modules/manager/cocoapods/artifacts returns pod exec error 1`] = `
+exports[`modules/manager/cocoapods/artifacts > returns pod exec error 1`] = `
 [
   {
     "cmd": "pod install",
@@ -54,7 +54,7 @@ exports[`modules/manager/cocoapods/artifacts returns pod exec error 1`] = `
 ]
 `;
 
-exports[`modules/manager/cocoapods/artifacts returns updated Podfile 1`] = `
+exports[`modules/manager/cocoapods/artifacts > returns updated Podfile 1`] = `
 [
   {
     "cmd": "docker pull ghcr.io/containerbase/sidecar",
@@ -84,7 +84,7 @@ exports[`modules/manager/cocoapods/artifacts returns updated Podfile 1`] = `
 ]
 `;
 
-exports[`modules/manager/cocoapods/artifacts returns updated Podfile and Pods files 1`] = `
+exports[`modules/manager/cocoapods/artifacts > returns updated Podfile and Pods files 1`] = `
 [
   {
     "cmd": "docker pull ghcr.io/containerbase/sidecar",
diff --git a/lib/modules/manager/cocoapods/artifacts.spec.ts b/lib/modules/manager/cocoapods/artifacts.spec.ts
index 11f40812ba..54ae7e7c48 100644
--- a/lib/modules/manager/cocoapods/artifacts.spec.ts
+++ b/lib/modules/manager/cocoapods/artifacts.spec.ts
@@ -10,10 +10,10 @@ import * as _datasource from '../../datasource';
 import type { UpdateArtifactsConfig } from '../types';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/git');
-jest.mock('../../../util/fs');
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/git');
+vi.mock('../../../util/fs');
+vi.mock('../../datasource', () => mockDeep());
 
 const datasource = mocked(_datasource);
 
diff --git a/lib/modules/manager/composer/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/composer/__snapshots__/extract.spec.ts.snap
index 14c8964636..2034a77e6f 100644
--- a/lib/modules/manager/composer/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/composer/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/composer/extract extractPackageFile() extracts dependencies with lock file 1`] = `
+exports[`modules/manager/composer/extract > extractPackageFile() > extracts dependencies with lock file 1`] = `
 {
   "deps": [
     {
@@ -213,7 +213,7 @@ exports[`modules/manager/composer/extract extractPackageFile() extracts dependen
 }
 `;
 
-exports[`modules/manager/composer/extract extractPackageFile() extracts dependencies with no lock file 1`] = `
+exports[`modules/manager/composer/extract > extractPackageFile() > extracts dependencies with no lock file 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/composer/artifacts.spec.ts b/lib/modules/manager/composer/artifacts.spec.ts
index 4229040a6c..4786db6e2b 100644
--- a/lib/modules/manager/composer/artifacts.spec.ts
+++ b/lib/modules/manager/composer/artifacts.spec.ts
@@ -13,10 +13,10 @@ import { PackagistDatasource } from '../../datasource/packagist';
 import type { UpdateArtifactsConfig } from '../types';
 import * as composer from '.';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../datasource', () => mockDeep());
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
+vi.mock('../../../util/exec/env');
+vi.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/composer/extract.spec.ts b/lib/modules/manager/composer/extract.spec.ts
index c55d8857d4..fdeafa3b15 100644
--- a/lib/modules/manager/composer/extract.spec.ts
+++ b/lib/modules/manager/composer/extract.spec.ts
@@ -3,7 +3,7 @@ import { Fixtures } from '../../../../test/fixtures';
 import { fs } from '../../../../test/util';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const requirements1 = Fixtures.get('composer1.json');
 const requirements2 = Fixtures.get('composer2.json');
diff --git a/lib/modules/manager/composer/utils.spec.ts b/lib/modules/manager/composer/utils.spec.ts
index 22fb07fd29..4bc799786d 100644
--- a/lib/modules/manager/composer/utils.spec.ts
+++ b/lib/modules/manager/composer/utils.spec.ts
@@ -8,7 +8,7 @@ import {
   requireComposerDependencyInstallation,
 } from './utils';
 
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../datasource', () => mockDeep());
 
 describe('modules/manager/composer/utils', () => {
   beforeEach(() => {
diff --git a/lib/modules/manager/copier/artifacts.spec.ts b/lib/modules/manager/copier/artifacts.spec.ts
index cd3e7df4c6..1c3ffff417 100644
--- a/lib/modules/manager/copier/artifacts.spec.ts
+++ b/lib/modules/manager/copier/artifacts.spec.ts
@@ -12,9 +12,9 @@ import { updateArtifacts } from '.';
 
 const datasource = mocked(_datasource);
 
-jest.mock('../../../util/git');
-jest.mock('../../../util/fs');
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/git');
+vi.mock('../../../util/fs');
+vi.mock('../../datasource', () => mockDeep());
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/cpanfile/extract.spec.ts b/lib/modules/manager/cpanfile/extract.spec.ts
index 6bdc1809a7..ed78e5132c 100644
--- a/lib/modules/manager/cpanfile/extract.spec.ts
+++ b/lib/modules/manager/cpanfile/extract.spec.ts
@@ -205,7 +205,7 @@ describe('modules/manager/cpanfile/extract', () => {
         });
       });
 
-      test('test phase', () => {
+      test('phase', () => {
         expect(
           extractPackageFile(
             codeBlock`
diff --git a/lib/modules/manager/custom/regex/__snapshots__/index.spec.ts.snap b/lib/modules/manager/custom/regex/__snapshots__/index.spec.ts.snap
index 25dd366315..358a5a5e96 100644
--- a/lib/modules/manager/custom/regex/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/manager/custom/regex/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/custom/regex/index extracts and applies a registryUrlTemplate 1`] = `
+exports[`modules/manager/custom/regex/index > extracts and applies a registryUrlTemplate 1`] = `
 {
   "deps": [
     {
@@ -22,7 +22,7 @@ exports[`modules/manager/custom/regex/index extracts and applies a registryUrlTe
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts and does not apply a registryUrlTemplate if the result is an invalid url 1`] = `
+exports[`modules/manager/custom/regex/index > extracts and does not apply a registryUrlTemplate if the result is an invalid url 1`] = `
 {
   "deps": [
     {
@@ -41,7 +41,7 @@ exports[`modules/manager/custom/regex/index extracts and does not apply a regist
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts dependency with autoReplaceStringTemplate 1`] = `
+exports[`modules/manager/custom/regex/index > extracts dependency with autoReplaceStringTemplate 1`] = `
 {
   "autoReplaceStringTemplate": "image: {{{depName}}}:{{{newValue}}}",
   "datasourceTemplate": "docker",
@@ -60,7 +60,7 @@ exports[`modules/manager/custom/regex/index extracts dependency with autoReplace
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts extractVersion 1`] = `
+exports[`modules/manager/custom/regex/index > extracts extractVersion 1`] = `
 {
   "deps": [
     {
@@ -79,7 +79,7 @@ exports[`modules/manager/custom/regex/index extracts extractVersion 1`] = `
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts multiple dependencies 1`] = `
+exports[`modules/manager/custom/regex/index > extracts multiple dependencies 1`] = `
 {
   "depTypeTemplate": "final",
   "deps": [
@@ -163,7 +163,7 @@ exports[`modules/manager/custom/regex/index extracts multiple dependencies 1`] =
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts multiple dependencies with multiple matchStrings 1`] = `
+exports[`modules/manager/custom/regex/index > extracts multiple dependencies with multiple matchStrings 1`] = `
 {
   "deps": [
     {
@@ -191,7 +191,7 @@ exports[`modules/manager/custom/regex/index extracts multiple dependencies with
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts registryUrl 1`] = `
+exports[`modules/manager/custom/regex/index > extracts registryUrl 1`] = `
 {
   "datasourceTemplate": "helm",
   "deps": [
@@ -219,7 +219,7 @@ exports[`modules/manager/custom/regex/index extracts registryUrl 1`] = `
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts with combination strategy 1`] = `
+exports[`modules/manager/custom/regex/index > extracts with combination strategy 1`] = `
 {
   "datasourceTemplate": "docker",
   "deps": [
@@ -238,7 +238,7 @@ exports[`modules/manager/custom/regex/index extracts with combination strategy 1
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts with combination strategy and multiple matches 1`] = `
+exports[`modules/manager/custom/regex/index > extracts with combination strategy and multiple matches 1`] = `
 {
   "datasourceTemplate": "docker",
   "deps": [
@@ -257,7 +257,7 @@ exports[`modules/manager/custom/regex/index extracts with combination strategy a
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts with combination strategy and non standard capture groups 1`] = `
+exports[`modules/manager/custom/regex/index > extracts with combination strategy and non standard capture groups 1`] = `
 {
   "datasourceTemplate": "docker",
   "depNameTemplate": "{{{ registry }}}/{{{ repository }}}",
@@ -279,7 +279,7 @@ exports[`modules/manager/custom/regex/index extracts with combination strategy a
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts with combination strategy and registry url 1`] = `
+exports[`modules/manager/custom/regex/index > extracts with combination strategy and registry url 1`] = `
 {
   "datasourceTemplate": "helm",
   "deps": [
@@ -304,7 +304,7 @@ exports[`modules/manager/custom/regex/index extracts with combination strategy a
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts with combination strategy and templates 1`] = `
+exports[`modules/manager/custom/regex/index > extracts with combination strategy and templates 1`] = `
 {
   "datasourceTemplate": "helm",
   "depNameTemplate": "helm_repo/{{{ depName }}}",
@@ -329,7 +329,7 @@ exports[`modules/manager/custom/regex/index extracts with combination strategy a
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts with recursive strategy and merged groups 1`] = `
+exports[`modules/manager/custom/regex/index > extracts with recursive strategy and merged groups 1`] = `
 {
   "depNameTemplate": "{{{ first }}}/{{{ second }}}/{{{ depName }}}",
   "deps": [
@@ -375,7 +375,7 @@ exports[`modules/manager/custom/regex/index extracts with recursive strategy and
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts with recursive strategy and multiple layers  1`] = `
+exports[`modules/manager/custom/regex/index > extracts with recursive strategy and multiple layers 1`] = `
 {
   "deps": [
     {
@@ -396,7 +396,7 @@ exports[`modules/manager/custom/regex/index extracts with recursive strategy and
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts with recursive strategy and multiple matches 1`] = `
+exports[`modules/manager/custom/regex/index > extracts with recursive strategy and multiple matches 1`] = `
 {
   "deps": [
     {
@@ -424,7 +424,7 @@ exports[`modules/manager/custom/regex/index extracts with recursive strategy and
 }
 `;
 
-exports[`modules/manager/custom/regex/index extracts with recursive strategy and single match 1`] = `
+exports[`modules/manager/custom/regex/index > extracts with recursive strategy and single match 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/custom/regex/index.spec.ts b/lib/modules/manager/custom/regex/index.spec.ts
index 560e4c02d5..ba6677519d 100644
--- a/lib/modules/manager/custom/regex/index.spec.ts
+++ b/lib/modules/manager/custom/regex/index.spec.ts
@@ -513,7 +513,7 @@ describe('modules/manager/custom/regex/index', () => {
     expect(res?.deps).toHaveLength(2);
   });
 
-  it('extracts with recursive strategy and multiple layers ', async () => {
+  it('extracts with recursive strategy and multiple layers', async () => {
     const config: CustomExtractConfig = {
       matchStrings: [
         '"backup":\\s*{[^}]*}',
diff --git a/lib/modules/manager/deps-edn/__snapshots__/parser.spec.ts.snap b/lib/modules/manager/deps-edn/__snapshots__/parser.spec.ts.snap
index aebeca80a8..4f05d02f28 100644
--- a/lib/modules/manager/deps-edn/__snapshots__/parser.spec.ts.snap
+++ b/lib/modules/manager/deps-edn/__snapshots__/parser.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/deps-edn/parser parseEdnFile extracts file 1`] = `
+exports[`modules/manager/deps-edn/parser > parseEdnFile > extracts file 1`] = `
 {
   "aliases": {
     "1.10": {
diff --git a/lib/modules/manager/devbox/artifacts.spec.ts b/lib/modules/manager/devbox/artifacts.spec.ts
index f2ffbd4dcf..e3c9a38735 100644
--- a/lib/modules/manager/devbox/artifacts.spec.ts
+++ b/lib/modules/manager/devbox/artifacts.spec.ts
@@ -7,9 +7,9 @@ import type { StatusResult } from '../../../util/git/types';
 import type { UpdateArtifact } from '../types';
 import { updateArtifacts } from './artifacts';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/git');
-jest.mock('../../../util/fs');
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/git');
+vi.mock('../../../util/fs');
 
 const globalConfig: RepoGlobalConfig = {
   localDir: '',
diff --git a/lib/modules/manager/docker-compose/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/docker-compose/__snapshots__/extract.spec.ts.snap
index d977673c61..e789348682 100644
--- a/lib/modules/manager/docker-compose/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/docker-compose/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/docker-compose/extract extractPackageFile() extracts multiple image lines for version 1 1`] = `
+exports[`modules/manager/docker-compose/extract > extractPackageFile() > extracts multiple image lines for version 1 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
@@ -74,7 +74,7 @@ exports[`modules/manager/docker-compose/extract extractPackageFile() extracts mu
 ]
 `;
 
-exports[`modules/manager/docker-compose/extract extractPackageFile() extracts multiple image lines for version 3 1`] = `
+exports[`modules/manager/docker-compose/extract > extractPackageFile() > extracts multiple image lines for version 3 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
@@ -148,7 +148,7 @@ exports[`modules/manager/docker-compose/extract extractPackageFile() extracts mu
 ]
 `;
 
-exports[`modules/manager/docker-compose/extract extractPackageFile() extracts multiple image lines for version 3 without set version key 1`] = `
+exports[`modules/manager/docker-compose/extract > extractPackageFile() > extracts multiple image lines for version 3 without set version key 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
diff --git a/lib/modules/manager/droneci/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/droneci/__snapshots__/extract.spec.ts.snap
index a5b0403ea1..a67efb2e06 100644
--- a/lib/modules/manager/droneci/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/droneci/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/droneci/extract extractPackageFile() extracts multiple image lines 1`] = `
+exports[`modules/manager/droneci/extract > extractPackageFile() > extracts multiple image lines 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
diff --git a/lib/modules/manager/flux/artifacts.spec.ts b/lib/modules/manager/flux/artifacts.spec.ts
index 9a7d507ec5..232dd81c0d 100644
--- a/lib/modules/manager/flux/artifacts.spec.ts
+++ b/lib/modules/manager/flux/artifacts.spec.ts
@@ -3,7 +3,7 @@ import { fs } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/flux/artifacts', () => {
   beforeAll(() => {
diff --git a/lib/modules/manager/git-submodules/extract.spec.ts b/lib/modules/manager/git-submodules/extract.spec.ts
index bee65e98a4..6b528b8b78 100644
--- a/lib/modules/manager/git-submodules/extract.spec.ts
+++ b/lib/modules/manager/git-submodules/extract.spec.ts
@@ -1,27 +1,28 @@
 import is from '@sindresorhus/is';
-import { mock } from 'jest-mock-extended';
-import type { Response, SimpleGit, SimpleGitFactory } from 'simple-git';
-import { simpleGit } from 'simple-git';
+import type { Response, SimpleGit } from 'simple-git';
+import Git from 'simple-git';
+import { mock } from 'vitest-mock-extended';
 import { GlobalConfig } from '../../../config/global';
 import * as hostRules from '../../../util/host-rules';
 import { extractPackageFile } from '.';
 
-jest.mock('simple-git');
-const simpleGitFactoryMock = simpleGit as jest.Mock<Partial<SimpleGit>>;
-const Git = jest.requireActual<SimpleGitFactory>('simple-git');
+vi.mock('simple-git', () => ({ default: vi.fn() }));
+const simpleGitFactoryMock = vi.mocked(Git);
 
 const gitMock = mock<SimpleGit>();
 
 describe('modules/manager/git-submodules/extract', () => {
-  beforeEach(() => {
+  beforeEach(async () => {
+    const { simpleGit: Git } =
+      await vi.importActual<typeof import('simple-git')>('simple-git');
     GlobalConfig.set({ localDir: `${__dirname}/__fixtures__` });
     // clear host rules
     hostRules.clear();
     // clear environment variables
     process.env = {};
 
-    simpleGitFactoryMock.mockImplementation((basePath: string) => {
-      const git = Git(basePath);
+    simpleGitFactoryMock.mockImplementation((...args: any[]) => {
+      const git = Git(...args);
 
       gitMock.env.mockImplementation(() => gitMock);
       gitMock.subModule.mockResolvedValue(
diff --git a/lib/modules/manager/git-submodules/update.spec.ts b/lib/modules/manager/git-submodules/update.spec.ts
index 3013a6b239..6629b54c6f 100644
--- a/lib/modules/manager/git-submodules/update.spec.ts
+++ b/lib/modules/manager/git-submodules/update.spec.ts
@@ -1,19 +1,19 @@
-import { mock } from 'jest-mock-extended';
 import type { SimpleGit } from 'simple-git';
 import { simpleGit } from 'simple-git';
 import type { DirectoryResult } from 'tmp-promise';
 import { dir } from 'tmp-promise';
 import { join } from 'upath';
+import { mock } from 'vitest-mock-extended';
 import { fs } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
 import type { RepoGlobalConfig } from '../../../config/types';
 import * as hostRules from '../../../util/host-rules';
 import type { Upgrade } from '../types';
 import { updateDependency } from '.';
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
-jest.mock('simple-git');
-const simpleGitFactoryMock = simpleGit as jest.Mock<Partial<SimpleGit>>;
+vi.mock('simple-git');
+const simpleGitFactoryMock = vi.mocked(simpleGit);
 const gitMock = mock<SimpleGit>();
 
 describe('modules/manager/git-submodules/update', () => {
@@ -25,7 +25,7 @@ describe('modules/manager/git-submodules/update', () => {
     process.env = {};
 
     simpleGitFactoryMock.mockReturnValue(gitMock);
-    gitMock.env.mockImplementation(() => gitMock);
+    gitMock.env.mockReturnValue(gitMock);
   });
 
   describe('updateDependency', () => {
diff --git a/lib/modules/manager/github-actions/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/github-actions/__snapshots__/extract.spec.ts.snap
index 2d48fac1dd..78eb551c8c 100644
--- a/lib/modules/manager/github-actions/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/github-actions/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/github-actions/extract extractPackageFile() extracts multiple action tag lines from yaml configuration file 1`] = `
+exports[`modules/manager/github-actions/extract > extractPackageFile() > extracts multiple action tag lines from yaml configuration file 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{depName}}/shellcheck@{{#if newDigest}}{{newDigest}}{{#if newValue}} # {{newValue}}{{/if}}{{/if}}{{#unless newDigest}}{{newValue}}{{/unless}}",
@@ -116,7 +116,7 @@ exports[`modules/manager/github-actions/extract extractPackageFile() extracts mu
 ]
 `;
 
-exports[`modules/manager/github-actions/extract extractPackageFile() extracts multiple docker image lines from yaml configuration file 1`] = `
+exports[`modules/manager/github-actions/extract > extractPackageFile() > extracts multiple docker image lines from yaml configuration file 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{depName}}/shellcheck@{{#if newDigest}}{{newDigest}}{{#if newValue}} # {{newValue}}{{/if}}{{/if}}{{#unless newDigest}}{{newValue}}{{/unless}}",
diff --git a/lib/modules/manager/gitlabci-include/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/gitlabci-include/__snapshots__/extract.spec.ts.snap
index 986b82e20f..fdc5f16c35 100644
--- a/lib/modules/manager/gitlabci-include/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/gitlabci-include/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/gitlabci-include/extract extractPackageFile() extracts multiple include blocks 1`] = `
+exports[`modules/manager/gitlabci-include/extract > extractPackageFile() > extracts multiple include blocks 1`] = `
 [
   {
     "currentValue": "1.0.0",
@@ -23,7 +23,7 @@ exports[`modules/manager/gitlabci-include/extract extractPackageFile() extracts
 ]
 `;
 
-exports[`modules/manager/gitlabci-include/extract extractPackageFile() extracts single include block 1`] = `
+exports[`modules/manager/gitlabci-include/extract > extractPackageFile() > extracts single include block 1`] = `
 [
   {
     "currentValue": "1.0.0",
diff --git a/lib/modules/manager/gitlabci/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/gitlabci/__snapshots__/extract.spec.ts.snap
index 46e96348ee..d7b9285c90 100644
--- a/lib/modules/manager/gitlabci/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/gitlabci/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/gitlabci/extract extractAllPackageFiles() extracts multiple image lines 1`] = `
+exports[`modules/manager/gitlabci/extract > extractAllPackageFiles() > extracts multiple image lines 1`] = `
 [
   {
     "deps": [
@@ -90,7 +90,7 @@ exports[`modules/manager/gitlabci/extract extractAllPackageFiles() extracts mult
 ]
 `;
 
-exports[`modules/manager/gitlabci/extract extractAllPackageFiles() extracts multiple image lines with comments 1`] = `
+exports[`modules/manager/gitlabci/extract > extractAllPackageFiles() > extracts multiple image lines with comments 1`] = `
 [
   {
     "deps": [
@@ -130,7 +130,7 @@ exports[`modules/manager/gitlabci/extract extractAllPackageFiles() extracts mult
 ]
 `;
 
-exports[`modules/manager/gitlabci/extract extractAllPackageFiles() extracts multiple included image lines 1`] = `
+exports[`modules/manager/gitlabci/extract > extractAllPackageFiles() > extracts multiple included image lines 1`] = `
 [
   {
     "deps": [
@@ -200,7 +200,7 @@ exports[`modules/manager/gitlabci/extract extractAllPackageFiles() extracts mult
 ]
 `;
 
-exports[`modules/manager/gitlabci/extract extractAllPackageFiles() extracts multiple named services 1`] = `
+exports[`modules/manager/gitlabci/extract > extractAllPackageFiles() > extracts multiple named services 1`] = `
 [
   {
     "deps": [
@@ -310,7 +310,7 @@ exports[`modules/manager/gitlabci/extract extractAllPackageFiles() extracts mult
 ]
 `;
 
-exports[`modules/manager/gitlabci/extract extractAllPackageFiles() extracts named services 1`] = `
+exports[`modules/manager/gitlabci/extract > extractAllPackageFiles() > extracts named services 1`] = `
 [
   {
     "deps": [
diff --git a/lib/modules/manager/glasskube/extract.spec.ts b/lib/modules/manager/glasskube/extract.spec.ts
index 7d8455de1a..c1ccf1e4f7 100644
--- a/lib/modules/manager/glasskube/extract.spec.ts
+++ b/lib/modules/manager/glasskube/extract.spec.ts
@@ -32,7 +32,7 @@ spec:
   url: https://packages.dl.glasskube.dev/packages
 `;
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/glasskube/extract', () => {
   beforeEach(() => {
diff --git a/lib/modules/manager/gleam/artifacts.spec.ts b/lib/modules/manager/gleam/artifacts.spec.ts
index d1e684d924..fd1c06df2d 100644
--- a/lib/modules/manager/gleam/artifacts.spec.ts
+++ b/lib/modules/manager/gleam/artifacts.spec.ts
@@ -8,8 +8,8 @@ import * as _fs from '../../../util/fs';
 import type { UpdateArtifact } from '../types';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/exec');
-jest.mock('../../../util/fs');
+vi.mock('../../../util/exec');
+vi.mock('../../../util/fs');
 
 const exec = mocked(_exec);
 const fs = mocked(_fs);
diff --git a/lib/modules/manager/gleam/extract.spec.ts b/lib/modules/manager/gleam/extract.spec.ts
index ecd61afc62..48f23120ce 100644
--- a/lib/modules/manager/gleam/extract.spec.ts
+++ b/lib/modules/manager/gleam/extract.spec.ts
@@ -3,7 +3,7 @@ import { mocked } from '../../../../test/util';
 import * as _fs from '../../../util/fs';
 import * as gleamManager from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const fs = mocked(_fs);
 
diff --git a/lib/modules/manager/gleam/locked-version.spec.ts b/lib/modules/manager/gleam/locked-version.spec.ts
index 3203d04f14..543a8d03e2 100644
--- a/lib/modules/manager/gleam/locked-version.spec.ts
+++ b/lib/modules/manager/gleam/locked-version.spec.ts
@@ -4,7 +4,7 @@ import { logger } from '../../../logger';
 import * as _fs from '../../../util/fs';
 import { extractLockFileVersions, parseLockFile } from './locked-version';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const fs = mocked(_fs);
 
diff --git a/lib/modules/manager/gomod/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/gomod/__snapshots__/extract.spec.ts.snap
index 93e19c1eaf..533f3215ff 100644
--- a/lib/modules/manager/gomod/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/gomod/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/gomod/extract extractPackageFile() extracts multi-line requires 1`] = `
+exports[`modules/manager/gomod/extract > extractPackageFile() > extracts multi-line requires 1`] = `
 [
   {
     "currentValue": "v1.15.21",
@@ -680,7 +680,7 @@ exports[`modules/manager/gomod/extract extractPackageFile() extracts multi-line
 ]
 `;
 
-exports[`modules/manager/gomod/extract extractPackageFile() extracts single-line requires 1`] = `
+exports[`modules/manager/gomod/extract > extractPackageFile() > extracts single-line requires 1`] = `
 [
   {
     "currentValue": "v0.7.0",
diff --git a/lib/modules/manager/gomod/__snapshots__/update.spec.ts.snap b/lib/modules/manager/gomod/__snapshots__/update.spec.ts.snap
index 2257c0b85f..02e16dc999 100644
--- a/lib/modules/manager/gomod/__snapshots__/update.spec.ts.snap
+++ b/lib/modules/manager/gomod/__snapshots__/update.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/gomod/update updateDependency replaces major gopkg.in updates 1`] = `
+exports[`modules/manager/gomod/update > updateDependency > replaces major gopkg.in updates 1`] = `
 "module github.com/renovate-tests/gomod1
 
 require github.com/pkg/errors v0.7.0
@@ -18,7 +18,7 @@ require github.com/caarlos0/env v3.5.0+incompatible
 "
 `;
 
-exports[`modules/manager/gomod/update updateDependency replaces quoted multiline 1`] = `
+exports[`modules/manager/gomod/update > updateDependency > replaces quoted multiline 1`] = `
 "module github.com/jesseduffield/lazygit
 
 require (
@@ -85,7 +85,7 @@ require (
 "
 `;
 
-exports[`modules/manager/gomod/update updateDependency replaces two values in one file 1`] = `
+exports[`modules/manager/gomod/update > updateDependency > replaces two values in one file 1`] = `
 "module github.com/renovate-tests/gomod1
 
 require github.com/pkg/errors v0.8.0
diff --git a/lib/modules/manager/gomod/artifacts.spec.ts b/lib/modules/manager/gomod/artifacts.spec.ts
index 4310e6887c..9b36eaf94f 100644
--- a/lib/modules/manager/gomod/artifacts.spec.ts
+++ b/lib/modules/manager/gomod/artifacts.spec.ts
@@ -15,21 +15,19 @@ import * as gomod from '.';
 
 type FS = typeof import('../../../util/fs');
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/git');
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('../../../util/http');
-jest.mock('../../../util/fs', () => {
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/git');
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/http');
+vi.mock('../../../util/fs', async () => {
   // restore
-  return {
-    __esModules: true,
-    ...jest.createMockFromModule<FS>('../../../util/fs'),
-    isValidLocalPath:
-      jest.requireActual<FS>('../../../util/fs').isValidLocalPath,
-  };
+  return mockDeep({
+    isValidLocalPath: (await vi.importActual<FS>('../../../util/fs'))
+      .isValidLocalPath,
+  });
 });
-jest.mock('../../datasource', () => mockDeep());
-jest.mock('./artifacts-extra', () => mockDeep());
+vi.mock('../../datasource', () => mockDeep());
+vi.mock('./artifacts-extra', () => mockDeep());
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/gradle-wrapper/artifacts.spec.ts b/lib/modules/manager/gradle-wrapper/artifacts.spec.ts
index 47caeb5cc8..f362aa6875 100644
--- a/lib/modules/manager/gradle-wrapper/artifacts.spec.ts
+++ b/lib/modules/manager/gradle-wrapper/artifacts.spec.ts
@@ -23,11 +23,11 @@ import type { UpdateArtifactsConfig, UpdateArtifactsResult } from '../types';
 import { updateBuildFile, updateLockFiles } from './artifacts';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
-jest.mock('../../../util/exec/env');
-jest.mock('../../datasource', () => mockDeep());
-jest.mock('../gradle');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../../../util/exec/env');
+vi.mock('../../datasource', () => mockDeep());
+vi.mock('../gradle');
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/gradle-wrapper/util.spec.ts b/lib/modules/manager/gradle-wrapper/util.spec.ts
index 5087e073d3..3160f8f1de 100644
--- a/lib/modules/manager/gradle-wrapper/util.spec.ts
+++ b/lib/modules/manager/gradle-wrapper/util.spec.ts
@@ -12,7 +12,7 @@ import {
 } from './utils';
 
 const platform = jest.spyOn(os, 'platform');
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/gradle-wrapper/util', () => {
   describe('getJavaConstraint()', () => {
diff --git a/lib/modules/manager/gradle/artifacts.spec.ts b/lib/modules/manager/gradle/artifacts.spec.ts
index 94cffe9dc0..dc96f38f4d 100644
--- a/lib/modules/manager/gradle/artifacts.spec.ts
+++ b/lib/modules/manager/gradle/artifacts.spec.ts
@@ -24,10 +24,10 @@ import type { StatusResult } from '../../../util/git/types';
 import { getPkgReleases } from '../../datasource';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
-jest.mock('../../../util/exec/env');
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../../../util/exec/env');
+vi.mock('../../datasource', () => mockDeep());
 
 process.env.CONTAINERBASE = 'true';
 
@@ -79,8 +79,7 @@ describe('modules/manager/gradle/artifacts', () => {
       }),
     );
 
-    // TODO: fix types, jest is using wrong overload (#22198)
-    fs.readLocalFile.mockImplementation((fileName: string): Promise<any> => {
+    fs.readLocalFile.mockImplementation((fileName: string): Promise<string> => {
       let content = '';
       if (fileName === 'gradle.lockfile') {
         content = 'New gradle.lockfile';
diff --git a/lib/modules/manager/gradle/extract.spec.ts b/lib/modules/manager/gradle/extract.spec.ts
index 65995556f3..49476cf9d4 100644
--- a/lib/modules/manager/gradle/extract.spec.ts
+++ b/lib/modules/manager/gradle/extract.spec.ts
@@ -6,18 +6,19 @@ import { matchesContentDescriptor } from './extract';
 import * as parser from './parser';
 import { extractAllPackageFiles } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 function mockFs(files: Record<string, string>): void {
-  // TODO: fix types, jest is using wrong overload (#22198)
-  fs.getLocalFiles.mockImplementation((fileNames: string[]): Promise<any> => {
-    const fileContentMap: Record<string, string | null> = {};
-    for (const fileName of fileNames) {
-      fileContentMap[fileName] = files?.[fileName];
-    }
-
-    return Promise.resolve(fileContentMap);
-  });
+  fs.getLocalFiles.mockImplementation(
+    (fileNames: string[]): Promise<Record<string, string | null>> => {
+      const fileContentMap: Record<string, string | null> = {};
+      for (const fileName of fileNames) {
+        fileContentMap[fileName] = files?.[fileName];
+      }
+
+      return Promise.resolve(fileContentMap);
+    },
+  );
 
   fs.getSiblingFileName.mockImplementation(
     (existingFileNameWithPath: string, otherFileName: string) => {
diff --git a/lib/modules/manager/gradle/parser.spec.ts b/lib/modules/manager/gradle/parser.spec.ts
index 365c20867b..9839218328 100644
--- a/lib/modules/manager/gradle/parser.spec.ts
+++ b/lib/modules/manager/gradle/parser.spec.ts
@@ -14,7 +14,7 @@ import {
   REGISTRY_URLS,
 } from './parser/common';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 function mockFs(files: Record<string, string>): void {
   fs.getSiblingFileName.mockImplementation(
diff --git a/lib/modules/manager/helm-requirements/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/helm-requirements/__snapshots__/extract.spec.ts.snap
index 9b4da68fb8..a2f2a047d0 100644
--- a/lib/modules/manager/helm-requirements/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/helm-requirements/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/helm-requirements/extract extractPackageFile() ensure that currentValue is string 1`] = `
+exports[`modules/manager/helm-requirements/extract > extractPackageFile() > ensure that currentValue is string 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -16,7 +16,7 @@ exports[`modules/manager/helm-requirements/extract extractPackageFile() ensure t
 }
 `;
 
-exports[`modules/manager/helm-requirements/extract extractPackageFile() parses simple requirements.yaml correctly 1`] = `
+exports[`modules/manager/helm-requirements/extract > extractPackageFile() > parses simple requirements.yaml correctly 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -38,7 +38,7 @@ exports[`modules/manager/helm-requirements/extract extractPackageFile() parses s
 }
 `;
 
-exports[`modules/manager/helm-requirements/extract extractPackageFile() resolves aliased registry urls 1`] = `
+exports[`modules/manager/helm-requirements/extract > extractPackageFile() > resolves aliased registry urls 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -60,7 +60,7 @@ exports[`modules/manager/helm-requirements/extract extractPackageFile() resolves
 }
 `;
 
-exports[`modules/manager/helm-requirements/extract extractPackageFile() skips invalid registry urls 1`] = `
+exports[`modules/manager/helm-requirements/extract > extractPackageFile() > skips invalid registry urls 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -89,7 +89,7 @@ exports[`modules/manager/helm-requirements/extract extractPackageFile() skips in
 }
 `;
 
-exports[`modules/manager/helm-requirements/extract extractPackageFile() skips local dependencies 1`] = `
+exports[`modules/manager/helm-requirements/extract > extractPackageFile() > skips local dependencies 1`] = `
 {
   "datasource": "helm",
   "deps": [
diff --git a/lib/modules/manager/helm-requirements/extract.spec.ts b/lib/modules/manager/helm-requirements/extract.spec.ts
index e203872bdd..305cc2d2ac 100644
--- a/lib/modules/manager/helm-requirements/extract.spec.ts
+++ b/lib/modules/manager/helm-requirements/extract.spec.ts
@@ -1,7 +1,7 @@
 import { fs } from '../../../../test/util';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/helm-requirements/extract', () => {
   describe('extractPackageFile()', () => {
diff --git a/lib/modules/manager/helm-values/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/helm-values/__snapshots__/extract.spec.ts.snap
index 22ab3d7bab..10690885d6 100644
--- a/lib/modules/manager/helm-values/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/helm-values/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/helm-values/extract extractPackageFile() extracts from complex values file correctly" 1`] = `
+exports[`modules/manager/helm-values/extract > extractPackageFile() > extracts from complex values file correctly" 1`] = `
 {
   "deps": [
     {
@@ -56,7 +56,7 @@ exports[`modules/manager/helm-values/extract extractPackageFile() extracts from
 }
 `;
 
-exports[`modules/manager/helm-values/extract extractPackageFile() extracts from values.yaml correctly with same structure as "helm create" 1`] = `
+exports[`modules/manager/helm-values/extract > extractPackageFile() > extracts from values.yaml correctly with same structure as "helm create" 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/helmfile/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/helmfile/__snapshots__/extract.spec.ts.snap
index 6f6a40faac..6403358750 100644
--- a/lib/modules/manager/helmfile/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/helmfile/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/helmfile/extract extractPackageFile() skip chart that does not have specified version 1`] = `
+exports[`modules/manager/helmfile/extract > extractPackageFile() > skip chart that does not have specified version 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -12,7 +12,7 @@ exports[`modules/manager/helmfile/extract extractPackageFile() skip chart that d
 }
 `;
 
-exports[`modules/manager/helmfile/extract extractPackageFile() skip chart with special character in the name 1`] = `
+exports[`modules/manager/helmfile/extract > extractPackageFile() > skip chart with special character in the name 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -36,7 +36,7 @@ exports[`modules/manager/helmfile/extract extractPackageFile() skip chart with s
 }
 `;
 
-exports[`modules/manager/helmfile/extract extractPackageFile() skip chart with unknown repository 1`] = `
+exports[`modules/manager/helmfile/extract > extractPackageFile() > skip chart with unknown repository 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -50,7 +50,7 @@ exports[`modules/manager/helmfile/extract extractPackageFile() skip chart with u
 }
 `;
 
-exports[`modules/manager/helmfile/extract extractPackageFile() skip if repository details are not specified 1`] = `
+exports[`modules/manager/helmfile/extract > extractPackageFile() > skip if repository details are not specified 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -64,7 +64,7 @@ exports[`modules/manager/helmfile/extract extractPackageFile() skip if repositor
 }
 `;
 
-exports[`modules/manager/helmfile/extract extractPackageFile() skip local charts 1`] = `
+exports[`modules/manager/helmfile/extract > extractPackageFile() > skip local charts 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -76,7 +76,7 @@ exports[`modules/manager/helmfile/extract extractPackageFile() skip local charts
 }
 `;
 
-exports[`modules/manager/helmfile/extract extractPackageFile() skip templetized release with invalid characters 1`] = `
+exports[`modules/manager/helmfile/extract > extractPackageFile() > skip templetized release with invalid characters 1`] = `
 {
   "datasource": "helm",
   "deps": [
diff --git a/lib/modules/manager/helmfile/artifacts.spec.ts b/lib/modules/manager/helmfile/artifacts.spec.ts
index ba5e7e6b5c..dc61b90e4c 100644
--- a/lib/modules/manager/helmfile/artifacts.spec.ts
+++ b/lib/modules/manager/helmfile/artifacts.spec.ts
@@ -11,11 +11,11 @@ import * as _datasource from '../../datasource';
 import type { UpdateArtifactsConfig } from '../types';
 import * as helmfile from '.';
 
-jest.mock('../../datasource', () => mockDeep());
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/http');
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
+vi.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/http');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
 
 const datasource = mocked(_datasource);
 
diff --git a/lib/modules/manager/helmfile/extract.spec.ts b/lib/modules/manager/helmfile/extract.spec.ts
index 9c36f13f5f..1cc5dc17eb 100644
--- a/lib/modules/manager/helmfile/extract.spec.ts
+++ b/lib/modules/manager/helmfile/extract.spec.ts
@@ -5,7 +5,7 @@ import { GlobalConfig } from '../../../config/global';
 import { FILE_ACCESS_VIOLATION_ERROR } from '../../../constants/error-messages';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const localDir = '/tmp/github/some/repo';
 
diff --git a/lib/modules/manager/helmsman/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/helmsman/__snapshots__/extract.spec.ts.snap
index 1aa37de040..33500a3639 100644
--- a/lib/modules/manager/helmsman/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/helmsman/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/helmsman/extract extractPackageFile() extract deps 1`] = `
+exports[`modules/manager/helmsman/extract > extractPackageFile() > extract deps 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/helmv3/__snapshots__/artifacts.spec.ts.snap b/lib/modules/manager/helmv3/__snapshots__/artifacts.spec.ts.snap
index ea3ede2331..f44af7fe57 100644
--- a/lib/modules/manager/helmv3/__snapshots__/artifacts.spec.ts.snap
+++ b/lib/modules/manager/helmv3/__snapshots__/artifacts.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/helmv3/artifacts alias name is picked, when repository is as alias and dependency defined 1`] = `
+exports[`modules/manager/helmv3/artifacts > alias name is picked, when repository is as alias and dependency defined 1`] = `
 [
   {
     "cmd": "helm repo add repo1 https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update --username basicUser --password secret",
@@ -49,7 +49,7 @@ exports[`modules/manager/helmv3/artifacts alias name is picked, when repository
 ]
 `;
 
-exports[`modules/manager/helmv3/artifacts do not add registryAliases to repository list 1`] = `
+exports[`modules/manager/helmv3/artifacts > do not add registryAliases to repository list 1`] = `
 [
   {
     "cmd": "helm repo add jetstack https://charts.jetstack.io --force-update",
@@ -120,7 +120,7 @@ exports[`modules/manager/helmv3/artifacts do not add registryAliases to reposito
 ]
 `;
 
-exports[`modules/manager/helmv3/artifacts log into private registries and repositories NOT defined in registryAliases 1`] = `
+exports[`modules/manager/helmv3/artifacts > log into private registries and repositories NOT defined in registryAliases 1`] = `
 [
   {
     "cmd": "helm registry login --username registryUser --password password registry.gitlab.com/user/oci-helm-test",
@@ -191,7 +191,7 @@ exports[`modules/manager/helmv3/artifacts log into private registries and reposi
 ]
 `;
 
-exports[`modules/manager/helmv3/artifacts log into private registries and repositories already defined in registryAliases 1`] = `
+exports[`modules/manager/helmv3/artifacts > log into private registries and repositories already defined in registryAliases 1`] = `
 [
   {
     "cmd": "helm registry login --username test --password aPassword registry.example.com/organization",
@@ -306,7 +306,7 @@ exports[`modules/manager/helmv3/artifacts log into private registries and reposi
 ]
 `;
 
-exports[`modules/manager/helmv3/artifacts returns null if unchanged 1`] = `
+exports[`modules/manager/helmv3/artifacts > returns null if unchanged 1`] = `
 [
   {
     "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update",
@@ -355,7 +355,7 @@ exports[`modules/manager/helmv3/artifacts returns null if unchanged 1`] = `
 ]
 `;
 
-exports[`modules/manager/helmv3/artifacts returns updated Chart.lock 1`] = `
+exports[`modules/manager/helmv3/artifacts > returns updated Chart.lock 1`] = `
 [
   {
     "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update",
@@ -404,7 +404,7 @@ exports[`modules/manager/helmv3/artifacts returns updated Chart.lock 1`] = `
 ]
 `;
 
-exports[`modules/manager/helmv3/artifacts returns updated Chart.lock for lockfile maintenance 1`] = `
+exports[`modules/manager/helmv3/artifacts > returns updated Chart.lock for lockfile maintenance 1`] = `
 [
   {
     "cmd": "helm repo add repo-test https://gitlab.com/api/v4/projects/xxxxxxx/packages/helm/stable --force-update",
@@ -453,7 +453,7 @@ exports[`modules/manager/helmv3/artifacts returns updated Chart.lock for lockfil
 ]
 `;
 
-exports[`modules/manager/helmv3/artifacts returns updated Chart.lock with docker 1`] = `
+exports[`modules/manager/helmv3/artifacts > returns updated Chart.lock with docker 1`] = `
 [
   {
     "cmd": "docker pull ghcr.io/containerbase/sidecar",
@@ -493,7 +493,7 @@ exports[`modules/manager/helmv3/artifacts returns updated Chart.lock with docker
 ]
 `;
 
-exports[`modules/manager/helmv3/artifacts sets repositories from registryAliases 1`] = `
+exports[`modules/manager/helmv3/artifacts > sets repositories from registryAliases 1`] = `
 [
   {
     "cmd": "helm repo add stable 'the stable_url' --force-update",
@@ -586,7 +586,7 @@ exports[`modules/manager/helmv3/artifacts sets repositories from registryAliases
 ]
 `;
 
-exports[`modules/manager/helmv3/artifacts sets repositories from registryAliases with docker 1`] = `
+exports[`modules/manager/helmv3/artifacts > sets repositories from registryAliases with docker 1`] = `
 [
   {
     "cmd": "docker pull ghcr.io/containerbase/sidecar",
diff --git a/lib/modules/manager/helmv3/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/helmv3/__snapshots__/extract.spec.ts.snap
index 2f38fb2775..187233b30b 100644
--- a/lib/modules/manager/helmv3/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/helmv3/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/helmv3/extract extractPackageFile() extract correctly oci references 1`] = `
+exports[`modules/manager/helmv3/extract > extractPackageFile() > extract correctly oci references 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -23,7 +23,7 @@ exports[`modules/manager/helmv3/extract extractPackageFile() extract correctly o
 }
 `;
 
-exports[`modules/manager/helmv3/extract extractPackageFile() parses simple Chart.yaml correctly 1`] = `
+exports[`modules/manager/helmv3/extract > extractPackageFile() > parses simple Chart.yaml correctly 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -46,7 +46,7 @@ exports[`modules/manager/helmv3/extract extractPackageFile() parses simple Chart
 }
 `;
 
-exports[`modules/manager/helmv3/extract extractPackageFile() resolves aliased registry urls 1`] = `
+exports[`modules/manager/helmv3/extract > extractPackageFile() > resolves aliased registry urls 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -76,7 +76,7 @@ exports[`modules/manager/helmv3/extract extractPackageFile() resolves aliased re
 }
 `;
 
-exports[`modules/manager/helmv3/extract extractPackageFile() skips invalid registry urls 1`] = `
+exports[`modules/manager/helmv3/extract > extractPackageFile() > skips invalid registry urls 1`] = `
 {
   "datasource": "helm",
   "deps": [
@@ -100,7 +100,7 @@ exports[`modules/manager/helmv3/extract extractPackageFile() skips invalid regis
 }
 `;
 
-exports[`modules/manager/helmv3/extract extractPackageFile() skips local dependencies 1`] = `
+exports[`modules/manager/helmv3/extract > extractPackageFile() > skips local dependencies 1`] = `
 {
   "datasource": "helm",
   "deps": [
diff --git a/lib/modules/manager/helmv3/artifacts.spec.ts b/lib/modules/manager/helmv3/artifacts.spec.ts
index 418b38dc7f..f1a5ef7bce 100644
--- a/lib/modules/manager/helmv3/artifacts.spec.ts
+++ b/lib/modules/manager/helmv3/artifacts.spec.ts
@@ -16,11 +16,11 @@ import * as _datasource from '../../datasource';
 import type { UpdateArtifactsConfig } from '../types';
 import * as helmv3 from '.';
 
-jest.mock('../../datasource', () => mockDeep());
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/http');
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
+vi.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/http');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
 const datasource = mocked(_datasource);
 
 const adminConfig: RepoGlobalConfig = {
diff --git a/lib/modules/manager/helmv3/extract.spec.ts b/lib/modules/manager/helmv3/extract.spec.ts
index 916cd2ba54..4151e205a9 100644
--- a/lib/modules/manager/helmv3/extract.spec.ts
+++ b/lib/modules/manager/helmv3/extract.spec.ts
@@ -3,7 +3,7 @@ import { DockerDatasource } from '../../datasource/docker';
 import type { ExtractConfig } from '../types';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 const config = partial<ExtractConfig>({
   registryAliases: {
     stable: 'https://charts.helm.sh/stable',
diff --git a/lib/modules/manager/hermit/artifacts.spec.ts b/lib/modules/manager/hermit/artifacts.spec.ts
index 510be6989e..37c806d059 100644
--- a/lib/modules/manager/hermit/artifacts.spec.ts
+++ b/lib/modules/manager/hermit/artifacts.spec.ts
@@ -8,8 +8,8 @@ import type { StatusResult } from '../../../util/git/types';
 import type { UpdateArtifact } from '../types';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/git');
-jest.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../../../util/fs');
 
 const getRepoStatusMock = mockedFunction(getRepoStatus);
 
diff --git a/lib/modules/manager/hermit/extract.spec.ts b/lib/modules/manager/hermit/extract.spec.ts
index 94a04acd40..bd7261bf46 100644
--- a/lib/modules/manager/hermit/extract.spec.ts
+++ b/lib/modules/manager/hermit/extract.spec.ts
@@ -3,7 +3,7 @@ import { readLocalDirectory } from '../../../util/fs';
 import { HermitDatasource } from '../../datasource/hermit';
 import { extractPackageFile } from './extract';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const readdirMock = mockedFunction(readLocalDirectory);
 
diff --git a/lib/modules/manager/homebrew/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/homebrew/__snapshots__/extract.spec.ts.snap
index d01bbdadad..ef91d35eef 100644
--- a/lib/modules/manager/homebrew/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/homebrew/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/homebrew/extract extractPackageFile() extracts "archive" github dependency 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > extracts "archive" github dependency 1`] = `
 {
   "deps": [
     {
@@ -18,7 +18,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() extracts "archive
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() extracts "releases" github dependency 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > extracts "releases" github dependency 1`] = `
 {
   "deps": [
     {
@@ -36,7 +36,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() extracts "release
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() handles no space before class header 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > handles no space before class header 1`] = `
 {
   "deps": [
     {
@@ -54,7 +54,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() handles no space
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() handles old "archive" github url format 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > handles old "archive" github url format 1`] = `
 {
   "deps": [
     {
@@ -72,7 +72,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() handles old "arch
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() skips github dependency with wrong format 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > skips github dependency with wrong format 1`] = `
 {
   "deps": [
     {
@@ -91,7 +91,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() skips github depe
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() skips if invalid url 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > skips if invalid url 1`] = `
 {
   "deps": [
     {
@@ -110,7 +110,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() skips if invalid
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() skips if invalid url protocol 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > skips if invalid url protocol 1`] = `
 {
   "deps": [
     {
@@ -129,7 +129,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() skips if invalid
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() skips if sha256 field is invalid 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > skips if sha256 field is invalid 1`] = `
 {
   "deps": [
     {
@@ -148,7 +148,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() skips if sha256 f
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() skips if there is no sha256 field 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > skips if there is no sha256 field 1`] = `
 {
   "deps": [
     {
@@ -167,7 +167,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() skips if there is
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() skips if there is no url field 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > skips if there is no url field 1`] = `
 {
   "deps": [
     {
@@ -186,7 +186,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() skips if there is
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() skips sourceforge dependency 1 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > skips sourceforge dependency 1 1`] = `
 {
   "deps": [
     {
@@ -205,7 +205,7 @@ exports[`modules/manager/homebrew/extract extractPackageFile() skips sourceforge
 }
 `;
 
-exports[`modules/manager/homebrew/extract extractPackageFile() skips sourceforge dependency 2 1`] = `
+exports[`modules/manager/homebrew/extract > extractPackageFile() > skips sourceforge dependency 2 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/homebrew/__snapshots__/update.spec.ts.snap b/lib/modules/manager/homebrew/__snapshots__/update.spec.ts.snap
index 139ef7b0f4..8cda95a889 100644
--- a/lib/modules/manager/homebrew/__snapshots__/update.spec.ts.snap
+++ b/lib/modules/manager/homebrew/__snapshots__/update.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/homebrew/update returns unchanged content if both got requests fail 1`] = `
+exports[`modules/manager/homebrew/update > returns unchanged content if both got requests fail 1`] = `
 "=begin
   url "https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz"
   sha256 "0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7"
@@ -63,7 +63,7 @@ end
 "
 `;
 
-exports[`modules/manager/homebrew/update updates "archive" github dependency 1`] = `
+exports[`modules/manager/homebrew/update > updates "archive" github dependency 1`] = `
 "# Copyright 2018 The Bazel Authors. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -114,7 +114,7 @@ end
 "
 `;
 
-exports[`modules/manager/homebrew/update updates "archive" github dependency from old url format 1`] = `
+exports[`modules/manager/homebrew/update > updates "archive" github dependency from old url format 1`] = `
 "# Copyright 2018 The Bazel Authors. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -165,7 +165,7 @@ end
 "
 `;
 
-exports[`modules/manager/homebrew/update updates "releases" github dependency 1`] = `
+exports[`modules/manager/homebrew/update > updates "releases" github dependency 1`] = `
 "=begin
   url "https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz"
   sha256 "0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7"
diff --git a/lib/modules/manager/html/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/html/__snapshots__/extract.spec.ts.snap
index 4bc58602ba..882fd4a8e1 100644
--- a/lib/modules/manager/html/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/html/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/html/extract extractPackageFile 1`] = `
+exports[`modules/manager/html/extract > extractPackageFile 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/index.spec.ts b/lib/modules/manager/index.spec.ts
index 8cf06bda3a..e2411c8582 100644
--- a/lib/modules/manager/index.spec.ts
+++ b/lib/modules/manager/index.spec.ts
@@ -5,7 +5,7 @@ import * as customManager from './custom';
 import type { ManagerApi } from './types';
 import * as manager from '.';
 
-jest.mock('../../util/fs');
+vi.mock('../../util/fs');
 
 const datasources = getDatasourceList();
 
@@ -47,7 +47,7 @@ describe('modules/manager/index', () => {
     });
   });
 
-  it('validates', () => {
+  it('validates', async () => {
     function validate(module: ManagerApi, moduleName: string): boolean {
       // no need to validate custom as it is a wrapper and not an actual manager
       if (moduleName === 'custom') {
@@ -76,8 +76,8 @@ describe('modules/manager/index', () => {
     const customMgrs = customManager.getCustomManagers();
 
     const loadedMgr = {
-      ...loadModules(__dirname, validate), // validate built-in managers
-      ...loadModules(join(__dirname, 'custom'), validate), // validate custom managers
+      ...(await loadModules(__dirname, validate)), // validate built-in managers
+      ...(await loadModules(join(__dirname, 'custom'), validate)), // validate custom managers
     };
     delete loadedMgr.custom;
 
diff --git a/lib/modules/manager/jenkins/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/jenkins/__snapshots__/extract.spec.ts.snap
index ad756050bc..fe246d7007 100644
--- a/lib/modules/manager/jenkins/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/jenkins/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/jenkins/extract extractPackageFile() extracts multiple image lines in text format 1`] = `
+exports[`modules/manager/jenkins/extract > extractPackageFile() > extracts multiple image lines in text format 1`] = `
 [
   {
     "currentValue": "1.2.3",
@@ -43,7 +43,7 @@ exports[`modules/manager/jenkins/extract extractPackageFile() extracts multiple
 ]
 `;
 
-exports[`modules/manager/jenkins/extract extractPackageFile() extracts multiple image lines in yaml format 1`] = `
+exports[`modules/manager/jenkins/extract > extractPackageFile() > extracts multiple image lines in yaml format 1`] = `
 [
   {
     "currentValue": "latest",
diff --git a/lib/modules/manager/jsonnet-bundler/__snapshots__/artifacts.spec.ts.snap b/lib/modules/manager/jsonnet-bundler/__snapshots__/artifacts.spec.ts.snap
index 39d4da7823..4fc28f71c4 100644
--- a/lib/modules/manager/jsonnet-bundler/__snapshots__/artifacts.spec.ts.snap
+++ b/lib/modules/manager/jsonnet-bundler/__snapshots__/artifacts.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/jsonnet-bundler/artifacts performs lock file maintenance 1`] = `
+exports[`modules/manager/jsonnet-bundler/artifacts > performs lock file maintenance 1`] = `
 [
   {
     "cmd": "jb update",
@@ -23,7 +23,7 @@ exports[`modules/manager/jsonnet-bundler/artifacts performs lock file maintenanc
 ]
 `;
 
-exports[`modules/manager/jsonnet-bundler/artifacts returns error when jb update fails 1`] = `
+exports[`modules/manager/jsonnet-bundler/artifacts > returns error when jb update fails 1`] = `
 [
   {
     "cmd": "jb update",
@@ -46,9 +46,9 @@ exports[`modules/manager/jsonnet-bundler/artifacts returns error when jb update
 ]
 `;
 
-exports[`modules/manager/jsonnet-bundler/artifacts returns null if there are no changes 1`] = `[]`;
+exports[`modules/manager/jsonnet-bundler/artifacts > returns null if there are no changes 1`] = `[]`;
 
-exports[`modules/manager/jsonnet-bundler/artifacts updates the vendor dir when dependencies change 1`] = `
+exports[`modules/manager/jsonnet-bundler/artifacts > updates the vendor dir when dependencies change 1`] = `
 [
   {
     "cmd": "jb update https://github.com/foo/foo.git ssh://git@github.com/foo/foo.git/bar",
diff --git a/lib/modules/manager/jsonnet-bundler/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/jsonnet-bundler/__snapshots__/extract.spec.ts.snap
index 638ef47fdf..7566691e75 100644
--- a/lib/modules/manager/jsonnet-bundler/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/jsonnet-bundler/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/jsonnet-bundler/extract extractPackageFile() extracts dependency 1`] = `
+exports[`modules/manager/jsonnet-bundler/extract > extractPackageFile() > extracts dependency 1`] = `
 {
   "deps": [
     {
@@ -23,7 +23,7 @@ exports[`modules/manager/jsonnet-bundler/extract extractPackageFile() extracts d
 }
 `;
 
-exports[`modules/manager/jsonnet-bundler/extract extractPackageFile() extracts dependency with custom name 1`] = `
+exports[`modules/manager/jsonnet-bundler/extract > extractPackageFile() > extracts dependency with custom name 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/jsonnet-bundler/artifacts.spec.ts b/lib/modules/manager/jsonnet-bundler/artifacts.spec.ts
index ea1ebe433e..ebc889aa81 100644
--- a/lib/modules/manager/jsonnet-bundler/artifacts.spec.ts
+++ b/lib/modules/manager/jsonnet-bundler/artifacts.spec.ts
@@ -7,9 +7,9 @@ import type { StatusResult } from '../../../util/git/types';
 import type { UpdateArtifactsConfig } from '../types';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
 
 const adminConfig: RepoGlobalConfig = {
   // `join` fixes Windows CI
diff --git a/lib/modules/manager/kustomize/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/kustomize/__snapshots__/extract.spec.ts.snap
index aae5dc9b65..9218189411 100644
--- a/lib/modules/manager/kustomize/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/kustomize/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/kustomize/extract extractPackageFile() extracts from digest 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > extracts from digest 1`] = `
 {
   "deps": [
     {
@@ -44,7 +44,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() extracts from di
 }
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() extracts from newTag 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > extracts from newTag 1`] = `
 {
   "deps": [
     {
@@ -77,7 +77,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() extracts from ne
 }
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() extracts http dependency 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > extracts http dependency 1`] = `
 [
   {
     "currentValue": "v0.0.1",
@@ -94,7 +94,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() extracts http de
 ]
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() extracts multiple image lines 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > extracts multiple image lines 1`] = `
 [
   {
     "currentValue": "v0.0.1",
@@ -113,7 +113,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() extracts multipl
 ]
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() extracts newName 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > extracts newName 1`] = `
 {
   "deps": [
     {
@@ -147,7 +147,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() extracts newName
 }
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() extracts ssh dependency 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > extracts ssh dependency 1`] = `
 [
   {
     "currentValue": "v0.0.1",
@@ -158,7 +158,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() extracts ssh dep
 ]
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() extracts ssh dependency with a subdir 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > extracts ssh dependency with a subdir 1`] = `
 [
   {
     "currentValue": "v2.0.0",
@@ -169,7 +169,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() extracts ssh dep
 ]
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() parses helmChart field 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > parses helmChart field 1`] = `
 {
   "deps": [
     {
@@ -194,7 +194,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() parses helmChart
 }
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() should extract bases resources and components from their respective blocks 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > should extract bases resources and components from their respective blocks 1`] = `
 [
   {
     "currentValue": "v0.0.1",
@@ -217,7 +217,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() should extract b
 ]
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() should extract dependencies when kind is Component 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > should extract dependencies when kind is Component 1`] = `
 [
   {
     "currentValue": "1.19.0",
@@ -244,7 +244,7 @@ exports[`modules/manager/kustomize/extract extractPackageFile() should extract d
 ]
 `;
 
-exports[`modules/manager/kustomize/extract extractPackageFile() should extract out image versions 1`] = `
+exports[`modules/manager/kustomize/extract > extractPackageFile() > should extract out image versions 1`] = `
 [
   {
     "autoReplaceStringTemplate": "{{newValue}}{{#if newDigest}}@{{newDigest}}{{/if}}",
diff --git a/lib/modules/manager/leiningen/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/leiningen/__snapshots__/extract.spec.ts.snap
index 147031d854..cb1dca3362 100644
--- a/lib/modules/manager/leiningen/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/leiningen/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/leiningen/extract extractPackageFile 1`] = `
+exports[`modules/manager/leiningen/extract > extractPackageFile 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/maven-wrapper/artifacts.spec.ts b/lib/modules/manager/maven-wrapper/artifacts.spec.ts
index 68fa2db732..2f8a691441 100644
--- a/lib/modules/manager/maven-wrapper/artifacts.spec.ts
+++ b/lib/modules/manager/maven-wrapper/artifacts.spec.ts
@@ -10,10 +10,10 @@ import { resetPrefetchedImages } from '../../../util/exec/docker';
 import { getPkgReleases } from '../../datasource';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
-jest.mock('../../../util/exec/env');
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../../../util/exec/env');
+vi.mock('../../datasource', () => mockDeep());
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/maven-wrapper/extract.spec.ts b/lib/modules/manager/maven-wrapper/extract.spec.ts
index f639b11833..455919055e 100644
--- a/lib/modules/manager/maven-wrapper/extract.spec.ts
+++ b/lib/modules/manager/maven-wrapper/extract.spec.ts
@@ -78,7 +78,7 @@ describe('modules/manager/maven-wrapper/extract', () => {
       ]);
     });
 
-    it('it should return null when there is no string matching the maven properties regex', () => {
+    it('should return null when there is no string matching the maven properties regex', () => {
       const res = extractPackageFile('nowrapper');
       expect(res).toBeNull();
     });
diff --git a/lib/modules/manager/maven/extract.spec.ts b/lib/modules/manager/maven/extract.spec.ts
index f564c877d5..e075d89101 100644
--- a/lib/modules/manager/maven/extract.spec.ts
+++ b/lib/modules/manager/maven/extract.spec.ts
@@ -1,7 +1,6 @@
 import { codeBlock } from 'common-tags';
 import { Fixtures } from '../../../../test/fixtures';
-import { fs } from '../../../../test/util';
-import { logger } from '../../../logger';
+import { fs, logger } from '../../../../test/util';
 import {
   extractAllPackageFiles,
   extractExtensions,
@@ -10,7 +9,7 @@ import {
   resolveParents,
 } from './extract';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const simpleContent = Fixtures.get('simple.pom.xml');
 const mirrorSettingsContent = Fixtures.get('mirror.settings.xml');
@@ -236,12 +235,11 @@ describe('modules/manager/maven/extract', () => {
     });
 
     it('extract dependencies with windows line endings', () => {
-      const logSpy = jest.spyOn(logger, 'warn');
       extractPackage(
         '<?xml version="1.0" encoding="UTF-8"?> \r\n',
         'some-file',
       );
-      expect(logSpy).toHaveBeenCalledWith(
+      expect(logger.logger.warn).toHaveBeenCalledWith(
         'Your pom.xml contains windows line endings. This is not supported and may result in parsing issues.',
       );
     });
diff --git a/lib/modules/manager/maven/index.spec.ts b/lib/modules/manager/maven/index.spec.ts
index 5980b3dfb7..bf19fe2f7a 100644
--- a/lib/modules/manager/maven/index.spec.ts
+++ b/lib/modules/manager/maven/index.spec.ts
@@ -9,7 +9,7 @@ import {
 } from './extract';
 import { updateDependency } from './update';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const simpleContent = Fixtures.get('simple.pom.xml');
 const parentPomContent = Fixtures.get('parent.pom.xml');
diff --git a/lib/modules/manager/meteor/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/meteor/__snapshots__/extract.spec.ts.snap
index 8a3f58a4d1..871899d739 100644
--- a/lib/modules/manager/meteor/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/meteor/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/meteor/extract extractPackageFile() returns results 1`] = `
+exports[`modules/manager/meteor/extract > extractPackageFile() > returns results 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/mise/extract.spec.ts b/lib/modules/manager/mise/extract.spec.ts
index 67e2edea53..939678b5d1 100644
--- a/lib/modules/manager/mise/extract.spec.ts
+++ b/lib/modules/manager/mise/extract.spec.ts
@@ -2,7 +2,7 @@ import { codeBlock } from 'common-tags';
 import { Fixtures } from '../../../../test/fixtures';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const miseFilename = '.mise.toml';
 
diff --git a/lib/modules/manager/mix/__snapshots__/artifacts.spec.ts.snap b/lib/modules/manager/mix/__snapshots__/artifacts.spec.ts.snap
index 293fe95d25..cbc96381f6 100644
--- a/lib/modules/manager/mix/__snapshots__/artifacts.spec.ts.snap
+++ b/lib/modules/manager/mix/__snapshots__/artifacts.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/mix/artifacts authenticates to private repositories in updated dependecies 1`] = `
+exports[`modules/manager/mix/artifacts > authenticates to private repositories in updated dependecies 1`] = `
 [
   {
     "file": {
@@ -12,7 +12,7 @@ exports[`modules/manager/mix/artifacts authenticates to private repositories in
 ]
 `;
 
-exports[`modules/manager/mix/artifacts authenticates to private repositories in updated dependecies 2`] = `
+exports[`modules/manager/mix/artifacts > authenticates to private repositories in updated dependecies 2`] = `
 [
   {
     "cmd": "docker ps --filter name=renovate_sidecar -aq",
@@ -42,7 +42,7 @@ exports[`modules/manager/mix/artifacts authenticates to private repositories in
 ]
 `;
 
-exports[`modules/manager/mix/artifacts returns null if unchanged 1`] = `
+exports[`modules/manager/mix/artifacts > returns null if unchanged 1`] = `
 [
   {
     "cmd": "mix deps.update plug",
@@ -65,7 +65,7 @@ exports[`modules/manager/mix/artifacts returns null if unchanged 1`] = `
 ]
 `;
 
-exports[`modules/manager/mix/artifacts returns updated mix.lock 1`] = `
+exports[`modules/manager/mix/artifacts > returns updated mix.lock 1`] = `
 [
   {
     "cmd": "docker pull ghcr.io/containerbase/sidecar",
diff --git a/lib/modules/manager/mix/artifacts.spec.ts b/lib/modules/manager/mix/artifacts.spec.ts
index 742476a21c..f0c6f59896 100644
--- a/lib/modules/manager/mix/artifacts.spec.ts
+++ b/lib/modules/manager/mix/artifacts.spec.ts
@@ -9,10 +9,10 @@ import { getPkgReleases as _getPkgReleases } from '../../datasource';
 import type { UpdateArtifactsConfig } from '../types';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../datasource', () => mockDeep());
 
 const getPkgReleases = mockedFunction(_getPkgReleases);
 
diff --git a/lib/modules/manager/nix/artifacts.spec.ts b/lib/modules/manager/nix/artifacts.spec.ts
index 7de02bf272..b2c78e343c 100644
--- a/lib/modules/manager/nix/artifacts.spec.ts
+++ b/lib/modules/manager/nix/artifacts.spec.ts
@@ -14,10 +14,10 @@ import * as _hostRules from '../../../util/host-rules';
 import type { UpdateArtifactsConfig } from '../types';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 const adminConfig: RepoGlobalConfig = {
   // `join` fixes Windows CI
diff --git a/lib/modules/manager/nix/extract.spec.ts b/lib/modules/manager/nix/extract.spec.ts
index 035a495eb0..e640e26dc6 100644
--- a/lib/modules/manager/nix/extract.spec.ts
+++ b/lib/modules/manager/nix/extract.spec.ts
@@ -3,7 +3,7 @@ import { GitRefsDatasource } from '../../datasource/git-refs';
 import { id as nixpkgsVersioning } from '../../versioning/nixpkgs';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/nix/extract', () => {
   const flake1Lock = `{
diff --git a/lib/modules/manager/npm/__snapshots__/utils.spec.ts.snap b/lib/modules/manager/npm/__snapshots__/utils.spec.ts.snap
index caf2ca7d61..161fdbaac7 100644
--- a/lib/modules/manager/npm/__snapshots__/utils.spec.ts.snap
+++ b/lib/modules/manager/npm/__snapshots__/utils.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/utils composeLockFile composes lockfile string out of an object 1`] = `
+exports[`modules/manager/npm/utils > composeLockFile > composes lockfile string out of an object 1`] = `
 "{
   "lockfileVersion": 2,
   "name": "lockfile-parsing",
diff --git a/lib/modules/manager/npm/artifacts.spec.ts b/lib/modules/manager/npm/artifacts.spec.ts
index c241b15189..3fef88de7c 100644
--- a/lib/modules/manager/npm/artifacts.spec.ts
+++ b/lib/modules/manager/npm/artifacts.spec.ts
@@ -12,8 +12,8 @@ import type { UpdateArtifactsConfig, Upgrade } from '../types';
 import * as rules from './post-update/rules';
 import { updateArtifacts } from '.';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/fs');
 
 const adminConfig: RepoGlobalConfig = {
   // `join` fixes Windows CI
diff --git a/lib/modules/manager/npm/detect.spec.ts b/lib/modules/manager/npm/detect.spec.ts
index 095e9ca3df..3a46e48e19 100644
--- a/lib/modules/manager/npm/detect.spec.ts
+++ b/lib/modules/manager/npm/detect.spec.ts
@@ -1,7 +1,7 @@
 import { fs } from '../../../../test/util';
 import { detectGlobalConfig } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/npm/detect', () => {
   describe('.detectGlobalConfig()', () => {
diff --git a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap
index 9e051b4110..7444f27e4b 100644
--- a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() catches invalid names 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > catches invalid names 1`] = `
 {
   "deps": [
     {
@@ -26,7 +26,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() catches invalid
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() extracts engines 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > extracts engines 1`] = `
 {
   "deps": [
     {
@@ -143,7 +143,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts engine
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() extracts non-npmjs 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > extracts non-npmjs 1`] = `
 {
   "deps": [
     {
@@ -355,7 +355,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts non-np
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() extracts npm package alias 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > extracts npm package alias 1`] = `
 {
   "deps": [
     {
@@ -437,7 +437,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts npm pa
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() extracts packageManager 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > extracts packageManager 1`] = `
 {
   "deps": [
     {
@@ -468,7 +468,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts packag
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > extracts volta 1`] = `
 {
   "deps": [
     {
@@ -536,7 +536,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta yarn unspecified-version 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > extracts volta yarn unspecified-version 1`] = `
 {
   "deps": [
     {
@@ -583,7 +583,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() finds a lock file 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > finds a lock file 1`] = `
 {
   "deps": [
     {
@@ -716,7 +716,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() finds a lock fi
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() finds complex yarn workspaces 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > finds complex yarn workspaces 1`] = `
 {
   "deps": [],
   "extractedConstraints": {},
@@ -737,7 +737,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() finds complex y
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() returns an array of dependencies 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > returns an array of dependencies 1`] = `
 {
   "deps": [
     {
@@ -870,7 +870,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() returns an arra
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() returns an array of dependencies with resolution comments 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > returns an array of dependencies with resolution comments 1`] = `
 {
   "deps": [
     {
@@ -985,7 +985,7 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() returns an arra
 }
 `;
 
-exports[`modules/manager/npm/extract/index .extractPackageFile() sets skipInstalls false if Yarn zero-install is used 1`] = `
+exports[`modules/manager/npm/extract/index > .extractPackageFile() > sets skipInstalls false if Yarn zero-install is used 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/npm/extract/__snapshots__/pnpm.spec.ts.snap b/lib/modules/manager/npm/extract/__snapshots__/pnpm.spec.ts.snap
index ac47e5c085..445c05c468 100644
--- a/lib/modules/manager/npm/extract/__snapshots__/pnpm.spec.ts.snap
+++ b/lib/modules/manager/npm/extract/__snapshots__/pnpm.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/extract/pnpm .detectPnpmWorkspaces() uses pnpm workspaces 1`] = `
+exports[`modules/manager/npm/extract/pnpm > .detectPnpmWorkspaces() > uses pnpm workspaces 1`] = `
 [
   {
     "managerData": {
diff --git a/lib/modules/manager/npm/extract/__snapshots__/yarn.spec.ts.snap b/lib/modules/manager/npm/extract/__snapshots__/yarn.spec.ts.snap
index cd6aa644b2..7093681f8d 100644
--- a/lib/modules/manager/npm/extract/__snapshots__/yarn.spec.ts.snap
+++ b/lib/modules/manager/npm/extract/__snapshots__/yarn.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/extract/yarn .getYarnLock() extracts yarn 1 1`] = `
+exports[`modules/manager/npm/extract/yarn > .getYarnLock() > extracts yarn 1 1`] = `
 {
   "ansi-styles@^3.2.1": "3.2.1",
   "chalk@^2.4.1": "2.4.1",
@@ -12,7 +12,7 @@ exports[`modules/manager/npm/extract/yarn .getYarnLock() extracts yarn 1 1`] = `
 }
 `;
 
-exports[`modules/manager/npm/extract/yarn .getYarnLock() extracts yarn 2 1`] = `
+exports[`modules/manager/npm/extract/yarn > .getYarnLock() > extracts yarn 2 1`] = `
 {
   "ansi-styles@^3.2.1": "3.2.1",
   "chalk@^2.4.1": "2.4.2",
@@ -25,7 +25,7 @@ exports[`modules/manager/npm/extract/yarn .getYarnLock() extracts yarn 2 1`] = `
 }
 `;
 
-exports[`modules/manager/npm/extract/yarn .getYarnLock() extracts yarn 2 cache version 1`] = `
+exports[`modules/manager/npm/extract/yarn > .getYarnLock() > extracts yarn 2 cache version 1`] = `
 {
   "@babel/runtime@^7.11.2": "7.11.2",
   "ansi-styles@^3.2.1": "3.2.1",
diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts
index a73936ce27..a361e9f5d2 100644
--- a/lib/modules/manager/npm/extract/index.spec.ts
+++ b/lib/modules/manager/npm/extract/index.spec.ts
@@ -7,7 +7,7 @@ import type { ExtractConfig } from '../../types';
 import { postExtract } from './post';
 import * as npmExtract from '.';
 
-jest.mock('../../../../util/fs');
+vi.mock('../../../../util/fs');
 
 const defaultExtractConfig = {
   skipInstalls: null,
@@ -22,8 +22,8 @@ const invalidNameContent = Fixtures.get('invalid-name.json', '..');
 
 describe('modules/manager/npm/extract/index', () => {
   describe('.extractPackageFile()', () => {
-    beforeEach(() => {
-      const realFs = jest.requireActual<typeof fs>('../../../../util/fs');
+    beforeEach(async () => {
+      const realFs = await vi.importActual<typeof fs>('../../../../util/fs');
       fs.readLocalFile.mockResolvedValue(null);
       fs.localPathExists.mockResolvedValue(false);
       fs.getSiblingFileName.mockImplementation(realFs.getSiblingFileName);
diff --git a/lib/modules/manager/npm/extract/npm.spec.ts b/lib/modules/manager/npm/extract/npm.spec.ts
index e169aa57ae..cb4ca95040 100644
--- a/lib/modules/manager/npm/extract/npm.spec.ts
+++ b/lib/modules/manager/npm/extract/npm.spec.ts
@@ -2,7 +2,7 @@ import { Fixtures } from '../../../../../test/fixtures';
 import { fs } from '../../../../../test/util';
 import { getNpmLock } from './npm';
 
-jest.mock('../../../../util/fs');
+vi.mock('../../../../util/fs');
 
 describe('modules/manager/npm/extract/npm', () => {
   describe('.getNpmLock()', () => {
diff --git a/lib/modules/manager/npm/extract/pnpm.spec.ts b/lib/modules/manager/npm/extract/pnpm.spec.ts
index 9677ac719d..17c57f4920 100644
--- a/lib/modules/manager/npm/extract/pnpm.spec.ts
+++ b/lib/modules/manager/npm/extract/pnpm.spec.ts
@@ -13,7 +13,7 @@ import {
   getPnpmLock,
 } from './pnpm';
 
-jest.mock('../../../../util/fs');
+vi.mock('../../../../util/fs');
 
 describe('modules/manager/npm/extract/pnpm', () => {
   beforeAll(() => {
@@ -90,8 +90,8 @@ describe('modules/manager/npm/extract/pnpm', () => {
   });
 
   describe('.detectPnpmWorkspaces()', () => {
-    beforeEach(() => {
-      const realFs = jest.requireActual<typeof fs>('../../../../util/fs');
+    beforeEach(async () => {
+      const realFs = await vi.importActual<typeof fs>('../../../../util/fs');
 
       // The real implementations of these functions are used for this block;
       // they do static path manipulation.
diff --git a/lib/modules/manager/npm/extract/post/locked-versions.spec.ts b/lib/modules/manager/npm/extract/post/locked-versions.spec.ts
index fffffa6d56..68db2ce39a 100644
--- a/lib/modules/manager/npm/extract/post/locked-versions.spec.ts
+++ b/lib/modules/manager/npm/extract/post/locked-versions.spec.ts
@@ -10,12 +10,12 @@ const npm = mocked(_npm);
 const pnpm = mocked(_pnpm);
 const yarn = mocked(_yarn);
 
-jest.mock('../npm');
-jest.mock('../yarn', () => ({
-  ...jest.requireActual<typeof import('../yarn')>('../yarn'),
-  getYarnLock: jest.fn(),
+vi.mock('../npm');
+vi.mock('../yarn', async () => ({
+  ...(await vi.importActual<typeof import('../yarn')>('../yarn')),
+  getYarnLock: vi.fn(),
 }));
-jest.mock('../pnpm');
+vi.mock('../pnpm');
 
 describe('modules/manager/npm/extract/post/locked-versions', () => {
   describe('.getLockedVersions()', () => {
diff --git a/lib/modules/manager/npm/extract/post/monorepo.spec.ts b/lib/modules/manager/npm/extract/post/monorepo.spec.ts
index 07c79f83c6..2122bda749 100644
--- a/lib/modules/manager/npm/extract/post/monorepo.spec.ts
+++ b/lib/modules/manager/npm/extract/post/monorepo.spec.ts
@@ -1,7 +1,7 @@
 import type { PackageFile } from '../../../types';
 import { detectMonorepos } from './monorepo';
 
-jest.mock('../pnpm');
+vi.mock('../pnpm');
 
 describe('modules/manager/npm/extract/post/monorepo', () => {
   describe('.extractPackageFile()', () => {
diff --git a/lib/modules/manager/npm/extract/yarn.spec.ts b/lib/modules/manager/npm/extract/yarn.spec.ts
index 8240595474..8e8f582800 100644
--- a/lib/modules/manager/npm/extract/yarn.spec.ts
+++ b/lib/modules/manager/npm/extract/yarn.spec.ts
@@ -2,7 +2,7 @@ import { Fixtures } from '../../../../../test/fixtures';
 import { fs } from '../../../../../test/util';
 import { getYarnLock, getYarnVersionFromLock } from './yarn';
 
-jest.mock('../../../../util/fs');
+vi.mock('../../../../util/fs');
 
 describe('modules/manager/npm/extract/yarn', () => {
   describe('.getYarnLock()', () => {
diff --git a/lib/modules/manager/npm/post-update/__snapshots__/index.spec.ts.snap b/lib/modules/manager/npm/post-update/__snapshots__/index.spec.ts.snap
index c4211b84dc..b1b39b940b 100644
--- a/lib/modules/manager/npm/post-update/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/manager/npm/post-update/__snapshots__/index.spec.ts.snap
@@ -1,12 +1,12 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/post-update/index updateYarnBinary() should return .yarnrc.yml content if it has been overwritten 1`] = `
+exports[`modules/manager/npm/post-update/index > updateYarnBinary() > should return .yarnrc.yml content if it has been overwritten 1`] = `
 "yarnPath: .yarn/releases/yarn-3.0.2.cjs
 a: b
 "
 `;
 
-exports[`modules/manager/npm/post-update/index updateYarnBinary() should return .yarnrc.yml content if it has been overwritten 2`] = `
+exports[`modules/manager/npm/post-update/index > updateYarnBinary() > should return .yarnrc.yml content if it has been overwritten 2`] = `
 [
   {
     "contents": "yarnPath: .yarn/releases/yarn-3.0.2.cjs
@@ -29,7 +29,7 @@ a: b
 ]
 `;
 
-exports[`modules/manager/npm/post-update/index updateYarnBinary() should update the Yarn binary 1`] = `
+exports[`modules/manager/npm/post-update/index > updateYarnBinary() > should update the Yarn binary 1`] = `
 [
   {
     "contents": "yarnPath: .yarn/releases/yarn-3.0.2.cjs
diff --git a/lib/modules/manager/npm/post-update/__snapshots__/npm.spec.ts.snap b/lib/modules/manager/npm/post-update/__snapshots__/npm.spec.ts.snap
index 7df15bab03..51fb7a393a 100644
--- a/lib/modules/manager/npm/post-update/__snapshots__/npm.spec.ts.snap
+++ b/lib/modules/manager/npm/post-update/__snapshots__/npm.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/post-update/npm generates lock files 1`] = `
+exports[`modules/manager/npm/post-update/npm > generates lock files 1`] = `
 [
   {
     "cmd": "npm install --package-lock-only --no-audit --prefer-dedupe --ignore-scripts",
@@ -23,7 +23,7 @@ exports[`modules/manager/npm/post-update/npm generates lock files 1`] = `
 ]
 `;
 
-exports[`modules/manager/npm/post-update/npm performs lock file maintenance 1`] = `
+exports[`modules/manager/npm/post-update/npm > performs lock file maintenance 1`] = `
 [
   {
     "cmd": "npm install --package-lock-only --no-audit --ignore-scripts",
@@ -46,7 +46,7 @@ exports[`modules/manager/npm/post-update/npm performs lock file maintenance 1`]
 ]
 `;
 
-exports[`modules/manager/npm/post-update/npm performs lock file updates 1`] = `
+exports[`modules/manager/npm/post-update/npm > performs lock file updates 1`] = `
 [
   {
     "cmd": "npm install --package-lock-only --no-audit --ignore-scripts some-dep@1.0.1",
@@ -69,7 +69,7 @@ exports[`modules/manager/npm/post-update/npm performs lock file updates 1`] = `
 ]
 `;
 
-exports[`modules/manager/npm/post-update/npm performs lock file updates retaining the package.json counterparts 1`] = `
+exports[`modules/manager/npm/post-update/npm > performs lock file updates retaining the package.json counterparts 1`] = `
 "{
   "name": "update-lockfile-massage-1",
   "version": "1.0.0",
@@ -156,7 +156,7 @@ exports[`modules/manager/npm/post-update/npm performs lock file updates retainin
 "
 `;
 
-exports[`modules/manager/npm/post-update/npm performs lock file updates retaining the package.json counterparts 2`] = `
+exports[`modules/manager/npm/post-update/npm > performs lock file updates retaining the package.json counterparts 2`] = `
 [
   {
     "cmd": "npm install --package-lock-only --no-audit --ignore-scripts postcss@8.4.8",
diff --git a/lib/modules/manager/npm/post-update/__snapshots__/pnpm.spec.ts.snap b/lib/modules/manager/npm/post-update/__snapshots__/pnpm.spec.ts.snap
index a1090d7d23..38aa9bfdd2 100644
--- a/lib/modules/manager/npm/post-update/__snapshots__/pnpm.spec.ts.snap
+++ b/lib/modules/manager/npm/post-update/__snapshots__/pnpm.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/post-update/pnpm catches errors 1`] = `
+exports[`modules/manager/npm/post-update/pnpm > catches errors 1`] = `
 [
   {
     "cmd": "pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile",
@@ -23,7 +23,7 @@ exports[`modules/manager/npm/post-update/pnpm catches errors 1`] = `
 ]
 `;
 
-exports[`modules/manager/npm/post-update/pnpm finds pnpm globally 1`] = `
+exports[`modules/manager/npm/post-update/pnpm > finds pnpm globally 1`] = `
 [
   {
     "cmd": "pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile",
@@ -46,7 +46,7 @@ exports[`modules/manager/npm/post-update/pnpm finds pnpm globally 1`] = `
 ]
 `;
 
-exports[`modules/manager/npm/post-update/pnpm generates lock files 1`] = `
+exports[`modules/manager/npm/post-update/pnpm > generates lock files 1`] = `
 [
   {
     "cmd": "pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile",
@@ -69,7 +69,7 @@ exports[`modules/manager/npm/post-update/pnpm generates lock files 1`] = `
 ]
 `;
 
-exports[`modules/manager/npm/post-update/pnpm performs lock file maintenance 1`] = `
+exports[`modules/manager/npm/post-update/pnpm > performs lock file maintenance 1`] = `
 [
   {
     "cmd": "pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile",
@@ -92,7 +92,7 @@ exports[`modules/manager/npm/post-update/pnpm performs lock file maintenance 1`]
 ]
 `;
 
-exports[`modules/manager/npm/post-update/pnpm uses the new version if packageManager is updated 1`] = `
+exports[`modules/manager/npm/post-update/pnpm > uses the new version if packageManager is updated 1`] = `
 [
   {
     "cmd": "pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile",
diff --git a/lib/modules/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap b/lib/modules/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap
index dd9dccc6e9..c427d6c5e5 100644
--- a/lib/modules/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap
+++ b/lib/modules/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/post-update/yarn allows and ignore scripts 1`] = `
+exports[`modules/manager/npm/post-update/yarn > allows and ignore scripts 1`] = `
 [
   {
     "cmd": "yarn install --mode=update-lockfile",
@@ -20,7 +20,7 @@ exports[`modules/manager/npm/post-update/yarn allows and ignore scripts 1`] = `
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn catches errors 1`] = `
+exports[`modules/manager/npm/post-update/yarn > catches errors 1`] = `
 [
   {
     "cmd": "yarn install --ignore-engines --ignore-platform --network-timeout 100000 --ignore-scripts",
@@ -37,7 +37,7 @@ exports[`modules/manager/npm/post-update/yarn catches errors 1`] = `
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn does not use global cache if zero install is detected 1`] = `
+exports[`modules/manager/npm/post-update/yarn > does not use global cache if zero install is detected 1`] = `
 [
   {
     "cmd": "yarn install",
@@ -57,7 +57,7 @@ exports[`modules/manager/npm/post-update/yarn does not use global cache if zero
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn generates lock files using yarn v1.22.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > generates lock files using yarn v1.22.0 1`] = `
 [
   {
     "cmd": "yarn install --ignore-engines --ignore-platform --network-timeout 100000 --ignore-scripts",
@@ -127,7 +127,7 @@ exports[`modules/manager/npm/post-update/yarn generates lock files using yarn v1
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn generates lock files using yarn v2.1.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > generates lock files using yarn v2.1.0 1`] = `
 [
   {
     "cmd": "yarn install",
@@ -149,7 +149,7 @@ exports[`modules/manager/npm/post-update/yarn generates lock files using yarn v2
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn generates lock files using yarn v2.2.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > generates lock files using yarn v2.2.0 1`] = `
 [
   {
     "cmd": "yarn install",
@@ -188,7 +188,7 @@ exports[`modules/manager/npm/post-update/yarn generates lock files using yarn v2
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn generates lock files using yarn v3.0.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > generates lock files using yarn v3.0.0 1`] = `
 [
   {
     "cmd": "yarn install --mode=update-lockfile",
@@ -225,7 +225,7 @@ exports[`modules/manager/npm/post-update/yarn generates lock files using yarn v3
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn only skips build if skipInstalls is false 1`] = `
+exports[`modules/manager/npm/post-update/yarn > only skips build if skipInstalls is false 1`] = `
 [
   {
     "cmd": "yarn install --mode=skip-build",
@@ -260,7 +260,7 @@ exports[`modules/manager/npm/post-update/yarn only skips build if skipInstalls i
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file maintenance in subdirectory independent workspaces using yarn v1.22.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file maintenance in subdirectory independent workspaces using yarn v1.22.0 1`] = `
 [
   {
     "cmd": "yarn install --ignore-engines --ignore-platform --network-timeout 100000 --ignore-scripts",
@@ -325,7 +325,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file maintenance in
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file maintenance in subdirectory independent workspaces using yarn v2.1.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file maintenance in subdirectory independent workspaces using yarn v2.1.0 1`] = `
 [
   {
     "cmd": "yarn install",
@@ -346,7 +346,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file maintenance in
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file maintenance in subdirectory independent workspaces using yarn v2.2.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file maintenance in subdirectory independent workspaces using yarn v2.2.0 1`] = `
 [
   {
     "cmd": "yarn install",
@@ -383,7 +383,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file maintenance in
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file maintenance in subdirectory independent workspaces using yarn v3.0.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file maintenance in subdirectory independent workspaces using yarn v3.0.0 1`] = `
 [
   {
     "cmd": "yarn install --mode=update-lockfile",
@@ -418,7 +418,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file maintenance in
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file maintenance using yarn v1.22.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file maintenance using yarn v1.22.0 1`] = `
 [
   {
     "cmd": "yarn install --ignore-engines --ignore-platform --network-timeout 100000 --ignore-scripts",
@@ -483,7 +483,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file maintenance usi
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file maintenance using yarn v2.1.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file maintenance using yarn v2.1.0 1`] = `
 [
   {
     "cmd": "yarn install",
@@ -504,7 +504,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file maintenance usi
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file maintenance using yarn v2.2.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file maintenance using yarn v2.2.0 1`] = `
 [
   {
     "cmd": "yarn install",
@@ -541,7 +541,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file maintenance usi
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file updates and full install using yarn v1.22.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file updates and full install using yarn v1.22.0 1`] = `
 [
   {
     "cmd": "yarn install --ignore-engines --ignore-platform --network-timeout 100000 --ignore-scripts",
@@ -570,7 +570,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file updates and ful
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file updates using yarn v1.22.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file updates using yarn v1.22.0 1`] = `
 [
   {
     "cmd": "yarn install --ignore-engines --ignore-platform --network-timeout 100000 --ignore-scripts",
@@ -599,7 +599,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file updates using y
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file updates using yarn v2.1.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file updates using yarn v2.1.0 1`] = `
 [
   {
     "cmd": "yarn install",
@@ -636,7 +636,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file updates using y
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs lock file updates using yarn v3.0.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs lock file updates using yarn v3.0.0 1`] = `
 [
   {
     "cmd": "yarn install --mode=update-lockfile",
@@ -671,7 +671,7 @@ exports[`modules/manager/npm/post-update/yarn performs lock file updates using y
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs yarn binary update using yarn v1.22.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs yarn binary update using yarn v1.22.0 1`] = `
 [
   {
     "cmd": "yarn set version 3.0.1",
@@ -706,7 +706,7 @@ exports[`modules/manager/npm/post-update/yarn performs yarn binary update using
 ]
 `;
 
-exports[`modules/manager/npm/post-update/yarn performs yarn binary update using yarn v2.1.0 1`] = `
+exports[`modules/manager/npm/post-update/yarn > performs yarn binary update using yarn v2.1.0 1`] = `
 [
   {
     "cmd": "yarn set version 3.0.1",
diff --git a/lib/modules/manager/npm/post-update/index.spec.ts b/lib/modules/manager/npm/post-update/index.spec.ts
index adbbdb953f..10b15d8ca6 100644
--- a/lib/modules/manager/npm/post-update/index.spec.ts
+++ b/lib/modules/manager/npm/post-update/index.spec.ts
@@ -18,11 +18,11 @@ import {
   writeUpdatedPackageFiles,
 } from './';
 
-jest.mock('../../../../util/fs');
-jest.mock('../../../../util/git');
-jest.mock('./npm');
-jest.mock('./yarn');
-jest.mock('./pnpm');
+vi.mock('../../../../util/fs');
+vi.mock('../../../../util/git');
+vi.mock('./npm');
+vi.mock('./yarn');
+vi.mock('./pnpm');
 
 describe('modules/manager/npm/post-update/index', () => {
   let baseConfig: PostUpdateConfig;
@@ -403,8 +403,7 @@ describe('modules/manager/npm/post-update/index', () => {
 
     it('works for npm', async () => {
       spyNpm.mockResolvedValueOnce({ error: false, lockFile: '{}' });
-      // TODO: fix types, jest is using wrong overload (#22198)
-      fs.readLocalFile.mockImplementation((f): Promise<any> => {
+      fs.readLocalFile.mockImplementation((f): Promise<string> => {
         if (f === '.npmrc') {
           return Promise.resolve('# dummy');
         }
@@ -666,7 +665,7 @@ describe('modules/manager/npm/post-update/index', () => {
       });
 
       it('should fuzzy merge the yarnrc Files', async () => {
-        (yarn.fuzzyMatchAdditionalYarnrcYml as jest.Mock).mockReturnValue({
+        vi.mocked(yarn.fuzzyMatchAdditionalYarnrcYml).mockReturnValue({
           npmRegistries: {
             'https://my-private-registry': { npmAuthToken: 'xxxxxx' },
           },
diff --git a/lib/modules/manager/npm/post-update/node-version.spec.ts b/lib/modules/manager/npm/post-update/node-version.spec.ts
index 64e3f6eefc..3f34dcc4e3 100644
--- a/lib/modules/manager/npm/post-update/node-version.spec.ts
+++ b/lib/modules/manager/npm/post-update/node-version.spec.ts
@@ -6,7 +6,7 @@ import {
   getNodeUpdate,
 } from './node-version';
 
-jest.mock('../../../../util/fs');
+vi.mock('../../../../util/fs');
 
 describe('modules/manager/npm/post-update/node-version', () => {
   const config = {
diff --git a/lib/modules/manager/npm/post-update/npm.spec.ts b/lib/modules/manager/npm/post-update/npm.spec.ts
index 5cff0a7d39..db25a206b1 100644
--- a/lib/modules/manager/npm/post-update/npm.spec.ts
+++ b/lib/modules/manager/npm/post-update/npm.spec.ts
@@ -6,9 +6,9 @@ import { GlobalConfig } from '../../../../config/global';
 import { getNodeToolConstraint } from './node-version';
 import * as npmHelper from './npm';
 
-jest.mock('../../../../util/exec/env');
-jest.mock('../../../../util/fs');
-jest.mock('./node-version');
+vi.mock('../../../../util/exec/env');
+vi.mock('../../../../util/fs');
+vi.mock('./node-version');
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/npm/post-update/pnpm.spec.ts b/lib/modules/manager/npm/post-update/pnpm.spec.ts
index 41c7e9dffa..5b0ce87585 100644
--- a/lib/modules/manager/npm/post-update/pnpm.spec.ts
+++ b/lib/modules/manager/npm/post-update/pnpm.spec.ts
@@ -6,9 +6,9 @@ import type { PostUpdateConfig, Upgrade } from '../../types';
 import { getNodeToolConstraint } from './node-version';
 import * as pnpmHelper from './pnpm';
 
-jest.mock('../../../../util/exec/env');
-jest.mock('../../../../util/fs');
-jest.mock('./node-version');
+vi.mock('../../../../util/exec/env');
+vi.mock('../../../../util/fs');
+vi.mock('./node-version');
 
 delete process.env.NPM_CONFIG_CACHE;
 process.env.CONTAINERBASE = 'true';
diff --git a/lib/modules/manager/npm/post-update/yarn.spec.ts b/lib/modules/manager/npm/post-update/yarn.spec.ts
index 2b2257dc75..9dd1414108 100644
--- a/lib/modules/manager/npm/post-update/yarn.spec.ts
+++ b/lib/modules/manager/npm/post-update/yarn.spec.ts
@@ -16,16 +16,16 @@ import type { NpmManagerData } from '../types';
 import { getNodeToolConstraint } from './node-version';
 import * as yarnHelper from './yarn';
 
-jest.mock('fs-extra', () =>
-  jest
-    .requireActual<
-      typeof import('../../../../../test/fixtures')
-    >('../../../../../test/fixtures')
-    .fsExtra(),
+vi.mock('fs-extra', async () =>
+  (
+    await vi.importActual<typeof import('../../../../../test/fixtures')>(
+      '../../../../../test/fixtures',
+    )
+  ).fsExtra(),
 );
-jest.mock('../../../../util/exec/env');
-jest.mock('./node-version');
-jest.mock('../../../datasource', () => mockDeep());
+vi.mock('../../../../util/exec/env');
+vi.mock('./node-version');
+vi.mock('../../../datasource', () => mockDeep());
 
 delete process.env.NPM_CONFIG_CACHE;
 
diff --git a/lib/modules/manager/npm/update/dependency/__snapshots__/index.spec.ts.snap b/lib/modules/manager/npm/update/dependency/__snapshots__/index.spec.ts.snap
index 99ca09571a..68eef7460a 100644
--- a/lib/modules/manager/npm/update/dependency/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/manager/npm/update/dependency/__snapshots__/index.spec.ts.snap
@@ -1,3 +1,3 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/update/dependency/index .updateDependency(fileContent, depType, depName, newValue) replaces a github fully specified version 1`] = `"{"dependencies":{"n":"git+https://github.com/owner/n#v1.1.0"}}"`;
+exports[`modules/manager/npm/update/dependency/index > .updateDependency(fileContent, depType, depName, newValue) > replaces a github fully specified version 1`] = `"{"dependencies":{"n":"git+https://github.com/owner/n#v1.1.0"}}"`;
diff --git a/lib/modules/manager/npm/update/locked-dependency/package-lock/dep-constraints.spec.ts b/lib/modules/manager/npm/update/locked-dependency/package-lock/dep-constraints.spec.ts
index 56fe90cfdd..e3e6f7c199 100644
--- a/lib/modules/manager/npm/update/locked-dependency/package-lock/dep-constraints.spec.ts
+++ b/lib/modules/manager/npm/update/locked-dependency/package-lock/dep-constraints.spec.ts
@@ -1,7 +1,7 @@
 import { Fixtures } from '../../../../../../../test/fixtures';
 import { findDepConstraints } from './dep-constraints';
 
-jest.mock('../../../../../../util/fs');
+vi.mock('../../../../../../util/fs');
 
 const packageJson = Fixtures.getJson('package.json');
 const packageLockJson = Fixtures.getJson('package-lock-v1.json');
diff --git a/lib/modules/manager/npm/update/locked-dependency/package-lock/get-locked.spec.ts b/lib/modules/manager/npm/update/locked-dependency/package-lock/get-locked.spec.ts
index 5cbb3a8737..699490419e 100644
--- a/lib/modules/manager/npm/update/locked-dependency/package-lock/get-locked.spec.ts
+++ b/lib/modules/manager/npm/update/locked-dependency/package-lock/get-locked.spec.ts
@@ -1,7 +1,7 @@
 import { Fixtures } from '../../../../../../../test/fixtures';
 import { getLockedDependencies } from './get-locked';
 
-jest.mock('../../../../../../util/fs');
+vi.mock('../../../../../../util/fs');
 
 const packageLockJson = Fixtures.getJson('package-lock-v1.json');
 const bundledPackageLockJson = Fixtures.getJson('bundled.package-lock.json');
diff --git a/lib/modules/manager/npm/update/package-version/__snapshots__/index.spec.ts.snap b/lib/modules/manager/npm/update/package-version/__snapshots__/index.spec.ts.snap
index cd31e59d3e..f319a6b145 100644
--- a/lib/modules/manager/npm/update/package-version/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/manager/npm/update/package-version/__snapshots__/index.spec.ts.snap
@@ -1,7 +1,7 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/npm/update/package-version/index .bumpPackageVersion() increments 1`] = `"{"name":"some-package","version":"0.0.3","dependencies":{"chalk":"2.4.2"}}"`;
+exports[`modules/manager/npm/update/package-version/index > .bumpPackageVersion() > increments 1`] = `"{"name":"some-package","version":"0.0.3","dependencies":{"chalk":"2.4.2"}}"`;
 
-exports[`modules/manager/npm/update/package-version/index .bumpPackageVersion() mirrors 1`] = `"{"name":"some-package","version":"2.4.2","dependencies":{"chalk":"2.4.2"}}"`;
+exports[`modules/manager/npm/update/package-version/index > .bumpPackageVersion() > mirrors 1`] = `"{"name":"some-package","version":"2.4.2","dependencies":{"chalk":"2.4.2"}}"`;
 
-exports[`modules/manager/npm/update/package-version/index .bumpPackageVersion() updates 1`] = `"{"name":"some-package","version":"0.1.0","dependencies":{"chalk":"2.4.2"}}"`;
+exports[`modules/manager/npm/update/package-version/index > .bumpPackageVersion() > updates 1`] = `"{"name":"some-package","version":"0.1.0","dependencies":{"chalk":"2.4.2"}}"`;
diff --git a/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap
index 60fcf38b3c..3fe1319db6 100644
--- a/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/nuget/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/nuget/extract extractPackageFile() extracts all dependencies 1`] = `
+exports[`modules/manager/nuget/extract > extractPackageFile() > extracts all dependencies 1`] = `
 [
   {
     "currentValue": "1.0.0",
@@ -146,7 +146,7 @@ exports[`modules/manager/nuget/extract extractPackageFile() extracts all depende
 ]
 `;
 
-exports[`modules/manager/nuget/extract extractPackageFile() extracts all dependencies from global packages file 1`] = `
+exports[`modules/manager/nuget/extract > extractPackageFile() > extracts all dependencies from global packages file 1`] = `
 [
   {
     "currentValue": "1.0.0",
@@ -283,7 +283,7 @@ exports[`modules/manager/nuget/extract extractPackageFile() extracts all depende
 ]
 `;
 
-exports[`modules/manager/nuget/extract extractPackageFile() extracts package version dependency 1`] = `
+exports[`modules/manager/nuget/extract > extractPackageFile() > extracts package version dependency 1`] = `
 [
   {
     "currentValue": "4.5.0",
diff --git a/lib/modules/manager/nuget/artifacts.spec.ts b/lib/modules/manager/nuget/artifacts.spec.ts
index 33a7465d63..561a5e65d7 100644
--- a/lib/modules/manager/nuget/artifacts.spec.ts
+++ b/lib/modules/manager/nuget/artifacts.spec.ts
@@ -9,11 +9,11 @@ import type { UpdateArtifactsConfig } from '../types';
 import * as util from './util';
 import * as nuget from '.';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('../../../util/git');
-jest.mock('./util');
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/git');
+vi.mock('./util');
 
 const { getDefaultRegistries, findGlobalJson } = mocked(util);
 
@@ -29,9 +29,11 @@ const adminConfig: RepoGlobalConfig = {
 const config: UpdateArtifactsConfig = {};
 
 describe('modules/manager/nuget/artifacts', () => {
-  beforeEach(() => {
+  beforeEach(async () => {
     const realFs =
-      jest.requireActual<typeof import('../../../util/fs')>('../../../util/fs');
+      await vi.importActual<typeof import('../../../util/fs')>(
+        '../../../util/fs',
+      );
     getDefaultRegistries.mockReturnValue([]);
     env.getChildProcessEnv.mockReturnValue(envMock.basic);
     fs.privateCacheDir.mockImplementation(realFs.privateCacheDir);
diff --git a/lib/modules/manager/nuget/package-tree.spec.ts b/lib/modules/manager/nuget/package-tree.spec.ts
index c687184d3b..30dff7c505 100644
--- a/lib/modules/manager/nuget/package-tree.spec.ts
+++ b/lib/modules/manager/nuget/package-tree.spec.ts
@@ -1,4 +1,3 @@
-import { fs as memfs } from 'memfs';
 import upath from 'upath';
 import { Fixtures } from '../../../../test/fixtures';
 import { scm } from '../../../../test/util';
@@ -6,15 +5,14 @@ import { GlobalConfig } from '../../../config/global';
 import type { RepoGlobalConfig } from '../../../config/types';
 import { getDependentPackageFiles } from './package-tree';
 
-jest.mock('fs', () => memfs);
-jest.mock('fs-extra', () =>
-  jest
-    .requireActual<
-      typeof import('../../../../test/fixtures')
-    >('../../../../test/fixtures')
-    .fsExtra(),
+vi.mock('fs-extra', async () =>
+  (
+    await vi.importActual<typeof import('../../../../test/fixtures')>(
+      '../../../../test/fixtures',
+    )
+  ).fsExtra(),
 );
-jest.mock('../../../util/git');
+vi.mock('../../../util/git');
 
 const adminConfig: RepoGlobalConfig = {
   localDir: upath.resolve('/tmp/repo'),
diff --git a/lib/modules/manager/nuget/util.spec.ts b/lib/modules/manager/nuget/util.spec.ts
index a1a01dec10..19721c8aab 100644
--- a/lib/modules/manager/nuget/util.spec.ts
+++ b/lib/modules/manager/nuget/util.spec.ts
@@ -10,7 +10,7 @@ import {
   getConfiguredRegistries,
 } from './util';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/nuget/util', () => {
   describe('findVersion', () => {
diff --git a/lib/modules/manager/pep621/artifacts.spec.ts b/lib/modules/manager/pep621/artifacts.spec.ts
index 2c586b2ecd..a1fc743968 100644
--- a/lib/modules/manager/pep621/artifacts.spec.ts
+++ b/lib/modules/manager/pep621/artifacts.spec.ts
@@ -9,8 +9,8 @@ import { getPkgReleases as _getPkgReleases } from '../../datasource';
 import type { UpdateArtifactsConfig } from '../types';
 import { updateArtifacts } from './artifacts';
 
-jest.mock('../../../util/fs');
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/fs');
+vi.mock('../../datasource', () => mockDeep());
 
 const getPkgReleases = mockedFunction(_getPkgReleases);
 
diff --git a/lib/modules/manager/pep621/extract.spec.ts b/lib/modules/manager/pep621/extract.spec.ts
index 5eec256633..366a8250c3 100644
--- a/lib/modules/manager/pep621/extract.spec.ts
+++ b/lib/modules/manager/pep621/extract.spec.ts
@@ -5,7 +5,7 @@ import { GitRefsDatasource } from '../../datasource/git-refs';
 import { depTypes } from './utils';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const pdmPyProject = Fixtures.get('pyproject_with_pdm.toml');
 const pdmSourcesPyProject = Fixtures.get('pyproject_pdm_sources.toml');
diff --git a/lib/modules/manager/pep621/processors/pdm.spec.ts b/lib/modules/manager/pep621/processors/pdm.spec.ts
index 580543b3f6..36f4cd1f2f 100644
--- a/lib/modules/manager/pep621/processors/pdm.spec.ts
+++ b/lib/modules/manager/pep621/processors/pdm.spec.ts
@@ -10,8 +10,8 @@ import type { UpdateArtifactsConfig } from '../../types';
 import { depTypes } from '../utils';
 import { PdmProcessor } from './pdm';
 
-jest.mock('../../../../util/fs');
-jest.mock('../../../datasource');
+vi.mock('../../../../util/fs');
+vi.mock('../../../datasource');
 
 const getPkgReleases = mockedFunction(_getPkgReleases);
 
diff --git a/lib/modules/manager/pep621/processors/uv.spec.ts b/lib/modules/manager/pep621/processors/uv.spec.ts
index e87dbe3aae..f407eb9e48 100644
--- a/lib/modules/manager/pep621/processors/uv.spec.ts
+++ b/lib/modules/manager/pep621/processors/uv.spec.ts
@@ -19,9 +19,9 @@ import type { UpdateArtifactsConfig } from '../../types';
 import { depTypes } from '../utils';
 import { UvProcessor } from './uv';
 
-jest.mock('google-auth-library');
-jest.mock('../../../../util/fs');
-jest.mock('../../../datasource');
+vi.mock('google-auth-library');
+vi.mock('../../../../util/fs');
+vi.mock('../../../datasource');
 
 const googleAuth = mocked(_googleAuth);
 const getPkgReleases = mockedFunction(_getPkgReleases);
diff --git a/lib/modules/manager/pip-compile/artifacts.spec.ts b/lib/modules/manager/pip-compile/artifacts.spec.ts
index 75217a8ca4..acb7a5f37d 100644
--- a/lib/modules/manager/pip-compile/artifacts.spec.ts
+++ b/lib/modules/manager/pip-compile/artifacts.spec.ts
@@ -21,12 +21,12 @@ import { updateArtifacts } from '.';
 
 const datasource = mocked(_datasource);
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('../../../util/http');
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/http');
+vi.mock('../../datasource', () => mockDeep());
 
 const requirementsWithUv = `# This file was autogenerated by uv via the following command:
 #    uv pip compile --generate-hashes --output-file=requirements.txt --python-version=3.11 --universal requirements.in
@@ -590,7 +590,7 @@ describe('modules/manager/pip-compile/artifacts', () => {
       );
     });
 
-    it('returns extracted arguments for uv ', () => {
+    it('returns extracted arguments for uv', () => {
       expect(
         constructPipCompileCmd(
           extractHeaderCommand(requirementsWithUv, 'subdir/requirements.txt'),
diff --git a/lib/modules/manager/pip-compile/common.spec.ts b/lib/modules/manager/pip-compile/common.spec.ts
index aa04aa764c..525950c186 100644
--- a/lib/modules/manager/pip-compile/common.spec.ts
+++ b/lib/modules/manager/pip-compile/common.spec.ts
@@ -10,7 +10,7 @@ import {
 } from './common';
 import { inferCommandExecDir } from './utils';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 function getCommandInHeader(command: string) {
   return `#
diff --git a/lib/modules/manager/pip-compile/extract.spec.ts b/lib/modules/manager/pip-compile/extract.spec.ts
index 9fe1b1dbb6..82bfd91b45 100644
--- a/lib/modules/manager/pip-compile/extract.spec.ts
+++ b/lib/modules/manager/pip-compile/extract.spec.ts
@@ -6,7 +6,7 @@ import type { RepoGlobalConfig } from '../../../config/types';
 import { logger } from '../../../logger';
 import { extractAllPackageFiles, extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const adminConfig: RepoGlobalConfig = {
   // `join` fixes Windows CI
diff --git a/lib/modules/manager/pip_requirements/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/pip_requirements/__snapshots__/extract.spec.ts.snap
index 4bbeef11ea..83735617c3 100644
--- a/lib/modules/manager/pip_requirements/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/pip_requirements/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/pip_requirements/extract extractPackageFile() extracts dependencies 1`] = `
+exports[`modules/manager/pip_requirements/extract > extractPackageFile() > extracts dependencies 1`] = `
 {
   "deps": [
     {
@@ -37,7 +37,7 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() extracts
 }
 `;
 
-exports[`modules/manager/pip_requirements/extract extractPackageFile() extracts multiple dependencies 1`] = `
+exports[`modules/manager/pip_requirements/extract > extractPackageFile() > extracts multiple dependencies 1`] = `
 [
   {
     "currentValue": "==1",
@@ -77,7 +77,7 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() extracts
 ]
 `;
 
-exports[`modules/manager/pip_requirements/extract extractPackageFile() handles comments and commands 1`] = `
+exports[`modules/manager/pip_requirements/extract > extractPackageFile() > handles comments and commands 1`] = `
 [
   {
     "currentValue": "==1.11.23",
@@ -118,7 +118,7 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles c
 ]
 `;
 
-exports[`modules/manager/pip_requirements/extract extractPackageFile() handles extra index url 1`] = `
+exports[`modules/manager/pip_requirements/extract > extractPackageFile() > handles extra index url 1`] = `
 {
   "additionalRegistryUrls": [
     "http://example.com/private-pypi/",
@@ -173,7 +173,7 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e
 }
 `;
 
-exports[`modules/manager/pip_requirements/extract extractPackageFile() handles extra index url and defaults without index to config 1`] = `
+exports[`modules/manager/pip_requirements/extract > extractPackageFile() > handles extra index url and defaults without index to config 1`] = `
 {
   "additionalRegistryUrls": [
     "http://example.com/private-pypi/",
@@ -225,7 +225,7 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e
 }
 `;
 
-exports[`modules/manager/pip_requirements/extract extractPackageFile() handles extra index url and defaults without index to pypi 1`] = `
+exports[`modules/manager/pip_requirements/extract > extractPackageFile() > handles extra index url and defaults without index to pypi 1`] = `
 {
   "additionalRegistryUrls": [
     "http://example.com/private-pypi/",
@@ -277,7 +277,7 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e
 }
 `;
 
-exports[`modules/manager/pip_requirements/extract extractPackageFile() handles extra spaces around pinned dependency equal signs 1`] = `
+exports[`modules/manager/pip_requirements/extract > extractPackageFile() > handles extra spaces around pinned dependency equal signs 1`] = `
 {
   "deps": [
     {
@@ -308,7 +308,7 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e
 }
 `;
 
-exports[`modules/manager/pip_requirements/extract extractPackageFile() handles extras and complex index url 1`] = `
+exports[`modules/manager/pip_requirements/extract > extractPackageFile() > handles extras and complex index url 1`] = `
 {
   "deps": [
     {
@@ -339,7 +339,7 @@ exports[`modules/manager/pip_requirements/extract extractPackageFile() handles e
 }
 `;
 
-exports[`modules/manager/pip_requirements/extract extractPackageFile() should handle hashes 1`] = `
+exports[`modules/manager/pip_requirements/extract > extractPackageFile() > should handle hashes 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/pip_requirements/artifacts.spec.ts b/lib/modules/manager/pip_requirements/artifacts.spec.ts
index 052dabf077..ba81c488d0 100644
--- a/lib/modules/manager/pip_requirements/artifacts.spec.ts
+++ b/lib/modules/manager/pip_requirements/artifacts.spec.ts
@@ -10,9 +10,9 @@ import { updateArtifacts } from '.';
 
 const datasource = mocked(_datasource);
 
-jest.mock('../../../util/exec/common');
-jest.mock('../../../util/fs');
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/exec/common');
+vi.mock('../../../util/fs');
+vi.mock('../../datasource', () => mockDeep());
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/pip_setup/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/pip_setup/__snapshots__/extract.spec.ts.snap
index d1367fccdb..840600af2b 100644
--- a/lib/modules/manager/pip_setup/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/pip_setup/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/pip_setup/extract extractPackageFile() returns found deps 1`] = `
+exports[`modules/manager/pip_setup/extract > extractPackageFile() > returns found deps 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/pipenv/artifacts.spec.ts b/lib/modules/manager/pipenv/artifacts.spec.ts
index 42f2931d2b..57e866810d 100644
--- a/lib/modules/manager/pipenv/artifacts.spec.ts
+++ b/lib/modules/manager/pipenv/artifacts.spec.ts
@@ -1,15 +1,9 @@
 import * as _fsExtra from 'fs-extra';
-import { mockDeep } from 'jest-mock-extended';
 import { join } from 'upath';
+import { mockDeep } from 'vitest-mock-extended';
 import { envMock, mockExecAll } from '../../../../test/exec-util';
 import { Fixtures } from '../../../../test/fixtures';
-import {
-  env,
-  git,
-  mocked,
-  mockedFunction,
-  partial,
-} from '../../../../test/util';
+import { env, git, partial } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
 import type { RepoGlobalConfig } from '../../../config/types';
 import { logger } from '../../../logger';
@@ -27,17 +21,23 @@ import {
 import type { PipfileLock } from './types';
 import { updateArtifacts } from '.';
 
-const datasource = mocked(_datasource);
-const find = mockedFunction(_find);
-
-jest.mock('fs-extra');
-const fsExtra = mocked(_fsExtra);
+// mock for cjs require for `@renovatebot/detect-tools`
+// https://github.com/vitest-dev/vitest/discussions/3134
+vi.hoisted(() => {
+  require.cache[require.resolve('fs-extra')] = {
+    exports: fixtures.fsExtra(),
+  } as never;
+});
+vi.mock('fs-extra', () => fixtures.fsExtra());
+vi.mock('../../../util/exec/env', () => mockDeep());
+vi.mock('../../../util/git', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/http', () => mockDeep());
+vi.mock('../../datasource', () => mockDeep());
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/git');
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('../../../util/http');
-jest.mock('../../datasource', () => mockDeep());
+const datasource = vi.mocked(_datasource);
+const find = vi.mocked(_find);
+const fsExtra = vi.mocked(_fsExtra);
 
 process.env.CONTAINERBASE = 'true';
 
@@ -82,6 +82,7 @@ function mockFiles(mockFiles: MockFiles): void {
 
 describe('modules/manager/pipenv/artifacts', () => {
   beforeEach(() => {
+    Fixtures.reset();
     env.getChildProcessEnv.mockReturnValue({
       ...envMock.basic,
       LANG: 'en_US.UTF-8',
@@ -712,6 +713,7 @@ describe('modules/manager/pipenv/artifacts', () => {
   it('returns updated Pipenv.lock when doing lockfile maintenance', async () => {
     fsExtra.ensureDir.mockResolvedValue(undefined as never);
     fsExtra.stat.mockResolvedValueOnce({} as never);
+    fsExtra.remove.mockResolvedValue();
 
     mockFiles({
       '/Pipfile.lock': ['Current Pipfile.lock', 'New Pipfile.lock'],
@@ -731,7 +733,15 @@ describe('modules/manager/pipenv/artifacts', () => {
         newPackageFileContent: '{}',
         config: lockMaintenanceConfig,
       }),
-    ).not.toBeNull();
+    ).toEqual([
+      {
+        file: {
+          contents: 'New Pipfile.lock',
+          path: 'Pipfile.lock',
+          type: 'addition',
+        },
+      },
+    ]);
 
     expect(execSnapshots).toMatchObject([
       {
diff --git a/lib/modules/manager/pipenv/extract.spec.ts b/lib/modules/manager/pipenv/extract.spec.ts
index 49727aa800..a52fb52967 100644
--- a/lib/modules/manager/pipenv/extract.spec.ts
+++ b/lib/modules/manager/pipenv/extract.spec.ts
@@ -1,13 +1,21 @@
 import { codeBlock } from 'common-tags';
 import * as _fsExtra from 'fs-extra';
 import { join } from 'upath';
-import { Fixtures } from '../../../../test/fixtures';
-import { mocked } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
 import { extractPackageFile } from '.';
+import { Fixtures } from '~test/fixtures';
 
-jest.mock('fs-extra');
-const fsExtra = mocked(_fsExtra);
+// mock for cjs require for `@renovatebot/detect-tools`
+// https://github.com/vitest-dev/vitest/discussions/3134
+vi.hoisted(() => {
+  require.cache[require.resolve('fs-extra')] = {
+    exports: fixtures.fsExtra(),
+  } as never;
+});
+
+vi.mock('fs-extra', () => fixtures.fsExtra());
+
+const fsExtra = vi.mocked(_fsExtra);
 
 const pipfile1 = Fixtures.get('Pipfile1');
 const pipfile2 = Fixtures.get('Pipfile2');
@@ -15,17 +23,16 @@ const pipfile3 = Fixtures.get('Pipfile3');
 const pipfile4 = Fixtures.get('Pipfile4');
 const pipfile5 = Fixtures.get('Pipfile5');
 
+const localDir = '/tmp/github/some/repo/';
+
 describe('modules/manager/pipenv/extract', () => {
   beforeEach(() => {
+    Fixtures.reset();
     GlobalConfig.set({
-      localDir: join('/tmp/github/some/repo'),
+      localDir: join(localDir),
     });
   });
 
-  afterEach(() => {
-    GlobalConfig.reset();
-  });
-
   describe('extractPackageFile()', () => {
     it('returns null for empty', async () => {
       expect(await extractPackageFile('[packages]\r\n', 'Pipfile')).toBeNull();
@@ -37,7 +44,7 @@ describe('modules/manager/pipenv/extract', () => {
 
     it('extracts dependencies', async () => {
       fsExtra.stat.mockResolvedValueOnce({} as never);
-      fsExtra.readFile.mockResolvedValueOnce(pipfile1 as never);
+      Fixtures.mock({ Pipfile: pipfile1 }, localDir);
       const res = await extractPackageFile(pipfile1, 'Pipfile');
       expect(res).toMatchObject({
         deps: [
@@ -134,7 +141,7 @@ describe('modules/manager/pipenv/extract', () => {
 
     it('extracts multiple dependencies', async () => {
       fsExtra.stat.mockResolvedValueOnce({} as never);
-      fsExtra.readFile.mockResolvedValueOnce(pipfile2 as never);
+      Fixtures.mock({ Pipfile: pipfile2 }, localDir);
       const res = await extractPackageFile(pipfile2, 'Pipfile');
       expect(res).toMatchObject({
         deps: [
diff --git a/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap
index 98429c3744..5e63f9d831 100644
--- a/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/poetry/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/poetry/extract extractPackageFile() extracts mixed versioning types 1`] = `
+exports[`modules/manager/poetry/extract > extractPackageFile() > extracts mixed versioning types 1`] = `
 {
   "deps": [
     {
@@ -349,7 +349,7 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts mixed vers
 }
 `;
 
-exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple dependencies (with dep = {version = "1.2.3"} case) 1`] = `
+exports[`modules/manager/poetry/extract > extractPackageFile() > extracts multiple dependencies (with dep = {version = "1.2.3"} case) 1`] = `
 {
   "deps": [
     {
@@ -474,7 +474,7 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple d
 }
 `;
 
-exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple dependencies 1`] = `
+exports[`modules/manager/poetry/extract > extractPackageFile() > extracts multiple dependencies 1`] = `
 [
   {
     "currentValue": "0.0.0",
@@ -555,7 +555,7 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple d
 ]
 `;
 
-exports[`modules/manager/poetry/extract extractPackageFile() handles multiple constraint dependencies 1`] = `
+exports[`modules/manager/poetry/extract > extractPackageFile() > handles multiple constraint dependencies 1`] = `
 {
   "deps": [
     {
@@ -570,7 +570,7 @@ exports[`modules/manager/poetry/extract extractPackageFile() handles multiple co
 }
 `;
 
-exports[`modules/manager/poetry/extract extractPackageFile() resolves lockedVersions from the lockfile 1`] = `
+exports[`modules/manager/poetry/extract > extractPackageFile() > resolves lockedVersions from the lockfile 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/poetry/artifacts.spec.ts b/lib/modules/manager/poetry/artifacts.spec.ts
index 35d5139d0e..9946674197 100644
--- a/lib/modules/manager/poetry/artifacts.spec.ts
+++ b/lib/modules/manager/poetry/artifacts.spec.ts
@@ -25,11 +25,11 @@ requires = ["poetry_core>=1.0", "wheel"]
 build-backend = "poetry.masonry.api"
 `;
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
-jest.mock('../../datasource', () => mockDeep());
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('google-auth-library');
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/fs');
+vi.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('google-auth-library');
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/poetry/extract.spec.ts b/lib/modules/manager/poetry/extract.spec.ts
index ead38910d4..cbfa6d4ba7 100644
--- a/lib/modules/manager/poetry/extract.spec.ts
+++ b/lib/modules/manager/poetry/extract.spec.ts
@@ -7,7 +7,7 @@ import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { PypiDatasource } from '../../datasource/pypi';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const pyproject1toml = Fixtures.get('pyproject.1.toml');
 const pyproject2toml = Fixtures.get('pyproject.2.toml');
diff --git a/lib/modules/manager/pre-commit/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/pre-commit/__snapshots__/extract.spec.ts.snap
index 986fcae3dc..16e79915a4 100644
--- a/lib/modules/manager/pre-commit/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/pre-commit/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/pre-commit/extract extractPackageFile() extracts from complex config file correctly 1`] = `
+exports[`modules/manager/pre-commit/extract > extractPackageFile() > extracts from complex config file correctly 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/pre-commit/extract.spec.ts b/lib/modules/manager/pre-commit/extract.spec.ts
index 011f7b242b..a52b0a90b7 100644
--- a/lib/modules/manager/pre-commit/extract.spec.ts
+++ b/lib/modules/manager/pre-commit/extract.spec.ts
@@ -5,7 +5,7 @@ import * as _hostRules from '../../../util/host-rules';
 import { PypiDatasource } from '../../datasource/pypi';
 import { extractPackageFile } from '.';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
 const hostRules = mocked(_hostRules);
 const filename = '.pre-commit.yaml';
 
diff --git a/lib/modules/manager/pub/artifacts.spec.ts b/lib/modules/manager/pub/artifacts.spec.ts
index c77417f0bd..0890ef29c9 100644
--- a/lib/modules/manager/pub/artifacts.spec.ts
+++ b/lib/modules/manager/pub/artifacts.spec.ts
@@ -10,11 +10,11 @@ import * as _datasource from '../../datasource';
 import type { UpdateArtifact, UpdateArtifactsConfig } from '../types';
 import * as pub from '.';
 
-jest.mock('../../../util/exec/env');
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
-jest.mock('../../../util/http');
-jest.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/exec/env');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../../../util/http');
+vi.mock('../../datasource', () => mockDeep());
 
 process.env.CONTAINERBASE = 'true';
 
diff --git a/lib/modules/manager/sbt/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/sbt/__snapshots__/extract.spec.ts.snap
index 87d51705bf..e1654d86a2 100644
--- a/lib/modules/manager/sbt/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/sbt/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/sbt/extract extractPackageFile() extract deps from native scala file with private variables 1`] = `
+exports[`modules/manager/sbt/extract > extractPackageFile() > extract deps from native scala file with private variables 1`] = `
 {
   "deps": [
     {
@@ -35,7 +35,7 @@ exports[`modules/manager/sbt/extract extractPackageFile() extract deps from nati
 }
 `;
 
-exports[`modules/manager/sbt/extract extractPackageFile() extract deps from native scala file with variables 1`] = `
+exports[`modules/manager/sbt/extract > extractPackageFile() > extract deps from native scala file with variables 1`] = `
 {
   "deps": [
     {
@@ -97,7 +97,7 @@ exports[`modules/manager/sbt/extract extractPackageFile() extract deps from nati
 }
 `;
 
-exports[`modules/manager/sbt/extract extractPackageFile() extracts deps for generic use-cases 1`] = `
+exports[`modules/manager/sbt/extract > extractPackageFile() > extracts deps for generic use-cases 1`] = `
 {
   "deps": [
     {
@@ -286,7 +286,7 @@ exports[`modules/manager/sbt/extract extractPackageFile() extracts deps for gene
 }
 `;
 
-exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when scala version is defined in a variable 1`] = `
+exports[`modules/manager/sbt/extract > extractPackageFile() > extracts deps when scala version is defined in a variable 1`] = `
 {
   "deps": [
     {
@@ -434,7 +434,7 @@ exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when sca
 }
 `;
 
-exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when scala version is defined in a variable with ThisBuild scope 1`] = `
+exports[`modules/manager/sbt/extract > extractPackageFile() > extracts deps when scala version is defined in a variable with ThisBuild scope 1`] = `
 {
   "deps": [
     {
@@ -460,7 +460,7 @@ exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when sca
 }
 `;
 
-exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when scala version is defined in a variable with a trailing comma 1`] = `
+exports[`modules/manager/sbt/extract > extractPackageFile() > extracts deps when scala version is defined in a variable with a trailing comma 1`] = `
 {
   "deps": [
     {
@@ -486,7 +486,7 @@ exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when sca
 }
 `;
 
-exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when scala version is defined with ThisBuild scope 1`] = `
+exports[`modules/manager/sbt/extract > extractPackageFile() > extracts deps when scala version is defined with ThisBuild scope 1`] = `
 {
   "deps": [
     {
@@ -512,7 +512,7 @@ exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when sca
 }
 `;
 
-exports[`modules/manager/sbt/extract extractPackageFile() extracts deps when scala version is defined with a trailing comma 1`] = `
+exports[`modules/manager/sbt/extract > extractPackageFile() > extracts deps when scala version is defined with a trailing comma 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/sbt/extract.spec.ts b/lib/modules/manager/sbt/extract.spec.ts
index 03f3cbf232..4d260ac04e 100644
--- a/lib/modules/manager/sbt/extract.spec.ts
+++ b/lib/modules/manager/sbt/extract.spec.ts
@@ -6,7 +6,7 @@ import {
   extractAllPackageFiles,
 } from './extract';
 
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 const extractPackageFile = (content: string) => extract(content, 'build.sbt');
 
diff --git a/lib/modules/manager/setup-cfg/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/setup-cfg/__snapshots__/extract.spec.ts.snap
index f0be467fd0..ed406f7f6c 100644
--- a/lib/modules/manager/setup-cfg/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/setup-cfg/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/setup-cfg/extract extractPackageFile() extracts dependencies 1`] = `
+exports[`modules/manager/setup-cfg/extract > extractPackageFile() > extracts dependencies 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/swift/__snapshots__/index.spec.ts.snap b/lib/modules/manager/swift/__snapshots__/index.spec.ts.snap
index 0df2720a70..f6d154fc6e 100644
--- a/lib/modules/manager/swift/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/manager/swift/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/swift/index extractPackageFile() parses multiple packages 1`] = `
+exports[`modules/manager/swift/index > extractPackageFile() > parses multiple packages 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/tekton/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/tekton/__snapshots__/extract.spec.ts.snap
index a6151f53ed..f09213f91e 100644
--- a/lib/modules/manager/tekton/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/tekton/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/tekton/extract extractPackageFile() extracts deps from a file 1`] = `
+exports[`modules/manager/tekton/extract > extractPackageFile() > extracts deps from a file 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/terraform/extract.spec.ts b/lib/modules/manager/terraform/extract.spec.ts
index e0eb63b5ae..6c883f41d9 100644
--- a/lib/modules/manager/terraform/extract.spec.ts
+++ b/lib/modules/manager/terraform/extract.spec.ts
@@ -28,7 +28,7 @@ const adminConfig: RepoGlobalConfig = {
 };
 
 // auto-mock fs
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/terraform/extract', () => {
   beforeEach(() => {
diff --git a/lib/modules/manager/terraform/lockfile/__snapshots__/hash.spec.ts.snap b/lib/modules/manager/terraform/lockfile/__snapshots__/hash.spec.ts.snap
index 69ff512cc5..289a5fd2d2 100644
--- a/lib/modules/manager/terraform/lockfile/__snapshots__/hash.spec.ts.snap
+++ b/lib/modules/manager/terraform/lockfile/__snapshots__/hash.spec.ts.snap
@@ -1,3 +1,3 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/terraform/lockfile/hash full walkthrough 1`] = `[]`;
+exports[`modules/manager/terraform/lockfile/hash > full walkthrough 1`] = `[]`;
diff --git a/lib/modules/manager/terraform/lockfile/hash.spec.ts b/lib/modules/manager/terraform/lockfile/hash.spec.ts
index bde55b218e..ebc0919b71 100644
--- a/lib/modules/manager/terraform/lockfile/hash.spec.ts
+++ b/lib/modules/manager/terraform/lockfile/hash.spec.ts
@@ -366,7 +366,7 @@ describe('modules/manager/terraform/lockfile/hash', () => {
     ]);
   });
 
-  it('it does not add any ziphashes when the shasums endpoint fails`', async () => {
+  it('does not add any ziphashes when the shasums endpoint fails`', async () => {
     const readStreamLinux = createReadStream(
       'lib/modules/manager/terraform/lockfile/__fixtures__/test.zip',
     );
diff --git a/lib/modules/manager/terraform/lockfile/index.spec.ts b/lib/modules/manager/terraform/lockfile/index.spec.ts
index 48171b70e9..a630b257d7 100644
--- a/lib/modules/manager/terraform/lockfile/index.spec.ts
+++ b/lib/modules/manager/terraform/lockfile/index.spec.ts
@@ -10,9 +10,9 @@ import { TerraformProviderHash } from './hash';
 import { getNewConstraint } from './index';
 
 // auto-mock fs
-jest.mock('../../../../util/fs');
-jest.mock('./hash');
-jest.mock('../../../datasource', () => mockDeep());
+vi.mock('../../../../util/fs');
+vi.mock('./hash');
+vi.mock('../../../datasource', () => mockDeep());
 
 const config = {
   constraints: {},
diff --git a/lib/modules/manager/terragrunt/artifacts.spec.ts b/lib/modules/manager/terragrunt/artifacts.spec.ts
index e7b49a76e0..bff31e8f0b 100644
--- a/lib/modules/manager/terragrunt/artifacts.spec.ts
+++ b/lib/modules/manager/terragrunt/artifacts.spec.ts
@@ -5,7 +5,7 @@ import * as terraformLockfile from '../terraform/lockfile';
 import type { UpdateArtifactsConfig } from '../types';
 import { updateArtifacts } from './artifacts';
 
-jest.mock('../terraform/lockfile');
+vi.mock('../terraform/lockfile');
 
 const config = {
   constraints: {},
diff --git a/lib/modules/manager/tflint-plugin/extract.spec.ts b/lib/modules/manager/tflint-plugin/extract.spec.ts
index 52cd0dbbc7..a2e679dc96 100644
--- a/lib/modules/manager/tflint-plugin/extract.spec.ts
+++ b/lib/modules/manager/tflint-plugin/extract.spec.ts
@@ -11,7 +11,7 @@ const adminConfig: RepoGlobalConfig = {
 };
 
 // auto-mock fs
-jest.mock('../../../util/fs');
+vi.mock('../../../util/fs');
 
 describe('modules/manager/tflint-plugin/extract', () => {
   beforeEach(() => {
diff --git a/lib/modules/manager/travis/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/travis/__snapshots__/extract.spec.ts.snap
index 16c0c57dc0..eea562a2a2 100644
--- a/lib/modules/manager/travis/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/travis/__snapshots__/extract.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/travis/extract extractPackageFile() returns results 1`] = `
+exports[`modules/manager/travis/extract > extractPackageFile() > returns results 1`] = `
 {
   "deps": [
     {
diff --git a/lib/modules/manager/vendir/__snapshots__/artifacts.spec.ts.snap b/lib/modules/manager/vendir/__snapshots__/artifacts.spec.ts.snap
index 059191726c..58a5566fb2 100644
--- a/lib/modules/manager/vendir/__snapshots__/artifacts.spec.ts.snap
+++ b/lib/modules/manager/vendir/__snapshots__/artifacts.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/manager/vendir/artifacts returns null if unchanged 1`] = `
+exports[`modules/manager/vendir/artifacts > returns null if unchanged 1`] = `
 [
   {
     "cmd": "vendir sync",
diff --git a/lib/modules/manager/vendir/artifacts.spec.ts b/lib/modules/manager/vendir/artifacts.spec.ts
index 6d9f99ca02..94898f3fcd 100644
--- a/lib/modules/manager/vendir/artifacts.spec.ts
+++ b/lib/modules/manager/vendir/artifacts.spec.ts
@@ -13,11 +13,11 @@ import * as vendir from '.';
 
 process.env.CONTAINERBASE = 'true';
 
-jest.mock('../../datasource', () => mockDeep());
-jest.mock('../../../util/exec/env', () => mockDeep());
-jest.mock('../../../util/http', () => mockDeep());
-jest.mock('../../../util/fs', () => mockDeep());
-jest.mock('../../../util/git', () => mockDeep());
+vi.mock('../../datasource', () => mockDeep());
+vi.mock('../../../util/exec/env', () => mockDeep());
+vi.mock('../../../util/http', () => mockDeep());
+vi.mock('../../../util/fs', () => mockDeep());
+vi.mock('../../../util/git', () => mockDeep());
 
 const adminConfig: RepoGlobalConfig = {
   localDir: join('/tmp/github/some/repo'), // `join` fixes Windows CI
diff --git a/lib/modules/platform/azure/__snapshots__/azure-helper.spec.ts.snap b/lib/modules/platform/azure/__snapshots__/azure-helper.spec.ts.snap
index 1a7c73e210..84f143e474 100644
--- a/lib/modules/platform/azure/__snapshots__/azure-helper.spec.ts.snap
+++ b/lib/modules/platform/azure/__snapshots__/azure-helper.spec.ts.snap
@@ -1,20 +1,20 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/platform/azure/azure-helper getAzureBranchObj should get the branch object 1`] = `
+exports[`modules/platform/azure/azure-helper > getAzureBranchObj > should get the branch object 1`] = `
 {
   "name": "refs/heads/branchName",
   "oldObjectId": "132",
 }
 `;
 
-exports[`modules/platform/azure/azure-helper getAzureBranchObj should get the branch object when ref missing 1`] = `
+exports[`modules/platform/azure/azure-helper > getAzureBranchObj > should get the branch object when ref missing 1`] = `
 {
   "name": "refs/heads/branchName",
   "oldObjectId": "0000000000000000000000000000000000000000",
 }
 `;
 
-exports[`modules/platform/azure/azure-helper getCommitDetails should get commit details 1`] = `
+exports[`modules/platform/azure/azure-helper > getCommitDetails > should get commit details 1`] = `
 {
   "parents": [
     "123456",
@@ -22,9 +22,9 @@ exports[`modules/platform/azure/azure-helper getCommitDetails should get commit
 }
 `;
 
-exports[`modules/platform/azure/azure-helper getFile should return the file content because it is not a json 1`] = `"{"hello"= "test"}"`;
+exports[`modules/platform/azure/azure-helper > getFile > should return the file content because it is not a json 1`] = `"{"hello"= "test"}"`;
 
-exports[`modules/platform/azure/azure-helper getRef should get the ref with full ref name 1`] = `
+exports[`modules/platform/azure/azure-helper > getRef > should get the ref with full ref name 1`] = `
 [
   {
     "objectId": "132",
@@ -32,7 +32,7 @@ exports[`modules/platform/azure/azure-helper getRef should get the ref with full
 ]
 `;
 
-exports[`modules/platform/azure/azure-helper getRef should get the ref with short ref name 1`] = `
+exports[`modules/platform/azure/azure-helper > getRef > should get the ref with short ref name 1`] = `
 [
   {
     "objectId": 132,
diff --git a/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap b/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap
index e782de620a..124e0dfb53 100644
--- a/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/platform/azure/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/platform/azure/index createPr() should create and return a PR object 1`] = `
+exports[`modules/platform/azure/index > createPr() > should create and return a PR object 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -15,7 +15,7 @@ exports[`modules/platform/azure/index createPr() should create and return a PR o
 }
 `;
 
-exports[`modules/platform/azure/index createPr() should create and return a PR object from base branch 1`] = `
+exports[`modules/platform/azure/index > createPr() > should create and return a PR object from base branch 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -30,7 +30,7 @@ exports[`modules/platform/azure/index createPr() should create and return a PR o
 }
 `;
 
-exports[`modules/platform/azure/index createPr() should create and return an approved PR object 1`] = `
+exports[`modules/platform/azure/index > createPr() > should create and return an approved PR object 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -49,7 +49,7 @@ exports[`modules/platform/azure/index createPr() should create and return an app
 }
 `;
 
-exports[`modules/platform/azure/index createPr() when usePlatformAutomerge is set should create and return a PR object with auto-complete set 1`] = `
+exports[`modules/platform/azure/index > createPr() > when usePlatformAutomerge is set > should create and return a PR object with auto-complete set 1`] = `
 {
   "autoCompleteSetBy": {
     "id": "123",
@@ -76,14 +76,14 @@ exports[`modules/platform/azure/index createPr() when usePlatformAutomerge is se
 }
 `;
 
-exports[`modules/platform/azure/index deleteLabel() Should delete a label 1`] = `
+exports[`modules/platform/azure/index > deleteLabel() > Should delete a label 1`] = `
 [
   [],
   [],
 ]
 `;
 
-exports[`modules/platform/azure/index ensureComment adds comment if missing 1`] = `
+exports[`modules/platform/azure/index > ensureComment > adds comment if missing 1`] = `
 [
   [
     {
@@ -105,19 +105,19 @@ content",
 ]
 `;
 
-exports[`modules/platform/azure/index ensureComment adds comment if missing 2`] = `[]`;
+exports[`modules/platform/azure/index > ensureComment > adds comment if missing 2`] = `[]`;
 
-exports[`modules/platform/azure/index ensureComment does nothing if comment exists and is the same 1`] = `[]`;
+exports[`modules/platform/azure/index > ensureComment > does nothing if comment exists and is the same 1`] = `[]`;
 
-exports[`modules/platform/azure/index ensureComment does nothing if comment exists and is the same 2`] = `[]`;
+exports[`modules/platform/azure/index > ensureComment > does nothing if comment exists and is the same 2`] = `[]`;
 
-exports[`modules/platform/azure/index ensureComment does nothing if comment exists and is the same when there is no topic 1`] = `[]`;
+exports[`modules/platform/azure/index > ensureComment > does nothing if comment exists and is the same when there is no topic 1`] = `[]`;
 
-exports[`modules/platform/azure/index ensureComment does nothing if comment exists and is the same when there is no topic 2`] = `[]`;
+exports[`modules/platform/azure/index > ensureComment > does nothing if comment exists and is the same when there is no topic 2`] = `[]`;
 
-exports[`modules/platform/azure/index ensureComment updates comment if missing 1`] = `[]`;
+exports[`modules/platform/azure/index > ensureComment > updates comment if missing 1`] = `[]`;
 
-exports[`modules/platform/azure/index ensureComment updates comment if missing 2`] = `
+exports[`modules/platform/azure/index > ensureComment > updates comment if missing 2`] = `
 [
   [
     {
@@ -135,7 +135,7 @@ content",
 ]
 `;
 
-exports[`modules/platform/azure/index getJsonFile() supports fetch from another repo 1`] = `
+exports[`modules/platform/azure/index > getJsonFile() > supports fetch from another repo 1`] = `
 [
   [
     "123456",
@@ -152,7 +152,7 @@ exports[`modules/platform/azure/index getJsonFile() supports fetch from another
 ]
 `;
 
-exports[`modules/platform/azure/index getPr(prNo) should return a pr in the right format 1`] = `
+exports[`modules/platform/azure/index > getPr(prNo) > should return a pr in the right format 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -170,32 +170,32 @@ exports[`modules/platform/azure/index getPr(prNo) should return a pr in the righ
 }
 `;
 
-exports[`modules/platform/azure/index getRepos() should return an array of repos 1`] = `
+exports[`modules/platform/azure/index > getRepos() > should return an array of repos 1`] = `
 [
   [],
 ]
 `;
 
-exports[`modules/platform/azure/index getRepos() should return an array of repos 2`] = `
+exports[`modules/platform/azure/index > getRepos() > should return an array of repos 2`] = `
 [
   "prj1/repo1",
   "prj1/repo2",
 ]
 `;
 
-exports[`modules/platform/azure/index initPlatform() should init 1`] = `
+exports[`modules/platform/azure/index > initPlatform() > should init 1`] = `
 {
   "endpoint": "https://dev.azure.com/renovate12345/",
 }
 `;
 
-exports[`modules/platform/azure/index initRepo should initialise the config for a repo 1`] = `
+exports[`modules/platform/azure/index > initRepo > should initialise the config for a repo 1`] = `
 [
   [],
 ]
 `;
 
-exports[`modules/platform/azure/index initRepo should initialise the config for a repo 2`] = `
+exports[`modules/platform/azure/index > initRepo > should initialise the config for a repo 2`] = `
 {
   "defaultBranch": "defBr",
   "isFork": false,
@@ -203,7 +203,7 @@ exports[`modules/platform/azure/index initRepo should initialise the config for
 }
 `;
 
-exports[`modules/platform/azure/index updatePr(prNo, title, body, platformPrOptions) should close the PR 1`] = `
+exports[`modules/platform/azure/index > updatePr(prNo, title, body, platformPrOptions) > should close the PR 1`] = `
 [
   [
     {
@@ -217,9 +217,9 @@ exports[`modules/platform/azure/index updatePr(prNo, title, body, platformPrOpti
 ]
 `;
 
-exports[`modules/platform/azure/index updatePr(prNo, title, body, platformPrOptions) should re-approve the PR 1`] = `undefined`;
+exports[`modules/platform/azure/index > updatePr(prNo, title, body, platformPrOptions) > should re-approve the PR 1`] = `undefined`;
 
-exports[`modules/platform/azure/index updatePr(prNo, title, body, platformPrOptions) should reopen the PR 1`] = `
+exports[`modules/platform/azure/index > updatePr(prNo, title, body, platformPrOptions) > should reopen the PR 1`] = `
 [
   [
     {
@@ -239,7 +239,7 @@ exports[`modules/platform/azure/index updatePr(prNo, title, body, platformPrOpti
 ]
 `;
 
-exports[`modules/platform/azure/index updatePr(prNo, title, body, platformPrOptions) should update the PR 1`] = `
+exports[`modules/platform/azure/index > updatePr(prNo, title, body, platformPrOptions) > should update the PR 1`] = `
 [
   [
     {
@@ -253,7 +253,7 @@ exports[`modules/platform/azure/index updatePr(prNo, title, body, platformPrOpti
 ]
 `;
 
-exports[`modules/platform/azure/index updatePr(prNo, title, body, platformPrOptions) should update the PR without description 1`] = `
+exports[`modules/platform/azure/index > updatePr(prNo, title, body, platformPrOptions) > should update the PR without description 1`] = `
 [
   [
     {
diff --git a/lib/modules/platform/azure/__snapshots__/util.spec.ts.snap b/lib/modules/platform/azure/__snapshots__/util.spec.ts.snap
index db6ecdf85a..e63410ffa7 100644
--- a/lib/modules/platform/azure/__snapshots__/util.spec.ts.snap
+++ b/lib/modules/platform/azure/__snapshots__/util.spec.ts.snap
@@ -1,20 +1,20 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/platform/azure/util getProjectAndRepo should return the object with project and repo 1`] = `
+exports[`modules/platform/azure/util > getProjectAndRepo > should return the object with project and repo 1`] = `
 {
   "project": "prjName",
   "repo": "myRepoName",
 }
 `;
 
-exports[`modules/platform/azure/util getProjectAndRepo should return the object with same strings 1`] = `
+exports[`modules/platform/azure/util > getProjectAndRepo > should return the object with same strings 1`] = `
 {
   "project": "myRepoName",
   "repo": "myRepoName",
 }
 `;
 
-exports[`modules/platform/azure/util getRenovatePRFormat should be formated (closed v2) 1`] = `
+exports[`modules/platform/azure/util > getRenovatePRFormat > should be formated (closed v2) 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -29,7 +29,7 @@ exports[`modules/platform/azure/util getRenovatePRFormat should be formated (clo
 }
 `;
 
-exports[`modules/platform/azure/util getRenovatePRFormat should be formated (closed) 1`] = `
+exports[`modules/platform/azure/util > getRenovatePRFormat > should be formated (closed) 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -44,7 +44,7 @@ exports[`modules/platform/azure/util getRenovatePRFormat should be formated (clo
 }
 `;
 
-exports[`modules/platform/azure/util getRenovatePRFormat should be formated (not closed) 1`] = `
+exports[`modules/platform/azure/util > getRenovatePRFormat > should be formated (not closed) 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -59,22 +59,22 @@ exports[`modules/platform/azure/util getRenovatePRFormat should be formated (not
 }
 `;
 
-exports[`modules/platform/azure/util getStorageExtraCloneOpts should configure basic auth 1`] = `
+exports[`modules/platform/azure/util > getStorageExtraCloneOpts > should configure basic auth 1`] = `
 {
   "-c": "http.extraheader=AUTHORIZATION: basic dXNlcjpwYXNz",
 }
 `;
 
-exports[`modules/platform/azure/util getStorageExtraCloneOpts should configure bearer token 1`] = `
+exports[`modules/platform/azure/util > getStorageExtraCloneOpts > should configure bearer token 1`] = `
 {
   "-c": "http.extraheader=AUTHORIZATION: bearer token",
 }
 `;
 
-exports[`modules/platform/azure/util getStorageExtraCloneOpts should configure personal access token 1`] = `
+exports[`modules/platform/azure/util > getStorageExtraCloneOpts > should configure personal access token 1`] = `
 {
   "-c": "http.extraheader=AUTHORIZATION: basic OjEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3OHRlc3Q=",
 }
 `;
 
-exports[`modules/platform/azure/util max4000Chars should be the same 1`] = `"Hello"`;
+exports[`modules/platform/azure/util > max4000Chars > should be the same 1`] = `"Hello"`;
diff --git a/lib/modules/platform/azure/azure-helper.spec.ts b/lib/modules/platform/azure/azure-helper.spec.ts
index 3b9f1db120..2abae10362 100644
--- a/lib/modules/platform/azure/azure-helper.spec.ts
+++ b/lib/modules/platform/azure/azure-helper.spec.ts
@@ -2,19 +2,21 @@ import { Readable } from 'node:stream';
 import type { IPolicyApi } from 'azure-devops-node-api/PolicyApi';
 import { GitPullRequestMergeStrategy } from 'azure-devops-node-api/interfaces/GitInterfaces';
 import type { PolicyConfiguration } from 'azure-devops-node-api/interfaces/PolicyInterfaces';
+import type { MockedObject } from 'vitest';
+import { mockDeep } from 'vitest-mock-extended';
 import { partial } from '../../../../test/util';
 
-jest.mock('./azure-got-wrapper');
+vi.mock('./azure-got-wrapper', () => mockDeep());
 
 describe('modules/platform/azure/azure-helper', () => {
   let azureHelper: typeof import('./azure-helper');
-  let azureApi: jest.Mocked<typeof import('./azure-got-wrapper')>;
+  let azureApi: MockedObject<typeof import('./azure-got-wrapper')>;
 
   beforeEach(async () => {
     // reset module
     jest.resetModules();
     azureHelper = await import('./azure-helper');
-    azureApi = jest.requireMock('./azure-got-wrapper');
+    azureApi = await vi.importMock('./azure-got-wrapper');
   });
 
   describe('getRef', () => {
@@ -436,7 +438,7 @@ describe('modules/platform/azure/azure-helper', () => {
   });
 
   describe('getAllProjectTeams', () => {
-    it('should get all teams ', async () => {
+    it('should get all teams', async () => {
       const team1 = Array.from({ length: 100 }, (_, index) => ({
         description: `team1 ${index + 1}`,
       }));
diff --git a/lib/modules/platform/azure/index.spec.ts b/lib/modules/platform/azure/index.spec.ts
index 73308cdfbf..42fc899387 100644
--- a/lib/modules/platform/azure/index.spec.ts
+++ b/lib/modules/platform/azure/index.spec.ts
@@ -8,7 +8,7 @@ import {
   PullRequestStatus,
 } from 'azure-devops-node-api/interfaces/GitInterfaces.js';
 import { mockDeep } from 'jest-mock-extended';
-import { mocked, partial } from '../../../../test/util';
+import { partial } from '../../../../test/util';
 import {
   REPOSITORY_ARCHIVED,
   REPOSITORY_NOT_FOUND,
@@ -19,14 +19,14 @@ import type * as _hostRules from '../../../util/host-rules';
 import type { Platform, RepoParams } from '../types';
 import { AzurePrVote } from './types';
 
-jest.mock('./azure-got-wrapper');
-jest.mock('./azure-helper');
-jest.mock('../../../util/git');
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('../../../util/sanitize', () =>
+vi.mock('./azure-got-wrapper', () => mockDeep());
+vi.mock('./azure-helper', () => mockDeep());
+vi.mock('../../../util/git', () => mockDeep());
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/sanitize', () =>
   mockDeep({ sanitize: (s: string) => s }),
 );
-jest.mock('timers/promises');
+vi.mock('timers/promises');
 
 describe('modules/platform/azure/index', () => {
   let hostRules: jest.Mocked<typeof _hostRules>;
@@ -39,12 +39,12 @@ describe('modules/platform/azure/index', () => {
   beforeEach(async () => {
     // reset module
     jest.resetModules();
-    hostRules = jest.requireMock('../../../util/host-rules');
+    hostRules = await vi.importMock('../../../util/host-rules');
     azure = await import('.');
-    azureApi = jest.requireMock('./azure-got-wrapper');
-    azureHelper = jest.requireMock('./azure-helper');
-    logger = mocked(await import('../../../logger')).logger;
-    git = jest.requireMock('../../../util/git');
+    azureApi = await vi.importMock('./azure-got-wrapper');
+    azureHelper = await vi.importMock('./azure-helper');
+    logger = vi.mocked(await import('../../../logger'), true).logger;
+    git = await vi.importMock('../../../util/git');
     git.branchExists.mockReturnValue(true);
     git.isBranchBehindBase.mockResolvedValue(false);
     hostRules.find.mockReturnValue({
diff --git a/lib/modules/platform/bitbucket-server/__snapshots__/index.spec.ts.snap b/lib/modules/platform/bitbucket-server/__snapshots__/index.spec.ts.snap
index 0d28800baf..c07e9499c7 100644
--- a/lib/modules/platform/bitbucket-server/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/platform/bitbucket-server/__snapshots__/index.spec.ts.snap
@@ -1,16 +1,16 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path addAssignees() does not throw 1`] = `undefined`;
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > addAssignees() > does not throw 1`] = `undefined`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path addReviewers does not throw 1`] = `undefined`;
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > addReviewers > does not throw 1`] = `undefined`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path addReviewers throws 1`] = `"Response code 405 (Method Not Allowed)"`;
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > addReviewers > throws 1`] = `[HTTPError: Response code 405 (Method Not Allowed)]`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path addReviewers throws on invalid reviewers 1`] = `"Response code 409 (Conflict)"`;
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > addReviewers > throws on invalid reviewers 1`] = `[HTTPError: Response code 409 (Conflict)]`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path deleteLAbel() does not throw 1`] = `undefined`;
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > deleteLAbel() > does not throw 1`] = `undefined`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path findPr() has pr 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > findPr() > has pr 1`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -25,7 +25,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path findPr()
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path getBranchPr() has pr 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > getBranchPr() > has pr 1`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -43,7 +43,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path getBranch
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() canRebase 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > getPr() > canRebase 1`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -61,7 +61,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() c
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() canRebase 2`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > getPr() > canRebase 2`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -79,7 +79,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() c
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() canRebase 3`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > getPr() > canRebase 3`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -97,7 +97,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() c
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() gets a PR 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > getPr() > gets a PR 1`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -115,7 +115,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() g
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() gets a closed PR 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > getPr() > gets a closed PR 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -131,7 +131,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path getPr() g
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path getPrList() has pr 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > getPrList() > has pr 1`] = `
 [
   {
     "bodyStruct": {
@@ -148,14 +148,14 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path getPrList
 ]
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path initPlatform() should init 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > initPlatform() > should init 1`] = `
 {
   "endpoint": "https://stash.renovatebot.com/",
   "gitAuthor": "Abc Def <abc@def.com>",
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path initRepo() generates URL if API does not contain clone links 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > initRepo() > generates URL if API does not contain clone links 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -163,7 +163,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path initRepo(
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path initRepo() uses http url from API with injected auth if http url in API response 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > initRepo() > uses http url from API with injected auth if http url in API response 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -171,7 +171,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path initRepo(
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path initRepo() uses ssh url from API if http not in API response 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > initRepo() > uses ssh url from API if http not in API response 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -179,7 +179,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path initRepo(
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path initRepo() works 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > initRepo() > works 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -187,9 +187,9 @@ exports[`modules/platform/bitbucket-server/index endpoint with no path initRepo(
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path massageMarkdown() returns diff files 1`] = `"**foo**bartext"`;
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > massageMarkdown() > returns diff files 1`] = `"**foo**bartext"`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path massageMarkdown() sanitizes HTML comments in the body 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > massageMarkdown() > sanitizes HTML comments in the body 1`] = `
 "---
 
 - [ ] If you want to rebase/retry this PR, click this checkbox
@@ -203,19 +203,19 @@ Followed by some information.
 "
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with no path updatePr() throws 1`] = `"Response code 405 (Method Not Allowed)"`;
+exports[`modules/platform/bitbucket-server/index > endpoint with no path > updatePr() > throws 1`] = `[HTTPError: Response code 405 (Method Not Allowed)]`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path addAssignees() does not throw 1`] = `undefined`;
+exports[`modules/platform/bitbucket-server/index > endpoint with path > addAssignees() > does not throw 1`] = `undefined`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path addReviewers does not throw 1`] = `undefined`;
+exports[`modules/platform/bitbucket-server/index > endpoint with path > addReviewers > does not throw 1`] = `undefined`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path addReviewers throws 1`] = `"Response code 405 (Method Not Allowed)"`;
+exports[`modules/platform/bitbucket-server/index > endpoint with path > addReviewers > throws 1`] = `[HTTPError: Response code 405 (Method Not Allowed)]`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path addReviewers throws on invalid reviewers 1`] = `"Response code 409 (Conflict)"`;
+exports[`modules/platform/bitbucket-server/index > endpoint with path > addReviewers > throws on invalid reviewers 1`] = `[HTTPError: Response code 409 (Conflict)]`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path deleteLAbel() does not throw 1`] = `undefined`;
+exports[`modules/platform/bitbucket-server/index > endpoint with path > deleteLAbel() > does not throw 1`] = `undefined`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path findPr() has pr 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > findPr() > has pr 1`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -230,7 +230,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path findPr() has
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path getBranchPr() has pr 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > getBranchPr() > has pr 1`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -248,7 +248,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path getBranchPr(
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path getPr() canRebase 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > getPr() > canRebase 1`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -266,7 +266,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path getPr() canR
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path getPr() canRebase 2`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > getPr() > canRebase 2`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -284,7 +284,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path getPr() canR
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path getPr() canRebase 3`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > getPr() > canRebase 3`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -302,7 +302,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path getPr() canR
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path getPr() gets a PR 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > getPr() > gets a PR 1`] = `
 {
   "bodyStruct": {
     "hash": "7980dafc4eb6f0c79278fd929d3e8e5954b32b68ae118a22565c7c369fc2f591",
@@ -320,7 +320,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path getPr() gets
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path getPr() gets a closed PR 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > getPr() > gets a closed PR 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -336,7 +336,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path getPr() gets
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path getPrList() has pr 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > getPrList() > has pr 1`] = `
 [
   {
     "bodyStruct": {
@@ -353,14 +353,14 @@ exports[`modules/platform/bitbucket-server/index endpoint with path getPrList()
 ]
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path initPlatform() should init 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > initPlatform() > should init 1`] = `
 {
   "endpoint": "https://stash.renovatebot.com/",
   "gitAuthor": "Abc Def <abc@def.com>",
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path initRepo() generates URL if API does not contain clone links 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > initRepo() > generates URL if API does not contain clone links 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -368,7 +368,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path initRepo() g
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path initRepo() uses http url from API with injected auth if http url in API response 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > initRepo() > uses http url from API with injected auth if http url in API response 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -376,7 +376,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path initRepo() u
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path initRepo() uses ssh url from API if http not in API response 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > initRepo() > uses ssh url from API if http not in API response 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -384,7 +384,7 @@ exports[`modules/platform/bitbucket-server/index endpoint with path initRepo() u
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path initRepo() works 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > initRepo() > works 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -392,9 +392,9 @@ exports[`modules/platform/bitbucket-server/index endpoint with path initRepo() w
 }
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path massageMarkdown() returns diff files 1`] = `"**foo**bartext"`;
+exports[`modules/platform/bitbucket-server/index > endpoint with path > massageMarkdown() > returns diff files 1`] = `"**foo**bartext"`;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path massageMarkdown() sanitizes HTML comments in the body 1`] = `
+exports[`modules/platform/bitbucket-server/index > endpoint with path > massageMarkdown() > sanitizes HTML comments in the body 1`] = `
 "---
 
 - [ ] If you want to rebase/retry this PR, click this checkbox
@@ -408,4 +408,4 @@ Followed by some information.
 "
 `;
 
-exports[`modules/platform/bitbucket-server/index endpoint with path updatePr() throws 1`] = `"Response code 405 (Method Not Allowed)"`;
+exports[`modules/platform/bitbucket-server/index > endpoint with path > updatePr() > throws 1`] = `[HTTPError: Response code 405 (Method Not Allowed)]`;
diff --git a/lib/modules/platform/bitbucket-server/index.spec.ts b/lib/modules/platform/bitbucket-server/index.spec.ts
index fda3b67376..c9af114a3e 100644
--- a/lib/modules/platform/bitbucket-server/index.spec.ts
+++ b/lib/modules/platform/bitbucket-server/index.spec.ts
@@ -11,9 +11,9 @@ import type { LongCommitSha } from '../../../util/git/types';
 import { ensureTrailingSlash } from '../../../util/url';
 import * as bitbucket from '.';
 
-jest.mock('timers/promises');
-jest.mock('../../../util/git');
-jest.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('timers/promises');
+vi.mock('../../../util/git');
+vi.mock('../../../util/host-rules', () => mockDeep());
 
 function sshLink(projectKey: string, repositorySlug: string): string {
   return `ssh://git@stash.renovatebot.com:7999/${projectKey.toLowerCase()}/${repositorySlug}.git`;
@@ -179,6 +179,7 @@ describe('modules/platform/bitbucket-server/index', () => {
     const urlHost = url.origin;
     const urlPath = url.pathname === '/' ? '' : url.pathname;
 
+    // eslint-disable-next-line vitest/valid-title
     describe(scenarioName, () => {
       const username = 'abc';
       const password = '123';
diff --git a/lib/modules/platform/bitbucket-server/utils.spec.ts b/lib/modules/platform/bitbucket-server/utils.spec.ts
index 9625459ad3..616a51c474 100644
--- a/lib/modules/platform/bitbucket-server/utils.spec.ts
+++ b/lib/modules/platform/bitbucket-server/utils.spec.ts
@@ -117,6 +117,7 @@ describe('modules/platform/bitbucket-server/utils', () => {
 
   describe('getRepoGitUrl', () => {
     Object.entries(scenarios).forEach(([scenarioName, url]) => {
+      // eslint-disable-next-line vitest/valid-title
       describe(scenarioName, () => {
         const username = 'abc';
         const password = '123';
diff --git a/lib/modules/platform/bitbucket/__snapshots__/index.spec.ts.snap b/lib/modules/platform/bitbucket/__snapshots__/index.spec.ts.snap
index b009eb1bde..0e4460ed91 100644
--- a/lib/modules/platform/bitbucket/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/platform/bitbucket/__snapshots__/index.spec.ts.snap
@@ -1,19 +1,19 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/platform/bitbucket/index addAssignees() does not throw 1`] = `undefined`;
+exports[`modules/platform/bitbucket/index > addAssignees() > does not throw 1`] = `undefined`;
 
-exports[`modules/platform/bitbucket/index ensureComment() does not throw 1`] = `false`;
+exports[`modules/platform/bitbucket/index > ensureComment() > does not throw 1`] = `false`;
 
-exports[`modules/platform/bitbucket/index ensureCommentRemoval() does not throw 1`] = `undefined`;
+exports[`modules/platform/bitbucket/index > ensureCommentRemoval() > does not throw 1`] = `undefined`;
 
-exports[`modules/platform/bitbucket/index findIssue() does not throw 1`] = `
+exports[`modules/platform/bitbucket/index > findIssue() > does not throw 1`] = `
 {
   "body": "content",
   "number": 25,
 }
 `;
 
-exports[`modules/platform/bitbucket/index findPr() finds pr 1`] = `
+exports[`modules/platform/bitbucket/index > findPr() > finds pr 1`] = `
 {
   "bodyStruct": {
     "hash": "761b7ad8ad439b2855fcbb611331c646ef0870b0631247bba3f3025cb6df5a53",
@@ -27,7 +27,7 @@ exports[`modules/platform/bitbucket/index findPr() finds pr 1`] = `
 }
 `;
 
-exports[`modules/platform/bitbucket/index getBranchPr() bitbucket finds PR for branch 1`] = `
+exports[`modules/platform/bitbucket/index > getBranchPr() > bitbucket finds PR for branch 1`] = `
 {
   "bodyStruct": {
     "hash": "761b7ad8ad439b2855fcbb611331c646ef0870b0631247bba3f3025cb6df5a53",
@@ -41,7 +41,7 @@ exports[`modules/platform/bitbucket/index getBranchPr() bitbucket finds PR for b
 }
 `;
 
-exports[`modules/platform/bitbucket/index getIssueList() get issues 1`] = `
+exports[`modules/platform/bitbucket/index > getIssueList() > get issues 1`] = `
 [
   {
     "content": {
@@ -60,7 +60,7 @@ exports[`modules/platform/bitbucket/index getIssueList() get issues 1`] = `
 ]
 `;
 
-exports[`modules/platform/bitbucket/index getPr() canRebase 1`] = `
+exports[`modules/platform/bitbucket/index > getPr() > canRebase 1`] = `
 {
   "bodyStruct": {
     "hash": "761b7ad8ad439b2855fcbb611331c646ef0870b0631247bba3f3025cb6df5a53",
@@ -74,7 +74,7 @@ exports[`modules/platform/bitbucket/index getPr() canRebase 1`] = `
 }
 `;
 
-exports[`modules/platform/bitbucket/index getPr() canRebase 2`] = `
+exports[`modules/platform/bitbucket/index > getPr() > canRebase 2`] = `
 {
   "bodyStruct": {
     "hash": "761b7ad8ad439b2855fcbb611331c646ef0870b0631247bba3f3025cb6df5a53",
@@ -88,7 +88,7 @@ exports[`modules/platform/bitbucket/index getPr() canRebase 2`] = `
 }
 `;
 
-exports[`modules/platform/bitbucket/index getPr() canRebase 3`] = `
+exports[`modules/platform/bitbucket/index > getPr() > canRebase 3`] = `
 {
   "bodyStruct": {
     "hash": "761b7ad8ad439b2855fcbb611331c646ef0870b0631247bba3f3025cb6df5a53",
@@ -102,7 +102,7 @@ exports[`modules/platform/bitbucket/index getPr() canRebase 3`] = `
 }
 `;
 
-exports[`modules/platform/bitbucket/index getPr() exists 1`] = `
+exports[`modules/platform/bitbucket/index > getPr() > exists 1`] = `
 {
   "bodyStruct": {
     "hash": "761b7ad8ad439b2855fcbb611331c646ef0870b0631247bba3f3025cb6df5a53",
@@ -116,7 +116,7 @@ exports[`modules/platform/bitbucket/index getPr() exists 1`] = `
 }
 `;
 
-exports[`modules/platform/bitbucket/index getPrList() filters PR list by author 1`] = `
+exports[`modules/platform/bitbucket/index > getPrList() > filters PR list by author 1`] = `
 [
   {
     "bodyStruct": {
@@ -132,7 +132,7 @@ exports[`modules/platform/bitbucket/index getPrList() filters PR list by author
 ]
 `;
 
-exports[`modules/platform/bitbucket/index massageMarkdown() returns diff files 1`] = `
+exports[`modules/platform/bitbucket/index > massageMarkdown() > returns diff files 1`] = `
 "**foo**
 
 
@@ -144,6 +144,6 @@ exports[`modules/platform/bitbucket/index massageMarkdown() returns diff files 1
 "
 `;
 
-exports[`modules/platform/bitbucket/index updatePr() rethrows exception when PR update error due to unknown reviewers error 1`] = `"Response code 400 (Bad Request)"`;
+exports[`modules/platform/bitbucket/index > updatePr() > rethrows exception when PR update error due to unknown reviewers error 1`] = `[HTTPError: Response code 400 (Bad Request)]`;
 
-exports[`modules/platform/bitbucket/index updatePr() throws an error on failure to get current list of reviewers 1`] = `"Response code 500 (Internal Server Error)"`;
+exports[`modules/platform/bitbucket/index > updatePr() > throws an error on failure to get current list of reviewers 1`] = `[HTTPError: Response code 500 (Internal Server Error)]`;
diff --git a/lib/modules/platform/bitbucket/index.spec.ts b/lib/modules/platform/bitbucket/index.spec.ts
index 379c5c2836..30192e85e7 100644
--- a/lib/modules/platform/bitbucket/index.spec.ts
+++ b/lib/modules/platform/bitbucket/index.spec.ts
@@ -6,8 +6,8 @@ import type { PlatformResult, RepoParams } from '../types';
 import type { PrTask } from './schema';
 import * as bitbucket from '.';
 
-jest.mock('../../../util/git');
-jest.mock('../../../util/host-rules');
+vi.mock('../../../util/git');
+vi.mock('../../../util/host-rules');
 
 const baseUrl = 'https://api.bitbucket.org';
 
@@ -1291,7 +1291,7 @@ describe('modules/platform/bitbucket/index', () => {
             bbUseDefaultReviewers: true,
           },
         }),
-      ).rejects.toThrow(new Error('Response code 401 (Unauthorized)'));
+      ).rejects.toThrow('Response code 401 (Unauthorized)');
     });
 
     it('removes reviewer if they are also the author of the pr', async () => {
@@ -1385,7 +1385,7 @@ describe('modules/platform/bitbucket/index', () => {
             bbUseDefaultReviewers: true,
           },
         }),
-      ).rejects.toThrow(new Error('Response code 400 (Bad Request)'));
+      ).rejects.toThrow('Response code 400 (Bad Request)');
     });
 
     it('rethrows exception when PR create error not due to reviewers field', async () => {
@@ -1424,7 +1424,7 @@ describe('modules/platform/bitbucket/index', () => {
             bbUseDefaultReviewers: true,
           },
         }),
-      ).rejects.toThrow(new Error('Response code 400 (Bad Request)'));
+      ).rejects.toThrow('Response code 400 (Bad Request)');
     });
 
     it('lists PR tasks and resolves the unresolved tasks', async () => {
@@ -1819,7 +1819,7 @@ describe('modules/platform/bitbucket/index', () => {
         .reply(401);
       await expect(() =>
         bitbucket.updatePr({ number: 5, prTitle: 'title', prBody: 'body' }),
-      ).rejects.toThrow(new Error('Response code 401 (Unauthorized)'));
+      ).rejects.toThrow('Response code 401 (Unauthorized)');
     });
 
     it('rethrows exception when PR update error due to unknown reviewers error', async () => {
@@ -1869,7 +1869,7 @@ describe('modules/platform/bitbucket/index', () => {
         });
       await expect(() =>
         bitbucket.updatePr({ number: 5, prTitle: 'title', prBody: 'body' }),
-      ).rejects.toThrow(new Error('Response code 400 (Bad Request)'));
+      ).rejects.toThrow('Response code 400 (Bad Request)');
     });
 
     it('throws an error on failure to get current list of reviewers', async () => {
diff --git a/lib/modules/platform/codecommit/index.spec.ts b/lib/modules/platform/codecommit/index.spec.ts
index 75ff969775..230ddea6e0 100644
--- a/lib/modules/platform/codecommit/index.spec.ts
+++ b/lib/modules/platform/codecommit/index.spec.ts
@@ -830,9 +830,9 @@ describe('modules/platform/codecommit/index', () => {
     });
   });
 
-  // eslint-disable-next-line jest/no-commented-out-tests
+  // eslint-disable-next-line vitest/no-commented-out-tests
   // describe('mergePr()', () => {
-  // eslint-disable-next-line jest/no-commented-out-tests
+  // eslint-disable-next-line vitest/no-commented-out-tests
   //   it('checks that rebase is not supported', async () => {
   //     expect(
   //       await codeCommit.mergePr({
@@ -843,7 +843,7 @@ describe('modules/platform/codecommit/index', () => {
   //     ).toBeFalse();
   //   });
 
-  // eslint-disable-next-line jest/no-commented-out-tests
+  // eslint-disable-next-line vitest/no-commented-out-tests
   //   it('posts Merge with auto', async () => {
   //     const prRes = {
   //       pullRequest: {
@@ -877,7 +877,7 @@ describe('modules/platform/codecommit/index', () => {
   //     ).toBeTrue();
   //   });
   //
-  // eslint-disable-next-line jest/no-commented-out-tests
+  // eslint-disable-next-line vitest/no-commented-out-tests
   //   it('posts Merge with squash', async () => {
   //     const prRes = {
   //       pullRequest: {
@@ -910,7 +910,7 @@ describe('modules/platform/codecommit/index', () => {
   //     ).toBeTrue();
   //   });
 
-  // eslint-disable-next-line jest/no-commented-out-tests
+  // eslint-disable-next-line vitest/no-commented-out-tests
   //   it('posts Merge with fast-forward', async () => {
   //     const prRes = {
   //       pullRequest: {
@@ -940,10 +940,10 @@ describe('modules/platform/codecommit/index', () => {
   //         id: 1,
   //         strategy: 'fast-forward',
   //       })
-  //     ).toBe(true);
+  //     ).toBeTrue();
   //   });
 
-  // eslint-disable-next-line jest/no-commented-out-tests
+  // eslint-disable-next-line vitest/no-commented-out-tests
   //   it('checks that merge-commit is not supported', async () => {
   //     const prRes = {
   //       pullRequest: {
@@ -1118,7 +1118,7 @@ describe('modules/platform/codecommit/index', () => {
       );
     });
 
-    it('throws an exception in case of api failed connection ', async () => {
+    it('throws an exception in case of api failed connection', async () => {
       const err = new Error('some error');
       codeCommitClient.on(GetCommentsForPullRequestCommand).rejectsOnce(err);
       const res = await codeCommit.ensureComment({
diff --git a/lib/modules/platform/comment.spec.ts b/lib/modules/platform/comment.spec.ts
index 54a7116b3a..4a76a288d9 100644
--- a/lib/modules/platform/comment.spec.ts
+++ b/lib/modules/platform/comment.spec.ts
@@ -3,8 +3,7 @@ import * as _cache from '../../util/cache/repository';
 import type { RepoCacheData } from '../../util/cache/repository/types';
 import { ensureComment, ensureCommentRemoval } from './comment';
 
-jest.mock('.');
-jest.mock('../../util/cache/repository');
+vi.mock('../../util/cache/repository');
 
 const cache = mocked(_cache);
 
diff --git a/lib/modules/platform/default-scm.spec.ts b/lib/modules/platform/default-scm.spec.ts
index 4b4c6360aa..3123e6de1d 100644
--- a/lib/modules/platform/default-scm.spec.ts
+++ b/lib/modules/platform/default-scm.spec.ts
@@ -2,7 +2,7 @@ import { git, partial } from '../../../test/util';
 import type { CommitFilesConfig, LongCommitSha } from '../../util/git/types';
 import { DefaultGitScm } from './default-scm';
 
-jest.mock('../../util/git');
+vi.mock('../../util/git');
 
 describe('modules/platform/default-scm', () => {
   const defaultGitScm = new DefaultGitScm();
diff --git a/lib/modules/platform/gerrit/index.spec.ts b/lib/modules/platform/gerrit/index.spec.ts
index 3b9c456f18..f9ccef2860 100644
--- a/lib/modules/platform/gerrit/index.spec.ts
+++ b/lib/modules/platform/gerrit/index.spec.ts
@@ -30,9 +30,9 @@ const codeReviewLabel: GerritLabelTypeInfo = {
   default_value: 0,
 };
 
-jest.mock('../../../util/host-rules');
-jest.mock('../../../util/git');
-jest.mock('./client');
+vi.mock('../../../util/host-rules');
+vi.mock('../../../util/git');
+vi.mock('./client');
 const clientMock = mocked(_client);
 const hostRules = mocked(_hostRules);
 
@@ -263,7 +263,7 @@ describe('modules/platform/gerrit/index', () => {
     });
   });
 
-  describe('createPr() - error ', () => {
+  describe('createPr() - error', () => {
     it('createPr() - no existing found => rejects', async () => {
       clientMock.findChanges.mockResolvedValueOnce([]);
       await expect(
@@ -485,7 +485,7 @@ describe('modules/platform/gerrit/index', () => {
         'unknownCtx',
         'renovate/stability-days',
         'renovate/merge-confidence',
-      ])('getBranchStatusCheck() - %s ', async (ctx) => {
+      ])('getBranchStatusCheck() - %s', async (ctx) => {
         await expect(
           gerrit.getBranchStatusCheck('renovate/dependency-1.x', ctx),
         ).resolves.toBe('yellow');
diff --git a/lib/modules/platform/gerrit/scm.spec.ts b/lib/modules/platform/gerrit/scm.spec.ts
index b826610149..b033e1eb05 100644
--- a/lib/modules/platform/gerrit/scm.spec.ts
+++ b/lib/modules/platform/gerrit/scm.spec.ts
@@ -8,8 +8,8 @@ import type {
   GerritRevisionInfo,
 } from './types';
 
-jest.mock('../../../util/git');
-jest.mock('./client');
+vi.mock('../../../util/git');
+vi.mock('./client');
 const clientMock = mocked(_client);
 
 describe('modules/platform/gerrit/scm', () => {
@@ -36,7 +36,7 @@ describe('modules/platform/gerrit/scm', () => {
       );
     });
 
-    it('open change found for branchname, rebase action is available -> isBehind == true ', async () => {
+    it('open change found for branchname, rebase action is available -> isBehind == true', async () => {
       const change = partial<GerritChange>({
         current_revision: 'currentRevSha',
         revisions: {
@@ -55,7 +55,7 @@ describe('modules/platform/gerrit/scm', () => {
       ).resolves.toBeTrue();
     });
 
-    it('open change found for branch name, but rebase action is not available -> isBehind == false ', async () => {
+    it('open change found for branch name, but rebase action is not available -> isBehind == false', async () => {
       const change = partial<GerritChange>({
         current_revision: 'currentRevSha',
         revisions: {
diff --git a/lib/modules/platform/gerrit/utils.spec.ts b/lib/modules/platform/gerrit/utils.spec.ts
index b609fdf7a8..6739afb4d3 100644
--- a/lib/modules/platform/gerrit/utils.spec.ts
+++ b/lib/modules/platform/gerrit/utils.spec.ts
@@ -15,7 +15,7 @@ import type {
 import * as utils from './utils';
 import { mapBranchStatusToLabel } from './utils';
 
-jest.mock('../../../util/host-rules');
+vi.mock('../../../util/host-rules');
 
 const baseUrl = 'https://gerrit.example.com';
 const hostRules = mocked(_hostRules);
diff --git a/lib/modules/platform/gitea/index.spec.ts b/lib/modules/platform/gitea/index.spec.ts
index a107b79475..c5c95e15c6 100644
--- a/lib/modules/platform/gitea/index.spec.ts
+++ b/lib/modules/platform/gitea/index.spec.ts
@@ -28,7 +28,7 @@ import type {
 } from './types';
 import * as gitea from '.';
 
-jest.mock('../../../util/git');
+vi.mock('../../../util/git');
 
 /**
  * latest tested gitea version.
diff --git a/lib/modules/platform/github/__snapshots__/index.spec.ts.snap b/lib/modules/platform/github/__snapshots__/index.spec.ts.snap
index fbd183bcf6..5a93d93251 100644
--- a/lib/modules/platform/github/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/platform/github/__snapshots__/index.spec.ts.snap
@@ -1,15 +1,15 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/platform/github/index getBranchForceRebase should throw 401 1`] = `"Response code 401 (Unauthorized)"`;
+exports[`modules/platform/github/index > getBranchForceRebase > should throw 401 1`] = `[HTTPError: Response code 401 (Unauthorized)]`;
 
-exports[`modules/platform/github/index getRepos should return an array of repos 1`] = `
+exports[`modules/platform/github/index > getRepos > should return an array of repos 1`] = `
 [
   "a/b",
   "c/d",
 ]
 `;
 
-exports[`modules/platform/github/index initPlatform() should support custom endpoint 1`] = `
+exports[`modules/platform/github/index > initPlatform() > should support custom endpoint 1`] = `
 {
   "endpoint": "https://ghe.renovatebot.com/",
   "gitAuthor": "undefined <user@domain.com>",
@@ -18,7 +18,7 @@ exports[`modules/platform/github/index initPlatform() should support custom endp
 }
 `;
 
-exports[`modules/platform/github/index initPlatform() should support custom endpoint without version 1`] = `
+exports[`modules/platform/github/index > initPlatform() > should support custom endpoint without version 1`] = `
 {
   "endpoint": "https://ghe.renovatebot.com/",
   "gitAuthor": "undefined <user@domain.com>",
@@ -27,7 +27,7 @@ exports[`modules/platform/github/index initPlatform() should support custom endp
 }
 `;
 
-exports[`modules/platform/github/index initPlatform() should support default endpoint no email access 1`] = `
+exports[`modules/platform/github/index > initPlatform() > should support default endpoint no email access 1`] = `
 {
   "endpoint": "https://api.github.com/",
   "gitAuthor": undefined,
@@ -36,7 +36,7 @@ exports[`modules/platform/github/index initPlatform() should support default end
 }
 `;
 
-exports[`modules/platform/github/index initPlatform() should support default endpoint no email result 1`] = `
+exports[`modules/platform/github/index > initPlatform() > should support default endpoint no email result 1`] = `
 {
   "endpoint": "https://api.github.com/",
   "gitAuthor": undefined,
@@ -45,7 +45,7 @@ exports[`modules/platform/github/index initPlatform() should support default end
 }
 `;
 
-exports[`modules/platform/github/index initPlatform() should support default endpoint with email 1`] = `
+exports[`modules/platform/github/index > initPlatform() > should support default endpoint with email 1`] = `
 {
   "endpoint": "https://api.github.com/",
   "gitAuthor": "undefined <user@domain.com>",
@@ -54,7 +54,7 @@ exports[`modules/platform/github/index initPlatform() should support default end
 }
 `;
 
-exports[`modules/platform/github/index initPlatform() should support gitAuthor and username 1`] = `
+exports[`modules/platform/github/index > initPlatform() > should support gitAuthor and username 1`] = `
 {
   "endpoint": "https://api.github.com/",
   "gitAuthor": "renovate@whitesourcesoftware.com",
@@ -63,7 +63,7 @@ exports[`modules/platform/github/index initPlatform() should support gitAuthor a
 }
 `;
 
-exports[`modules/platform/github/index initRepo detects fork default branch mismatch 1`] = `
+exports[`modules/platform/github/index > initRepo > detects fork default branch mismatch 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -71,7 +71,7 @@ exports[`modules/platform/github/index initRepo detects fork default branch mism
 }
 `;
 
-exports[`modules/platform/github/index initRepo should fork when using forkToken 1`] = `
+exports[`modules/platform/github/index > initRepo > should fork when using forkToken 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -79,7 +79,7 @@ exports[`modules/platform/github/index initRepo should fork when using forkToken
 }
 `;
 
-exports[`modules/platform/github/index initRepo should merge 1`] = `
+exports[`modules/platform/github/index > initRepo > should merge 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -87,7 +87,7 @@ exports[`modules/platform/github/index initRepo should merge 1`] = `
 }
 `;
 
-exports[`modules/platform/github/index initRepo should not guess at merge 1`] = `
+exports[`modules/platform/github/index > initRepo > should not guess at merge 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -95,7 +95,7 @@ exports[`modules/platform/github/index initRepo should not guess at merge 1`] =
 }
 `;
 
-exports[`modules/platform/github/index initRepo should rebase 1`] = `
+exports[`modules/platform/github/index > initRepo > should rebase 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -103,7 +103,7 @@ exports[`modules/platform/github/index initRepo should rebase 1`] = `
 }
 `;
 
-exports[`modules/platform/github/index initRepo should squash 1`] = `
+exports[`modules/platform/github/index > initRepo > should squash 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -111,7 +111,7 @@ exports[`modules/platform/github/index initRepo should squash 1`] = `
 }
 `;
 
-exports[`modules/platform/github/index initRepo should update fork when using forkToken and forkOrg 1`] = `
+exports[`modules/platform/github/index > initRepo > should update fork when using forkToken and forkOrg 1`] = `
 {
   "defaultBranch": "master",
   "isFork": false,
@@ -119,4 +119,4 @@ exports[`modules/platform/github/index initRepo should update fork when using fo
 }
 `;
 
-exports[`modules/platform/github/index massageMarkdown(input) returns updated pr body 1`] = `"[https://github.com/foo/bar/issues/5](https://redirect.github.com/foo/bar/issues/5) plus also [a link](https://redirect.github.com/foo/bar/issues/5)"`;
+exports[`modules/platform/github/index > massageMarkdown(input) > returns updated pr body 1`] = `"[https://github.com/foo/bar/issues/5](https://redirect.github.com/foo/bar/issues/5) plus also [a link](https://redirect.github.com/foo/bar/issues/5)"`;
diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts
index 9eaf850b78..32f56d291f 100644
--- a/lib/modules/platform/github/index.spec.ts
+++ b/lib/modules/platform/github/index.spec.ts
@@ -1,7 +1,8 @@
+import { RequestError } from 'got';
 import { mockDeep } from 'jest-mock-extended';
 import { DateTime } from 'luxon';
 import * as httpMock from '../../../../test/http-mock';
-import { logger, mocked } from '../../../../test/util';
+import { logger } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
 import {
   PLATFORM_RATE_LIMIT_EXCEEDED,
@@ -12,6 +13,7 @@ import {
   REPOSITORY_NOT_FOUND,
   REPOSITORY_RENAMED,
 } from '../../../constants/error-messages';
+import { ExternalHostError } from '../../../types/errors/external-host-error';
 import * as repository from '../../../util/cache/repository';
 import * as _git from '../../../util/git';
 import type { LongCommitSha } from '../../../util/git/types';
@@ -30,14 +32,14 @@ import * as github from '.';
 
 const githubApiHost = 'https://api.github.com';
 
-jest.mock('timers/promises');
+vi.mock('timers/promises');
 
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('../../../util/http/queue');
-const hostRules: jest.Mocked<typeof _hostRules> = mocked(_hostRules);
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/http/queue');
+const hostRules = vi.mocked(_hostRules);
 
-jest.mock('../../../util/git');
-const git: jest.Mocked<typeof _git> = mocked(_git);
+vi.mock('../../../util/git');
+const git = vi.mocked(_git);
 
 describe('modules/platform/github/index', () => {
   beforeEach(() => {
@@ -65,7 +67,7 @@ describe('modules/platform/github/index', () => {
       );
     });
 
-    it('should throw if using fine-grained token with GHE <3.10 ', async () => {
+    it('should throw if using fine-grained token with GHE <3.10', async () => {
       httpMock
         .scope('https://ghe.renovatebot.com')
         .head('/')
@@ -80,7 +82,7 @@ describe('modules/platform/github/index', () => {
       );
     });
 
-    it('should throw if using fine-grained token with GHE unknown version ', async () => {
+    it('should throw if using fine-grained token with GHE unknown version', async () => {
       httpMock.scope('https://ghe.renovatebot.com').head('/').reply(200);
       await expect(
         github.initPlatform({
@@ -3561,7 +3563,7 @@ describe('modules/platform/github/index', () => {
       await expect(github.reattemptPlatformAutomerge(pr)).toResolve();
 
       expect(logger.logger.warn).toHaveBeenCalledWith(
-        { err: new Error('external-host-error') },
+        { err: new ExternalHostError(expect.any(RequestError), 'github') },
         'Error re-attempting PR platform automerge',
       );
     });
diff --git a/lib/modules/platform/github/scm.spec.ts b/lib/modules/platform/github/scm.spec.ts
index 7e25cde834..7a5f4ad3d1 100644
--- a/lib/modules/platform/github/scm.spec.ts
+++ b/lib/modules/platform/github/scm.spec.ts
@@ -3,7 +3,7 @@ import type { CommitFilesConfig, LongCommitSha } from '../../../util/git/types';
 import { GithubScm } from './scm';
 import * as _github from '.';
 
-jest.mock('.');
+vi.mock('.');
 const github = mocked(_github);
 
 describe('modules/platform/github/scm', () => {
diff --git a/lib/modules/platform/gitlab/__snapshots__/index.spec.ts.snap b/lib/modules/platform/gitlab/__snapshots__/index.spec.ts.snap
index 2ab3cf9572..fd38501389 100644
--- a/lib/modules/platform/gitlab/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/platform/gitlab/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/platform/gitlab/index getBranchPr(branchName) should return the PR object 1`] = `
+exports[`modules/platform/gitlab/index > getBranchPr(branchName) > should return the PR object 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -14,7 +14,7 @@ exports[`modules/platform/gitlab/index getBranchPr(branchName) should return the
 }
 `;
 
-exports[`modules/platform/gitlab/index getBranchPr(branchName) should strip deprecated draft prefix from title 1`] = `
+exports[`modules/platform/gitlab/index > getBranchPr(branchName) > should strip deprecated draft prefix from title 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -29,7 +29,7 @@ exports[`modules/platform/gitlab/index getBranchPr(branchName) should strip depr
 }
 `;
 
-exports[`modules/platform/gitlab/index getBranchPr(branchName) should strip draft prefix from title 1`] = `
+exports[`modules/platform/gitlab/index > getBranchPr(branchName) > should strip draft prefix from title 1`] = `
 {
   "bodyStruct": {
     "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@@ -44,7 +44,7 @@ exports[`modules/platform/gitlab/index getBranchPr(branchName) should strip draf
 }
 `;
 
-exports[`modules/platform/gitlab/index getPr(prNo) removes deprecated draft prefix from returned title 1`] = `
+exports[`modules/platform/gitlab/index > getPr(prNo) > removes deprecated draft prefix from returned title 1`] = `
 {
   "bodyStruct": {
     "hash": "23f41dbec0785a6c77457dd6ebf99ae5970c5fffc9f7a8ad7f66c1b8eeba5b90",
@@ -59,7 +59,7 @@ exports[`modules/platform/gitlab/index getPr(prNo) removes deprecated draft pref
 }
 `;
 
-exports[`modules/platform/gitlab/index getPr(prNo) removes draft prefix from returned title 1`] = `
+exports[`modules/platform/gitlab/index > getPr(prNo) > removes draft prefix from returned title 1`] = `
 {
   "bodyStruct": {
     "hash": "23f41dbec0785a6c77457dd6ebf99ae5970c5fffc9f7a8ad7f66c1b8eeba5b90",
@@ -74,7 +74,7 @@ exports[`modules/platform/gitlab/index getPr(prNo) removes draft prefix from ret
 }
 `;
 
-exports[`modules/platform/gitlab/index getPr(prNo) returns the PR 1`] = `
+exports[`modules/platform/gitlab/index > getPr(prNo) > returns the PR 1`] = `
 {
   "bodyStruct": {
     "hash": "23f41dbec0785a6c77457dd6ebf99ae5970c5fffc9f7a8ad7f66c1b8eeba5b90",
@@ -88,7 +88,7 @@ exports[`modules/platform/gitlab/index getPr(prNo) returns the PR 1`] = `
 }
 `;
 
-exports[`modules/platform/gitlab/index getPr(prNo) returns the PR with nonexisting branch 1`] = `
+exports[`modules/platform/gitlab/index > getPr(prNo) > returns the PR with nonexisting branch 1`] = `
 {
   "bodyStruct": {
     "hash": "23f41dbec0785a6c77457dd6ebf99ae5970c5fffc9f7a8ad7f66c1b8eeba5b90",
@@ -102,7 +102,7 @@ exports[`modules/platform/gitlab/index getPr(prNo) returns the PR with nonexisti
 }
 `;
 
-exports[`modules/platform/gitlab/index getPr(prNo) returns the mergeable PR 1`] = `
+exports[`modules/platform/gitlab/index > getPr(prNo) > returns the mergeable PR 1`] = `
 {
   "bodyStruct": {
     "hash": "23f41dbec0785a6c77457dd6ebf99ae5970c5fffc9f7a8ad7f66c1b8eeba5b90",
@@ -116,21 +116,21 @@ exports[`modules/platform/gitlab/index getPr(prNo) returns the mergeable PR 1`]
 }
 `;
 
-exports[`modules/platform/gitlab/index initPlatform() should accept custom endpoint 1`] = `
+exports[`modules/platform/gitlab/index > initPlatform() > should accept custom endpoint 1`] = `
 {
   "endpoint": "https://gitlab.renovatebot.com/",
   "gitAuthor": "Renovate Bot <a@b.com>",
 }
 `;
 
-exports[`modules/platform/gitlab/index initPlatform() should default to gitlab.com 1`] = `
+exports[`modules/platform/gitlab/index > initPlatform() > should default to gitlab.com 1`] = `
 {
   "endpoint": "https://gitlab.com/api/v4/",
   "gitAuthor": "Renovate Bot <a@b.com>",
 }
 `;
 
-exports[`modules/platform/gitlab/index initRepo should fall back respecting when GITLAB_IGNORE_REPO_URL is set 1`] = `
+exports[`modules/platform/gitlab/index > initRepo > should fall back respecting when GITLAB_IGNORE_REPO_URL is set 1`] = `
 [
   [
     {
@@ -146,7 +146,7 @@ exports[`modules/platform/gitlab/index initRepo should fall back respecting when
 ]
 `;
 
-exports[`modules/platform/gitlab/index initRepo should use ssh_url_to_repo if gitUrl is set to ssh 1`] = `
+exports[`modules/platform/gitlab/index > initRepo > should use ssh_url_to_repo if gitUrl is set to ssh 1`] = `
 [
   [
     {
@@ -162,7 +162,7 @@ exports[`modules/platform/gitlab/index initRepo should use ssh_url_to_repo if gi
 ]
 `;
 
-exports[`modules/platform/gitlab/index massageMarkdown(input) returns updated pr body 1`] = `
+exports[`modules/platform/gitlab/index > massageMarkdown(input) > returns updated pr body 1`] = `
 "https://github.com/foo/bar/issues/5 plus also [a link](https://github.com/foo/bar/issues/5
 
   Merge Requests are the best, here are some MRs.
diff --git a/lib/modules/platform/gitlab/index.spec.ts b/lib/modules/platform/gitlab/index.spec.ts
index acb602fbf8..2c3d38398d 100644
--- a/lib/modules/platform/gitlab/index.spec.ts
+++ b/lib/modules/platform/gitlab/index.spec.ts
@@ -19,9 +19,10 @@ import { getPrBodyStruct } from '../pr-body';
 import * as prBodyModule from '../utils/pr-body';
 import * as gitlab from '.';
 
-jest.mock('../../../util/host-rules', () => mockDeep());
-jest.mock('../../../util/git');
-jest.mock('timers/promises');
+vi.mock('../../../util/host-rules', () => mockDeep());
+vi.mock('../../../util/git', () => mockDeep());
+vi.mock('timers/promises');
+vi.mock('../utils/pr-body', { spy: true });
 
 const timers = mocked(_timers);
 
@@ -3425,30 +3426,29 @@ These updates have all been created already. Click a checkbox below to force a r
     });
 
     it('returns updated pr body', async () => {
-      jest.doMock('../utils/pr-body');
-      const { smartTruncate } = await import('../utils/pr-body');
-
       await initFakePlatform('13.4.0');
       expect(gitlab.massageMarkdown(prBody)).toMatchSnapshot();
-      expect(smartTruncate).not.toHaveBeenCalled();
+      expect(prBodyModule.smartTruncate).toHaveBeenCalledOnce();
     });
 
     it('truncates description if too low API version', async () => {
-      const smartTruncate = jest.spyOn(prBodyModule, 'smartTruncate');
-
       await initFakePlatform('13.3.0');
       gitlab.massageMarkdown(prBody);
-      expect(smartTruncate).toHaveBeenCalledTimes(1);
-      expect(smartTruncate).toHaveBeenCalledWith(expect.any(String), 25000);
+      expect(prBodyModule.smartTruncate).toHaveBeenCalledTimes(1);
+      expect(prBodyModule.smartTruncate).toHaveBeenCalledWith(
+        expect.any(String),
+        25000,
+      );
     });
 
     it('truncates description for API version gt 13.4', async () => {
-      const smartTruncate = jest.spyOn(prBodyModule, 'smartTruncate');
-
       await initFakePlatform('13.4.1');
       gitlab.massageMarkdown(prBody);
-      expect(smartTruncate).toHaveBeenCalledTimes(1);
-      expect(smartTruncate).toHaveBeenCalledWith(expect.any(String), 1000000);
+      expect(prBodyModule.smartTruncate).toHaveBeenCalledTimes(1);
+      expect(prBodyModule.smartTruncate).toHaveBeenCalledWith(
+        expect.any(String),
+        1000000,
+      );
     });
   });
 
diff --git a/lib/modules/platform/index.spec.ts b/lib/modules/platform/index.spec.ts
index 03655d0c81..5fca3c99eb 100644
--- a/lib/modules/platform/index.spec.ts
+++ b/lib/modules/platform/index.spec.ts
@@ -6,16 +6,15 @@ import api from './api';
 import type { Platform } from './types';
 import * as platform from '.';
 
-jest.unmock('.');
-jest.unmock('./scm');
+vi.unmock('.');
+vi.unmock('./scm');
 
 describe('modules/platform/index', () => {
   beforeEach(() => {
-    jest.resetModules();
     process.env.RENOVATE_X_GITHUB_HOST_RULES = 'true';
   });
 
-  it('validates', () => {
+  it('validates', async () => {
     function validate(module: Platform | undefined, name: string): boolean {
       // TODO: test required api (#9650)
       if (!module?.initPlatform) {
@@ -25,7 +24,7 @@ describe('modules/platform/index', () => {
     }
     const platforms = api;
 
-    const loadedMgr = loadModules(
+    const loadedMgr = await loadModules(
       __dirname,
       undefined,
       (m) => !['utils', 'git'].includes(m),
diff --git a/lib/modules/platform/local/scm.spec.ts b/lib/modules/platform/local/scm.spec.ts
index e96eee93fe..ec32ddc67d 100644
--- a/lib/modules/platform/local/scm.spec.ts
+++ b/lib/modules/platform/local/scm.spec.ts
@@ -2,10 +2,10 @@ import { execSync as _execSync } from 'node:child_process';
 import { mockedFunction } from '../../../../test/util';
 import { LocalFs } from './scm';
 
-jest.mock('glob', () => ({
-  glob: jest.fn().mockImplementation(() => Promise.resolve(['file1', 'file2'])),
+vi.mock('glob', () => ({
+  glob: vi.fn().mockImplementation(() => Promise.resolve(['file1', 'file2'])),
 }));
-jest.mock('node:child_process');
+vi.mock('node:child_process');
 const execSync = mockedFunction(_execSync);
 
 describe('modules/platform/local/scm', () => {
diff --git a/lib/modules/platform/scm.spec.ts b/lib/modules/platform/scm.spec.ts
index 0d9ad3af4b..0d98857bc5 100644
--- a/lib/modules/platform/scm.spec.ts
+++ b/lib/modules/platform/scm.spec.ts
@@ -3,8 +3,8 @@ import type { PlatformId } from '../../constants';
 import { PLATFORM_NOT_FOUND } from '../../constants/error-messages';
 import { scm, setPlatformScmApi } from './scm';
 
-jest.mock('../../util/git');
-jest.unmock('./scm'); //mocked from test/setup
+vi.mock('../../util/git');
+vi.unmock('./scm'); //mocked from test/setup
 
 describe('modules/platform/scm', () => {
   it('no platform chosen', () => {
diff --git a/lib/modules/platform/utils/__snapshots__/pr-body.spec.ts.snap b/lib/modules/platform/utils/__snapshots__/pr-body.spec.ts.snap
index 4b6abce102..d0e1726ddb 100644
--- a/lib/modules/platform/utils/__snapshots__/pr-body.spec.ts.snap
+++ b/lib/modules/platform/utils/__snapshots__/pr-body.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`modules/platform/utils/pr-body .smartTruncate truncates to 300 not smart 1`] = `
+exports[`modules/platform/utils/pr-body > .smartTruncate > truncates to 300 not smart 1`] = `
 "This PR contains the following updates:
 
 | Package | Type | Update | Change |
@@ -17,7 +17,7 @@ exports[`modules/platform/utils/pr-body .smartTruncate truncates to 300 not smar
 ### [\`v19."
 `;
 
-exports[`modules/platform/utils/pr-body .smartTruncate truncates to 1000 1`] = `
+exports[`modules/platform/utils/pr-body > .smartTruncate > truncates to 1000 1`] = `
 "This PR contains the following updates:
 
 | Package | Type | Update | Change |
diff --git a/lib/modules/versioning/composer/index.spec.ts b/lib/modules/versioning/composer/index.spec.ts
index 56feb52346..714a46ff13 100644
--- a/lib/modules/versioning/composer/index.spec.ts
+++ b/lib/modules/versioning/composer/index.spec.ts
@@ -239,7 +239,7 @@ describe('modules/versioning/composer/index', () => {
     ${['1.2.3-p1', '1.2.3-p2', '1.2.3']}                                          | ${['1.2.3', '1.2.3-p1', '1.2.3-p2']}
     ${['1.2.3-p1', '1.2.2']}                                                      | ${['1.2.2', '1.2.3-p1']}
     ${['1.0-p1', '1']}                                                            | ${['1', '1.0-p1']}
-  `('$versions -> sortVersions -> $expected ', ({ versions, expected }) => {
+  `('$versions -> sortVersions -> $expected', ({ versions, expected }) => {
     expect(versions.sort(semver.sortVersions)).toEqual(expected);
   });
 
diff --git a/lib/modules/versioning/debian/index.spec.ts b/lib/modules/versioning/debian/index.spec.ts
index 4c86f3d4d4..68fd232f1c 100644
--- a/lib/modules/versioning/debian/index.spec.ts
+++ b/lib/modules/versioning/debian/index.spec.ts
@@ -406,7 +406,7 @@ describe('modules/versioning/debian/index', () => {
     ${'12'}           | ${'oldoldstable'} | ${2}
     ${'11'}           | ${'oldstable'}    | ${0}
     ${'10'}           | ${'stable'}       | ${-2}
-  `('debian.sortVersions($a, $b) === $expected ', ({ a, b, expected }) => {
+  `('debian.sortVersions($a, $b) === $expected', ({ a, b, expected }) => {
     expect(debian.sortVersions(a, b)).toEqual(expected);
   });
 
diff --git a/lib/modules/versioning/index.spec.ts b/lib/modules/versioning/index.spec.ts
index 3de40de933..73d3b7c57b 100644
--- a/lib/modules/versioning/index.spec.ts
+++ b/lib/modules/versioning/index.spec.ts
@@ -34,7 +34,7 @@ describe('modules/versioning/index', () => {
     ]);
   });
 
-  it('validates', () => {
+  it('validates', async () => {
     function validate(
       module: VersioningApi | VersioningApiConstructor,
       name: string,
@@ -50,7 +50,7 @@ describe('modules/versioning/index', () => {
     }
     const vers = allVersioning.getVersionings();
 
-    const loadedVers = loadModules(__dirname);
+    const loadedVers = await loadModules(__dirname);
     expect(Array.from(vers.keys())).toEqual(Object.keys(loadedVers));
 
     for (const name of vers.keys()) {
@@ -108,6 +108,7 @@ describe('modules/versioning/index', () => {
     }
 
     for (const supportedScheme of supportedSchemes ?? []) {
+      // eslint-disable-next-line vitest/valid-title
       it(supportedScheme, async () => {
         const schemeKeys = getAllPropertyNames(
           allVersioning.get(supportedScheme),
@@ -119,7 +120,7 @@ describe('modules/versioning/index', () => {
 
         expect(schemeKeys).toEqual(npmApi);
 
-        const apiOrCtor = (await import(`./${supportedScheme}`)).api;
+        const apiOrCtor = (await import(`./${supportedScheme}/index.ts`)).api;
         if (isVersioningApiConstructor(apiOrCtor)) {
           return;
         }
diff --git a/lib/modules/versioning/nixpkgs/index.spec.ts b/lib/modules/versioning/nixpkgs/index.spec.ts
index 5686533558..0a8ee76636 100644
--- a/lib/modules/versioning/nixpkgs/index.spec.ts
+++ b/lib/modules/versioning/nixpkgs/index.spec.ts
@@ -61,7 +61,7 @@ describe('modules/versioning/nixpkgs/index', () => {
     versions                                                                                         | expected
     ${['nixos-21.11', 'nixos-22.05', 'nixos-22.05-small', 'nixos-unstable', 'nixos-unstable-small']} | ${['nixos-21.11', 'nixos-22.05', 'nixos-22.05-small', 'nixos-unstable', 'nixos-unstable-small']}
   `(
-    '$versions -> sortVersions -> $expected ',
+    '$versions -> sortVersions -> $expected',
     ({ versions, expected }: { versions: string[]; expected: string[] }) => {
       expect(versions.sort((a, b) => versioning.sortVersions(a, b))).toEqual(
         expected,
diff --git a/lib/modules/versioning/ruby/index.spec.ts b/lib/modules/versioning/ruby/index.spec.ts
index ea1d697824..f5e4946f9b 100644
--- a/lib/modules/versioning/ruby/index.spec.ts
+++ b/lib/modules/versioning/ruby/index.spec.ts
@@ -113,7 +113,7 @@ describe('modules/versioning/ruby/index', () => {
   it.each`
     versions                                     | expected
     ${['1.2.3-beta', '2.0.1', '1.3.4', '1.2.3']} | ${['1.2.3-beta', '1.2.3', '1.3.4', '2.0.1']}
-  `('$versions -> sortVersions -> $expected ', ({ versions, expected }) => {
+  `('$versions -> sortVersions -> $expected', ({ versions, expected }) => {
     expect(versions.sort(semverRuby.sortVersions)).toEqual(expected);
   });
 
diff --git a/lib/modules/versioning/ubuntu/index.spec.ts b/lib/modules/versioning/ubuntu/index.spec.ts
index 5a60006fa9..48faf61c96 100644
--- a/lib/modules/versioning/ubuntu/index.spec.ts
+++ b/lib/modules/versioning/ubuntu/index.spec.ts
@@ -396,7 +396,7 @@ describe('modules/versioning/ubuntu/index', () => {
     versions                                                  | expected
     ${['17.03', '18.04', '18.04', '6.10', '19.10']}           | ${['6.10', '17.03', '18.04', '18.04', '19.10']}
     ${['17.03', 'zesty', 'bionic', 'bionic', 'edgy', 'eoan']} | ${['edgy', '17.03', 'zesty', 'bionic', 'bionic', 'eoan']}
-  `('$versions -> sortVersions -> $expected ', ({ versions, expected }) => {
+  `('$versions -> sortVersions -> $expected', ({ versions, expected }) => {
     expect(versions.sort(ubuntu.sortVersions)).toEqual(expected);
   });
 
diff --git a/lib/modules/versioning/versioning-metadata.spec.ts b/lib/modules/versioning/versioning-metadata.spec.ts
index e7cd9705ec..f1661e4b68 100644
--- a/lib/modules/versioning/versioning-metadata.spec.ts
+++ b/lib/modules/versioning/versioning-metadata.spec.ts
@@ -37,13 +37,12 @@ describe('modules/versioning/versioning-metadata', () => {
     });
 
     it('contains mandatory fields', async () => {
-      const versioningObj = await import(`./${versioning}`);
+      const versioningObj = await import(`./${versioning}/index.ts`);
       expect(versioningObj.id).toEqual(versioning);
       expect(versioningObj.displayName).toBeDefined();
       expect(versioningObj.urls).toBeArray();
       expect(versioningObj.supportsRanges).toBeBoolean();
       if (versioningObj.supportsRanges === true) {
-        // eslint-disable-next-line jest/no-conditional-expect
         expect(versioningObj.supportedRangeStrategies).toBeArrayOfStrings();
       }
     });
diff --git a/lib/util/cache/package/decorator.spec.ts b/lib/util/cache/package/decorator.spec.ts
index 283ea5a36d..101bcdd7a8 100644
--- a/lib/util/cache/package/decorator.spec.ts
+++ b/lib/util/cache/package/decorator.spec.ts
@@ -4,7 +4,7 @@ import { cache } from './decorator';
 import * as file from './file';
 import * as packageCache from '.';
 
-jest.mock('./file');
+vi.mock('./file');
 
 describe('util/cache/package/decorator', () => {
   const setCache = file.set;
diff --git a/lib/util/cache/package/index.spec.ts b/lib/util/cache/package/index.spec.ts
index b4cb217c4e..61b06b199d 100644
--- a/lib/util/cache/package/index.spec.ts
+++ b/lib/util/cache/package/index.spec.ts
@@ -1,8 +1,8 @@
 import { cleanup, get, init, set } from '.';
 
-jest.mock('./file');
-jest.mock('./redis');
-jest.mock('./sqlite');
+vi.mock('./file');
+vi.mock('./redis');
+vi.mock('./sqlite');
 
 describe('util/cache/package/index', () => {
   beforeEach(() => {
diff --git a/lib/util/cache/repository/impl/local.spec.ts b/lib/util/cache/repository/impl/local.spec.ts
index fb30643011..54d8fbc593 100644
--- a/lib/util/cache/repository/impl/local.spec.ts
+++ b/lib/util/cache/repository/impl/local.spec.ts
@@ -9,7 +9,7 @@ import type { RepoCacheData } from '../types';
 import { CacheFactory } from './cache-factory';
 import { RepoCacheLocal } from './local';
 
-jest.mock('../../../fs');
+vi.mock('../../../fs');
 
 async function createCacheRecord(
   data: RepoCacheData,
diff --git a/lib/util/cache/repository/impl/s3.spec.ts b/lib/util/cache/repository/impl/s3.spec.ts
index f461b5e6ee..dbf34365a0 100644
--- a/lib/util/cache/repository/impl/s3.spec.ts
+++ b/lib/util/cache/repository/impl/s3.spec.ts
@@ -18,7 +18,7 @@ import type { RepoCacheRecord } from '../schema';
 import { CacheFactory } from './cache-factory';
 import { RepoCacheS3 } from './s3';
 
-jest.mock('../../../fs');
+vi.mock('../../../fs');
 
 function createGetObjectCommandInput(
   repository: string,
diff --git a/lib/util/cache/repository/index.spec.ts b/lib/util/cache/repository/index.spec.ts
index b8158d58d9..70369220a7 100644
--- a/lib/util/cache/repository/index.spec.ts
+++ b/lib/util/cache/repository/index.spec.ts
@@ -6,7 +6,7 @@ import { initRepoCache } from './init';
 import type { RepoCacheConfig } from './types';
 import { getCache, isCacheModified, resetCache, saveCache } from '.';
 
-jest.mock('../../fs');
+vi.mock('../../fs');
 
 const fs = mocked(_fs);
 
diff --git a/lib/util/check-token.spec.ts b/lib/util/check-token.spec.ts
index 34b596aa99..c25b003f41 100644
--- a/lib/util/check-token.spec.ts
+++ b/lib/util/check-token.spec.ts
@@ -1,4 +1,4 @@
-import { mockDeep } from 'jest-mock-extended';
+import { mockDeep } from 'vitest-mock-extended';
 import { hostRules, logger } from '../../test/util';
 import { GlobalConfig } from '../config/global';
 import { GithubReleasesDatasource } from '../modules/datasource/github-releases';
@@ -14,7 +14,7 @@ import {
   takePersonalAccessTokenIfPossible,
 } from './check-token';
 
-jest.mock('./host-rules', () => mockDeep());
+vi.mock('./host-rules', () => mockDeep());
 
 describe('util/check-token', () => {
   describe('checkGithubToken', () => {
diff --git a/lib/util/exec/common.spec.ts b/lib/util/exec/common.spec.ts
index f8a9a1b8bd..fc880c675e 100644
--- a/lib/util/exec/common.spec.ts
+++ b/lib/util/exec/common.spec.ts
@@ -5,7 +5,7 @@ import { mockedFunction, partial } from '../../../test/util';
 import { exec } from './common';
 import type { DataListener, RawExecOptions } from './types';
 
-jest.mock('node:child_process');
+vi.mock('node:child_process');
 const spawn = mockedFunction(_spawn);
 
 type MessageListener = (message: Serializable, sendHandle: SendHandle) => void;
diff --git a/lib/util/exec/containerbase.spec.ts b/lib/util/exec/containerbase.spec.ts
index f8b7ec8293..e3a9b6fb04 100644
--- a/lib/util/exec/containerbase.spec.ts
+++ b/lib/util/exec/containerbase.spec.ts
@@ -8,7 +8,7 @@ import {
 } from './containerbase';
 import type { ToolConstraint } from './types';
 
-jest.mock('../../modules/datasource');
+vi.mock('../../modules/datasource');
 
 const datasource = mocked(_datasource);
 
diff --git a/lib/util/exec/docker/index.spec.ts b/lib/util/exec/docker/index.spec.ts
index 92f67a1a5d..28dc102ac3 100644
--- a/lib/util/exec/docker/index.spec.ts
+++ b/lib/util/exec/docker/index.spec.ts
@@ -1,4 +1,3 @@
-import { mockDeep } from 'jest-mock-extended';
 import { mockExecAll, mockExecSequence } from '../../../../test/exec-util';
 import { partial } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
@@ -16,7 +15,7 @@ import {
   sideCarImage,
 } from '.';
 
-jest.mock('../../../modules/datasource', () => mockDeep());
+vi.mock('../../../modules/datasource', () => ({ getPkgReleases: vi.fn() }));
 
 describe('util/exec/docker/index', () => {
   describe('prefetchDockerImage', () => {
@@ -181,7 +180,7 @@ describe('util/exec/docker/index', () => {
       expect(logger.warn).toHaveBeenCalled();
     });
 
-    it('handles empty container list ', async () => {
+    it('handles empty container list', async () => {
       const execSnapshots = mockExecAll({ stdout: '\n\n\n', stderr: '' });
       await removeDanglingContainers();
       expect(execSnapshots).toMatchObject([
diff --git a/lib/util/exec/hermit.spec.ts b/lib/util/exec/hermit.spec.ts
index 0d524108be..15bcdfdc63 100644
--- a/lib/util/exec/hermit.spec.ts
+++ b/lib/util/exec/hermit.spec.ts
@@ -7,7 +7,7 @@ import { GlobalConfig } from '../../config/global';
 import { findHermitCwd, getHermitEnvs, isHermit } from './hermit';
 import type { RawExecOptions } from './types';
 
-jest.mock('find-up');
+vi.mock('find-up');
 const findUp = mockedFunction(_findUp);
 const localDir = '/tmp/renovate/repository/project-a';
 
diff --git a/lib/util/exec/index.spec.ts b/lib/util/exec/index.spec.ts
index 3e3385b442..cbdc0e6c40 100644
--- a/lib/util/exec/index.spec.ts
+++ b/lib/util/exec/index.spec.ts
@@ -1,4 +1,4 @@
-import { mockDeep } from 'jest-mock-extended';
+import { mockDeep } from 'vitest-mock-extended';
 import { exec as cpExec, envMock } from '../../../test/exec-util';
 import { mockedFunction } from '../../../test/util';
 import { GlobalConfig } from '../../config/global';
@@ -11,11 +11,11 @@ import { exec } from '.';
 
 const getHermitEnvsMock = mockedFunction(getHermitEnvs);
 
-jest.mock('./hermit', () => ({
-  ...jest.requireActual<typeof import('./hermit')>('./hermit'),
-  getHermitEnvs: jest.fn(),
+vi.mock('./hermit', async () => ({
+  ...(await vi.importActual<typeof import('./hermit')>('./hermit')),
+  getHermitEnvs: vi.fn(),
 }));
-jest.mock('../../modules/datasource', () => mockDeep());
+vi.mock('../../modules/datasource', () => mockDeep());
 
 interface TestInput {
   processEnv: Record<string, string>;
@@ -46,7 +46,7 @@ describe('util/exec/index', () => {
 
   beforeEach(() => {
     dockerModule.resetPrefetchedImages();
-    jest.restoreAllMocks();
+    vi.restoreAllMocks();
     processEnvOrig = process.env;
     GlobalConfig.reset();
   });
@@ -878,7 +878,7 @@ describe('util/exec/index', () => {
       throw new Error('some error occurred');
     });
 
-    const removeDockerContainerSpy = jest.spyOn(
+    const removeDockerContainerSpy = vi.spyOn(
       dockerModule,
       'removeDockerContainer',
     );
@@ -893,14 +893,14 @@ describe('util/exec/index', () => {
     cpExec.mockImplementation(() => {
       throw new Error('some error occurred');
     });
-    jest
-      .spyOn(dockerModule, 'generateDockerCommand')
-      .mockImplementation((): any => 'asdf');
+    vi.spyOn(dockerModule, 'generateDockerCommand').mockImplementation(
+      (): any => 'asdf',
+    );
 
     // The `removeDockerContainer` function is called once before it's used in the `catch` block.
     // We want it to fail in the catch block so we can assert the error is wrapped.
     let calledOnce = false;
-    const removeDockerContainerSpy = jest.spyOn(
+    const removeDockerContainerSpy = vi.spyOn(
       dockerModule,
       'removeDockerContainer',
     );
@@ -931,7 +931,7 @@ describe('util/exec/index', () => {
       error.signal = 'SIGTERM';
       throw error;
     });
-    const removeDockerContainerSpy = jest.spyOn(
+    const removeDockerContainerSpy = vi.spyOn(
       dockerModule,
       'removeDockerContainer',
     );
diff --git a/lib/util/fs/__snapshots__/index.spec.ts.snap b/lib/util/fs/__snapshots__/index.spec.ts.snap
index fd4ae153cf..a3aa9dba8c 100644
--- a/lib/util/fs/__snapshots__/index.spec.ts.snap
+++ b/lib/util/fs/__snapshots__/index.spec.ts.snap
@@ -1,13 +1,13 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`util/fs/index readLocalDirectory returns dir content 1`] = `
+exports[`util/fs/index > readLocalDirectory > returns dir content 1`] = `
 [
   "Cargo.lock",
   "Cargo.toml",
 ]
 `;
 
-exports[`util/fs/index readLocalDirectory returns dir content 2`] = `
+exports[`util/fs/index > readLocalDirectory > returns dir content 2`] = `
 [
   "Cargo.lock",
   "Cargo.toml",
diff --git a/lib/util/fs/index.spec.ts b/lib/util/fs/index.spec.ts
index 2a0fa3b63b..15b68da010 100644
--- a/lib/util/fs/index.spec.ts
+++ b/lib/util/fs/index.spec.ts
@@ -40,9 +40,9 @@ import {
   writeSystemFile,
 } from '.';
 
-jest.mock('../exec/env');
-jest.mock('find-up');
-jest.mock('../git');
+vi.mock('../exec/env');
+vi.mock('find-up');
+vi.mock('../git');
 
 const findUp = mockedFunction(_findUp);
 
diff --git a/lib/util/git/behind-base-branch-cache.spec.ts b/lib/util/git/behind-base-branch-cache.spec.ts
index 23d6f53141..3f4b9c3595 100644
--- a/lib/util/git/behind-base-branch-cache.spec.ts
+++ b/lib/util/git/behind-base-branch-cache.spec.ts
@@ -7,7 +7,7 @@ import {
 } from './behind-base-branch-cache';
 import type { LongCommitSha } from './types';
 
-jest.mock('../cache/repository');
+vi.mock('../cache/repository');
 const repositoryCache = mocked(_repositoryCache);
 
 describe('util/git/behind-base-branch-cache', () => {
diff --git a/lib/util/git/conflicts-cache.spec.ts b/lib/util/git/conflicts-cache.spec.ts
index 038a34fe32..2d0216d95f 100644
--- a/lib/util/git/conflicts-cache.spec.ts
+++ b/lib/util/git/conflicts-cache.spec.ts
@@ -6,7 +6,7 @@ import {
   setCachedConflictResult,
 } from './conflicts-cache';
 
-jest.mock('../cache/repository');
+vi.mock('../cache/repository');
 const repositoryCache = mocked(_repositoryCache);
 
 describe('util/git/conflicts-cache', () => {
diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts
index e06e7fb40f..8b8effd3ae 100644
--- a/lib/util/git/index.spec.ts
+++ b/lib/util/git/index.spec.ts
@@ -15,20 +15,18 @@ import type { FileChange } from './types';
 import * as git from '.';
 import { setNoVerify } from '.';
 
-jest.mock('./conflicts-cache');
-jest.mock('./behind-base-branch-cache');
-jest.mock('./modified-cache');
-jest.mock('timers/promises');
-jest.mock('../cache/repository');
+vi.mock('./conflicts-cache');
+vi.mock('./behind-base-branch-cache');
+vi.mock('./modified-cache');
+vi.mock('timers/promises');
+vi.mock('../cache/repository');
 const behindBaseCache = mocked(_behindBaseCache);
 const conflictsCache = mocked(_conflictsCache);
 const modifiedCache = mocked(_modifiedCache);
 // Class is no longer exported
 const SimpleGit = Git().constructor as { prototype: ReturnType<typeof Git> };
 
-describe('util/git/index', () => {
-  jest.setTimeout(60000);
-
+describe('util/git/index', { timeout: 10000 }, () => {
   const masterCommitDate = new Date();
   masterCommitDate.setMilliseconds(0);
   let base: tmp.DirectoryResult;
diff --git a/lib/util/git/modified-cache.spec.ts b/lib/util/git/modified-cache.spec.ts
index 1c679021fc..17e19e96b2 100644
--- a/lib/util/git/modified-cache.spec.ts
+++ b/lib/util/git/modified-cache.spec.ts
@@ -6,7 +6,7 @@ import {
   setCachedModifiedResult,
 } from './modified-cache';
 
-jest.mock('../cache/repository');
+vi.mock('../cache/repository');
 const repositoryCache = mocked(_repositoryCache);
 
 describe('util/git/modified-cache', () => {
diff --git a/lib/util/git/pristine.spec.ts b/lib/util/git/pristine.spec.ts
index 01b3371c93..7bf620e5e7 100644
--- a/lib/util/git/pristine.spec.ts
+++ b/lib/util/git/pristine.spec.ts
@@ -3,7 +3,7 @@ import * as _repositoryCache from '../cache/repository';
 import type { BranchCache, RepoCacheData } from '../cache/repository/types';
 import { getCachedPristineResult } from './pristine';
 
-jest.mock('../cache/repository');
+vi.mock('../cache/repository');
 const repositoryCache = mocked(_repositoryCache);
 
 describe('util/git/pristine', () => {
diff --git a/lib/util/git/private-key.spec.ts b/lib/util/git/private-key.spec.ts
index 4b64a88a96..d9a9131b88 100644
--- a/lib/util/git/private-key.spec.ts
+++ b/lib/util/git/private-key.spec.ts
@@ -1,21 +1,21 @@
 import os from 'node:os';
 import fs from 'fs-extra';
-import { any, mockDeep } from 'jest-mock-extended';
 import upath from 'upath';
+import { any, mockFn } from 'vitest-mock-extended';
 import { Fixtures } from '../../../test/fixtures';
 import { mockedExtended } from '../../../test/util';
 import * as exec_ from '../exec';
 import { configSigningKey, writePrivateKey } from './private-key';
 import { setPrivateKey } from '.';
 
-jest.mock('fs-extra', () =>
-  jest
-    .requireActual<
-      typeof import('../../../test/fixtures')
-    >('../../../test/fixtures')
-    .fsExtra(),
+vi.mock('fs-extra', async () =>
+  (
+    await vi.importActual<typeof import('../../../test/fixtures')>(
+      '../../../test/fixtures',
+    )
+  ).fsExtra(),
 );
-jest.mock('../exec', () => mockDeep());
+vi.mock('../exec', () => ({ exec: mockFn() }));
 
 const exec = mockedExtended(exec_);
 
@@ -23,6 +23,7 @@ describe('util/git/private-key', () => {
   describe('writePrivateKey()', () => {
     beforeEach(() => {
       Fixtures.reset();
+      exec.exec.mockReset();
     });
 
     it('returns if no private key', async () => {
diff --git a/lib/util/git/semantic.spec.ts b/lib/util/git/semantic.spec.ts
index 7a977a020d..603b2ef15d 100644
--- a/lib/util/git/semantic.spec.ts
+++ b/lib/util/git/semantic.spec.ts
@@ -3,7 +3,7 @@ import { git, partial } from '../../../test/util';
 import { initRepoCache } from '../cache/repository/init';
 import { detectSemanticCommits } from './semantic';
 
-jest.mock('.');
+vi.mock('.');
 
 let config: RenovateConfig;
 
diff --git a/lib/util/git/set-branch-commit.spec.ts b/lib/util/git/set-branch-commit.spec.ts
index 77051f48cd..f26a0d4a6f 100644
--- a/lib/util/git/set-branch-commit.spec.ts
+++ b/lib/util/git/set-branch-commit.spec.ts
@@ -4,8 +4,8 @@ import type { BranchCache, RepoCacheData } from '../cache/repository/types';
 import { setBranchNewCommit } from './set-branch-commit';
 import type { LongCommitSha } from './types';
 
-jest.mock('../cache/repository');
-jest.mock('.');
+vi.mock('../cache/repository');
+vi.mock('.');
 const repositoryCache = mocked(_repositoryCache);
 
 describe('util/git/set-branch-commit', () => {
diff --git a/lib/util/git/url.spec.ts b/lib/util/git/url.spec.ts
index d4728d493a..6ccb272b8f 100644
--- a/lib/util/git/url.spec.ts
+++ b/lib/util/git/url.spec.ts
@@ -1,8 +1,8 @@
-import { mockDeep } from 'jest-mock-extended';
+import { mockDeep } from 'vitest-mock-extended';
 import { hostRules } from '../../../test/util';
 import { getHttpUrl, getRemoteUrlWithToken, parseGitUrl } from './url';
 
-jest.mock('../host-rules', () => mockDeep());
+vi.mock('../host-rules', () => mockDeep());
 
 describe('util/git/url', () => {
   describe('parseGitUrl', () => {
diff --git a/lib/util/github/graphql/datasource-fetcher.spec.ts b/lib/util/github/graphql/datasource-fetcher.spec.ts
index 7046905135..98683bc332 100644
--- a/lib/util/github/graphql/datasource-fetcher.spec.ts
+++ b/lib/util/github/graphql/datasource-fetcher.spec.ts
@@ -16,7 +16,7 @@ import type {
   GithubGraphqlRepoResponse,
 } from './types';
 
-jest.mock('../../../util/cache/package');
+vi.mock('../../../util/cache/package');
 const packageCache = mocked(_packageCache);
 
 interface TestAdapterInput {
diff --git a/lib/util/http/cache/package-http-cache-provider.spec.ts b/lib/util/http/cache/package-http-cache-provider.spec.ts
index 524f60e084..bd9921c116 100644
--- a/lib/util/http/cache/package-http-cache-provider.spec.ts
+++ b/lib/util/http/cache/package-http-cache-provider.spec.ts
@@ -7,7 +7,7 @@ import * as _packageCache from '../../cache/package';
 import { PackageHttpCacheProvider } from './package-http-cache-provider';
 import type { HttpCache } from './schema';
 
-jest.mock('../../../util/cache/package', () => mockDeep());
+vi.mock('../../../util/cache/package', () => mockDeep());
 const packageCache = mocked(_packageCache);
 
 const http = new Http('test');
diff --git a/lib/util/http/github.spec.ts b/lib/util/http/github.spec.ts
index c95854a6fb..fe9566c365 100644
--- a/lib/util/http/github.spec.ts
+++ b/lib/util/http/github.spec.ts
@@ -17,7 +17,7 @@ import * as hostRules from '../host-rules';
 import { GithubHttp, setBaseUrl } from './github';
 import type { GraphqlPageCache } from './github';
 
-jest.mock('../cache/repository');
+vi.mock('../cache/repository');
 const repositoryCache = mocked(_repositoryCache);
 
 const githubApiHost = 'https://api.github.com';
@@ -937,7 +937,7 @@ describe('util/http/github', () => {
       });
     });
 
-    it('throw error if a ', async () => {
+    it('throw error if a', async () => {
       httpMock
         .scope(githubApiHost)
         .get('/foo/bar/contents/lore/ipsum.bin')
diff --git a/lib/util/http/gitlab.spec.ts b/lib/util/http/gitlab.spec.ts
index 6ab99079d3..8f2f38d83e 100644
--- a/lib/util/http/gitlab.spec.ts
+++ b/lib/util/http/gitlab.spec.ts
@@ -114,7 +114,7 @@ describe('util/http/gitlab', () => {
       await expect(
         gitlabApi.get('some-url'),
       ).rejects.toThrowErrorMatchingInlineSnapshot(
-        `"Response code 403 (Forbidden)"`,
+        `[HTTPError: Response code 403 (Forbidden)]`,
       );
     });
 
@@ -123,7 +123,7 @@ describe('util/http/gitlab', () => {
       await expect(
         gitlabApi.get('some-url'),
       ).rejects.toThrowErrorMatchingInlineSnapshot(
-        `"Response code 404 (Not Found)"`,
+        `[HTTPError: Response code 404 (Not Found)]`,
       );
     });
 
diff --git a/lib/util/http/host-rules.spec.ts b/lib/util/http/host-rules.spec.ts
index 3ca3db64fb..3889b1bbd8 100644
--- a/lib/util/http/host-rules.spec.ts
+++ b/lib/util/http/host-rules.spec.ts
@@ -7,7 +7,7 @@ import type { GotOptions } from './types';
 
 const url = 'https://github.com';
 
-jest.mock('global-agent');
+vi.mock('global-agent');
 
 describe('util/http/host-rules', () => {
   const options: GotOptions = {
diff --git a/lib/util/http/index.spec.ts b/lib/util/http/index.spec.ts
index 57eafc9007..7ffa5caaa4 100644
--- a/lib/util/http/index.spec.ts
+++ b/lib/util/http/index.spec.ts
@@ -617,11 +617,11 @@ describe('util/http/index', () => {
 
   describe('Throttling', () => {
     afterEach(() => {
-      jest.useRealTimers();
+      vi.useRealTimers();
     });
 
     it('works without throttling', async () => {
-      jest.useFakeTimers({ advanceTimers: 1 });
+      vi.useFakeTimers({ shouldAdvanceTime: true, advanceTimeDelta: 1 });
       httpMock.scope(baseUrl).get('/foo').twice().reply(200, 'bar');
 
       const t1 = Date.now();
@@ -633,13 +633,13 @@ describe('util/http/index', () => {
     });
 
     it('limits request rate by host', async () => {
-      jest.useFakeTimers({ advanceTimers: true });
+      vi.useFakeTimers({ shouldAdvanceTime: true });
       httpMock.scope(baseUrl).get('/foo').twice().reply(200, 'bar');
       hostRules.add({ matchHost: 'renovate.com', maxRequestsPerSecond: 0.25 });
 
       const t1 = Date.now();
       await http.get('http://renovate.com/foo');
-      jest.advanceTimersByTime(4000);
+      vi.advanceTimersByTime(4000);
       await http.get('http://renovate.com/foo');
       const t2 = Date.now();
 
diff --git a/lib/util/http/jira.spec.ts b/lib/util/http/jira.spec.ts
index e84b2e5f2d..8f56e07136 100644
--- a/lib/util/http/jira.spec.ts
+++ b/lib/util/http/jira.spec.ts
@@ -5,9 +5,7 @@ describe('util/http/jira', () => {
   const api = new JiraHttp();
 
   it('throws error if setBaseUrl not called', async () => {
-    await expect(api.postJson('some-path')).rejects.toThrow(
-      new TypeError('Invalid URL'),
-    );
+    await expect(api.postJson('some-path')).rejects.toThrow('Invalid URL');
   });
 
   it('accepts custom baseUrl', async () => {
diff --git a/lib/util/http/legacy.ts b/lib/util/http/legacy.ts
index 99493d5dbd..3582c251d1 100644
--- a/lib/util/http/legacy.ts
+++ b/lib/util/http/legacy.ts
@@ -8,6 +8,7 @@ Object.defineProperty(HttpError.prototype, 'statusCode', {
   get: function statusCode(this: HttpError) {
     return this.response?.statusCode;
   },
+  configurable: true, // required by azure tests
 });
 
 Object.defineProperty(HttpError.prototype, 'body', {
@@ -19,6 +20,7 @@ Object.defineProperty(HttpError.prototype, 'body', {
       this.response.body = value;
     }
   },
+  configurable: true,
 });
 
 Object.defineProperty(HttpError.prototype, 'headers', {
@@ -31,6 +33,7 @@ Object.defineProperty(HttpError.prototype, 'url', {
   get: function url(this: HttpError) {
     return this.response?.url;
   },
+  configurable: true,
 });
 
 Object.defineProperty(HttpError.prototype, 'host', {
@@ -39,6 +42,7 @@ Object.defineProperty(HttpError.prototype, 'host', {
     const url = urlStr ? parseUrl(urlStr) : null;
     return url?.host;
   },
+  configurable: true,
 });
 
 export type GotLegacyError<E = unknown, T = unknown> = HttpError & {
diff --git a/lib/util/ignore.spec.ts b/lib/util/ignore.spec.ts
index c9b483aeca..a91393b7d1 100644
--- a/lib/util/ignore.spec.ts
+++ b/lib/util/ignore.spec.ts
@@ -1,9 +1,9 @@
 import { logger } from '../logger';
 import { isSkipComment } from './ignore';
 
-jest.mock('../logger', () => ({
+vi.mock('../logger', () => ({
   logger: {
-    debug: jest.fn(),
+    debug: vi.fn(),
   },
 }));
 
diff --git a/lib/util/json-writer/editor-config.spec.ts b/lib/util/json-writer/editor-config.spec.ts
index f015329f36..8fb0b0c684 100644
--- a/lib/util/json-writer/editor-config.spec.ts
+++ b/lib/util/json-writer/editor-config.spec.ts
@@ -1,13 +1,16 @@
-import { fs as memfs } from 'memfs';
 import { Fixtures } from '../../../test/fixtures';
 import { configFileNames } from '../../config/app-strings';
 import { GlobalConfig } from '../../config/global';
 import { EditorConfig } from './editor-config';
 
+// mock `require` calls to `fs` and `memfs`
+// https://github.com/vitest-dev/vitest/discussions/3134
 // use real fs to read wasm files for `@one-ini/wasm`
-jest.mock('fs', () => {
-  const realFs = jest.requireActual<typeof import('fs')>('fs');
-  return {
+// @ts-expect-error no toplevel await on commonjs
+await vi.hoisted(async () => {
+  const { fs: memfs } = await vi.importActual<typeof import('memfs')>('memfs');
+  const realFs = await vi.importActual<typeof import('fs')>('fs');
+  const fs = {
     ...memfs,
     readFileSync: (file: string, ...args: any[]) => {
       if (file.endsWith('.wasm')) {
@@ -16,6 +19,8 @@ jest.mock('fs', () => {
       return memfs.readFileSync(file, ...args);
     },
   };
+
+  require.cache.fs = { exports: fs } as never;
 });
 
 const defaultConfigFile = configFileNames[0];
@@ -28,7 +33,6 @@ describe('util/json-writer/editor-config', () => {
   });
 
   beforeEach(() => {
-    jest.restoreAllMocks();
     Fixtures.reset();
   });
 
diff --git a/lib/util/modules.ts b/lib/util/modules.ts
index f64975ed5b..0c094ad334 100644
--- a/lib/util/modules.ts
+++ b/lib/util/modules.ts
@@ -1,6 +1,8 @@
 import fs from 'node:fs';
 import upath from 'upath';
 
+// TODO: move to `test/util.ts` or `test/modules.ts`
+
 function relatePath(here: string, there: string): string {
   const thereParts = upath.normalizeTrim(there).split('/');
   const hereParts = upath.normalizeTrim(here).split('/');
@@ -24,11 +26,11 @@ function relatePath(here: string, there: string): string {
   return result.join('/');
 }
 
-export function loadModules<T>(
+export async function loadModules<T>(
   dirname: string,
   validate?: (module: T, moduleName: string) => boolean,
   filter: (moduleName: string) => boolean = () => true,
-): Record<string, T> {
+): Promise<Record<string, T>> {
   const result: Record<string, T> = {};
 
   const moduleNames: string[] = fs
@@ -41,7 +43,7 @@ export function loadModules<T>(
 
   for (const moduleName of moduleNames) {
     const modulePath = upath.join(relatePath(__dirname, dirname), moduleName);
-    const module = require(modulePath); // eslint-disable-line
+    const module = await import(modulePath);
     // istanbul ignore if
     if (!module || (validate && !validate(module, moduleName))) {
       throw new Error(`Invalid module: ${modulePath}`);
diff --git a/lib/util/mutex.spec.ts b/lib/util/mutex.spec.ts
index 13ac898446..efb7e3b486 100644
--- a/lib/util/mutex.spec.ts
+++ b/lib/util/mutex.spec.ts
@@ -1,4 +1,3 @@
-import { afterEach } from '@jest/globals';
 import { acquireLock, getMutex } from './mutex';
 
 describe('util/mutex', () => {
diff --git a/lib/util/package-rules/index.spec.ts b/lib/util/package-rules/index.spec.ts
index bb7999b8b6..8e6e6a0b75 100644
--- a/lib/util/package-rules/index.spec.ts
+++ b/lib/util/package-rules/index.spec.ts
@@ -731,7 +731,7 @@ describe('util/package-rules/index', () => {
         error = err;
       }
 
-      expect(error).toStrictEqual(new Error(MISSING_API_CREDENTIALS));
+      expect(error).toMatchObject(new Error(MISSING_API_CREDENTIALS));
       expect(error.validationError).toBe('Missing credentials');
       expect(error.validationMessage).toBe(
         'The `matchConfidence` matcher in `packageRules` requires authentication. Please refer to the [documentation](https://docs.renovatebot.com/configuration-options/#matchconfidence) and add the required host rule.',
diff --git a/lib/util/regex.spec.ts b/lib/util/regex.spec.ts
index 4252ed17b0..b741eb13de 100644
--- a/lib/util/regex.spec.ts
+++ b/lib/util/regex.spec.ts
@@ -3,10 +3,6 @@ import { CONFIG_VALIDATION } from '../constants/error-messages';
 import { regEx } from './regex';
 
 describe('util/regex', () => {
-  beforeEach(() => {
-    jest.resetModules();
-  });
-
   it('uses RE2', () => {
     expect(regEx('foo')).toBeInstanceOf(RE2);
   });
@@ -30,9 +26,12 @@ describe('util/regex', () => {
   });
 
   it('Falls back to RegExp', async () => {
-    jest.doMock('re2', () => {
-      throw new Error();
-    });
+    vi.resetModules();
+    vi.doMock('../expose.cjs', () => ({
+      re2: () => {
+        throw new Error();
+      },
+    }));
 
     const regex = await import('./regex');
     expect(regex.regEx('foo')).toBeInstanceOf(RegExp);
diff --git a/lib/util/template/__snapshots__/index.spec.ts.snap b/lib/util/template/__snapshots__/index.spec.ts.snap
index 5dc65a486f..86b9834f8a 100644
--- a/lib/util/template/__snapshots__/index.spec.ts.snap
+++ b/lib/util/template/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`util/template/index string to pretty JSON  1`] = `
+exports[`util/template/index > string to pretty JSON 1`] = `
 "{
   "some": {
     "fancy": "json"
diff --git a/lib/util/template/index.spec.ts b/lib/util/template/index.spec.ts
index eceb5229a8..3fff793622 100644
--- a/lib/util/template/index.spec.ts
+++ b/lib/util/template/index.spec.ts
@@ -3,7 +3,7 @@ import { getOptions } from '../../config/options';
 import * as _execUtils from '../exec/utils';
 import * as template from '.';
 
-jest.mock('../exec/utils');
+vi.mock('../exec/utils');
 
 const execUtils = mocked(_execUtils);
 
@@ -89,7 +89,7 @@ describe('util/template/index', () => {
     expect(output).toContain('False');
   });
 
-  it('string to pretty JSON ', () => {
+  it('string to pretty JSON', () => {
     const userTemplate =
       '{{{ stringToPrettyJSON \'{"some":{"fancy":"json"}}\'}}}';
     const output = template.compile(userTemplate, undefined as never);
diff --git a/lib/workers/global/autodiscover.spec.ts b/lib/workers/global/autodiscover.spec.ts
index 8af94614df..3f6f43e640 100644
--- a/lib/workers/global/autodiscover.spec.ts
+++ b/lib/workers/global/autodiscover.spec.ts
@@ -4,13 +4,14 @@ import * as _ghApi from '../../modules/platform/github';
 import * as _hostRules from '../../util/host-rules';
 import { autodiscoverRepositories } from './autodiscover';
 
-jest.mock('../../modules/platform/github');
-jest.unmock('../../modules/platform');
-jest.unmock('../../modules/platform/scm');
+vi.mock('../../modules/platform/github');
+vi.mock('../../util/host-rules');
+vi.unmock('../../modules/platform');
+vi.unmock('../../modules/platform/scm');
 
 // imports are readonly
-const hostRules = _hostRules;
-const ghApi: jest.Mocked<typeof _ghApi> = _ghApi as never;
+const hostRules = vi.mocked(_hostRules);
+const ghApi = vi.mocked(_ghApi);
 
 describe('workers/global/autodiscover', () => {
   let config: RenovateConfig;
@@ -44,10 +45,10 @@ describe('workers/global/autodiscover', () => {
   it('autodiscovers github but empty', async () => {
     config.autodiscover = true;
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() => Promise.resolve([]));
+    ghApi.getRepos.mockImplementation(() => Promise.resolve([]));
     const res = await autodiscoverRepositories(config);
     expect(res).toEqual(config);
   });
@@ -55,10 +56,10 @@ describe('workers/global/autodiscover', () => {
   it('autodiscovers github repos', async () => {
     config.autodiscover = true;
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() => Promise.resolve(['a', 'b']));
+    ghApi.getRepos.mockImplementation(() => Promise.resolve(['a', 'b']));
     const res = await autodiscoverRepositories(config);
     expect(res.repositories).toHaveLength(2);
   });
@@ -67,10 +68,10 @@ describe('workers/global/autodiscover', () => {
     config.autodiscover = true;
     config.autodiscoverFilter = ['project/re*'];
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() =>
+    ghApi.getRepos.mockImplementation(() =>
       Promise.resolve(['project/repo', 'project/another-repo']),
     );
     const res = await autodiscoverRepositories(config);
@@ -81,10 +82,10 @@ describe('workers/global/autodiscover', () => {
     config.autodiscover = true;
     config.autodiscoverFilter = ['project/*'];
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() =>
+    ghApi.getRepos.mockImplementation(() =>
       Promise.resolve(['project/repo', 'project/.github']),
     );
     const res = await autodiscoverRepositories(config);
@@ -95,10 +96,10 @@ describe('workers/global/autodiscover', () => {
     config.autodiscover = true;
     config.autodiscoverFilter = ['project/re*'];
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() =>
+    ghApi.getRepos.mockImplementation(() =>
       Promise.resolve(['another-project/repo', 'another-project/another-repo']),
     );
     const res = await autodiscoverRepositories(config);
@@ -109,10 +110,10 @@ describe('workers/global/autodiscover', () => {
     config.autodiscover = true;
     config.autodiscoverFilter = ['/project/RE*./i'];
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() =>
+    ghApi.getRepos.mockImplementation(() =>
       Promise.resolve(['project/repo', 'project/another-repo']),
     );
     const res = await autodiscoverRepositories(config);
@@ -123,10 +124,10 @@ describe('workers/global/autodiscover', () => {
     config.autodiscover = true;
     config.autodiscoverFilter = ['!/project/re*./'];
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() =>
+    ghApi.getRepos.mockImplementation(() =>
       Promise.resolve(['project/repo', 'project/another-repo']),
     );
     const res = await autodiscoverRepositories(config);
@@ -137,10 +138,10 @@ describe('workers/global/autodiscover', () => {
     config.autodiscover = true;
     config.autodiscoverFilter = '!project/re*';
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() =>
+    ghApi.getRepos.mockImplementation(() =>
       Promise.resolve(['project/repo', 'project/another-repo']),
     );
     const res = await autodiscoverRepositories(config);
@@ -151,10 +152,10 @@ describe('workers/global/autodiscover', () => {
     config.autodiscover = true;
     config.autodiscoverFilter = ['/project/re**./'];
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() =>
+    ghApi.getRepos.mockImplementation(() =>
       Promise.resolve(['project/repo', 'project/another-repo']),
     );
     await expect(autodiscoverRepositories(config)).rejects.toThrow();
@@ -164,7 +165,7 @@ describe('workers/global/autodiscover', () => {
     config.autodiscover = true;
     config.autodiscoverFilter = ['another-project/re*', 'department/dev/*'];
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
     // retains order
@@ -173,7 +174,7 @@ describe('workers/global/autodiscover', () => {
       'another-project/repo',
       'department/dev/bProject',
     ];
-    ghApi.getRepos = jest.fn(() =>
+    ghApi.getRepos.mockImplementation(() =>
       Promise.resolve([
         'another-project/another-repo',
         ...expectedRepositories,
@@ -187,10 +188,10 @@ describe('workers/global/autodiscover', () => {
     config.autodiscover = true;
     config.autodiscoverFilter = ['project/re*'];
     config.platform = 'github';
-    hostRules.find = jest.fn(() => ({
+    hostRules.find.mockImplementation(() => ({
       token: 'abc',
     }));
-    ghApi.getRepos = jest.fn(() =>
+    ghApi.getRepos.mockImplementation(() =>
       Promise.resolve(['project/repo', 'PROJECT/repo2']),
     );
     const res = await autodiscoverRepositories(config);
diff --git a/lib/workers/global/config/parse/__snapshots__/env.spec.ts.snap b/lib/workers/global/config/parse/__snapshots__/env.spec.ts.snap
index 0f673583d4..1c356ae187 100644
--- a/lib/workers/global/config/parse/__snapshots__/env.spec.ts.snap
+++ b/lib/workers/global/config/parse/__snapshots__/env.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/global/config/parse/env .getConfig(env) supports Azure DevOps 1`] = `
+exports[`workers/global/config/parse/env > .getConfig(env) > supports Azure DevOps 1`] = `
 {
   "endpoint": "an Azure DevOps endpoint",
   "hostRules": [],
@@ -9,7 +9,7 @@ exports[`workers/global/config/parse/env .getConfig(env) supports Azure DevOps 1
 }
 `;
 
-exports[`workers/global/config/parse/env .getConfig(env) supports Bitbucket token 1`] = `
+exports[`workers/global/config/parse/env > .getConfig(env) > supports Bitbucket token 1`] = `
 {
   "endpoint": "a bitbucket endpoint",
   "hostRules": [],
@@ -19,7 +19,7 @@ exports[`workers/global/config/parse/env .getConfig(env) supports Bitbucket toke
 }
 `;
 
-exports[`workers/global/config/parse/env .getConfig(env) supports Bitbucket username/password 1`] = `
+exports[`workers/global/config/parse/env > .getConfig(env) > supports Bitbucket username/password 1`] = `
 {
   "endpoint": "a bitbucket endpoint",
   "hostRules": [],
@@ -29,14 +29,14 @@ exports[`workers/global/config/parse/env .getConfig(env) supports Bitbucket user
 }
 `;
 
-exports[`workers/global/config/parse/env .getConfig(env) supports GitHub custom endpoint 1`] = `
+exports[`workers/global/config/parse/env > .getConfig(env) > supports GitHub custom endpoint 1`] = `
 {
   "endpoint": "a ghe endpoint",
   "hostRules": [],
 }
 `;
 
-exports[`workers/global/config/parse/env .getConfig(env) supports GitHub custom endpoint and github.com 1`] = `
+exports[`workers/global/config/parse/env > .getConfig(env) > supports GitHub custom endpoint and github.com 1`] = `
 {
   "endpoint": "a ghe endpoint",
   "hostRules": [
@@ -50,7 +50,7 @@ exports[`workers/global/config/parse/env .getConfig(env) supports GitHub custom
 }
 `;
 
-exports[`workers/global/config/parse/env .getConfig(env) supports GitHub custom endpoint and gitlab.com 1`] = `
+exports[`workers/global/config/parse/env > .getConfig(env) > supports GitHub custom endpoint and gitlab.com 1`] = `
 {
   "endpoint": "a ghe endpoint",
   "hostRules": [],
@@ -58,14 +58,14 @@ exports[`workers/global/config/parse/env .getConfig(env) supports GitHub custom
 }
 `;
 
-exports[`workers/global/config/parse/env .getConfig(env) supports GitHub token 1`] = `
+exports[`workers/global/config/parse/env > .getConfig(env) > supports GitHub token 1`] = `
 {
   "hostRules": [],
   "token": "github.com token",
 }
 `;
 
-exports[`workers/global/config/parse/env .getConfig(env) supports GitLab custom endpoint 1`] = `
+exports[`workers/global/config/parse/env > .getConfig(env) > supports GitLab custom endpoint 1`] = `
 {
   "endpoint": "a gitlab endpoint",
   "hostRules": [],
@@ -74,7 +74,7 @@ exports[`workers/global/config/parse/env .getConfig(env) supports GitLab custom
 }
 `;
 
-exports[`workers/global/config/parse/env .getConfig(env) supports GitLab token 1`] = `
+exports[`workers/global/config/parse/env > .getConfig(env) > supports GitLab token 1`] = `
 {
   "hostRules": [],
   "platform": "gitlab",
diff --git a/lib/workers/global/config/parse/__snapshots__/file.spec.ts.snap b/lib/workers/global/config/parse/__snapshots__/file.spec.ts.snap
index 6e19554751..9ff0741dea 100644
--- a/lib/workers/global/config/parse/__snapshots__/file.spec.ts.snap
+++ b/lib/workers/global/config/parse/__snapshots__/file.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/global/config/parse/file .getConfig() migrates 1`] = `
+exports[`workers/global/config/parse/file > .getConfig() > migrates 1`] = `
 {
   "rangeStrategy": "bump",
 }
diff --git a/lib/workers/global/config/parse/file.spec.ts b/lib/workers/global/config/parse/file.spec.ts
index f55369d055..f6801ce407 100644
--- a/lib/workers/global/config/parse/file.spec.ts
+++ b/lib/workers/global/config/parse/file.spec.ts
@@ -72,7 +72,7 @@ describe('workers/global/config/parse/file', () => {
 
     it.each([
       [
-        'config.js',
+        'config.invalid.js',
         `module.exports = {
         "platform": "github",
         "token":"abcdef",
@@ -84,8 +84,8 @@ describe('workers/global/config/parse/file', () => {
         "repositories": [ "test/test" ],
       };`,
       ],
-      ['config.json5', `"invalid":`],
-      ['config.yaml', `invalid: -`],
+      ['config.invalid.json5', `"invalid":`],
+      ['config.invalid.yaml', `clearly: "invalid" "yaml"`],
     ])(
       'fatal error and exit if error in parsing %s',
       async (fileName, fileContent) => {
diff --git a/lib/workers/global/config/parse/index.spec.ts b/lib/workers/global/config/parse/index.spec.ts
index 54321079d6..ae4f375c01 100644
--- a/lib/workers/global/config/parse/index.spec.ts
+++ b/lib/workers/global/config/parse/index.spec.ts
@@ -4,9 +4,9 @@ import { getParentDir, readSystemFile } from '../../../../util/fs';
 import getArgv from './__fixtures__/argv';
 import * as _hostRulesFromEnv from './host-rules-from-env';
 
-jest.mock('../../../../modules/datasource/npm');
-jest.mock('../../../../util/fs');
-jest.mock('./host-rules-from-env');
+vi.mock('../../../../modules/datasource/npm');
+vi.mock('../../../../util/fs');
+vi.mock('./host-rules-from-env');
 
 const { hostRulesFromEnv } = mocked(_hostRulesFromEnv);
 
@@ -174,9 +174,7 @@ describe('workers/global/config/parse/index', () => {
     });
 
     it('only initializes the file when the env var LOG_FILE is properly set', async () => {
-      jest.doMock('../../../../../config.js', () => ({}), {
-        virtual: true,
-      });
+      vi.doMock('../../../../../config.js', () => ({ default: {} }));
       const env: NodeJS.ProcessEnv = {};
       const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
       expect(parsedConfig).not.toContain([['logFile', 'someFile']]);
@@ -184,13 +182,12 @@ describe('workers/global/config/parse/index', () => {
     });
 
     it('massage onboardingNoDeps when autodiscover is false', async () => {
-      jest.doMock(
-        '../../../../../config.js',
-        () => ({ onboardingNoDeps: 'auto', autodiscover: false }),
-        {
-          virtual: true,
+      vi.doMock('../../../../../config.js', () => ({
+        default: {
+          onboardingNoDeps: 'auto',
+          autodiscover: false,
         },
-      );
+      }));
       const env: NodeJS.ProcessEnv = {};
       const parsedConfig = await configParser.parseConfigs(env, defaultArgv);
       expect(parsedConfig).toContainEntries([['onboardingNoDeps', 'enabled']]);
diff --git a/lib/workers/global/index.spec.ts b/lib/workers/global/index.spec.ts
index 9348676f0d..b088284ac6 100644
--- a/lib/workers/global/index.spec.ts
+++ b/lib/workers/global/index.spec.ts
@@ -13,23 +13,25 @@ import * as configParser from './config/parse';
 import * as limits from './limits';
 import * as globalWorker from '.';
 
-jest.mock('../repository');
-jest.mock('../../util/fs');
-jest.mock('../../config/presets');
+vi.mock('../repository');
+vi.mock('../../util/fs');
+vi.mock('../../config/presets');
 
-jest.mock('fs-extra', () => {
-  const realFs = jest.requireActual<typeof fs>('fs-extra');
+vi.mock('fs-extra', async () => {
+  const realFs = await vi.importActual<typeof fs>('fs-extra');
   return {
-    ensureDir: jest.fn(),
-    remove: jest.fn(),
-    readFile: jest.fn((file: string, options: any) => {
-      if (file.endsWith('.wasm.gz')) {
-        return realFs.readFile(file, options);
-      }
-      return undefined;
-    }),
-    writeFile: jest.fn(),
-    outputFile: jest.fn(),
+    default: {
+      ensureDir: vi.fn(),
+      remove: vi.fn(),
+      readFile: vi.fn((file: string, options: any) => {
+        if (file.endsWith('.wasm.gz')) {
+          return realFs.readFile(file, options);
+        }
+        return undefined;
+      }),
+      writeFile: vi.fn(),
+      outputFile: vi.fn(),
+    },
   };
 });
 
diff --git a/lib/workers/global/initialize.spec.ts b/lib/workers/global/initialize.spec.ts
index 2402e0e934..79fd703275 100644
--- a/lib/workers/global/initialize.spec.ts
+++ b/lib/workers/global/initialize.spec.ts
@@ -4,7 +4,7 @@ import { initPlatform as _initPlatform } from '../../modules/platform';
 import * as hostRules from '../../util/host-rules';
 import { globalInitialize } from './initialize';
 
-jest.mock('../../util/git');
+vi.mock('../../util/git');
 const initPlatform = mockedFunction(_initPlatform);
 
 describe('workers/global/initialize', () => {
diff --git a/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap b/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap
index 1699d07771..639e26aaf7 100644
--- a/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap
+++ b/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section dependency dashboard lookup warnings Dependency Lookup Warnings message in issues body 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > checks detected dependencies section > dependency dashboard lookup warnings > Dependency Lookup Warnings message in issues body 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 
@@ -87,7 +87,7 @@ This repository currently has no open or pending branches.
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section multi base branch repo add detected dependencies to the Dependency Dashboard body 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > checks detected dependencies section > multi base branch repo > add detected dependencies to the Dependency Dashboard body 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 This repository currently has no open or pending branches.
@@ -195,7 +195,7 @@ This repository currently has no open or pending branches.
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section multi base branch repo show default message in issues body when packageFiles is empty 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > checks detected dependencies section > multi base branch repo > show default message in issues body when packageFiles is empty 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 This repository currently has no open or pending branches.
@@ -262,7 +262,7 @@ None detected
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section multi base branch repo show default message in issues body when when packageFiles is null 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > checks detected dependencies section > multi base branch repo > show default message in issues body when when packageFiles is null 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 This repository currently has no open or pending branches.
@@ -329,7 +329,7 @@ None detected
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section single base branch repo add detected dependencies to the Dependency Dashboard body 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > checks detected dependencies section > single base branch repo > add detected dependencies to the Dependency Dashboard body 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 This repository currently has no open or pending branches.
@@ -382,7 +382,7 @@ This repository currently has no open or pending branches.
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section single base branch repo show default message in issues body when packageFiles is empty 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > checks detected dependencies section > single base branch repo > show default message in issues body when packageFiles is empty 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 This repository currently has no open or pending branches.
@@ -394,7 +394,7 @@ None detected
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section single base branch repo show default message in issues body when when packageFiles is null 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > checks detected dependencies section > single base branch repo > show default message in issues body when when packageFiles is null 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 This repository currently has no open or pending branches.
@@ -406,7 +406,7 @@ None detected
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section single base branch repo shows different combinations of version+digest for a given dependency 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > checks detected dependencies section > single base branch repo > shows different combinations of version+digest for a given dependency 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 This repository currently has no open or pending branches.
@@ -445,7 +445,7 @@ This repository currently has no open or pending branches.
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() contains logged problems 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > contains logged problems 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 ## Repository problems
@@ -471,7 +471,7 @@ None detected
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() contains logged problems with custom header 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > contains logged problems with custom header 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 ## Repository problems
@@ -493,7 +493,7 @@ None detected
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() open or update Dependency Dashboard when all branches are closed and dependencyDashboardAutoclose is false 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > open or update Dependency Dashboard when all branches are closed and dependencyDashboardAutoclose is false 1`] = `
 "This is a header
 
 This repository currently has no open or pending branches.
@@ -507,7 +507,7 @@ And this is a footer
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() open or update Dependency Dashboard when rules contain approvals 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > open or update Dependency Dashboard when rules contain approvals 1`] = `
 "This is a header for platform:github
 
 This repository currently has no open or pending branches.
@@ -521,7 +521,7 @@ And this is a footer for repository:test
 "
 `;
 
-exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() rechecks branches 1`] = `
+exports[`workers/repository/dependency-dashboard > ensureDependencyDashboard() > rechecks branches 1`] = `
 "This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
 
 ## Pending Approval
diff --git a/lib/workers/repository/changelog/index.spec.ts b/lib/workers/repository/changelog/index.spec.ts
index 709103b105..cfc634a6e6 100644
--- a/lib/workers/repository/changelog/index.spec.ts
+++ b/lib/workers/repository/changelog/index.spec.ts
@@ -3,7 +3,7 @@ import type { BranchUpgradeConfig } from '../../types';
 import { getChangeLogJSON } from '../update/pr/changelog';
 import { embedChangelogs } from '.';
 
-jest.mock('../update/pr/changelog');
+vi.mock('../update/pr/changelog');
 
 mockedFunction(getChangeLogJSON).mockResolvedValue({
   hasReleaseNotes: true,
diff --git a/lib/workers/repository/config-migration/branch/create.spec.ts b/lib/workers/repository/config-migration/branch/create.spec.ts
index 2905fa5582..e7e2536bfe 100644
--- a/lib/workers/repository/config-migration/branch/create.spec.ts
+++ b/lib/workers/repository/config-migration/branch/create.spec.ts
@@ -8,8 +8,8 @@ import { createConfigMigrationBranch } from './create';
 import { MigratedDataFactory } from './migrated-data';
 import type { MigratedData } from './migrated-data';
 
-jest.mock('../../../../util/fs');
-jest.mock('../../../../util/git');
+vi.mock('../../../../util/fs');
+vi.mock('../../../../util/git');
 
 describe('workers/repository/config-migration/branch/create', () => {
   const raw = Fixtures.getJson('./renovate.json');
diff --git a/lib/workers/repository/config-migration/branch/index.spec.ts b/lib/workers/repository/config-migration/branch/index.spec.ts
index c2b98b4687..4ab6f6b79a 100644
--- a/lib/workers/repository/config-migration/branch/index.spec.ts
+++ b/lib/workers/repository/config-migration/branch/index.spec.ts
@@ -1,4 +1,4 @@
-import { mock } from 'jest-mock-extended';
+import { mock } from 'vitest-mock-extended';
 import { Fixtures } from '../../../../../test/fixtures';
 import type { RenovateConfig } from '../../../../../test/util';
 import {
@@ -17,11 +17,11 @@ import type { MigratedData } from './migrated-data';
 import { rebaseMigrationBranch } from './rebase';
 import { checkConfigMigrationBranch } from '.';
 
-jest.mock('./migrated-data');
-jest.mock('./rebase');
-jest.mock('./create');
-jest.mock('../../../../util/git');
-jest.mock('../../update/branch/handle-existing');
+vi.mock('./migrated-data');
+vi.mock('./rebase');
+vi.mock('./create');
+vi.mock('../../../../util/git');
+vi.mock('../../update/branch/handle-existing');
 
 const migratedData = Fixtures.getJson<MigratedData>('./migrated-data.json');
 
diff --git a/lib/workers/repository/config-migration/branch/migrated-data.spec.ts b/lib/workers/repository/config-migration/branch/migrated-data.spec.ts
index 38b237c72a..ddeb9dfa17 100644
--- a/lib/workers/repository/config-migration/branch/migrated-data.spec.ts
+++ b/lib/workers/repository/config-migration/branch/migrated-data.spec.ts
@@ -9,12 +9,12 @@ import { EditorConfig } from '../../../../util/json-writer';
 import { detectRepoFileConfig } from '../../init/merge';
 import { MigratedDataFactory, applyPrettierFormatting } from './migrated-data';
 
-jest.mock('../../../../config/migration');
-jest.mock('../../../../util/git');
-jest.mock('../../../../util/fs');
-jest.mock('../../../../util/json-writer');
-jest.mock('../../init/merge');
-jest.mock('detect-indent');
+vi.mock('../../../../config/migration');
+vi.mock('../../../../util/git');
+vi.mock('../../../../util/fs');
+vi.mock('../../../../util/json-writer');
+vi.mock('../../init/merge');
+vi.mock('detect-indent');
 
 const migratedData = Fixtures.getJson('./migrated-data.json');
 const migratedDataJson5 = Fixtures.getJson('./migrated-data.json5');
diff --git a/lib/workers/repository/config-migration/branch/rebase.spec.ts b/lib/workers/repository/config-migration/branch/rebase.spec.ts
index 4f6b9d9019..fdaa102373 100644
--- a/lib/workers/repository/config-migration/branch/rebase.spec.ts
+++ b/lib/workers/repository/config-migration/branch/rebase.spec.ts
@@ -9,7 +9,7 @@ import { MigratedDataFactory } from './migrated-data';
 import type { MigratedData } from './migrated-data';
 import { jsonStripWhitespaces, rebaseMigrationBranch } from './rebase';
 
-jest.mock('../../../../util/git');
+vi.mock('../../../../util/git');
 
 const formattedMigratedData = Fixtures.getJson(
   './migrated-data-formatted.json',
diff --git a/lib/workers/repository/config-migration/index.spec.ts b/lib/workers/repository/config-migration/index.spec.ts
index 19ae2263ee..8ebc459aff 100644
--- a/lib/workers/repository/config-migration/index.spec.ts
+++ b/lib/workers/repository/config-migration/index.spec.ts
@@ -8,9 +8,9 @@ import { MigratedDataFactory } from './branch/migrated-data';
 import { ensureConfigMigrationPr } from './pr';
 import { configMigration } from './index';
 
-jest.mock('./pr');
-jest.mock('./branch');
-jest.mock('./branch/migrated-data');
+vi.mock('./pr');
+vi.mock('./branch');
+vi.mock('./branch/migrated-data');
 
 const content = Fixtures.getJson('./migrated-data.json', './branch');
 const filename = 'renovate.json';
diff --git a/lib/workers/repository/config-migration/pr/__snapshots__/index.spec.ts.snap b/lib/workers/repository/config-migration/pr/__snapshots__/index.spec.ts.snap
index 1d88bc780b..fdb30956f4 100644
--- a/lib/workers/repository/config-migration/pr/__snapshots__/index.spec.ts.snap
+++ b/lib/workers/repository/config-migration/pr/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/config-migration/pr/index ensureConfigMigrationPr() creates PR for JSON5 config file 1`] = `
+exports[`workers/repository/config-migration/pr/index > ensureConfigMigrationPr() > creates PR for JSON5 config file 1`] = `
 "The Renovate config in this repository needs migrating. Typically this is because one or more configuration options you are using have been renamed.
 
   You don't need to merge this PR right away, because Renovate will continue to migrate these fields internally each time it runs. But later some of these fields may be fully deprecated and the migrations removed. So it's a good idea to merge this migration PR soon. 
@@ -20,7 +20,7 @@ This PR has been generated by [Renovate Bot](https://github.com/renovatebot/reno
 "
 `;
 
-exports[`workers/repository/config-migration/pr/index ensureConfigMigrationPr() creates PR with empty footer and header 1`] = `
+exports[`workers/repository/config-migration/pr/index > ensureConfigMigrationPr() > creates PR with empty footer and header 1`] = `
 "
 
 The Renovate config in this repository needs migrating. Typically this is because one or more configuration options you are using have been renamed.
@@ -42,7 +42,7 @@ The Renovate config in this repository needs migrating. Typically this is becaus
 "
 `;
 
-exports[`workers/repository/config-migration/pr/index ensureConfigMigrationPr() creates PR with footer and header using templating 1`] = `
+exports[`workers/repository/config-migration/pr/index > ensureConfigMigrationPr() > creates PR with footer and header using templating 1`] = `
 "This is a header for platform:github
 
 The Renovate config in this repository needs migrating. Typically this is because one or more configuration options you are using have been renamed.
@@ -64,7 +64,7 @@ And this is a footer for repository:test baseBranch:some-branch
 "
 `;
 
-exports[`workers/repository/config-migration/pr/index ensureConfigMigrationPr() creates PR with footer and header with trailing and leading newlines 1`] = `
+exports[`workers/repository/config-migration/pr/index > ensureConfigMigrationPr() > creates PR with footer and header with trailing and leading newlines 1`] = `
 "
 
 This should not be the first line of the PR
diff --git a/lib/workers/repository/config-migration/pr/index.spec.ts b/lib/workers/repository/config-migration/pr/index.spec.ts
index 162d60b5ce..da2c5f0492 100644
--- a/lib/workers/repository/config-migration/pr/index.spec.ts
+++ b/lib/workers/repository/config-migration/pr/index.spec.ts
@@ -14,7 +14,7 @@ import type { MigratedData } from '../branch/migrated-data';
 import { ensureConfigMigrationPr } from '.';
 
 describe('workers/repository/config-migration/pr/index', () => {
-  const spy = jest.spyOn(platform, 'massageMarkdown');
+  const spy = platform.massageMarkdown;
   const { configFileName, migratedContent } = Fixtures.getJson(
     './migrated-data.json',
   );
diff --git a/lib/workers/repository/dependency-dashboard.spec.ts b/lib/workers/repository/dependency-dashboard.spec.ts
index 4a67016793..458974dd1c 100644
--- a/lib/workers/repository/dependency-dashboard.spec.ts
+++ b/lib/workers/repository/dependency-dashboard.spec.ts
@@ -20,7 +20,7 @@ import { getDashboardMarkdownVulnerabilities } from './dependency-dashboard';
 import { PackageFiles } from './package-files';
 
 const createVulnerabilitiesMock = jest.fn();
-jest.mock('./process/vulnerabilities', () => {
+vi.mock('./process/vulnerabilities', () => {
   return {
     __esModule: true,
     Vulnerabilities: class {
diff --git a/lib/workers/repository/error-config.spec.ts b/lib/workers/repository/error-config.spec.ts
index 0ae61dc68e..65ec016961 100644
--- a/lib/workers/repository/error-config.spec.ts
+++ b/lib/workers/repository/error-config.spec.ts
@@ -10,8 +10,6 @@ import {
   raiseCredentialsWarningIssue,
 } from './error-config';
 
-jest.mock('../../modules/platform');
-
 let config: RenovateConfig;
 
 beforeEach(() => {
diff --git a/lib/workers/repository/error.spec.ts b/lib/workers/repository/error.spec.ts
index abc2dd622c..1277a827ae 100644
--- a/lib/workers/repository/error.spec.ts
+++ b/lib/workers/repository/error.spec.ts
@@ -34,7 +34,7 @@ import {
 import { ExternalHostError } from '../../types/errors/external-host-error';
 import handleError from './error';
 
-jest.mock('./error-config');
+vi.mock('./error-config');
 
 let config: RenovateConfig;
 
diff --git a/lib/workers/repository/extract/__snapshots__/file-match.spec.ts.snap b/lib/workers/repository/extract/__snapshots__/file-match.spec.ts.snap
index ec22a18b22..674a61add3 100644
--- a/lib/workers/repository/extract/__snapshots__/file-match.spec.ts.snap
+++ b/lib/workers/repository/extract/__snapshots__/file-match.spec.ts.snap
@@ -1,37 +1,37 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/extract/file-match filterIgnoredFiles() ignores partial matches 1`] = `
+exports[`workers/repository/extract/file-match > filterIgnoredFiles() > ignores partial matches 1`] = `
 [
   "package.json",
 ]
 `;
 
-exports[`workers/repository/extract/file-match filterIgnoredFiles() returns minimatch matches 1`] = `
+exports[`workers/repository/extract/file-match > filterIgnoredFiles() > returns minimatch matches 1`] = `
 [
   "package.json",
 ]
 `;
 
-exports[`workers/repository/extract/file-match getIncludedFiles() returns exact matches 1`] = `
+exports[`workers/repository/extract/file-match > getIncludedFiles() > returns exact matches 1`] = `
 [
   "frontend/package.json",
 ]
 `;
 
-exports[`workers/repository/extract/file-match getIncludedFiles() returns minimatch matches 1`] = `
+exports[`workers/repository/extract/file-match > getIncludedFiles() > returns minimatch matches 1`] = `
 [
   "frontend/package.json",
 ]
 `;
 
-exports[`workers/repository/extract/file-match getMatchingFiles() deduplicates 1`] = `
+exports[`workers/repository/extract/file-match > getMatchingFiles() > deduplicates 1`] = `
 [
   "frontend/package.json",
   "package.json",
 ]
 `;
 
-exports[`workers/repository/extract/file-match getMatchingFiles() returns npm files 1`] = `
+exports[`workers/repository/extract/file-match > getMatchingFiles() > returns npm files 1`] = `
 [
   "frontend/package.json",
   "package.json",
diff --git a/lib/workers/repository/extract/file-match.spec.ts b/lib/workers/repository/extract/file-match.spec.ts
index 85942c05c3..8894fe7b48 100644
--- a/lib/workers/repository/extract/file-match.spec.ts
+++ b/lib/workers/repository/extract/file-match.spec.ts
@@ -1,7 +1,7 @@
 import type { RenovateConfig } from '../../../../test/util';
 import * as fileMatch from './file-match';
 
-jest.mock('../../../util/git');
+vi.mock('../../../util/git');
 
 describe('workers/repository/extract/file-match', () => {
   const fileList = ['package.json', 'frontend/package.json'];
diff --git a/lib/workers/repository/extract/index.spec.ts b/lib/workers/repository/extract/index.spec.ts
index f769a21419..702402e704 100644
--- a/lib/workers/repository/extract/index.spec.ts
+++ b/lib/workers/repository/extract/index.spec.ts
@@ -6,8 +6,8 @@ import type { PackageFile } from '../../../modules/manager/types';
 import * as _managerFiles from './manager-files';
 import { extractAllDependencies } from '.';
 
-jest.mock('./manager-files');
-jest.mock('../../../util/git');
+vi.mock('./manager-files');
+vi.mock('../../../util/git');
 
 const managerFiles = mocked(_managerFiles);
 
diff --git a/lib/workers/repository/extract/manager-files.spec.ts b/lib/workers/repository/extract/manager-files.spec.ts
index 0b22e14973..d578c4f8de 100644
--- a/lib/workers/repository/extract/manager-files.spec.ts
+++ b/lib/workers/repository/extract/manager-files.spec.ts
@@ -4,9 +4,9 @@ import * as _html from '../../../modules/manager/html';
 import * as _fileMatch from './file-match';
 import { getManagerPackageFiles } from './manager-files';
 
-jest.mock('./file-match');
-jest.mock('../../../modules/manager/html');
-jest.mock('../../../util/fs');
+vi.mock('./file-match');
+vi.mock('../../../modules/manager/html');
+vi.mock('../../../util/fs');
 
 const fileMatch = mocked(_fileMatch);
 const html = mocked(_html);
diff --git a/lib/workers/repository/finalize/prune.spec.ts b/lib/workers/repository/finalize/prune.spec.ts
index 4048a75223..091af7e3b8 100644
--- a/lib/workers/repository/finalize/prune.spec.ts
+++ b/lib/workers/repository/finalize/prune.spec.ts
@@ -4,7 +4,7 @@ import { GlobalConfig } from '../../../config/global';
 import type { Pr } from '../../../modules/platform/types';
 import * as cleanup from './prune';
 
-jest.mock('../../../util/git');
+vi.mock('../../../util/git');
 
 let config: RenovateConfig;
 
diff --git a/lib/workers/repository/finalize/repository-statistics.spec.ts b/lib/workers/repository/finalize/repository-statistics.spec.ts
index 11960e3084..37e49e9ad3 100644
--- a/lib/workers/repository/finalize/repository-statistics.spec.ts
+++ b/lib/workers/repository/finalize/repository-statistics.spec.ts
@@ -15,8 +15,8 @@ import {
   runRenovateRepoStats,
 } from './repository-statistics';
 
-jest.mock('../../../modules/platform/github/pr');
-jest.mock('../../../util/http/github');
+vi.mock('../../../modules/platform/github/pr');
+vi.mock('../../../util/http/github');
 
 const prJson = Fixtures.getJson('./pr-list.json');
 const result = Object.keys(prJson).map((key) => {
diff --git a/lib/workers/repository/index.spec.ts b/lib/workers/repository/index.spec.ts
index 652c15caf2..b32701db7c 100644
--- a/lib/workers/repository/index.spec.ts
+++ b/lib/workers/repository/index.spec.ts
@@ -9,10 +9,10 @@ import { renovateRepository } from '.';
 
 const process = mocked(_process);
 
-jest.mock('./init');
-jest.mock('./process');
-jest.mock('./result');
-jest.mock('./error');
+vi.mock('./init');
+vi.mock('./process');
+vi.mock('./result');
+vi.mock('./error');
 
 describe('workers/repository/index', () => {
   describe('renovateRepository()', () => {
diff --git a/lib/workers/repository/init/__snapshots__/vulnerability.spec.ts.snap b/lib/workers/repository/init/__snapshots__/vulnerability.spec.ts.snap
index 755f67ba3d..25471ebe58 100644
--- a/lib/workers/repository/init/__snapshots__/vulnerability.spec.ts.snap
+++ b/lib/workers/repository/init/__snapshots__/vulnerability.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/init/vulnerability detectVulnerabilityAlerts() returns go alerts 1`] = `
+exports[`workers/repository/init/vulnerability > detectVulnerabilityAlerts() > returns go alerts 1`] = `
 [
   {
     "force": {
@@ -36,7 +36,7 @@ go",
 ]
 `;
 
-exports[`workers/repository/init/vulnerability detectVulnerabilityAlerts() returns maven alerts 1`] = `
+exports[`workers/repository/init/vulnerability > detectVulnerabilityAlerts() > returns maven alerts 1`] = `
 [
   {
     "force": {
@@ -72,7 +72,7 @@ An issue was discovered in FasterXML jackson-databind prior to 2.7.9.4, 2.8.11.2
 ]
 `;
 
-exports[`workers/repository/init/vulnerability detectVulnerabilityAlerts() returns pip alerts 1`] = `
+exports[`workers/repository/init/vulnerability > detectVulnerabilityAlerts() > returns pip alerts 1`] = `
 [
   {
     "force": {
diff --git a/lib/workers/repository/init/index.spec.ts b/lib/workers/repository/init/index.spec.ts
index f36df0329d..39e2a9d0df 100644
--- a/lib/workers/repository/init/index.spec.ts
+++ b/lib/workers/repository/init/index.spec.ts
@@ -8,16 +8,16 @@ import * as _config from './config';
 import * as _merge from './merge';
 import { initRepo } from '.';
 
-jest.mock('../../../util/git');
-jest.mock('../onboarding/branch');
-jest.mock('../configured');
-jest.mock('../init/apis');
-jest.mock('../init/config');
-jest.mock('../init/merge');
-jest.mock('../../../config/secrets');
-jest.mock('../../../modules/platform', () => ({
-  platform: { initRepo: jest.fn() },
-  getPlatformList: jest.fn(),
+vi.mock('../../../util/git');
+vi.mock('../onboarding/branch');
+vi.mock('../configured');
+vi.mock('../init/apis');
+vi.mock('../init/config');
+vi.mock('../init/merge');
+vi.mock('../../../config/secrets');
+vi.mock('../../../modules/platform', () => ({
+  platform: { initRepo: vi.fn() },
+  getPlatformList: vi.fn(),
 }));
 
 const apis = mocked(_apis);
diff --git a/lib/workers/repository/init/inherited.spec.ts b/lib/workers/repository/init/inherited.spec.ts
index c375edee9c..b870c910a5 100644
--- a/lib/workers/repository/init/inherited.spec.ts
+++ b/lib/workers/repository/init/inherited.spec.ts
@@ -10,7 +10,7 @@ import {
 import { logger } from '../../../logger';
 import { mergeInheritedConfig } from './inherited';
 
-jest.mock('../../../config/presets');
+vi.mock('../../../config/presets');
 
 const presets = mocked(presets_);
 
diff --git a/lib/workers/repository/init/merge.spec.ts b/lib/workers/repository/init/merge.spec.ts
index c975e3ee7d..97f2b46411 100644
--- a/lib/workers/repository/init/merge.spec.ts
+++ b/lib/workers/repository/init/merge.spec.ts
@@ -26,9 +26,9 @@ import {
   setNpmTokenInNpmrc,
 } from './merge';
 
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
-jest.mock('../onboarding/branch/onboarding-branch-cache');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../onboarding/branch/onboarding-branch-cache');
 
 const migrate = mocked(_migrate);
 const migrateAndValidate = mocked(_migrateAndValidate);
@@ -43,8 +43,8 @@ beforeEach(() => {
   config.warnings = [];
 });
 
-jest.mock('../../../config/migration');
-jest.mock('../../../config/migrate-validate');
+vi.mock('../../../config/migration');
+vi.mock('../../../config/migrate-validate');
 
 describe('workers/repository/init/merge', () => {
   afterEach(() => {
diff --git a/lib/workers/repository/onboarding/branch/check.spec.ts b/lib/workers/repository/onboarding/branch/check.spec.ts
index 1eb22c0767..e99a33c85f 100644
--- a/lib/workers/repository/onboarding/branch/check.spec.ts
+++ b/lib/workers/repository/onboarding/branch/check.spec.ts
@@ -7,8 +7,8 @@ import * as _cache from '../../../../util/cache/repository';
 import type { LongCommitSha } from '../../../../util/git/types';
 import { isOnboarded } from './check';
 
-jest.mock('../../../../util/cache/repository');
-jest.mock('../../../../util/git');
+vi.mock('../../../../util/cache/repository');
+vi.mock('../../../../util/git');
 
 const cache = mocked(_cache);
 
diff --git a/lib/workers/repository/onboarding/branch/config.spec.ts b/lib/workers/repository/onboarding/branch/config.spec.ts
index 238b8b939c..17ce99014d 100644
--- a/lib/workers/repository/onboarding/branch/config.spec.ts
+++ b/lib/workers/repository/onboarding/branch/config.spec.ts
@@ -5,9 +5,9 @@ import * as presets from '../../../../config/presets/local';
 import { PRESET_DEP_NOT_FOUND } from '../../../../config/presets/util';
 import { getOnboardingConfig, getOnboardingConfigContents } from './config';
 
-jest.mock('../../../../config/presets/local');
+vi.mock('../../../../config/presets/local');
 
-const mockedPresets = presets as jest.Mocked<typeof presets>;
+const mockedPresets = vi.mocked(presets);
 
 describe('workers/repository/onboarding/branch/config', () => {
   let config: RenovateConfig;
diff --git a/lib/workers/repository/onboarding/branch/create.spec.ts b/lib/workers/repository/onboarding/branch/create.spec.ts
index eff82ee09c..39ef37aa7b 100644
--- a/lib/workers/repository/onboarding/branch/create.spec.ts
+++ b/lib/workers/repository/onboarding/branch/create.spec.ts
@@ -3,7 +3,7 @@ import { scm } from '../../../../../test/util';
 import { getConfig } from '../../../../config/defaults';
 import { createOnboardingBranch } from './create';
 
-jest.mock('./config', () => ({
+vi.mock('./config', () => ({
   getOnboardingConfigContents: () =>
     JSON.stringify({
       foo: 'bar',
diff --git a/lib/workers/repository/onboarding/branch/index.spec.ts b/lib/workers/repository/onboarding/branch/index.spec.ts
index 82961dbe7a..e3cae8012d 100644
--- a/lib/workers/repository/onboarding/branch/index.spec.ts
+++ b/lib/workers/repository/onboarding/branch/index.spec.ts
@@ -23,12 +23,12 @@ import { checkOnboardingBranch } from '.';
 
 const configModule: any = _config;
 
-jest.mock('../../../../util/cache/repository');
-jest.mock('../../../../util/fs');
-jest.mock('../../../../util/git');
-jest.mock('./config');
-jest.mock('./rebase');
-jest.mock('./onboarding-branch-cache');
+vi.mock('../../../../util/cache/repository');
+vi.mock('../../../../util/fs');
+vi.mock('../../../../util/git');
+vi.mock('./config');
+vi.mock('./rebase');
+vi.mock('./onboarding-branch-cache');
 
 const cache = mocked(_cache);
 const rebase = mocked(_rebase);
diff --git a/lib/workers/repository/onboarding/branch/onboarding-branch-cache.spec.ts b/lib/workers/repository/onboarding/branch/onboarding-branch-cache.spec.ts
index ed9e9746d4..ecd7d9f703 100644
--- a/lib/workers/repository/onboarding/branch/onboarding-branch-cache.spec.ts
+++ b/lib/workers/repository/onboarding/branch/onboarding-branch-cache.spec.ts
@@ -16,8 +16,8 @@ import {
   setOnboardingConfigDetails,
 } from './onboarding-branch-cache';
 
-jest.mock('../../../../util/cache/repository');
-jest.mock('../../../../util/git');
+vi.mock('../../../../util/cache/repository');
+vi.mock('../../../../util/git');
 const cache = mocked(_cache);
 
 describe('workers/repository/onboarding/branch/onboarding-branch-cache', () => {
diff --git a/lib/workers/repository/onboarding/branch/rebase.spec.ts b/lib/workers/repository/onboarding/branch/rebase.spec.ts
index 5fe8a211cf..bcecde0a78 100644
--- a/lib/workers/repository/onboarding/branch/rebase.spec.ts
+++ b/lib/workers/repository/onboarding/branch/rebase.spec.ts
@@ -9,7 +9,7 @@ import { rebaseOnboardingBranch } from './rebase';
 
 const configModule = mocked(_config);
 
-jest.mock('./config');
+vi.mock('./config');
 
 describe('workers/repository/onboarding/branch/rebase', () => {
   beforeAll(() => {
diff --git a/lib/workers/repository/onboarding/pr/__snapshots__/config-description.spec.ts.snap b/lib/workers/repository/onboarding/pr/__snapshots__/config-description.spec.ts.snap
index 1d338c6d48..1cab8241f1 100644
--- a/lib/workers/repository/onboarding/pr/__snapshots__/config-description.spec.ts.snap
+++ b/lib/workers/repository/onboarding/pr/__snapshots__/config-description.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/onboarding/pr/config-description getConfigDesc() contains the onboardingConfigFileName if set 1`] = `
+exports[`workers/repository/onboarding/pr/config-description > getConfigDesc() > contains the onboardingConfigFileName if set 1`] = `
 "
 ### Configuration Summary
 
@@ -15,7 +15,7 @@ Based on the default config's presets, Renovate will:
 "
 `;
 
-exports[`workers/repository/onboarding/pr/config-description getConfigDesc() falls back to "renovate.json" if onboardingConfigFileName is not set 1`] = `
+exports[`workers/repository/onboarding/pr/config-description > getConfigDesc() > falls back to "renovate.json" if onboardingConfigFileName is not set 1`] = `
 "
 ### Configuration Summary
 
@@ -30,7 +30,7 @@ Based on the default config's presets, Renovate will:
 "
 `;
 
-exports[`workers/repository/onboarding/pr/config-description getConfigDesc() falls back to "renovate.json" if onboardingConfigFileName is not valid 1`] = `
+exports[`workers/repository/onboarding/pr/config-description > getConfigDesc() > falls back to "renovate.json" if onboardingConfigFileName is not valid 1`] = `
 "
 ### Configuration Summary
 
@@ -45,34 +45,34 @@ Based on the default config's presets, Renovate will:
 "
 `;
 
-exports[`workers/repository/onboarding/pr/config-description getConfigDesc() returns a full list 1`] = `
+exports[`workers/repository/onboarding/pr/config-description > getConfigDesc() > include retry/refresh checkbox message only if onboardingRebaseCheckbox is true 1`] = `
 "
 ### Configuration Summary
 
 Based on the default config's presets, Renovate will:
 
   - Start dependency updates only once this onboarding PR is merged
-  - description 1
-  - description two
-  - something else
-  - this is Docker-only
+  - Run Renovate on following schedule: before 5am
 
-🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs.
+🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`.github/renovate.json\` in this branch and select the Retry/Rebase checkbox below. Renovate will update the Pull Request description the next time it runs.
 
 ---
 "
 `;
 
-exports[`workers/repository/onboarding/pr/config-description getConfigDesc() include retry/refresh checkbox message only if onboardingRebaseCheckbox is true 1`] = `
+exports[`workers/repository/onboarding/pr/config-description > getConfigDesc() > returns a full list 1`] = `
 "
 ### Configuration Summary
 
 Based on the default config's presets, Renovate will:
 
   - Start dependency updates only once this onboarding PR is merged
-  - Run Renovate on following schedule: before 5am
+  - description 1
+  - description two
+  - something else
+  - this is Docker-only
 
-🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`.github/renovate.json\` in this branch and select the Retry/Rebase checkbox below. Renovate will update the Pull Request description the next time it runs.
+🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to \`renovate.json\` in this branch. Renovate will update the Pull Request description the next time it runs.
 
 ---
 "
diff --git a/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap b/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap
index 625b52c907..2df66344f2 100644
--- a/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap
+++ b/lib/workers/repository/onboarding/pr/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/onboarding/pr/index ensureOnboardingPr() creates PR with empty footer and header(onboardingRebaseCheckbox="false") 1`] = `
+exports[`workers/repository/onboarding/pr/index > ensureOnboardingPr() > creates PR with empty footer and header(onboardingRebaseCheckbox="false") 1`] = `
 "
 
 Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.
@@ -32,7 +32,7 @@ If you need any further assistance then you can also [request help here](https:/
 "
 `;
 
-exports[`workers/repository/onboarding/pr/index ensureOnboardingPr() creates PR with empty footer and header(onboardingRebaseCheckbox="true") 1`] = `
+exports[`workers/repository/onboarding/pr/index > ensureOnboardingPr() > creates PR with empty footer and header(onboardingRebaseCheckbox="true") 1`] = `
 "
 
 Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.
@@ -69,7 +69,7 @@ If you need any further assistance then you can also [request help here](https:/
 "
 `;
 
-exports[`workers/repository/onboarding/pr/index ensureOnboardingPr() creates PR with footer and header using templating(onboardingRebaseCheckbox="false") 1`] = `
+exports[`workers/repository/onboarding/pr/index > ensureOnboardingPr() > creates PR with footer and header using templating(onboardingRebaseCheckbox="false") 1`] = `
 "This is a header for platform:github
 
 Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.
@@ -101,7 +101,7 @@ And this is a footer for repository:test baseBranch:some-branch
 "
 `;
 
-exports[`workers/repository/onboarding/pr/index ensureOnboardingPr() creates PR with footer and header using templating(onboardingRebaseCheckbox="true") 1`] = `
+exports[`workers/repository/onboarding/pr/index > ensureOnboardingPr() > creates PR with footer and header using templating(onboardingRebaseCheckbox="true") 1`] = `
 "This is a header for platform:github
 
 Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.
@@ -138,7 +138,7 @@ And this is a footer for repository:test baseBranch:some-branch
 "
 `;
 
-exports[`workers/repository/onboarding/pr/index ensureOnboardingPr() creates PR with footer and header with trailing and leading newlines(onboardingRebaseCheckbox="false") 1`] = `
+exports[`workers/repository/onboarding/pr/index > ensureOnboardingPr() > creates PR with footer and header with trailing and leading newlines(onboardingRebaseCheckbox="false") 1`] = `
 "
 
 This should not be the first line of the PR
@@ -175,7 +175,7 @@ There should be several empty lines at the end of the PR
 "
 `;
 
-exports[`workers/repository/onboarding/pr/index ensureOnboardingPr() creates PR with footer and header with trailing and leading newlines(onboardingRebaseCheckbox="true") 1`] = `
+exports[`workers/repository/onboarding/pr/index > ensureOnboardingPr() > creates PR with footer and header with trailing and leading newlines(onboardingRebaseCheckbox="true") 1`] = `
 "
 
 This should not be the first line of the PR
diff --git a/lib/workers/repository/onboarding/pr/index.spec.ts b/lib/workers/repository/onboarding/pr/index.spec.ts
index ecf18987c0..bc2cbe960f 100644
--- a/lib/workers/repository/onboarding/pr/index.spec.ts
+++ b/lib/workers/repository/onboarding/pr/index.spec.ts
@@ -11,7 +11,7 @@ import type { BranchConfig } from '../../../types';
 import { OnboardingState } from '../common';
 import { ensureOnboardingPr } from '.';
 
-jest.mock('../../../../util/git');
+vi.mock('../../../../util/git');
 
 describe('workers/repository/onboarding/pr/index', () => {
   describe('ensureOnboardingPr()', () => {
diff --git a/lib/workers/repository/process/extract-update.spec.ts b/lib/workers/repository/process/extract-update.spec.ts
index 220e9c8535..fe47bec130 100644
--- a/lib/workers/repository/process/extract-update.spec.ts
+++ b/lib/workers/repository/process/extract-update.spec.ts
@@ -16,10 +16,10 @@ import {
 
 const createVulnerabilitiesMock = jest.fn();
 
-jest.mock('./write');
-jest.mock('./sort');
-jest.mock('./fetch');
-jest.mock('./vulnerabilities', () => {
+vi.mock('./write');
+vi.mock('./sort');
+vi.mock('./fetch');
+vi.mock('./vulnerabilities', () => {
   return {
     __esModule: true,
     Vulnerabilities: class {
@@ -29,10 +29,10 @@ jest.mock('./vulnerabilities', () => {
     },
   };
 });
-jest.mock('../updates/branchify');
-jest.mock('../extract');
-jest.mock('../../../util/cache/repository');
-jest.mock('../../../util/git');
+vi.mock('../updates/branchify');
+vi.mock('../extract');
+vi.mock('../../../util/cache/repository');
+vi.mock('../../../util/git');
 
 const branchify = mocked(_branchify);
 const repositoryCache = mocked(_repositoryCache);
diff --git a/lib/workers/repository/process/fetch.spec.ts b/lib/workers/repository/process/fetch.spec.ts
index 0ad23785fe..bea294a28f 100644
--- a/lib/workers/repository/process/fetch.spec.ts
+++ b/lib/workers/repository/process/fetch.spec.ts
@@ -9,7 +9,7 @@ import * as lookup from './lookup';
 
 const lookupUpdates = mocked(lookup).lookupUpdates;
 
-jest.mock('./lookup');
+vi.mock('./lookup');
 
 describe('workers/repository/process/fetch', () => {
   describe('fetchUpdates()', () => {
diff --git a/lib/workers/repository/process/index.spec.ts b/lib/workers/repository/process/index.spec.ts
index 28fb4ad622..990b5b31c1 100644
--- a/lib/workers/repository/process/index.spec.ts
+++ b/lib/workers/repository/process/index.spec.ts
@@ -9,8 +9,8 @@ import * as _extractUpdate from './extract-update';
 import { lookup } from './extract-update';
 import { extractDependencies, updateRepo } from '.';
 
-jest.mock('../../../util/git');
-jest.mock('./extract-update');
+vi.mock('../../../util/git');
+vi.mock('./extract-update');
 
 const extract = mocked(_extractUpdate).extract;
 
diff --git a/lib/workers/repository/process/libyear.spec.ts b/lib/workers/repository/process/libyear.spec.ts
index cbf6182e01..5a001cc9d3 100644
--- a/lib/workers/repository/process/libyear.spec.ts
+++ b/lib/workers/repository/process/libyear.spec.ts
@@ -5,7 +5,7 @@ import type { PackageFile } from '../../../modules/manager/types';
 import type { Timestamp } from '../../../util/timestamp';
 import { calculateLibYears } from './libyear';
 
-jest.mock('../../../instrumentation/reporting');
+vi.mock('../../../instrumentation/reporting');
 
 describe('workers/repository/process/libyear', () => {
   const config: RenovateConfig = {};
diff --git a/lib/workers/repository/process/lookup/__snapshots__/filter-checks.spec.ts.snap b/lib/workers/repository/process/lookup/__snapshots__/filter-checks.spec.ts.snap
index 5bf232ab92..92b550c89b 100644
--- a/lib/workers/repository/process/lookup/__snapshots__/filter-checks.spec.ts.snap
+++ b/lib/workers/repository/process/lookup/__snapshots__/filter-checks.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() picks up minimumConfidence settings from updateType 1`] = `
+exports[`workers/repository/process/lookup/filter-checks > .filterInternalChecks() > picks up minimumConfidence settings from updateType 1`] = `
 {
   "pendingChecks": false,
   "pendingReleases": [
@@ -24,7 +24,7 @@ exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks()
 }
 `;
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() picks up minimumReleaseAge settings from hostRules 1`] = `
+exports[`workers/repository/process/lookup/filter-checks > .filterInternalChecks() > picks up minimumReleaseAge settings from hostRules 1`] = `
 {
   "pendingChecks": false,
   "pendingReleases": [],
@@ -35,7 +35,7 @@ exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks()
 }
 `;
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() picks up minimumReleaseAge settings from updateType 1`] = `
+exports[`workers/repository/process/lookup/filter-checks > .filterInternalChecks() > picks up minimumReleaseAge settings from updateType 1`] = `
 {
   "pendingChecks": false,
   "pendingReleases": [
@@ -51,7 +51,7 @@ exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks()
 }
 `;
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() returns latest release if internalChecksFilter=none 1`] = `
+exports[`workers/repository/process/lookup/filter-checks > .filterInternalChecks() > returns latest release if internalChecksFilter=none 1`] = `
 {
   "pendingChecks": false,
   "pendingReleases": [],
@@ -62,7 +62,7 @@ exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks()
 }
 `;
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() returns non-latest release if internalChecksFilter=flexible and some pass checks 1`] = `
+exports[`workers/repository/process/lookup/filter-checks > .filterInternalChecks() > returns non-latest release if internalChecksFilter=flexible and some pass checks 1`] = `
 {
   "pendingChecks": false,
   "pendingReleases": [
@@ -82,7 +82,7 @@ exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks()
 }
 `;
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() returns non-latest release if internalChecksFilter=strict and some pass checks 1`] = `
+exports[`workers/repository/process/lookup/filter-checks > .filterInternalChecks() > returns non-latest release if internalChecksFilter=strict and some pass checks 1`] = `
 {
   "pendingChecks": false,
   "pendingReleases": [
@@ -102,7 +102,7 @@ exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks()
 }
 `;
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() returns non-pending latest release if internalChecksFilter=flexible and none pass checks 1`] = `
+exports[`workers/repository/process/lookup/filter-checks > .filterInternalChecks() > returns non-pending latest release if internalChecksFilter=flexible and none pass checks 1`] = `
 {
   "pendingChecks": false,
   "pendingReleases": [],
@@ -113,7 +113,7 @@ exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks()
 }
 `;
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() returns pending latest release if internalChecksFilter=strict and none pass checks 1`] = `
+exports[`workers/repository/process/lookup/filter-checks > .filterInternalChecks() > returns pending latest release if internalChecksFilter=strict and none pass checks 1`] = `
 {
   "pendingChecks": true,
   "pendingReleases": [],
diff --git a/lib/workers/repository/process/lookup/filter-checks.spec.ts b/lib/workers/repository/process/lookup/filter-checks.spec.ts
index 37c0a56d66..daeea017bc 100644
--- a/lib/workers/repository/process/lookup/filter-checks.spec.ts
+++ b/lib/workers/repository/process/lookup/filter-checks.spec.ts
@@ -17,13 +17,13 @@ import type { Timestamp } from '../../../../util/timestamp';
 import { filterInternalChecks } from './filter-checks';
 import type { LookupUpdateConfig, UpdateResult } from './types';
 
-jest.mock('../../../../util/date');
+vi.mock('../../../../util/date');
 const dateUtil = mocked(_dateUtil);
 
-jest.mock('../../../../util/merge-confidence');
+vi.mock('../../../../util/merge-confidence');
 const mergeConfidence = mocked(_mergeConfidence);
 
-jest.mock('../../../../modules/datasource/common');
+vi.mock('../../../../modules/datasource/common');
 const { getDatasourceFor } = mocked(_datasourceCommon);
 
 class DummyDatasource extends Datasource {
diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts
index 31fe794392..5148a225dc 100644
--- a/lib/workers/repository/process/lookup/index.spec.ts
+++ b/lib/workers/repository/process/lookup/index.spec.ts
@@ -596,7 +596,7 @@ describe('workers/repository/process/lookup/index', () => {
 
       const res = await lookup.lookupUpdates(config);
 
-      expect(() => res.unwrapOrThrow()).toThrow(Error(CONFIG_VALIDATION));
+      expect(() => res.unwrapOrThrow()).toThrow(CONFIG_VALIDATION);
     });
 
     it('returns patch update even if separate patches not configured', async () => {
diff --git a/lib/workers/repository/process/vulnerabilities.spec.ts b/lib/workers/repository/process/vulnerabilities.spec.ts
index 8922742ae9..f42fd4e6eb 100644
--- a/lib/workers/repository/process/vulnerabilities.spec.ts
+++ b/lib/workers/repository/process/vulnerabilities.spec.ts
@@ -11,7 +11,7 @@ const getVulnerabilitiesMock =
   mockFn<typeof OsvOffline.prototype.getVulnerabilities>();
 const createMock = jest.fn();
 
-jest.mock('@renovatebot/osv-offline', () => {
+vi.mock('@renovatebot/osv-offline', () => {
   return {
     __esModule: true,
     OsvOffline: class {
diff --git a/lib/workers/repository/process/write.spec.ts b/lib/workers/repository/process/write.spec.ts
index 70a8165ffc..baefbce2c0 100644
--- a/lib/workers/repository/process/write.spec.ts
+++ b/lib/workers/repository/process/write.spec.ts
@@ -23,24 +23,23 @@ import {
   writeUpdates,
 } from './write';
 
-jest.mock('../../../util/git');
-jest.mock('../../../util/cache/repository');
+vi.mock('../../../util/git');
+vi.mock('../../../util/cache/repository');
+vi.mock('./limits');
+vi.mock('../update/branch');
 
 const branchWorker = mocked(_branchWorker);
 const limits = mocked(_limits);
 const repoCache = mocked(_repoCache);
 
-branchWorker.processBranch = jest.fn();
-
-limits.getConcurrentPrsCount = jest.fn().mockResolvedValue(0);
-limits.getConcurrentBranchesCount = jest.fn().mockResolvedValue(0);
-limits.getPrHourlyCount = jest.fn().mockResolvedValue(0);
-
 let config: RenovateConfig;
 
 beforeEach(() => {
   config = getConfig();
   repoCache.getCache.mockReturnValue({});
+  limits.getConcurrentPrsCount.mockResolvedValue(0);
+  limits.getConcurrentBranchesCount.mockResolvedValue(0);
+  limits.getPrHourlyCount.mockResolvedValue(0);
 });
 
 describe('workers/repository/process/write', () => {
diff --git a/lib/workers/repository/reconfigure/index.spec.ts b/lib/workers/repository/reconfigure/index.spec.ts
index 52aff264f7..5c7ff97ab5 100644
--- a/lib/workers/repository/reconfigure/index.spec.ts
+++ b/lib/workers/repository/reconfigure/index.spec.ts
@@ -4,7 +4,7 @@ import { GlobalConfig } from '../../../config/global';
 import * as _validate from './validate';
 import { checkReconfigureBranch } from '.';
 
-jest.mock('./validate');
+vi.mock('./validate');
 
 const validate = mocked(_validate);
 
diff --git a/lib/workers/repository/reconfigure/reconfigure-cache.spec.ts b/lib/workers/repository/reconfigure/reconfigure-cache.spec.ts
index 166f69f149..6649c31cae 100644
--- a/lib/workers/repository/reconfigure/reconfigure-cache.spec.ts
+++ b/lib/workers/repository/reconfigure/reconfigure-cache.spec.ts
@@ -6,7 +6,7 @@ import {
   setReconfigureBranchCache,
 } from './reconfigure-cache';
 
-jest.mock('../../../util/cache/repository');
+vi.mock('../../../util/cache/repository');
 
 const cache = mocked(_cache);
 
diff --git a/lib/workers/repository/reconfigure/validate.spec.ts b/lib/workers/repository/reconfigure/validate.spec.ts
index 44525545d0..6cd8371831 100644
--- a/lib/workers/repository/reconfigure/validate.spec.ts
+++ b/lib/workers/repository/reconfigure/validate.spec.ts
@@ -1,4 +1,4 @@
-import { mock } from 'jest-mock-extended';
+import { mock } from 'vitest-mock-extended';
 import type { RenovateConfig } from '../../../../test/util';
 import { fs, git, mocked, partial, platform, scm } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
@@ -9,10 +9,10 @@ import type { LongCommitSha } from '../../../util/git/types';
 import * as _merge from '../init/merge';
 import { validateReconfigureBranch } from './validate';
 
-jest.mock('../../../util/cache/repository');
-jest.mock('../../../util/fs');
-jest.mock('../../../util/git');
-jest.mock('../init/merge');
+vi.mock('../../../util/cache/repository');
+vi.mock('../../../util/fs');
+vi.mock('../../../util/git');
+vi.mock('../init/merge');
 
 const cache = mocked(_cache);
 const merge = mocked(_merge);
diff --git a/lib/workers/repository/update/branch/__snapshots__/get-updated.spec.ts.snap b/lib/workers/repository/update/branch/__snapshots__/get-updated.spec.ts.snap
index eecb58e2d9..cc7ef6876b 100644
--- a/lib/workers/repository/update/branch/__snapshots__/get-updated.spec.ts.snap
+++ b/lib/workers/repository/update/branch/__snapshots__/get-updated.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() bumps versions in autoReplace managers 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > bumps versions in autoReplace managers 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -16,7 +16,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() b
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() bumps versions in updateDependency managers 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > bumps versions in updateDependency managers 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -32,7 +32,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() b
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles autoreplace base updated 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles autoreplace base updated 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -48,7 +48,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles autoreplace branch needs update 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles autoreplace branch needs update 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -64,7 +64,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles content change 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles content change 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -80,7 +80,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles git submodules 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles git submodules 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -96,7 +96,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles isRemediation rebase 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles isRemediation rebase 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -112,7 +112,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles isRemediation success 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles isRemediation success 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -128,7 +128,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles lock file errors 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles lock file errors 1`] = `
 {
   "artifactErrors": [
     {
@@ -149,7 +149,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles lock files 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles lock files 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -171,7 +171,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles lockFileMaintenance 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles lockFileMaintenance 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -187,7 +187,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() handles lockFileMaintenance error 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > handles lockFileMaintenance error 1`] = `
 {
   "artifactErrors": [
     {
@@ -202,7 +202,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() h
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() update artifacts on update-lockfile strategy 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > update artifacts on update-lockfile strategy 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
@@ -224,7 +224,7 @@ exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() u
 }
 `;
 
-exports[`workers/repository/update/branch/get-updated getUpdatedPackageFiles() update artifacts on update-lockfile strategy with no updateLockedDependency 1`] = `
+exports[`workers/repository/update/branch/get-updated > getUpdatedPackageFiles() > update artifacts on update-lockfile strategy with no updateLockedDependency 1`] = `
 {
   "artifactErrors": [],
   "artifactNotices": [],
diff --git a/lib/workers/repository/update/branch/auto-replace.spec.ts b/lib/workers/repository/update/branch/auto-replace.spec.ts
index 03ada2c1e2..e10a4c0180 100644
--- a/lib/workers/repository/update/branch/auto-replace.spec.ts
+++ b/lib/workers/repository/update/branch/auto-replace.spec.ts
@@ -12,7 +12,7 @@ const sampleHtml = Fixtures.get(
   `../../../../modules/manager/html`,
 );
 
-jest.mock('../../../../util/fs');
+vi.mock('../../../../util/fs');
 
 describe('workers/repository/update/branch/auto-replace', () => {
   describe('doAutoReplace', () => {
diff --git a/lib/workers/repository/update/branch/automerge.spec.ts b/lib/workers/repository/update/branch/automerge.spec.ts
index aad62addb5..cf5ef50e3f 100644
--- a/lib/workers/repository/update/branch/automerge.spec.ts
+++ b/lib/workers/repository/update/branch/automerge.spec.ts
@@ -5,7 +5,7 @@ import type { Pr } from '../../../../modules/platform/types';
 import * as schedule from '../branch/schedule';
 import { tryBranchAutomerge } from './automerge';
 
-jest.mock('../../../../util/git');
+vi.mock('../../../../util/git');
 
 describe('workers/repository/update/branch/automerge', () => {
   describe('tryBranchAutomerge', () => {
diff --git a/lib/workers/repository/update/branch/execute-post-upgrade-commands.spec.ts b/lib/workers/repository/update/branch/execute-post-upgrade-commands.spec.ts
index fc5210e2ac..0a4c335cc6 100644
--- a/lib/workers/repository/update/branch/execute-post-upgrade-commands.spec.ts
+++ b/lib/workers/repository/update/branch/execute-post-upgrade-commands.spec.ts
@@ -4,8 +4,8 @@ import type { StatusResult } from '../../../../util/git/types';
 import type { BranchConfig, BranchUpgradeConfig } from '../../../types';
 import * as postUpgradeCommands from './execute-post-upgrade-commands';
 
-jest.mock('../../../../util/fs');
-jest.mock('../../../../util/git');
+vi.mock('../../../../util/fs');
+vi.mock('../../../../util/git');
 
 describe('workers/repository/update/branch/execute-post-upgrade-commands', () => {
   describe('postUpgradeCommandsExecutor', () => {
diff --git a/lib/workers/repository/update/branch/get-updated.spec.ts b/lib/workers/repository/update/branch/get-updated.spec.ts
index 08a037138a..009aaa264b 100644
--- a/lib/workers/repository/update/branch/get-updated.spec.ts
+++ b/lib/workers/repository/update/branch/get-updated.spec.ts
@@ -28,18 +28,18 @@ const pep621 = mocked(_pep621);
 const pipCompile = mocked(_pipCompile);
 const poetry = mocked(_poetry);
 
-jest.mock('../../../../modules/manager/bundler');
-jest.mock('../../../../modules/manager/composer');
-jest.mock('../../../../modules/manager/helmv3');
-jest.mock('../../../../modules/manager/npm');
-jest.mock('../../../../modules/manager/git-submodules');
-jest.mock('../../../../modules/manager/gomod', () => mockDeep());
-jest.mock('../../../../modules/manager/batect-wrapper');
-jest.mock('../../../../modules/manager/pep621');
-jest.mock('../../../../modules/manager/pip-compile');
-jest.mock('../../../../modules/manager/poetry');
-jest.mock('../../../../util/git');
-jest.mock('./auto-replace');
+vi.mock('../../../../modules/manager/bundler');
+vi.mock('../../../../modules/manager/composer');
+vi.mock('../../../../modules/manager/helmv3');
+vi.mock('../../../../modules/manager/npm');
+vi.mock('../../../../modules/manager/git-submodules');
+vi.mock('../../../../modules/manager/gomod', () => mockDeep());
+vi.mock('../../../../modules/manager/batect-wrapper');
+vi.mock('../../../../modules/manager/pep621');
+vi.mock('../../../../modules/manager/pip-compile');
+vi.mock('../../../../modules/manager/poetry');
+vi.mock('../../../../util/git');
+vi.mock('./auto-replace');
 
 describe('workers/repository/update/branch/get-updated', () => {
   describe('getUpdatedPackageFiles()', () => {
diff --git a/lib/workers/repository/update/branch/index.spec.ts b/lib/workers/repository/update/branch/index.spec.ts
index feddb9d5c3..c910e7e66b 100644
--- a/lib/workers/repository/update/branch/index.spec.ts
+++ b/lib/workers/repository/update/branch/index.spec.ts
@@ -51,23 +51,23 @@ import * as _reuse from './reuse';
 import * as _schedule from './schedule';
 import * as branchWorker from '.';
 
-jest.mock('./get-updated');
-jest.mock('./schedule');
-jest.mock('./check-existing');
-jest.mock('./reuse');
-jest.mock('../../../../modules/manager/npm/post-update');
-jest.mock('./automerge');
-jest.mock('./commit');
-jest.mock('../pr');
-jest.mock('../pr/automerge');
-jest.mock('../../changelog');
-jest.mock('../../../../util/exec');
-jest.mock('../../../../util/merge-confidence');
-jest.mock('../../../../util/sanitize');
-jest.mock('../../../../util/fs');
-jest.mock('../../../../util/git');
-jest.mock('../../../global/limits');
-jest.mock('../../../../util/cache/repository');
+vi.mock('./get-updated');
+vi.mock('./schedule');
+vi.mock('./check-existing');
+vi.mock('./reuse');
+vi.mock('../../../../modules/manager/npm/post-update');
+vi.mock('./automerge');
+vi.mock('./commit');
+vi.mock('../pr');
+vi.mock('../pr/automerge');
+vi.mock('../../changelog');
+vi.mock('../../../../util/exec');
+vi.mock('../../../../util/merge-confidence');
+vi.mock('../../../../util/sanitize');
+vi.mock('../../../../util/fs');
+vi.mock('../../../../util/git');
+vi.mock('../../../global/limits');
+vi.mock('../../../../util/cache/repository');
 
 const getUpdated = mocked(_getUpdated);
 const schedule = mocked(_schedule);
@@ -145,7 +145,6 @@ describe('workers/repository/update/branch/index', () => {
         usePlatformAutomerge: true,
       });
       GlobalConfig.set(adminConfig);
-      // TODO: fix types, jest is using wrong overload (#22198)
       sanitize.sanitize.mockImplementation((input) => input!);
       repoCache.getCache.mockReturnValue({});
     });
diff --git a/lib/workers/repository/update/branch/lock-files/index.spec.ts b/lib/workers/repository/update/branch/lock-files/index.spec.ts
index 509b5f4609..b8ff010863 100644
--- a/lib/workers/repository/update/branch/lock-files/index.spec.ts
+++ b/lib/workers/repository/update/branch/lock-files/index.spec.ts
@@ -14,12 +14,9 @@ const config: PostUpdateConfig = {
 
 const hostRules = mocked(_hostRules);
 
-jest.mock('../../../../../util/git');
-jest.mock('../../../../../util/fs');
-
-hostRules.find = jest.fn((_) => ({
-  token: 'abc',
-}));
+vi.mock('../../../../../util/git');
+vi.mock('../../../../../util/fs');
+vi.mock('../../../../../util/host-rules');
 
 const { writeUpdatedPackageFiles, getAdditionalFiles } = lockFiles;
 
@@ -29,6 +26,9 @@ describe('workers/repository/update/branch/lock-files/index', () => {
       GlobalConfig.set({
         localDir: 'some-tmp-dir',
       });
+      hostRules.find.mockImplementation((_) => ({
+        token: 'abc',
+      }));
     });
 
     it('returns if no updated packageFiles', async () => {
diff --git a/lib/workers/repository/update/pr/body/changelogs.spec.ts b/lib/workers/repository/update/pr/body/changelogs.spec.ts
index bcdb38ebab..7ef68efb75 100644
--- a/lib/workers/repository/update/pr/body/changelogs.spec.ts
+++ b/lib/workers/repository/update/pr/body/changelogs.spec.ts
@@ -2,7 +2,7 @@ import { mocked } from '../../../../../../test/util';
 import * as _template from '../../../../../util/template';
 import { getChangelogs } from './changelogs';
 
-jest.mock('../../../../../util/template');
+vi.mock('../../../../../util/template');
 const template = mocked(_template);
 
 describe('workers/repository/update/pr/body/changelogs', () => {
diff --git a/lib/workers/repository/update/pr/body/footer.spec.ts b/lib/workers/repository/update/pr/body/footer.spec.ts
index 178e2b2dfe..40d5eb90fa 100644
--- a/lib/workers/repository/update/pr/body/footer.spec.ts
+++ b/lib/workers/repository/update/pr/body/footer.spec.ts
@@ -2,7 +2,7 @@ import { mocked } from '../../../../../../test/util';
 import * as _template from '../../../../../util/template';
 import { getPrFooter } from './footer';
 
-jest.mock('../../../../../util/template');
+vi.mock('../../../../../util/template');
 const template = mocked(_template);
 
 describe('workers/repository/update/pr/body/footer', () => {
diff --git a/lib/workers/repository/update/pr/body/header.spec.ts b/lib/workers/repository/update/pr/body/header.spec.ts
index b4ed57f545..1a2302c43e 100644
--- a/lib/workers/repository/update/pr/body/header.spec.ts
+++ b/lib/workers/repository/update/pr/body/header.spec.ts
@@ -2,7 +2,7 @@ import { mocked } from '../../../../../../test/util';
 import * as _template from '../../../../../util/template';
 import { getPrHeader } from './header';
 
-jest.mock('../../../../../util/template');
+vi.mock('../../../../../util/template');
 const template = mocked(_template);
 
 describe('workers/repository/update/pr/body/header', () => {
diff --git a/lib/workers/repository/update/pr/body/index.spec.ts b/lib/workers/repository/update/pr/body/index.spec.ts
index 0308e4d8c2..7454b505ee 100644
--- a/lib/workers/repository/update/pr/body/index.spec.ts
+++ b/lib/workers/repository/update/pr/body/index.spec.ts
@@ -11,28 +11,28 @@ import * as _notes from './notes';
 import * as _table from './updates-table';
 import { getPrBody } from '.';
 
-jest.mock('./changelogs');
+vi.mock('./changelogs');
 const changelogs = mocked(_changelogs);
 
-jest.mock('./config-description');
+vi.mock('./config-description');
 const configDescription = mocked(_configDescription);
 
-jest.mock('./controls');
+vi.mock('./controls');
 const controls = mocked(_controls);
 
-jest.mock('./footer');
+vi.mock('./footer');
 const footer = mocked(_footer);
 
-jest.mock('./header');
+vi.mock('./header');
 const header = mocked(_header);
 
-jest.mock('./notes');
+vi.mock('./notes');
 const notes = mocked(_notes);
 
-jest.mock('./updates-table');
+vi.mock('./updates-table');
 const table = mocked(_table);
 
-jest.mock('../../../../../util/template');
+vi.mock('../../../../../util/template');
 const template = mocked(_template);
 
 describe('workers/repository/update/pr/body/index', () => {
diff --git a/lib/workers/repository/update/pr/body/notes.spec.ts b/lib/workers/repository/update/pr/body/notes.spec.ts
index 3345fc0fac..25473d15bd 100644
--- a/lib/workers/repository/update/pr/body/notes.spec.ts
+++ b/lib/workers/repository/update/pr/body/notes.spec.ts
@@ -2,7 +2,7 @@ import { mocked } from '../../../../../../test/util';
 import * as _template from '../../../../../util/template';
 import { getPrExtraNotes, getPrNotes } from './notes';
 
-jest.mock('../../../../../util/template');
+vi.mock('../../../../../util/template');
 const template = mocked(_template);
 
 describe('workers/repository/update/pr/body/notes', () => {
diff --git a/lib/workers/repository/update/pr/changelog/__snapshots__/index.spec.ts.snap b/lib/workers/repository/update/pr/changelog/__snapshots__/index.spec.ts.snap
index cca6fc27ff..3508330904 100644
--- a/lib/workers/repository/update/pr/changelog/__snapshots__/index.spec.ts.snap
+++ b/lib/workers/repository/update/pr/changelog/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/update/pr/changelog/index getChangeLogJSON filters unnecessary warns 1`] = `
+exports[`workers/repository/update/pr/changelog/index > getChangeLogJSON > filters unnecessary warns 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -59,7 +59,7 @@ exports[`workers/repository/update/pr/changelog/index getChangeLogJSON filters u
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/index getChangeLogJSON supports github enterprise and github enterprise changelog 1`] = `
+exports[`workers/repository/update/pr/changelog/index > getChangeLogJSON > supports github enterprise and github enterprise changelog 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -118,7 +118,7 @@ exports[`workers/repository/update/pr/changelog/index getChangeLogJSON supports
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/index getChangeLogJSON supports github enterprise and github.com changelog 1`] = `
+exports[`workers/repository/update/pr/changelog/index > getChangeLogJSON > supports github enterprise and github.com changelog 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -177,7 +177,7 @@ exports[`workers/repository/update/pr/changelog/index getChangeLogJSON supports
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/index getChangeLogJSON supports github.com and github enterprise changelog 1`] = `
+exports[`workers/repository/update/pr/changelog/index > getChangeLogJSON > supports github.com and github enterprise changelog 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -236,7 +236,7 @@ exports[`workers/repository/update/pr/changelog/index getChangeLogJSON supports
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/index getChangeLogJSON supports node engines 1`] = `
+exports[`workers/repository/update/pr/changelog/index > getChangeLogJSON > supports node engines 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -295,7 +295,7 @@ exports[`workers/repository/update/pr/changelog/index getChangeLogJSON supports
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/index getChangeLogJSON uses GitHub tags 1`] = `
+exports[`workers/repository/update/pr/changelog/index > getChangeLogJSON > uses GitHub tags 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -359,7 +359,7 @@ exports[`workers/repository/update/pr/changelog/index getChangeLogJSON uses GitH
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/index getChangeLogJSON works without Github 1`] = `
+exports[`workers/repository/update/pr/changelog/index > getChangeLogJSON > works without Github 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
diff --git a/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap b/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap
index c0278ad6e0..2f639fdd4a 100644
--- a/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap
+++ b/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() ReleaseNotes Correctness handles gitlab sourceDirectory 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > ReleaseNotes Correctness > handles gitlab sourceDirectory 1`] = `
 {
   "body": "-   add new auth, fix accept header and base path in mock
 
@@ -15,7 +15,7 @@ See merge request itentialopensource/adapter-utils!177
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() ReleaseNotes Correctness parses adapter-utils 4.33.0 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > ReleaseNotes Correctness > parses adapter-utils 4.33.0 1`] = `
 {
   "body": "-   add new auth, fix accept header and base path in mock
 
@@ -30,7 +30,7 @@ See merge request itentialopensource/adapter-utils!177
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() ReleaseNotes Correctness parses yargs 15.2.0 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > ReleaseNotes Correctness > parses yargs 15.2.0 1`] = `
 {
   "body": "##### âš  BREAKING CHANGES
 
@@ -61,7 +61,7 @@ exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd(
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() ReleaseNotes Correctness parses yargs 15.3.0 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > ReleaseNotes Correctness > parses yargs 15.3.0 1`] = `
 {
   "body": "##### Features
 
@@ -77,7 +77,7 @@ exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd(
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() handles github sourceDirectory 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > handles github sourceDirectory 1`] = `
 {
   "body": "-   Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370).
 -   Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368).
@@ -87,7 +87,7 @@ exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd(
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() parses angular.js 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > parses angular.js 1`] = `
 {
   "body": "#### Bug Fixes
 
@@ -118,7 +118,7 @@ exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd(
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() parses gitlab.com/gitlab-org/gitter/webapp 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > parses gitlab.com/gitlab-org/gitter/webapp 1`] = `
 {
   "body": "-   Removing markup from a part of the French translation, <https://gitlab.com/gitlab-org/gitter/webapp/-/merge_requests/1878>
 -   Fix typo documentation -> documentation, <https://gitlab.com/gitlab-org/gitter/webapp/-/merge_requests/1880>
@@ -135,7 +135,7 @@ exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd(
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() parses jest 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > parses jest 1`] = `
 {
   "body": "##### Fixes
 
@@ -328,7 +328,7 @@ exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd(
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() parses js-yaml 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > parses js-yaml 1`] = `
 {
   "body": "-   Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370).
 -   Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368).
@@ -338,7 +338,7 @@ exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd(
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() parses self hosted gitlab 1`] = `
+exports[`workers/repository/update/pr/changelog/release-notes > getReleaseNotesMd() > parses self hosted gitlab 1`] = `
 {
   "body": "-   Removing markup from a part of the French translation, <https://gitlab.com/gitlab-org/gitter/webapp/-/merge_requests/1878>
 -   Fix typo documentation -> documentation, <https://gitlab.com/gitlab-org/gitter/webapp/-/merge_requests/1880>
diff --git a/lib/workers/repository/update/pr/changelog/github/__snapshots__/index.spec.ts.snap b/lib/workers/repository/update/pr/changelog/github/__snapshots__/index.spec.ts.snap
index 59fa65d000..c916193973 100644
--- a/lib/workers/repository/update/pr/changelog/github/__snapshots__/index.spec.ts.snap
+++ b/lib/workers/repository/update/pr/changelog/github/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON filters unnecessary warns 1`] = `
+exports[`workers/repository/update/pr/changelog/github/index > getChangeLogJSON > filters unnecessary warns 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -59,7 +59,7 @@ exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON fi
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON supports github enterprise and github enterprise changelog 1`] = `
+exports[`workers/repository/update/pr/changelog/github/index > getChangeLogJSON > supports github enterprise and github enterprise changelog 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -118,7 +118,7 @@ exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON su
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON supports github enterprise and github.com changelog 1`] = `
+exports[`workers/repository/update/pr/changelog/github/index > getChangeLogJSON > supports github enterprise and github.com changelog 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -177,7 +177,7 @@ exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON su
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON supports node engines 1`] = `
+exports[`workers/repository/update/pr/changelog/github/index > getChangeLogJSON > supports node engines 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -236,7 +236,7 @@ exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON su
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON uses GitHub tags 1`] = `
+exports[`workers/repository/update/pr/changelog/github/index > getChangeLogJSON > uses GitHub tags 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -295,7 +295,7 @@ exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON us
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/github/index getChangeLogJSON works without Github 1`] = `
+exports[`workers/repository/update/pr/changelog/github/index > getChangeLogJSON > works without Github 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
diff --git a/lib/workers/repository/update/pr/changelog/github/index.spec.ts b/lib/workers/repository/update/pr/changelog/github/index.spec.ts
index b5a3523ca1..79b5b8219e 100644
--- a/lib/workers/repository/update/pr/changelog/github/index.spec.ts
+++ b/lib/workers/repository/update/pr/changelog/github/index.spec.ts
@@ -9,7 +9,7 @@ import * as hostRules from '../../../../../../util/host-rules';
 import type { Timestamp } from '../../../../../../util/timestamp';
 import type { BranchUpgradeConfig } from '../../../../../types';
 
-jest.mock('../../../../../../modules/datasource/npm');
+vi.mock('../../../../../../modules/datasource/npm');
 
 const upgrade = partial<BranchUpgradeConfig>({
   manager: 'some-manager',
diff --git a/lib/workers/repository/update/pr/changelog/gitlab/__snapshots__/index.spec.ts.snap b/lib/workers/repository/update/pr/changelog/gitlab/__snapshots__/index.spec.ts.snap
index 20133cafc0..11be2dfccf 100644
--- a/lib/workers/repository/update/pr/changelog/gitlab/__snapshots__/index.spec.ts.snap
+++ b/lib/workers/repository/update/pr/changelog/gitlab/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON handles empty GitLab tags response 1`] = `
+exports[`workers/repository/update/pr/changelog/gitlab/index > getChangeLogJSON > handles empty GitLab tags response 1`] = `
 {
   "hasReleaseNotes": false,
   "project": {
@@ -49,7 +49,7 @@ exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON ha
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON supports gitlab enterprise and gitlab enterprise changelog 1`] = `
+exports[`workers/repository/update/pr/changelog/gitlab/index > getChangeLogJSON > supports gitlab enterprise and gitlab enterprise changelog 1`] = `
 {
   "hasReleaseNotes": false,
   "project": {
@@ -98,7 +98,7 @@ exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON su
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON supports self-hosted gitlab changelog 1`] = `
+exports[`workers/repository/update/pr/changelog/gitlab/index > getChangeLogJSON > supports self-hosted gitlab changelog 1`] = `
 {
   "hasReleaseNotes": false,
   "project": {
@@ -147,7 +147,7 @@ exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON su
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON uses GitLab tags 1`] = `
+exports[`workers/repository/update/pr/changelog/gitlab/index > getChangeLogJSON > uses GitLab tags 1`] = `
 {
   "hasReleaseNotes": true,
   "project": {
@@ -216,7 +216,7 @@ exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON us
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON uses GitLab tags with error 1`] = `
+exports[`workers/repository/update/pr/changelog/gitlab/index > getChangeLogJSON > uses GitLab tags with error 1`] = `
 {
   "hasReleaseNotes": false,
   "project": {
@@ -265,7 +265,7 @@ exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON us
 }
 `;
 
-exports[`workers/repository/update/pr/changelog/gitlab/index getChangeLogJSON works without GitLab 1`] = `
+exports[`workers/repository/update/pr/changelog/gitlab/index > getChangeLogJSON > works without GitLab 1`] = `
 {
   "hasReleaseNotes": false,
   "project": {
diff --git a/lib/workers/repository/update/pr/changelog/index.spec.ts b/lib/workers/repository/update/pr/changelog/index.spec.ts
index f74d1cbc1a..4f0d4f375d 100644
--- a/lib/workers/repository/update/pr/changelog/index.spec.ts
+++ b/lib/workers/repository/update/pr/changelog/index.spec.ts
@@ -9,13 +9,15 @@ import type { BranchConfig } from '../../../../types';
 import * as releases from './releases';
 import { getChangeLogJSON } from '.';
 
-jest.mock('../../../../../modules/datasource/npm');
+vi.mock('../../../../../modules/datasource/npm');
+vi.mock('../../../../../util/github/graphql');
+vi.mock('./releases', { spy: true });
 
 const githubApiHost = 'https://api.github.com';
 
-const githubTagsMock = jest.spyOn(githubGraphql, 'queryTags');
-const githubReleasesMock = jest.spyOn(githubGraphql, 'queryReleases');
-const getInRangeReleasesMock = jest.spyOn(releases, 'getInRangeReleases');
+const githubTagsMock = vi.mocked(githubGraphql).queryTags;
+const githubReleasesMock = vi.mocked(githubGraphql).queryReleases;
+const getInRangeReleasesMock = vi.mocked(releases).getInRangeReleases;
 
 const upgrade = partial<BranchConfig>({
   endpoint: 'https://api.github.com/',
diff --git a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts
index 42534bb5bc..fc7091a85e 100644
--- a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts
+++ b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts
@@ -25,7 +25,7 @@ import type {
   ChangeLogResult,
 } from './types';
 
-jest.mock('../../../../../util/host-rules', () => mockDeep());
+vi.mock('../../../../../util/host-rules', () => mockDeep());
 
 const hostRules = mocked(_hostRules);
 
@@ -1182,7 +1182,6 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('parses gitlab.com/gitlab-org/gitter/webapp', async () => {
-      jest.setTimeout(0);
       httpMock
         .scope('https://api.gitlab.com/')
         .get(
@@ -1212,7 +1211,6 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
 
     it('parses self hosted gitlab', async () => {
       hostRules.find.mockReturnValue({ token: 'some-token' });
-      jest.setTimeout(0);
       httpMock
         .scope('https://my.custom.domain/')
         .get(
diff --git a/lib/workers/repository/update/pr/code-owners.spec.ts b/lib/workers/repository/update/pr/code-owners.spec.ts
index 4e45521a2d..043f2d3c11 100644
--- a/lib/workers/repository/update/pr/code-owners.spec.ts
+++ b/lib/workers/repository/update/pr/code-owners.spec.ts
@@ -4,8 +4,8 @@ import { fs, git } from '../../../../../test/util';
 import type { Pr } from '../../../../modules/platform';
 import { codeOwnersForPr } from './code-owners';
 
-jest.mock('../../../../util/fs');
-jest.mock('../../../../util/git');
+vi.mock('../../../../util/fs');
+vi.mock('../../../../util/git');
 
 describe('workers/repository/update/pr/code-owners', () => {
   describe('codeOwnersForPr', () => {
@@ -258,7 +258,6 @@ describe('workers/repository/update/pr/code-owners', () => {
     ];
     codeOwnerFilePaths.forEach((codeOwnerFilePath) => {
       it(`detects code owner file at '${codeOwnerFilePath}'`, async () => {
-        // TODO: fix types, jest is using wrong overload (#22198)
         fs.readLocalFile.mockImplementation((path): Promise<any> => {
           if (path === codeOwnerFilePath) {
             return Promise.resolve(['* @mike'].join('\n'));
diff --git a/lib/workers/repository/update/pr/index.spec.ts b/lib/workers/repository/update/pr/index.spec.ts
index 20de0385e3..d43e09ec20 100644
--- a/lib/workers/repository/update/pr/index.spec.ts
+++ b/lib/workers/repository/update/pr/index.spec.ts
@@ -31,25 +31,25 @@ import * as _prCache from './pr-cache';
 import { generatePrBodyFingerprintConfig } from './pr-fingerprint';
 import { ensurePr } from '.';
 
-jest.mock('../../../../util/git');
-jest.mock('../../changelog');
+vi.mock('../../../../util/git');
+vi.mock('../../changelog');
 
-jest.mock('../../../global/limits');
+vi.mock('../../../global/limits');
 const limits = mocked(_limits);
 
-jest.mock('../branch/status-checks');
+vi.mock('../branch/status-checks');
 const checks = mocked(_statusChecks);
 
-jest.mock('./body');
+vi.mock('./body');
 const prBody = mocked(_prBody);
 
-jest.mock('./participants');
+vi.mock('./participants');
 const participants = mocked(_participants);
 
-jest.mock('../../../../modules/platform/comment');
+vi.mock('../../../../modules/platform/comment');
 const comment = mocked(_comment);
 
-jest.mock('./pr-cache');
+vi.mock('./pr-cache');
 const prCache = mocked(_prCache);
 
 describe('workers/repository/update/pr/index', () => {
@@ -463,7 +463,7 @@ describe('workers/repository/update/pr/index', () => {
         });
       });
 
-      it('ignores reviewable content ', async () => {
+      it('ignores reviewable content', async () => {
         // See: https://reviewable.io/
 
         const reviewableContent =
diff --git a/lib/workers/repository/update/pr/participants.spec.ts b/lib/workers/repository/update/pr/participants.spec.ts
index b74e108a47..f2a4435227 100644
--- a/lib/workers/repository/update/pr/participants.spec.ts
+++ b/lib/workers/repository/update/pr/participants.spec.ts
@@ -6,10 +6,10 @@ import * as _util from '../../../../util/sample';
 import * as _codeOwners from './code-owners';
 import { addParticipants } from './participants';
 
-jest.mock('../../../../util/sample');
+vi.mock('../../../../util/sample');
 const util = mocked(_util);
 
-jest.mock('./code-owners');
+vi.mock('./code-owners');
 const codeOwners = mocked(_codeOwners);
 
 describe('workers/repository/update/pr/participants', () => {
diff --git a/lib/workers/repository/update/pr/pr-cache.spec.ts b/lib/workers/repository/update/pr/pr-cache.spec.ts
index 3aaea8cc63..afbb116ad1 100644
--- a/lib/workers/repository/update/pr/pr-cache.spec.ts
+++ b/lib/workers/repository/update/pr/pr-cache.spec.ts
@@ -6,7 +6,7 @@ import type {
 } from '../../../../util/cache/repository/types';
 import { getPrCache, setPrCache } from './pr-cache';
 
-jest.mock('../../../../util/cache/repository');
+vi.mock('../../../../util/cache/repository');
 const cache = mocked(_cache);
 
 describe('workers/repository/update/pr/pr-cache', () => {
diff --git a/lib/workers/repository/updates/__snapshots__/generate.spec.ts.snap b/lib/workers/repository/updates/__snapshots__/generate.spec.ts.snap
index 2bf6c1fbc2..ce17e9898a 100644
--- a/lib/workers/repository/updates/__snapshots__/generate.spec.ts.snap
+++ b/lib/workers/repository/updates/__snapshots__/generate.spec.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`workers/repository/updates/generate generateBranchConfig() handles @types specially (reversed) 1`] = `
+exports[`workers/repository/updates/generate > generateBranchConfig() > handles @types specially (reversed) 1`] = `
 {
   "addLabels": [],
   "automerge": false,
@@ -83,13 +83,18 @@ exports[`workers/repository/updates/generate generateBranchConfig() handles @typ
 }
 `;
 
-exports[`workers/repository/updates/generate generateBranchConfig() handles @types specially 1`] = `
+exports[`workers/repository/updates/generate > generateBranchConfig() > handles @types specially 1`] = `
 {
   "addLabels": [],
   "automerge": false,
   "branchName": "some-branch",
   "commitBodyTable": true,
-  "commitMessage": "\\n\\n| datasource | package         | from  | to    |\\n| ---------- | --------------- | ----- | ----- |\\n| npm        | @types/some-dep | 0.5.7 | 0.5.8 |\\n",
+  "commitMessage": "
+
+| datasource | package         | from  | to    |
+| ---------- | --------------- | ----- | ----- |
+| npm        | @types/some-dep | 0.5.7 | 0.5.8 |
+",
   "constraints": {},
   "datasource": "npm",
   "depName": "some-dep",
@@ -166,7 +171,7 @@ exports[`workers/repository/updates/generate generateBranchConfig() handles @typ
 }
 `;
 
-exports[`workers/repository/updates/generate generateBranchConfig() handles lockFileMaintenance 1`] = `
+exports[`workers/repository/updates/generate > generateBranchConfig() > handles lockFileMaintenance 1`] = `
 {
   "addLabels": [],
   "automerge": false,
@@ -204,7 +209,7 @@ exports[`workers/repository/updates/generate generateBranchConfig() handles lock
 }
 `;
 
-exports[`workers/repository/updates/generate generateBranchConfig() handles lockFileUpdate 1`] = `
+exports[`workers/repository/updates/generate > generateBranchConfig() > handles lockFileUpdate 1`] = `
 {
   "addLabels": [],
   "automerge": false,
diff --git a/lib/workers/repository/updates/branchify.spec.ts b/lib/workers/repository/updates/branchify.spec.ts
index a4bcb1fb5e..e079802169 100644
--- a/lib/workers/repository/updates/branchify.spec.ts
+++ b/lib/workers/repository/updates/branchify.spec.ts
@@ -8,8 +8,8 @@ import * as _flatten from './flatten';
 const flattenUpdates = mocked(_flatten).flattenUpdates;
 const embedChangelogs = mocked(_changelog).embedChangelogs;
 
-jest.mock('./flatten');
-jest.mock('../changelog');
+vi.mock('./flatten');
+vi.mock('../changelog');
 
 let config: RenovateConfig;
 
diff --git a/lib/workers/repository/updates/flatten.spec.ts b/lib/workers/repository/updates/flatten.spec.ts
index 2503377a59..9dec9e91a9 100644
--- a/lib/workers/repository/updates/flatten.spec.ts
+++ b/lib/workers/repository/updates/flatten.spec.ts
@@ -3,7 +3,7 @@ import type { RenovateConfig } from '../../../../test/util';
 import { getConfig } from '../../../config/defaults';
 import { flattenUpdates, sanitizeDepName } from './flatten';
 
-jest.mock('../../../util/git/semantic');
+vi.mock('../../../util/git/semantic');
 
 let config: RenovateConfig;
 
diff --git a/package.json b/package.json
index 1b6e3b931c..8133c62cd6 100644
--- a/package.json
+++ b/package.json
@@ -20,15 +20,16 @@
     "doc-fix": "run-s markdown-lint-fix prettier-fix",
     "doc-fix-everything": "run-s doc-fix doc-fence-check lint-documentation",
     "doc-fence-check": "node tools/check-fenced-code.mjs",
-    "lint-documentation": "jest --coverage false test/docs/**.spec.ts",
-    "lint-other": "jest --coverage false test/other/**.spec.ts",
+    "lint-documentation": "vitest run --coverage false test/docs/**.spec.ts",
+    "lint-other": "vitest run --coverage false test/other/**.spec.ts",
     "eslint": "eslint . --cache --cache-location .cache/eslint",
     "eslint-fix": "eslint --cache --cache-location .cache/eslint --fix .",
     "eslint-ci": "eslint . --cache --cache-strategy content --cache-location .cache/eslint --format gha",
     "generate": "run-s 'generate:*'",
     "generate:imports": "node tools/generate-imports.mjs",
     "git-check": "node tools/check-git-version.mjs",
-    "jest": "GIT_ALLOW_PROTOCOL=file LOG_LEVEL=fatal node --experimental-vm-modules node_modules/jest/bin/jest.js --logHeapUsage",
+    "jest": "GIT_ALLOW_PROTOCOL=file LOG_LEVEL=fatal vitest run --logHeapUsage",
+    "vitest": "GIT_ALLOW_PROTOCOL=file LOG_LEVEL=fatal vitest run --logHeapUsage",
     "lint": "run-s ls-lint type-check eslint prettier markdown-lint git-check doc-fence-check",
     "lint-fix": "run-s eslint-fix prettier-fix markdown-lint-fix",
     "ls-lint": "ls-lint",
@@ -264,11 +265,6 @@
     "@containerbase/eslint-plugin": "1.1.4",
     "@eslint/js": "9.20.0",
     "@hyrious/marshal": "0.3.3",
-    "@jest/environment": "29.7.0",
-    "@jest/globals": "29.7.0",
-    "@jest/reporters": "29.7.0",
-    "@jest/test-result": "29.7.0",
-    "@jest/types": "29.6.3",
     "@ls-lint/ls-lint": "2.2.3",
     "@openpgp/web-stream-tools": "0.1.3",
     "@semantic-release/exec": "7.0.3",
@@ -313,45 +309,45 @@
     "@types/url-join": "4.0.3",
     "@types/validate-npm-package-name": "4.0.2",
     "@types/xmldoc": "1.1.9",
+    "@vitest/coverage-v8": "3.0.6",
+    "@vitest/eslint-plugin": "1.1.31",
     "aws-sdk-client-mock": "4.1.0",
     "callsite": "1.0.0",
     "common-tags": "1.8.2",
     "conventional-changelog-conventionalcommits": "8.0.0",
     "emojibase-data": "16.0.2",
+    "esbuild": "0.25.0",
     "eslint": "9.20.1",
     "eslint-config-prettier": "10.0.1",
     "eslint-formatter-gha": "1.5.2",
     "eslint-import-resolver-typescript": "3.8.2",
     "eslint-plugin-import": "2.31.0",
-    "eslint-plugin-jest": "28.11.0",
     "eslint-plugin-promise": "7.2.1",
-    "expect": "29.7.0",
     "expect-more-jest": "5.5.0",
     "globals": "15.15.0",
     "graphql": "16.10.0",
     "husky": "9.1.7",
-    "jest": "29.7.0",
     "jest-extended": "4.0.2",
-    "jest-mock": "29.7.0",
-    "jest-mock-extended": "3.0.7",
-    "jest-snapshot": "29.7.0",
     "lint-staged": "15.4.3",
     "markdownlint-cli2": "0.17.2",
     "memfs": "4.17.0",
     "nock": "13.5.6",
     "npm-run-all2": "7.0.2",
     "nyc": "17.1.0",
-    "pretty-format": "29.7.0",
     "rimraf": "6.0.1",
     "semantic-release": "24.2.3",
     "tar": "7.4.3",
     "tmp-promise": "3.0.3",
-    "ts-jest": "29.2.5",
     "ts-node": "10.9.2",
     "type-fest": "4.35.0",
     "typescript": "5.7.3",
     "typescript-eslint": "8.24.1",
-    "unified": "9.2.2"
+    "unified": "9.2.2",
+    "vite": "6.1.1",
+    "vite-tsconfig-paths": "5.1.4",
+    "vitest": "3.0.6",
+    "vitest-github-actions-reporter": "0.11.1",
+    "vitest-mock-extended": "3.0.1"
   },
   "packageManager": "pnpm@10.4.1",
   "files": [
@@ -369,6 +365,9 @@
       "better-sqlite3",
       "re2"
     ],
+    "overrides": {
+      "esbuild": "0.25.0"
+    },
     "patchedDependencies": {
       "re2": "patches/re2.patch"
     }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6257c9d812..b2a4c6e097 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4,6 +4,9 @@ settings:
   autoInstallPeers: true
   excludeLinksFromLockfile: false
 
+overrides:
+  esbuild: 0.25.0
+
 patchedDependencies:
   re2:
     hash: 018babd22b7ce951bcd10d6246f1e541a7ac7ba212f7fa8985e774ece67d08e1
@@ -353,21 +356,6 @@ importers:
       '@hyrious/marshal':
         specifier: 0.3.3
         version: 0.3.3
-      '@jest/environment':
-        specifier: 29.7.0
-        version: 29.7.0
-      '@jest/globals':
-        specifier: 29.7.0
-        version: 29.7.0
-      '@jest/reporters':
-        specifier: 29.7.0
-        version: 29.7.0
-      '@jest/test-result':
-        specifier: 29.7.0
-        version: 29.7.0
-      '@jest/types':
-        specifier: 29.6.3
-        version: 29.6.3
       '@ls-lint/ls-lint':
         specifier: 2.2.3
         version: 2.2.3
@@ -500,6 +488,12 @@ importers:
       '@types/xmldoc':
         specifier: 1.1.9
         version: 1.1.9
+      '@vitest/coverage-v8':
+        specifier: 3.0.6
+        version: 3.0.6(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0))
+      '@vitest/eslint-plugin':
+        specifier: 1.1.31
+        version: 1.1.31(@typescript-eslint/utils@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3)(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0))
       aws-sdk-client-mock:
         specifier: 4.1.0
         version: 4.1.0
@@ -515,6 +509,9 @@ importers:
       emojibase-data:
         specifier: 16.0.2
         version: 16.0.2(emojibase@16.0.0)
+      esbuild:
+        specifier: 0.25.0
+        version: 0.25.0
       eslint:
         specifier: 9.20.1
         version: 9.20.1
@@ -530,15 +527,9 @@ importers:
       eslint-plugin-import:
         specifier: 2.31.0
         version: 2.31.0(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.8.2)(eslint@9.20.1)
-      eslint-plugin-jest:
-        specifier: 28.11.0
-        version: 28.11.0(@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(jest@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3)
       eslint-plugin-promise:
         specifier: 7.2.1
         version: 7.2.1(eslint@9.20.1)
-      expect:
-        specifier: 29.7.0
-        version: 29.7.0
       expect-more-jest:
         specifier: 5.5.0
         version: 5.5.0
@@ -551,21 +542,9 @@ importers:
       husky:
         specifier: 9.1.7
         version: 9.1.7
-      jest:
-        specifier: 29.7.0
-        version: 29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3))
       jest-extended:
         specifier: 4.0.2
         version: 4.0.2(jest@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)))
-      jest-mock:
-        specifier: 29.7.0
-        version: 29.7.0
-      jest-mock-extended:
-        specifier: 3.0.7
-        version: 3.0.7(jest@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3)
-      jest-snapshot:
-        specifier: 29.7.0
-        version: 29.7.0
       lint-staged:
         specifier: 15.4.3
         version: 15.4.3
@@ -584,9 +563,6 @@ importers:
       nyc:
         specifier: 17.1.0
         version: 17.1.0
-      pretty-format:
-        specifier: 29.7.0
-        version: 29.7.0
       rimraf:
         specifier: 6.0.1
         version: 6.0.1
@@ -599,9 +575,6 @@ importers:
       tmp-promise:
         specifier: 3.0.3
         version: 3.0.3
-      ts-jest:
-        specifier: 29.2.5
-        version: 29.2.5(@babel/core@7.26.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.9))(jest@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3)
       ts-node:
         specifier: 10.9.2
         version: 10.9.2(@types/node@22.13.4)(typescript@5.7.3)
@@ -617,6 +590,21 @@ importers:
       unified:
         specifier: 9.2.2
         version: 9.2.2
+      vite:
+        specifier: 6.1.1
+        version: 6.1.1(@types/node@22.13.4)(yaml@2.7.0)
+      vite-tsconfig-paths:
+        specifier: 5.1.4
+        version: 5.1.4(typescript@5.7.3)(vite@6.1.1(@types/node@22.13.4)(yaml@2.7.0))
+      vitest:
+        specifier: 3.0.6
+        version: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0)
+      vitest-github-actions-reporter:
+        specifier: 0.11.1
+        version: 0.11.1(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0))
+      vitest-mock-extended:
+        specifier: 3.0.1
+        version: 3.0.1(typescript@5.7.3)(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0))
     optionalDependencies:
       better-sqlite3:
         specifier: 11.8.1
@@ -630,6 +618,18 @@ importers:
 
 packages:
 
+  '@actions/core@1.11.1':
+    resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==}
+
+  '@actions/exec@1.1.1':
+    resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==}
+
+  '@actions/http-client@2.2.3':
+    resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==}
+
+  '@actions/io@1.1.3':
+    resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==}
+
   '@ampproject/remapping@2.3.0':
     resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
     engines: {node: '>=6.0.0'}
@@ -993,6 +993,10 @@ packages:
   '@bcoe/v8-coverage@0.2.3':
     resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
 
+  '@bcoe/v8-coverage@1.0.2':
+    resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
+    engines: {node: '>=18'}
+
   '@breejs/later@4.2.0':
     resolution: {integrity: sha512-EVMD0SgJtOuFeg0lAVbCwa+qeTKILb87jqvLyUtQswGD9+ce2nB52Y5zbTF1Hc0MDFfbydcMcxb47jSdhikVHA==}
     engines: {node: '>= 10'}
@@ -1016,6 +1020,156 @@ packages:
     resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
     engines: {node: '>=12'}
 
+  '@esbuild/aix-ppc64@0.25.0':
+    resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [aix]
+
+  '@esbuild/android-arm64@0.25.0':
+    resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm@0.25.0':
+    resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-x64@0.25.0':
+    resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/darwin-arm64@0.25.0':
+    resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.25.0':
+    resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/freebsd-arm64@0.25.0':
+    resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.25.0':
+    resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/linux-arm64@0.25.0':
+    resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.25.0':
+    resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.25.0':
+    resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.25.0':
+    resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==}
+    engines: {node: '>=18'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.25.0':
+    resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==}
+    engines: {node: '>=18'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.25.0':
+    resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.25.0':
+    resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==}
+    engines: {node: '>=18'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.25.0':
+    resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==}
+    engines: {node: '>=18'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.25.0':
+    resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/netbsd-arm64@0.25.0':
+    resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-x64@0.25.0':
+    resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/openbsd-arm64@0.25.0':
+    resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.25.0':
+    resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/sunos-x64@0.25.0':
+    resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/win32-arm64@0.25.0':
+    resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.25.0':
+    resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.25.0':
+    resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [win32]
+
   '@eslint-community/eslint-utils@4.4.1':
     resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -1054,6 +1208,10 @@ packages:
     resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
+  '@fastify/busboy@2.1.1':
+    resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
+    engines: {node: '>=14'}
+
   '@gwhitney/detect-indent@7.0.1':
     resolution: {integrity: sha512-7bQW+gkKa2kKZPeJf6+c6gFK9ARxQfn+FKy9ScTBppyKRWH2KzsmweXUoklqeEiHiNVWaeP5csIdsNq6w7QhzA==}
     engines: {node: '>=12.20'}
@@ -1215,7 +1373,6 @@ packages:
 
   '@ls-lint/ls-lint@2.2.3':
     resolution: {integrity: sha512-ekM12jNm/7O2I/hsRv9HvYkRdfrHpiV1epVuI2NP+eTIcEgdIdKkKCs9KgQydu/8R5YXTov9aHdOgplmCHLupw==}
-    cpu: [x64, arm64, s390x]
     os: [darwin, linux, win32]
     hasBin: true
 
@@ -1574,6 +1731,101 @@ packages:
     resolution: {integrity: sha512-vuLfebLvwYWwQYJeZiHHs5NmydjO6cdhwS1dUHJbXMi0WD8kBa/+f7gz4WcuNJPRR+enLFQUHs89OCjfl6Os0g==}
     engines: {node: ^20.9.0 || ^22.11.0, pnpm: ^9.0.0}
 
+  '@rollup/rollup-android-arm-eabi@4.34.8':
+    resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==}
+    cpu: [arm]
+    os: [android]
+
+  '@rollup/rollup-android-arm64@4.34.8':
+    resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==}
+    cpu: [arm64]
+    os: [android]
+
+  '@rollup/rollup-darwin-arm64@4.34.8':
+    resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@rollup/rollup-darwin-x64@4.34.8':
+    resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==}
+    cpu: [x64]
+    os: [darwin]
+
+  '@rollup/rollup-freebsd-arm64@4.34.8':
+    resolution: {integrity: sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@rollup/rollup-freebsd-x64@4.34.8':
+    resolution: {integrity: sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@rollup/rollup-linux-arm-gnueabihf@4.34.8':
+    resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm-musleabihf@4.34.8':
+    resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-gnu@4.34.8':
+    resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-musl@4.34.8':
+    resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-loongarch64-gnu@4.34.8':
+    resolution: {integrity: sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==}
+    cpu: [loong64]
+    os: [linux]
+
+  '@rollup/rollup-linux-powerpc64le-gnu@4.34.8':
+    resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@rollup/rollup-linux-riscv64-gnu@4.34.8':
+    resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@rollup/rollup-linux-s390x-gnu@4.34.8':
+    resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==}
+    cpu: [s390x]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-gnu@4.34.8':
+    resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-musl@4.34.8':
+    resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-win32-arm64-msvc@4.34.8':
+    resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==}
+    cpu: [arm64]
+    os: [win32]
+
+  '@rollup/rollup-win32-ia32-msvc@4.34.8':
+    resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==}
+    cpu: [ia32]
+    os: [win32]
+
+  '@rollup/rollup-win32-x64-msvc@4.34.8':
+    resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==}
+    cpu: [x64]
+    os: [win32]
+
   '@rtsao/scc@1.1.0':
     resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
 
@@ -2183,6 +2435,57 @@ packages:
     resolution: {integrity: sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
+  '@vitest/coverage-v8@3.0.6':
+    resolution: {integrity: sha512-JRTlR8Bw+4BcmVTICa7tJsxqphAktakiLsAmibVLAWbu1lauFddY/tXeM6sAyl1cgkPuXtpnUgaCPhTdz1Qapg==}
+    peerDependencies:
+      '@vitest/browser': 3.0.6
+      vitest: 3.0.6
+    peerDependenciesMeta:
+      '@vitest/browser':
+        optional: true
+
+  '@vitest/eslint-plugin@1.1.31':
+    resolution: {integrity: sha512-xlsLr+e+AXZ/00eVZCtNmMeCJoJaRCoLDiAgLcxgQjSS1EertieB2MUHf8xIqPKs9lECc/UpL+y1xDcpvi02hw==}
+    peerDependencies:
+      '@typescript-eslint/utils': '>= 8.0'
+      eslint: '>= 8.57.0'
+      typescript: '>= 5.0.0'
+      vitest: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+      vitest:
+        optional: true
+
+  '@vitest/expect@3.0.6':
+    resolution: {integrity: sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg==}
+
+  '@vitest/mocker@3.0.6':
+    resolution: {integrity: sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==}
+    peerDependencies:
+      msw: ^2.4.9
+      vite: ^5.0.0 || ^6.0.0
+    peerDependenciesMeta:
+      msw:
+        optional: true
+      vite:
+        optional: true
+
+  '@vitest/pretty-format@3.0.6':
+    resolution: {integrity: sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg==}
+
+  '@vitest/runner@3.0.6':
+    resolution: {integrity: sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA==}
+
+  '@vitest/snapshot@3.0.6':
+    resolution: {integrity: sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg==}
+
+  '@vitest/spy@3.0.6':
+    resolution: {integrity: sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q==}
+
+  '@vitest/utils@3.0.6':
+    resolution: {integrity: sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ==}
+
   '@yarnpkg/core@4.2.0':
     resolution: {integrity: sha512-h+cjnATkpO0ya6I5U4RYvOet/IsswOje3eBq9CsFM4XJZ2nS4WBBeFwYe0tqLD87IwKsoyuIdUwZjPHcn2DM8g==}
     engines: {node: '>=18.12.0'}
@@ -2341,6 +2644,10 @@ packages:
     resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
     engines: {node: '>=0.10.0'}
 
+  assertion-error@2.0.1:
+    resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+    engines: {node: '>=12'}
+
   async-function@1.0.0:
     resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
     engines: {node: '>= 0.4'}
@@ -2348,9 +2655,6 @@ packages:
   async-mutex@0.5.0:
     resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==}
 
-  async@3.2.6:
-    resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
-
   auth-header@1.0.0:
     resolution: {integrity: sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA==}
 
@@ -2451,10 +2755,6 @@ packages:
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
     hasBin: true
 
-  bs-logger@0.2.6:
-    resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
-    engines: {node: '>= 6'}
-
   bser@2.1.1:
     resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
 
@@ -2481,6 +2781,10 @@ packages:
   bzip-deflate@1.0.0:
     resolution: {integrity: sha512-9RMnpiJqMYMJcLdr4pxwowZ8Zh3P+tVswE/bnX6tZ14UGKNcdV5WVK2P+lGp2As+RCjl+i3SFJ117HyCaaHNDA==}
 
+  cac@6.7.14:
+    resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+    engines: {node: '>=8'}
+
   cacache@18.0.4:
     resolution: {integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==}
     engines: {node: ^16.14.0 || >=18.0.0}
@@ -2535,6 +2839,10 @@ packages:
   caniuse-lite@1.0.30001700:
     resolution: {integrity: sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==}
 
+  chai@5.2.0:
+    resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
+    engines: {node: '>=12'}
+
   chalk@2.4.2:
     resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
     engines: {node: '>=4'}
@@ -2576,6 +2884,10 @@ packages:
   character-reference-invalid@2.0.1:
     resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
 
+  check-error@2.1.1:
+    resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
+    engines: {node: '>= 16'}
+
   chownr@1.1.4:
     resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
 
@@ -2838,6 +3150,10 @@ packages:
       babel-plugin-macros:
         optional: true
 
+  deep-eql@5.0.2:
+    resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+    engines: {node: '>=6'}
+
   deep-extend@0.6.0:
     resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
     engines: {node: '>=4.0.0'}
@@ -2953,11 +3269,6 @@ packages:
     engines: {node: '>=16'}
     hasBin: true
 
-  ejs@3.1.10:
-    resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
-    engines: {node: '>=0.10.0'}
-    hasBin: true
-
   electron-to-chromium@1.5.103:
     resolution: {integrity: sha512-P6+XzIkfndgsrjROJWfSvVEgNHtPgbhVyTkwLjUM2HU/h7pZRORgaTlHqfAikqxKmdJMLW8fftrdGWbd/Ds0FA==}
 
@@ -3036,6 +3347,9 @@ packages:
     resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
     engines: {node: '>= 0.4'}
 
+  es-module-lexer@1.6.0:
+    resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==}
+
   es-object-atoms@1.1.1:
     resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
     engines: {node: '>= 0.4'}
@@ -3055,6 +3369,11 @@ packages:
   es6-error@4.1.1:
     resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
 
+  esbuild@0.25.0:
+    resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==}
+    engines: {node: '>=18'}
+    hasBin: true
+
   escalade@3.2.0:
     resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
     engines: {node: '>=6'}
@@ -3139,19 +3458,6 @@ packages:
       '@typescript-eslint/parser':
         optional: true
 
-  eslint-plugin-jest@28.11.0:
-    resolution: {integrity: sha512-QAfipLcNCWLVocVbZW8GimKn5p5iiMcgGbRzz8z/P5q7xw+cNEpYqyzFMtIF/ZgF2HLOyy+dYBut+DoYolvqig==}
-    engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0}
-    peerDependencies:
-      '@typescript-eslint/eslint-plugin': ^6.0.0 || ^7.0.0 || ^8.0.0
-      eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
-      jest: '*'
-    peerDependenciesMeta:
-      '@typescript-eslint/eslint-plugin':
-        optional: true
-      jest:
-        optional: true
-
   eslint-plugin-promise@7.2.1:
     resolution: {integrity: sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -3201,6 +3507,9 @@ packages:
     resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
     engines: {node: '>=4.0'}
 
+  estree-walker@3.0.3:
+    resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
   esutils@2.0.3:
     resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
     engines: {node: '>=0.10.0'}
@@ -3237,6 +3546,10 @@ packages:
   expect-more@1.3.0:
     resolution: {integrity: sha512-HnXT5nJb9V3DMnr5RgA1TiKbu5kRaJ0GD1JkuhZvnr1Qe3HJq+ESnrcl/jmVUZ8Ycnl3Sp0OTYUhmO36d2+zow==}
 
+  expect-type@1.1.0:
+    resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
+    engines: {node: '>=12.0.0'}
+
   expect@29.7.0:
     resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -3304,9 +3617,6 @@ packages:
   file-uri-to-path@1.0.0:
     resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
 
-  filelist@1.0.4:
-    resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
-
   fill-range@7.1.1:
     resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
     engines: {node: '>=8'}
@@ -3540,6 +3850,9 @@ packages:
     resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==}
     engines: {node: '>=18'}
 
+  globrex@0.1.2:
+    resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
+
   good-enough-parser@1.1.23:
     resolution: {integrity: sha512-QUcQZutczESpdo2w9BMG6VpLFoq9ix7ER5HLM1mAdZdri2F3eISkCb8ep84W6YOo0grYWJdyT/8JkYqGjQfSSQ==}
     engines: {node: '>=18.12.0', yarn: ^1.17.0}
@@ -4033,6 +4346,10 @@ packages:
     resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
     engines: {node: '>=10'}
 
+  istanbul-lib-source-maps@5.0.6:
+    resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
+    engines: {node: '>=10'}
+
   istanbul-reports@3.1.7:
     resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
     engines: {node: '>=8'}
@@ -4044,11 +4361,6 @@ packages:
     resolution: {integrity: sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==}
     engines: {node: 20 || >=22}
 
-  jake@10.9.2:
-    resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
-    engines: {node: '>=10'}
-    hasBin: true
-
   java-properties@1.0.2:
     resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==}
     engines: {node: '>= 0.6.0'}
@@ -4132,12 +4444,6 @@ packages:
     resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
 
-  jest-mock-extended@3.0.7:
-    resolution: {integrity: sha512-7lsKdLFcW9B9l5NzZ66S/yTQ9k8rFtnwYdCNuRU/81fqDWicNDVhitTSPnrGmNeNm0xyw0JHexEOShrIKRCIRQ==}
-    peerDependencies:
-      jest: ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0
-      typescript: ^3.0.0 || ^4.0.0 || ^5.0.0
-
   jest-mock@29.7.0:
     resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -4378,9 +4684,6 @@ packages:
   lodash.isstring@4.0.1:
     resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
 
-  lodash.memoize@4.1.2:
-    resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
-
   lodash.merge@4.6.2:
     resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
 
@@ -4400,6 +4703,9 @@ packages:
   longest-streak@2.0.4:
     resolution: {integrity: sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==}
 
+  loupe@3.1.3:
+    resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
+
   lowercase-keys@2.0.0:
     resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
     engines: {node: '>=8'}
@@ -4422,6 +4728,12 @@ packages:
     resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==}
     engines: {node: '>=12'}
 
+  magic-string@0.30.17:
+    resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+
+  magicast@0.3.5:
+    resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
+
   make-dir@3.1.0:
     resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
     engines: {node: '>=8'}
@@ -4654,10 +4966,6 @@ packages:
   minimatch@3.1.2:
     resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
 
-  minimatch@5.1.6:
-    resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
-    engines: {node: '>=10'}
-
   minimatch@9.0.2:
     resolution: {integrity: sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg==}
     engines: {node: '>=16 || 14 >=14.17'}
@@ -5192,6 +5500,13 @@ packages:
     resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==}
     engines: {node: '>=18'}
 
+  pathe@2.0.3:
+    resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+  pathval@2.0.0:
+    resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
+    engines: {node: '>= 14.16'}
+
   pend@1.2.0:
     resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
 
@@ -5234,6 +5549,10 @@ packages:
     resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
     engines: {node: '>= 0.4'}
 
+  postcss@8.5.3:
+    resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
+    engines: {node: ^10 || ^12 || >=14}
+
   prebuild-install@7.1.3:
     resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
     engines: {node: '>=10'}
@@ -5483,6 +5802,11 @@ packages:
     resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==}
     engines: {node: '>=8.0'}
 
+  rollup@4.34.8:
+    resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==}
+    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+    hasBin: true
+
   run-parallel@1.2.0:
     resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
 
@@ -5603,6 +5927,9 @@ packages:
     resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
     engines: {node: '>= 0.4'}
 
+  siginfo@2.0.0:
+    resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
   signal-exit@3.0.7:
     resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
 
@@ -5669,6 +5996,10 @@ packages:
     resolution: {integrity: sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==}
     engines: {node: '>=8'}
 
+  source-map-js@1.2.1:
+    resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+    engines: {node: '>=0.10.0'}
+
   source-map-support@0.5.13:
     resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
 
@@ -5725,6 +6056,12 @@ packages:
     resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
     engines: {node: '>=10'}
 
+  stackback@0.0.2:
+    resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
+  std-env@3.8.0:
+    resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==}
+
   stream-combiner2@1.1.1:
     resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==}
 
@@ -5867,6 +6204,10 @@ packages:
     resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
     engines: {node: '>=8'}
 
+  test-exclude@7.0.1:
+    resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
+    engines: {node: '>=18'}
+
   text-table@0.2.0:
     resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
 
@@ -5896,6 +6237,12 @@ packages:
     resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==}
     engines: {node: '>=12'}
 
+  tinybench@2.9.0:
+    resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+  tinyexec@0.3.2:
+    resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
+
   tinyglobby@0.2.12:
     resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==}
     engines: {node: '>=12.0.0'}
@@ -5903,6 +6250,18 @@ packages:
   tinylogic@2.0.0:
     resolution: {integrity: sha512-dljTkiLLITtsjqBvTA1MRZQK/sGP4kI3UJKc3yA9fMzYbMF2RhcN04SeROVqJBIYYOoJMM8u0WDnhFwMSFQotw==}
 
+  tinypool@1.0.2:
+    resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+
+  tinyrainbow@2.0.0:
+    resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
+    engines: {node: '>=14.0.0'}
+
+  tinyspy@3.0.2:
+    resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
+    engines: {node: '>=14.0.0'}
+
   tmp-promise@3.0.3:
     resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==}
 
@@ -5962,30 +6321,6 @@ packages:
       typescript:
         optional: true
 
-  ts-jest@29.2.5:
-    resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
-    hasBin: true
-    peerDependencies:
-      '@babel/core': '>=7.0.0-beta.0 <8'
-      '@jest/transform': ^29.0.0
-      '@jest/types': ^29.0.0
-      babel-jest: ^29.0.0
-      esbuild: '*'
-      jest: ^29.0.0
-      typescript: '>=4.3 <6'
-    peerDependenciesMeta:
-      '@babel/core':
-        optional: true
-      '@jest/transform':
-        optional: true
-      '@jest/types':
-        optional: true
-      babel-jest:
-        optional: true
-      esbuild:
-        optional: true
-
   ts-node@10.9.2:
     resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
     hasBin: true
@@ -6000,6 +6335,16 @@ packages:
       '@swc/wasm':
         optional: true
 
+  tsconfck@3.1.5:
+    resolution: {integrity: sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==}
+    engines: {node: ^18 || >=20}
+    hasBin: true
+    peerDependencies:
+      typescript: ^5.0.0
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
   tsconfig-paths@3.15.0:
     resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
 
@@ -6122,6 +6467,10 @@ packages:
   undici-types@6.20.0:
     resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
 
+  undici@5.28.5:
+    resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==}
+    engines: {node: '>=14.0'}
+
   unicode-emoji-modifier-base@1.0.0:
     resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==}
     engines: {node: '>=4'}
@@ -6234,6 +6583,99 @@ packages:
   vfile@4.2.1:
     resolution: {integrity: sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==}
 
+  vite-node@3.0.6:
+    resolution: {integrity: sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+    hasBin: true
+
+  vite-tsconfig-paths@5.1.4:
+    resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==}
+    peerDependencies:
+      vite: '*'
+    peerDependenciesMeta:
+      vite:
+        optional: true
+
+  vite@6.1.1:
+    resolution: {integrity: sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+    hasBin: true
+    peerDependencies:
+      '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+      jiti: '>=1.21.0'
+      less: '*'
+      lightningcss: ^1.21.0
+      sass: '*'
+      sass-embedded: '*'
+      stylus: '*'
+      sugarss: '*'
+      terser: ^5.16.0
+      tsx: ^4.8.1
+      yaml: ^2.4.2
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+      jiti:
+        optional: true
+      less:
+        optional: true
+      lightningcss:
+        optional: true
+      sass:
+        optional: true
+      sass-embedded:
+        optional: true
+      stylus:
+        optional: true
+      sugarss:
+        optional: true
+      terser:
+        optional: true
+      tsx:
+        optional: true
+      yaml:
+        optional: true
+
+  vitest-github-actions-reporter@0.11.1:
+    resolution: {integrity: sha512-ZHHB0wBgOPhMYCB17WKVlJZa+5SdudBZFoVoebwfq3ioIUTeLQGYHwh85vpdJAxRghLP8d0qI/6eCTueGyDVXA==}
+    engines: {node: '>=14.16.0'}
+    peerDependencies:
+      vitest: '>=0.28.5'
+
+  vitest-mock-extended@3.0.1:
+    resolution: {integrity: sha512-VI7CRRvIi+MbAsqdGTxp3K+eiY7BR1zrVflZ5DBrFUXPjRZRgxXajlYdNyIu3v1bb5ZfdLANXwZ9i/RfVMfS6A==}
+    peerDependencies:
+      typescript: 3.x || 4.x || 5.x
+      vitest: '>=3.0.0'
+
+  vitest@3.0.6:
+    resolution: {integrity: sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+    hasBin: true
+    peerDependencies:
+      '@edge-runtime/vm': '*'
+      '@types/debug': ^4.1.12
+      '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+      '@vitest/browser': 3.0.6
+      '@vitest/ui': 3.0.6
+      happy-dom: '*'
+      jsdom: '*'
+    peerDependenciesMeta:
+      '@edge-runtime/vm':
+        optional: true
+      '@types/debug':
+        optional: true
+      '@types/node':
+        optional: true
+      '@vitest/browser':
+        optional: true
+      '@vitest/ui':
+        optional: true
+      happy-dom:
+        optional: true
+      jsdom:
+        optional: true
+
   vuln-vects@1.1.0:
     resolution: {integrity: sha512-LGDwn9nRz94YoeqOn2TZqQXzyonBc5FJppSgH34S/1U+3bgPONq/vvfiCbCQ4MeBll58xx+kDmhS73ac+EHBBw==}
 
@@ -6280,6 +6722,11 @@ packages:
     engines: {node: ^18.17.0 || >=20.5.0}
     hasBin: true
 
+  why-is-node-running@2.3.0:
+    resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+    engines: {node: '>=8'}
+    hasBin: true
+
   word-wrap@1.2.5:
     resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
     engines: {node: '>=0.10.0'}
@@ -6403,6 +6850,22 @@ ignoredOptionalDependencies:
 
 snapshots:
 
+  '@actions/core@1.11.1':
+    dependencies:
+      '@actions/exec': 1.1.1
+      '@actions/http-client': 2.2.3
+
+  '@actions/exec@1.1.1':
+    dependencies:
+      '@actions/io': 1.1.3
+
+  '@actions/http-client@2.2.3':
+    dependencies:
+      tunnel: 0.0.6
+      undici: 5.28.5
+
+  '@actions/io@1.1.3': {}
+
   '@ampproject/remapping@2.3.0':
     dependencies:
       '@jridgewell/gen-mapping': 0.3.8
@@ -7219,7 +7682,8 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/helper-plugin-utils@7.26.5': {}
+  '@babel/helper-plugin-utils@7.26.5':
+    optional: true
 
   '@babel/helper-string-parser@7.25.9': {}
 
@@ -7240,86 +7704,103 @@ snapshots:
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.9)':
     dependencies:
       '@babel/core': 7.26.9
       '@babel/helper-plugin-utils': 7.26.5
+    optional: true
 
   '@babel/runtime-corejs3@7.26.9':
     dependencies:
@@ -7349,7 +7830,10 @@ snapshots:
       '@babel/helper-string-parser': 7.25.9
       '@babel/helper-validator-identifier': 7.25.9
 
-  '@bcoe/v8-coverage@0.2.3': {}
+  '@bcoe/v8-coverage@0.2.3':
+    optional: true
+
+  '@bcoe/v8-coverage@1.0.2': {}
 
   '@breejs/later@4.2.0': {}
 
@@ -7370,18 +7854,93 @@ snapshots:
     dependencies:
       '@jridgewell/trace-mapping': 0.3.9
 
-  '@eslint-community/eslint-utils@4.4.1(eslint@9.20.1)':
-    dependencies:
-      eslint: 9.20.1
-      eslint-visitor-keys: 3.4.3
+  '@esbuild/aix-ppc64@0.25.0':
+    optional: true
 
-  '@eslint-community/regexpp@4.12.1': {}
+  '@esbuild/android-arm64@0.25.0':
+    optional: true
 
-  '@eslint/config-array@0.19.2':
-    dependencies:
-      '@eslint/object-schema': 2.1.6
-      debug: 4.4.0
-      minimatch: 3.1.2
+  '@esbuild/android-arm@0.25.0':
+    optional: true
+
+  '@esbuild/android-x64@0.25.0':
+    optional: true
+
+  '@esbuild/darwin-arm64@0.25.0':
+    optional: true
+
+  '@esbuild/darwin-x64@0.25.0':
+    optional: true
+
+  '@esbuild/freebsd-arm64@0.25.0':
+    optional: true
+
+  '@esbuild/freebsd-x64@0.25.0':
+    optional: true
+
+  '@esbuild/linux-arm64@0.25.0':
+    optional: true
+
+  '@esbuild/linux-arm@0.25.0':
+    optional: true
+
+  '@esbuild/linux-ia32@0.25.0':
+    optional: true
+
+  '@esbuild/linux-loong64@0.25.0':
+    optional: true
+
+  '@esbuild/linux-mips64el@0.25.0':
+    optional: true
+
+  '@esbuild/linux-ppc64@0.25.0':
+    optional: true
+
+  '@esbuild/linux-riscv64@0.25.0':
+    optional: true
+
+  '@esbuild/linux-s390x@0.25.0':
+    optional: true
+
+  '@esbuild/linux-x64@0.25.0':
+    optional: true
+
+  '@esbuild/netbsd-arm64@0.25.0':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.25.0':
+    optional: true
+
+  '@esbuild/openbsd-arm64@0.25.0':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.25.0':
+    optional: true
+
+  '@esbuild/sunos-x64@0.25.0':
+    optional: true
+
+  '@esbuild/win32-arm64@0.25.0':
+    optional: true
+
+  '@esbuild/win32-ia32@0.25.0':
+    optional: true
+
+  '@esbuild/win32-x64@0.25.0':
+    optional: true
+
+  '@eslint-community/eslint-utils@4.4.1(eslint@9.20.1)':
+    dependencies:
+      eslint: 9.20.1
+      eslint-visitor-keys: 3.4.3
+
+  '@eslint-community/regexpp@4.12.1': {}
+
+  '@eslint/config-array@0.19.2':
+    dependencies:
+      '@eslint/object-schema': 2.1.6
+      debug: 4.4.0
+      minimatch: 3.1.2
     transitivePeerDependencies:
       - supports-color
 
@@ -7416,6 +7975,8 @@ snapshots:
       '@eslint/core': 0.12.0
       levn: 0.4.1
 
+  '@fastify/busboy@2.1.1': {}
+
   '@gwhitney/detect-indent@7.0.1': {}
 
   '@humanfs/core@0.19.1': {}
@@ -7464,6 +8025,7 @@ snapshots:
       jest-message-util: 29.7.0
       jest-util: 29.7.0
       slash: 3.0.0
+    optional: true
 
   '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3))':
     dependencies:
@@ -7499,6 +8061,7 @@ snapshots:
       - babel-plugin-macros
       - supports-color
       - ts-node
+    optional: true
 
   '@jest/environment@29.7.0':
     dependencies:
@@ -7506,6 +8069,7 @@ snapshots:
       '@jest/types': 29.6.3
       '@types/node': 22.13.4
       jest-mock: 29.7.0
+    optional: true
 
   '@jest/expect-utils@29.4.1':
     dependencies:
@@ -7514,6 +8078,7 @@ snapshots:
   '@jest/expect-utils@29.7.0':
     dependencies:
       jest-get-type: 29.6.3
+    optional: true
 
   '@jest/expect@29.7.0':
     dependencies:
@@ -7521,6 +8086,7 @@ snapshots:
       jest-snapshot: 29.7.0
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   '@jest/fake-timers@29.7.0':
     dependencies:
@@ -7530,6 +8096,7 @@ snapshots:
       jest-message-util: 29.7.0
       jest-mock: 29.7.0
       jest-util: 29.7.0
+    optional: true
 
   '@jest/globals@29.7.0':
     dependencies:
@@ -7539,6 +8106,7 @@ snapshots:
       jest-mock: 29.7.0
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   '@jest/reporters@29.7.0':
     dependencies:
@@ -7568,6 +8136,7 @@ snapshots:
       v8-to-istanbul: 9.3.0
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   '@jest/schemas@29.6.3':
     dependencies:
@@ -7578,6 +8147,7 @@ snapshots:
       '@jridgewell/trace-mapping': 0.3.25
       callsites: 3.1.0
       graceful-fs: 4.2.11
+    optional: true
 
   '@jest/test-result@29.7.0':
     dependencies:
@@ -7585,6 +8155,7 @@ snapshots:
       '@jest/types': 29.6.3
       '@types/istanbul-lib-coverage': 2.0.6
       collect-v8-coverage: 1.0.2
+    optional: true
 
   '@jest/test-sequencer@29.7.0':
     dependencies:
@@ -7592,6 +8163,7 @@ snapshots:
       graceful-fs: 4.2.11
       jest-haste-map: 29.7.0
       slash: 3.0.0
+    optional: true
 
   '@jest/transform@29.7.0':
     dependencies:
@@ -7612,6 +8184,7 @@ snapshots:
       write-file-atomic: 4.0.2
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   '@jest/types@29.6.3':
     dependencies:
@@ -7621,6 +8194,7 @@ snapshots:
       '@types/node': 22.13.4
       '@types/yargs': 17.0.33
       chalk: 4.1.2
+    optional: true
 
   '@jridgewell/gen-mapping@0.3.8':
     dependencies:
@@ -8066,6 +8640,63 @@ snapshots:
 
   '@renovatebot/ruby-semver@4.0.0': {}
 
+  '@rollup/rollup-android-arm-eabi@4.34.8':
+    optional: true
+
+  '@rollup/rollup-android-arm64@4.34.8':
+    optional: true
+
+  '@rollup/rollup-darwin-arm64@4.34.8':
+    optional: true
+
+  '@rollup/rollup-darwin-x64@4.34.8':
+    optional: true
+
+  '@rollup/rollup-freebsd-arm64@4.34.8':
+    optional: true
+
+  '@rollup/rollup-freebsd-x64@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-arm-gnueabihf@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-arm-musleabihf@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-arm64-gnu@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-arm64-musl@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-loongarch64-gnu@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-powerpc64le-gnu@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-riscv64-gnu@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-s390x-gnu@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-x64-gnu@4.34.8':
+    optional: true
+
+  '@rollup/rollup-linux-x64-musl@4.34.8':
+    optional: true
+
+  '@rollup/rollup-win32-arm64-msvc@4.34.8':
+    optional: true
+
+  '@rollup/rollup-win32-ia32-msvc@4.34.8':
+    optional: true
+
+  '@rollup/rollup-win32-x64-msvc@4.34.8':
+    optional: true
+
   '@rtsao/scc@1.1.0': {}
 
   '@seald-io/binary-search-tree@1.0.3': {}
@@ -8176,6 +8807,7 @@ snapshots:
   '@sinonjs/fake-timers@10.3.0':
     dependencies:
       '@sinonjs/commons': 3.0.1
+    optional: true
 
   '@sinonjs/fake-timers@11.2.2':
     dependencies:
@@ -8586,19 +9218,23 @@ snapshots:
       '@types/babel__generator': 7.6.8
       '@types/babel__template': 7.4.4
       '@types/babel__traverse': 7.20.6
+    optional: true
 
   '@types/babel__generator@7.6.8':
     dependencies:
       '@babel/types': 7.26.9
+    optional: true
 
   '@types/babel__template@7.4.4':
     dependencies:
       '@babel/parser': 7.26.9
       '@babel/types': 7.26.9
+    optional: true
 
   '@types/babel__traverse@7.20.6':
     dependencies:
       '@babel/types': 7.26.9
+    optional: true
 
   '@types/better-sqlite3@7.6.12':
     dependencies:
@@ -8661,20 +9297,24 @@ snapshots:
   '@types/graceful-fs@4.1.9':
     dependencies:
       '@types/node': 22.13.4
+    optional: true
 
   '@types/http-cache-semantics@4.0.4': {}
 
   '@types/ini@4.1.1': {}
 
-  '@types/istanbul-lib-coverage@2.0.6': {}
+  '@types/istanbul-lib-coverage@2.0.6':
+    optional: true
 
   '@types/istanbul-lib-report@3.0.3':
     dependencies:
       '@types/istanbul-lib-coverage': 2.0.6
+    optional: true
 
   '@types/istanbul-reports@3.0.4':
     dependencies:
       '@types/istanbul-lib-report': 3.0.3
+    optional: true
 
   '@types/js-yaml@4.0.9': {}
 
@@ -8757,7 +9397,8 @@ snapshots:
 
   '@types/sinonjs__fake-timers@8.1.5': {}
 
-  '@types/stack-utils@2.0.3': {}
+  '@types/stack-utils@2.0.3':
+    optional: true
 
   '@types/tar@6.1.13':
     dependencies:
@@ -8778,11 +9419,13 @@ snapshots:
 
   '@types/xmldoc@1.1.9': {}
 
-  '@types/yargs-parser@21.0.3': {}
+  '@types/yargs-parser@21.0.3':
+    optional: true
 
   '@types/yargs@17.0.33':
     dependencies:
       '@types/yargs-parser': 21.0.3
+    optional: true
 
   '@types/yauzl@2.10.3':
     dependencies:
@@ -8866,6 +9509,72 @@ snapshots:
       '@typescript-eslint/types': 8.24.1
       eslint-visitor-keys: 4.2.0
 
+  '@vitest/coverage-v8@3.0.6(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0))':
+    dependencies:
+      '@ampproject/remapping': 2.3.0
+      '@bcoe/v8-coverage': 1.0.2
+      debug: 4.4.0
+      istanbul-lib-coverage: 3.2.2
+      istanbul-lib-report: 3.0.1
+      istanbul-lib-source-maps: 5.0.6
+      istanbul-reports: 3.1.7
+      magic-string: 0.30.17
+      magicast: 0.3.5
+      std-env: 3.8.0
+      test-exclude: 7.0.1
+      tinyrainbow: 2.0.0
+      vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0)
+    transitivePeerDependencies:
+      - supports-color
+
+  '@vitest/eslint-plugin@1.1.31(@typescript-eslint/utils@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3)(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0))':
+    dependencies:
+      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1)(typescript@5.7.3)
+      eslint: 9.20.1
+    optionalDependencies:
+      typescript: 5.7.3
+      vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0)
+
+  '@vitest/expect@3.0.6':
+    dependencies:
+      '@vitest/spy': 3.0.6
+      '@vitest/utils': 3.0.6
+      chai: 5.2.0
+      tinyrainbow: 2.0.0
+
+  '@vitest/mocker@3.0.6(vite@6.1.1(@types/node@22.13.4)(yaml@2.7.0))':
+    dependencies:
+      '@vitest/spy': 3.0.6
+      estree-walker: 3.0.3
+      magic-string: 0.30.17
+    optionalDependencies:
+      vite: 6.1.1(@types/node@22.13.4)(yaml@2.7.0)
+
+  '@vitest/pretty-format@3.0.6':
+    dependencies:
+      tinyrainbow: 2.0.0
+
+  '@vitest/runner@3.0.6':
+    dependencies:
+      '@vitest/utils': 3.0.6
+      pathe: 2.0.3
+
+  '@vitest/snapshot@3.0.6':
+    dependencies:
+      '@vitest/pretty-format': 3.0.6
+      magic-string: 0.30.17
+      pathe: 2.0.3
+
+  '@vitest/spy@3.0.6':
+    dependencies:
+      tinyspy: 3.0.2
+
+  '@vitest/utils@3.0.6':
+    dependencies:
+      '@vitest/pretty-format': 3.0.6
+      loupe: 3.1.3
+      tinyrainbow: 2.0.0
+
   '@yarnpkg/core@4.2.0(typanion@3.14.0)':
     dependencies:
       '@arcanis/slice-ansi': 1.1.1
@@ -8970,6 +9679,7 @@ snapshots:
   ansi-escapes@4.3.2:
     dependencies:
       type-fest: 0.21.3
+    optional: true
 
   ansi-escapes@7.0.0:
     dependencies:
@@ -8997,6 +9707,7 @@ snapshots:
     dependencies:
       normalize-path: 3.0.0
       picomatch: 2.3.1
+    optional: true
 
   append-transform@2.0.0:
     dependencies:
@@ -9065,14 +9776,14 @@ snapshots:
 
   arrify@1.0.1: {}
 
+  assertion-error@2.0.1: {}
+
   async-function@1.0.0: {}
 
   async-mutex@0.5.0:
     dependencies:
       tslib: 2.8.1
 
-  async@3.2.6: {}
-
   auth-header@1.0.0: {}
 
   available-typed-arrays@1.0.7:
@@ -9104,6 +9815,7 @@ snapshots:
       slash: 3.0.0
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   babel-plugin-istanbul@6.1.1:
     dependencies:
@@ -9114,6 +9826,7 @@ snapshots:
       test-exclude: 6.0.0
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   babel-plugin-jest-hoist@29.6.3:
     dependencies:
@@ -9121,6 +9834,7 @@ snapshots:
       '@babel/types': 7.26.9
       '@types/babel__core': 7.20.5
       '@types/babel__traverse': 7.20.6
+    optional: true
 
   babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.9):
     dependencies:
@@ -9140,12 +9854,14 @@ snapshots:
       '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.9)
       '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.9)
       '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.9)
+    optional: true
 
   babel-preset-jest@29.6.3(@babel/core@7.26.9):
     dependencies:
       '@babel/core': 7.26.9
       babel-plugin-jest-hoist: 29.6.3
       babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.9)
+    optional: true
 
   backslash@0.2.0: {}
 
@@ -9207,13 +9923,10 @@ snapshots:
       node-releases: 2.0.19
       update-browserslist-db: 1.1.2(browserslist@4.24.4)
 
-  bs-logger@0.2.6:
-    dependencies:
-      fast-json-stable-stringify: 2.1.0
-
   bser@2.1.1:
     dependencies:
       node-int64: 0.4.0
+    optional: true
 
   buffer-crc32@0.2.13: {}
 
@@ -9235,6 +9948,8 @@ snapshots:
 
   bzip-deflate@1.0.0: {}
 
+  cac@6.7.14: {}
+
   cacache@18.0.4:
     dependencies:
       '@npmcli/fs': 3.1.1
@@ -9314,10 +10029,19 @@ snapshots:
 
   camelcase@5.3.1: {}
 
-  camelcase@6.3.0: {}
+  camelcase@6.3.0:
+    optional: true
 
   caniuse-lite@1.0.30001700: {}
 
+  chai@5.2.0:
+    dependencies:
+      assertion-error: 2.0.1
+      check-error: 2.1.1
+      deep-eql: 5.0.2
+      loupe: 3.1.3
+      pathval: 2.0.0
+
   chalk@2.4.2:
     dependencies:
       ansi-styles: 3.2.1
@@ -9352,6 +10076,8 @@ snapshots:
 
   character-reference-invalid@2.0.1: {}
 
+  check-error@2.1.1: {}
+
   chownr@1.1.4:
     optional: true
 
@@ -9359,7 +10085,8 @@ snapshots:
 
   chownr@3.0.0: {}
 
-  ci-info@3.9.0: {}
+  ci-info@3.9.0:
+    optional: true
 
   ci-info@4.1.0: {}
 
@@ -9425,9 +10152,11 @@ snapshots:
 
   cluster-key-slot@1.1.2: {}
 
-  co@4.6.0: {}
+  co@4.6.0:
+    optional: true
 
-  collect-v8-coverage@1.0.2: {}
+  collect-v8-coverage@1.0.2:
+    optional: true
 
   color-convert@1.9.3:
     dependencies:
@@ -9526,6 +10255,7 @@ snapshots:
       - babel-plugin-macros
       - supports-color
       - ts-node
+    optional: true
 
   create-require@1.1.1: {}
 
@@ -9596,7 +10326,10 @@ snapshots:
     dependencies:
       mimic-response: 3.1.0
 
-  dedent@1.5.3: {}
+  dedent@1.5.3:
+    optional: true
+
+  deep-eql@5.0.2: {}
 
   deep-extend@0.6.0: {}
 
@@ -9634,7 +10367,8 @@ snapshots:
   detect-libc@2.0.3:
     optional: true
 
-  detect-newline@3.1.0: {}
+  detect-newline@3.1.0:
+    optional: true
 
   detect-node@2.1.0: {}
 
@@ -9705,15 +10439,12 @@ snapshots:
       minimatch: 9.0.2
       semver: 7.7.1
 
-  ejs@3.1.10:
-    dependencies:
-      jake: 10.9.2
-
   electron-to-chromium@1.5.103: {}
 
   email-addresses@5.0.0: {}
 
-  emittery@0.13.1: {}
+  emittery@0.13.1:
+    optional: true
 
   emoji-regex@10.4.0: {}
 
@@ -9821,6 +10552,8 @@ snapshots:
 
   es-errors@1.3.0: {}
 
+  es-module-lexer@1.6.0: {}
+
   es-object-atoms@1.1.1:
     dependencies:
       es-errors: 1.3.0
@@ -9844,11 +10577,40 @@ snapshots:
 
   es6-error@4.1.1: {}
 
+  esbuild@0.25.0:
+    optionalDependencies:
+      '@esbuild/aix-ppc64': 0.25.0
+      '@esbuild/android-arm': 0.25.0
+      '@esbuild/android-arm64': 0.25.0
+      '@esbuild/android-x64': 0.25.0
+      '@esbuild/darwin-arm64': 0.25.0
+      '@esbuild/darwin-x64': 0.25.0
+      '@esbuild/freebsd-arm64': 0.25.0
+      '@esbuild/freebsd-x64': 0.25.0
+      '@esbuild/linux-arm': 0.25.0
+      '@esbuild/linux-arm64': 0.25.0
+      '@esbuild/linux-ia32': 0.25.0
+      '@esbuild/linux-loong64': 0.25.0
+      '@esbuild/linux-mips64el': 0.25.0
+      '@esbuild/linux-ppc64': 0.25.0
+      '@esbuild/linux-riscv64': 0.25.0
+      '@esbuild/linux-s390x': 0.25.0
+      '@esbuild/linux-x64': 0.25.0
+      '@esbuild/netbsd-arm64': 0.25.0
+      '@esbuild/netbsd-x64': 0.25.0
+      '@esbuild/openbsd-arm64': 0.25.0
+      '@esbuild/openbsd-x64': 0.25.0
+      '@esbuild/sunos-x64': 0.25.0
+      '@esbuild/win32-arm64': 0.25.0
+      '@esbuild/win32-ia32': 0.25.0
+      '@esbuild/win32-x64': 0.25.0
+
   escalade@3.2.0: {}
 
   escape-string-regexp@1.0.5: {}
 
-  escape-string-regexp@2.0.0: {}
+  escape-string-regexp@2.0.0:
+    optional: true
 
   escape-string-regexp@4.0.0: {}
 
@@ -9934,17 +10696,6 @@ snapshots:
       - eslint-import-resolver-webpack
       - supports-color
 
-  eslint-plugin-jest@28.11.0(@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(jest@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3):
-    dependencies:
-      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1)(typescript@5.7.3)
-      eslint: 9.20.1
-    optionalDependencies:
-      '@typescript-eslint/eslint-plugin': 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3)
-      jest: 29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3))
-    transitivePeerDependencies:
-      - supports-color
-      - typescript
-
   eslint-plugin-promise@7.2.1(eslint@9.20.1):
     dependencies:
       '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1)
@@ -10016,6 +10767,10 @@ snapshots:
 
   estraverse@5.3.0: {}
 
+  estree-walker@3.0.3:
+    dependencies:
+      '@types/estree': 1.0.6
+
   esutils@2.0.3: {}
 
   eventemitter3@4.0.7: {}
@@ -10033,6 +10788,7 @@ snapshots:
       onetime: 5.1.2
       signal-exit: 3.0.7
       strip-final-newline: 2.0.0
+    optional: true
 
   execa@8.0.1:
     dependencies:
@@ -10061,7 +10817,8 @@ snapshots:
       strip-final-newline: 4.0.0
       yoctocolors: 2.1.1
 
-  exit@0.1.2: {}
+  exit@0.1.2:
+    optional: true
 
   expand-template@2.0.3:
     optional: true
@@ -10074,6 +10831,8 @@ snapshots:
 
   expect-more@1.3.0: {}
 
+  expect-type@1.1.0: {}
+
   expect@29.7.0:
     dependencies:
       '@jest/expect-utils': 29.7.0
@@ -10081,6 +10840,7 @@ snapshots:
       jest-matcher-utils: 29.7.0
       jest-message-util: 29.7.0
       jest-util: 29.7.0
+    optional: true
 
   exponential-backoff@3.1.2:
     optional: true
@@ -10124,6 +10884,7 @@ snapshots:
   fb-watchman@2.0.2:
     dependencies:
       bser: 2.1.1
+    optional: true
 
   fd-slicer@1.1.0:
     dependencies:
@@ -10148,10 +10909,6 @@ snapshots:
   file-uri-to-path@1.0.0:
     optional: true
 
-  filelist@1.0.4:
-    dependencies:
-      minimatch: 5.1.6
-
   fill-range@7.1.1:
     dependencies:
       to-regex-range: 5.0.1
@@ -10441,6 +11198,8 @@ snapshots:
       slash: 5.1.0
       unicorn-magic: 0.3.0
 
+  globrex@0.1.2: {}
+
   good-enough-parser@1.1.23:
     dependencies:
       '@thi.ng/zipper': 1.0.3
@@ -10581,7 +11340,8 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  human-signals@2.1.0: {}
+  human-signals@2.1.0:
+    optional: true
 
   human-signals@5.0.0: {}
 
@@ -10646,6 +11406,7 @@ snapshots:
     dependencies:
       pkg-dir: 4.2.0
       resolve-cwd: 3.0.0
+    optional: true
 
   import-meta-resolve@4.1.0: {}
 
@@ -10773,7 +11534,8 @@ snapshots:
     dependencies:
       get-east-asian-width: 1.3.0
 
-  is-generator-fn@2.1.0: {}
+  is-generator-fn@2.1.0:
+    optional: true
 
   is-generator-function@1.1.0:
     dependencies:
@@ -10896,6 +11658,7 @@ snapshots:
       semver: 6.3.1
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   istanbul-lib-instrument@6.0.3:
     dependencies:
@@ -10930,6 +11693,14 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  istanbul-lib-source-maps@5.0.6:
+    dependencies:
+      '@jridgewell/trace-mapping': 0.3.25
+      debug: 4.4.0
+      istanbul-lib-coverage: 3.2.2
+    transitivePeerDependencies:
+      - supports-color
+
   istanbul-reports@3.1.7:
     dependencies:
       html-escaper: 2.0.2
@@ -10945,13 +11716,6 @@ snapshots:
     dependencies:
       '@isaacs/cliui': 8.0.2
 
-  jake@10.9.2:
-    dependencies:
-      async: 3.2.6
-      chalk: 4.1.2
-      filelist: 1.0.4
-      minimatch: 3.1.2
-
   java-properties@1.0.2: {}
 
   jest-changed-files@29.7.0:
@@ -10959,6 +11723,7 @@ snapshots:
       execa: 5.1.1
       jest-util: 29.7.0
       p-limit: 3.1.0
+    optional: true
 
   jest-circus@29.7.0:
     dependencies:
@@ -10985,6 +11750,7 @@ snapshots:
     transitivePeerDependencies:
       - babel-plugin-macros
       - supports-color
+    optional: true
 
   jest-cli@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)):
     dependencies:
@@ -11004,6 +11770,7 @@ snapshots:
       - babel-plugin-macros
       - supports-color
       - ts-node
+    optional: true
 
   jest-config@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)):
     dependencies:
@@ -11035,6 +11802,7 @@ snapshots:
     transitivePeerDependencies:
       - babel-plugin-macros
       - supports-color
+    optional: true
 
   jest-diff@29.7.0:
     dependencies:
@@ -11046,6 +11814,7 @@ snapshots:
   jest-docblock@29.7.0:
     dependencies:
       detect-newline: 3.1.0
+    optional: true
 
   jest-each@29.7.0:
     dependencies:
@@ -11054,6 +11823,7 @@ snapshots:
       jest-get-type: 29.6.3
       jest-util: 29.7.0
       pretty-format: 29.7.0
+    optional: true
 
   jest-environment-node@29.7.0:
     dependencies:
@@ -11063,6 +11833,7 @@ snapshots:
       '@types/node': 22.13.4
       jest-mock: 29.7.0
       jest-util: 29.7.0
+    optional: true
 
   jest-extended@4.0.2(jest@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3))):
     dependencies:
@@ -11088,11 +11859,13 @@ snapshots:
       walker: 1.0.8
     optionalDependencies:
       fsevents: 2.3.3
+    optional: true
 
   jest-leak-detector@29.7.0:
     dependencies:
       jest-get-type: 29.6.3
       pretty-format: 29.7.0
+    optional: true
 
   jest-matcher-utils@29.4.1:
     dependencies:
@@ -11107,6 +11880,7 @@ snapshots:
       jest-diff: 29.7.0
       jest-get-type: 29.6.3
       pretty-format: 29.7.0
+    optional: true
 
   jest-message-util@29.7.0:
     dependencies:
@@ -11119,24 +11893,22 @@ snapshots:
       pretty-format: 29.7.0
       slash: 3.0.0
       stack-utils: 2.0.6
-
-  jest-mock-extended@3.0.7(jest@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3):
-    dependencies:
-      jest: 29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3))
-      ts-essentials: 10.0.4(typescript@5.7.3)
-      typescript: 5.7.3
+    optional: true
 
   jest-mock@29.7.0:
     dependencies:
       '@jest/types': 29.6.3
       '@types/node': 22.13.4
       jest-util: 29.7.0
+    optional: true
 
   jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
     optionalDependencies:
       jest-resolve: 29.7.0
+    optional: true
 
-  jest-regex-util@29.6.3: {}
+  jest-regex-util@29.6.3:
+    optional: true
 
   jest-resolve-dependencies@29.7.0:
     dependencies:
@@ -11144,6 +11916,7 @@ snapshots:
       jest-snapshot: 29.7.0
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   jest-resolve@29.7.0:
     dependencies:
@@ -11156,6 +11929,7 @@ snapshots:
       resolve: 1.22.10
       resolve.exports: 2.0.3
       slash: 3.0.0
+    optional: true
 
   jest-runner@29.7.0:
     dependencies:
@@ -11182,6 +11956,7 @@ snapshots:
       source-map-support: 0.5.13
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   jest-runtime@29.7.0:
     dependencies:
@@ -11209,6 +11984,7 @@ snapshots:
       strip-bom: 4.0.0
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   jest-snapshot@29.7.0:
     dependencies:
@@ -11234,6 +12010,7 @@ snapshots:
       semver: 7.7.1
     transitivePeerDependencies:
       - supports-color
+    optional: true
 
   jest-util@29.7.0:
     dependencies:
@@ -11243,6 +12020,7 @@ snapshots:
       ci-info: 3.9.0
       graceful-fs: 4.2.11
       picomatch: 2.3.1
+    optional: true
 
   jest-validate@29.7.0:
     dependencies:
@@ -11252,6 +12030,7 @@ snapshots:
       jest-get-type: 29.6.3
       leven: 3.1.0
       pretty-format: 29.7.0
+    optional: true
 
   jest-watcher@29.7.0:
     dependencies:
@@ -11263,6 +12042,7 @@ snapshots:
       emittery: 0.13.1
       jest-util: 29.7.0
       string-length: 4.0.2
+    optional: true
 
   jest-worker@29.7.0:
     dependencies:
@@ -11270,6 +12050,7 @@ snapshots:
       jest-util: 29.7.0
       merge-stream: 2.0.0
       supports-color: 8.1.1
+    optional: true
 
   jest@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)):
     dependencies:
@@ -11282,6 +12063,7 @@ snapshots:
       - babel-plugin-macros
       - supports-color
       - ts-node
+    optional: true
 
   js-md4@0.3.2: {}
 
@@ -11374,11 +12156,13 @@ snapshots:
 
   kind-of@6.0.3: {}
 
-  kleur@3.0.3: {}
+  kleur@3.0.3:
+    optional: true
 
   klona@2.0.6: {}
 
-  leven@3.1.0: {}
+  leven@3.1.0:
+    optional: true
 
   levn@0.4.1:
     dependencies:
@@ -11459,8 +12243,6 @@ snapshots:
 
   lodash.isstring@4.0.1: {}
 
-  lodash.memoize@4.1.2: {}
-
   lodash.merge@4.6.2: {}
 
   lodash.uniqby@4.7.0: {}
@@ -11479,6 +12261,8 @@ snapshots:
 
   longest-streak@2.0.4: {}
 
+  loupe@3.1.3: {}
+
   lowercase-keys@2.0.0: {}
 
   lru-cache@10.4.3: {}
@@ -11495,6 +12279,16 @@ snapshots:
 
   luxon@3.5.0: {}
 
+  magic-string@0.30.17:
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.5.0
+
+  magicast@0.3.5:
+    dependencies:
+      '@babel/parser': 7.26.9
+      '@babel/types': 7.26.9
+      source-map-js: 1.2.1
+
   make-dir@3.1.0:
     dependencies:
       semver: 6.3.1
@@ -11526,6 +12320,7 @@ snapshots:
   makeerror@1.0.12:
     dependencies:
       tmpl: 1.0.5
+    optional: true
 
   map-obj@1.0.1: {}
 
@@ -11852,7 +12647,8 @@ snapshots:
 
   mime@4.0.6: {}
 
-  mimic-fn@2.1.0: {}
+  mimic-fn@2.1.0:
+    optional: true
 
   mimic-fn@4.0.0: {}
 
@@ -11874,10 +12670,6 @@ snapshots:
     dependencies:
       brace-expansion: 1.1.11
 
-  minimatch@5.1.6:
-    dependencies:
-      brace-expansion: 2.0.1
-
   minimatch@9.0.2:
     dependencies:
       brace-expansion: 2.0.1
@@ -12037,7 +12829,8 @@ snapshots:
       css-select: 5.1.0
       he: 1.2.0
 
-  node-int64@0.4.0: {}
+  node-int64@0.4.0:
+    optional: true
 
   node-preload@0.2.1:
     dependencies:
@@ -12070,7 +12863,8 @@ snapshots:
       semver: 7.7.1
       validate-npm-package-license: 3.0.4
 
-  normalize-path@3.0.0: {}
+  normalize-path@3.0.0:
+    optional: true
 
   normalize-url@6.1.0: {}
 
@@ -12092,6 +12886,7 @@ snapshots:
   npm-run-path@4.0.1:
     dependencies:
       path-key: 3.1.1
+    optional: true
 
   npm-run-path@5.3.0:
     dependencies:
@@ -12182,6 +12977,7 @@ snapshots:
   onetime@5.1.2:
     dependencies:
       mimic-fn: 2.1.0
+    optional: true
 
   onetime@6.0.0:
     dependencies:
@@ -12385,6 +13181,10 @@ snapshots:
 
   path-type@6.0.0: {}
 
+  pathe@2.0.3: {}
+
+  pathval@2.0.0: {}
+
   pend@1.2.0: {}
 
   pgp-utils@0.0.35:
@@ -12402,7 +13202,8 @@ snapshots:
 
   pify@3.0.0: {}
 
-  pirates@4.0.6: {}
+  pirates@4.0.6:
+    optional: true
 
   pkg-conf@2.1.0:
     dependencies:
@@ -12415,6 +13216,12 @@ snapshots:
 
   possible-typed-array-names@1.1.0: {}
 
+  postcss@8.5.3:
+    dependencies:
+      nanoid: 3.3.8
+      picocolors: 1.1.1
+      source-map-js: 1.2.1
+
   prebuild-install@7.1.3:
     dependencies:
       detect-libc: 2.0.3
@@ -12466,6 +13273,7 @@ snapshots:
     dependencies:
       kleur: 3.0.3
       sisteransi: 1.0.5
+    optional: true
 
   propagate@2.0.1: {}
 
@@ -12497,7 +13305,8 @@ snapshots:
 
   punycode@2.3.1: {}
 
-  pure-rand@6.1.0: {}
+  pure-rand@6.1.0:
+    optional: true
 
   purepack@1.0.6: {}
 
@@ -12669,6 +13478,7 @@ snapshots:
   resolve-cwd@3.0.0:
     dependencies:
       resolve-from: 5.0.0
+    optional: true
 
   resolve-from@4.0.0: {}
 
@@ -12676,7 +13486,8 @@ snapshots:
 
   resolve-pkg-maps@1.0.0: {}
 
-  resolve.exports@2.0.3: {}
+  resolve.exports@2.0.3:
+    optional: true
 
   resolve@1.22.10:
     dependencies:
@@ -12722,6 +13533,31 @@ snapshots:
       semver-compare: 1.0.0
       sprintf-js: 1.1.3
 
+  rollup@4.34.8:
+    dependencies:
+      '@types/estree': 1.0.6
+    optionalDependencies:
+      '@rollup/rollup-android-arm-eabi': 4.34.8
+      '@rollup/rollup-android-arm64': 4.34.8
+      '@rollup/rollup-darwin-arm64': 4.34.8
+      '@rollup/rollup-darwin-x64': 4.34.8
+      '@rollup/rollup-freebsd-arm64': 4.34.8
+      '@rollup/rollup-freebsd-x64': 4.34.8
+      '@rollup/rollup-linux-arm-gnueabihf': 4.34.8
+      '@rollup/rollup-linux-arm-musleabihf': 4.34.8
+      '@rollup/rollup-linux-arm64-gnu': 4.34.8
+      '@rollup/rollup-linux-arm64-musl': 4.34.8
+      '@rollup/rollup-linux-loongarch64-gnu': 4.34.8
+      '@rollup/rollup-linux-powerpc64le-gnu': 4.34.8
+      '@rollup/rollup-linux-riscv64-gnu': 4.34.8
+      '@rollup/rollup-linux-s390x-gnu': 4.34.8
+      '@rollup/rollup-linux-x64-gnu': 4.34.8
+      '@rollup/rollup-linux-x64-musl': 4.34.8
+      '@rollup/rollup-win32-arm64-msvc': 4.34.8
+      '@rollup/rollup-win32-ia32-msvc': 4.34.8
+      '@rollup/rollup-win32-x64-msvc': 4.34.8
+      fsevents: 2.3.3
+
   run-parallel@1.2.0:
     dependencies:
       queue-microtask: 1.2.3
@@ -12879,6 +13715,8 @@ snapshots:
       side-channel-map: 1.0.1
       side-channel-weakmap: 1.0.2
 
+  siginfo@2.0.0: {}
+
   signal-exit@3.0.7: {}
 
   signal-exit@4.1.0: {}
@@ -12916,13 +13754,15 @@ snapshots:
       nise: 6.1.1
       supports-color: 7.2.0
 
-  sisteransi@1.0.5: {}
+  sisteransi@1.0.5:
+    optional: true
 
   skin-tone@2.0.0:
     dependencies:
       unicode-emoji-modifier-base: 1.0.0
 
-  slash@3.0.0: {}
+  slash@3.0.0:
+    optional: true
 
   slash@5.1.0: {}
 
@@ -12960,10 +13800,13 @@ snapshots:
     dependencies:
       is-plain-obj: 2.1.0
 
+  source-map-js@1.2.1: {}
+
   source-map-support@0.5.13:
     dependencies:
       buffer-from: 1.1.2
       source-map: 0.6.1
+    optional: true
 
   source-map-support@0.5.21:
     dependencies:
@@ -13023,6 +13866,11 @@ snapshots:
   stack-utils@2.0.6:
     dependencies:
       escape-string-regexp: 2.0.0
+    optional: true
+
+  stackback@0.0.2: {}
+
+  std-env@3.8.0: {}
 
   stream-combiner2@1.1.1:
     dependencies:
@@ -13035,6 +13883,7 @@ snapshots:
     dependencies:
       char-regex: 1.0.2
       strip-ansi: 6.0.1
+    optional: true
 
   string-width@4.2.3:
     dependencies:
@@ -13099,7 +13948,8 @@ snapshots:
 
   strip-comments-strings@1.2.0: {}
 
-  strip-final-newline@2.0.0: {}
+  strip-final-newline@2.0.0:
+    optional: true
 
   strip-final-newline@3.0.0: {}
 
@@ -13131,6 +13981,7 @@ snapshots:
   supports-color@8.1.1:
     dependencies:
       has-flag: 4.0.0
+    optional: true
 
   supports-hyperlinks@3.2.0:
     dependencies:
@@ -13191,6 +14042,12 @@ snapshots:
       glob: 7.2.3
       minimatch: 3.1.2
 
+  test-exclude@7.0.1:
+    dependencies:
+      '@istanbuljs/schema': 0.1.3
+      glob: 10.4.5
+      minimatch: 9.0.5
+
   text-table@0.2.0: {}
 
   thenify-all@1.6.0:
@@ -13222,6 +14079,10 @@ snapshots:
     dependencies:
       convert-hrtime: 5.0.0
 
+  tinybench@2.9.0: {}
+
+  tinyexec@0.3.2: {}
+
   tinyglobby@0.2.12:
     dependencies:
       fdir: 6.4.3(picomatch@4.0.2)
@@ -13229,13 +14090,20 @@ snapshots:
 
   tinylogic@2.0.0: {}
 
+  tinypool@1.0.2: {}
+
+  tinyrainbow@2.0.0: {}
+
+  tinyspy@3.0.2: {}
+
   tmp-promise@3.0.3:
     dependencies:
       tmp: 0.2.3
 
   tmp@0.2.3: {}
 
-  tmpl@1.0.5: {}
+  tmpl@1.0.5:
+    optional: true
 
   to-regex-range@5.0.1:
     dependencies:
@@ -13276,25 +14144,6 @@ snapshots:
     optionalDependencies:
       typescript: 5.7.3
 
-  ts-jest@29.2.5(@babel/core@7.26.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.9))(jest@29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3):
-    dependencies:
-      bs-logger: 0.2.6
-      ejs: 3.1.10
-      fast-json-stable-stringify: 2.1.0
-      jest: 29.7.0(@types/node@22.13.4)(ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3))
-      jest-util: 29.7.0
-      json5: 2.2.3
-      lodash.memoize: 4.1.2
-      make-error: 1.3.6
-      semver: 7.7.1
-      typescript: 5.7.3
-      yargs-parser: 21.1.1
-    optionalDependencies:
-      '@babel/core': 7.26.9
-      '@jest/transform': 29.7.0
-      '@jest/types': 29.6.3
-      babel-jest: 29.7.0(@babel/core@7.26.9)
-
   ts-node@10.9.2(@types/node@22.13.4)(typescript@5.7.3):
     dependencies:
       '@cspotcode/source-map-support': 0.8.1
@@ -13313,6 +14162,10 @@ snapshots:
       v8-compile-cache-lib: 3.0.1
       yn: 3.1.1
 
+  tsconfck@3.1.5(typescript@5.7.3):
+    optionalDependencies:
+      typescript: 5.7.3
+
   tsconfig-paths@3.15.0:
     dependencies:
       '@types/json5': 0.0.29
@@ -13347,7 +14200,8 @@ snapshots:
 
   type-fest@0.18.1: {}
 
-  type-fest@0.21.3: {}
+  type-fest@0.21.3:
+    optional: true
 
   type-fest@0.6.0: {}
 
@@ -13433,6 +14287,10 @@ snapshots:
 
   undici-types@6.20.0: {}
 
+  undici@5.28.5:
+    dependencies:
+      '@fastify/busboy': 2.1.1
+
   unicode-emoji-modifier-base@1.0.0: {}
 
   unicorn-magic@0.1.0: {}
@@ -13529,6 +14387,7 @@ snapshots:
       '@jridgewell/trace-mapping': 0.3.25
       '@types/istanbul-lib-coverage': 2.0.6
       convert-source-map: 2.0.0
+    optional: true
 
   validate-npm-package-license@3.0.4:
     dependencies:
@@ -13553,11 +14412,104 @@ snapshots:
       unist-util-stringify-position: 2.0.3
       vfile-message: 2.0.4
 
+  vite-node@3.0.6(@types/node@22.13.4)(yaml@2.7.0):
+    dependencies:
+      cac: 6.7.14
+      debug: 4.4.0
+      es-module-lexer: 1.6.0
+      pathe: 2.0.3
+      vite: 6.1.1(@types/node@22.13.4)(yaml@2.7.0)
+    transitivePeerDependencies:
+      - '@types/node'
+      - jiti
+      - less
+      - lightningcss
+      - sass
+      - sass-embedded
+      - stylus
+      - sugarss
+      - supports-color
+      - terser
+      - tsx
+      - yaml
+
+  vite-tsconfig-paths@5.1.4(typescript@5.7.3)(vite@6.1.1(@types/node@22.13.4)(yaml@2.7.0)):
+    dependencies:
+      debug: 4.4.0
+      globrex: 0.1.2
+      tsconfck: 3.1.5(typescript@5.7.3)
+    optionalDependencies:
+      vite: 6.1.1(@types/node@22.13.4)(yaml@2.7.0)
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+
+  vite@6.1.1(@types/node@22.13.4)(yaml@2.7.0):
+    dependencies:
+      esbuild: 0.25.0
+      postcss: 8.5.3
+      rollup: 4.34.8
+    optionalDependencies:
+      '@types/node': 22.13.4
+      fsevents: 2.3.3
+      yaml: 2.7.0
+
+  vitest-github-actions-reporter@0.11.1(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0)):
+    dependencies:
+      '@actions/core': 1.11.1
+      vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0)
+
+  vitest-mock-extended@3.0.1(typescript@5.7.3)(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0)):
+    dependencies:
+      ts-essentials: 10.0.4(typescript@5.7.3)
+      typescript: 5.7.3
+      vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0)
+
+  vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.4)(yaml@2.7.0):
+    dependencies:
+      '@vitest/expect': 3.0.6
+      '@vitest/mocker': 3.0.6(vite@6.1.1(@types/node@22.13.4)(yaml@2.7.0))
+      '@vitest/pretty-format': 3.0.6
+      '@vitest/runner': 3.0.6
+      '@vitest/snapshot': 3.0.6
+      '@vitest/spy': 3.0.6
+      '@vitest/utils': 3.0.6
+      chai: 5.2.0
+      debug: 4.4.0
+      expect-type: 1.1.0
+      magic-string: 0.30.17
+      pathe: 2.0.3
+      std-env: 3.8.0
+      tinybench: 2.9.0
+      tinyexec: 0.3.2
+      tinypool: 1.0.2
+      tinyrainbow: 2.0.0
+      vite: 6.1.1(@types/node@22.13.4)(yaml@2.7.0)
+      vite-node: 3.0.6(@types/node@22.13.4)(yaml@2.7.0)
+      why-is-node-running: 2.3.0
+    optionalDependencies:
+      '@types/debug': 4.1.12
+      '@types/node': 22.13.4
+    transitivePeerDependencies:
+      - jiti
+      - less
+      - lightningcss
+      - msw
+      - sass
+      - sass-embedded
+      - stylus
+      - sugarss
+      - supports-color
+      - terser
+      - tsx
+      - yaml
+
   vuln-vects@1.1.0: {}
 
   walker@1.0.8:
     dependencies:
       makeerror: 1.0.12
+    optional: true
 
   webidl-conversions@3.0.1: {}
 
@@ -13621,6 +14573,11 @@ snapshots:
     dependencies:
       isexe: 3.1.1
 
+  why-is-node-running@2.3.0:
+    dependencies:
+      siginfo: 2.0.0
+      stackback: 0.0.2
+
   word-wrap@1.2.5: {}
 
   wordwrap@1.0.0: {}
@@ -13662,6 +14619,7 @@ snapshots:
     dependencies:
       imurmurhash: 0.1.4
       signal-exit: 3.0.7
+    optional: true
 
   write-file-atomic@5.0.1:
     dependencies:
diff --git a/test/exec-util.ts b/test/exec-util.ts
index 0fb5ca0de4..a197d7bf70 100644
--- a/test/exec-util.ts
+++ b/test/exec-util.ts
@@ -6,7 +6,7 @@ import type { RawExecOptions } from '../lib/util/exec/types';
 import { regEx } from '../lib/util/regex';
 import { mockedFunction } from './util';
 
-jest.mock('../lib/util/exec/common');
+vi.mock('../lib/util/exec/common');
 
 export type ExecResult = { stdout: string; stderr: string } | Error;
 
diff --git a/test/fixtures.ts b/test/fixtures.ts
index 2c498ac07d..7970cae942 100644
--- a/test/fixtures.ts
+++ b/test/fixtures.ts
@@ -1,4 +1,3 @@
-import fs from 'node:fs';
 import type { PathLike, Stats } from 'node:fs';
 import callsite from 'callsite';
 import type { DirectoryJSON } from 'memfs';
@@ -6,7 +5,8 @@ import { fs as memfs, vol } from 'memfs';
 import type { TDataOut } from 'memfs/lib/encoding';
 import upath from 'upath';
 
-const realFs = fs; //jest.requireActual<typeof fs>('fs');
+// eslint-disable-next-line @typescript-eslint/no-require-imports
+const realFs: typeof import('node:fs') = require('node:fs'); // used to bypass vitest mock
 
 /**
  * Class to work with in-memory file-system
@@ -95,14 +95,15 @@ export class Fixtures {
    */
   static reset(): void {
     vol.reset();
-    fsExtraMock.pathExists.mockImplementation(pathExists);
-    fsExtraMock.remove.mockImplementation(memfs.promises.rm);
-    fsExtraMock.removeSync.mockImplementation(memfs.rmSync);
-    fsExtraMock.readFile.mockImplementation(readFile);
-    fsExtraMock.writeFile.mockImplementation(memfs.promises.writeFile);
-    fsExtraMock.outputFile.mockImplementation(outputFile);
-    fsExtraMock.stat.mockImplementation(stat);
-    fsExtraMock.chmod.mockImplementation(memfs.promises.chmod);
+    fsExtraMock.pathExists.mockReset();
+    fsExtraMock.remove.mockReset();
+    fsExtraMock.removeSync.mockReset();
+    fsExtraMock.readFile.mockReset();
+    fsExtraMock.writeFile.mockReset();
+    fsExtraMock.outputFile.mockReset();
+    fsExtraMock.stat.mockReset();
+    fsExtraMock.chmod.mockReset();
+    fsExtraMock.ensureDir.mockReset();
   }
 
   private static getPathToFixtures(fixturesRoot = '.'): string {
@@ -113,27 +114,32 @@ export class Fixtures {
 }
 
 const fsExtraMock = {
-  pathExists: jest.fn(),
-  remove: jest.fn(),
-  removeSync: jest.fn(),
-  readFile: jest.fn(),
-  writeFile: jest.fn(),
-  outputFile: jest.fn(),
-  stat: jest.fn(),
-  chmod: jest.fn(),
+  pathExists: vi.fn(pathExists),
+  remove: vi.fn(memfs.promises.rm),
+  removeSync: vi.fn(memfs.rmSync),
+  readFile: vi.fn(readFile),
+  writeFile: vi.fn(memfs.promises.writeFile),
+  outputFile: vi.fn(outputFile),
+  stat: vi.fn(stat),
+  chmod: vi.fn(memfs.promises.chmod),
+  // See fs-extra
+  ensureDir: vi.fn((path) =>
+    memfs.promises.mkdir(path, { recursive: true, mode: 0o777 }),
+  ),
 };
 
 // Temporary solution, when all tests will be rewritten to Fixtures mocks can be moved into __mocks__ folder
 export function fsExtra(): any {
-  return {
+  const fs = {
     ...memfs,
     ...fsExtraMock,
   };
+  return { ...fs, default: fs };
 }
 
 export function readFile(fileName: string, options: any): Promise<TDataOut> {
   if (fileName.endsWith('.wasm') || fileName.endsWith('.wasm.gz')) {
-    return fs.promises.readFile(fileName, options);
+    return realFs.promises.readFile(fileName, options);
   }
 
   return memfs.promises.readFile(fileName, options);
diff --git a/test/global-setup.ts b/test/global-setup.ts
deleted file mode 100644
index 394fe3851b..0000000000
--- a/test/global-setup.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default function () {
-  // Set timezone so snapshots are consistent
-  process.env.TZ = 'UTC';
-}
diff --git a/test/http-mock.ts b/test/http-mock.ts
index 5413a44282..a2ced5325a 100644
--- a/test/http-mock.ts
+++ b/test/http-mock.ts
@@ -1,5 +1,5 @@
+import fs from 'node:fs';
 import type { Url } from 'node:url';
-import { afterAll, afterEach, beforeAll } from '@jest/globals';
 import { codeBlock } from 'common-tags';
 // eslint-disable-next-line no-restricted-imports
 import nock from 'nock';
@@ -123,7 +123,6 @@ function massageHttpMockStacktrace(err: Error): void {
     return;
   }
 
-  const fs: typeof import('fs-extra') = jest.requireActual('fs-extra');
   const content = fs.readFileSync(state.testPath, { encoding: 'utf8' });
 
   // Shrink the `testName` until we could locate it in the source file
diff --git a/test/jest-legacy.ts b/test/jest-legacy.ts
new file mode 100644
index 0000000000..993c09667c
--- /dev/null
+++ b/test/jest-legacy.ts
@@ -0,0 +1,57 @@
+import { vi } from 'vitest';
+
+// TODO: remove when all tests are migrated to vitest
+Object.defineProperty(globalThis, 'jest', {
+  value: {
+    fn: vi.fn,
+    spyOn: vi.spyOn,
+    doMock: vi.doMock,
+    doUnmock: vi.doUnmock,
+    resetModules: vi.resetModules,
+    resetAllMocks: vi.resetAllMocks,
+    restoreAllMocks: vi.restoreAllMocks,
+    useFakeTimers: vi.useFakeTimers,
+    useRealTimers: vi.useRealTimers,
+    setSystemTime: vi.setSystemTime,
+    advanceTimersByTime: vi.advanceTimersByTime,
+    advanceTimersByTimeAsync: vi.advanceTimersByTimeAsync,
+  },
+});
+
+interface GlobalJest {
+  /** @deprecated */
+  fn: typeof vi.fn;
+  /** @deprecated */
+  spyOn: typeof vi.spyOn;
+
+  /** @deprecated */
+  doMock: typeof vi.doMock;
+  /** @deprecated */
+  doUnmock: typeof vi.doUnmock;
+
+  /** @deprecated */
+  resetModules: typeof vi.resetModules;
+
+  /** @deprecated */
+  resetAllMocks: typeof vi.resetAllMocks;
+  /** @deprecated */
+  restoreAllMocks: typeof vi.restoreAllMocks;
+
+  /** @deprecated */
+  useFakeTimers: typeof vi.useFakeTimers;
+  /** @deprecated */
+  useRealTimers: typeof vi.useRealTimers;
+  /** @deprecated */
+  setSystemTime: typeof vi.setSystemTime;
+  /** @deprecated */
+  advanceTimersByTime: typeof vi.advanceTimersByTime;
+  /** @deprecated */
+  advanceTimersByTimeAsync: typeof vi.advanceTimersByTimeAsync;
+}
+
+declare global {
+  /**
+   * @deprecated
+   */
+  const jest: GlobalJest;
+}
diff --git a/test/newline-snapshot-serializer.ts b/test/newline-snapshot-serializer.ts
deleted file mode 100644
index adbd674156..0000000000
--- a/test/newline-snapshot-serializer.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-let prev: string;
-
-// this does not work as intended
-// see https://jestjs.io/docs/en/configuration#snapshotserializers-arraystring
-export function print(val: string): string {
-  return JSON.stringify(val);
-}
-export function test(val: string): boolean {
-  if (['prBody', 'prTitle'].some((str) => str === prev)) {
-    return typeof val === 'string' && val.includes('\n');
-  }
-  prev = val;
-  return false;
-}
diff --git a/test/s3.ts b/test/s3.ts
index 85f94122e7..b14eab9b42 100644
--- a/test/s3.ts
+++ b/test/s3.ts
@@ -1,4 +1,3 @@
-import { jest } from '@jest/globals';
 import * as _s3 from '../lib/util/s3';
 
-export const s3 = jest.mocked(_s3);
+export const s3 = vi.mocked(_s3);
diff --git a/test/setup.ts b/test/setup.ts
index 6eddbf176d..49da83aa70 100644
--- a/test/setup.ts
+++ b/test/setup.ts
@@ -1,20 +1,29 @@
 // Check for missing or pending http mocks
 import './http-mock';
-import { mockDeep } from 'jest-mock-extended';
+import { mockDeep } from 'vitest-mock-extended';
 import type { Platform, PlatformScm } from '../lib/modules/platform';
+import * as _fixtures from './fixtures';
 
-jest.mock('../lib/modules/platform', () => ({
+// Set timezone so snapshots are consistent
+process.env.TZ = 'UTC';
+
+vi.mock('../lib/modules/platform', () => ({
   platform: mockDeep<Platform>(),
-  initPlatform: jest.fn(),
-  getPlatformList: jest.fn(),
+  initPlatform: vi.fn(),
+  getPlatformList: vi.fn(),
 }));
 
-jest.mock('../lib/modules/platform/scm', () => ({
+vi.mock('../lib/modules/platform/scm', () => ({
   scm: mockDeep<PlatformScm>(),
 }));
 
-jest.mock('../lib/logger', () => {
+vi.mock('../lib/logger', () => {
   return mockDeep({
     withMeta: <T>(_: Record<string, unknown>, cb: () => T): T => cb(),
   });
 });
+
+Object.defineProperty(global, 'fixtures', { value: _fixtures });
+declare global {
+  const fixtures: typeof _fixtures;
+}
diff --git a/test/to-migrate.ts b/test/to-migrate.ts
index 41fac75dda..dd800e9445 100644
--- a/test/to-migrate.ts
+++ b/test/to-migrate.ts
@@ -1,10 +1,8 @@
-import { expect } from '@jest/globals';
 import type {
   Migration,
   MigrationConstructor,
 } from '../lib/config/migrations/types';
 import type { RenovateConfig } from '../lib/config/types';
-import { MigrationsService } from './../lib/config/migrations/migrations-service';
 
 declare global {
   // eslint-disable-next-line @typescript-eslint/no-namespace
@@ -20,12 +18,16 @@ declare global {
 }
 
 expect.extend({
-  toMigrate(
+  async toMigrate(
     CustomMigration: MigrationConstructor,
     originalConfig: RenovateConfig,
     expectedConfig: RenovateConfig,
     isMigrated = true,
   ) {
+    // async load to avoid circular dependency
+    const { MigrationsService } = await import(
+      './../lib/config/migrations/migrations-service'
+    );
     class CustomMigrationsService extends MigrationsService {
       public static override getMigrations(
         original: RenovateConfig,
diff --git a/test/tsconfig.json b/test/tsconfig.json
deleted file mode 100644
index 9df43c15e2..0000000000
--- a/test/tsconfig.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "extends": "../tsconfig"
-}
diff --git a/test/types/expect-more-jest.d.ts b/test/types/expect-more-jest.d.ts
new file mode 100644
index 0000000000..05764462e6
--- /dev/null
+++ b/test/types/expect-more-jest.d.ts
@@ -0,0 +1,71 @@
+/**
+ * partial from expect-more-jest
+ * https://github.com/JamieMason/expect-more
+ */
+interface ExpectMoreMatchers<R> {
+  /**
+   * Asserts that a value is an `Array` including only the values provided in the given `allowedValues` array and no others. The order and number of times each value appears in either array does not matter. Returns true unless `value` contains a value which does not feature in `allowedValues`.
+   * @example
+   * expect([5, 10, 1]).toBeArrayIncludingOnly([1, 5, 10]);
+   */
+  toBeArrayIncludingOnly(allowedValues: unknown[]): R;
+
+  /**
+   * Asserts that a value is an `Array` where every member is equal to ${other}.
+   * @example
+   * expect([{ name: 'Guybrush' }, { name: 'Elaine' }]).toBeArrayOf({
+   *   name: expect.toBeNonEmptyString()
+   * });
+   */
+  toBeArrayOf(other: unknown): R;
+
+  /**
+   * Asserts that a value is an `Array` containing only `String` values.
+   * @example
+   * expect(['we', 'are', 'all', 'strings']).toBeArrayOfStrings();
+   */
+  toBeArrayOfStrings(): R;
+
+  /**
+   * Asserts that a value is a valid `Array` containing no items.
+   * @example
+   * expect([]).toBeEmptyArray();
+   */
+  toBeEmptyArray(): R;
+
+  /**
+   * Asserts that a value is a valid `String` containing no characters.
+   * @example
+   * expect('').toBeEmptyString();
+   */
+  toBeEmptyString(): R;
+
+  /**
+   * Asserts that a value is a `String` of valid JSON.
+   * @example
+   * expect('{"i":"am valid JSON"}').toBeJsonString();
+   */
+  toBeJsonString(): R;
+
+  /**
+   * Asserts that a value is an `Array` containing at least one value.
+   * @example
+   * expect(['i', 'am not empty']).toBeNonEmptyArray();
+   */
+  toBeNonEmptyArray(): R;
+
+  /**
+   * Asserts that a value is an `Object` containing at least one own member.
+   * @example
+   * expect({ i: 'am not empty' }).toBeNonEmptyObject();
+   */
+  toBeNonEmptyObject(): R;
+}
+
+declare module 'vitest' {
+  interface Assertion<T = any> extends ExpectMoreMatchers<T> {}
+  //   interface AsymmetricMatchersContaining<T = any> extends CustomMatchers<T> {}
+  interface ExpectStatic extends ExpectMoreMatchers<any> {}
+}
+
+export {};
diff --git a/test/types/jest-extended.d.ts b/test/types/jest-extended.d.ts
new file mode 100644
index 0000000000..7152bcebb4
--- /dev/null
+++ b/test/types/jest-extended.d.ts
@@ -0,0 +1,882 @@
+/**
+ * partial from jest-exteded
+ * https://github.com/jest-community/jest-extended
+ */
+interface JestExtendedMatchers<R> {
+  /**
+   * Use .toBeEmpty when checking if a String '', Array [] or Object {} is empty.
+   */
+  toBeEmpty(): R;
+
+  /**
+   * Use .toBeOneOf when checking if a value is a member of a given Array.
+   * @param {Array.<*>} members
+   */
+  // included in vitest
+  // toBeOneOf<E = unknown>(members: readonly E[]): R;
+
+  /**
+   * Use `.toBeNil` when checking a value is `null` or `undefined`.
+   */
+  toBeNil(): R;
+
+  /**
+   * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`.
+   * @param {Function} predicate
+   */
+  toSatisfy<E = any>(predicate: (x: E) => boolean): R;
+
+  /**
+   * Use `.toBeArray` when checking if a value is an `Array`.
+   */
+  toBeArray(): R;
+
+  /**
+   * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x.
+   * @param {Number} x
+   */
+  toBeArrayOfSize(x: number): R;
+
+  /**
+   * Use `.toBeAfter` when checking if a date occurs after `date`.
+   * @param {Date} date
+   */
+  toBeAfter(date: Date): R;
+
+  /**
+   * Use `.toBeBefore` when checking if a date occurs before `date`.
+   * @param {Date} date
+   */
+  toBeBefore(date: Date): R;
+
+  /**
+   * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set.
+   * @param {Array.<*>} members
+   */
+  toIncludeAllMembers<E = unknown>(members: readonly E[]): R;
+
+  /**
+   * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set.
+   * @param {Array.<*>} members
+   */
+  toIncludeAnyMembers<E = unknown>(members: readonly E[]): R;
+
+  /**
+   * Use `.toIncludeSameMembers` when checking if two arrays contain equal values, in any order.
+   * @param {Array.<*>} members
+   */
+  toIncludeSameMembers<E = unknown>(members: readonly E[]): R;
+
+  /**
+   * Use `.toPartiallyContain` when checking if any array value matches the partial member.
+   * @param {*} member
+   */
+  toPartiallyContain<E = unknown>(member: E): R;
+
+  /**
+   * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array.
+   * @param {Function} predicate
+   */
+  toSatisfyAll<E = any>(predicate: (x: E) => boolean): R;
+
+  /**
+   * Use `.toSatisfyAny` when you want to use a custom matcher by supplying a predicate function that returns `true` for any matching value in an array.
+   * @param {Function} predicate
+   */
+  toSatisfyAny(predicate: (x: any) => boolean): R;
+
+  /**
+   * Use `.toBeBoolean` when checking if a value is a `Boolean`.
+   */
+  toBeBoolean(): R;
+
+  /**
+   * Use `.toBeTrue` when checking a value is equal (===) to `true`.
+   */
+  toBeTrue(): R;
+
+  /**
+   * Use `.toBeFalse` when checking a value is equal (===) to `false`.
+   */
+  toBeFalse(): R;
+
+  /**
+   * Use `.toBeDate` when checking if a value is a `Date`.
+   */
+  toBeDate(): R;
+
+  /**
+   * Use `.toBeValidDate` when checking if a value is a `valid Date`.
+   */
+  toBeValidDate(): R;
+
+  /**
+   * Use `.toBeFunction` when checking if a value is a `Function`.
+   */
+  toBeFunction(): R;
+
+  /**
+   * Use `.toBeDateString` when checking if a value is a valid date string.
+   */
+  toBeDateString(): R;
+
+  /**
+   * Use `.toBeHexadecimal` when checking if a value is a valid HTML hex color.
+   */
+  toBeHexadecimal(): R;
+
+  /**
+   * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`.
+   *
+   * Note: Required Jest version >=23
+   *
+   * @param {Mock} mock
+   * @param {boolean} [failIfNoSecondInvocation=true]
+   */
+  toHaveBeenCalledBefore(
+    mock: jest.MockInstance<any, any[]>,
+    failIfNoSecondInvocation?: boolean,
+  ): R;
+
+  /**
+   * Use `.toHaveBeenCalledAfter` when checking if a `Mock` was called after another `Mock`.
+   *
+   * Note: Required Jest version >=23
+   *
+   * @param {Mock} mock
+   * @param {boolean} [failIfNoFirstInvocation=true]
+   */
+  toHaveBeenCalledAfter(
+    mock: jest.MockInstance<any, any[]>,
+    failIfNoFirstInvocation?: boolean,
+  ): R;
+
+  /**
+   * Use `.toHaveBeenCalledOnce` to check if a `Mock` was called exactly one time.
+   */
+  toHaveBeenCalledOnce(): R;
+
+  /**
+   * Use `.toHaveBeenCalledExactlyOnceWith` to check if a `Mock` was called exactly one time with the expected value.
+   */
+  toHaveBeenCalledExactlyOnceWith(...args: unknown[]): R;
+
+  /**
+   * Use `.toBeNumber` when checking if a value is a `Number`.
+   */
+  toBeNumber(): R;
+
+  /**
+   * Use `.toBeNaN` when checking a value is `NaN`.
+   */
+  toBeNaN(): R;
+
+  /**
+   * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`.
+   */
+  toBeFinite(): R;
+
+  /**
+   * Use `.toBePositive` when checking if a value is a positive `Number`.
+   */
+  toBePositive(): R;
+
+  /**
+   * Use `.toBeNegative` when checking if a value is a negative `Number`.
+   */
+  toBeNegative(): R;
+
+  /**
+   * Use `.toBeEven` when checking if a value is an even `Number`.
+   */
+  toBeEven(): R;
+
+  /**
+   * Use `.toBeOdd` when checking if a value is an odd `Number`.
+   */
+  toBeOdd(): R;
+
+  /**
+   * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive).
+   *
+   * @param {Number} start
+   * @param {Number} end
+   */
+  toBeWithin(start: number, end: number): R;
+
+  /**
+   * Use `.toBeInRange` when checking if an array has elements in range min (inclusive) and max (inclusive).
+   *
+   * @param min
+   * @param max
+   */
+  toBeInRange(min: number, max: number): R;
+
+  /**
+   * Use `.toBeObject` when checking if a value is an `Object`.
+   */
+  toBeObject(): R;
+
+  /**
+   * Use `.toContainKey` when checking if an object contains the provided key.
+   *
+   * @param {String} key
+   */
+  toContainKey(key: string): R;
+
+  /**
+   * Use `.toContainKeys` when checking if an object has all of the provided keys.
+   *
+   * @param {Array.<String>} keys
+   */
+  toContainKeys<E = unknown>(keys: readonly (keyof E | string)[]): R;
+
+  /**
+   * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys.
+   *
+   * @param {Array.<String>} keys
+   */
+  toContainAllKeys<E = unknown>(keys: readonly (keyof E | string)[]): R;
+
+  /**
+   * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys.
+   *
+   * @param {Array.<String>} keys
+   */
+  toContainAnyKeys<E = unknown>(keys: readonly (keyof E | string)[]): R;
+
+  /**
+   * Use `.toContainValue` when checking if an object contains the provided value.
+   *
+   * @param {*} value
+   */
+  toContainValue<E = unknown>(value: E): R;
+
+  /**
+   * Use `.toContainValues` when checking if an object contains all of the provided values.
+   *
+   * @param {Array.<*>} values
+   */
+  toContainValues<E = unknown>(values: readonly E[]): R;
+
+  /**
+   * Use `.toContainAllValues` when checking if an object only contains all of the provided values.
+   *
+   * @param {Array.<*>} values
+   */
+  toContainAllValues<E = unknown>(values: readonly E[]): R;
+
+  /**
+   * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values.
+   *
+   * @param {Array.<*>} values
+   */
+  toContainAnyValues<E = unknown>(values: readonly E[]): R;
+
+  /**
+   * Use `.toContainEntry` when checking if an object contains the provided entry.
+   *
+   * @param {Array.<[keyof E, E[keyof E]>} entry
+   */
+  toContainEntry<E = unknown>(entry: readonly [keyof E, E[keyof E]]): R;
+
+  /**
+   * Use `.toContainEntries` when checking if an object contains all of the provided entries.
+   *
+   * @param {Array.<Array.<keyof E, E[keyof E]>>} entries
+   */
+  toContainEntries<E = unknown>(
+    entries: readonly (readonly [keyof E, E[keyof E]])[],
+  ): R;
+
+  /**
+   * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries.
+   *
+   * @param {Array.<Array.<keyof E, E[keyof E]>>} entries
+   */
+  toContainAllEntries<E = unknown>(
+    entries: readonly (readonly [keyof E, E[keyof E]])[],
+  ): R;
+
+  /**
+   * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries.
+   *
+   * @param {Array.<Array.<keyof E, E[keyof E]>>} entries
+   */
+  toContainAnyEntries<E = unknown>(
+    entries: readonly (readonly [keyof E, E[keyof E]])[],
+  ): R;
+
+  /**
+   * Use `.toBeExtensible` when checking if an object is extensible.
+   */
+  toBeExtensible(): R;
+
+  /**
+   * Use `.toBeFrozen` when checking if an object is frozen.
+   */
+  toBeFrozen(): R;
+
+  /**
+   * Use `.toBeSealed` when checking if an object is sealed.
+   */
+  toBeSealed(): R;
+
+  /**
+   * Use `.toResolve` when checking if a promise resolves.
+   */
+  toResolve(): R;
+
+  /**
+   * Use `.toReject` when checking if a promise rejects.
+   */
+  toReject(): R;
+
+  /**
+   * Use `.toBeString` when checking if a value is a `String`.
+   */
+  toBeString(): R;
+
+  /**
+   * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings.
+   *
+   * @param {String} string
+   */
+  toEqualCaseInsensitive(string: string): R;
+
+  /**
+   * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix.
+   *
+   * @param {String} prefix
+   */
+  toStartWith(prefix: string): R;
+
+  /**
+   * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix.
+   *
+   * @param {String} suffix
+   */
+  toEndWith(suffix: string): R;
+
+  /**
+   * Use `.toInclude` when checking if a `String` includes the given `String` substring.
+   *
+   * @param {String} substring
+   */
+  toInclude(substring: string): R;
+
+  /**
+   * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times.
+   *
+   * @param {String} substring
+   * @param {Number} times
+   */
+  toIncludeRepeated(substring: string, times: number): R;
+
+  /**
+   * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings.
+   *
+   * @param {Array.<String>} substring
+   */
+  toIncludeMultiple(substring: readonly string[]): R;
+
+  /**
+   * Use `.toThrowWithMessage` when checking if a callback function throws an error of a given type with a given error message.
+   *
+   * @param {Function} type
+   * @param {String | RegExp} message
+   */
+  toThrowWithMessage(
+    type: (...args: any[]) => any,
+    message: string | RegExp,
+  ): R;
+
+  /**
+   * Use `.toBeEmptyObject` when checking if a value is an empty `Object`.
+   */
+  toBeEmptyObject(): R;
+
+  /**
+   * Use `.toBeSymbol` when checking if a value is a `Symbol`.
+   */
+  toBeSymbol(): R;
+
+  /**
+   * Use `.toBeBetween` when checking if a date occurs between `startDate` and `endDate`.
+   * @param {Date} startDate
+   * @param {Date} endDate
+   */
+  toBeBetween(startDate: Date, endDate: Date): R;
+
+  /**
+   * Use `.toBeBeforeOrEqualTo` when checking if a date equals to or occurs before `date`.
+   * @param {Date} date
+   */
+  toBeBeforeOrEqualTo(date: Date): R;
+
+  /**
+   * Use `.toBeAfterOrEqualTo` when checking if a date equals to or occurs after `date`.
+   * @param {Date} date
+   */
+  toBeAfterOrEqualTo(date: Date): R;
+
+  /**
+   * Use `.toEqualIgnoringWhitespace` when checking if a `String` is equal (===) to given `String` ignoring white-space.
+   *
+   * @param {String} string
+   */
+  toEqualIgnoringWhitespace(string: string): R;
+}
+
+declare global {
+  namespace jest {
+    interface Matchers<R, T = {}> {
+      /**
+       * Use .toBeEmpty when checking if a String '', Array [], Object {} or Iterable (i.e. Map, Set) is empty.
+       */
+      toBeEmpty(): R;
+
+      /**
+       * Use .toBeOneOf when checking if a value is a member of a given Array.
+       * @param {Array.<*>} members
+       */
+      // included in vitest
+      // toBeOneOf<E = unknown>(members: readonly E[]): R;
+
+      /**
+       * Use `.toBeNil` when checking a value is `null` or `undefined`.
+       */
+      toBeNil(): R;
+
+      /**
+       * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`.
+       * @param {Function} predicate
+       */
+      // included in vitest
+      // toSatisfy<E = any>(predicate: (x: E) => boolean): R;
+
+      /**
+       * Use `.toBeArray` when checking if a value is an `Array`.
+       */
+      toBeArray(): R;
+
+      /**
+       * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x.
+       * @param {Number} x
+       */
+      toBeArrayOfSize(x: number): R;
+
+      /**
+       * Use `.toBeAfter` when checking if a date occurs after `date`.
+       * @param {Date} date
+       */
+      toBeAfter(date: Date): R;
+
+      /**
+       * Use `.toBeBefore` when checking if a date occurs before `date`.
+       * @param {Date} date
+       */
+      toBeBefore(date: Date): R;
+
+      /**
+       * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set.
+       * @param {Array.<*>} members
+       */
+      toIncludeAllMembers<E = unknown>(members: readonly E[]): R;
+
+      /**
+       * Use `.toIncludeAllPartialMembers` when checking if an `Array` contains all of the same partial members of a given set.
+       * @param {Array.<*>} members
+       */
+      toIncludeAllPartialMembers<E = unknown>(members: readonly E[]): R;
+
+      /**
+       * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set.
+       * @param {Array.<*>} members
+       */
+      toIncludeAnyMembers<E = unknown>(members: readonly E[]): R;
+
+      /**
+       * Use `.toIncludeSameMembers` when checking if two arrays contain equal values, in any order.
+       * @param {Array.<*>} members
+       */
+      toIncludeSameMembers<E = unknown>(members: readonly E[]): R;
+
+      /**
+       * Use `.toPartiallyContain` when checking if any array value matches the partial member.
+       * @param {*} member
+       */
+      toPartiallyContain<E = unknown>(member: E): R;
+
+      /**
+       * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array.
+       * @param {Function} predicate
+       */
+      toSatisfyAll<E = any>(predicate: (x: E) => boolean): R;
+
+      /**
+       * Use `.toSatisfyAny` when you want to use a custom matcher by supplying a predicate function that returns `true` for any matching value in an array.
+       * @param {Function} predicate
+       */
+      toSatisfyAny(predicate: (x: any) => boolean): R;
+
+      /**
+       * Use `.toBeBoolean` when checking if a value is a `Boolean`.
+       */
+      toBeBoolean(): R;
+
+      /**
+       * Use `.toBeTrue` when checking a value is equal (===) to `true`.
+       */
+      toBeTrue(): R;
+
+      /**
+       * Use `.toBeFalse` when checking a value is equal (===) to `false`.
+       */
+      toBeFalse(): R;
+
+      /**
+       * Use `.toBeDate` when checking if a value is a `Date`.
+       */
+      toBeDate(): R;
+
+      /**
+       * Use `.toBeValidDate` when checking if a value is a `valid Date`.
+       */
+      toBeValidDate(): R;
+
+      /**
+       * Use `.toBeFunction` when checking if a value is a `Function`.
+       */
+      toBeFunction(): R;
+
+      /**
+       * Use `.toBeDateString` when checking if a value is a valid date string.
+       */
+      toBeDateString(): R;
+
+      /**
+       * Use `.toBeHexadecimal` when checking if a value is a valid HTML hex color.
+       */
+      toBeHexadecimal(): R;
+
+      /**
+       * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`.
+       *
+       * Note: Required Jest version >=23
+       *
+       * @param {Mock} mock
+       * @param {boolean} [failIfNoSecondInvocation=true]
+       */
+      toHaveBeenCalledBefore(
+        mock: jest.MockInstance<any, any[]>,
+        failIfNoSecondInvocation?: boolean,
+      ): R;
+
+      /**
+       * Use `.toHaveBeenCalledAfter` when checking if a `Mock` was called after another `Mock`.
+       *
+       * Note: Required Jest version >=23
+       *
+       * @param {Mock} mock
+       * @param {boolean} [failIfNoFirstInvocation=true]
+       */
+      toHaveBeenCalledAfter(
+        mock: jest.MockInstance<any, any[]>,
+        failIfNoFirstInvocation?: boolean,
+      ): R;
+
+      /**
+       * Use `.toHaveBeenCalledOnce` to check if a `Mock` was called exactly one time.
+       */
+      toHaveBeenCalledOnce(): R;
+
+      /**
+       * Use `.toHaveBeenCalledExactlyOnceWith` to check if a `Mock` was called exactly one time with the expected value.
+       */
+      toHaveBeenCalledExactlyOnceWith(...args: unknown[]): R;
+
+      /**
+       * Use `.toBeNumber` when checking if a value is a `Number`.
+       */
+      toBeNumber(): R;
+
+      /**
+       * Use `.toBeNaN` when checking a value is `NaN`.
+       */
+      toBeNaN(): R;
+
+      /**
+       * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`.
+       */
+      toBeFinite(): R;
+
+      /**
+       * Use `.toBePositive` when checking if a value is a positive `Number`.
+       */
+      toBePositive(): R;
+
+      /**
+       * Use `.toBeNegative` when checking if a value is a negative `Number`.
+       */
+      toBeNegative(): R;
+
+      /**
+       * Use `.toBeEven` when checking if a value is an even `Number`.
+       */
+      toBeEven(): R;
+
+      /**
+       * Use `.toBeOdd` when checking if a value is an odd `Number`.
+       */
+      toBeOdd(): R;
+
+      /**
+       * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive).
+       *
+       * @param {Number} start
+       * @param {Number} end
+       */
+      toBeWithin(start: number, end: number): R;
+
+      /**
+       * Use `.toBeInRange` when checking if an array has elements in range min (inclusive) and max (inclusive).
+       *
+       * @param min
+       * @param max
+       */
+      toBeInRange(min: number, max: number): R;
+
+      /**
+       * Use `.toBeInteger` when checking if a value is an integer.
+       */
+      toBeInteger(): R;
+
+      /**
+       * Use `.toBeObject` when checking if a value is an `Object`.
+       */
+      toBeObject(): R;
+
+      /**
+       * Use `.toContainKey` when checking if an object contains the provided key.
+       *
+       * @param {String} key
+       */
+      toContainKey<E = unknown>(key: keyof E | string): R;
+
+      /**
+       * Use `.toContainKeys` when checking if an object has all of the provided keys.
+       *
+       * @param {Array.<String>} keys
+       */
+      toContainKeys<E = unknown>(keys: readonly (keyof E | string)[]): R;
+
+      /**
+       * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys.
+       *
+       * @param {Array.<String>} keys
+       */
+      toContainAllKeys<E = unknown>(keys: readonly (keyof E | string)[]): R;
+
+      /**
+       * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys.
+       *
+       * @param {Array.<String>} keys
+       */
+      toContainAnyKeys<E = unknown>(keys: readonly (keyof E | string)[]): R;
+
+      /**
+       * Use `.toContainValue` when checking if an object contains the provided value.
+       *
+       * @param {*} value
+       */
+      toContainValue<E = unknown>(value: E): R;
+
+      /**
+       * Use `.toContainValues` when checking if an object contains all of the provided values.
+       *
+       * @param {Array.<*>} values
+       */
+      toContainValues<E = unknown>(values: readonly E[]): R;
+
+      /**
+       * Use `.toContainAllValues` when checking if an object only contains all of the provided values.
+       *
+       * @param {Array.<*>} values
+       */
+      toContainAllValues<E = unknown>(values: readonly E[]): R;
+
+      /**
+       * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values.
+       *
+       * @param {Array.<*>} values
+       */
+      toContainAnyValues<E = unknown>(values: readonly E[]): R;
+
+      /**
+       * Use `.toContainEntry` when checking if an object contains the provided entry.
+       *
+       * @param {Array.<String, String>} entry
+       */
+      toContainEntry<E = unknown>(entry: readonly [keyof E, E[keyof E]]): R;
+
+      /**
+       * Use `.toContainEntries` when checking if an object contains all of the provided entries.
+       *
+       * @param {Array.<Array.<keyof E, E[keyof E]>>} entries
+       */
+      toContainEntries<E = unknown>(
+        entries: readonly (readonly [keyof E, E[keyof E]])[],
+      ): R;
+
+      /**
+       * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries.
+       *
+       * @param {Array.<Array.<keyof E, E[keyof E]>>} entries
+       */
+      toContainAllEntries<E = unknown>(
+        entries: readonly (readonly [keyof E, E[keyof E]])[],
+      ): R;
+
+      /**
+       * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries.
+       *
+       * @param {Array.<Array.<keyof E, E[keyof E]>>} entries
+       */
+      toContainAnyEntries<E = unknown>(
+        entries: readonly (readonly [keyof E, E[keyof E]])[],
+      ): R;
+
+      /**
+       * Use `.toBeExtensible` when checking if an object is extensible.
+       */
+      toBeExtensible(): R;
+
+      /**
+       * Use `.toBeFrozen` when checking if an object is frozen.
+       */
+      toBeFrozen(): R;
+
+      /**
+       * Use `.toBeSealed` when checking if an object is sealed.
+       */
+      toBeSealed(): R;
+
+      /**
+       * Use `.toResolve` when checking if a promise resolves.
+       */
+      toResolve(): Promise<R>;
+
+      /**
+       * Use `.toReject` when checking if a promise rejects.
+       */
+      toReject(): Promise<R>;
+
+      /**
+       * Use `.toBeString` when checking if a value is a `String`.
+       */
+      toBeString(): R;
+
+      /**
+       * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings.
+       *
+       * @param {String} string
+       */
+      toEqualCaseInsensitive(string: string): R;
+
+      /**
+       * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix.
+       *
+       * @param {String} prefix
+       */
+      toStartWith(prefix: string): R;
+
+      /**
+       * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix.
+       *
+       * @param {String} suffix
+       */
+      toEndWith(suffix: string): R;
+
+      /**
+       * Use `.toInclude` when checking if a `String` includes the given `String` substring.
+       *
+       * @param {String} substring
+       */
+      toInclude(substring: string): R;
+
+      /**
+       * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times.
+       *
+       * @param {String} substring
+       * @param {Number} times
+       */
+      toIncludeRepeated(substring: string, times: number): R;
+
+      /**
+       * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings.
+       *
+       * @param {Array.<String>} substring
+       */
+      toIncludeMultiple(substring: readonly string[]): R;
+
+      /**
+       * Use `.toThrowWithMessage` when checking if a callback function throws an error of a given type with a given error message.
+       *
+       * @param {Function} type
+       * @param {String | RegExp} message
+       */
+      toThrowWithMessage(
+        type:
+          | (new (...args: any[]) => { message: string })
+          | (abstract new (...args: any[]) => { message: string })
+          | ((...args: any[]) => { message: string }),
+        message: string | RegExp,
+      ): R;
+
+      /**
+       * Use `.toBeEmptyObject` when checking if a value is an empty `Object`.
+       */
+      toBeEmptyObject(): R;
+
+      /**
+       * Use `.toBeSymbol` when checking if a value is a `Symbol`.
+       */
+      toBeSymbol(): R;
+
+      /**
+       * Use `.toBeBetween` when checking if a date occurs between `startDate` and `endDate`.
+       * @param {Date} startDate
+       * @param {Date} endDate
+       */
+      toBeBetween(startDate: Date, endDate: Date): R;
+
+      /**
+       * Use `.toBeBeforeOrEqualTo` when checking if a date equals to or occurs before `date`.
+       * @param {Date} date
+       */
+      toBeBeforeOrEqualTo(date: Date): R;
+
+      /**
+       * Use `.toBeAfterOrEqualTo` when checking if a date equals to or occurs after `date`.
+       * @param {Date} date
+       */
+      toBeAfterOrEqualTo(date: Date): R;
+
+      /**
+       * Use `.toEqualIgnoringWhitespace` when checking if a `String` is equal (===) to given `String` ignoring white-space.
+       *
+       * @param {String} string
+       */
+      toEqualIgnoringWhitespace(string: string): R;
+    }
+
+    interface Expect extends JestExtendedMatchers<any> {}
+  }
+}
+
+declare module 'vitest' {
+  interface ExpectStatic extends JestExtendedMatchers<any> {}
+}
+
+export {};
diff --git a/test/types/jest-mock-extended.d.ts b/test/types/jest-mock-extended.d.ts
new file mode 100644
index 0000000000..8829b4c529
--- /dev/null
+++ b/test/types/jest-mock-extended.d.ts
@@ -0,0 +1,7 @@
+// TODO: remve when all tests are migrated to vitest
+/**
+ * @deprecated
+ */
+declare module 'jest-mock-extended' {
+  export * from 'vitest-mock-extended';
+}
diff --git a/test/types/jest.d.ts b/test/types/jest.d.ts
index fcad0bbe16..10004c8986 100644
--- a/test/types/jest.d.ts
+++ b/test/types/jest.d.ts
@@ -1,161 +1,30 @@
-import type { AsymmetricMatchers, BaseExpect, Matchers } from 'expect';
-import type { SnapshotMatchers } from 'jest-snapshot';
-import type { Global } from '@jest/types';
-import type { Jest } from '@jest/environment';
-import type {
-  ClassLike,
-  FunctionLike,
-  MockInstance as JestMockInstance,
-  Mocked as JestMocked,
-  MockedClass as JestMockedClass,
-  MockedFunction as JestMockedFunction,
-  MockedObject as JestMockedObject,
-  SpyInstance as JestSpyInstance,
-} from 'jest-mock';
+import type * as vitest from 'vitest';
 
 //------------------------------------------------
 // Required global jest types
 //------------------------------------------------
 declare global {
-  // Extension point for jest matchers
-  type JestMatchers<R, T = any> = jest.Matchers<R> &
-    SnapshotMatchers<R extends void | Promise<void> ? R : void, T> &
-    Omit<
-      Matchers<R extends void | Promise<void> ? R : void>,
-      'toMatchObject'
-    > & {
-      // TODO: override, because type issues (#22198)
-      /**
-       * Used to check that a JavaScript object matches a subset of the properties of an object
-       *
-       * Optionally, you can provide an object to use as Generic type for the expected value.
-       * This ensures that the matching object matches the structure of the provided object-like type.
-       *
-       * @example
-       *
-       * type House = {
-       *   bath: boolean;
-       *   bedrooms: number;
-       *   kitchen: {
-       *     amenities: string[];
-       *     area: number;
-       *     wallColor: string;
-       *   }
-       * };
-       *
-       * expect(desiredHouse).toMatchObject<House>({...standardHouse, kitchen: {area: 20}}) // wherein standardHouse is some base object of type House
-       */
-      toMatchObject<E extends object | any[]>(
-        expected: E,
-      ): R extends void | Promise<void> ? R : void;
-    };
-}
-
-type JestInverse<Matchers> = {
-  /**
-   * Inverse next matcher. If you know how to test something, `.not` lets you test its opposite.
-   */
-  not: Matchers;
-};
-
-type JestPromiseMatchers<T> = {
-  /**
-   * Unwraps the reason of a rejected promise so any other matcher can be chained.
-   * If the promise is fulfilled the assertion fails.
-   */
-  rejects: JestMatchers<Promise<void>, T> &
-    JestInverse<JestMatchers<Promise<void>, T>>;
-  /**
-   * Unwraps the value of a fulfilled promise so any other matcher can be chained.
-   * If the promise is rejected the assertion fails.
-   */
-  resolves: JestMatchers<Promise<void>, T> &
-    JestInverse<JestMatchers<Promise<void>, T>>;
-};
-
-type JestExpect = {
-  <T = unknown>(
-    actual: T,
-  ): JestMatchers<void, T> &
-    JestInverse<JestMatchers<void, T>> &
-    JestPromiseMatchers<T>;
-  addSnapshotSerializer: (arg: Plugin) => void;
-} & BaseExpect &
-  AsymmetricMatchers &
-  JestInverse<Omit<AsymmetricMatchers, 'any' | 'anything'>> &
-  jest.Expect;
-
-type JestItEach = Global.It['each'];
-
-interface JestEach extends JestItEach {
-  (
-    strings: TemplateStringsArray,
-    ...placeholders: any[]
-  ): (
-    name: string,
-    fn: (arg: any) => ReturnType<Global.TestFn>,
-    timeout?: number,
-  ) => void;
-}
-
-interface JestIt extends Global.It {
-  // TODO: override, because type issues (#22198)
-  each: JestEach;
-}
+  namespace jest {
+    type MockInstance<T, Y extends any[]> = vitest.MockedFunction<
+      (...args: Y) => T
+    >;
+    type SpyInstance<T, Y extends any[]> = vitest.MockInstance<
+      (...args: Y) => T
+    >;
 
-declare global {
-  const afterAll: Global.HookBase;
-  const afterEach: Global.HookBase;
-  const beforeAll: Global.HookBase;
-  const beforeEach: Global.HookBase;
-  const describe: Global.Describe;
-  const expect: JestExpect;
-  const it: JestIt;
-  var jest: Omit<Jest, 'fn'> & {
-    // TODO: override, because type issues (#22198)
-    fn(): jest.Mock;
-    fn<T, Y extends any[]>(implementation?: (...args: Y) => T): jest.Mock<T, Y>;
-  };
-  const test: JestIt;
+    /** @deprecated */
+    type Mocked<T> = vitest.MockedObject<T>;
 
-  namespace jest {
-    /**
-     * Wraps a class, function or object type with Jest mock type definitions.
-     */
-    type Mocked<T extends object> = JestMocked<T>;
     /**
-     * Wraps a class type with Jest mock type definitions.
+     * @deprecated Use `MockedObject` from `vitest` instead
      */
-    type MockedClass<T extends ClassLike> = JestMockedClass<T>;
-    /**
-     * Wraps a function type with Jest mock type definitions.
-     */
-    type MockedFunction<T extends FunctionLike> = JestMockedFunction<T>;
-    /**
-     * Wraps an object type with Jest mock type definitions.
-     */
-    type MockedObject<T extends object> = JestMockedObject<T>;
-
-    type MockInstance<T, Y extends any[]> = JestMockInstance<(...args: Y) => T>;
-
-    interface Mock<T = any, Y extends any[] = any>
-      extends Function,
-        MockInstance<T, Y> {
-      new (...args: Y): T;
-      (...args: Y): T;
-    }
-
-    interface CustomMatcherResult {
-      pass: boolean;
-      message: string | (() => string);
-    }
-
-    type SpyInstance<T, Y extends any[]> = JestSpyInstance<(...args: Y) => T>;
+    type MockedObject<T> = vitest.MockedObject<T>;
 
-    // Extension point for jest matchers
-    interface Expect {}
+    /** @deprecated */
+    type MockedFunction<T extends (...args: any[]) => any> =
+      vitest.MockedFunction<T>;
 
-    // Extension point for jest matchers
-    interface Matchers<R> {}
+    /** @deprecated */
+    type Mock<T = any> = vitest.Mock<T>;
   }
 }
diff --git a/test/util.ts b/test/util.ts
index cb689c3af5..9ccf37bd8f 100644
--- a/test/util.ts
+++ b/test/util.ts
@@ -1,8 +1,6 @@
-import crypto from 'node:crypto';
-import { expect, jest } from '@jest/globals';
-import type { DeepMockProxy } from 'jest-mock-extended';
-import type { Plugin } from 'pretty-format';
 import upath from 'upath';
+import type { MockedFunction } from 'vitest';
+import type { DeepMockProxy } from 'vitest-mock-extended';
 import type { RenovateConfig } from '../lib/config/types';
 import * as _logger from '../lib/logger';
 import type { Platform } from '../lib/modules/platform';
@@ -16,15 +14,14 @@ import { regEx } from '../lib/util/regex';
 
 /**
  * Simple wrapper for getting mocked version of a module
- * @param module module which is mocked by `jest.mock`
+ * @param module module which is mocked by `vi.mock`
+ * @deprecated Use `vi.mocked` instead
  */
-export function mocked<T extends object>(module: T): jest.Mocked<T> {
-  return jest.mocked(module);
-}
+export const mocked = vi.mocked;
 
 /**
  * Simple wrapper for getting mocked version of a module
- * @param module module which is mocked by `jest-mock-extended.mockDeep`
+ * @param module module which is mocked by `vitest-mock-extended.mockDeep`
  */
 export function mockedExtended<T extends object>(module: T): DeepMockProxy<T> {
   return module as DeepMockProxy<T>;
@@ -32,12 +29,13 @@ export function mockedExtended<T extends object>(module: T): DeepMockProxy<T> {
 
 /**
  * Simple wrapper for getting mocked version of a function
- * @param func function which is mocked by `jest.mock`
+ * @param func function which is mocked by `vi.mock`
+ * @deprecated Use `vi.mocked` instead
  */
 export function mockedFunction<T extends (...args: any[]) => any>(
   func: T,
-): jest.MockedFunction<T> {
-  return func as jest.MockedFunction<T>;
+): MockedFunction<T> {
+  return func as MockedFunction<T>;
 }
 
 /**
@@ -51,15 +49,14 @@ export function partial(obj: unknown = {}): unknown {
   return obj;
 }
 
-export const fs = jest.mocked(_fs);
-export const git = jest.mocked(_git);
+export const fs = vi.mocked(_fs);
+export const git = vi.mocked(_git);
 
-// TODO: fix types, jest / typescript is using wrong overload (#22198)
-export const platform = jest.mocked(partial<Required<Platform>>(_platform));
-export const scm = jest.mocked(_scm);
-export const env = jest.mocked(_env);
-export const hostRules = jest.mocked(_hostRules);
-export const logger = jest.mocked(_logger);
+export const platform = vi.mocked(partial<Required<Platform>>(_platform));
+export const scm = vi.mocked(_scm);
+export const env = vi.mocked(_env);
+export const hostRules = vi.mocked(_hostRules);
+export const logger = vi.mocked(_logger, true);
 
 export type { RenovateConfig };
 
@@ -102,44 +99,6 @@ export function getFixturePath(fixtureFile: string, fixtureRoot = '.'): string {
   return upath.join(callerDir, fixtureRoot, '__fixtures__', fixtureFile);
 }
 
-/**
- * Can be used to search and replace strings in jest snapshots.
- * @example
- * expect.addSnapshotSerializer(
- *     replacingSerializer(upath.toUnix(gradleDir.path), 'localDir')
- * );
- */
-export const replacingSerializer = (
-  search: string,
-  replacement: string,
-): Plugin => ({
-  test: (value) => typeof value === 'string' && value.includes(search),
-  serialize: (val, config, indent, depth, refs, printer) => {
-    const replaced = (val as string).replace(search, replacement);
-    return printer(replaced, config, indent, depth, refs);
-  },
-});
-
-export function addReplacingSerializer(from: string, to: string): void {
-  expect.addSnapshotSerializer(replacingSerializer(from, to));
-}
-
-function toHash(buf: Buffer): string {
-  return crypto.createHash('sha256').update(buf).digest('hex');
-}
-
-const bufferSerializer: Plugin = {
-  test: (value) => Buffer.isBuffer(value),
-  serialize: (val, config, indent, depth, refs, printer) => {
-    const replaced = toHash(val);
-    return printer(replaced, config, indent, depth, refs);
-  },
-};
-
-export function addBufferSerializer(): void {
-  expect.addSnapshotSerializer(bufferSerializer);
-}
-
 export function regexMatches(target: string, patterns: string[]): boolean {
   return patterns.some((patt: string) => {
     const re = regEx(patt);
diff --git a/tools/test/types.ts b/tools/test/types.ts
index 49834e3565..9fda482489 100644
--- a/tools/test/types.ts
+++ b/tools/test/types.ts
@@ -1,5 +1,3 @@
-import type { JestConfigWithTsJest } from 'ts-jest';
-
 /**
  * Configuration for single test shard.
  */
@@ -68,16 +66,3 @@ export interface ShardGroup {
    */
   'upload-artifact-name': string;
 }
-
-export type JestConfig = JestConfigWithTsJest & {
-  // https://github.com/renovatebot/renovate/issues/17034
-  workerIdleMemoryLimit?: string;
-};
-
-/**
- * Subset of Jest config that is relevant for sharded test run.
- */
-export type JestShardedSubconfig = Pick<
-  JestConfig,
-  'testMatch' | 'coverageDirectory'
->;
diff --git a/tools/test/utils.ts b/tools/test/utils.ts
index c80f597a0b..6c4133fdb5 100644
--- a/tools/test/utils.ts
+++ b/tools/test/utils.ts
@@ -1,11 +1,23 @@
 import { env } from 'process';
 
-export function getCoverageIgnorePatterns(): string[] | undefined {
-  const patterns = ['/node_modules/', '<rootDir>/test/', '<rootDir>/tools/'];
+export function getCoverageIgnorePatterns(): string[] {
+  const patterns = [];
 
   if (env.TEST_LEGACY_DECRYPTION !== 'true') {
-    patterns.push('<rootDir>/lib/config/decrypt/legacy.ts');
+    patterns.push('lib/config/decrypt/legacy.ts');
   }
 
   return patterns;
 }
+
+/**
+ * Convert match pattern to a form that matches on file with `.ts` or `.spec.ts` extension.
+ */
+export function normalizePattern(
+  pattern: string,
+  suffix: '.ts' | '.spec.ts',
+): string {
+  return pattern.endsWith('.spec.ts')
+    ? pattern.replace(/\.spec\.ts$/, suffix)
+    : `${pattern}/**/*${suffix}`;
+}
diff --git a/tsconfig.app.json b/tsconfig.app.json
index 8f46a98c57..d566f67926 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -5,7 +5,9 @@
     "sourceMap": true,
     "inlineSources": true,
     "importHelpers": true,
-    "types": ["node"]
+    "moduleResolution": "node10",
+    "types": ["node"],
+    "paths": {} // no paths for production
   },
   "files": ["lib/renovate.ts", "lib/config-validator.ts"],
   "include": ["lib/**/*.d.ts"]
diff --git a/tsconfig.json b/tsconfig.json
index b2577db2a9..a5d00ee31b 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -6,7 +6,7 @@
     "outDir": "./dist",
     /* https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping */
     "target": "es2022",
-    "moduleResolution": "node10",
+    "moduleResolution": "node",
     "module": "CommonJS",
     "sourceMap": true,
     "allowSyntheticDefaultImports": true,
@@ -18,10 +18,14 @@
     "useUnknownInCatchVariables": false /* we aren't prepared for enabling this by default since ts 4.4*/,
     "isolatedModules": true /* required for esbuild */,
     "lib": ["es2023"],
-    "types": ["node", "jest-extended", "expect-more-jest"],
+    "types": ["node", "vitest/globals"],
     "allowJs": true,
     "checkJs": true,
-    "ignoreDeprecations": "5.0"
+    "ignoreDeprecations": "5.0",
+    "skipLibCheck": true, // https://github.com/vitejs/vite/discussions/12466#discussioncomment-7596971
+    "paths": {
+      "~test/*": ["./test/*"]
+    }
   },
   "include": ["**/*.ts", "**/*.js", "**/*.mjs", "**/*.cjs"],
   "exclude": [
diff --git a/tsconfig.spec.json b/tsconfig.spec.json
index 101c5a0ad2..dc340484c3 100644
--- a/tsconfig.spec.json
+++ b/tsconfig.spec.json
@@ -1,6 +1,8 @@
 {
   "extends": "./tsconfig",
   "compilerOptions": {
+    "moduleResolution": "node",
+    "module": "CommonJS",
     "allowJs": false,
     "checkJs": false
   }
diff --git a/vitest.config.ts b/vitest.config.ts
new file mode 100644
index 0000000000..f477f9d4f1
--- /dev/null
+++ b/vitest.config.ts
@@ -0,0 +1,128 @@
+import tsconfigPaths from 'vite-tsconfig-paths';
+import type { ViteUserConfig } from 'vitest/config';
+import {
+  coverageConfigDefaults,
+  defaultExclude,
+  defineConfig,
+  mergeConfig,
+} from 'vitest/config';
+import GitHubActionsReporter from 'vitest-github-actions-reporter';
+import { testShards } from './tools/test/shards';
+import {
+  getCoverageIgnorePatterns,
+  normalizePattern,
+} from './tools/test/utils';
+
+const ci = !!process.env.CI;
+
+/**
+ * Generates Vitest config for sharded test run.
+ *
+ * If `TEST_SHARD` environment variable is not set,
+ * it falls back to the provided config.
+ *
+ * Otherwise, `fallback` value is used to determine some defaults.
+ */
+function configureShardingOrFallbackTo(
+  fallback: ViteUserConfig,
+): ViteUserConfig {
+  const shardKey = process.env.TEST_SHARD;
+  if (!shardKey) {
+    return fallback;
+  }
+
+  if (!testShards[shardKey]) {
+    const keys = Object.keys(testShards).join(', ');
+    throw new Error(
+      `Unknown value for TEST_SHARD: ${shardKey} (possible values: ${keys})`,
+    );
+  }
+
+  const include: string[] = [];
+  const exclude: string[] = [...defaultExclude];
+
+  for (const [key, { matchPaths: patterns }] of Object.entries(testShards)) {
+    if (key === shardKey) {
+      const testMatchPatterns = patterns.map((pattern) => {
+        const filePattern = normalizePattern(pattern, '.spec.ts');
+        return filePattern;
+      });
+      include.push(...testMatchPatterns);
+      break;
+    }
+
+    const testMatchPatterns = patterns.map((pattern) => {
+      const filePattern = normalizePattern(pattern, '.spec.ts');
+      return `**/${filePattern}`;
+    });
+    exclude.push(...testMatchPatterns);
+  }
+
+  const reportsDirectory = `./coverage/shard/${shardKey}`;
+  return {
+    test: {
+      include,
+      exclude,
+      coverage: {
+        reportsDirectory,
+      },
+    },
+  };
+}
+
+// https://vitejs.dev/config/
+export default defineConfig(() =>
+  mergeConfig(
+    {
+      plugins: [tsconfigPaths()],
+      cacheDir: ci ? '.cache/vitest' : undefined,
+      test: {
+        globals: true,
+        setupFiles: [
+          'jest-extended/all',
+          'expect-more-jest',
+          './test/setup.ts',
+          './test/jest-legacy.ts',
+          'test/to-migrate.ts',
+        ],
+        reporters: ci ? ['default', new GitHubActionsReporter()] : ['default'],
+        mockReset: true,
+        coverage: {
+          provider: 'v8',
+          ignoreEmptyLines: true,
+          reporter: ci
+            ? ['text-summary', 'lcovonly', 'json']
+            : ['text-summary', 'html', 'json'],
+          enabled: true,
+          exclude: [
+            ...coverageConfigDefaults.exclude,
+            ...getCoverageIgnorePatterns(),
+            '**/*.spec.ts', // should work from defaults
+            'lib/**/{__fixtures__,__mocks__,__testutil__,test}/**',
+            'lib/**/types.ts',
+            'lib/types/**',
+            'tools/**',
+            '+(config.js)',
+            '__mocks__/**',
+            // fully ignored files
+            'lib/config-validator.ts',
+            'lib/modules/datasource/hex/v2/package.ts',
+            'lib/modules/datasource/hex/v2/signed.ts',
+            'lib/util/cache/package/redis.ts',
+            'lib/util/http/legacy.ts',
+            'lib/workers/repository/cache.ts',
+          ],
+        },
+        alias: {
+          // TODO: remove when migration is done
+          'jest-mock-extended': 'vitest-mock-extended',
+        },
+      },
+    } satisfies ViteUserConfig,
+    configureShardingOrFallbackTo({
+      test: {
+        exclude: ['tools/docs/test/**/*.spec.ts'],
+      },
+    }),
+  ),
+);
-- 
GitLab