Skip to content

Commit 2029a3b

Browse files
committed
Add ignoreExtraArgs option
1 parent ff8c781 commit 2029a3b

File tree

3 files changed

+65
-21
lines changed

3 files changed

+65
-21
lines changed

README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,10 @@ expect(mock()).toBe(undefined)
205205
import type { WhenOptions } from 'vitest-when'
206206
```
207207

208-
| option | default | type | description |
209-
| ------- | ------- | ------- | -------------------------------------------------- |
210-
| `times` | N/A | integer | Only trigger configured behavior a number of times |
208+
| option | default | type | description |
209+
| ----------------- | ------- | ------- | -------------------------------------------------- |
210+
| `ignoreExtraArgs` | `false` | boolean | Ignore extra arguments when matching arguments |
211+
| `times` | N/A | integer | Only trigger configured behavior a number of times |
211212

212213
### `.calledWith(...args: Parameters<TFunc>): Stub<TFunc>`
213214

@@ -306,6 +307,17 @@ expect(mock('hello')).toEqual('sup?')
306307
expect(mock('hello')).toEqual('sup?')
307308
```
308309

310+
You can also ignore extra arguments when matching arguments.
311+
312+
```ts
313+
const mock = when(vi.fn(), { ignoreExtraArgs: true })
314+
.calledWith('hello')
315+
.thenReturn('world')
316+
317+
expect(mock('hello')).toEqual('world')
318+
expect(mock('hello', 'jello')).toEqual('world')
319+
```
320+
309321
### `.thenResolve(value: TReturn) -> Mock<TFunc>`
310322

311323
When the stubbing is satisfied, resolve a `Promise` with `value`

src/behaviors.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
} from './types.ts'
1111

1212
export interface WhenOptions {
13+
ignoreExtraArgs?: boolean
1314
times?: number
1415
}
1516

@@ -40,6 +41,7 @@ export interface BehaviorEntry<TArgs extends unknown[]> {
4041
args: WithMatchers<TArgs>
4142
behavior: Behavior
4243
calls: TArgs[]
44+
ignoreExtraArgs: boolean
4345
maxCallCount?: number | undefined
4446
}
4547

@@ -60,6 +62,7 @@ export type Behavior =
6062

6163
export interface BehaviorOptions<TValue> {
6264
value: TValue
65+
ignoreExtraArgs: boolean
6366
maxCallCount: number | undefined
6467
}
6568

@@ -92,8 +95,9 @@ export const createBehaviorStack = <
9295
addReturn: (values) => {
9396
behaviors.unshift(
9497
...getBehaviorOptions(values, options).map(
95-
({ value, maxCallCount }) => ({
98+
({ value, ignoreExtraArgs, maxCallCount }) => ({
9699
args,
100+
ignoreExtraArgs,
97101
maxCallCount,
98102
behavior: { type: BehaviorType.RETURN, value },
99103
calls: [],
@@ -104,8 +108,9 @@ export const createBehaviorStack = <
104108
addResolve: (values) => {
105109
behaviors.unshift(
106110
...getBehaviorOptions(values, options).map(
107-
({ value, maxCallCount }) => ({
111+
({ value, ignoreExtraArgs, maxCallCount }) => ({
108112
args,
113+
ignoreExtraArgs,
109114
maxCallCount,
110115
behavior: { type: BehaviorType.RESOLVE, value },
111116
calls: [],
@@ -116,8 +121,9 @@ export const createBehaviorStack = <
116121
addThrow: (values) => {
117122
behaviors.unshift(
118123
...getBehaviorOptions(values, options).map(
119-
({ value, maxCallCount }) => ({
124+
({ value, ignoreExtraArgs, maxCallCount }) => ({
120125
args,
126+
ignoreExtraArgs,
121127
maxCallCount,
122128
behavior: { type: BehaviorType.THROW, error: value },
123129
calls: [],
@@ -128,8 +134,9 @@ export const createBehaviorStack = <
128134
addReject: (values) => {
129135
behaviors.unshift(
130136
...getBehaviorOptions(values, options).map(
131-
({ value, maxCallCount }) => ({
137+
({ value, ignoreExtraArgs, maxCallCount }) => ({
132138
args,
139+
ignoreExtraArgs,
133140
maxCallCount,
134141
behavior: { type: BehaviorType.REJECT, error: value },
135142
calls: [],
@@ -140,8 +147,9 @@ export const createBehaviorStack = <
140147
addDo: (values) => {
141148
behaviors.unshift(
142149
...getBehaviorOptions(values, options).map(
143-
({ value, maxCallCount }) => ({
150+
({ value, ignoreExtraArgs, maxCallCount }) => ({
144151
args,
152+
ignoreExtraArgs,
145153
maxCallCount,
146154
behavior: {
147155
type: BehaviorType.DO,
@@ -158,14 +166,15 @@ export const createBehaviorStack = <
158166

159167
const getBehaviorOptions = <TValue>(
160168
values: TValue[],
161-
{ times }: WhenOptions,
169+
{ ignoreExtraArgs, times }: WhenOptions,
162170
): BehaviorOptions<TValue>[] => {
163171
if (values.length === 0) {
164172
values = [undefined as TValue]
165173
}
166174

167175
return values.map((value, index) => ({
168176
value,
177+
ignoreExtraArgs: ignoreExtraArgs ?? false,
169178
maxCallCount: times ?? (index < values.length - 1 ? 1 : undefined),
170179
}))
171180
}
@@ -179,18 +188,17 @@ const behaviorAvailable = <TArgs extends unknown[]>(
179188
)
180189
}
181190

182-
const behaviorMatches = <TArgs extends unknown[]>(args: TArgs) => {
191+
const behaviorMatches = <TArgs extends unknown[]>(actualArguments: TArgs) => {
183192
return (behavior: BehaviorEntry<TArgs>): boolean => {
184-
let index = 0
185-
186-
while (index < args.length || index < behavior.args.length) {
187-
if (!equals(args[index], behavior.args[index])) {
188-
return false
189-
}
190-
191-
index += 1
192-
}
193-
194-
return true
193+
// Check arity
194+
const expectedArguments = behavior.args
195+
const { ignoreExtraArgs } = behavior
196+
if (expectedArguments.length !== actualArguments.length && !ignoreExtraArgs)
197+
return false
198+
199+
// Check arguments
200+
return expectedArguments.every((expectedArgument, index) => {
201+
return equals(actualArguments[index], expectedArgument)
202+
})
195203
}
196204
}

test/vitest-when.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,4 +279,28 @@ describe('vitest-when', () => {
279279
// intentionally do not call the spy
280280
expect(true).toBe(true)
281281
})
282+
283+
it('should ignore extra args if configured', () => {
284+
const spy = subject
285+
.when(vi.fn(), { ignoreExtraArgs: true })
286+
.calledWith('Outcomes are:')
287+
.thenReturn('loggy')
288+
289+
expect(spy('Outcomes are:')).toEqual('loggy')
290+
expect(spy('Outcomes are:', 'stuff')).toEqual('loggy')
291+
expect(spy('Outcomes are:', 'stuff', 'that', 'keeps', 'going')).toEqual(
292+
'loggy',
293+
)
294+
expect(spy('Outcomes are not:', 'stuff')).toEqual(undefined)
295+
})
296+
297+
it('should ignore all args if configured', () => {
298+
const spy = subject
299+
.when(vi.fn(), { ignoreExtraArgs: true })
300+
.calledWith()
301+
.thenReturn('yesss')
302+
303+
expect(spy()).toEqual('yesss')
304+
expect(spy(1, 2, 3, 4, 5)).toEqual('yesss')
305+
})
282306
})

0 commit comments

Comments
 (0)