0
# Test Spies
1
2
Test spies record function calls, arguments, return values, and exceptions without changing the original function's behavior. They're perfect for verifying that functions are called correctly and for observing interactions between components.
3
4
## Capabilities
5
6
### Creating Spies
7
8
Create spies to monitor function calls and gather interaction data.
9
10
```javascript { .api }
11
/**
12
* Creates an anonymous spy function
13
* @returns New spy function that records calls
14
*/
15
function spy(): SinonSpy;
16
17
/**
18
* Wraps an existing function with spy functionality
19
* @param func - Function to wrap with spy
20
* @returns Spy wrapping the original function
21
*/
22
function spy<F extends Function>(func: F): SinonSpy<F>;
23
24
/**
25
* Replaces an object method with a spy
26
* @param object - Object containing the method
27
* @param method - Method name to spy on
28
* @returns Spy replacing the original method
29
*/
30
function spy<T>(object: T, method: keyof T): SinonSpy;
31
```
32
33
**Usage Examples:**
34
35
```javascript
36
import { spy } from "sinon";
37
38
// Anonymous spy
39
const callback = spy();
40
someFunction(callback);
41
console.log(callback.called); // true
42
43
// Spy on existing function
44
const originalFn = (x) => x * 2;
45
const spiedFn = spy(originalFn);
46
console.log(spiedFn(5)); // 10 (original behavior preserved)
47
console.log(spiedFn.calledWith(5)); // true
48
49
// Spy on object method
50
const user = { getName: () => "John" };
51
const nameSpy = spy(user, "getName");
52
user.getName(); // Still returns "John"
53
console.log(nameSpy.calledOnce); // true
54
```
55
56
### Property Spying
57
58
Spy on object property getters and setters to monitor property access patterns.
59
60
```javascript { .api }
61
/**
62
* Spy on object property accessors (getter/setter)
63
* @param object - Object containing the property
64
* @param property - Property name to spy on
65
* @param accessors - Array specifying which accessors to spy on
66
* @returns Spy for the property accessors
67
*/
68
function spy<T>(object: T, property: keyof T, accessors: ["get"] | ["set"] | ["get", "set"]): SinonSpy;
69
```
70
71
**Usage Examples:**
72
73
```javascript
74
import { spy } from "sinon";
75
76
const user = {
77
_name: "John",
78
get name() {
79
return this._name;
80
},
81
set name(value) {
82
this._name = value;
83
}
84
};
85
86
// Spy on getter only
87
const getterSpy = spy(user, "name", ["get"]);
88
console.log(user.name); // "John"
89
console.log(getterSpy.calledOnce); // true
90
91
// Spy on setter only
92
const setterSpy = spy(user, "name", ["set"]);
93
user.name = "Jane";
94
console.log(setterSpy.calledOnce); // true
95
console.log(setterSpy.calledWith("Jane")); // true
96
97
// Spy on both getter and setter
98
const user2 = { /* similar object */ };
99
const accessorSpy = spy(user2, "name", ["get", "set"]);
100
user2.name = "Bob"; // Records setter call
101
console.log(user2.name); // Records getter call
102
console.log(accessorSpy.callCount); // 2
103
```
104
105
### Spy Properties
106
107
Properties for checking spy call state and history.
108
109
```javascript { .api }
110
interface SinonSpy {
111
/** Whether the spy was called at least once */
112
called: boolean;
113
114
/** Number of times the spy was called */
115
callCount: number;
116
117
/** Whether the spy was called exactly once */
118
calledOnce: boolean;
119
120
/** Whether the spy was called exactly twice */
121
calledTwice: boolean;
122
123
/** Whether the spy was called exactly three times */
124
calledThrice: boolean;
125
126
/** First call object (null if never called) */
127
firstCall: SinonSpyCall | null;
128
129
/** Second call object (null if called less than twice) */
130
secondCall: SinonSpyCall | null;
131
132
/** Third call object (null if called less than three times) */
133
thirdCall: SinonSpyCall | null;
134
135
/** Last call object (null if never called) */
136
lastCall: SinonSpyCall | null;
137
}
138
```
139
140
### Argument Verification
141
142
Methods for verifying spy calls with specific arguments.
143
144
```javascript { .api }
145
interface SinonSpy {
146
/**
147
* Check if spy was called with specific arguments (partial match)
148
* @param args - Arguments to check for
149
* @returns Whether spy was called with these arguments
150
*/
151
calledWith(...args: any[]): boolean;
152
153
/**
154
* Check if spy was called with exact arguments (exact match)
155
* @param args - Exact arguments to check for
156
* @returns Whether spy was called with exactly these arguments
157
*/
158
calledWithExactly(...args: any[]): boolean;
159
160
/**
161
* Check if spy was called with arguments matching patterns
162
* @param matchers - Matcher patterns to check against
163
* @returns Whether spy was called with matching arguments
164
*/
165
calledWithMatch(...matchers: any[]): boolean;
166
167
/**
168
* Check if spy was always called with specific arguments
169
* @param args - Arguments that should be present in every call
170
* @returns Whether every call included these arguments
171
*/
172
alwaysCalledWith(...args: any[]): boolean;
173
174
/**
175
* Check if spy was always called with exact arguments
176
* @param args - Exact arguments for every call
177
* @returns Whether every call had exactly these arguments
178
*/
179
alwaysCalledWithExactly(...args: any[]): boolean;
180
181
/**
182
* Check if spy was always called with matching arguments
183
* @param matchers - Matcher patterns for every call
184
* @returns Whether every call matched these patterns
185
*/
186
alwaysCalledWithMatch(...matchers: any[]): boolean;
187
188
/**
189
* Check if spy was never called with specific arguments
190
* @param args - Arguments that should never be present
191
* @returns Whether spy was never called with these arguments
192
*/
193
neverCalledWith(...args: any[]): boolean;
194
195
/**
196
* Check if spy was never called with matching arguments
197
* @param matchers - Matcher patterns that should never match
198
* @returns Whether spy was never called with matching arguments
199
*/
200
neverCalledWithMatch(...matchers: any[]): boolean;
201
}
202
```
203
204
**Usage Examples:**
205
206
```javascript
207
const spy = sinon.spy();
208
209
spy("hello", { name: "world" });
210
spy("goodbye", { name: "world" });
211
212
console.log(spy.calledWith("hello")); // true
213
console.log(spy.calledWithExactly("hello", { name: "world" })); // true
214
console.log(spy.alwaysCalledWith({ name: "world" })); // true
215
console.log(spy.neverCalledWith("invalid")); // true
216
217
// Using matchers
218
import { match } from "sinon";
219
console.log(spy.calledWithMatch("hello", match.object)); // true
220
```
221
222
### Context Verification
223
224
Methods for verifying the `this` context of spy calls.
225
226
```javascript { .api }
227
interface SinonSpy {
228
/**
229
* Check if spy was called with specific `this` context
230
* @param thisValue - The expected `this` value
231
* @returns Whether spy was called with this context
232
*/
233
calledOn(thisValue: any): boolean;
234
235
/**
236
* Check if spy was always called with specific `this` context
237
* @param thisValue - The expected `this` value for all calls
238
* @returns Whether all calls used this context
239
*/
240
alwaysCalledOn(thisValue: any): boolean;
241
242
/**
243
* Check if spy was called as a constructor (with `new`)
244
* @returns Whether spy was called with `new` operator
245
*/
246
calledWithNew(): boolean;
247
248
/**
249
* Check if spy was always called as a constructor
250
* @returns Whether all calls used `new` operator
251
*/
252
alwaysCalledWithNew(): boolean;
253
}
254
```
255
256
### Return Value Verification
257
258
Methods for verifying spy return values and exceptions.
259
260
```javascript { .api }
261
interface SinonSpy {
262
/**
263
* Check if spy threw an exception
264
* @param error - Optional specific error to check for
265
* @returns Whether spy threw (the specified) exception
266
*/
267
threw(error?: any): boolean;
268
269
/**
270
* Check if spy always threw an exception
271
* @param error - Optional specific error to check for
272
* @returns Whether spy always threw (the specified) exception
273
*/
274
alwaysThrew(error?: any): boolean;
275
276
/**
277
* Check if spy returned a specific value
278
* @param value - The expected return value
279
* @returns Whether spy returned this value
280
*/
281
returned(value: any): boolean;
282
283
/**
284
* Check if spy always returned a specific value
285
* @param value - The expected return value for all calls
286
* @returns Whether spy always returned this value
287
*/
288
alwaysReturned(value: any): boolean;
289
}
290
```
291
292
### Call Access
293
294
Methods for accessing individual calls and their details.
295
296
```javascript { .api }
297
interface SinonSpy {
298
/**
299
* Get a specific call by index
300
* @param index - Zero-based call index
301
* @returns Call object or null if index is invalid
302
*/
303
getCall(index: number): SinonSpyCall | null;
304
305
/**
306
* Get all calls made to the spy
307
* @returns Array of all call objects
308
*/
309
getCalls(): SinonSpyCall[];
310
311
/**
312
* Create spy subset that only considers calls with specific arguments
313
* @param args - Arguments to filter calls by
314
* @returns New spy containing only matching calls
315
*/
316
withArgs(...args: any[]): SinonSpy;
317
}
318
```
319
320
### Spy Utilities
321
322
Utility methods for managing spy state and formatting.
323
324
```javascript { .api }
325
interface SinonSpy {
326
/**
327
* Reset the spy's call history (but keep the spy active)
328
*/
329
resetHistory(): void;
330
331
/**
332
* Restore the original method (for spies on object methods)
333
*/
334
restore(): void;
335
336
/**
337
* Format spy information with custom format string
338
* @param format - Format string with placeholders like %n, %c, etc.
339
* @param args - Additional arguments for formatting
340
* @returns Formatted string representation
341
*/
342
printf(format: string, ...args: any[]): string;
343
}
344
```
345
346
**Usage Examples:**
347
348
```javascript
349
const obj = { method: (x) => x * 2 };
350
const spy = sinon.spy(obj, "method");
351
352
obj.method(5);
353
obj.method(10);
354
355
// Access specific calls
356
console.log(spy.getCall(0).args); // [5]
357
console.log(spy.getCall(1).args); // [10]
358
359
// Get all calls
360
const calls = spy.getCalls();
361
console.log(calls.length); // 2
362
363
// Create filtered spy
364
const spy5 = spy.withArgs(5);
365
console.log(spy5.calledOnce); // true
366
367
// Cleanup
368
spy.resetHistory();
369
console.log(spy.callCount); // 0
370
spy.restore(); // Restore original method
371
```
372
373
## Types
374
375
```javascript { .api }
376
interface SinonSpyCall {
377
/** Arguments passed to this call */
378
args: any[];
379
380
/** The `this` value for this call */
381
thisValue: any;
382
383
/** Return value of this call */
384
returnValue: any;
385
386
/** Exception thrown by this call (if any) */
387
exception: Error | null;
388
389
/** Check if this call was made with specific arguments */
390
calledWith(...args: any[]): boolean;
391
392
/** Check if this call was made with exact arguments */
393
calledWithExactly(...args: any[]): boolean;
394
395
/** Check if this call was made with matching arguments */
396
calledWithMatch(...matchers: any[]): boolean;
397
398
/** Check if this call was made with specific `this` context */
399
calledOn(thisValue: any): boolean;
400
401
/** Check if this call returned a specific value */
402
returned(value: any): boolean;
403
404
/** Check if this call threw an exception */
405
threw(error?: any): boolean;
406
}
407
408
// Generic spy interface for typed functions
409
interface SinonSpy<F extends Function = Function> extends SinonSpy {
410
(...args: Parameters<F>): ReturnType<F>;
411
}
412
```