Skip to content

Commit 2f1dc5c

Browse files
authored
feat!: remove tinyspy internal properties on Vitest spies (#3069)
1 parent 93c7e39 commit 2f1dc5c

File tree

6 files changed

+117
-97
lines changed

6 files changed

+117
-97
lines changed

docs/api/mock.md

+23-11
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ You should use spy assertions (e.g., [`toHaveBeenCalled`](/api/expect#tohavebeen
100100

101101
```js
102102
const myMockFn = vi.fn(() => 'original')
103-
103+
104104
myMockFn.withImplementation(() => 'temp', () => {
105105
myMockFn() // 'temp'
106106
})
@@ -113,15 +113,15 @@ You should use spy assertions (e.g., [`toHaveBeenCalled`](/api/expect#tohavebeen
113113
```ts
114114
test('async callback', () => {
115115
const myMockFn = vi.fn(() => 'original')
116-
116+
117117
// We await this call since the callback is async
118118
await myMockFn.withImplementation(
119119
() => 'temp',
120120
async () => {
121121
myMockFn() // 'temp'
122122
},
123123
)
124-
124+
125125
myMockFn() // 'original'
126126
})
127127
```
@@ -246,12 +246,15 @@ You should use spy assertions (e.g., [`toHaveBeenCalled`](/api/expect#tohavebeen
246246

247247
This is an array containing all arguments for each call. One item of the array is the arguments of that call.
248248

249-
If a function was invoked twice with the following arguments `fn(arg1, arg2)`, `fn(arg3, arg4)` in that order, then `mock.calls` will be:
250-
251249
```js
252-
[
253-
['arg1', 'arg2'],
254-
['arg3', 'arg4'],
250+
const fn = vi.fn()
251+
252+
fn('arg1', 'arg2')
253+
fn('arg3', 'arg4')
254+
255+
fn.mock.calls === [
256+
['arg1', 'arg2'], // first call
257+
['arg3', 'arg4'], // second call
255258
]
256259
```
257260

@@ -268,14 +271,23 @@ This is an array containing all values, that were `returned` from the function.
268271

269272
The `value` property contains returned value or thrown error.
270273

271-
If function returned `result`, then threw an error, then `mock.results` will be:
272-
273274
```js
274-
[
275+
const fn = vi.fn()
276+
277+
const result = fn() // returned 'result'
278+
279+
try {
280+
fn() // threw Error
281+
}
282+
catch {}
283+
284+
fn.mock.results === [
285+
// first result
275286
{
276287
type: 'return',
277288
value: 'result',
278289
},
290+
// last result
279291
{
280292
type: 'throw',
281293
value: Error,

packages/expect/src/jest-expect.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
466466
def(['toHaveBeenLastCalledWith', 'lastCalledWith'], function (...args: any[]) {
467467
const spy = getSpy(this)
468468
const spyName = spy.getMockName()
469-
const lastCall = spy.mock.calls[spy.calls.length - 1]
469+
const lastCall = spy.mock.calls[spy.mock.calls.length - 1]
470470

471471
this.assert(
472472
jestEquals(lastCall, args, [iterableEquality]),
@@ -596,7 +596,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
596596
def(['toHaveLastReturnedWith', 'lastReturnedWith'], function (value: any) {
597597
const spy = getSpy(this)
598598
const spyName = spy.getMockName()
599-
const { value: lastResult } = spy.mock.results[spy.returns.length - 1]
599+
const { value: lastResult } = spy.mock.results[spy.mock.results.length - 1]
600600
const pass = jestEquals(lastResult, value)
601601
this.assert(
602602
pass,

packages/spy/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@
2929
"prepublishOnly": "pnpm build"
3030
},
3131
"dependencies": {
32-
"tinyspy": "^1.0.2"
32+
"tinyspy": "^2.1.0"
3333
}
3434
}

packages/spy/src/index.ts

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { SpyImpl } from 'tinyspy'
1+
import type { SpyInternalImpl } from 'tinyspy'
22
import * as tinyspy from 'tinyspy'
33

44
interface MockResultReturn<T> {
@@ -135,7 +135,7 @@ export type Mocked<T> = {
135135
} &
136136
T
137137

138-
export type EnhancedSpy<TArgs extends any[] = any[], TReturns = any> = SpyInstance<TArgs, TReturns> & SpyImpl<TArgs, TReturns>
138+
export type EnhancedSpy<TArgs extends any[] = any[], TReturns = any> = SpyInstance<TArgs, TReturns> & SpyInternalImpl<TArgs, TReturns>
139139

140140
export const spies = new Set<SpyInstance>()
141141

@@ -170,15 +170,15 @@ export function spyOn<T, K extends keyof T>(
170170
} as const
171171
const objMethod = accessType ? { [dictionary[accessType]]: method } : method
172172

173-
const stub = tinyspy.spyOn(obj, objMethod as any)
173+
const stub = tinyspy.internalSpyOn(obj, objMethod as any)
174174

175175
return enhanceSpy(stub) as SpyInstance
176176
}
177177

178178
let callOrder = 0
179179

180180
function enhanceSpy<TArgs extends any[], TReturns>(
181-
spy: SpyImpl<TArgs, TReturns>,
181+
spy: SpyInternalImpl<TArgs, TReturns>,
182182
): SpyInstance<TArgs, TReturns> {
183183
const stub = spy as unknown as EnhancedSpy<TArgs, TReturns>
184184

@@ -187,9 +187,11 @@ function enhanceSpy<TArgs extends any[], TReturns>(
187187
let instances: any[] = []
188188
let invocations: number[] = []
189189

190+
const state = tinyspy.getInternalState(spy)
191+
190192
const mockContext = {
191193
get calls() {
192-
return stub.calls
194+
return state.calls
193195
},
194196
get instances() {
195197
return instances
@@ -198,13 +200,13 @@ function enhanceSpy<TArgs extends any[], TReturns>(
198200
return invocations
199201
},
200202
get results() {
201-
return stub.results.map(([callType, value]) => {
203+
return state.results.map(([callType, value]) => {
202204
const type = callType === 'error' ? 'throw' : 'return'
203205
return { type, value }
204206
})
205207
},
206208
get lastCall() {
207-
return stub.calls[stub.calls.length - 1]
209+
return state.calls[state.calls.length - 1]
208210
},
209211
}
210212

@@ -220,7 +222,7 @@ function enhanceSpy<TArgs extends any[], TReturns>(
220222
}
221223

222224
stub.mockClear = () => {
223-
stub.reset()
225+
state.reset()
224226
instances = []
225227
invocations = []
226228
return stub
@@ -303,10 +305,10 @@ function enhanceSpy<TArgs extends any[], TReturns>(
303305
get: () => mockContext,
304306
})
305307

306-
stub.willCall(function (this: unknown, ...args) {
308+
state.willCall(function (this: unknown, ...args) {
307309
instances.push(this)
308310
invocations.push(++callOrder)
309-
const impl = implementationChangedTemporarily ? implementation! : onceImplementations.shift() || implementation || stub.getOriginal() || (() => {})
311+
const impl = implementationChangedTemporarily ? implementation! : onceImplementations.shift() || implementation || state.getOriginal() || (() => {})
310312
return impl.apply(this, args)
311313
})
312314

@@ -322,5 +324,5 @@ export function fn<TArgs extends any[] = any[], R = any>(
322324
export function fn<TArgs extends any[] = any[], R = any>(
323325
implementation?: (...args: TArgs) => R,
324326
): Mock<TArgs, R> {
325-
return enhanceSpy(tinyspy.spyOn({ fn: implementation || (() => {}) }, 'fn')) as unknown as Mock
327+
return enhanceSpy(tinyspy.internalSpyOn({ fn: implementation || (() => {}) }, 'fn')) as unknown as Mock
326328
}

packages/vitest/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@
154154
"strip-literal": "^1.0.0",
155155
"tinybench": "^2.3.1",
156156
"tinypool": "^0.4.0",
157-
"tinyspy": "^1.0.2",
158157
"vite": "^3.0.0 || ^4.0.0",
159158
"vite-node": "workspace:*",
160159
"why-is-node-running": "^2.2.2"

0 commit comments

Comments
 (0)