Skip to content

Commit

Permalink
fix(types): accept MockInstance as stubbing target (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcous authored Nov 1, 2024
1 parent cbe8f01 commit 46fb4cb
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 7 deletions.
9 changes: 4 additions & 5 deletions src/stubs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { Mock } from 'vitest'
import {
createBehaviorStack,
type BehaviorStack,
BehaviorType,
} from './behaviors.ts'
import { NotAMockFunctionError } from './errors.ts'
import type { AnyFunction } from './types.ts'
import type { AnyFunction, MockInstance } from './types.ts'

const BEHAVIORS_KEY = Symbol('behaviors')

Expand Down Expand Up @@ -63,7 +62,7 @@ export const configureStub = <TFunc extends AnyFunction>(
return behaviors
}

export const validateSpy = (maybeSpy: unknown): Mock => {
export const validateSpy = (maybeSpy: unknown): MockInstance => {
if (
typeof maybeSpy === 'function' &&
'mockImplementation' in maybeSpy &&
Expand All @@ -73,14 +72,14 @@ export const validateSpy = (maybeSpy: unknown): Mock => {
'getMockName' in maybeSpy &&
typeof maybeSpy.getMockName === 'function'
) {
return maybeSpy as Mock
return maybeSpy as unknown as MockInstance
}

throw new NotAMockFunctionError(maybeSpy)
}

export const getBehaviorStack = <TFunc extends AnyFunction>(
spy: Mock,
spy: MockInstance,
): BehaviorStack<TFunc> | undefined => {
const existingImplementation = spy.getMockImplementation() as
| WhenStubImplementation<TFunc>
Expand Down
17 changes: 17 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,20 @@

/** Any function, for use in `extends` */
export type AnyFunction = (...args: never[]) => unknown

/**
* Minimally typed version of Vitest's `MockInstance`.
*
* Used to ensure backwards compatibility
* with older versions of Vitest.
*/
export interface MockInstance<TFunc extends AnyFunction = AnyFunction> {
getMockName(): string
getMockImplementation(): TFunc | undefined
mockImplementation: (impl: TFunc) => this
mock: MockContext<TFunc>
}

export interface MockContext<TFunc extends AnyFunction> {
calls: Parameters<TFunc>[]
}
4 changes: 2 additions & 2 deletions src/vitest-when.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { configureStub } from './stubs.ts'
import type { WhenOptions } from './behaviors.ts'
import type { AnyFunction } from './types.ts'
import type { AnyFunction, MockInstance } from './types.ts'
import { getDebug, type DebugResult } from './debug.ts'

export { type WhenOptions, type Behavior, BehaviorType } from './behaviors.ts'
Expand All @@ -22,7 +22,7 @@ export interface Stub<TArgs extends unknown[], TReturn> {
}

export const when = <TFunc extends AnyFunction>(
spy: TFunc,
spy: TFunc | MockInstance<TFunc>,
options: WhenOptions = {},
): StubWrapper<TFunc> => {
const behaviorStack = configureStub(spy)
Expand Down
10 changes: 10 additions & 0 deletions test/typing.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ describe('vitest-when type signatures', () => {
assertType<subject.Stub<[number], any>>(stub)
})

it('should handle an spied function', () => {
const target = { simple }
const spy = vi.spyOn(target, 'simple')
const stub = subject.when(spy).calledWith(1)

stub.thenReturn('hello')

assertType<subject.Stub<[number], any>>(stub)
})

it('should handle a simple function', () => {
const stub = subject.when(simple).calledWith(1)

Expand Down

0 comments on commit 46fb4cb

Please sign in to comment.