···11-# Mock Functions
11+# Mocks
2233-You can create a mock function to track its execution with `vi.fn` method. If you want to track a method on an already created object, you can use `vi.spyOn` method:
33+You can create a mock function or a class to track its execution with the `vi.fn` method. If you want to track a property on an already created object, you can use the `vi.spyOn` method:
4455```js
66import { vi } from 'vitest'
···1818getApplesSpy.mock.calls.length === 1
1919```
20202121-You should use mock assertions (e.g., [`toHaveBeenCalled`](/api/expect#tohavebeencalled)) on [`expect`](/api/expect) to assert mock result. This API reference describes available properties and methods to manipulate mock behavior.
2121+You should use mock assertions (e.g., [`toHaveBeenCalled`](/api/expect#tohavebeencalled)) on [`expect`](/api/expect) to assert mock results. This API reference describes available properties and methods to manipulate mock behavior.
22222323::: tip
2424The custom function implementation in the types below is marked with a generic `<T>`.
···3030function getMockImplementation(): T | undefined
3131```
32323333-Returns current mock implementation if there is one.
3333+Returns the current mock implementation if there is one.
34343535If the mock was created with [`vi.fn`](/api/vi#vi-fn), it will use the provided method as the mock implementation.
3636···4242function getMockName(): string
4343```
44444545-Use it to return the name assigned to the mock with the `.mockName(name)` method. By default, it will return `vi.fn()`.
4545+Use it to return the name assigned to the mock with the `.mockName(name)` method. By default, `vi.fn()` mocks will return `'vi.fn()'`, while spies created with `vi.spyOn` will keep the original name.
46464747## mockClear
48484949```ts
5050-function mockClear(): MockInstance<T>
5050+function mockClear(): Mock<T>
5151```
52525353Clears all information about every call. After calling it, all properties on `.mock` will return to their initial state. This method does not reset implementations. It is useful for cleaning up mocks between different assertions.
···7272## mockName
73737474```ts
7575-function mockName(name: string): MockInstance<T>
7575+function mockName(name: string): Mock<T>
7676```
77777878Sets the internal mock name. This is useful for identifying the mock when an assertion fails.
···8080## mockImplementation
81818282```ts
8383-function mockImplementation(fn: T): MockInstance<T>
8383+function mockImplementation(fn: T): Mock<T>
8484```
85858686Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function.
···102102## mockImplementationOnce
103103104104```ts
105105-function mockImplementationOnce(fn: T): MockInstance<T>
105105+function mockImplementationOnce(fn: T): Mock<T>
106106```
107107108108Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function. This method can be chained to produce different results for multiple function calls.
···135135function withImplementation(
136136 fn: T,
137137 cb: () => void
138138-): MockInstance<T>
138138+): Mock<T>
139139function withImplementation(
140140 fn: T,
141141 cb: () => Promise<void>
142142-): Promise<MockInstance<T>>
142142+): Promise<Mock<T>>
143143```
144144145145Overrides the original mock implementation temporarily while the callback is being executed.
···177177## mockRejectedValue
178178179179```ts
180180-function mockRejectedValue(value: unknown): MockInstance<T>
180180+function mockRejectedValue(value: unknown): Mock<T>
181181```
182182183183-Accepts an error that will be rejected when async function is called.
183183+Accepts an error that will be rejected when an async function is called.
184184185185```ts
186186const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'))
···191191## mockRejectedValueOnce
192192193193```ts
194194-function mockRejectedValueOnce(value: unknown): MockInstance<T>
194194+function mockRejectedValueOnce(value: unknown): Mock<T>
195195```
196196197197Accepts a value that will be rejected during the next function call. If chained, each consecutive call will reject the specified value.
···209209## mockReset
210210211211```ts
212212-function mockReset(): MockInstance<T>
212212+function mockReset(): Mock<T>
213213```
214214215215-Does what [`mockClear`](#mockClear) does and resets inner implementation to the original function.
216216-This also resets all "once" implementations.
215215+Does what [`mockClear`](#mockClear) does and resets the mock implementation. This also resets all "once" implementations.
217216218218-Note that resetting a mock from `vi.fn()` will set implementation to an empty function that returns `undefined`.
219219-resetting a mock from `vi.fn(impl)` will restore implementation to `impl`.
217217+Note that resetting a mock from `vi.fn()` will set the implementation to an empty function that returns `undefined`.
218218+Resetting a mock from `vi.fn(impl)` will reset the implementation to `impl`.
220219221220This is useful when you want to reset a mock to its original state.
222221···241240## mockRestore
242241243242```ts
244244-function mockRestore(): MockInstance<T>
243243+function mockRestore(): Mock<T>
245244```
246245247247-Does what [`mockReset`](#mockReset) does and restores original descriptors of spied-on objects.
246246+Does what [`mockReset`](#mockreset) does and restores the original descriptors of spied-on objects, if the mock was created with [`vi.spyOn`](/api/vi#vi-spyon).
248247249249-Note that restoring a mock from `vi.fn()` will set implementation to an empty function that returns `undefined`.
250250-Restoring a mock from `vi.fn(impl)` will restore implementation to `impl`.
248248+`mockRestore` on a `vi.fn()` mock is identical to [`mockReset`](#mockreset).
251249252250```ts
253251const person = {
···270268## mockResolvedValue
271269272270```ts
273273-function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>
271271+function mockResolvedValue(value: Awaited<ReturnType<T>>): Mock<T>
274272```
275273276274Accepts a value that will be resolved when the async function is called. TypeScript will only accept values that match the return type of the original function.
···284282## mockResolvedValueOnce
285283286284```ts
287287-function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): MockInstance<T>
285285+function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): Mock<T>
288286```
289287290288Accepts a value that will be resolved during the next function call. TypeScript will only accept values that match the return type of the original function. If chained, each consecutive call will resolve the specified value.
···305303## mockReturnThis
306304307305```ts
308308-function mockReturnThis(): MockInstance<T>
306306+function mockReturnThis(): Mock<T>
309307```
310308311309Use this if you need to return the `this` context from the method without invoking the actual implementation. This is a shorthand for:
···319317## mockReturnValue
320318321319```ts
322322-function mockReturnValue(value: ReturnType<T>): MockInstance<T>
320320+function mockReturnValue(value: ReturnType<T>): Mock<T>
323321```
324322325323Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
···335333## mockReturnValueOnce
336334337335```ts
338338-function mockReturnValueOnce(value: ReturnType<T>): MockInstance<T>
336336+function mockReturnValueOnce(value: ReturnType<T>): Mock<T>
339337```
340338341339Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
···379377const lastCall: Parameters<T> | undefined
380378```
381379382382-This contains the arguments of the last call. If mock wasn't called, it will return `undefined`.
380380+This contains the arguments of the last call. If the mock wasn't called, it will return `undefined`.
383381384382## mock.results
385383···388386 type: 'return'
389387 /**
390388 * The value that was returned from the function.
391391- * If function returned a Promise, then this will be a resolved value.
389389+ * If the function returned a Promise, then this will be a resolved value.
392390 */
393391 value: T
394392}
···418416419417- `'return'` - function returned without throwing.
420418- `'throw'` - function threw a value.
419419+- `'incomplete'` - the function did not finish running yet.
421420422421The `value` property contains the returned value or thrown error. If the function returned a `Promise`, then `result` will always be `'return'` even if the promise was rejected.
423422···450449## mock.settledResults
451450452451```ts
452452+interface MockSettledResultIncomplete {
453453+ type: 'incomplete'
454454+ value: undefined
455455+}
456456+453457interface MockSettledResultFulfilled<T> {
454458 type: 'fulfilled'
455459 value: T
···463467export type MockSettledResult<T>
464468 = | MockSettledResultFulfilled<T>
465469 | MockSettledResultRejected
470470+ | MockSettledResultIncomplete
466471467472const settledResults: MockSettledResult<Awaited<ReturnType<T>>>[]
468473```
469474470470-An array containing all values that were `resolved` or `rejected` from the function.
475475+An array containing all values that were resolved or rejected by the function.
471476472472-This array will be empty if the function was never resolved or rejected.
477477+If the function returned non-promise values, the `value` will be kept as is, but the `type` will still says `fulfilled` or `rejected`.
478478+479479+Until the value is resolved or rejected, the `settledResult` type will be `incomplete`.
473480474481```js
475482const fn = vi.fn().mockResolvedValueOnce('result')
476483477484const result = fn()
478485479479-fn.mock.settledResults === []
486486+fn.mock.settledResults === [
487487+ {
488488+ type: 'incomplete',
489489+ value: undefined,
490490+ },
491491+]
480492481493await result
482494···533545const instances: ReturnType<T>[]
534546```
535547536536-This property is an array containing all instances that were created when the mock was called with the `new` keyword. Note that this is an actual context (`this`) of the function, not a return value.
548548+This property is an array containing all instances that were created when the mock was called with the `new` keyword. Note that this is the actual context (`this`) of the function, not a return value.
537549538550::: warning
539539-If mock was instantiated with `new MyClass()`, then `mock.instances` will be an array with one value:
551551+If the mock was instantiated with `new MyClass()`, then `mock.instances` will be an array with one value:
540552541553```js
542554const MyClass = vi.fn()
···545557MyClass.mock.instances[0] === a
546558```
547559548548-If you return a value from constructor, it will not be in `instances` array, but instead inside `results`:
560560+If you return a value from the constructor, it will not be in the `instances` array, but instead inside `results`:
549561550562```js
551563const Spy = vi.fn(() => ({ method: vi.fn() }))
+202-46
docs/api/vi.md
···16161717### vi.mock
18181919-- **Type**: `(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void`
2020-- **Type**: `<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void`
1919+```ts
2020+interface MockOptions {
2121+ spy?: boolean
2222+}
2323+2424+interface MockFactory<T> {
2525+ (importOriginal: () => T): unknown
2626+}
2727+2828+function mock(
2929+ path: string,
3030+ factory?: MockOptions | MockFactory<unknown>
3131+): void
3232+function mock<T>(
3333+ module: Promise<T>,
3434+ factory?: MockOptions | MockFactory<T>
3535+): void
3636+```
21372238Substitutes all imported modules from provided `path` with another module. You can use configured Vite aliases inside a path. The call to `vi.mock` is hoisted, so it doesn't matter where you call it. It will always be executed before all imports. If you need to reference some variables outside of its scope, you can define them inside [`vi.hoisted`](#vi-hoisted) and reference them inside `vi.mock`.
2339···159175160176### vi.doMock
161177162162-- **Type**: `(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void`
163163-- **Type**: `<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void`
178178+```ts
179179+function doMock(
180180+ path: string,
181181+ factory?: MockOptions | MockFactory<unknown>
182182+): void
183183+function doMock<T>(
184184+ module: Promise<T>,
185185+ factory?: MockOptions | MockFactory<T>
186186+): void
187187+```
164188165189The same as [`vi.mock`](#vi-mock), but it's not hoisted to the top of the file, so you can reference variables in the global file scope. The next [dynamic import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) of the module will be mocked.
166190···207231208232### vi.mocked
209233210210-- **Type**: `<T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>`
211211-- **Type**: `<T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>`
234234+```ts
235235+function mocked<T>(
236236+ object: T,
237237+ deep?: boolean
238238+): MaybeMockedDeep<T>
239239+function mocked<T>(
240240+ object: T,
241241+ options?: { partial?: boolean; deep?: boolean }
242242+): MaybePartiallyMockedDeep<T>
243243+```
212244213245Type helper for TypeScript. Just returns the object that was passed.
214246···243275244276### vi.importActual
245277246246-- **Type**: `<T>(path: string) => Promise<T>`
278278+```ts
279279+function importActual<T>(path: string): Promise<T>
280280+```
247281248282Imports module, bypassing all checks if it should be mocked. Can be useful if you want to mock module partially.
249283···257291258292### vi.importMock
259293260260-- **Type**: `<T>(path: string) => Promise<MaybeMockedDeep<T>>`
294294+```ts
295295+function importMock<T>(path: string): Promise<MaybeMockedDeep<T>>
296296+```
261297262298Imports a module with all of its properties (including nested properties) mocked. Follows the same rules that [`vi.mock`](#vi-mock) does. For the rules applied, see [algorithm](/guide/mocking#automocking-algorithm).
263299264300### vi.unmock
265301266266-- **Type**: `(path: string | Promise<Module>) => void`
302302+```ts
303303+function unmock(path: string | Promise<Module>): void
304304+```
267305268306Removes module from the mocked registry. All calls to import will return the original module even if it was mocked before. This call is hoisted to the top of the file, so it will only unmock modules that were defined in `setupFiles`, for example.
269307270308### vi.doUnmock
271309272272-- **Type**: `(path: string | Promise<Module>) => void`
310310+```ts
311311+function doUnmock(path: string | Promise<Module>): void
312312+```
273313274314The same as [`vi.unmock`](#vi-unmock), but is not hoisted to the top of the file. The next import of the module will import the original module instead of the mock. This will not unmock previously imported modules.
275315···308348309349### vi.resetModules
310350311311-- **Type**: `() => Vitest`
351351+```ts
352352+function resetModules(): Vitest
353353+```
312354313355Resets modules registry by clearing the cache of all modules. This allows modules to be reevaluated when reimported. Top-level imports cannot be re-evaluated. Might be useful to isolate modules where local state conflicts between tests.
314356···338380:::
339381340382### vi.dynamicImportSettled
383383+384384+```ts
385385+function dynamicImportSettled(): Promise<void>
386386+```
341387342388Wait for all imports to load. Useful, if you have a synchronous call that starts importing a module that you cannot wait otherwise.
343389···370416371417### vi.fn
372418373373-- **Type:** `(fn?: Function) => Mock`
419419+```ts
420420+function fn(fn?: Procedure | Constructable): Mock
421421+```
374422375423Creates a spy on a function, though can be initiated without one. Every time a function is invoked, it stores its call arguments, returns, and instances. Also, you can manipulate its behavior with [methods](/api/mock).
376424If no function is given, mock will return `undefined`, when invoked.
···390438expect(getApples).toHaveNthReturnedWith(2, 5)
391439```
392440441441+You can also pass down a class to `vi.fn`:
442442+443443+```ts
444444+const Cart = vi.fn(class {
445445+ get = () => 0
446446+})
447447+448448+const cart = new Cart()
449449+expect(Cart).toHaveBeenCalled()
450450+```
451451+393452### vi.mockObject <Version>3.2.0</Version>
394453395395-- **Type:** `<T>(value: T) => MaybeMockedDeep<T>`
454454+```ts
455455+function mockObject<T>(value: T): MaybeMockedDeep<T>
456456+```
396457397458Deeply mocks properties and methods of a given object in the same way as `vi.mock()` mocks module exports. See [automocking](/guide/mocking.html#automocking-algorithm) for the detail.
398459···428489429490### vi.isMockFunction
430491431431-- **Type:** `(fn: Function) => boolean`
492492+```ts
493493+function isMockFunction(fn: unknown): asserts fn is Mock
494494+```
432495433496Checks that a given parameter is a mock function. If you are using TypeScript, it will also narrow down its type.
434497435498### vi.clearAllMocks
499499+500500+```ts
501501+function clearAllMocks(): Vitest
502502+```
436503437504Calls [`.mockClear()`](/api/mock#mockclear) on all spies.
438505This will clear mock history without affecting mock implementations.
439506440507### vi.resetAllMocks
441508509509+```ts
510510+function resetAllMocks(): Vitest
511511+```
512512+442513Calls [`.mockReset()`](/api/mock#mockreset) on all spies.
443443-This will clear mock history and reset each mock's implementation to its original.
514514+This will clear mock history and reset each mock's implementation.
444515445516### vi.restoreAllMocks
446517447447-Calls [`.mockRestore()`](/api/mock#mockrestore) on all spies.
448448-This will clear mock history, restore all original mock implementations, and restore original descriptors of spied-on objects.
518518+```ts
519519+function restoreAllMocks(): Vitest
520520+```
521521+522522+This restores all original implementations on spies created with [`vi.spyOn`](#vi-spyon).
523523+524524+After the mock was restored, you can spy on it again.
525525+526526+::: warning
527527+This method also does not affect mocks created during [automocking](/guide/mocking-modules#mocking-a-module).
528528+529529+Note that unlike [`mock.mockRestore`](/api/mock#mockrestore), `vi.restoreAllMocks` will not clear mock history or reset the mock implementation
530530+:::
449531450532### vi.spyOn
451533452452-- **Type:** `<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance`
534534+```ts
535535+function spyOn<T, K extends keyof T>(
536536+ object: T,
537537+ key: K,
538538+ accessor?: 'get' | 'set'
539539+): Mock<T[K]>
540540+```
453541454542Creates a spy on a method or getter/setter of an object similar to [`vi.fn()`](#vi-fn). It returns a [mock function](/api/mock).
455543···509597:::
510598511599::: tip
512512-You can call [`vi.restoreAllMocks`](#vi-restoreallmocks) inside [`afterEach`](/api/#aftereach) (or enable [`test.restoreMocks`](/config/#restoreMocks)) to restore all methods to their original implementations. This will restore the original [object descriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty), so you won't be able to change method's implementation:
600600+You can call [`vi.restoreAllMocks`](#vi-restoreallmocks) inside [`afterEach`](/api/#aftereach) (or enable [`test.restoreMocks`](/config/#restoreMocks)) to restore all methods to their original implementations after every test. This will restore the original [object descriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty), so you won't be able to change method's implementation anymore, unless you spy again:
513601514602```ts
515603const cart = {
···545633546634### vi.stubEnv {#vi-stubenv}
547635548548-- **Type:** `<T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => Vitest`
636636+```ts
637637+function stubEnv<T extends string>(
638638+ name: T,
639639+ value: T extends 'PROD' | 'DEV' | 'SSR' ? boolean : string | undefined
640640+): Vitest
641641+```
549642550643Changes the value of environmental variable on `process.env` and `import.meta.env`. You can restore its value by calling `vi.unstubAllEnvs`.
551644···579672580673### vi.unstubAllEnvs {#vi-unstuballenvs}
581674582582-- **Type:** `() => Vitest`
675675+```ts
676676+function unstubAllEnvs(): Vitest
677677+```
583678584679Restores all `import.meta.env` and `process.env` values that were changed with `vi.stubEnv`. When it's called for the first time, Vitest remembers the original value and will store it, until `unstubAllEnvs` is called again.
585680···608703609704### vi.stubGlobal
610705611611-- **Type:** `(name: string | number | symbol, value: unknown) => Vitest`
706706+```ts
707707+function stubGlobal(
708708+ name: string | number | symbol,
709709+ value: unknown
710710+): Vitest
711711+```
612712613713Changes the value of global variable. You can restore its original value by calling `vi.unstubAllGlobals`.
614714···637737638738### vi.unstubAllGlobals {#vi-unstuballglobals}
639739640640-- **Type:** `() => Vitest`
740740+```ts
741741+function unstubAllGlobals(): Vitest
742742+```
641743642744Restores all global values on `globalThis`/`global` (and `window`/`top`/`self`/`parent`, if you are using `jsdom` or `happy-dom` environment) that were changed with `vi.stubGlobal`. When it's called for the first time, Vitest remembers the original value and will store it, until `unstubAllGlobals` is called again.
643745···670772671773### vi.advanceTimersByTime
672774673673-- **Type:** `(ms: number) => Vitest`
775775+```ts
776776+function advanceTimersByTime(ms: number): Vitest
777777+```
674778675779This method will invoke every initiated timer until the specified number of milliseconds is passed or the queue is empty - whatever comes first.
676780···687791688792### vi.advanceTimersByTimeAsync
689793690690-- **Type:** `(ms: number) => Promise<Vitest>`
794794+```ts
795795+function advanceTimersByTimeAsync(ms: number): Promise<Vitest>
796796+```
691797692798This method will invoke every initiated timer until the specified number of milliseconds is passed or the queue is empty - whatever comes first. This will include asynchronously set timers.
693799···704810705811### vi.advanceTimersToNextTimer
706812707707-- **Type:** `() => Vitest`
813813+```ts
814814+function advanceTimersToNextTimer(): Vitest
815815+```
708816709817Will call next available timer. Useful to make assertions between each timer call. You can chain call it to manage timers by yourself.
710818···719827720828### vi.advanceTimersToNextTimerAsync
721829722722-- **Type:** `() => Promise<Vitest>`
830830+```ts
831831+function advanceTimersToNextTimerAsync(): Promise<Vitest>
832832+```
723833724834Will call next available timer and wait until it's resolved if it was set asynchronously. Useful to make assertions between each timer call.
725835···734844await vi.advanceTimersToNextTimerAsync() // log: 3
735845```
736846737737-### vi.advanceTimersToNextFrame <Version>2.1.0</Version> {#vi-advancetimerstonextframe}
847847+### vi.advanceTimersToNextFrame {#vi-advancetimerstonextframe}
738848739739-- **Type:** `() => Vitest`
849849+```ts
850850+function advanceTimersToNextFrame(): Vitest
851851+```
740852741853Similar to [`vi.advanceTimersByTime`](https://vitest.dev/api/vi#vi-advancetimersbytime), but will advance timers by the milliseconds needed to execute callbacks currently scheduled with `requestAnimationFrame`.
742854···754866755867### vi.getTimerCount
756868757757-- **Type:** `() => number`
869869+```ts
870870+function getTimerCount(): number
871871+```
758872759873Get the number of waiting timers.
760874761875### vi.clearAllTimers
762876877877+```ts
878878+function clearAllTimers(): void
879879+```
880880+763881Removes all timers that are scheduled to run. These timers will never run in the future.
764882765883### vi.getMockedSystemTime
766884767767-- **Type**: `() => Date | null`
885885+```ts
886886+function getMockedSystemTime(): Date | null
887887+```
768888769889Returns mocked current date. If date is not mocked the method will return `null`.
770890771891### vi.getRealSystemTime
772892773773-- **Type**: `() => number`
893893+```ts
894894+function getRealSystemTime(): number
895895+```
774896775897When using `vi.useFakeTimers`, `Date.now` calls are mocked. If you need to get real time in milliseconds, you can call this function.
776898777899### vi.runAllTicks
778900779779-- **Type:** `() => Vitest`
901901+```ts
902902+function runAllTicks(): Vitest
903903+```
780904781905Calls every microtask that was queued by `process.nextTick`. This will also run all microtasks scheduled by themselves.
782906783907### vi.runAllTimers
784908785785-- **Type:** `() => Vitest`
909909+```ts
910910+function runAllTimers(): Vitest
911911+```
786912787913This method will invoke every initiated timer until the timer queue is empty. It means that every timer called during `runAllTimers` will be fired. If you have an infinite interval, it will throw after 10 000 tries (can be configured with [`fakeTimers.loopLimit`](/config/#faketimers-looplimit)).
788914···805931806932### vi.runAllTimersAsync
807933808808-- **Type:** `() => Promise<Vitest>`
934934+```ts
935935+function runAllTimersAsync(): Promise<Vitest>
936936+```
809937810938This method will asynchronously invoke every initiated timer until the timer queue is empty. It means that every timer called during `runAllTimersAsync` will be fired even asynchronous timers. If you have an infinite interval,
811939it will throw after 10 000 tries (can be configured with [`fakeTimers.loopLimit`](/config/#faketimers-looplimit)).
···822950823951### vi.runOnlyPendingTimers
824952825825-- **Type:** `() => Vitest`
953953+```ts
954954+function runOnlyPendingTimers(): Vitest
955955+```
826956827957This method will call every timer that was initiated after [`vi.useFakeTimers`](#vi-usefaketimers) call. It will not fire any timer that was initiated during its call.
828958···837967838968### vi.runOnlyPendingTimersAsync
839969840840-- **Type:** `() => Promise<Vitest>`
970970+```ts
971971+function runOnlyPendingTimersAsync(): Promise<Vitest>
972972+```
841973842974This method will asynchronously call every timer that was initiated after [`vi.useFakeTimers`](#vi-usefaketimers) call, even asynchronous ones. It will not fire any timer that was initiated during its call.
843975···864996865997### vi.setSystemTime
866998867867-- **Type**: `(date: string | number | Date) => void`
999999+```ts
10001000+function setSystemTime(date: string | number | Date): Vitest
10011001+```
86810028691003If fake timers are enabled, this method simulates a user changing the system clock (will affect date related API like `hrtime`, `performance.now` or `new Date()`) - however, it will not fire any timers. If fake timers are not enabled, this method will only mock `Date.*` calls.
8701004···88510198861020### vi.useFakeTimers
8871021888888-- **Type:** `(config?: FakeTimerInstallOpts) => Vitest`
10221022+```ts
10231023+function useFakeTimers(config?: FakeTimerInstallOpts): Vitest
10241024+```
88910258901026To enable mocking timers, you need to call this method. It will wrap all further calls to timers (such as `setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`, `setImmediate`, `clearImmediate`, and `Date`) until [`vi.useRealTimers()`](#vi-userealtimers) is called.
8911027···90010369011037### vi.isFakeTimers {#vi-isfaketimers}
9021038903903-- **Type:** `() => boolean`
10391039+```ts
10401040+function isFakeTimers(): boolean
10411041+```
90410429051043Returns `true` if fake timers are enabled.
90610449071045### vi.useRealTimers
9081046909909-- **Type:** `() => Vitest`
10471047+```ts
10481048+function useRealTimers(): Vitest
10491049+```
91010509111051When timers have run out, you may call this method to return mocked timers to its original implementations. All timers that were scheduled before will be discarded.
9121052···91610569171057### vi.waitFor {#vi-waitfor}
9181058919919-- **Type:** `<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>`
10591059+```ts
10601060+function waitFor<T>(
10611061+ callback: WaitForCallback<T>,
10621062+ options?: number | WaitForOptions
10631063+): Promise<T>
10641064+```
92010659211066Wait for the callback to execute successfully. If the callback throws an error or returns a rejected promise it will continue to wait until it succeeds or times out.
9221067···97811239791124### vi.waitUntil {#vi-waituntil}
9801125981981-- **Type:** `<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>`
11261126+```ts
11271127+function waitUntil<T>(
11281128+ callback: WaitUntilCallback<T>,
11291129+ options?: number | WaitUntilOptions
11301130+): Promise<T>
11311131+```
98211329831133This is similar to `vi.waitFor`, but if the callback throws any errors, execution is immediately interrupted and an error message is received. If the callback returns falsy value, the next check will continue until truthy value is returned. This is useful when you need to wait for something to exist before taking the next step.
9841134···1003115310041154### vi.hoisted {#vi-hoisted}
1005115510061006-- **Type**: `<T>(factory: () => T) => T`
11561156+```ts
11571157+function hoisted<T>(factory: () => T): T
11581158+```
1007115910081160All static `import` statements in ES modules are hoisted to the top of the file, so any code that is defined before the imports will actually be executed after imports are evaluated.
10091161···1080123210811233### vi.setConfig
1082123410831083-- **Type**: `RuntimeConfig`
12351235+```ts
12361236+function setConfig(config: RuntimeOptions): void
12371237+```
1084123810851239Updates config for the current test file. This method supports only config options that will affect the current test file:
10861240···1105125911061260### vi.resetConfig
1107126111081108-- **Type**: `RuntimeConfig`
12621262+```ts
12631263+function resetConfig(): void
12641264+```
1109126511101266If [`vi.setConfig`](#vi-setconfig) was called before, this will reset config to the original state.
+6-5
docs/config/index.md
···16431643- **Type:** `boolean`
16441644- **Default:** `false`
1645164516461646-Will call [`.mockClear()`](/api/mock#mockclear) on all spies before each test.
16461646+Will call [`vi.clearAllMocks()`](/api/vi#vi-clearallmocks) before each test.
16471647This will clear mock history without affecting mock implementations.
1648164816491649### mockReset
···16511651- **Type:** `boolean`
16521652- **Default:** `false`
1653165316541654-Will call [`.mockReset()`](/api/mock#mockreset) on all spies before each test.
16551655-This will clear mock history and reset each implementation to its original.
16541654+Will call [`vi.resetAllMocks()`](/api/vi#vi-resetallmocks) before each test.
16551655+This will clear mock history and reset each implementation.
1656165616571657### restoreMocks
1658165816591659- **Type:** `boolean`
16601660- **Default:** `false`
1661166116621662-Will call [`.mockRestore()`](/api/mock#mockrestore) on all spies before each test.
16631663-This will clear mock history, restore each implementation to its original, and restore original descriptors of spied-on objects..
16621662+Will call [`vi.restoreAllMocks()`](/api/vi#vi-restoreallmocks) before each test.
16631663+16641664+This restores all original implementations on spies created with [`vi.spyOn`](#vi-spyon).
1664166516651666### unstubEnvs {#unstubenvs}
16661667
+46-1
docs/guide/migration.md
···116116117117Note that now if you provide an arrow function, you will get [`<anonymous> is not a constructor` error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_a_constructor) when the mock is called.
118118119119+### Changes to Mocking
120120+121121+Alongside new features like supporting constructors, Vitest 4 creates mocks differently to address several module mocking issues that we received over the years. This release attemts to make module spies less confusing, especially when working with classes.
122122+123123+- `vi.fn().getMockName()` now returns `vi.fn()` by default instead of `spy`. This can affect snapshots with mocks - the name will be changed from `[MockFunction spy]` to `[MockFunction]`. Spies created with `vi.spyOn` will keep using the original name by default for better debugging experience
124124+- `vi.restoreAllMocks` no longer resets the state of spies and only restores spies created manually with `vi.spyOn`, automocks are no longer affected by this function (this also affects the config option [`restoreMocks`](/config/#restoremocks)). Note that `.mockRestore` will still reset the mock implementation and clear the state
125125+- Calling `vi.spyOn` on a mock now returns the same mock
126126+- Automocked instance methods are now properly isolated, but share a state with the prototype. Overriding the prototype implementation will always affect instance methods unless the methods have a custom mock implementation of their own. Calling `.mockReset` on the mock also no longer breaks that inheritance.
127127+```ts
128128+import { AutoMockedClass } from './example.js'
129129+const instance1 = new AutoMockedClass()
130130+const instance2 = new AutoMockedClass()
131131+132132+instance1.method.mockReturnValue(42)
133133+134134+expect(instance1.method()).toBe(42)
135135+expect(instance2.method()).toBe(undefined)
136136+137137+expect(AutoMockedClass.prototype.method).toHaveBeenCalledTimes(2)
138138+139139+instance1.method.mockReset()
140140+AutoMockedClass.prototype.method.mockReturnValue(100)
141141+142142+expect(instance1.method()).toBe(100)
143143+expect(instance2.method()).toBe(100)
144144+145145+expect(AutoMockedClass.prototype.method).toHaveBeenCalledTimes(4)
146146+```
147147+- Automocked methods can no longer be restored, even with a manual `.mockRestore`. Automocked modules with `spy: true` will keep working as before
148148+- Automocked getters no longer call the original getter. By default, automocked getters now return `undefined`. You can keep using `vi.spyOn(object, name, 'get')` to spy on a getter and change its implementation
149149+- The mock `vi.fn(implementation).mockReset()` now correctly returns the mock implementation in `.getMockImplementation()`
150150+- `vi.fn().mock.invocationCallOrder` now starts with `1`, like Jest does, instead of `0`
151151+119152### Standalone mode with filename filter
120153121154To improve user experience, Vitest will now start running the matched files when [`--standalone`](/guide/cli#standalone) is used with filename filter.
···181214182215If you decide to keep globals disabled, be aware that common libraries like [`testing-library`](https://testing-library.com/) will not run auto DOM [cleanup](https://testing-library.com/docs/svelte-testing-library/api/#cleanup).
183216184184-### `spy.mockReset`
217217+### `mock.mockReset`
185218186219Jest's [`mockReset`](https://jestjs.io/docs/mock-function-api#mockfnmockreset) replaces the mock implementation with an
187220empty function that returns `undefined`.
188221189222Vitest's [`mockReset`](/api/mock#mockreset) resets the mock implementation to its original.
190223That is, resetting a mock created by `vi.fn(impl)` will reset the mock implementation to `impl`.
224224+225225+### `mock.mock` is Persistent
226226+227227+Jest will recreate the mock state when `.mockClear` is called, meaning you always need to access it as a getter. Vitest, on the other hand, holds a persistent reference to the state, meaning you can reuse it:
228228+229229+```ts
230230+const mock = vi.fn()
231231+const state = mock.mock
232232+mock.mockClear()
233233+234234+expect(state).toBe(mock.mock) // fails in Jest
235235+```
191236192237### Module Mocks
193238
+410
docs/guide/mocking-modules.md
···11+# Mocking Modules
22+33+## Defining a Module
44+55+Before mocking a "module", we should define what it is. In Vitest context, the "module" is a file that exports something. Using [plugins](https://vite.dev/guide/api-plugin.html), any file can be turned into a JavaScript module. The "module object" is a namespace object that holds dynamic references to exported identifiers. Simply put, it's an object with exported methods and properties. In this example, `example.js` is a module that exports `method` and `variable`:
66+77+```js [example.js]
88+export function answer() {
99+ // ...
1010+ return 42
1111+}
1212+1313+export const variable = 'example'
1414+```
1515+1616+The `exampleObject` here is a module object:
1717+1818+```js [example.test.js]
1919+import * as exampleObject from './example.js'
2020+```
2121+2222+The `exampleObject` will always exist even if you imported the example using named imports:
2323+2424+```js [example.test.js]
2525+import { answer, variable } from './example.js'
2626+```
2727+2828+You can only reference `exampleObject` outside the example module itself. For example, in a test.
2929+3030+## Mocking a Module
3131+3232+For the purpose of this guide, let's introduce some definitions.
3333+3434+- **Mocked module** is a module that was completely replaced with another one.
3535+- **Spied module** is a mocked module, but its exported methods keep the original implementation. They can also be tracked.
3636+- **Mocked export** is a module export, which invocations can be tracked.
3737+- **Spied export** is a mocked export.
3838+3939+To mock a module completely, you can use the [`vi.mock` API](/api/vi#vi-mock). You can define a new module dynamically by providing a factory that returns a new module as a second argument:
4040+4141+```ts
4242+import { vi } from 'vitest'
4343+4444+// The ./example.js module will be replaced with
4545+// the result of a factory function, and the
4646+// original ./example.js module will never be called
4747+vi.mock(import('./example.js'), () => {
4848+ return {
4949+ answer() {
5050+ // ...
5151+ return 42
5252+ },
5353+ variable: 'mock',
5454+ }
5555+})
5656+```
5757+5858+::: tip
5959+Remember that you can call `vi.mock` in a [setup file](/config/#setupfiles) to apply the module mock in every test file automatically.
6060+:::
6161+6262+::: tip
6363+Note the usage of dynamic import: `import('./example.ts')`. Vitest will strip it before the code is executed, but it allows TypeScript to properly validate the string and type the `importOriginal` method in your IDE or CLI.
6464+:::
6565+6666+If your code is trying to access a method that was not returned from this factory, Vitest will throw an error with a helpful message. Note that `answer` is not mocked, i.e. it cannot be tracked. To make it trackable, use `vi.fn()` instead:
6767+6868+```ts
6969+import { vi } from 'vitest'
7070+7171+vi.mock(import('./example.js'), () => {
7272+ return {
7373+ answer: vi.fn(),
7474+ variable: 'mock',
7575+ }
7676+})
7777+```
7878+7979+The factory method accepts an `importOriginal` function that will execute the original module and return its module object:
8080+8181+```ts
8282+import { expect, vi } from 'vitest'
8383+import { answer } from './example.js'
8484+8585+vi.mock(import('./example.js'), async (importOriginal) => {
8686+ const originalModule = await importOriginal()
8787+ return {
8888+ answer: vi.fn(originalModule.answer),
8989+ variable: 'mock',
9090+ }
9191+})
9292+9393+expect(answer()).toBe(42)
9494+9595+expect(answer).toHaveBeenCalled()
9696+expect(answer).toHaveReturned(42)
9797+```
9898+9999+::: warning
100100+Note that `importOriginal` is asynchronous and needs to be awaited.
101101+:::
102102+103103+In the above example, we provided the original `answer` to the `vi.fn()` call so it can keep calling it while being tracked at the same time.
104104+105105+If you require the use of `importOriginal`, consider spying on the export directly via another API: `vi.spyOn`. Instead of replacing the whole module, you can spy only on a single exported method. To do that, you need to import the module as a namespace object:
106106+107107+```ts
108108+import { expect, vi } from 'vitest'
109109+import * as exampleObject from './example.js'
110110+111111+const spy = vi.spyOn(exampleObject, 'answer').mockReturnValue(0)
112112+113113+expect(exampleObject.answer()).toBe(0)
114114+expect(exampleObject.answer).toHaveBeenCalled()
115115+```
116116+117117+::: danger Browser Mode Support
118118+This will not work in the [Browser Mode](/guide/browser/) because it uses the browser's native ESM support to serve modules. The module namespace object is sealed and can't be reconfigured. To bypass this limitation, Vitest supports `{ spy: true }` option in `vi.mock('./example.js')`. This will automatically spy on every export in the module without replacing them with fake ones.
119119+120120+```ts
121121+import { vi } from 'vitest'
122122+import * as exampleObject from './example.js'
123123+124124+vi.mock('./example.js', { spy: true })
125125+126126+vi.mocked(exampleObject.answer).mockReturnValue(0)
127127+```
128128+:::
129129+130130+::: warning
131131+You only need to import the module as a namespace object in the file where you are using the `vi.spyOn` utility. If the `answer` is called in another file and is imported there as a named export, Vitest will be able to properly track it as long as the function that called it is called after `vi.spyOn`:
132132+133133+```ts [source.js]
134134+import { answer } from './example.js'
135135+136136+export function question() {
137137+ if (answer() === 42) {
138138+ return 'Ultimate Question of Life, the Universe, and Everything'
139139+ }
140140+141141+ return 'Unknown Question'
142142+}
143143+```
144144+:::
145145+146146+Note that `vi.spyOn` will only spy on calls that were done after it spied on the method. So, if the function is executed at the top level during an import or it was called before the spying, `vi.spyOn` will not be able to report on it.
147147+148148+To automatically mock any module before it is imported, you can call `vi.mock` with a path:
149149+150150+```ts
151151+import { vi } from 'vitest'
152152+153153+vi.mock(import('./example.js'))
154154+```
155155+156156+If the file `./__mocks__/example.js` exists, then Vitest will load it instead. Otherwise, Vitest will load the original module and replace everything recursively:
157157+158158+- All arrays will be empty
159159+- All primitives will stay untouched
160160+- All getters will return `undefined`
161161+- All methods will return `undefined`
162162+- All objects will be deeply cloned
163163+- All instances of classes and their prototypes will be cloned
164164+165165+To disable this behavior, you can pass down `spy: true` as the second argument:
166166+167167+```ts
168168+import { vi } from 'vitest'
169169+170170+vi.mock(import('./example.js'), { spy: true })
171171+```
172172+173173+Instead of returning `undefined`, all methods will call the original implementation, but you can still keep track of these calls:
174174+175175+```ts
176176+import { expect, vi } from 'vitest'
177177+import { answer } from './example.js'
178178+179179+vi.mock(import('./example.js'), { spy: true })
180180+181181+// calls the original implementation
182182+expect(answer()).toBe(42)
183183+// vitest can still track the invocations
184184+expect(answer).toHaveBeenCalled()
185185+```
186186+187187+One nice thing that mocked modules support is sharing the state between the instance and its prototype. Consider this module:
188188+189189+```ts [answer.js]
190190+export class Answer {
191191+ constructor(value) {
192192+ this._value = value
193193+ }
194194+195195+ value() {
196196+ return this._value
197197+ }
198198+}
199199+```
200200+201201+By mocking it, we can keep track of every invocation of `.value()` even without having access to the instance itself:
202202+203203+```ts [answer.test.js]
204204+import { expect, test, vi } from 'vitest'
205205+import { Answer } from './answer.js'
206206+207207+vi.mock(import('./answer.js'), { spy: true })
208208+209209+test('instance inherits the state', () => {
210210+ // these invocations could be private inside another function
211211+ // that you don't have access to in your test
212212+ const answer1 = new Answer(42)
213213+ const answer2 = new Answer(0)
214214+215215+ expect(answer1.value()).toBe(42)
216216+ expect(answer1.value).toHaveBeenCalled()
217217+ // note that different instances have their own states
218218+ expect(answer2.value).not.toHaveBeenCalled()
219219+220220+ expect(answer2.value()).toBe(0)
221221+222222+ // but the prototype state accumulates all calls
223223+ expect(Answer.prototype.value).toHaveBeenCalledTimes(2)
224224+ expect(Answer.prototype.value).toHaveReturned(42)
225225+ expect(Answer.prototype.value).toHaveReturned(0)
226226+})
227227+```
228228+229229+This can be very useful to track calls to instances that are never exposed.
230230+231231+## Mocking Non-existing Module
232232+233233+Vitest supports mocking virtual modules. These modules don't exist on the file system, but your code imports them. For example, this can happen when your development environment is different from production. One common example is mocking `vscode` APIs in your unit tests.
234234+235235+By default, Vitest will fail transforming files if it cannot find the source of the import. To bypass this, you need to specify it in your config. You can either always redirect the import to a file, or just signal Vite to ignore it and use the `vi.mock` factory to define its exports.
236236+237237+To redirect the import, use [`test.alias`](/config/#alias) config option:
238238+239239+```ts [vitest.config.ts]
240240+import { defineConfig } from 'vitest/config'
241241+import { resolve } from 'node:path'
242242+243243+export default defineConfig({
244244+ test: {
245245+ alias: {
246246+ vscode: resolve(import.meta.dirname, './mock/vscode.js'),
247247+ },
248248+ },
249249+})
250250+```
251251+252252+To mark the module as always resolved, return the same string from `resolveId` hook of a plugin:
253253+254254+```ts [vitest.config.ts]
255255+import { defineConfig } from 'vitest/config'
256256+import { resolve } from 'node:path'
257257+258258+export default defineConfig({
259259+ plugins: [
260260+ {
261261+ name: 'virtual-vscode',
262262+ resolveId(id) {
263263+ if (id === 'vscode') {
264264+ return 'vscode'
265265+ }
266266+ }
267267+ }
268268+ ]
269269+})
270270+```
271271+272272+Now you can use `vi.mock` as usual in your tests:
273273+274274+```ts
275275+import { vi } from 'vitest'
276276+277277+vi.mock(import('vscode'), () => {
278278+ return {
279279+ window: {
280280+ createOutputChannel: vi.fn(),
281281+ }
282282+ }
283283+})
284284+```
285285+286286+## How it Works
287287+288288+Vitest implements different module mocking mechanisms depending on the environment. The only feature they share is the plugin transformer. When Vitest sees that a file has `vi.mock` inside, it will transform every static import into a dynamic one and move the `vi.mock` call to the top of the file. This allows Vitest to register the mock before the import happens without breaking the ESM rule of hoisted imports.
289289+290290+::: code-group
291291+```ts [example.js]
292292+import { answer } from './answer.js'
293293+294294+vi.mock(import('./answer.js'))
295295+296296+console.log(answer)
297297+```
298298+```ts [example.transformed.js]
299299+vi.mock('./answer.js')
300300+301301+const __vitest_module_0__ = await __handle_mock__(
302302+ () => import('./answer.js')
303303+)
304304+// to keep the live binding, we have to access
305305+// the export on the module namespace
306306+console.log(__vitest_module_0__.answer())
307307+```
308308+:::
309309+310310+The `__handle_mock__` wrapper just makes sure the mock is resolved before the import is initiated, it doesn't modify the module in any way.
311311+312312+The module mocking plugins are available in the [`@vitest/mocker` package](https://github.com/vitest-dev/vitest/tree/main/packages/mocker).
313313+314314+### JSDOM, happy-dom, Node
315315+316316+When you run your tests in an emulated environment, Vitest creates a [module runner](https://vite.dev/guide/api-environment-runtimes.html#modulerunner) that can consume Vite code. The module runner is designed in such a way that Vitest can hook into the module evaluation and replace it with the mock, if it was registered. This means that Vitest runs your code in an ESM-like environment, but it doesn't use native ESM mechanism directly. This allows the test runner to bend the rules around ES Modules immutability, allowing users to call `vi.spyOn` on a seemingly ES Module.
317317+318318+### Browser Mode
319319+320320+Vitest uses native ESM in the Browser Mode. This means that we cannot replace the module so easily. Instead, Vitest intercepts the fetch request (via playwright's `page.route` or a Vite plugin API if using `preview` or `webdriverio`) and serves transformed code, if the module was mocked.
321321+322322+For example, if the module is automocked, Vitest can parse static exports and create a placeholder module:
323323+324324+::: code-group
325325+```ts [answer.js]
326326+export function answer() {
327327+ return 42
328328+}
329329+```
330330+```ts [answer.transformed.js]
331331+function answer() {
332332+ return 42
333333+}
334334+335335+const __private_module__ = {
336336+ [Symbol.toStringTag]: 'Module',
337337+ answer: vi.fn(answer),
338338+}
339339+340340+export const answer = __private_module__.answer
341341+```
342342+:::
343343+344344+The example is simplified for brevity, but the concept is unchanged. We can inject a `__private_module__` variable into the module to hold the mocked values. If the user called `vi.mock` with `spy: true`, we pass down the original value; otherwise, we create a simple `vi.fn()` mock.
345345+346346+If user defined a custom factory, this makes it harder to inject the code, but not impossible. When the mocked file is served, we first resolve the factory in the browser, then pass down the keys back to the server, and use them to create a placeholder module:
347347+348348+```ts
349349+const resolvedFactoryKeys = await resolveBrowserFactory(url)
350350+const mockedModule = `
351351+const __private_module__ = getFactoryReturnValue(${url})
352352+${resolvedFactoryKeys.map(key => `export const ${key} = __private_module__["${key}"]`).join('\n')}
353353+`
354354+```
355355+356356+This module can now be served back to the browser. You can inspect the code in the devtools when you run the tests.
357357+358358+## Mocking Modules Pitfalls
359359+360360+Beware that it is not possible to mock calls to methods that are called inside other methods of the same file. For example, in this code:
361361+362362+```ts [foobar.js]
363363+export function foo() {
364364+ return 'foo'
365365+}
366366+367367+export function foobar() {
368368+ return `${foo()}bar`
369369+}
370370+```
371371+372372+It is not possible to mock the `foo` method from the outside because it is referenced directly. So this code will have no effect on the `foo` call inside `foobar` (but it will affect the `foo` call in other modules):
373373+374374+```ts [foobar.test.ts]
375375+import { vi } from 'vitest'
376376+import * as mod from './foobar.js'
377377+378378+// this will only affect "foo" outside of the original module
379379+vi.spyOn(mod, 'foo')
380380+vi.mock(import('./foobar.js'), async (importOriginal) => {
381381+ return {
382382+ ...await importOriginal(),
383383+ // this will only affect "foo" outside of the original module
384384+ foo: () => 'mocked'
385385+ }
386386+})
387387+```
388388+389389+You can confirm this behavior by providing the implementation to the `foobar` method directly:
390390+391391+```ts [foobar.test.js]
392392+import * as mod from './foobar.js'
393393+394394+vi.spyOn(mod, 'foo')
395395+396396+// exported foo references mocked method
397397+mod.foobar(mod.foo)
398398+```
399399+400400+```ts [foobar.js]
401401+export function foo() {
402402+ return 'foo'
403403+}
404404+405405+export function foobar(injectedFoo) {
406406+ return injectedFoo === foo // false
407407+}
408408+```
409409+410410+This is the intended behavior, and we do not plan to implement a workaround. Consider refactoring your code into multiple files or use techniques such as [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection). We believe that making the application testable is not the responsibility of the test runner, but of the application architecture.
+29-220
docs/guide/mocking.md
···155155156156## Modules
157157158158-Mock modules observe third-party-libraries, that are invoked in some other code, allowing you to test arguments, output or even redeclare its implementation.
159159-160160-See the [`vi.mock()` API section](/api/vi#vi-mock) for a more in-depth detailed API description.
161161-162162-### Automocking Algorithm
163163-164164-If your code is importing a mocked module, without any associated `__mocks__` file or `factory` for this module, Vitest will mock the module itself by invoking it and mocking every export.
165165-166166-The following principles apply
167167-* All arrays will be emptied
168168-* All primitives and collections will stay the same
169169-* All objects will be deeply cloned
170170-* All instances of classes and their prototypes will be deeply cloned
171171-172172-### Virtual Modules
173173-174174-Vitest supports mocking Vite [virtual modules](https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention). It works differently from how virtual modules are treated in Jest. Instead of passing down `virtual: true` to a `vi.mock` function, you need to tell Vite that module exists otherwise it will fail during parsing. You can do that in several ways:
175175-176176-1. Provide an alias
177177-178178-```ts [vitest.config.js]
179179-import { defineConfig } from 'vitest/config'
180180-import { resolve } from 'node:path'
181181-export default defineConfig({
182182- test: {
183183- alias: {
184184- '$app/forms': resolve('./mocks/forms.js'),
185185- },
186186- },
187187-})
188188-```
189189-190190-2. Provide a plugin that resolves a virtual module
191191-192192-```ts [vitest.config.js]
193193-import { defineConfig } from 'vitest/config'
194194-export default defineConfig({
195195- plugins: [
196196- {
197197- name: 'virtual-modules',
198198- resolveId(id) {
199199- if (id === '$app/forms') {
200200- return 'virtual:$app/forms'
201201- }
202202- },
203203- },
204204- ],
205205-})
206206-```
207207-208208-The benefit of the second approach is that you can dynamically create different virtual entrypoints. If you redirect several virtual modules into a single file, then all of them will be affected by `vi.mock`, so make sure to use unique identifiers.
209209-210210-### Mocking Pitfalls
211211-212212-Beware that it is not possible to mock calls to methods that are called inside other methods of the same file. For example, in this code:
213213-214214-```ts [foobar.js]
215215-export function foo() {
216216- return 'foo'
217217-}
218218-219219-export function foobar() {
220220- return `${foo()}bar`
221221-}
222222-```
223223-224224-It is not possible to mock the `foo` method from the outside because it is referenced directly. So this code will have no effect on the `foo` call inside `foobar` (but it will affect the `foo` call in other modules):
225225-226226-```ts [foobar.test.ts]
227227-import { vi } from 'vitest'
228228-import * as mod from './foobar.js'
229229-230230-// this will only affect "foo" outside of the original module
231231-vi.spyOn(mod, 'foo')
232232-vi.mock('./foobar.js', async (importOriginal) => {
233233- return {
234234- ...await importOriginal<typeof import('./foobar.js')>(),
235235- // this will only affect "foo" outside of the original module
236236- foo: () => 'mocked'
237237- }
238238-})
239239-```
240240-241241-You can confirm this behaviour by providing the implementation to the `foobar` method directly:
242242-243243-```ts [foobar.test.js]
244244-import * as mod from './foobar.js'
245245-246246-vi.spyOn(mod, 'foo')
247247-248248-// exported foo references mocked method
249249-mod.foobar(mod.foo)
250250-```
251251-252252-```ts [foobar.js]
253253-export function foo() {
254254- return 'foo'
255255-}
256256-257257-export function foobar(injectedFoo) {
258258- return injectedFoo === foo // false
259259-}
260260-```
261261-262262-This is the intended behaviour. It is usually a sign of bad code when mocking is involved in such a manner. Consider refactoring your code into multiple files or improving your application architecture by using techniques such as [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection).
263263-264264-### Example
265265-266266-```js
267267-import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
268268-import { Client } from 'pg'
269269-import { failure, success } from './handlers.js'
270270-271271-// get todos
272272-export async function getTodos(event, context) {
273273- const client = new Client({
274274- // ...clientOptions
275275- })
276276-277277- await client.connect()
278278-279279- try {
280280- const result = await client.query('SELECT * FROM todos;')
281281-282282- client.end()
283283-284284- return success({
285285- message: `${result.rowCount} item(s) returned`,
286286- data: result.rows,
287287- status: true,
288288- })
289289- }
290290- catch (e) {
291291- console.error(e.stack)
292292-293293- client.end()
294294-295295- return failure({ message: e, status: false })
296296- }
297297-}
298298-299299-vi.mock('pg', () => {
300300- const Client = vi.fn()
301301- Client.prototype.connect = vi.fn()
302302- Client.prototype.query = vi.fn()
303303- Client.prototype.end = vi.fn()
304304-305305- return { Client }
306306-})
307307-308308-vi.mock('./handlers.js', () => {
309309- return {
310310- success: vi.fn(),
311311- failure: vi.fn(),
312312- }
313313-})
314314-315315-describe('get a list of todo items', () => {
316316- let client
317317-318318- beforeEach(() => {
319319- client = new Client()
320320- })
321321-322322- afterEach(() => {
323323- vi.clearAllMocks()
324324- })
325325-326326- it('should return items successfully', async () => {
327327- client.query.mockResolvedValueOnce({ rows: [], rowCount: 0 })
328328-329329- await getTodos()
330330-331331- expect(client.connect).toBeCalledTimes(1)
332332- expect(client.query).toBeCalledWith('SELECT * FROM todos;')
333333- expect(client.end).toBeCalledTimes(1)
334334-335335- expect(success).toBeCalledWith({
336336- message: '0 item(s) returned',
337337- data: [],
338338- status: true,
339339- })
340340- })
341341-342342- it('should throw an error', async () => {
343343- const mError = new Error('Unable to retrieve rows')
344344- client.query.mockRejectedValueOnce(mError)
345345-346346- await getTodos()
347347-348348- expect(client.connect).toBeCalledTimes(1)
349349- expect(client.query).toBeCalledWith('SELECT * FROM todos;')
350350- expect(client.end).toBeCalledTimes(1)
351351- expect(failure).toBeCalledWith({ message: mError, status: false })
352352- })
353353-})
354354-```
158158+See ["Mocking Modules" guide](/guide/mocking-modules).
355159356160## File System
357161···594398595399## Classes
596400597597-You can mock an entire class with a single `vi.fn` call - since all classes are also functions, this works out of the box. Beware that currently Vitest doesn't respect the `new` keyword so the `new.target` is always `undefined` in the body of a function.
401401+You can mock an entire class with a single `vi.fn` call.
598402599403```ts
600404class Dog {
···621425}
622426```
623427624624-We can re-create this class with ES5 functions:
428428+We can re-create this class with `vi.fn` (or `vi.spyOn().mockImplementation()`):
625429626430```ts
627627-const Dog = vi.fn(function (name) {
628628- this.name = name
629629- // mock instance methods in the constructor, each instance will have its own spy
630630- this.greet = vi.fn(() => `Hi! My name is ${this.name}!`)
431431+const Dog = vi.fn(class {
432432+ static getType = vi.fn(() => 'mocked animal')
433433+434434+ constructor(name) {
435435+ this.name = name
436436+ }
437437+438438+ greet = vi.fn(() => `Hi! My name is ${this.name}!`)
439439+ speak = vi.fn(() => 'loud bark!')
440440+ feed = vi.fn()
631441})
632632-633633-// notice that static methods are mocked directly on the function,
634634-// not on the instance of the class
635635-Dog.getType = vi.fn(() => 'mocked animal')
636636-637637-// mock the "speak" and "feed" methods on every instance of a class
638638-// all `new Dog()` instances will inherit and share these spies
639639-Dog.prototype.speak = vi.fn(() => 'loud bark!')
640640-Dog.prototype.feed = vi.fn()
641442```
642443643444::: warning
···658459Marti instanceof CorrectDogClass // ✅ true
659460Newt instanceof IncorrectDogClass // ❌ false!
660461```
462462+463463+If you are mocking classes, prefer the class syntax over the function.
661464:::
662465663466::: tip WHEN TO USE?
···667470import { Dog } from './dog.js'
668471669472vi.mock(import('./dog.js'), () => {
670670- const Dog = vi.fn()
671671- Dog.prototype.feed = vi.fn()
672672- // ... other mocks
473473+ const Dog = vi.fn(class {
474474+ feed = vi.fn()
475475+ // ... other mocks
476476+ })
673477 return { Dog }
674478})
675479```
···685489import { expect, test, vi } from 'vitest'
686490import { feed } from '../src/feed.js'
687491688688-const Dog = vi.fn()
689689-Dog.prototype.feed = vi.fn()
492492+const Dog = vi.fn(class {
493493+ feed = vi.fn()
494494+})
690495691496test('can feed dogs', () => {
692497 const dogMax = new Dog('Max')
···712517713518const Max = new Dog('Max')
714519715715-// methods assigned to the prototype are shared between instances
716716-expect(Max.speak).toHaveBeenCalled()
520520+// methods are not shared between instances if you assigned them directly
521521+expect(Max.speak).not.toHaveBeenCalled()
717522expect(Max.greet).not.toHaveBeenCalled()
718523```
719524···724529725530// "vi.mocked" is a type helper, since
726531// TypeScript doesn't know that Dog is a mocked class,
727727-// it wraps any function in a MockInstance<T> type
532532+// it wraps any function in a Mock<T> type
728533// without validating if the function is a mock
729534vi.mocked(dog.speak).mockReturnValue('woof woof')
730535···744549745550::: tip
746551You can also spy on getters and setters using the same method.
552552+:::
553553+554554+::: danger
555555+Using classes with `vi.fn()` was introduced in Vitest 4. Previously, you had to use `function` and `prototype` inheritence directly. See [v3 guide](https://v3.vitest.dev/guide/mocking.html#classes).
747556:::
748557749558## Cheat Sheet
···153153 if (log.includes('run [...filters]')) {
154154 return false
155155 }
156156+ if (log.startsWith(`[vitest]`) && log.includes(`did not use 'function' or 'class' in its implementation`)) {
157157+ return false
158158+ }
156159 },
157160 projects: [
158161 project('threads', 'red'),
+103-66
packages/mocker/src/automocker.ts
···11-import type { MockedModuleType } from './registry'
22-31type Key = string | symbol
4233+export type CreateMockInstanceProcedure = (options?: {
44+ prototypeMembers?: (string | symbol)[]
55+ name?: string | symbol
66+ originalImplementation?: (...args: any[]) => any
77+ keepMembersImplementation?: boolean
88+}) => any
99+510export interface MockObjectOptions {
66- type: MockedModuleType
1111+ type: 'automock' | 'autospy'
712 globalConstructors: GlobalConstructors
88- spyOn: (obj: any, prop: Key) => any
1313+ createMockInstance: CreateMockInstanceProcedure
914}
10151116export function mockObject(
···2631 }
2732 }
28333434+ const createMock = (currentValue: (...args: any[]) => any) => {
3535+ if (!options.createMockInstance) {
3636+ throw new Error(
3737+ '[@vitest/mocker] `createMockInstance` is not defined. This is a Vitest error. Please open a new issue with reproduction.',
3838+ )
3939+ }
4040+ const createMockInstance = options.createMockInstance
4141+ const prototypeMembers = currentValue.prototype
4242+ ? collectFunctionProperties(currentValue.prototype)
4343+ : []
4444+ return createMockInstance({
4545+ name: currentValue.name,
4646+ prototypeMembers,
4747+ originalImplementation: options.type === 'autospy' ? currentValue : undefined,
4848+ keepMembersImplementation: options.type === 'autospy',
4949+ })
5050+ }
5151+2952 const mockPropertiesOf = (
3053 container: Record<Key, any>,
3154 newContainer: Record<Key, any>,
···4063 // Modules define their exports as getters. We want to process those.
4164 if (!isModule && descriptor.get) {
4265 try {
4343- Object.defineProperty(newContainer, property, descriptor)
6666+ if (options.type === 'autospy') {
6767+ Object.defineProperty(newContainer, property, descriptor)
6868+ }
6969+ else {
7070+ Object.defineProperty(newContainer, property, {
7171+ configurable: descriptor.configurable,
7272+ enumerable: descriptor.enumerable,
7373+ // automatically mock getters and setters
7474+ // https://github.com/vitest-dev/vitest/issues/8345
7575+ get: () => {},
7676+ set: descriptor.set ? () => {} : undefined,
7777+ })
7878+ }
4479 }
4580 catch {
4681 // Ignore errors, just move on to the next prop.
···4984 }
50855186 // Skip special read-only props, we don't want to mess with those.
5252- if (isSpecialProp(property, containerType)) {
8787+ if (isReadonlyProp(container[property], property)) {
5388 continue
5489 }
5590···68103 const type = getType(value)
6910470105 if (Array.isArray(value)) {
7171- define(newContainer, property, [])
106106+ if (options.type === 'automock') {
107107+ define(newContainer, property, [])
108108+ }
109109+ else {
110110+ const array = value.map((value) => {
111111+ if (value && typeof value === 'object') {
112112+ const newObject = {}
113113+ mockPropertiesOf(value, newObject)
114114+ return newObject
115115+ }
116116+ if (typeof value === 'function') {
117117+ return createMock(value)
118118+ }
119119+ return value
120120+ })
121121+ define(newContainer, property, array)
122122+ }
72123 continue
73124 }
74125···8513686137 // Sometimes this assignment fails for some unknown reason. If it does,
87138 // just move along.
8888- if (!define(newContainer, property, isFunction ? value : {})) {
139139+ if (!define(newContainer, property, isFunction || options.type === 'autospy' ? value : {})) {
89140 continue
90141 }
9114292143 if (isFunction) {
9393- if (!options.spyOn) {
9494- throw new Error(
9595- '[@vitest/mocker] `spyOn` is not defined. This is a Vitest error. Please open a new issue with reproduction.',
9696- )
9797- }
9898- const spyOn = options.spyOn
9999- function mockFunction(this: any) {
100100- // detect constructor call and mock each instance's methods
101101- // so that mock states between prototype/instances don't affect each other
102102- // (jest reference https://github.com/jestjs/jest/blob/2c3d2409879952157433de215ae0eee5188a4384/packages/jest-mock/src/index.ts#L678-L691)
103103- if (this instanceof newContainer[property]) {
104104- for (const { key, descriptor } of getAllMockableProperties(
105105- this,
106106- false,
107107- options.globalConstructors,
108108- )) {
109109- // skip getter since it's not mocked on prototype as well
110110- if (descriptor.get) {
111111- continue
112112- }
113113-114114- const value = this[key]
115115- const type = getType(value)
116116- const isFunction
117117- = type.includes('Function') && typeof value === 'function'
118118- if (isFunction) {
119119- // mock and delegate calls to original prototype method, which should be also mocked already
120120- const original = this[key]
121121- const mock = spyOn(this, key as string)
122122- .mockImplementation(original)
123123- const origMockReset = mock.mockReset
124124- mock.mockRestore = mock.mockReset = () => {
125125- origMockReset.call(mock)
126126- mock.mockImplementation(original)
127127- return mock
128128- }
129129- }
130130- }
131131- }
132132- }
133133- const mock = spyOn(newContainer, property)
134134- if (options.type === 'automock') {
135135- mock.mockImplementation(mockFunction)
136136- const origMockReset = mock.mockReset
137137- mock.mockRestore = mock.mockReset = () => {
138138- origMockReset.call(mock)
139139- mock.mockImplementation(mockFunction)
140140- return mock
141141- }
142142- }
143143- // tinyspy retains length, but jest doesn't.
144144- Object.defineProperty(newContainer[property], 'length', { value: 0 })
144144+ const mock = createMock(newContainer[property])
145145+ newContainer[property] = mock
145146 }
146147147148 refs.track(value, newContainer[property])
···184185 return Object.prototype.toString.apply(value).slice(8, -1)
185186}
186187187187-function isSpecialProp(prop: Key, parentType: string) {
188188- return (
189189- parentType.includes('Function')
190190- && typeof prop === 'string'
191191- && ['arguments', 'callee', 'caller', 'length', 'name'].includes(prop)
192192- )
188188+function isReadonlyProp(object: unknown, prop: string | symbol) {
189189+ if (
190190+ prop === 'arguments'
191191+ || prop === 'caller'
192192+ || prop === 'callee'
193193+ || prop === 'name'
194194+ || prop === 'length'
195195+ ) {
196196+ const typeName = getType(object)
197197+ return (
198198+ typeName === 'Function'
199199+ || typeName === 'AsyncFunction'
200200+ || typeName === 'GeneratorFunction'
201201+ || typeName === 'AsyncGeneratorFunction'
202202+ )
203203+ }
204204+205205+ if (
206206+ prop === 'source'
207207+ || prop === 'global'
208208+ || prop === 'ignoreCase'
209209+ || prop === 'multiline'
210210+ ) {
211211+ return getType(object) === 'RegExp'
212212+ }
213213+214214+ return false
193215}
194216195217export interface GlobalConstructors {
···250272 : (key: string | symbol) => collector.add(key)
251273 Object.getOwnPropertyNames(obj).forEach(collect)
252274 Object.getOwnPropertySymbols(obj).forEach(collect)
275275+}
276276+277277+function collectFunctionProperties(prototype: any) {
278278+ const properties = new Set<string | symbol>()
279279+ collectOwnProperties(prototype, (prop) => {
280280+ const descriptor = Object.getOwnPropertyDescriptor(prototype, prop)
281281+ if (!descriptor || descriptor.get) {
282282+ return
283283+ }
284284+ const type = getType(descriptor.value)
285285+ if (type.includes('Function') && !isReadonlyProp(descriptor.value, prop)) {
286286+ properties.add(prop)
287287+ }
288288+ })
289289+ return Array.from(properties)
253290}
+587-719
packages/spy/src/index.ts
···11-import type { SpyInternalImpl } from 'tinyspy'
22-import * as tinyspy from 'tinyspy'
11+import type {
22+ Classes,
33+ Constructable,
44+ Methods,
55+ Mock,
66+ MockConfig,
77+ MockContext,
88+ MockInstanceOption,
99+ MockProcedureContext,
1010+ MockResult,
1111+ MockReturnType,
1212+ MockSettledResult,
1313+ Procedure,
1414+ Properties,
1515+} from './types'
31644-interface MockResultReturn<T> {
55- type: 'return'
66- /**
77- * The value that was returned from the function. If function returned a Promise, then this will be a resolved value.
88- */
99- value: T
1010-}
1111-interface MockResultIncomplete {
1212- type: 'incomplete'
1313- value: undefined
1414-}
1515-interface MockResultThrow {
1616- type: 'throw'
1717- /**
1818- * An error that was thrown during function execution.
1919- */
2020- value: any
2121-}
2222-2323-interface MockSettledResultFulfilled<T> {
2424- type: 'fulfilled'
2525- value: T
2626-}
2727-2828-interface MockSettledResultRejected {
2929- type: 'rejected'
3030- value: any
3131-}
3232-3333-export type MockResult<T>
3434- = | MockResultReturn<T>
3535- | MockResultThrow
3636- | MockResultIncomplete
3737-export type MockSettledResult<T>
3838- = | MockSettledResultFulfilled<T>
3939- | MockSettledResultRejected
4040-4141-type MockParameters<T extends Procedure | Constructable> = T extends Constructable
4242- ? ConstructorParameters<T>
4343- : T extends Procedure
4444- ? Parameters<T> : never
4545-4646-type MockReturnType<T extends Procedure | Constructable> = T extends Constructable
4747- ? void
4848- : T extends Procedure
4949- ? ReturnType<T> : never
5050-5151-type MockFnContext<T extends Procedure | Constructable> = T extends Constructable
5252- ? InstanceType<T>
5353- : ThisParameterType<T>
5454-5555-export interface MockContext<T extends Procedure | Constructable> {
5656- /**
5757- * This is an array containing all arguments for each call. One item of the array is the arguments of that call.
5858- *
5959- * @see https://vitest.dev/api/mock#mock-calls
6060- * @example
6161- * const fn = vi.fn()
6262- *
6363- * fn('arg1', 'arg2')
6464- * fn('arg3')
6565- *
6666- * fn.mock.calls === [
6767- * ['arg1', 'arg2'], // first call
6868- * ['arg3'], // second call
6969- * ]
7070- */
7171- calls: MockParameters<T>[]
7272- /**
7373- * This is an array containing all instances that were instantiated when mock was called with a `new` keyword. Note that this is an actual context (`this`) of the function, not a return value.
7474- * @see https://vitest.dev/api/mock#mock-instances
7575- */
7676- instances: MockResultReturn<T>[]
7777- /**
7878- * An array of `this` values that were used during each call to the mock function.
7979- * @see https://vitest.dev/api/mock#mock-contexts
8080- */
8181- contexts: MockFnContext<T>[]
8282- /**
8383- * The order of mock's execution. This returns an array of numbers which are shared between all defined mocks.
8484- *
8585- * @see https://vitest.dev/api/mock#mock-invocationcallorder
8686- * @example
8787- * const fn1 = vi.fn()
8888- * const fn2 = vi.fn()
8989- *
9090- * fn1()
9191- * fn2()
9292- * fn1()
9393- *
9494- * fn1.mock.invocationCallOrder === [1, 3]
9595- * fn2.mock.invocationCallOrder === [2]
9696- */
9797- invocationCallOrder: number[]
9898- /**
9999- * This is an array containing all values that were `returned` from the function.
100100- *
101101- * The `value` property contains the returned value or thrown error. If the function returned a `Promise`, then `result` will always be `'return'` even if the promise was rejected.
102102- *
103103- * @see https://vitest.dev/api/mock#mock-results
104104- * @example
105105- * const fn = vi.fn()
106106- * .mockReturnValueOnce('result')
107107- * .mockImplementationOnce(() => { throw new Error('thrown error') })
108108- *
109109- * const result = fn()
110110- *
111111- * try {
112112- * fn()
113113- * }
114114- * catch {}
115115- *
116116- * fn.mock.results === [
117117- * {
118118- * type: 'return',
119119- * value: 'result',
120120- * },
121121- * {
122122- * type: 'throw',
123123- * value: Error,
124124- * },
125125- * ]
126126- */
127127- results: MockResult<MockReturnType<T>>[]
128128- /**
129129- * An array containing all values that were `resolved` or `rejected` from the function.
130130- *
131131- * This array will be empty if the function was never resolved or rejected.
132132- *
133133- * @see https://vitest.dev/api/mock#mock-settledresults
134134- * @example
135135- * const fn = vi.fn().mockResolvedValueOnce('result')
136136- *
137137- * const result = fn()
138138- *
139139- * fn.mock.settledResults === []
140140- * fn.mock.results === [
141141- * {
142142- * type: 'return',
143143- * value: Promise<'result'>,
144144- * },
145145- * ]
146146- *
147147- * await result
148148- *
149149- * fn.mock.settledResults === [
150150- * {
151151- * type: 'fulfilled',
152152- * value: 'result',
153153- * },
154154- * ]
155155- */
156156- settledResults: MockSettledResult<Awaited<MockReturnType<T>>>[]
157157- /**
158158- * This contains the arguments of the last call. If spy wasn't called, will return `undefined`.
159159- * @see https://vitest.dev/api/mock#mock-lastcall
160160- */
161161- lastCall: MockParameters<T> | undefined
162162- /** @internal */
163163- _state: (state?: InternalState) => InternalState
164164-}
165165-166166-interface InternalState {
167167- implementation: Procedure | Constructable | undefined
168168- onceImplementations: (Procedure | Constructable)[]
169169- implementationChangedTemporarily: boolean
170170-}
171171-172172-type Procedure = (...args: any[]) => any
173173-// pick a single function type from function overloads, unions, etc...
174174-type NormalizedProcedure<T extends Procedure | Constructable> = T extends Constructable
175175- ? ({
176176- new (...args: ConstructorParameters<T>): InstanceType<T>
177177- })
178178- | ({
179179- (this: InstanceType<T>, ...args: ConstructorParameters<T>): void
180180- })
181181- : T extends Procedure
182182- ? (...args: Parameters<T>) => ReturnType<T>
183183- : never
184184-185185-type Methods<T> = keyof {
186186- [K in keyof T as T[K] extends Procedure ? K : never]: T[K];
187187-}
188188-type Properties<T> = {
189189- [K in keyof T]: T[K] extends Procedure ? never : K;
190190-}[keyof T]
191191-& (string | symbol)
192192-type Classes<T> = {
193193- [K in keyof T]: T[K] extends new (...args: any[]) => any ? K : never;
194194-}[keyof T]
195195-& (string | symbol)
196196-197197-/*
198198-cf. https://typescript-eslint.io/rules/method-signature-style/
199199-200200-Typescript assignability is different between
201201- { foo: (f: T) => U } (this is "method-signature-style")
202202-and
203203- { foo(f: T): U }
204204-205205-Jest uses the latter for `MockInstance.mockImplementation` etc... and it allows assignment such as:
206206- const boolFn: Jest.Mock<() => boolean> = jest.fn<() => true>(() => true)
207207-*/
208208-/* eslint-disable ts/method-signature-style */
209209-export interface MockInstance<T extends Procedure | Constructable = Procedure> extends Disposable {
210210- /**
211211- * Use it to return the name assigned to the mock with the `.mockName(name)` method. By default, it will return `vi.fn()`.
212212- * @see https://vitest.dev/api/mock#getmockname
213213- */
214214- getMockName(): string
215215- /**
216216- * Sets the internal mock name. This is useful for identifying the mock when an assertion fails.
217217- * @see https://vitest.dev/api/mock#mockname
218218- */
219219- mockName(name: string): this
220220- /**
221221- * Current context of the mock. It stores information about all invocation calls, instances, and results.
222222- */
223223- mock: MockContext<T>
224224- /**
225225- * Clears all information about every call. After calling it, all properties on `.mock` will return to their initial state. This method does not reset implementations. It is useful for cleaning up mocks between different assertions.
226226- *
227227- * To automatically call this method before each test, enable the [`clearMocks`](https://vitest.dev/config/#clearmocks) setting in the configuration.
228228- * @see https://vitest.dev/api/mock#mockclear
229229- */
230230- mockClear(): this
231231- /**
232232- * Does what `mockClear` does and resets inner implementation to the original function. This also resets all "once" implementations.
233233- *
234234- * Note that resetting a mock from `vi.fn()` will set implementation to an empty function that returns `undefined`.
235235- * Resetting a mock from `vi.fn(impl)` will set implementation to `impl`. It is useful for completely resetting a mock to its default state.
236236- *
237237- * To automatically call this method before each test, enable the [`mockReset`](https://vitest.dev/config/#mockreset) setting in the configuration.
238238- * @see https://vitest.dev/api/mock#mockreset
239239- */
240240- mockReset(): this
241241- /**
242242- * Does what `mockReset` does and restores original descriptors of spied-on objects.
243243- *
244244- * Note that restoring mock from `vi.fn()` will set implementation to an empty function that returns `undefined`. Restoring a `vi.fn(impl)` will restore implementation to `impl`.
245245- * @see https://vitest.dev/api/mock#mockrestore
246246- */
247247- mockRestore(): void
248248- /**
249249- * Returns current permanent mock implementation if there is one.
250250- *
251251- * If mock was created with `vi.fn`, it will consider passed down method as a mock implementation.
252252- *
253253- * If mock was created with `vi.spyOn`, it will return `undefined` unless a custom implementation was provided.
254254- */
255255- getMockImplementation(): NormalizedProcedure<T> | undefined
256256- /**
257257- * Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function.
258258- * @see https://vitest.dev/api/mock#mockimplementation
259259- * @example
260260- * const increment = vi.fn().mockImplementation(count => count + 1);
261261- * expect(increment(3)).toBe(4);
262262- */
263263- mockImplementation(fn: NormalizedProcedure<T>): this
264264- /**
265265- * Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function. This method can be chained to produce different results for multiple function calls.
266266- *
267267- * When the mocked function runs out of implementations, it will invoke the default implementation set with `vi.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called.
268268- * @see https://vitest.dev/api/mock#mockimplementationonce
269269- * @example
270270- * const fn = vi.fn(count => count).mockImplementationOnce(count => count + 1);
271271- * expect(fn(3)).toBe(4);
272272- * expect(fn(3)).toBe(3);
273273- */
274274- mockImplementationOnce(fn: NormalizedProcedure<T>): this
275275- /**
276276- * Overrides the original mock implementation temporarily while the callback is being executed.
277277- *
278278- * Note that this method takes precedence over the [`mockImplementationOnce`](https://vitest.dev/api/mock#mockimplementationonce).
279279- * @see https://vitest.dev/api/mock#withimplementation
280280- * @example
281281- * const myMockFn = vi.fn(() => 'original')
282282- *
283283- * myMockFn.withImplementation(() => 'temp', () => {
284284- * myMockFn() // 'temp'
285285- * })
286286- *
287287- * myMockFn() // 'original'
288288- */
289289- withImplementation<T2>(fn: NormalizedProcedure<T>, cb: () => T2): T2 extends Promise<unknown> ? Promise<this> : this
290290-291291- /**
292292- * Use this if you need to return the `this` context from the method without invoking the actual implementation.
293293- * @see https://vitest.dev/api/mock#mockreturnthis
294294- */
295295- mockReturnThis(): this
296296- /**
297297- * Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
298298- * @see https://vitest.dev/api/mock#mockreturnvalue
299299- * @example
300300- * const mock = vi.fn()
301301- * mock.mockReturnValue(42)
302302- * mock() // 42
303303- * mock.mockReturnValue(43)
304304- * mock() // 43
305305- */
306306- mockReturnValue(value: MockReturnType<T>): this
307307- /**
308308- * Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
309309- *
310310- * When the mocked function runs out of implementations, it will invoke the default implementation set with `vi.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called.
311311- * @example
312312- * const myMockFn = vi
313313- * .fn()
314314- * .mockReturnValue('default')
315315- * .mockReturnValueOnce('first call')
316316- * .mockReturnValueOnce('second call')
317317- *
318318- * // 'first call', 'second call', 'default'
319319- * console.log(myMockFn(), myMockFn(), myMockFn())
320320- */
321321- mockReturnValueOnce(value: MockReturnType<T>): this
322322- /**
323323- * Accepts a value that will be resolved when the async function is called. TypeScript will only accept values that match the return type of the original function.
324324- * @example
325325- * const asyncMock = vi.fn().mockResolvedValue(42)
326326- * asyncMock() // Promise<42>
327327- */
328328- mockResolvedValue(value: Awaited<MockReturnType<T>>): this
329329- /**
330330- * Accepts a value that will be resolved during the next function call. TypeScript will only accept values that match the return type of the original function. If chained, each consecutive call will resolve the specified value.
331331- * @example
332332- * const myMockFn = vi
333333- * .fn()
334334- * .mockResolvedValue('default')
335335- * .mockResolvedValueOnce('first call')
336336- * .mockResolvedValueOnce('second call')
337337- *
338338- * // Promise<'first call'>, Promise<'second call'>, Promise<'default'>
339339- * console.log(myMockFn(), myMockFn(), myMockFn())
340340- */
341341- mockResolvedValueOnce(value: Awaited<MockReturnType<T>>): this
342342- /**
343343- * Accepts an error that will be rejected when async function is called.
344344- * @example
345345- * const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'))
346346- * await asyncMock() // throws Error<'Async error'>
347347- */
348348- mockRejectedValue(error: unknown): this
349349- /**
350350- * Accepts a value that will be rejected during the next function call. If chained, each consecutive call will reject the specified value.
351351- * @example
352352- * const asyncMock = vi
353353- * .fn()
354354- * .mockResolvedValueOnce('first call')
355355- * .mockRejectedValueOnce(new Error('Async error'))
356356- *
357357- * await asyncMock() // first call
358358- * await asyncMock() // throws Error<'Async error'>
359359- */
360360- mockRejectedValueOnce(error: unknown): this
361361-}
362362-/* eslint-enable ts/method-signature-style */
363363-364364-export interface Mock<T extends Procedure | Constructable = Procedure> extends MockInstance<T> {
365365- new (...args: MockParameters<T>): T extends Constructable ? InstanceType<T> : MockReturnType<T>
366366- (...args: MockParameters<T>): MockReturnType<T>
367367-}
368368-369369-type PartialMaybePromise<T> = T extends Promise<Awaited<T>>
370370- ? Promise<Partial<Awaited<T>>>
371371- : Partial<T>
372372-373373-export interface PartialMock<T extends Procedure = Procedure>
374374- extends MockInstance<
375375- (...args: Parameters<T>) => PartialMaybePromise<ReturnType<T>>
376376- > {
377377- new (...args: Parameters<T>): ReturnType<T>
378378- (...args: Parameters<T>): ReturnType<T>
379379-}
380380-381381-export type MaybeMockedConstructor<T> = T extends new (
382382- ...args: Array<any>
383383-) => infer R
384384- ? Mock<(...args: ConstructorParameters<T>) => R>
385385- : T
386386-export type MockedFunction<T extends Procedure> = Mock<T> & {
387387- [K in keyof T]: T[K];
388388-}
389389-export type PartiallyMockedFunction<T extends Procedure> = PartialMock<T> & {
390390- [K in keyof T]: T[K];
391391-}
392392-export type MockedFunctionDeep<T extends Procedure> = Mock<T>
393393- & MockedObjectDeep<T>
394394-export type PartiallyMockedFunctionDeep<T extends Procedure> = PartialMock<T>
395395- & MockedObjectDeep<T>
396396-export type MockedObject<T> = MaybeMockedConstructor<T> & {
397397- [K in Methods<T>]: T[K] extends Procedure ? MockedFunction<T[K]> : T[K];
398398-} & { [K in Properties<T>]: T[K] }
399399-export type MockedObjectDeep<T> = MaybeMockedConstructor<T> & {
400400- [K in Methods<T>]: T[K] extends Procedure ? MockedFunctionDeep<T[K]> : T[K];
401401-} & { [K in Properties<T>]: MaybeMockedDeep<T[K]> }
402402-403403-export type MaybeMockedDeep<T> = T extends Procedure
404404- ? MockedFunctionDeep<T>
405405- : T extends object
406406- ? MockedObjectDeep<T>
407407- : T
408408-409409-export type MaybePartiallyMockedDeep<T> = T extends Procedure
410410- ? PartiallyMockedFunctionDeep<T>
411411- : T extends object
412412- ? MockedObjectDeep<T>
413413- : T
414414-415415-export type MaybeMocked<T> = T extends Procedure
416416- ? MockedFunction<T>
417417- : T extends object
418418- ? MockedObject<T>
419419- : T
420420-421421-export type MaybePartiallyMocked<T> = T extends Procedure
422422- ? PartiallyMockedFunction<T>
423423- : T extends object
424424- ? MockedObject<T>
425425- : T
426426-427427-interface Constructable {
428428- new (...args: any[]): any
429429-}
430430-431431-export type MockedClass<T extends Constructable> = MockInstance<
432432- (...args: ConstructorParameters<T>) => InstanceType<T>
433433-> & {
434434- prototype: T extends { prototype: any } ? Mocked<T['prototype']> : never
435435-} & T
436436-437437-export type Mocked<T> = {
438438- [P in keyof T]: T[P] extends Procedure
439439- ? MockInstance<T[P]>
440440- : T[P] extends Constructable
441441- ? MockedClass<T[P]>
442442- : T[P];
443443-} & T
444444-445445-export const mocks: Set<MockInstance<any>> = new Set()
446446-447447-export function isMockFunction(fn: any): fn is MockInstance {
1717+export function isMockFunction(fn: any): fn is Mock {
44818 return (
449449- typeof fn === 'function' && '_isMockFunction' in fn && fn._isMockFunction
1919+ typeof fn === 'function' && '_isMockFunction' in fn && fn._isMockFunction === true
45020 )
45121}
45222453453-export function spyOn<T, S extends Properties<Required<T>>>(
454454- obj: T,
455455- methodName: S,
456456- accessType: 'get'
2323+const MOCK_RESTORE = new Set<() => void>()
2424+// Jest keeps the state in a separate WeakMap which is good for memory,
2525+// but it makes the state slower to access and return different values
2626+// if you stored it before calling `mockClear` where it will be recreated
2727+const REGISTERED_MOCKS = new Set<Mock>()
2828+const MOCK_CONFIGS = new WeakMap<Mock, MockConfig>()
2929+3030+export function createMockInstance(options: MockInstanceOption = {}): Mock {
3131+ const {
3232+ originalImplementation,
3333+ restore,
3434+ mockImplementation,
3535+ resetToMockImplementation,
3636+ resetToMockName,
3737+ } = options
3838+3939+ if (restore) {
4040+ MOCK_RESTORE.add(restore)
4141+ }
4242+4343+ const config = getDefaultConfig(originalImplementation)
4444+ const state = getDefaultState()
4545+4646+ const mock = createMock({
4747+ config,
4848+ state,
4949+ ...options,
5050+ })
5151+ // inherit the default name so it appears in snapshots and logs
5252+ // this is used by `vi.spyOn()` for better debugging.
5353+ // when `vi.fn()` is called, we just use the default string
5454+ if (resetToMockName) {
5555+ config.mockName = mock.name || 'vi.fn()'
5656+ }
5757+ MOCK_CONFIGS.set(mock, config)
5858+ REGISTERED_MOCKS.add(mock)
5959+6060+ mock._isMockFunction = true
6161+ mock.getMockImplementation = () => {
6262+ // Jest only returns `config.mockImplementation` here,
6363+ // but we think it makes sense to return what the next function will be called
6464+ return config.onceMockImplementations[0] || config.mockImplementation
6565+ }
6666+6767+ Object.defineProperty(mock, 'mock', {
6868+ configurable: false,
6969+ enumerable: true,
7070+ writable: false,
7171+ value: state,
7272+ })
7373+7474+ mock.mockImplementation = function mockImplementation(implementation) {
7575+ config.mockImplementation = implementation
7676+ return mock
7777+ }
7878+7979+ mock.mockImplementationOnce = function mockImplementationOnce(implementation) {
8080+ config.onceMockImplementations.push(implementation)
8181+ return mock
8282+ }
8383+8484+ mock.withImplementation = function withImplementation(implementation, callback) {
8585+ const previousImplementation = config.mockImplementation
8686+ const previousOnceImplementations = config.onceMockImplementations
8787+8888+ const reset = () => {
8989+ config.mockImplementation = previousImplementation
9090+ config.onceMockImplementations = previousOnceImplementations
9191+ }
9292+9393+ config.mockImplementation = implementation
9494+ config.onceMockImplementations = []
9595+9696+ const returnValue = callback()
9797+9898+ if (typeof returnValue === 'object' && typeof (returnValue as Promise<any>)?.then === 'function') {
9999+ return (returnValue as Promise<any>).then(() => {
100100+ reset()
101101+ return mock
102102+ }) as any
103103+ }
104104+ else {
105105+ reset()
106106+ }
107107+ return mock
108108+ }
109109+110110+ mock.mockReturnThis = function mockReturnThis() {
111111+ return mock.mockImplementation(function (this: any) {
112112+ return this
113113+ })
114114+ }
115115+116116+ mock.mockReturnValue = function mockReturnValue(value) {
117117+ return mock.mockImplementation(() => value)
118118+ }
119119+120120+ mock.mockReturnValueOnce = function mockReturnValueOnce(value) {
121121+ return mock.mockImplementationOnce(() => value)
122122+ }
123123+124124+ mock.mockResolvedValue = function mockResolvedValue(value) {
125125+ return mock.mockImplementation(() => Promise.resolve(value))
126126+ }
127127+128128+ mock.mockResolvedValueOnce = function mockResolvedValueOnce(value) {
129129+ return mock.mockImplementationOnce(() => Promise.resolve(value))
130130+ }
131131+132132+ mock.mockRejectedValue = function mockRejectedValue(value) {
133133+ return mock.mockImplementation(() => Promise.reject(value))
134134+ }
135135+136136+ mock.mockRejectedValueOnce = function mockRejectedValueOnce(value) {
137137+ return mock.mockImplementationOnce(() => Promise.reject(value))
138138+ }
139139+140140+ mock.mockClear = function mockClear() {
141141+ state.calls = []
142142+ state.contexts = []
143143+ state.instances = []
144144+ state.invocationCallOrder = []
145145+ state.results = []
146146+ state.settledResults = []
147147+ return mock
148148+ }
149149+150150+ mock.mockReset = function mockReset() {
151151+ mock.mockClear()
152152+ config.mockImplementation = resetToMockImplementation
153153+ ? mockImplementation
154154+ : undefined
155155+ config.mockName = resetToMockName ? (mock.name || 'vi.fn()') : 'vi.fn()'
156156+ config.onceMockImplementations = []
157157+ return mock
158158+ }
159159+160160+ mock.mockRestore = function mockRestore() {
161161+ mock.mockReset()
162162+ return restore?.()
163163+ }
164164+165165+ mock.mockName = function mockName(name: string) {
166166+ if (typeof name === 'string') {
167167+ config.mockName = name
168168+ }
169169+ return mock
170170+ }
171171+172172+ mock.getMockName = function getMockName() {
173173+ return config.mockName || 'vi.fn()'
174174+ }
175175+176176+ if (Symbol.dispose) {
177177+ mock[Symbol.dispose] = () => mock.mockRestore()
178178+ }
179179+180180+ if (mockImplementation) {
181181+ mock.mockImplementation(mockImplementation)
182182+ }
183183+184184+ return mock
185185+}
186186+187187+export function fn<T extends Procedure | Constructable = Procedure>(
188188+ originalImplementation?: T,
189189+): Mock<T> {
190190+ return createMockInstance({
191191+ // we pass this down so getMockImplementation() always returns the value
192192+ mockImplementation: originalImplementation,
193193+ // special case so that .mockReset() resets the value to
194194+ // the the originalImplementation instead of () => undefined
195195+ resetToMockImplementation: true,
196196+ }) as Mock<T>
197197+}
198198+199199+export function spyOn<T extends object, S extends Properties<Required<T>>>(
200200+ object: T,
201201+ key: S,
202202+ accessor: 'get'
457203): Mock<() => T[S]>
458458-export function spyOn<T, G extends Properties<Required<T>>>(
459459- obj: T,
460460- methodName: G,
461461- accessType: 'set'
204204+export function spyOn<T extends object, G extends Properties<Required<T>>>(
205205+ object: T,
206206+ key: G,
207207+ accessor: 'set'
462208): Mock<(arg: T[G]) => void>
463463-export function spyOn<T, M extends Classes<Required<T>> | Methods<Required<T>>>(
464464- obj: T,
465465- methodName: M
209209+export function spyOn<T extends object, M extends Classes<Required<T>> | Methods<Required<T>>>(
210210+ object: T,
211211+ key: M
466212): Required<T>[M] extends { new (...args: infer A): infer R }
467213 ? Mock<{ new (...args: A): R }>
468214 : T[M] extends Procedure
469215 ? Mock<T[M]>
470216 : never
471471-export function spyOn<T, K extends keyof T>(
472472- obj: T,
473473- method: K,
474474- accessType?: 'get' | 'set',
217217+export function spyOn<T extends object, K extends keyof T>(
218218+ object: T,
219219+ key: K,
220220+ accessor?: 'get' | 'set',
475221): Mock {
476476- const dictionary = {
477477- get: 'getter',
478478- set: 'setter',
479479- } as const
480480- const objMethod = accessType ? { [dictionary[accessType]]: method } : method
222222+ assert(
223223+ object != null,
224224+ 'The vi.spyOn() function could not find an object to spy upon. The first argument must be defined.',
225225+ )
481226482482- let state: InternalState | undefined
227227+ assert(
228228+ typeof object === 'object' || typeof object === 'function',
229229+ 'Vitest cannot spy on a primitive value.',
230230+ )
483231484484- const descriptor = getDescriptor(obj, method)
485485- const fn = descriptor && descriptor[accessType || 'value']
232232+ const [originalDescriptorObject, originalDescriptor] = getDescriptor(object, key) || []
233233+ assert(
234234+ originalDescriptor || key in object,
235235+ `The property "${String(key)}" is not defined on the ${typeof object}.`,
236236+ )
237237+ let accessType: 'get' | 'set' | 'value' = accessor || 'value'
238238+ let ssr = false
486239487487- // inherit implementations if it was already mocked
488488- if (isMockFunction(fn)) {
489489- state = fn.mock._state()
240240+ // vite ssr support - actual function is stored inside a getter
241241+ if (
242242+ accessType === 'value'
243243+ && originalDescriptor
244244+ && originalDescriptor.value == null
245245+ && originalDescriptor.get
246246+ ) {
247247+ accessType = 'get'
248248+ ssr = true
490249 }
491250492492- try {
493493- const stub = tinyspy.internalSpyOn(obj, objMethod as any)
251251+ let original: Procedure | undefined
494252495495- const spy = enhanceSpy(stub) as Mock
253253+ if (originalDescriptor) {
254254+ original = originalDescriptor[accessType]
255255+ }
256256+ else if (accessType !== 'value') {
257257+ original = () => object[key]
258258+ }
259259+ else {
260260+ original = object[key] as unknown as Procedure
261261+ }
496262497497- if (state) {
498498- spy.mock._state(state)
263263+ if (isMockFunction(original)) {
264264+ return original
265265+ }
266266+267267+ const reassign = (cb: any) => {
268268+ const { value, ...desc } = originalDescriptor || {
269269+ configurable: true,
270270+ writable: true,
499271 }
272272+ if (accessType !== 'value') {
273273+ delete desc.writable // getter/setter can't have writable attribute at all
274274+ }
275275+ ;(desc as PropertyDescriptor)[accessType] = cb
276276+ Object.defineProperty(object, key, desc)
277277+ }
500278501501- return spy
279279+ const restore = () => {
280280+ // if method is defined on the prototype, we can just remove it from
281281+ // the current object instead of redefining a copy of it
282282+ if (originalDescriptorObject !== object) {
283283+ Reflect.deleteProperty(object, key)
284284+ }
285285+ else if (originalDescriptor && !original) {
286286+ Object.defineProperty(object, key, originalDescriptor)
287287+ }
288288+ else {
289289+ reassign(original)
290290+ }
291291+ }
292292+293293+ const mock = createMockInstance({
294294+ restore,
295295+ originalImplementation: ssr && original ? original() : original,
296296+ resetToMockName: true,
297297+ })
298298+299299+ try {
300300+ reassign(
301301+ ssr
302302+ ? () => mock
303303+ : mock,
304304+ )
502305 }
503306 catch (error) {
504307 if (
505308 error instanceof TypeError
506309 && Symbol.toStringTag
507507- && (obj as any)[Symbol.toStringTag] === 'Module'
310310+ && (object as any)[Symbol.toStringTag] === 'Module'
508311 && (error.message.includes('Cannot redefine property')
509312 || error.message.includes('Cannot replace module namespace')
510313 || error.message.includes('can\'t redefine non-configurable property'))
511314 ) {
512315 throw new TypeError(
513513- `Cannot spy on export "${String(objMethod)}". Module namespace is not configurable in ESM. See: https://vitest.dev/guide/browser/#limitations`,
316316+ `Cannot spy on export "${String(key)}". Module namespace is not configurable in ESM. See: https://vitest.dev/guide/browser/#limitations`,
514317 { cause: error },
515318 )
516319 }
517320518321 throw error
519322 }
323323+324324+ return mock
520325}
521326522522-let callOrder = 0
523523-524524-function enhanceSpy<T extends Procedure | Constructable>(
525525- spy: SpyInternalImpl<MockParameters<T>, MockReturnType<T>>,
526526-): MockInstance<T> {
527527- type TReturns = MockReturnType<T>
528528-529529- const stub = spy as unknown as MockInstance<T>
530530-531531- let implementation: NormalizedProcedure<T> | undefined
532532-533533- let onceImplementations: NormalizedProcedure<T>[] = []
534534- let implementationChangedTemporarily = false
535535-536536- let instances: any[] = []
537537- let contexts: any[] = []
538538- let invocations: number[] = []
539539-540540- const state = tinyspy.getInternalState(spy)
541541-542542- const mockContext: MockContext<T> = {
543543- get calls() {
544544- return state.calls as MockParameters<T>[]
545545- },
546546- get contexts() {
547547- return contexts
548548- },
549549- get instances() {
550550- return instances
551551- },
552552- get invocationCallOrder() {
553553- return invocations
554554- },
555555- get results() {
556556- return state.results.map(([callType, value]) => {
557557- const type
558558- = callType === 'error' ? ('throw' as const) : ('return' as const)
559559- return { type, value }
560560- })
561561- },
562562- get settledResults() {
563563- return state.resolves.map(([callType, value]) => {
564564- const type
565565- = callType === 'error' ? ('rejected' as const) : ('fulfilled' as const)
566566- return { type, value }
567567- })
568568- },
569569- get lastCall() {
570570- return state.calls[state.calls.length - 1] as MockParameters<T>
571571- },
572572- _state(state) {
573573- if (state) {
574574- implementation = state.implementation as NormalizedProcedure<T>
575575- onceImplementations = state.onceImplementations as NormalizedProcedure<T>[]
576576- implementationChangedTemporarily = state.implementationChangedTemporarily
577577- }
578578- return {
579579- implementation,
580580- onceImplementations,
581581- implementationChangedTemporarily,
582582- }
583583- },
584584- }
585585-586586- function mockCall(this: unknown, ...args: any) {
587587- if (!new.target) {
588588- instances.push(this)
589589- contexts.push(this)
590590- }
591591- invocations.push(++callOrder)
592592- const impl = implementationChangedTemporarily
593593- ? implementation!
594594- : onceImplementations.shift()
595595- || implementation
596596- || state.getOriginal()
597597- || function () {}
598598- if (new.target) {
599599- try {
600600- const result = Reflect.construct(impl, args, new.target)
601601- instances.push(result)
602602- contexts.push(result)
603603- return result
604604- }
605605- catch (error) {
606606- instances.push(undefined)
607607- contexts.push(undefined)
608608-609609- if (error instanceof TypeError && error.message.includes('is not a constructor')) {
610610- throw new TypeError(`The spy implementation did not use 'function' or 'class', see https://vitest.dev/api/vi#vi-spyon for examples.`, {
611611- cause: error,
612612- })
613613- }
614614-615615- throw error
616616- }
617617- }
618618- return (impl as Procedure).apply(this, args)
619619- }
620620-621621- let name: string = (stub as any).name
622622-623623- stub.getMockName = () => name || 'vi.fn()'
624624- stub.mockName = (n) => {
625625- name = n
626626- return stub
627627- }
628628-629629- stub.mockClear = () => {
630630- state.reset()
631631- instances = []
632632- contexts = []
633633- invocations = []
634634- return stub
635635- }
636636-637637- stub.mockReset = () => {
638638- stub.mockClear()
639639- implementation = undefined
640640- onceImplementations = []
641641- return stub
642642- }
643643-644644- stub.mockRestore = () => {
645645- stub.mockReset()
646646- state.restore()
647647- return stub
648648- }
649649-650650- if (Symbol.dispose) {
651651- stub[Symbol.dispose] = () => stub.mockRestore()
652652- }
653653-654654- stub.getMockImplementation = () =>
655655- implementationChangedTemporarily ? implementation : (onceImplementations.at(0) || implementation)
656656- stub.mockImplementation = (fn: NormalizedProcedure<T>) => {
657657- implementation = fn
658658- state.willCall(mockCall)
659659- return stub
660660- }
661661-662662- stub.mockImplementationOnce = (fn: NormalizedProcedure<T>) => {
663663- onceImplementations.push(fn)
664664- return stub
665665- }
666666-667667- function withImplementation(fn: NormalizedProcedure<T>, cb: () => void): MockInstance<T>
668668- function withImplementation(fn: NormalizedProcedure<T>, cb: () => Promise<void>): Promise<MockInstance<T>>
669669- function withImplementation(fn: NormalizedProcedure<T>, cb: () => void | Promise<void>): MockInstance<T> | Promise<MockInstance<T>> {
670670- const originalImplementation = implementation
671671-672672- implementation = fn
673673- state.willCall(mockCall)
674674- implementationChangedTemporarily = true
675675-676676- const reset = () => {
677677- implementation = originalImplementation
678678- implementationChangedTemporarily = false
679679- }
680680-681681- const result = cb()
682682-683683- if (typeof result === 'object' && result && typeof result.then === 'function') {
684684- return result.then(() => {
685685- reset()
686686- return stub
687687- })
688688- }
689689-690690- reset()
691691-692692- return stub
693693- }
694694-695695- stub.withImplementation = withImplementation
696696-697697- stub.mockReturnThis = () =>
698698- stub.mockImplementation(function (this: MockFnContext<T>) {
699699- return this
700700- } as NormalizedProcedure<T>)
701701-702702- stub.mockReturnValue = (val: TReturns) => stub.mockImplementation(function () {
703703- return val
704704- } as NormalizedProcedure<T>)
705705- stub.mockReturnValueOnce = (val: TReturns) => stub.mockImplementationOnce(function () {
706706- return val
707707- } as NormalizedProcedure<T>)
708708-709709- stub.mockResolvedValue = (val: Awaited<TReturns>) =>
710710- stub.mockImplementation(function () {
711711- return Promise.resolve(val)
712712- } as NormalizedProcedure<T>)
713713-714714- stub.mockResolvedValueOnce = (val: Awaited<TReturns>) =>
715715- stub.mockImplementationOnce(function () {
716716- return Promise.resolve(val)
717717- } as NormalizedProcedure<T>)
718718-719719- stub.mockRejectedValue = (val: unknown) =>
720720- stub.mockImplementation(function () {
721721- return Promise.reject(val)
722722- } as NormalizedProcedure<T>)
723723-724724- stub.mockRejectedValueOnce = (val: unknown) =>
725725- stub.mockImplementationOnce(function () {
726726- return Promise.reject(val)
727727- } as NormalizedProcedure<T>)
728728-729729- Object.defineProperty(stub, 'mock', {
730730- get: () => mockContext,
731731- })
732732-733733- state.willCall(mockCall)
734734-735735- mocks.add(stub)
736736-737737- return stub as any
738738-}
739739-740740-export function fn<T extends Procedure | Constructable = Procedure>(
741741- implementation?: T,
742742-): Mock<T> {
743743- const inernalSpy = tinyspy.internalSpyOn({
744744- spy: implementation || function spy() {} as T,
745745- }, 'spy')
746746- const enhancedSpy = enhanceSpy(inernalSpy)
747747- if (implementation) {
748748- enhancedSpy.mockImplementation(implementation)
749749- }
750750-751751- return enhancedSpy as any
752752-}
753753-754754-function getDescriptor(
755755- obj: any,
756756- method: string | symbol | number,
757757-): PropertyDescriptor | undefined {
327327+function getDescriptor(obj: any, method: string | symbol | number): [any, PropertyDescriptor] | undefined {
758328 const objDescriptor = Object.getOwnPropertyDescriptor(obj, method)
759329 if (objDescriptor) {
760760- return objDescriptor
330330+ return [obj, objDescriptor]
761331 }
762332 let currentProto = Object.getPrototypeOf(obj)
763333 while (currentProto !== null) {
764334 const descriptor = Object.getOwnPropertyDescriptor(currentProto, method)
765335 if (descriptor) {
766766- return descriptor
336336+ return [currentProto, descriptor]
767337 }
768338 currentProto = Object.getPrototypeOf(currentProto)
769339 }
770340}
341341+342342+function assert(condition: any, message: string): asserts condition {
343343+ if (!condition) {
344344+ throw new Error(message)
345345+ }
346346+}
347347+348348+let invocationCallCounter = 1
349349+350350+function createMock(
351351+ {
352352+ state,
353353+ config,
354354+ name: mockName,
355355+ prototypeState,
356356+ prototypeConfig,
357357+ keepMembersImplementation,
358358+ prototypeMembers = [],
359359+ }: MockInstanceOption & {
360360+ state: MockContext
361361+ config: MockConfig
362362+ },
363363+) {
364364+ const original = config.mockOriginal
365365+ const name = (mockName || original?.name || 'Mock') as string
366366+ const namedObject: Record<string, Mock<Procedure | Constructable>> = {
367367+ // to keep the name of the function intact
368368+ [name]: (function (this: any, ...args: any[]) {
369369+ registerCalls(args, state, prototypeState)
370370+ registerInvocationOrder(invocationCallCounter++, state, prototypeState)
371371+372372+ const result = {
373373+ type: 'incomplete',
374374+ value: undefined,
375375+ } as MockResult<Procedure>
376376+377377+ const settledResult = {
378378+ type: 'incomplete',
379379+ value: undefined,
380380+ } as MockSettledResult<Procedure>
381381+382382+ registerResult(result, state, prototypeState)
383383+ registerSettledResult(settledResult, state, prototypeState)
384384+385385+ const context = new.target ? undefined : this
386386+ const [instanceIndex, instancePrototypeIndex] = registerInstance(context, state, prototypeState)
387387+ const [contextIndex, contextPrototypeIndex] = registerContext(context, state, prototypeState)
388388+389389+ const implementation: Procedure | Constructable
390390+ = config.onceMockImplementations.shift()
391391+ || config.mockImplementation
392392+ || prototypeConfig?.onceMockImplementations.shift()
393393+ || prototypeConfig?.mockImplementation
394394+ || original
395395+ || function () {}
396396+397397+ let returnValue
398398+ let thrownValue
399399+ let didThrow = false
400400+401401+ try {
402402+ if (new.target) {
403403+ returnValue = Reflect.construct(implementation, args, new.target)
404404+405405+ // jest calls this before the implementation, but we have to resolve this _after_
406406+ // because we cannot do it before the `Reflect.construct` called the custom implementation.
407407+ // fortunetly, the constructor is always an empty functon because `prototypeMethods`
408408+ // are only used by the automocker, so this doesn't matter
409409+ for (const prop of prototypeMembers) {
410410+ const prototypeMock = returnValue[prop]
411411+ const isMock = isMockFunction(prototypeMock)
412412+ const prototypeState = isMock ? prototypeMock.mock : undefined
413413+ const prototypeConfig = isMock ? MOCK_CONFIGS.get(prototypeMock) : undefined
414414+ returnValue[prop] = createMockInstance({
415415+ originalImplementation: keepMembersImplementation
416416+ ? prototypeConfig?.mockOriginal
417417+ : undefined,
418418+ prototypeState,
419419+ prototypeConfig,
420420+ keepMembersImplementation,
421421+ })
422422+ }
423423+ }
424424+ else {
425425+ returnValue = (implementation as Procedure).apply(this, args)
426426+ }
427427+ }
428428+ catch (error: any) {
429429+ thrownValue = error
430430+ didThrow = true
431431+ if (error instanceof TypeError && error.message.includes('is not a constructor')) {
432432+ console.warn(`[vitest] The ${namedObject[name].getMockName()} mock did not use 'function' or 'class' in its implementation, see https://vitest.dev/api/vi#vi-spyon for examples.`)
433433+ }
434434+ throw error
435435+ }
436436+ finally {
437437+ if (didThrow) {
438438+ result.type = 'throw'
439439+ result.value = thrownValue
440440+441441+ settledResult.type = 'rejected'
442442+ settledResult.value = thrownValue
443443+ }
444444+ else {
445445+ result.type = 'return'
446446+ result.value = returnValue
447447+448448+ if (new.target) {
449449+ state.contexts[contextIndex - 1] = returnValue
450450+ state.instances[instanceIndex - 1] = returnValue
451451+452452+ if (contextPrototypeIndex != null && prototypeState) {
453453+ prototypeState.contexts[contextPrototypeIndex - 1] = returnValue
454454+ }
455455+ if (instancePrototypeIndex != null && prototypeState) {
456456+ prototypeState.instances[instancePrototypeIndex - 1] = returnValue
457457+ }
458458+ }
459459+460460+ if (returnValue instanceof Promise) {
461461+ returnValue.then(
462462+ (settledValue) => {
463463+ settledResult.type = 'fulfilled'
464464+ settledResult.value = settledValue
465465+ },
466466+ (rejectedValue) => {
467467+ settledResult.type = 'rejected'
468468+ settledResult.value = rejectedValue
469469+ },
470470+ )
471471+ }
472472+ else {
473473+ settledResult.type = 'fulfilled'
474474+ settledResult.value = returnValue
475475+ }
476476+ }
477477+ }
478478+479479+ return returnValue
480480+ }) as Mock,
481481+ }
482482+ if (original) {
483483+ copyOriginalStaticProperties(namedObject[name], original)
484484+ }
485485+ return namedObject[name]
486486+}
487487+488488+function registerCalls(args: unknown[], state: MockContext, prototypeState?: MockContext) {
489489+ state.calls.push(args)
490490+ prototypeState?.calls.push(args)
491491+}
492492+493493+function registerInvocationOrder(order: number, state: MockContext, prototypeState?: MockContext) {
494494+ state.invocationCallOrder.push(order)
495495+ prototypeState?.invocationCallOrder.push(order)
496496+}
497497+498498+function registerResult(result: MockResult<Procedure>, state: MockContext, prototypeState?: MockContext) {
499499+ state.results.push(result)
500500+ prototypeState?.results.push(result)
501501+}
502502+503503+function registerSettledResult(result: MockSettledResult<Procedure>, state: MockContext, prototypeState?: MockContext) {
504504+ state.settledResults.push(result)
505505+ prototypeState?.settledResults.push(result)
506506+}
507507+508508+function registerInstance(instance: MockReturnType<Procedure>, state: MockContext, prototypeState?: MockContext) {
509509+ const instanceIndex = state.instances.push(instance)
510510+ const instancePrototypeIndex = prototypeState?.instances.push(instance)
511511+ return [instanceIndex, instancePrototypeIndex] as const
512512+}
513513+514514+function registerContext(context: MockProcedureContext<Procedure>, state: MockContext, prototypeState?: MockContext) {
515515+ const contextIndex = state.contexts.push(context)
516516+ const contextPrototypeIndex = prototypeState?.contexts.push(context)
517517+ return [contextIndex, contextPrototypeIndex] as const
518518+}
519519+520520+function copyOriginalStaticProperties(mock: Mock, original: Procedure | Constructable) {
521521+ const { properties, descriptors } = getAllProperties(original)
522522+523523+ for (const key of properties) {
524524+ const descriptor = descriptors[key]!
525525+ const mockDescriptor = getDescriptor(mock, key)
526526+ if (mockDescriptor) {
527527+ continue
528528+ }
529529+530530+ Object.defineProperty(mock, key, descriptor)
531531+ }
532532+}
533533+534534+const ignoreProperties = new Set<string | symbol>([
535535+ 'length',
536536+ 'name',
537537+ 'prototype',
538538+ Symbol.for('nodejs.util.promisify.custom'),
539539+])
540540+541541+function getAllProperties(original: Procedure | Constructable) {
542542+ const properties = new Set<string | symbol>()
543543+ const descriptors: Record<string | symbol, PropertyDescriptor | undefined>
544544+ = {}
545545+ while (
546546+ original
547547+ && original !== Object.prototype
548548+ && original !== Function.prototype
549549+ ) {
550550+ const ownProperties = [
551551+ ...Object.getOwnPropertyNames(original),
552552+ ...Object.getOwnPropertySymbols(original),
553553+ ]
554554+ for (const prop of ownProperties) {
555555+ if (descriptors[prop] || ignoreProperties.has(prop)) {
556556+ continue
557557+ }
558558+ properties.add(prop)
559559+ descriptors[prop] = Object.getOwnPropertyDescriptor(original, prop)
560560+ }
561561+ original = Object.getPrototypeOf(original)
562562+ }
563563+ return {
564564+ properties,
565565+ descriptors,
566566+ }
567567+}
568568+569569+function getDefaultConfig(original?: Procedure | Constructable): MockConfig {
570570+ return {
571571+ mockImplementation: undefined,
572572+ mockOriginal: original,
573573+ mockName: 'vi.fn()',
574574+ onceMockImplementations: [],
575575+ }
576576+}
577577+578578+function getDefaultState(): MockContext {
579579+ const state = {
580580+ calls: [],
581581+ contexts: [],
582582+ instances: [],
583583+ invocationCallOrder: [],
584584+ settledResults: [],
585585+ results: [],
586586+ get lastCall() {
587587+ return state.calls.at(-1)
588588+ },
589589+ }
590590+ return state
591591+}
592592+593593+export function restoreAllMocks(): void {
594594+ for (const restore of MOCK_RESTORE) {
595595+ restore()
596596+ }
597597+ MOCK_RESTORE.clear()
598598+}
599599+600600+export function clearAllMocks(): void {
601601+ REGISTERED_MOCKS.forEach(mock => mock.mockClear())
602602+}
603603+604604+export function resetAllMocks(): void {
605605+ REGISTERED_MOCKS.forEach(mock => mock.mockReset())
606606+}
607607+608608+export type {
609609+ MaybeMocked,
610610+ MaybeMockedConstructor,
611611+ MaybeMockedDeep,
612612+ MaybePartiallyMocked,
613613+ MaybePartiallyMockedDeep,
614614+ Mock,
615615+ MockContext,
616616+ Mocked,
617617+ MockedClass,
618618+ MockedFunction,
619619+ MockedFunctionDeep,
620620+ MockedObject,
621621+ MockedObjectDeep,
622622+ MockInstance,
623623+ MockInstanceOption,
624624+ MockParameters,
625625+ MockProcedureContext,
626626+ MockResult,
627627+ MockResultIncomplete,
628628+ MockResultReturn,
629629+ MockResultThrow,
630630+ MockReturnType,
631631+ MockSettledResult,
632632+ MockSettledResultFulfilled,
633633+ MockSettledResultIncomplete,
634634+ MockSettledResultRejected,
635635+ PartiallyMockedFunction,
636636+ PartiallyMockedFunctionDeep,
637637+ PartialMock,
638638+} from './types'
+463
packages/spy/src/types.ts
···11+export interface MockResultReturn<T> {
22+ type: 'return'
33+ /**
44+ * The value that was returned from the function. If function returned a Promise, then this will be a resolved value.
55+ */
66+ value: T
77+}
88+export interface MockResultIncomplete {
99+ type: 'incomplete'
1010+ value: undefined
1111+}
1212+export interface MockResultThrow {
1313+ type: 'throw'
1414+ /**
1515+ * An error that was thrown during function execution.
1616+ */
1717+ value: any
1818+}
1919+2020+export interface MockSettledResultIncomplete {
2121+ type: 'incomplete'
2222+ value: undefined
2323+}
2424+2525+export interface MockSettledResultFulfilled<T> {
2626+ type: 'fulfilled'
2727+ value: T
2828+}
2929+3030+export interface MockSettledResultRejected {
3131+ type: 'rejected'
3232+ value: any
3333+}
3434+3535+export type MockResult<T>
3636+ = | MockResultReturn<T>
3737+ | MockResultThrow
3838+ | MockResultIncomplete
3939+export type MockSettledResult<T>
4040+ = | MockSettledResultFulfilled<T>
4141+ | MockSettledResultRejected
4242+ | MockSettledResultIncomplete
4343+4444+export type MockParameters<T extends Procedure | Constructable> = T extends Constructable
4545+ ? ConstructorParameters<T>
4646+ : T extends Procedure
4747+ ? Parameters<T> : never
4848+4949+export type MockReturnType<T extends Procedure | Constructable> = T extends Constructable
5050+ ? void
5151+ : T extends Procedure
5252+ ? ReturnType<T> : never
5353+5454+export type MockProcedureContext<T extends Procedure | Constructable> = T extends Constructable
5555+ ? InstanceType<T>
5656+ : ThisParameterType<T>
5757+5858+export interface MockContext<T extends Procedure | Constructable = Procedure> {
5959+ /**
6060+ * This is an array containing all arguments for each call. One item of the array is the arguments of that call.
6161+ *
6262+ * @see https://vitest.dev/api/mock#mock-calls
6363+ * @example
6464+ * const fn = vi.fn()
6565+ *
6666+ * fn('arg1', 'arg2')
6767+ * fn('arg3')
6868+ *
6969+ * fn.mock.calls === [
7070+ * ['arg1', 'arg2'], // first call
7171+ * ['arg3'], // second call
7272+ * ]
7373+ */
7474+ calls: MockParameters<T>[]
7575+ /**
7676+ * This is an array containing all instances that were instantiated when mock was called with a `new` keyword. Note that this is an actual context (`this`) of the function, not a return value.
7777+ * @see https://vitest.dev/api/mock#mock-instances
7878+ */
7979+ instances: MockReturnType<T>[]
8080+ /**
8181+ * An array of `this` values that were used during each call to the mock function.
8282+ * @see https://vitest.dev/api/mock#mock-contexts
8383+ */
8484+ contexts: MockProcedureContext<T>[]
8585+ /**
8686+ * The order of mock's execution. This returns an array of numbers which are shared between all defined mocks.
8787+ *
8888+ * @see https://vitest.dev/api/mock#mock-invocationcallorder
8989+ * @example
9090+ * const fn1 = vi.fn()
9191+ * const fn2 = vi.fn()
9292+ *
9393+ * fn1()
9494+ * fn2()
9595+ * fn1()
9696+ *
9797+ * fn1.mock.invocationCallOrder === [1, 3]
9898+ * fn2.mock.invocationCallOrder === [2]
9999+ */
100100+ invocationCallOrder: number[]
101101+ /**
102102+ * This is an array containing all values that were `returned` from the function.
103103+ *
104104+ * The `value` property contains the returned value or thrown error. If the function returned a `Promise`, then `result` will always be `'return'` even if the promise was rejected.
105105+ *
106106+ * @see https://vitest.dev/api/mock#mock-results
107107+ * @example
108108+ * const fn = vi.fn()
109109+ * .mockReturnValueOnce('result')
110110+ * .mockImplementationOnce(() => { throw new Error('thrown error') })
111111+ *
112112+ * const result = fn()
113113+ *
114114+ * try {
115115+ * fn()
116116+ * }
117117+ * catch {}
118118+ *
119119+ * fn.mock.results === [
120120+ * {
121121+ * type: 'return',
122122+ * value: 'result',
123123+ * },
124124+ * {
125125+ * type: 'throw',
126126+ * value: Error,
127127+ * },
128128+ * ]
129129+ */
130130+ results: MockResult<MockReturnType<T>>[]
131131+ /**
132132+ * An array containing all values that were `resolved` or `rejected` from the function.
133133+ *
134134+ * This array will be empty if the function was never resolved or rejected.
135135+ *
136136+ * @see https://vitest.dev/api/mock#mock-settledresults
137137+ * @example
138138+ * const fn = vi.fn().mockResolvedValueOnce('result')
139139+ *
140140+ * const result = fn()
141141+ *
142142+ * fn.mock.settledResults === [
143143+ * {
144144+ * type: 'incomplete',
145145+ * value: undefined,
146146+ * }
147147+ * ]
148148+ * fn.mock.results === [
149149+ * {
150150+ * type: 'return',
151151+ * value: Promise<'result'>,
152152+ * },
153153+ * ]
154154+ *
155155+ * await result
156156+ *
157157+ * fn.mock.settledResults === [
158158+ * {
159159+ * type: 'fulfilled',
160160+ * value: 'result',
161161+ * },
162162+ * ]
163163+ */
164164+ settledResults: MockSettledResult<Awaited<MockReturnType<T>>>[]
165165+ /**
166166+ * This contains the arguments of the last call. If spy wasn't called, will return `undefined`.
167167+ * @see https://vitest.dev/api/mock#mock-lastcall
168168+ */
169169+ lastCall: MockParameters<T> | undefined
170170+}
171171+172172+export type Procedure = (...args: any[]) => any
173173+// pick a single function type from function overloads, unions, etc...
174174+export type NormalizedProcedure<T extends Procedure | Constructable> = T extends Constructable
175175+ ? ({
176176+ new (...args: ConstructorParameters<T>): InstanceType<T>
177177+ })
178178+ | ({
179179+ (this: InstanceType<T>, ...args: ConstructorParameters<T>): void
180180+ })
181181+ : T extends Procedure
182182+ ? (...args: Parameters<T>) => ReturnType<T>
183183+ : never
184184+185185+export type Methods<T> = keyof {
186186+ [K in keyof T as T[K] extends Procedure ? K : never]: T[K];
187187+}
188188+export type Properties<T> = {
189189+ [K in keyof T]: T[K] extends Procedure ? never : K;
190190+}[keyof T]
191191+& (string | symbol)
192192+export type Classes<T> = {
193193+ [K in keyof T]: T[K] extends new (...args: any[]) => any ? K : never;
194194+}[keyof T]
195195+& (string | symbol)
196196+197197+/*
198198+cf. https://typescript-eslint.io/rules/method-signature-style/
199199+200200+Typescript assignability is different between
201201+ { foo: (f: T) => U } (this is "method-signature-style")
202202+and
203203+ { foo(f: T): U }
204204+205205+Jest uses the latter for `MockInstance.mockImplementation` etc... and it allows assignment such as:
206206+ const boolFn: Jest.Mock<() => boolean> = jest.fn<() => true>(() => true)
207207+*/
208208+/* eslint-disable ts/method-signature-style */
209209+export interface MockInstance<T extends Procedure | Constructable = Procedure> extends Disposable {
210210+ /**
211211+ * Use it to return the name assigned to the mock with the `.mockName(name)` method. By default, it will return `vi.fn()`.
212212+ * @see https://vitest.dev/api/mock#getmockname
213213+ */
214214+ getMockName(): string
215215+ /**
216216+ * Sets the internal mock name. This is useful for identifying the mock when an assertion fails.
217217+ * @see https://vitest.dev/api/mock#mockname
218218+ */
219219+ mockName(name: string): this
220220+ /**
221221+ * Current context of the mock. It stores information about all invocation calls, instances, and results.
222222+ */
223223+ mock: MockContext<T>
224224+ /**
225225+ * Clears all information about every call. After calling it, all properties on `.mock` will return to their initial state. This method does not reset implementations. It is useful for cleaning up mocks between different assertions.
226226+ *
227227+ * To automatically call this method before each test, enable the [`clearMocks`](https://vitest.dev/config/#clearmocks) setting in the configuration.
228228+ * @see https://vitest.dev/api/mock#mockclear
229229+ */
230230+ mockClear(): this
231231+ /**
232232+ * Does what `mockClear` does and resets inner implementation to the original function. This also resets all "once" implementations.
233233+ *
234234+ * Note that resetting a mock from `vi.fn()` will set implementation to an empty function that returns `undefined`.
235235+ * Resetting a mock from `vi.fn(impl)` will set implementation to `impl`. It is useful for completely resetting a mock to its default state.
236236+ *
237237+ * To automatically call this method before each test, enable the [`mockReset`](https://vitest.dev/config/#mockreset) setting in the configuration.
238238+ * @see https://vitest.dev/api/mock#mockreset
239239+ */
240240+ mockReset(): this
241241+ /**
242242+ * Does what `mockReset` does and restores original descriptors of spied-on objects.
243243+ * @see https://vitest.dev/api/mock#mockrestore
244244+ */
245245+ mockRestore(): void
246246+ /**
247247+ * Returns current permanent mock implementation if there is one.
248248+ *
249249+ * If mock was created with `vi.fn`, it will consider passed down method as a mock implementation.
250250+ *
251251+ * If mock was created with `vi.spyOn`, it will return `undefined` unless a custom implementation was provided.
252252+ */
253253+ getMockImplementation(): NormalizedProcedure<T> | undefined
254254+ /**
255255+ * Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function.
256256+ * @see https://vitest.dev/api/mock#mockimplementation
257257+ * @example
258258+ * const increment = vi.fn().mockImplementation(count => count + 1);
259259+ * expect(increment(3)).toBe(4);
260260+ */
261261+ mockImplementation(fn: NormalizedProcedure<T>): this
262262+ /**
263263+ * Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function. This method can be chained to produce different results for multiple function calls.
264264+ *
265265+ * When the mocked function runs out of implementations, it will invoke the default implementation set with `vi.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called.
266266+ * @see https://vitest.dev/api/mock#mockimplementationonce
267267+ * @example
268268+ * const fn = vi.fn(count => count).mockImplementationOnce(count => count + 1);
269269+ * expect(fn(3)).toBe(4);
270270+ * expect(fn(3)).toBe(3);
271271+ */
272272+ mockImplementationOnce(fn: NormalizedProcedure<T>): this
273273+ /**
274274+ * Overrides the original mock implementation temporarily while the callback is being executed.
275275+ *
276276+ * Note that this method takes precedence over the [`mockImplementationOnce`](https://vitest.dev/api/mock#mockimplementationonce).
277277+ * @see https://vitest.dev/api/mock#withimplementation
278278+ * @example
279279+ * const myMockFn = vi.fn(() => 'original')
280280+ *
281281+ * myMockFn.withImplementation(() => 'temp', () => {
282282+ * myMockFn() // 'temp'
283283+ * })
284284+ *
285285+ * myMockFn() // 'original'
286286+ */
287287+ withImplementation<T2>(fn: NormalizedProcedure<T>, cb: () => T2): T2 extends Promise<unknown> ? Promise<this> : this
288288+289289+ /**
290290+ * Use this if you need to return the `this` context from the method without invoking the actual implementation.
291291+ * @see https://vitest.dev/api/mock#mockreturnthis
292292+ */
293293+ mockReturnThis(): this
294294+ /**
295295+ * Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
296296+ * @see https://vitest.dev/api/mock#mockreturnvalue
297297+ * @example
298298+ * const mock = vi.fn()
299299+ * mock.mockReturnValue(42)
300300+ * mock() // 42
301301+ * mock.mockReturnValue(43)
302302+ * mock() // 43
303303+ */
304304+ mockReturnValue(value: MockReturnType<T>): this
305305+ /**
306306+ * Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
307307+ *
308308+ * When the mocked function runs out of implementations, it will invoke the default implementation set with `vi.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called.
309309+ * @example
310310+ * const myMockFn = vi
311311+ * .fn()
312312+ * .mockReturnValue('default')
313313+ * .mockReturnValueOnce('first call')
314314+ * .mockReturnValueOnce('second call')
315315+ *
316316+ * // 'first call', 'second call', 'default'
317317+ * console.log(myMockFn(), myMockFn(), myMockFn())
318318+ */
319319+ mockReturnValueOnce(value: MockReturnType<T>): this
320320+ /**
321321+ * Accepts a value that will be resolved when the async function is called. TypeScript will only accept values that match the return type of the original function.
322322+ * @example
323323+ * const asyncMock = vi.fn().mockResolvedValue(42)
324324+ * asyncMock() // Promise<42>
325325+ */
326326+ mockResolvedValue(value: Awaited<MockReturnType<T>>): this
327327+ /**
328328+ * Accepts a value that will be resolved during the next function call. TypeScript will only accept values that match the return type of the original function. If chained, each consecutive call will resolve the specified value.
329329+ * @example
330330+ * const myMockFn = vi
331331+ * .fn()
332332+ * .mockResolvedValue('default')
333333+ * .mockResolvedValueOnce('first call')
334334+ * .mockResolvedValueOnce('second call')
335335+ *
336336+ * // Promise<'first call'>, Promise<'second call'>, Promise<'default'>
337337+ * console.log(myMockFn(), myMockFn(), myMockFn())
338338+ */
339339+ mockResolvedValueOnce(value: Awaited<MockReturnType<T>>): this
340340+ /**
341341+ * Accepts an error that will be rejected when async function is called.
342342+ * @example
343343+ * const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'))
344344+ * await asyncMock() // throws Error<'Async error'>
345345+ */
346346+ mockRejectedValue(error: unknown): this
347347+ /**
348348+ * Accepts a value that will be rejected during the next function call. If chained, each consecutive call will reject the specified value.
349349+ * @example
350350+ * const asyncMock = vi
351351+ * .fn()
352352+ * .mockResolvedValueOnce('first call')
353353+ * .mockRejectedValueOnce(new Error('Async error'))
354354+ *
355355+ * await asyncMock() // first call
356356+ * await asyncMock() // throws Error<'Async error'>
357357+ */
358358+ mockRejectedValueOnce(error: unknown): this
359359+}
360360+/* eslint-enable ts/method-signature-style */
361361+362362+export interface Mock<T extends Procedure | Constructable = Procedure> extends MockInstance<T> {
363363+ new (...args: MockParameters<T>): T extends Constructable ? InstanceType<T> : MockReturnType<T>
364364+ (...args: MockParameters<T>): MockReturnType<T>
365365+ /** @internal */
366366+ _isMockFunction: true
367367+}
368368+369369+type PartialMaybePromise<T> = T extends Promise<Awaited<T>>
370370+ ? Promise<Partial<Awaited<T>>>
371371+ : Partial<T>
372372+373373+export interface PartialMock<T extends Procedure = Procedure>
374374+ extends MockInstance<
375375+ (...args: Parameters<T>) => PartialMaybePromise<ReturnType<T>>
376376+ > {
377377+ new (...args: Parameters<T>): ReturnType<T>
378378+ (...args: Parameters<T>): ReturnType<T>
379379+}
380380+381381+export type MaybeMockedConstructor<T> = T extends new (
382382+ ...args: Array<any>
383383+) => infer R
384384+ ? Mock<(...args: ConstructorParameters<T>) => R>
385385+ : T
386386+export type MockedFunction<T extends Procedure> = Mock<T> & {
387387+ [K in keyof T]: T[K];
388388+}
389389+export type PartiallyMockedFunction<T extends Procedure> = PartialMock<T> & {
390390+ [K in keyof T]: T[K];
391391+}
392392+export type MockedFunctionDeep<T extends Procedure> = Mock<T>
393393+ & MockedObjectDeep<T>
394394+export type PartiallyMockedFunctionDeep<T extends Procedure> = PartialMock<T>
395395+ & MockedObjectDeep<T>
396396+export type MockedObject<T> = MaybeMockedConstructor<T> & {
397397+ [K in Methods<T>]: T[K] extends Procedure ? MockedFunction<T[K]> : T[K];
398398+} & { [K in Properties<T>]: T[K] }
399399+export type MockedObjectDeep<T> = MaybeMockedConstructor<T> & {
400400+ [K in Methods<T>]: T[K] extends Procedure ? MockedFunctionDeep<T[K]> : T[K];
401401+} & { [K in Properties<T>]: MaybeMockedDeep<T[K]> }
402402+403403+export type MaybeMockedDeep<T> = T extends Procedure
404404+ ? MockedFunctionDeep<T>
405405+ : T extends object
406406+ ? MockedObjectDeep<T>
407407+ : T
408408+409409+export type MaybePartiallyMockedDeep<T> = T extends Procedure
410410+ ? PartiallyMockedFunctionDeep<T>
411411+ : T extends object
412412+ ? MockedObjectDeep<T>
413413+ : T
414414+415415+export type MaybeMocked<T> = T extends Procedure
416416+ ? MockedFunction<T>
417417+ : T extends object
418418+ ? MockedObject<T>
419419+ : T
420420+421421+export type MaybePartiallyMocked<T> = T extends Procedure
422422+ ? PartiallyMockedFunction<T>
423423+ : T extends object
424424+ ? MockedObject<T>
425425+ : T
426426+427427+export interface Constructable {
428428+ new (...args: any[]): any
429429+}
430430+431431+export type MockedClass<T extends Constructable> = MockInstance<
432432+ (...args: ConstructorParameters<T>) => InstanceType<T>
433433+> & {
434434+ prototype: T extends { prototype: any } ? Mocked<T['prototype']> : never
435435+} & T
436436+437437+export type Mocked<T> = {
438438+ [P in keyof T]: T[P] extends Procedure
439439+ ? MockInstance<T[P]>
440440+ : T[P] extends Constructable
441441+ ? MockedClass<T[P]>
442442+ : T[P];
443443+} & T
444444+445445+export interface MockConfig {
446446+ mockImplementation: Procedure | Constructable | undefined
447447+ mockOriginal: Procedure | Constructable | undefined
448448+ mockName: string
449449+ onceMockImplementations: Array<Procedure | Constructable>
450450+}
451451+452452+export interface MockInstanceOption {
453453+ originalImplementation?: Procedure | Constructable
454454+ mockImplementation?: Procedure | Constructable
455455+ resetToMockImplementation?: boolean
456456+ restore?: () => void
457457+ prototypeMembers?: (string | symbol)[]
458458+ keepMembersImplementation?: boolean
459459+ prototypeState?: MockContext
460460+ prototypeConfig?: MockConfig
461461+ resetToMockName?: boolean
462462+ name?: string | symbol
463463+}
···22import { expect, test } from 'vitest'
3344test('has access to child_process API', ({ task, skip }) => {
55- skip(task.file.pool !== 'child_process', 'Run only in child_process pool')
55+ skip(task.file.pool !== 'forks', 'Run only in child_process pool')
66 expect(process.send).toBeDefined()
77})
8899test('doesn\'t have access to threads API', ({ task, skip }) => {
1010- skip(task.file.pool !== 'child_process', 'Run only in child_process pool')
1010+ skip(task.file.pool !== 'forks', 'Run only in child_process pool')
1111 expect(isMainThread).toBe(true)
1212 expect(threadId).toBe(0)
1313})
+17-17
test/core/test/jest-expect.test.ts
···714714describe('toHaveBeenCalled', () => {
715715 describe('negated', () => {
716716 it('fails if called', () => {
717717- const mock = vi.fn()
717717+ const mock = vi.fn().mockName('spy')
718718 mock()
719719720720 expect(() => {
···753753describe('toHaveBeenCalledWith', () => {
754754 describe('negated', () => {
755755 it('fails if called', () => {
756756- const mock = vi.fn()
756756+ const mock = vi.fn().mockName('spy')
757757 mock(3)
758758759759 expect(() => {
···766766describe('toHaveBeenCalledExactlyOnceWith', () => {
767767 describe('negated', () => {
768768 it('fails if called', () => {
769769- const mock = vi.fn()
769769+ const mock = vi.fn().mockName('spy')
770770 mock(3)
771771772772 expect(() => {
···796796 })
797797798798 it('fails if not called or called too many times', () => {
799799- const mock = vi.fn()
799799+ const mock = vi.fn().mockName('spy')
800800801801 expect(() => {
802802 expect(mock).toHaveBeenCalledExactlyOnceWith(3)
···816816817817 expect(() => {
818818 expect(mock).toHaveBeenCalledExactlyOnceWith(3)
819819- }).toThrow(/^expected "spy" to be called once with arguments: \[ 3 \][^e]/)
819819+ }).toThrow(/^expected "vi\.fn\(\)" to be called once with arguments: \[ 3 \][^e]/)
820820 })
821821822822 it('passes if called exactly once with args', () => {
···829829830830describe('toHaveBeenCalledBefore', () => {
831831 it('success if expect mock is called before result mock', () => {
832832- const expectMock = vi.fn()
833833- const resultMock = vi.fn()
832832+ const expectMock = vi.fn().mockName('expectMock')
833833+ const resultMock = vi.fn().mockName('resultMock')
834834835835 expectMock()
836836 resultMock()
···859859860860 expect(() => {
861861 expect(expectMock).toHaveBeenCalledBefore(resultMock)
862862- }).toThrow(/^expected "spy" to have been called before "spy"/)
862862+ }).toThrow(/^expected "vi\.fn\(\)" to have been called before "vi\.fn\(\)"/)
863863 })
864864865865 it('throws with correct mock name if failed', () => {
···875875 })
876876877877 it('fails if expect mock is not called', () => {
878878- const resultMock = vi.fn()
878878+ const resultMock = vi.fn().mockName('resultMock')
879879880880 resultMock()
881881882882 expect(() => {
883883 expect(vi.fn()).toHaveBeenCalledBefore(resultMock)
884884- }).toThrow(/^expected "spy" to have been called before "spy"/)
884884+ }).toThrow(/^expected "vi\.fn\(\)" to have been called before "resultMock"/)
885885 })
886886887887 it('not fails if expect mock is not called with option `failIfNoFirstInvocation` set to false', () => {
···893893 })
894894895895 it('fails if result mock is not called', () => {
896896- const expectMock = vi.fn()
896896+ const expectMock = vi.fn().mockName('expectMock')
897897898898 expectMock()
899899900900 expect(() => {
901901 expect(expectMock).toHaveBeenCalledBefore(vi.fn())
902902- }).toThrow(/^expected "spy" to have been called before "spy"/)
902902+ }).toThrow(/^expected "expectMock" to have been called before "vi\.fn\(\)"/)
903903 })
904904})
905905···935935936936 expect(() => {
937937 expect(expectMock).toHaveBeenCalledAfter(resultMock)
938938- }).toThrow(/^expected "spy" to have been called after "spy"/)
938938+ }).toThrow(/^expected "vi\.fn\(\)" to have been called after "vi\.fn\(\)"/)
939939 })
940940941941 it('throws with correct mock name if failed', () => {
···951951 })
952952953953 it('fails if result mock is not called', () => {
954954- const expectMock = vi.fn()
954954+ const expectMock = vi.fn().mockName('expectMock')
955955956956 expectMock()
957957958958 expect(() => {
959959 expect(expectMock).toHaveBeenCalledAfter(vi.fn())
960960- }).toThrow(/^expected "spy" to have been called after "spy"/)
960960+ }).toThrow(/^expected "expectMock" to have been called after "vi\.fn\(\)"/)
961961 })
962962963963 it('not fails if result mock is not called with option `failIfNoFirstInvocation` set to false', () => {
···969969 })
970970971971 it('fails if expect mock is not called', () => {
972972- const resultMock = vi.fn()
972972+ const resultMock = vi.fn().mockName('resultMock')
973973974974 resultMock()
975975976976 expect(() => {
977977 expect(vi.fn()).toHaveBeenCalledAfter(resultMock)
978978- }).toThrow(/^expected "spy" to have been called after "spy"/)
978978+ }).toThrow(/^expected "vi\.fn\(\)" to have been called after "resultMock"/)
979979 })
980980})
981981
+5-52
test/core/test/jest-mock.test.ts
···11import { describe, expect, expectTypeOf, it, vi } from 'vitest'
22-import { rolldownVersion } from 'vitest/node'
3243describe('jest mock compat layer', () => {
54 const returnFactory = (type: string) => (value: any) => ({ type, value })
···8685 expectTypeOf(spy.mock.contexts[0]).toEqualTypeOf<SpyClass>()
8786 expect(spy.mock.instances).toEqual([instance])
8887 expect(spy.mock.contexts).toEqual([instance])
8989- })
9090-9191- it('throws an error when constructing a class with an arrow function', () => {
9292- function getTypeError() {
9393- // esbuild transforms it into () => {\n}, but rolldown keeps it
9494- return new TypeError(rolldownVersion
9595- ? '() => {} is not a constructor'
9696- : `() => {
9797- } is not a constructor`)
9898- }
9999-100100- const arrow = () => {}
101101- const Fn = vi.fn(arrow)
102102- expect(() => new Fn()).toThrow(new TypeError(
103103- `The spy implementation did not use 'function' or 'class', see https://vitest.dev/api/vi#vi-spyon for examples.`,
104104- {
105105- cause: getTypeError(),
106106- },
107107- ))
108108-109109- const obj = {
110110- Spy: arrow,
111111- }
112112-113113- vi.spyOn(obj, 'Spy')
114114-115115- expect(
116116- // @ts-expect-error typescript knows you can't do that
117117- () => new obj.Spy(),
118118- ).toThrow(new TypeError(
119119- `The spy implementation did not use 'function' or 'class', see https://vitest.dev/api/vi#vi-spyon for examples.`,
120120- {
121121- cause: getTypeError(),
122122- },
123123- ))
124124-125125- const properClass = {
126126- Spy: class {},
127127- }
128128-129129- vi.spyOn(properClass, 'Spy').mockImplementation(() => {})
130130-131131- expect(() => new properClass.Spy()).toThrow(new TypeError(
132132- `The spy implementation did not use 'function' or 'class', see https://vitest.dev/api/vi#vi-spyon for examples.`,
133133- {
134134- cause: getTypeError(),
135135- },
136136- ))
13788 })
1388913990 it('implementation is set correctly on init', () => {
···224175225176 spy.mockRestore()
226177227227- expect(spy.getMockImplementation()).toBe(undefined)
178178+ // Sicne Vitest 4 this is a special case where
179179+ // vi.fn(impl) will always return impl, unless overriden
180180+ expect(spy.getMockImplementation()).toBe(originalFn)
228181229182 expect(spy.mock.results).toEqual([])
230183 })
···422375 expect(obj.method).toHaveBeenCalledTimes(1)
423376 vi.spyOn(obj, 'method')
424377 obj.method()
425425- expect(obj.method).toHaveBeenCalledTimes(1)
378378+ expect(obj.method).toHaveBeenCalledTimes(2)
426379 })
427380428381 it('spyOn on the getter multiple times', () => {
···450403451404 expect(vi.isMockFunction(obj.method)).toBe(true)
452405 expect(obj.method()).toBe('mocked')
453453- expect(spy1).not.toBe(spy2)
406406+ expect(spy1).toBe(spy2)
454407455408 spy2.mockImplementation(() => 'mocked2')
456409
···813813 "expected": "Array [
814814 "hey",
815815]",
816816- "message": "expected 2nd "spy" call to have been called with [ 'hey' ]",
816816+ "message": "expected 2nd "vi.fn()" call to have been called with [ 'hey' ]",
817817}
818818`;
819819···824824 "expected": "Array [
825825 "hey",
826826]",
827827- "message": "expected 3rd "spy" call to have been called with [ 'hey' ], but called only 2 times",
827827+ "message": "expected 3rd "vi.fn()" call to have been called with [ 'hey' ], but called only 2 times",
828828}
829829`;
830830
+11-11
test/core/test/__snapshots__/mocked.test.ts.snap
···11// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2233exports[`mocked function which fails on toReturnWith > just one call 1`] = `
44-"expected "spy" to return with: 2 at least once
44+"expected "vi.fn()" to return with: 2 at least once
5566Received:
7788- 1st spy call return:
88+ 1st vi.fn() call return:
991010- 2
1111+ 1
···1616`;
17171818exports[`mocked function which fails on toReturnWith > multi calls 1`] = `
1919-"expected "spy" to return with: 2 at least once
1919+"expected "vi.fn()" to return with: 2 at least once
20202121Received:
22222323- 1st spy call return:
2323+ 1st vi.fn() call return:
24242525- 2
2626+ 1
27272828- 2nd spy call return:
2828+ 2nd vi.fn() call return:
29293030- 2
3131+ 1
32323333- 3rd spy call return:
3333+ 3rd vi.fn() call return:
34343535- 2
3636+ 1
···4141`;
42424343exports[`mocked function which fails on toReturnWith > oject type 1`] = `
4444-"expected "spy" to return with: { a: '4' } at least once
4444+"expected "vi.fn()" to return with: { a: '4' } at least once
45454646Received:
47474848- 1st spy call return:
4848+ 1st vi.fn() call return:
49495050 {
5151- "a": "4",
5252+ "a": "1",
5353 }
54545555- 2nd spy call return:
5555+ 2nd vi.fn() call return:
56565757 {
5858- "a": "4",
5959+ "a": "1",
6060 }
61616262- 3rd spy call return:
6262+ 3rd vi.fn() call return:
63636464 {
6565- "a": "4",
···7272`;
73737474exports[`mocked function which fails on toReturnWith > zero call 1`] = `
7575-"expected "spy" to return with: 2 at least once
7575+"expected "vi.fn()" to return with: 2 at least once
76767777Number of calls: 0
7878"