[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

chore: keep length static (#8782)

authored by

Vladimir and committed by
GitHub
(Oct 23, 2025, 7:04 PM +0200) a1dcffe4 2eedbce7

+53 -33
+11 -3
docs/api/mock.md
··· 21 21 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. 22 22 23 23 ::: warning IMPORTANT 24 - Vitest spies inherit implementation's `length` property. This means that `length` can be different from the original implementation: 24 + Vitest spies inherit implementation's [`length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length) property when initialized, but it doesn't override it if the implementation was changed later: 25 25 26 - ```ts 26 + ::: code-group 27 + ```ts [vi.fn] 28 + const fn = vi.fn((arg1) => {}) 29 + fn.length // == 1 30 + 31 + fn.mockImplementation(() => {}) 32 + fn.length // == 1 33 + ``` 34 + ```ts [vi.spyOn] 27 35 const example = { 28 36 fn(arg1, arg2) { 29 37 // ... ··· 34 42 fn.length // == 2 35 43 36 44 fn.mockImplementation(() => {}) 37 - fn.length // == 0 45 + fn.length // == 2 38 46 ``` 39 47 ::: 40 48
+7 -19
packages/spy/src/index.ts
··· 48 48 state, 49 49 ...options, 50 50 }) 51 + const mockLength = (mockImplementation || originalImplementation)?.length ?? 0 52 + Object.defineProperty(mock, 'length', { 53 + writable: true, 54 + enumerable: false, 55 + value: mockLength, 56 + configurable: true, 57 + }) 51 58 // inherit the default name so it appears in snapshots and logs 52 59 // this is used by `vi.spyOn()` for better debugging. 53 60 // when `vi.fn()` is called, we just use the default string ··· 494 501 if (original) { 495 502 copyOriginalStaticProperties(namedObject[name], original) 496 503 } 497 - let overrideLength: number | undefined 498 - Object.defineProperty(namedObject[name], 'length', { 499 - configurable: true, 500 - get: () => { 501 - if (overrideLength != null) { 502 - return overrideLength 503 - } 504 - 505 - const implementation = config.onceMockImplementations[0] 506 - || config.mockImplementation 507 - || prototypeConfig?.onceMockImplementations[0] 508 - || prototypeConfig?.mockImplementation 509 - || original 510 - return implementation?.length ?? 0 511 - }, 512 - set: (length: number) => { 513 - overrideLength = length 514 - }, 515 - }) 516 504 return namedObject[name] 517 505 } 518 506
+35 -11
test/core/test/mocking/vi-fn.test.ts
··· 20 20 }).toThrowError() 21 21 }) 22 22 23 - test('vi.fn() has correct length', () => { 24 - const fn0 = vi.fn(() => {}) 25 - expect(fn0.length).toBe(0) 23 + describe('fn.length is consistent', () => { 24 + test('vi.fn() has correct length', () => { 25 + const fn0 = vi.fn(() => {}) 26 + expect(fn0.length).toBe(0) 26 27 27 - const fnArgs = vi.fn((..._args) => {}) 28 - expect(fnArgs.length).toBe(0) 28 + const fnArgs = vi.fn((..._args) => {}) 29 + expect(fnArgs.length).toBe(0) 29 30 30 - const fn1 = vi.fn((_arg1) => {}) 31 - expect(fn1.length).toBe(1) 31 + const fn1 = vi.fn((_arg1) => {}) 32 + expect(fn1.length).toBe(1) 32 33 33 - const fn2 = vi.fn((_arg1, _arg2) => {}) 34 - expect(fn2.length).toBe(2) 34 + const fn2 = vi.fn((_arg1, _arg2) => {}) 35 + expect(fn2.length).toBe(2) 35 36 36 - const fn3 = vi.fn((_arg1, _arg2, _arg3) => {}) 37 - expect(fn3.length).toBe(3) 37 + const fn3 = vi.fn((_arg1, _arg2, _arg3) => {}) 38 + expect(fn3.length).toBe(3) 39 + }) 40 + 41 + test('vi.fn() always returns length of the initial implementation', () => { 42 + const fn = vi.fn<(...args: any[]) => void>((_arg) => {}) 43 + 44 + expect(fn.length).toBe(1) 45 + 46 + fn.mockImplementationOnce(() => {}) 47 + 48 + expect(fn.length).toBe(1) 49 + fn(1) 50 + expect(fn.length).toBe(1) 51 + 52 + fn.mockImplementation((_arg1, _arg2) => {}) 53 + 54 + expect(fn.length).toBe(1) 55 + fn(1) 56 + expect(fn.length).toBe(1) 57 + 58 + fn.withImplementation((_arg1, _arg2, _arg3) => {}, () => { 59 + expect(fn.length).toBe(1) 60 + }) 61 + }) 38 62 }) 39 63 40 64 test('vi.fn() has overridable length', () => {