0
# Spy System
1
2
Jasmine's comprehensive mocking and spying functionality for testing object interactions, method calls, and return values. Includes spy creation, behavior configuration, call tracking, and verification.
3
4
## Capabilities
5
6
### Spy Creation Functions
7
8
Functions for creating spies on existing objects and methods.
9
10
```javascript { .api }
11
/**
12
* Install a spy on an existing object method
13
* @param obj - Object containing the method to spy on
14
* @param methodName - Name of the method to spy on
15
* @returns Spy object for configuration and verification
16
*/
17
function spyOn(obj: object, methodName: string): Spy;
18
19
/**
20
* Install a spy on an object property getter or setter
21
* @param obj - Object containing the property to spy on
22
* @param propertyName - Name of the property to spy on
23
* @param accessType - Type of access to spy on ('get', 'set', or both)
24
* @returns PropertySpy object
25
*/
26
function spyOnProperty(obj: object, propertyName: string, accessType?: 'get' | 'set'): PropertySpy;
27
28
/**
29
* Install spies on all functions of an object
30
* @param obj - Object to spy on all functions
31
* @param includeNonEnumerable - Whether to include non-enumerable functions
32
* @returns Object with all function names as keys and spies as values
33
*/
34
function spyOnAllFunctions(obj: object, includeNonEnumerable?: boolean): { [key: string]: Spy };
35
```
36
37
**Usage Examples:**
38
39
```javascript
40
const calculator = {
41
add: (a, b) => a + b,
42
multiply: (a, b) => a * b
43
};
44
45
// Spy on existing method
46
const addSpy = spyOn(calculator, 'add');
47
calculator.add(2, 3);
48
expect(addSpy).toHaveBeenCalledWith(2, 3);
49
50
// Spy on property
51
const obj = {
52
get value() { return this._value; },
53
set value(val) { this._value = val; }
54
};
55
56
spyOnProperty(obj, 'value', 'get');
57
const val = obj.value;
58
expect(obj.value).toHaveBeenCalled();
59
60
// Spy on all functions
61
const mathUtils = {
62
add: (a, b) => a + b,
63
subtract: (a, b) => a - b,
64
helper: () => 'helper'
65
};
66
67
spyOnAllFunctions(mathUtils);
68
mathUtils.add(1, 2);
69
mathUtils.subtract(5, 3);
70
expect(mathUtils.add).toHaveBeenCalled();
71
expect(mathUtils.subtract).toHaveBeenCalled();
72
```
73
74
### Jasmine Spy Factory Functions
75
76
Functions for creating standalone spies and spy objects.
77
78
```javascript { .api }
79
/**
80
* Create a standalone spy function
81
* @param name - Optional name for the spy (for better error messages)
82
* @param originalFn - Optional original function to wrap
83
* @returns Spy function
84
*/
85
jasmine.createSpy(name?: string, originalFn?: Function): Spy;
86
87
/**
88
* Create an object with multiple spy methods
89
* @param baseName - Base name for the spy object
90
* @param methodNames - Array of method names or object with method configurations
91
* @param propertyNames - Optional array of property names or object with property configurations
92
* @returns Object with spy methods and properties
93
*/
94
jasmine.createSpyObj(
95
baseName: string,
96
methodNames: string[] | { [methodName: string]: any },
97
propertyNames?: string[] | { [propertyName: string]: any }
98
): any;
99
```
100
101
**Usage Examples:**
102
103
```javascript
104
// Create standalone spy
105
const callback = jasmine.createSpy('callback');
106
callback('arg1', 'arg2');
107
expect(callback).toHaveBeenCalledWith('arg1', 'arg2');
108
109
// Create spy with original function
110
const originalFn = (x) => x * 2;
111
const spy = jasmine.createSpy('doubler', originalFn);
112
113
// Create spy object with methods
114
const userService = jasmine.createSpyObj('UserService', [
115
'getUser',
116
'saveUser',
117
'deleteUser'
118
]);
119
120
userService.getUser.and.returnValue({ id: 1, name: 'John' });
121
const user = userService.getUser(1);
122
expect(user.name).toBe('John');
123
124
// Create spy object with methods and properties
125
const apiClient = jasmine.createSpyObj(
126
'ApiClient',
127
['get', 'post'],
128
['baseUrl', 'timeout']
129
);
130
131
apiClient.baseUrl = 'https://api.example.com';
132
apiClient.get.and.returnValue(Promise.resolve({ data: 'response' }));
133
```
134
135
### Spy Behavior Configuration
136
137
Methods for configuring how spies behave when called.
138
139
```javascript { .api }
140
interface SpyStrategy {
141
/**
142
* Make spy return a specific value
143
* @param value - Value to return when spy is called
144
* @returns The spy for chaining
145
*/
146
returnValue(value: any): Spy;
147
148
/**
149
* Make spy return different values on successive calls
150
* @param ...values - Values to return in order
151
* @returns The spy for chaining
152
*/
153
returnValues(...values: any[]): Spy;
154
155
/**
156
* Make spy call a fake function instead of original
157
* @param fn - Function to call instead
158
* @returns The spy for chaining
159
*/
160
callFake(fn: Function): Spy;
161
162
/**
163
* Make spy call through to the original function
164
* @returns The spy for chaining
165
*/
166
callThrough(): Spy;
167
168
/**
169
* Make spy throw an error when called
170
* @param msg - Error message or Error object to throw
171
* @returns The spy for chaining
172
*/
173
throwError(msg?: string | Error): Spy;
174
175
/**
176
* Make spy do nothing when called (default behavior)
177
* @returns The spy for chaining
178
*/
179
stub(): Spy;
180
181
/**
182
* Make spy return a resolved promise
183
* @param value - Value to resolve with
184
* @returns The spy for chaining
185
*/
186
resolveTo(value?: any): Spy;
187
188
/**
189
* Make spy return a rejected promise
190
* @param value - Value to reject with
191
* @returns The spy for chaining
192
*/
193
rejectWith(value?: any): Spy;
194
}
195
```
196
197
**Usage Examples:**
198
199
```javascript
200
const spy = jasmine.createSpy('testSpy');
201
202
// Return specific value
203
spy.and.returnValue(42);
204
expect(spy()).toBe(42);
205
206
// Return different values
207
spy.and.returnValues(1, 2, 3);
208
expect(spy()).toBe(1);
209
expect(spy()).toBe(2);
210
expect(spy()).toBe(3);
211
212
// Call fake function
213
spy.and.callFake((x, y) => x + y);
214
expect(spy(5, 3)).toBe(8);
215
216
// Throw error
217
spy.and.throwError('Something went wrong');
218
expect(() => spy()).toThrowError('Something went wrong');
219
220
// Return promises
221
const asyncSpy = jasmine.createSpy('asyncSpy');
222
asyncSpy.and.resolveTo('success');
223
await expectAsync(asyncSpy()).toBeResolvedTo('success');
224
225
asyncSpy.and.rejectWith('error');
226
await expectAsync(asyncSpy()).toBeRejectedWith('error');
227
228
// Call through to original
229
const obj = { method: (x) => x * 2 };
230
spyOn(obj, 'method').and.callThrough();
231
expect(obj.method(5)).toBe(10); // calls original
232
expect(obj.method).toHaveBeenCalledWith(5);
233
```
234
235
### Call Tracking and Verification
236
237
Methods for tracking and verifying spy calls.
238
239
```javascript { .api }
240
interface CallTracker {
241
/**
242
* Get the number of times the spy was called
243
* @returns Number of calls
244
*/
245
count(): number;
246
247
/**
248
* Get arguments for a specific call
249
* @param index - Index of the call (0-based)
250
* @returns Array of arguments for that call
251
*/
252
argsFor(index: number): any[];
253
254
/**
255
* Get all arguments for all calls
256
* @returns Array of argument arrays
257
*/
258
allArgs(): any[][];
259
260
/**
261
* Get all call objects with full details
262
* @returns Array of call objects
263
*/
264
all(): CallInfo[];
265
266
/**
267
* Get the most recent call object
268
* @returns Most recent call object or undefined
269
*/
270
mostRecent(): CallInfo | undefined;
271
272
/**
273
* Get the first call object
274
* @returns First call object or undefined
275
*/
276
first(): CallInfo | undefined;
277
278
/**
279
* Reset the spy's call history
280
*/
281
reset(): void;
282
}
283
284
interface CallInfo {
285
object: any;
286
args: any[];
287
returnValue: any;
288
}
289
```
290
291
**Usage Examples:**
292
293
```javascript
294
const spy = jasmine.createSpy('testSpy');
295
296
spy('first', 'call');
297
spy('second', 'call');
298
spy('third', 'call');
299
300
// Check call count
301
expect(spy.calls.count()).toBe(3);
302
303
// Check specific call arguments
304
expect(spy.calls.argsFor(0)).toEqual(['first', 'call']);
305
expect(spy.calls.argsFor(1)).toEqual(['second', 'call']);
306
307
// Get all arguments
308
expect(spy.calls.allArgs()).toEqual([
309
['first', 'call'],
310
['second', 'call'],
311
['third', 'call']
312
]);
313
314
// Get call details
315
const firstCall = spy.calls.first();
316
expect(firstCall.args).toEqual(['first', 'call']);
317
318
const lastCall = spy.calls.mostRecent();
319
expect(lastCall.args).toEqual(['third', 'call']);
320
321
// Reset call history
322
spy.calls.reset();
323
expect(spy.calls.count()).toBe(0);
324
```
325
326
### Spy Object Interface
327
328
The complete spy object interface showing all available properties and methods.
329
330
```javascript { .api }
331
interface Spy extends Function {
332
/** Strategy object for configuring spy behavior */
333
and: SpyStrategy;
334
335
/** Call tracker for verifying calls */
336
calls: CallTracker;
337
338
/** Original function identity (internal) */
339
identity: string;
340
}
341
342
interface PropertySpy {
343
/** Strategy object for configuring property spy behavior */
344
and: SpyStrategy;
345
346
/** Call tracker for verifying property access */
347
calls: CallTracker;
348
}
349
```
350
351
### Advanced Spy Features
352
353
Additional spy functionality for complex testing scenarios.
354
355
```javascript { .api }
356
/**
357
* Add a custom spy strategy that can be used by any spy
358
* @param name - Name of the strategy
359
* @param factory - Function that creates the strategy
360
*/
361
jasmine.addSpyStrategy(name: string, factory: (spy: Spy) => Function): void;
362
363
/**
364
* Set the default spy strategy for all new spies
365
* @param defaultStrategyFn - Function that returns default strategy
366
*/
367
jasmine.setDefaultSpyStrategy(defaultStrategyFn: (name: string, originalFn?: Function) => Function): void;
368
```
369
370
**Usage Examples:**
371
372
```javascript
373
// Add custom spy strategy
374
jasmine.addSpyStrategy('returnRandomValue', (spy) => {
375
return () => Math.random();
376
});
377
378
const spy = jasmine.createSpy('randomSpy');
379
spy.and.returnRandomValue();
380
const result = spy();
381
expect(typeof result).toBe('number');
382
383
// Set default spy strategy
384
jasmine.setDefaultSpyStrategy((name, originalFn) => {
385
return function() {
386
console.log(`Spy ${name} was called`);
387
return originalFn ? originalFn.apply(this, arguments) : undefined;
388
};
389
});
390
```
391
392
### Spy Restoration
393
394
Methods for restoring original functionality after spying.
395
396
```javascript { .api }
397
/**
398
* Restore all spies to their original functions
399
* Usually called in afterEach hooks
400
*/
401
function restoreAllSpies(): void;
402
```
403
404
**Usage Examples:**
405
406
```javascript
407
describe('Test suite with spies', () => {
408
let originalConsoleLog;
409
410
beforeEach(() => {
411
originalConsoleLog = console.log;
412
spyOn(console, 'log');
413
});
414
415
afterEach(() => {
416
// Restore all spies after each test
417
restoreAllSpies();
418
});
419
420
it('should spy on console.log', () => {
421
console.log('test message');
422
expect(console.log).toHaveBeenCalledWith('test message');
423
});
424
425
it('should have clean slate', () => {
426
// console.log spy is restored to original
427
expect(console.log).toBe(originalConsoleLog);
428
});
429
});
430
```
431
432
## Types
433
434
```javascript { .api }
435
interface Spy extends Function {
436
and: SpyStrategy;
437
calls: CallTracker;
438
identity: string;
439
}
440
441
interface SpyStrategy {
442
returnValue(value: any): Spy;
443
returnValues(...values: any[]): Spy;
444
callFake(fn: Function): Spy;
445
callThrough(): Spy;
446
throwError(msg?: string | Error): Spy;
447
stub(): Spy;
448
resolveTo(value?: any): Spy;
449
rejectWith(value?: any): Spy;
450
}
451
452
interface CallTracker {
453
count(): number;
454
argsFor(index: number): any[];
455
allArgs(): any[][];
456
all(): CallInfo[];
457
mostRecent(): CallInfo | undefined;
458
first(): CallInfo | undefined;
459
reset(): void;
460
}
461
462
interface CallInfo {
463
object: any;
464
args: any[];
465
returnValue: any;
466
}
467
468
interface PropertySpy {
469
and: SpyStrategy;
470
calls: CallTracker;
471
}
472
```