diff --git a/packages/spy/src/index.ts b/packages/spy/src/index.ts index 6ce989bf6b7c..f8e52892c66b 100644 --- a/packages/spy/src/index.ts +++ b/packages/spy/src/index.ts @@ -141,6 +141,8 @@ export interface MockContext { } type Procedure = (...args: any[]) => any +// pick a single function type from function overloads, unions, etc... +type NormalizedPrecedure = (...args: Parameters) => ReturnType type Methods = keyof { [K in keyof T as T[K] extends Procedure ? K : never]: T[K]; @@ -204,14 +206,14 @@ export interface MockInstance { * * If mock was created with `vi.spyOn`, it will return `undefined` unless a custom implementation was provided. */ - getMockImplementation(): T | undefined + getMockImplementation(): NormalizedPrecedure | undefined /** * Accepts a function that will be used as an implementation of the mock. * @example * const increment = vi.fn().mockImplementation(count => count + 1); * expect(increment(3)).toBe(4); */ - mockImplementation(fn: T): this + mockImplementation(fn: NormalizedPrecedure): this /** * Accepts a function that will be used as a mock implementation during the next call. Can be chained so that multiple function calls produce different results. * @example @@ -219,7 +221,7 @@ export interface MockInstance { * expect(fn(3)).toBe(4); * expect(fn(3)).toBe(3); */ - mockImplementationOnce(fn: T): this + mockImplementationOnce(fn: NormalizedPrecedure): this /** * Overrides the original mock implementation temporarily while the callback is being executed. * @example @@ -231,7 +233,7 @@ export interface MockInstance { * * myMockFn() // 'original' */ - withImplementation(fn: T, cb: () => T2): T2 extends Promise ? Promise : this + withImplementation(fn: NormalizedPrecedure, cb: () => T2): T2 extends Promise ? Promise : this /** * Use this if you need to return `this` context from the method without invoking actual implementation. diff --git a/test/core/test/vi.spec.ts b/test/core/test/vi.spec.ts index 292aa1c19e3a..45a0b632ea85 100644 --- a/test/core/test/vi.spec.ts +++ b/test/core/test/vi.spec.ts @@ -152,6 +152,22 @@ describe('testing vi utils', () => { expectTypeOf(gSpy.mock.contexts).toEqualTypeOf() }) + test('mockImplementation types', async () => { + // overload + const fs = { readFileSync() {} } as any as typeof import('node:fs') + vi.spyOn(fs, 'readFileSync').mockImplementation(() => 'str') + vi.spyOn(fs, 'readFileSync').mockImplementation(() => Buffer.from('buf')) + vi.fn(fs.readFileSync).mockImplementation(() => 'str') + vi.fn(fs.readFileSync).mockImplementation(() => Buffer.from('buf')) + + // union + interface Handler { + (v: number): number + other: (v: number) => number + } + vi.fn().mockImplementation(v => v + 1) + }) + test('can change config', () => { const state = getWorkerState() expect(state.config.hookTimeout).toBe(10000)