Skip to content

chore: migrate test runner from Jest to Vitest#6937

Draft
FabienMotte wants to merge 31 commits intomasterfrom
chore/jest-to-vitest-migration
Draft

chore: migrate test runner from Jest to Vitest#6937
FabienMotte wants to merge 31 commits intomasterfrom
chore/jest-to-vitest-migration

Conversation

@FabienMotte
Copy link
Copy Markdown
Contributor

@FabienMotte FabienMotte commented Mar 20, 2026

Summary

Migrate the entire monorepo test runner from Jest 27 to Vitest 4. This eliminates the Babel dependency for tests, leverages Vite's native ESM/TypeScript/JSX handling, and modernizes the test infrastructure.

Core migration

  • Replace jest.config.js with vitest.config.ts at root level and in subpackages (algoliasearch-helper, create-instantsearch-app)
  • Mechanical jest.*vi.* replacements across all test files (~1400+ vi.fn(), vi.mock(), vi.spyOn(), etc.)
  • Migrate jest.requireActual() (sync) → await vi.importActual() (async) in all mock factories
  • Replace @jest-environment pragmas with @vitest-environment across ~200 test files
  • Migrate custom matchers (toWarnDev, toMatchNormalizedInlineSnapshot, Vue matchers) to Vitest types and APIs
  • Convert done() callback patterns to return new Promise() wrapper (deprecated in Vitest)
  • Replace jest-environment-jsdom custom environment with Vitest's built-in jsdom (Node 20 provides all needed globals natively)

Subpackage migrations

  • algoliasearch-helper: Rewrite test/run.js to use startVitest() API instead of jest.runCLI()
  • create-instantsearch-app: Convert entire source from CJS to ESM ("type": "module"), add dual exports (index.js + index.cjs) for backwards compatibility, rename template configs from .template.js.template.cjs, add .template.js fallback for custom templates

Configuration updates

  • TypeScript: Add "types": ["vitest/globals"], remove @types/jest
  • ESLint: Replace eslint-plugin-jest with eslint-plugin-vitest, update all rule references
  • Babel: Remove Jest/CJS code path, keep Storybook branch only
  • CI: Update .circleci/config.yml for Vitest commands and JUnit output paths
  • Vue: Support both Vue 2 (@vitejs/plugin-vue2) and Vue 3 (@vitejs/plugin-vue) via env var switching

Performance optimizations

  • happy-dom: Switch test environment from jsdom to happy-dom across ~200 test files for faster DOM simulation
  • Threads: Switch Vitest to threads pool in CI and test runners for better parallelism

Vitest 4 compatibility fixes

  • Fix Mock type params, implicit any, and spread arg errors for Vitest 4
  • Import Mock, MockInstance, MockedFunction types from vitest instead of relying on globals
  • Drop vi.fn() type args (removed in Vitest 4), remove unused imports
  • Remove leftover Jasmine type reference that polluted vitest globals
  • Add vite@8 to root devDependencies for correct type resolution

Vue 3 fixes

  • Resolve Vue 3 dependencies in Vitest config
  • Repair Vue 3 Vitest prep script and snapshots
  • Remove redundant esbuild config from Vitest

Codemod test migration

  • Migrate jscodeshift codemod tests (instantsearch-codemods, instantsearch.js/scripts/transforms) to Vitest
  • Replace jscodeshift/dist/testUtils.defineTest (which uses CJS require() for transforms) with applyTransform + ESM imports
  • Remove codemod/transform exclusions from vitest.config.ts so all tests run in the main suite

Bug fixes along the way

  • Fix unhandled errors/rejections across the test suite (mock routers missing dispose(), incorrect Promise constructors, etc.)
  • Normalize widget snapshots before inline assertions
  • Remove stale dependencies (jsdom-global, babel-eslint)
  • Handle jsdom v29 behavioral changes (accessible name computation, non-configurable sessionStorage)
  • Disable OXC JSX dev mode to prevent __self/__source attributes breaking snapshots and accessible name assertions

Cleanup

  • Remove all Jest config files, custom Jest environments, and Jest-specific dependencies
  • Remove obsolete common widget snapshots
  • Rename remaining "jest" references to "vitest" in comments and file paths
  • Regenerate all snapshots

Benchmarks

Local

Local benchmarks on Apple Silicon via yarn test (wall-clock time, no coverage).

Jest 27 (master) Vitest 4 (this branch)
Test files 377 377
Tests 4,311 (173 skipped) 4,311 (173 skipped)
Wall-clock time 129.54s 137.18s

Vitest wall-clock time is higher locally due to Vite's module transformation and environment setup overhead. The tradeoff is eliminating the Babel transpilation pipeline, gaining native ESM/TypeScript/JSX support, and modernizing the DX (HMR watch mode, better error formatting, native coverage via v8).

CircleCI

Recent CircleCI unit tests job runs on this branch are more stable and faster on rolling metrics than master.

Jest 27 (master) Vitest 4 (this branch)
Latest run 4m 18.9s 4m 39.7s
Median of last 5 runs 4m 57.0s 4m 39.7s
Average of last 5 runs 5m 26.4s 4m 39.7s
Last 5 range 4m 15.3s to 7m 49.7s 4m 28.4s to 4m 47.9s

The latest single run is noisy, but the last-5 median is about 17s faster on this branch and the last-5 average is about 47s faster (-14.3%). Some longer master runs are likely inflated by flaky tests being retried, which makes the branch's tighter timing range a better signal than any one-off run.

Test plan

  • Root vitest suite passes (377 test files, 4,138 tests)
  • algoliasearch-helper tests pass (95 test files, 445 tests)
  • create-instantsearch-app tests pass (10 test files, 74 tests)
  • yarn lint passes
  • TypeScript compilation passes with vitest/globals types
  • CI pipeline validates all test jobs (unit tests, Vue v3 tests, JUnit output)

@FabienMotte FabienMotte force-pushed the chore/jest-to-vitest-migration branch from fce176c to 71ed792 Compare March 20, 2026 17:24
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 20, 2026

More templates

algoliasearch-helper

npm i https://pkg.pr.new/algolia/instantsearch/algoliasearch-helper@6937

instantsearch-ui-components

npm i https://pkg.pr.new/algolia/instantsearch/instantsearch-ui-components@6937

instantsearch.css

npm i https://pkg.pr.new/algolia/instantsearch/instantsearch.css@6937

instantsearch.js

npm i https://pkg.pr.new/algolia/instantsearch/instantsearch.js@6937

react-instantsearch

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch@6937

react-instantsearch-core

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch-core@6937

react-instantsearch-nextjs

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch-nextjs@6937

react-instantsearch-router-nextjs

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch-router-nextjs@6937

vue-instantsearch

npm i https://pkg.pr.new/algolia/instantsearch/vue-instantsearch@6937

commit: c44ceb6

Replace jscodeshift's `defineTest` (which uses CJS `require()` to load
.ts transforms) with `applyTransform` + ESM imports. Remove codemod and
transform exclusions from vitest.config.ts so all tests run in the main
suite.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant