fix(spy): can respy on an exported method (#8521)

This commit is contained in:
Vladimir 2025-09-03 11:19:51 +02:00 committed by GitHub
parent 5790931929
commit bf450b4339
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 61 additions and 3 deletions

View File

@ -260,8 +260,16 @@ export function spyOn<T extends object, K extends keyof T>(
original = object[key] as unknown as Procedure
}
if (isMockFunction(original)) {
return original
const originalImplementation = ssr && original ? original() : original
const originalType = typeof originalImplementation
assert(
originalType === 'function',
`vi.spyOn() can only spy on a function. Received ${originalType}.`,
)
if (isMockFunction(originalImplementation)) {
return originalImplementation
}
const reassign = (cb: any) => {
@ -292,7 +300,7 @@ export function spyOn<T extends object, K extends keyof T>(
const mock = createMockInstance({
restore,
originalImplementation: ssr && original ? original() : original,
originalImplementation,
resetToMockName: true,
})

View File

@ -592,6 +592,56 @@ describe('vi.spyOn() restoration', () => {
})
})
describe('vi.spyOn() on Vite SSR', () => {
test('vi.spyOn() throws an error if a getter returns a non-function value in SSR', () => {
const module = {
get primitive() {
return 42
},
}
expect(() => {
// @ts-expect-error types recognize it's not a function
vi.spyOn(module, 'primitive')
}).toThrowError('vi.spyOn() can only spy on a function. Received number.')
})
test('vi.spyOn() assigns the method on a getter', () => {
const method = () => {}
const module = {
get method() {
return method
},
}
const spy = vi.spyOn(module, 'method')
expect(spy.getMockImplementation()).toBe(undefined)
module.method()
expect(spy.mock.calls).toEqual([[]])
expect(module.method).toBe(spy)
spy.mockRestore()
expect(module.method).toBe(method)
})
test('vi.spyOn() can reassign the SSR getter method', () => {
const method = () => {}
const module = {
get method() {
return method
},
}
const spy1 = vi.spyOn(module, 'method')
const spy2 = vi.spyOn(module, 'method')
expect(vi.isMockFunction(spy1)).toBe(true)
expect(vi.isMockFunction(spy2)).toBe(true)
expect(spy1).toBe(spy2)
module.method()
expect(spy1.mock.calls).toEqual([[]])
expect(spy2.mock.calls).toEqual([[]])
})
})
function assertStateEmpty(state: MockContext<any>) {
expect(state.calls).toHaveLength(0)
expect(state.results).toHaveLength(0)