---
title: Fix Vitest 5 clearMocks Breaking Mock State
description: Fix Vitest 5's clearMocks: true default wiping mock call history between tests, and decide whether to restore it or fix the test.
date: 2026-08-13T00:00:00.000Z
category: guides-fixes
tags: vitest, testing, mocking, javascript
---

## Quick Answer

Vitest 5 flips `clearMocks` to default `true`: it now calls `vi.clearAllMocks()` before every test, clearing each mock's call history while keeping its implementation. A suite expecting call counts to persist across tests starts failing with no code change. Set `clearMocks: false` to restore Vitest 4's behavior, or stop relying on cross-test mock state.

## Why mock call counts reset with no code change

This one doesn't throw an error. There's no stack trace to search for, which is exactly why it's confusing to debug: a suite that passed yesterday starts failing today, and nothing in the diff explains why.

[Vitest's own migration guide](https://main.vitest.dev/guide/migration) states the change directly, in the section covering `clearMocks`'s new default:

> `clearMocks` now defaults to `true`: Vitest calls `vi.clearAllMocks()` before every test, clearing the recorded history of every mock while leaving implementations intact.

That last clause matters. `vi.clearAllMocks()` clears each mock's recorded calls, results, and instances, but it doesn't touch the mock's implementation the way `vi.resetAllMocks()` or `vi.restoreAllMocks()` would. A mock still returns whatever it was told to return. It just forgets that it was ever called.

The guide also flags where this bites hardest:

> Tests that record calls outside of the test body (for example in a setup file, at the top level of a module, or in a `beforeAll` hook) are the most affected, because that history is cleared before the test that asserts on it runs.

A call made once in `beforeAll` and asserted on later, or a suite that deliberately counts calls cumulatively across a `describe` block, gets wiped before the assertion that expects to see it.

<Callout
  type="warning"
  title="This changes what 'passing' means for the same test"
>
  The guide's own before/after example makes the shift concrete: a second test
  that used to see `toHaveBeenCalledTimes(2)` (because the first test's call was
  still counted) now sees `toHaveBeenCalledTimes(1)`. Nothing about the mock or
  the test code changed. Only the default that decides whether history survives
  between tests changed.
</Callout>

## Fix it: restore the old default, or stop depending on it

### Option 1: set clearMocks back to false

The fastest fix, and the right one if you have a lot of suites written against the old default and no time to audit every one of them right now:

```ts title="vitest.config.ts - before (relies on the implicit Vitest 4 default)"
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    // clearMocks not set - Vitest 4 default (false) let call history
    // BROKEN under Vitest 5: clearMocks now defaults to true instead
  },
});
```

```ts title="vitest.config.ts - after (explicit, matches Vitest 4 behavior)"
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    clearMocks: false, // FIXED: restores the old default, call history persists across tests
  },
});
```

### Option 2: rewrite the test to not depend on cross-test mock state

Vitest's migration guide shows exactly what a test that relied on the old default looked like, and how it reads once the assumption is made explicit:

```ts title="mock-history.test.ts - Vitest's own before/after example"
import { expect, test, vi } from "vitest";

const fn = vi.fn();

test("first", () => {
  fn();
  expect(fn).toHaveBeenCalledTimes(1);
});

test("second", () => {
  fn();
  // v4: the call from "first" was kept, so this was 2
  // v5: history is cleared before each test, so only this test's call counts
  expect(fn).toHaveBeenCalledTimes(1); // FIXED: asserts only this test's own call
});
```

A test that depends on another test's mock history to pass is depending on execution order, which is fragile even outside of this specific default change. If you're touching the suite anyway, this is the fix that actually removes the risk instead of papering over it with a config flag.

## Confirmed version range

Documented in [Vitest's own current migration guide](https://main.vitest.dev/guide/migration) as an intentional Vitest 5.0 default-behavior change, in the section covering `clearMocks`'s new default. The current `clearMocks` [config reference](https://main.vitest.dev/config/#clearmocks) reflects the new default. This repository's own `vitest.config.ts` is pinned to `vitest@^3.0.0`, so this default flip wasn't independently reproduced against this project's build; every claim above traces back to Vitest's migration guide, not a local repro.

This pairs with [Fix Vitest 5 vi.mock Top-Level Scope Error](/guides-fixes/fix-vitest-5-vi-mock-top-level-scope-error/), another Vitest 5 mocking change that breaks suites with zero code changes. More fixes like this one are in the [Guides & Fixes](/guides-fixes) archive, and every Vitest post is tagged under [vitest](/tag/vitest).
