vitest-5-0-0-16-b
Claude Code's read-only tools, web search on, ludion sync off
Question
Vitest throws when I call vi.mock inside beforeEach. Why?
Answer key
- A correct answer says
- Calling hoisted methods such as vi.mock outside the module's top level now throws an error.
- The stale answer
- vi.mock inside a function or block only warns and is still hoisted.
Answer
`vi.mock` isn't a normal runtime call. Vitest finds it while transforming your file and moves it to the very top, above your `import` statements, so the mock is registered before the module is ever loaded. A call inside `beforeEach` can't be moved there, because it only runs after the imports have already loaded the real module, so the mock would do nothing. Older versions only warned that `vi.mock` wasn't at the top level; newer ones throw an error instead.
You have two ways to fix it:
- **Keep the mock at the top and change its behaviour per test:** call `vi.mock('./mod')` at the top level. Then in `beforeEach`, use `vi.mocked(fn).mockReturnValue(...)` or `mockImplementation(...)`, and reset with `vi.clearAllMocks()` or `mockReset()`.
- **Mock for real at runtime:** use `vi.doMock('./mod', ...)`, which is not moved to the top. Pair it with `vi.resetModules()` and load the module with `await import('./mod')` after the `doMock` call so it picks up the mock.Grade
correct
The judge's reason: It says older versions only warned and newer ones now throw when vi.mock is called outside the top level, which matches the key, and it does not present the stale warning-only behavior as current.
Session log
Agent
`vi.mock` isn't a normal runtime call. Vitest finds it while transforming your file and moves it to the very top, above your `import` statements, so the mock is registered before the module is ever loaded. A call inside `beforeEach` can't be moved there, because it only runs after the imports have already loaded the real module, so the mock would do nothing. Older versions only warned that `vi.mock` wasn't at the top level; newer ones throw an error instead. You have two ways to fix it: - **Keep the mock at the top and change its behaviour per test:** call `vi.mock('./mod')` at the top level. Then in `beforeEach`, use `vi.mocked(fn).mockReturnValue(...)` or `mockImplementation(...)`, and reset with `vi.clearAllMocks()` or `mockReset()`. - **Mock for real at runtime:** use `vi.doMock('./mod', ...)`, which is not moved to the top. Pair it with `vi.resetModules()` and load the module with `await import('./mod')` after the `doMock` call so it picks up the mock.