Skip to content

Commit

Permalink
fix(spy): fix type error when assigning vi.spyOn to MockInstance
Browse files Browse the repository at this point in the history
…of function overload (#6086)
  • Loading branch information
hi-ogawa authored Jul 11, 2024
1 parent fbed105 commit e9f9adc
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 5 deletions.
8 changes: 4 additions & 4 deletions packages/spy/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,11 @@ export function spyOn<T, G extends Properties<Required<T>>>(
export function spyOn<T, M extends Classes<Required<T>> | Methods<Required<T>>>(
obj: T,
methodName: M
): Required<T>[M] extends
| { new (...args: infer A): infer R }
| ((...args: infer A) => infer R)
): Required<T>[M] extends { new (...args: infer A): infer R }
? MockInstance<(this: R, ...args: A) => R>
: never
: T[M] extends Procedure
? MockInstance<T[M]>
: never
export function spyOn<T, K extends keyof T>(
obj: T,
method: K,
Expand Down
36 changes: 35 additions & 1 deletion test/core/test/vi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @vitest-environment jsdom
*/

import type { Mock, MockedFunction, MockedObject } from 'vitest'
import type { Mock, MockInstance, MockedFunction, MockedObject } from 'vitest'
import { describe, expect, expectTypeOf, test, vi } from 'vitest'
import { getWorkerState } from '../../../packages/vitest/src/utils'

Expand Down Expand Up @@ -118,6 +118,40 @@ describe('testing vi utils', () => {
expect(someFn4).not.toBeCalled()
})

test(`vi.spyOn for function overload types`, () => {
class MyElement {
scrollTo(options?: ScrollToOptions): void
scrollTo(x: number, y: number): void
scrollTo() {}
}

// verify `spyOn` is assignable to `MockInstance` with overload
const spy: MockInstance<MyElement['scrollTo']> = vi.spyOn(
MyElement.prototype,
'scrollTo',
)

// however `Parameters` only picks up the last overload
// due to typescript limitation
expectTypeOf(spy.mock.calls).toEqualTypeOf<
[x: number, y: number][]
>()
})

test(`mock.contexts types`, () => {
class TestClass {
f(this: TestClass) {}
g() {}
}

const fSpy = vi.spyOn(TestClass.prototype, 'f')
const gSpy = vi.spyOn(TestClass.prototype, 'g')

// contexts inferred only when `this` is explicitly annotated
expectTypeOf(fSpy.mock.contexts).toEqualTypeOf<TestClass[]>()
expectTypeOf(gSpy.mock.contexts).toEqualTypeOf<unknown[]>()
})

test('can change config', () => {
const state = getWorkerState()
expect(state.config.hookTimeout).toBe(10000)
Expand Down

0 comments on commit e9f9adc

Please sign in to comment.