0
# Argument Matching
1
2
Sinon's matcher system provides flexible argument matching for creating sophisticated test assertions and stub behaviors. Matchers allow you to specify patterns instead of exact values, making tests more robust and expressive.
3
4
## Capabilities
5
6
### Basic Type Matchers
7
8
Match arguments based on their JavaScript types.
9
10
```javascript { .api }
11
declare namespace match {
12
/** Matches any value (always returns true) */
13
const any: SinonMatcher;
14
15
/** Matches any defined value (not null or undefined) */
16
const defined: SinonMatcher;
17
18
/** Matches truthy values */
19
const truthy: SinonMatcher;
20
21
/** Matches falsy values */
22
const falsy: SinonMatcher;
23
24
/** Matches boolean values */
25
const bool: SinonMatcher;
26
27
/** Matches number values (including NaN) */
28
const number: SinonMatcher;
29
30
/** Matches string values */
31
const string: SinonMatcher;
32
33
/** Matches object values (including arrays, functions, etc.) */
34
const object: SinonMatcher;
35
36
/** Matches function values */
37
const func: SinonMatcher;
38
39
/** Matches array values */
40
const array: SinonMatcher;
41
42
/** Matches regular expression values */
43
const regexp: SinonMatcher;
44
45
/** Matches Date objects */
46
const date: SinonMatcher;
47
48
/** Matches Symbol values */
49
const symbol: SinonMatcher;
50
51
/** Matches Map objects */
52
const map: SinonMatcher;
53
54
/** Matches Set objects */
55
const set: SinonMatcher;
56
}
57
```
58
59
**Usage Examples:**
60
61
```javascript
62
import { match } from "sinon";
63
64
const spy = sinon.spy();
65
66
spy("hello", 42, true, {}, []);
67
68
// Use type matchers in assertions
69
sinon.assert.calledWith(spy, match.string, match.number, match.bool, match.object, match.array);
70
71
// Use in stub configurations
72
const stub = sinon.stub();
73
stub.withArgs(match.string).returns("string argument");
74
stub.withArgs(match.number).returns("number argument");
75
76
console.log(stub("test")); // "string argument"
77
console.log(stub(123)); // "number argument"
78
```
79
80
### Value Matchers
81
82
Match arguments based on specific values or references.
83
84
```javascript { .api }
85
declare namespace match {
86
/**
87
* Matches the exact same reference (using ===)
88
* @param value - Value to match by reference
89
* @returns Matcher for the exact reference
90
*/
91
function same(value: any): SinonMatcher;
92
93
/**
94
* Matches values with specific typeof result
95
* @param type - Expected typeof string
96
* @returns Matcher for the typeof result
97
*/
98
function typeOf(type: string): SinonMatcher;
99
100
/**
101
* Matches instances of a specific constructor
102
* @param constructor - Constructor function to match against
103
* @returns Matcher for instanceof check
104
*/
105
function instanceOf(constructor: Function): SinonMatcher;
106
}
107
```
108
109
**Usage Examples:**
110
111
```javascript
112
const obj = { name: "test" };
113
const spy = sinon.spy();
114
115
spy(obj, new Date(), "hello");
116
117
// Match by reference
118
sinon.assert.calledWith(spy, match.same(obj));
119
120
// Match by typeof
121
sinon.assert.calledWith(spy, match.object, match.typeOf("object"), match.typeOf("string"));
122
123
// Match by instanceof
124
sinon.assert.calledWith(spy, match.object, match.instanceOf(Date), match.string);
125
```
126
127
### Property Matchers
128
129
Match objects based on their properties and property values.
130
131
```javascript { .api }
132
declare namespace match {
133
/**
134
* Matches objects that have a specific property
135
* @param property - Property name to check for
136
* @param value - Optional expected property value
137
* @returns Matcher for property existence and value
138
*/
139
function has(property: string, value?: any): SinonMatcher;
140
141
/**
142
* Matches objects that have a specific own property (not inherited)
143
* @param property - Property name that must be own property
144
* @param value - Optional expected property value
145
* @returns Matcher for own property existence and value
146
*/
147
function hasOwn(property: string, value?: any): SinonMatcher;
148
149
/**
150
* Matches objects that have nested property paths
151
* @param path - Dot-separated property path (e.g., "user.profile.name")
152
* @param value - Optional expected nested property value
153
* @returns Matcher for nested property existence and value
154
*/
155
function hasNested(path: string, value?: any): SinonMatcher;
156
}
157
```
158
159
**Usage Examples:**
160
161
```javascript
162
const spy = sinon.spy();
163
164
const user = {
165
id: 1,
166
name: "John",
167
profile: {
168
email: "john@example.com",
169
settings: { theme: "dark" }
170
}
171
};
172
173
spy(user);
174
175
// Match by property existence
176
sinon.assert.calledWith(spy, match.has("name"));
177
sinon.assert.calledWith(spy, match.has("id", 1));
178
179
// Match by own property (not inherited)
180
sinon.assert.calledWith(spy, match.hasOwn("name"));
181
182
// Match nested properties
183
sinon.assert.calledWith(spy, match.hasNested("profile.email"));
184
sinon.assert.calledWith(spy, match.hasNested("profile.settings.theme", "dark"));
185
```
186
187
### Numeric Matchers
188
189
Match numbers based on ranges and comparisons.
190
191
```javascript { .api }
192
declare namespace match {
193
/**
194
* Matches numbers greater than specified value
195
* @param value - Minimum value (exclusive)
196
* @returns Matcher for numbers greater than value
197
*/
198
function greaterThan(value: number): SinonMatcher;
199
200
/**
201
* Matches numbers greater than or equal to specified value
202
* @param value - Minimum value (inclusive)
203
* @returns Matcher for numbers >= value
204
*/
205
function atLeast(value: number): SinonMatcher;
206
207
/**
208
* Matches numbers less than specified value
209
* @param value - Maximum value (exclusive)
210
* @returns Matcher for numbers less than value
211
*/
212
function lessThan(value: number): SinonMatcher;
213
214
/**
215
* Matches numbers less than or equal to specified value
216
* @param value - Maximum value (inclusive)
217
* @returns Matcher for numbers <= value
218
*/
219
function atMost(value: number): SinonMatcher;
220
}
221
```
222
223
**Usage Examples:**
224
225
```javascript
226
const spy = sinon.spy();
227
228
spy(25, 100, 5);
229
230
// Numeric comparisons
231
sinon.assert.calledWith(spy, match.greaterThan(18)); // 25 > 18
232
sinon.assert.calledWith(spy, match.atLeast(25)); // 25 >= 25
233
sinon.assert.calledWith(spy, match.lessThan(200)); // 100 < 200
234
sinon.assert.calledWith(spy, match.atMost(10)); // 5 <= 10
235
236
// Use in stubs
237
const stub = sinon.stub();
238
stub.withArgs(match.greaterThan(50)).returns("large number");
239
stub.withArgs(match.atMost(50)).returns("small number");
240
241
console.log(stub(100)); // "large number"
242
console.log(stub(25)); // "small number"
243
```
244
245
### String Matchers
246
247
Match strings based on patterns and content.
248
249
```javascript { .api }
250
declare namespace match {
251
/**
252
* Matches strings that start with specified prefix
253
* @param prefix - Required string prefix
254
* @returns Matcher for strings starting with prefix
255
*/
256
function startsWith(prefix: string): SinonMatcher;
257
258
/**
259
* Matches strings that end with specified suffix
260
* @param suffix - Required string suffix
261
* @returns Matcher for strings ending with suffix
262
*/
263
function endsWith(suffix: string): SinonMatcher;
264
265
/**
266
* Matches strings that contain specified substring
267
* @param substring - Required substring
268
* @returns Matcher for strings containing substring
269
*/
270
function includes(substring: string): SinonMatcher;
271
}
272
```
273
274
**Usage Examples:**
275
276
```javascript
277
const spy = sinon.spy();
278
279
spy("hello world", "testing123", "world hello");
280
281
// String pattern matching
282
sinon.assert.calledWith(spy, match.startsWith("hello"));
283
sinon.assert.calledWith(spy, match.endsWith("123"));
284
sinon.assert.calledWith(spy, match.includes("world"));
285
286
// Combine multiple string patterns
287
sinon.assert.calledWith(spy,
288
match.startsWith("hello").and(match.includes("world"))
289
);
290
```
291
292
### Array and Collection Matchers
293
294
Match arrays and collections based on content and structure.
295
296
```javascript { .api }
297
declare namespace match {
298
/**
299
* Matches arrays where every element matches the provided matcher
300
* @param matcher - Matcher that all elements must satisfy
301
* @returns Matcher for arrays where all elements match
302
*/
303
function every(matcher: SinonMatcher): SinonMatcher;
304
305
/**
306
* Matches arrays where at least one element matches the provided matcher
307
* @param matcher - Matcher that at least one element must satisfy
308
* @returns Matcher for arrays where some elements match
309
*/
310
function some(matcher: SinonMatcher): SinonMatcher;
311
312
/**
313
* Matches arrays that contain all specified elements (order doesn't matter)
314
* @param elements - Elements that must be present in array
315
* @returns Matcher for arrays containing all elements
316
*/
317
function arrayContaining(elements: any[]): SinonMatcher;
318
319
/**
320
* Matches arrays or objects by deep equality
321
* @param value - Value to match by deep comparison
322
* @returns Matcher for deep equality
323
*/
324
function deepEquals(value: any): SinonMatcher;
325
326
/**
327
* Matches arrays with specific length
328
* @param length - Expected array length
329
* @returns Matcher for arrays with exact length
330
*/
331
function arrayWithLength(length: number): SinonMatcher;
332
}
333
```
334
335
**Usage Examples:**
336
337
```javascript
338
const spy = sinon.spy();
339
340
spy([1, 2, 3], ["a", "b", "c"], [5, 10, 15]);
341
342
// Array content matching
343
sinon.assert.calledWith(spy, match.every(match.number));
344
sinon.assert.calledWith(spy, match.some(match.string));
345
sinon.assert.calledWith(spy, match.arrayContaining([1, 3])); // Contains 1 and 3
346
347
// Array structure matching
348
sinon.assert.calledWith(spy, match.arrayWithLength(3));
349
350
// Deep equality
351
const expectedData = { items: [1, 2, 3], total: 3 };
352
spy(expectedData);
353
sinon.assert.calledWith(spy, match.deepEquals(expectedData));
354
```
355
356
### Custom Matchers
357
358
Create custom matchers with predicate functions.
359
360
```javascript { .api }
361
declare namespace match {
362
/**
363
* Creates a custom matcher using a predicate function
364
* @param predicate - Function that returns true for matching values
365
* @param message - Optional description for the matcher
366
* @returns Custom matcher based on predicate
367
*/
368
function (predicate: (value: any) => boolean, message?: string): SinonMatcher;
369
}
370
```
371
372
**Usage Examples:**
373
374
```javascript
375
const spy = sinon.spy();
376
377
// Custom matchers with predicates
378
const isEven = match((n) => n % 2 === 0, "even number");
379
const isValidEmail = match((email) => email.includes("@"), "valid email");
380
const isPositive = match((n) => n > 0, "positive number");
381
382
spy(4, "test@example.com", -5);
383
384
sinon.assert.calledWith(spy, isEven); // 4 is even
385
sinon.assert.calledWith(spy, isValidEmail); // has @
386
sinon.assert.neverCalledWith(spy, isPositive); // -5 is not positive
387
388
// Use in stubs
389
const stub = sinon.stub();
390
stub.withArgs(isEven).returns("even");
391
stub.withArgs(isPositive).returns("positive");
392
393
console.log(stub(4)); // "even"
394
console.log(stub(3)); // undefined (no match)
395
```
396
397
### Matcher Combinations
398
399
Combine multiple matchers using logical operators.
400
401
```javascript { .api }
402
interface SinonMatcher {
403
/**
404
* Combine matchers with logical AND
405
* @param matcher - Matcher to combine with AND logic
406
* @returns Combined matcher (both must match)
407
*/
408
and(matcher: SinonMatcher): SinonMatcher;
409
410
/**
411
* Combine matchers with logical OR
412
* @param matcher - Matcher to combine with OR logic
413
* @returns Combined matcher (either can match)
414
*/
415
or(matcher: SinonMatcher): SinonMatcher;
416
}
417
```
418
419
**Usage Examples:**
420
421
```javascript
422
const spy = sinon.spy();
423
424
spy("hello123", 42, "world");
425
426
// Combine matchers with AND
427
const stringWithNumbers = match.string.and(match.includes("123"));
428
sinon.assert.calledWith(spy, stringWithNumbers);
429
430
// Combine matchers with OR
431
const stringOrNumber = match.string.or(match.number);
432
sinon.assert.calledWith(spy, stringOrNumber); // Matches first and second args
433
434
// Complex combinations
435
const validId = match.number.and(match.greaterThan(0));
436
const validName = match.string.and(match.startsWith("user_"));
437
const validIdentifier = validId.or(validName);
438
439
const stub = sinon.stub();
440
stub.withArgs(validIdentifier).returns("valid");
441
442
console.log(stub(42)); // "valid" (positive number)
443
console.log(stub("user_123")); // "valid" (starts with user_)
444
console.log(stub(-1)); // undefined (negative number)
445
```
446
447
### Matcher Usage in Different Contexts
448
449
Using matchers across various Sinon features.
450
451
**Usage Examples:**
452
453
```javascript
454
// In spy assertions
455
const spy = sinon.spy();
456
spy({ id: 1, name: "test" });
457
sinon.assert.calledWith(spy, match.has("id", 1));
458
459
// In stub behaviors
460
const stub = sinon.stub();
461
stub.withArgs(match.string, match.number).returns("string and number");
462
stub.withArgs(match.object).callsFake((obj) => `Object with ${Object.keys(obj).length} keys`);
463
464
// In mock expectations
465
const obj = { process: () => {} };
466
const mock = sinon.mock(obj);
467
mock.expects("process").withArgs(match.array, match.func);
468
469
// In fake verification
470
const fake = sinon.fake();
471
fake([1, 2, 3], () => {});
472
console.log(fake.calledWith(match.every(match.number), match.func)); // true
473
```
474
475
### Built-in Matcher Utilities
476
477
Additional utility matchers for common patterns.
478
479
```javascript { .api }
480
declare namespace match {
481
/** Matches null values */
482
const nullValue: SinonMatcher;
483
484
/** Matches undefined values */
485
const undef: SinonMatcher;
486
487
/** Matches NaN values */
488
const nan: SinonMatcher;
489
490
/** Matches positive numbers (> 0) */
491
const positive: SinonMatcher;
492
493
/** Matches negative numbers (< 0) */
494
const negative: SinonMatcher;
495
496
/** Matches integer numbers */
497
const integer: SinonMatcher;
498
499
/** Matches float numbers */
500
const float: SinonMatcher;
501
}
502
```
503
504
**Usage Examples:**
505
506
```javascript
507
const spy = sinon.spy();
508
509
spy(null, undefined, NaN, 3.14, -5, 42);
510
511
// Use built-in utility matchers
512
sinon.assert.calledWith(spy, match.nullValue);
513
sinon.assert.calledWith(spy, match.undef);
514
sinon.assert.calledWith(spy, match.nan);
515
sinon.assert.calledWith(spy, match.float); // 3.14
516
sinon.assert.calledWith(spy, match.negative); // -5
517
sinon.assert.calledWith(spy, match.integer); // 42
518
```
519
520
## Types
521
522
```javascript { .api }
523
interface SinonMatcher {
524
/** Test if a value matches this matcher */
525
test(value: any): boolean;
526
527
/** Combine with another matcher using AND logic */
528
and(matcher: SinonMatcher): SinonMatcher;
529
530
/** Combine with another matcher using OR logic */
531
or(matcher: SinonMatcher): SinonMatcher;
532
533
/** String representation of the matcher */
534
toString(): string;
535
}
536
537
interface SinonMatch {
538
// Basic matchers
539
any: SinonMatcher;
540
defined: SinonMatcher;
541
truthy: SinonMatcher;
542
falsy: SinonMatcher;
543
bool: SinonMatcher;
544
number: SinonMatcher;
545
string: SinonMatcher;
546
object: SinonMatcher;
547
func: SinonMatcher;
548
array: SinonMatcher;
549
regexp: SinonMatcher;
550
date: SinonMatcher;
551
552
// Value matchers
553
same(value: any): SinonMatcher;
554
typeOf(type: string): SinonMatcher;
555
instanceOf(constructor: Function): SinonMatcher;
556
557
// Property matchers
558
has(property: string, value?: any): SinonMatcher;
559
hasOwn(property: string, value?: any): SinonMatcher;
560
hasNested(path: string, value?: any): SinonMatcher;
561
562
// Numeric matchers
563
greaterThan(value: number): SinonMatcher;
564
lessThan(value: number): SinonMatcher;
565
atLeast(value: number): SinonMatcher;
566
atMost(value: number): SinonMatcher;
567
568
// String matchers
569
startsWith(prefix: string): SinonMatcher;
570
endsWith(suffix: string): SinonMatcher;
571
includes(substring: string): SinonMatcher;
572
573
// Collection matchers
574
every(matcher: SinonMatcher): SinonMatcher;
575
some(matcher: SinonMatcher): SinonMatcher;
576
arrayContaining(elements: any[]): SinonMatcher;
577
deepEquals(value: any): SinonMatcher;
578
579
// Custom matcher
580
(predicate: (value: any) => boolean, message?: string): SinonMatcher;
581
}
582
```