{"record":{"id":"8eded8d9699f332e","repo":"vitest-dev/vitest","slug":"vi-when-the-argument-must-be-a-mock-function-crea","errorCode":null,"errorMessage":"vi.when: the argument must be a mock function created with `vi.fn()` or `vi.spyOn()`","messagePattern":"vi\\.when: the argument must be a mock function created with `vi\\.fn\\(\\)` or `vi\\.spyOn\\(\\)`","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/integrations/mock/when.ts","lineNumber":296,"sourceCode":" *\n *   expect(spy('darkMode')).toBe(true)\n * }\n *\n * // spy's original implementation is restored here\n * expect(spy('darkMode')).toBe(undefined)\n *\n * @example\n * // Throw on unmatched calls\n * vi.when(spy, { onUnmatched: 'throw' })\n *   .calledWith(1)\n *   .thenReturn({ id: 1, name: 'Alice' })\n *\n * expect(spy(1)).toEqual({ id: 1, name: 'Alice' })\n * expect(() => spy(2)).toThrow()\n */\nexport function when<Fn extends Procedure>(spy: Fn | Mock<Fn>, options?: WhenOptions<Fn>): When<Fn> {\n  if (!isMockFunction(spy)) {\n    throw new TypeError('vi.when: the argument must be a mock function created with `vi.fn()` or `vi.spyOn()`')\n  }\n\n  type ScopedParameters = Parameters<Fn>\n  type ScopedReturn = ReturnType<Fn>\n\n  const behaviors: Behavior<ScopedParameters, ScopedReturn>[] = []\n  const originalImplementation = spy.getMockImplementation()\n\n  function findAction(args: ScopedParameters) {\n    const testers = [\n      ...getCustomEqualityTesters(),\n      iterableEquality,\n    ]\n\n    for (const behavior of behaviors) {\n      if (equals(args, behavior.arguments, testers)) {\n        return behavior.actions.findLast(action => !(action.remaining === 0 && action.called)) ?? null\n      }","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/integrations/mock/when.ts#L278-L314","documentation":"Thrown by `vi.when(...)` when the `spy` argument fails `isMockFunction(...)`. `vi.when` stubs behavior on a mock by calling `spy.mockImplementation`, so the input must be a Vitest mock created via `vi.fn()` or `vi.spyOn()`. A TypeError is raised because passing any other value is a programming error, not a runtime condition.","triggerScenarios":"Calling `vi.when(realFn)` with a plain function; `vi.when(obj.method)` where the method was never spied on; passing a jest.fn() (non-Vitest mock) across an interop boundary; passing `undefined` because the import resolved to undefined.","commonSituations":"Forgetting to wrap a function with `vi.fn()`; spying on a method that doesn't exist on the target; module mock returning the un-mocked original; refactoring that loses the mock reference.","solutions":["Wrap the function first: `const spy = vi.fn(myFn); vi.when(spy).calledWith(...).thenReturn(...)`.","For an object method, use `vi.spyOn(obj, 'method')` before passing it to `vi.when`.","Double-check the import returns the mock you expect (e.g. after `vi.mock(...)` with a factory)."],"exampleFix":"// before\nfunction add(a, b) { return a + b }\nvi.when(add).calledWith(1, 2).thenReturn(3)\n\n// after\nconst add = vi.fn((a, b) => a + b)\nvi.when(add).calledWith(1, 2).thenReturn(3)","handlingStrategy":"type-guard","validationCode":"import { isMockFunction } from '@vitest/spy'\nfunction whenSafe(spy) {\n  if (!isMockFunction(spy)) throw new TypeError('expected a vi.fn/vi.spyOn mock')\n  return vi.when(spy)\n}","typeGuard":"import { isMockFunction } from '@vitest/spy'\nfunction isMockable(v): v is ReturnType<typeof vi.fn> {\n  return isMockFunction(v)\n}","tryCatchPattern":null,"preventionTips":["Always create the mock with vi.fn() or vi.spyOn() before passing to vi.when.","Add a type guard helper in test utilities to catch non-mocks early.","Verify module mocks return the mocked implementation, not the original."],"tags":["vi-when","mocking","type-guard","vi-fn","vi-spyon"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}