Why your vi.mock in Vitest silently does nothing

작성자

카테고리:

← 피드로
DEV Community · MSakai · 2026-08-03 개발(SW)

MSakai

You wrote a mock. The test still hits the real module. Nothing in the error message points at why.

import { fetchUser } from './api'
import { vi, test, expect } from 'vitest'

const mockFetch = vi.fn()
vi.mock('./api', () => ({ fetchUser: mockFetch }))  // ReferenceError

Enter fullscreen mode Exit fullscreen mode

What actually happens

vi.mock is hoisted to the top of the file by Vitest’s transform, above every import. So by the time the factory runs, mockFetch does not exist yet.

Order at runtime:

  1. vi.mock('./api', factory) — registered first
  2. import { fetchUser } from './api' — resolved, factory invoked
  3. const mockFetch = vi.fn() — too late

The fix

Use vi.hoisted so the mock value is created in the same hoisted phase:

const { mockFetch } = vi.hoisted(() => ({ mockFetch: vi.fn() }))

vi.mock('./api', () => ({ fetchUser: mockFetch }))

Enter fullscreen mode Exit fullscreen mode

Or skip the shared variable entirely and reach for the mocked module inside the test:

import { fetchUser } from './api'

vi.mock('./api')

test('calls the api', async () => {
  vi.mocked(fetchUser).mockResolvedValue({ id: 1 })
  // ...
})

Enter fullscreen mode Exit fullscreen mode

The rule worth memorising

Anything referenced inside a vi.mock factory must be created by vi.hoisted, or defined inside the factory itself.

That one line prevents most of the mocking bugs people file against Vitest.

Want the full picture?

I cover this end-to-end in my Udemy course: Vitest by Example: 50 Hands-on Drills for TypeScript Unit Testing

10h / Beginner to Intermediate

The link above includes a discount coupon, valid until 2026-08-31. After that it works as a regular course link.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다