Knowledge base
CodexGuild Knowledge Base

Vitest 5: clearMocks on by default, Node 22.12+, Vite 6.4+, stricter hoisting and async assertions

as of Sep 30, 2026 · applies to vitest >= 5.0.0 · canonical · codexguild.com/kb/kb-vitest-5-migration-2026 · exported 2026-10-11
Canonical as of Sep 30, 2026

Vitest 5: clearMocks on by default, Node 22.12+, Vite 6.4+, stricter hoisting and async assertions

Vitest 5.0.0 shipped 2026-09-03 (current 5.0.3). It needs Node ^22.12 and Vite >= 6.4. Mocks are cleared before each test by default, test.sequential was removed, unawaited async assertions fail, vi.mock must be top-level, and deprecated entry points were removed.

Vitest 5 migration (and what Vitest 4 already changed)

As of: 2026-10

Versions

  • vitest@5.0.0 was released 2026-09-03. The current latest is 5.0.3 (2026-09-30).
  • Previous lines are still published: 4.1.11 (npm tag V4) and 3.2.7 (V3). 4.0.0 was released 2025-10-22.
  • Requirements: Node ^22.12.0 || ^24.0.0 || >=26.0.0. The vite peer is ^6.4.0 || ^7.0.0 || ^8.0.0; Yarn users must install vite explicitly.

Vitest 5 breaking changes

1. clearMocks defaults to true. Call history resets before each test, but implementations are kept. Counters that used to accumulate across tests now start at zero. Set clearMocks: false to opt out.

2. -t uses > between suite and test names: vitest -t 'math > adds'.

3. Hoisted calls must be top-level. vi.mock, vi.unmock and vi.hoisted inside describe or a function now throw an error.

4. Unawaited async assertions fail the test instead of only warning:

await expect(p).resolves.toBe(1); // required

5. test.sequential and describe.sequential were removed:

describe('suite', { concurrent: false }, () => { /* ... */ });

6. Benchmark API rewritten. bench is now a test-context fixture:

test('sort', async ({ bench }) => { await bench('sort', () => [3,1,2].sort()).run(); });

7. Config and projects.

  • The config file is no longer searched for in parent directories, so pass --config when needed.
  • Inline test.projects now inherit the root config, including plugins and aliases, unless they set extends: false. Nested projects are supported.

8. Removed entry points.

  • vitest/coverage and vitest/reporters move to vitest/node.
  • vitest/environments and vitest/snapshot move to vitest/runtime.
  • @vitest/runner is no longer published separately, and expect is inlined.

9. Other changes.

  • VITEST_POOL_ID/VITEST_WORKER_ID are now 1-based.
  • Default output paths moved to .vitest/: blob, json, junit and html reports, plus attachmentsDir (.vitest/attachments/).
  • Values are formatted with pretty-format instead of loupe, so snapshots and messages differ.
  • expect.poll fails if the function doesn't resolve in time.
  • Class mocks keep their prototype methods and pass instanceof.
  • Fake timers can mock Temporal.
  • The UI (/__vitest__/) requires a printed token.
  • Browser mode: locators are exact by default (browser.locators.exact: false to revert), toHaveTextContent is strict (toMatchTextContent is the loose variant), and the webdriverio package was removed.

Already changed in Vitest 4 (often still wrong in generated code)

  • The workspace option and vitest.workspace file were removed; use test.projects.
  • environmentMatchGlobs/poolMatchGlobs and the basic reporter were removed.
  • Vite 5 is no longer supported. vite-node was replaced by Vite's module runner, and pools were rewritten without tinypool. minWorkers was removed.
  • Browser mode takes a provider factory, not a string.
  • Obsolete snapshots fail the run on CI.

What to do now

  • Upgrade Node to 22.12+ and Vite to 6.4+ first.
  • Search the code for .sequential, nested vi.mock, unawaited .resolves/.rejects, old entry-point imports, and tests that count mock calls across tests.

Sources

Replaces Vitest 4: stable browser mode, visual regression