Skip to content

Commit

Permalink
feat!: remove tinyspy internal properties on Vitest spies (#3069)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va committed Mar 29, 2023
1 parent 93c7e39 commit 2f1dc5c
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 97 deletions.
34 changes: 23 additions & 11 deletions docs/api/mock.md
Expand Up @@ -100,7 +100,7 @@ You should use spy assertions (e.g., [`toHaveBeenCalled`](/api/expect#tohavebeen

```js
const myMockFn = vi.fn(() => 'original')

myMockFn.withImplementation(() => 'temp', () => {
myMockFn() // 'temp'
})
Expand All @@ -113,15 +113,15 @@ You should use spy assertions (e.g., [`toHaveBeenCalled`](/api/expect#tohavebeen
```ts
test('async callback', () => {
const myMockFn = vi.fn(() => 'original')

// We await this call since the callback is async
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn() // 'temp'
},
)

myMockFn() // 'original'
})
```
Expand Down Expand Up @@ -246,12 +246,15 @@ You should use spy assertions (e.g., [`toHaveBeenCalled`](/api/expect#tohavebeen

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

If a function was invoked twice with the following arguments `fn(arg1, arg2)`, `fn(arg3, arg4)` in that order, then `mock.calls` will be:

```js
[
['arg1', 'arg2'],
['arg3', 'arg4'],
const fn = vi.fn()

fn('arg1', 'arg2')
fn('arg3', 'arg4')

fn.mock.calls === [
['arg1', 'arg2'], // first call
['arg3', 'arg4'], // second call
]
```

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

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

If function returned `result`, then threw an error, then `mock.results` will be:

```js
[
const fn = vi.fn()

const result = fn() // returned 'result'

try {
fn() // threw Error
}
catch {}

fn.mock.results === [
// first result
{
type: 'return',
value: 'result',
},
// last result
{
type: 'throw',
value: Error,
Expand Down
4 changes: 2 additions & 2 deletions packages/expect/src/jest-expect.ts
Expand Up @@ -466,7 +466,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
def(['toHaveBeenLastCalledWith', 'lastCalledWith'], function (...args: any[]) {
const spy = getSpy(this)
const spyName = spy.getMockName()
const lastCall = spy.mock.calls[spy.calls.length - 1]
const lastCall = spy.mock.calls[spy.mock.calls.length - 1]

this.assert(
jestEquals(lastCall, args, [iterableEquality]),
Expand Down Expand Up @@ -596,7 +596,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
def(['toHaveLastReturnedWith', 'lastReturnedWith'], function (value: any) {
const spy = getSpy(this)
const spyName = spy.getMockName()
const { value: lastResult } = spy.mock.results[spy.returns.length - 1]
const { value: lastResult } = spy.mock.results[spy.mock.results.length - 1]
const pass = jestEquals(lastResult, value)
this.assert(
pass,
Expand Down
2 changes: 1 addition & 1 deletion packages/spy/package.json
Expand Up @@ -29,6 +29,6 @@
"prepublishOnly": "pnpm build"
},
"dependencies": {
"tinyspy": "^1.0.2"
"tinyspy": "^2.1.0"
}
}
24 changes: 13 additions & 11 deletions packages/spy/src/index.ts
@@ -1,4 +1,4 @@
import type { SpyImpl } from 'tinyspy'
import type { SpyInternalImpl } from 'tinyspy'
import * as tinyspy from 'tinyspy'

interface MockResultReturn<T> {
Expand Down Expand Up @@ -135,7 +135,7 @@ export type Mocked<T> = {
} &
T

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

export const spies = new Set<SpyInstance>()

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

const stub = tinyspy.spyOn(obj, objMethod as any)
const stub = tinyspy.internalSpyOn(obj, objMethod as any)

return enhanceSpy(stub) as SpyInstance
}

let callOrder = 0

function enhanceSpy<TArgs extends any[], TReturns>(
spy: SpyImpl<TArgs, TReturns>,
spy: SpyInternalImpl<TArgs, TReturns>,
): SpyInstance<TArgs, TReturns> {
const stub = spy as unknown as EnhancedSpy<TArgs, TReturns>

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

const state = tinyspy.getInternalState(spy)

const mockContext = {
get calls() {
return stub.calls
return state.calls
},
get instances() {
return instances
Expand All @@ -198,13 +200,13 @@ function enhanceSpy<TArgs extends any[], TReturns>(
return invocations
},
get results() {
return stub.results.map(([callType, value]) => {
return state.results.map(([callType, value]) => {
const type = callType === 'error' ? 'throw' : 'return'
return { type, value }
})
},
get lastCall() {
return stub.calls[stub.calls.length - 1]
return state.calls[state.calls.length - 1]
},
}

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

stub.mockClear = () => {
stub.reset()
state.reset()
instances = []
invocations = []
return stub
Expand Down Expand Up @@ -303,10 +305,10 @@ function enhanceSpy<TArgs extends any[], TReturns>(
get: () => mockContext,
})

stub.willCall(function (this: unknown, ...args) {
state.willCall(function (this: unknown, ...args) {
instances.push(this)
invocations.push(++callOrder)
const impl = implementationChangedTemporarily ? implementation! : onceImplementations.shift() || implementation || stub.getOriginal() || (() => {})
const impl = implementationChangedTemporarily ? implementation! : onceImplementations.shift() || implementation || state.getOriginal() || (() => {})
return impl.apply(this, args)
})

Expand All @@ -322,5 +324,5 @@ export function fn<TArgs extends any[] = any[], R = any>(
export function fn<TArgs extends any[] = any[], R = any>(
implementation?: (...args: TArgs) => R,
): Mock<TArgs, R> {
return enhanceSpy(tinyspy.spyOn({ fn: implementation || (() => {}) }, 'fn')) as unknown as Mock
return enhanceSpy(tinyspy.internalSpyOn({ fn: implementation || (() => {}) }, 'fn')) as unknown as Mock
}
1 change: 0 additions & 1 deletion packages/vitest/package.json
Expand Up @@ -154,7 +154,6 @@
"strip-literal": "^1.0.0",
"tinybench": "^2.3.1",
"tinypool": "^0.4.0",
"tinyspy": "^1.0.2",
"vite": "^3.0.0 || ^4.0.0",
"vite-node": "workspace:*",
"why-is-node-running": "^2.2.2"
Expand Down

0 comments on commit 2f1dc5c

Please sign in to comment.